WebKit Bugzilla
Attachment 347510 Details for
Bug 188745
: Update libwebrtc up to 984f1a80c0
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
patch (text/plain), 29.43 MB, created by
youenn fablet
on 2018-08-20 10:57:38 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
youenn fablet
Created:
2018-08-20 10:57:38 PDT
Size:
29.43 MB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index ee74960aa01..883cd0665b4 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,15 @@ >+2018-08-20 Youenn Fablet <youenn@apple.com> >+ >+ Update libwebrtc up to 984f1a80c0 >+ https://bugs.webkit.org/show_bug.cgi?id=188745 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Updated tests according new webrtc backend. >+ >+ * webrtc/libwebrtc/setLocalDescriptionCrash.html: >+ * webrtc/video-getParameters.html: >+ > 2018-08-14 Antoine Quint <graouts@apple.com> > > [Web Animations] Crash under AnimationTimeline::cancelOrRemoveDeclarativeAnimation() >diff --git a/LayoutTests/webrtc/libwebrtc/setLocalDescriptionCrash.html b/LayoutTests/webrtc/libwebrtc/setLocalDescriptionCrash.html >index 7a0142c2a47..886a97c52df 100644 >--- a/LayoutTests/webrtc/libwebrtc/setLocalDescriptionCrash.html >+++ b/LayoutTests/webrtc/libwebrtc/setLocalDescriptionCrash.html >@@ -10,7 +10,7 @@ > <script> > function badifyAnswer(answer) > { >- return {type: answer.type, sdp: answer.sdp.replace("BUNDLE video", "BUNDLE")}; >+ return {type: answer.type, sdp: answer.sdp.replace("v=0", "v")}; > } > > promise_test((test) => { >@@ -29,9 +29,9 @@ promise_test((test) => { > badAnswer = badifyAnswer(answer); > return pc2.setLocalDescription(badAnswer); > }).then(assert_unreached, (e) => { >- assert_equals(e.message, "Failed to set local answer sdp: Failed to enable BUNDLE."); >+ assert_equals(e.message, "Expect line: v="); > return pc2.setLocalDescription(badAnswer).then(assert_unreached, (e) => { >- assert_equals(e.message, "Failed to set local answer sdp: no pending remote description."); >+ assert_equals(e.message, "Expect line: v="); > }); > }); > }, "Testing calling twice setLocalDescription with a bad SDP"); >diff --git a/LayoutTests/webrtc/video-getParameters.html b/LayoutTests/webrtc/video-getParameters.html >index c9c949f8a5e..3b269080b3d 100644 >--- a/LayoutTests/webrtc/video-getParameters.html >+++ b/LayoutTests/webrtc/video-getParameters.html >@@ -45,6 +45,9 @@ promise_test((test) => { > receiverParameters.encodings[0].fec.ssrc = 1; > receiverParameters.encodings[0].rtx.ssrc = 1; > >+ senderParameters.transactionId = ""; >+ receiverParameters.transactionId = ""; >+ > assert_equals(JSON.stringify(senderParameters), JSON.stringify(receiverParameters), "testing sender vs. receiver parameters"); > > senderParameters.encodings[0].ssrc = 1; >diff --git a/Source/ThirdParty/libwebrtc/ChangeLog b/Source/ThirdParty/libwebrtc/ChangeLog >index 8f6aebb7b6a..4a016177e25 100644 >--- a/Source/ThirdParty/libwebrtc/ChangeLog >+++ b/Source/ThirdParty/libwebrtc/ChangeLog >@@ -1,3 +1,38 @@ >+2018-08-20 Youenn Fablet <youenn@apple.com> >+ >+ Update libwebrtc up to 984f1a80c0 >+ https://bugs.webkit.org/show_bug.cgi?id=188745 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Updated webrtc to 984f1a80c0. >+ Updated libyuv accordingly. >+ Added abseil-cpp and rnnoise third party source code. >+ Removed WebKit specific patches that are no longer needed. >+ >+ * Configurations/libwebrtc.iOS.exp: Updated to include new required symbols. >+ * Configurations/libwebrtc.iOSsim.exp: Ditto. >+ * Configurations/libwebrtc.mac.exp: Ditto. >+ * Source/third_party/abseil-cpp: Added. >+ * Source/third_party/rnnoise: Added. >+ * Source/webrtc: Updated. >+ * WebKit/0001-Adapting-libwebrtc-H264-codec.patch: Removed. >+ * WebKit/0001-Disable-SIGPIPE-for-WebRTC-sockets.patch: Removed. >+ * WebKit/0001-Update-RTCVideoEncoderH264.mm-for-WebKit.patch: Removed. >+ * WebKit/0001-Using-VCP.patch: Removed. >+ * WebKit/0003-Fixing-VP8-files.patch: Removed. >+ * WebKit/0004-Removing-parameter-names-from-files-included-from-We.patch: Removed. >+ * WebKit/0005-Fix-RTC_FATAL.patch: Removed. >+ * WebKit/0006-Disabling-VP8.patch: Removed. >+ * WebKit/0007-Fix-RTC_STRINGIZE.patch: Removed. >+ * WebKit/0008-Fix-sanitizer.patch: Removed. >+ * WebKit/0009-Remove-dispatch_set_target_queue.patch: Removed. >+ * WebKit/0010-Fix-RTCVideoEncoderH264-CVPixelBuffer-leak.patch: Removed. >+ * WebKit/0011-Fix-AudioDeviceID-array-leak.patch: Removed. >+ * WebKit/0012-Add-WK-prefix-to-Objective-C-classes-and-protocols.patch: Removed. >+ * WebKit/0013-Fix-SafeSetError-use-after-move.patch: Removed. >+ * libwebrtc.xcodeproj/project.pbxproj: >+ > 2018-08-06 David Kilzer <ddkilzer@apple.com> > > [libwebrtc] SafeSetError() in peerconnection.cc contains use-after-move of webrtc::RTCError variable >diff --git a/Source/ThirdParty/libwebrtc/Configurations/Base.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/Base.xcconfig >index 074d8b3be2d..b04182e31f8 100644 >--- a/Source/ThirdParty/libwebrtc/Configurations/Base.xcconfig >+++ b/Source/ThirdParty/libwebrtc/Configurations/Base.xcconfig >@@ -52,7 +52,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; > GCC_WARN_UNUSED_VARIABLE = YES; > PREBINDING = NO; > STRIP_INSTALLED_PRODUCT = NO; >-WARNING_CFLAGS = -Wexit-time-destructors -Wglobal-constructors -Wthread-safety; >+WARNING_CFLAGS = -Wthread-safety; > > SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx; > VALID_ARCHS = $(ARCHS_STANDARD_64_BIT); >diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOS.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOS.exp >index 89f4e8b8a9c..8478b284152 100644 >--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOS.exp >+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOS.exp >@@ -1,7 +1,4 @@ > __ZN3rtc10LogMessage10LogToDebugENS_15LoggingSeverityE >-__ZN3rtc12FatalMessageC1EPKci >-__ZN3rtc12FatalMessageC1EPKciPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE >-__ZN3rtc12FatalMessageD1Ev > __ZN3rtc14MessageHandlerD2Ev > __ZN3rtc14VideoSinkWantsC1Ev > __ZN3rtc14VideoSinkWantsD1Ev >@@ -9,7 +6,6 @@ __ZN3rtc17CopyOnWriteBuffer21CloneDataIfReferencedEm > __ZN3rtc17CopyOnWriteBufferC1ERKS0_ > __ZN3rtc17CopyOnWriteBufferC1Emm > __ZN3rtc17CopyOnWriteBufferD1Ev >-__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE > __ZN3rtc6Thread22CreateWithSocketServerEv > __ZN3rtc6Thread5StartEPNS_8RunnableE > __ZN3rtc6Thread6CreateEv >@@ -34,15 +30,11 @@ __ZN6webrtc16ConvertVideoTypeENS_9VideoTypeE > __ZN6webrtc18CreateIceCandidateERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_PNS_13SdpParseErrorE > __ZN6webrtc19RTCCertificateStats5kTypeE > __ZN6webrtc19RTCDataChannelStats5kTypeE >-__ZN6webrtc20CoreVideoFrameBuffer6ToI420Ev >-__ZN6webrtc20CoreVideoFrameBufferC2EP10__CVBuffer >-__ZN6webrtc20CoreVideoFrameBufferD2Ev > __ZN6webrtc24CreateSessionDescriptionERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_PNS_13SdpParseErrorE > __ZN6webrtc24RTCIceCandidatePairStats5kTypeE > __ZN6webrtc24RTCInboundRTPStreamStats5kTypeE > __ZN6webrtc24RTCMediaStreamTrackStats5kTypeE > __ZN6webrtc25RTCOutboundRTPStreamStats5kTypeE >-__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE > __ZN6webrtc27SessionDescriptionInterface6kOfferE > __ZN6webrtc27SessionDescriptionInterface7kAnswerE > __ZN6webrtc27SessionDescriptionInterface9kPrAnswerE >@@ -50,7 +42,6 @@ __ZN6webrtc8internal21SynchronousMethodCall6InvokeERKN3rtc8LocationEPNS2_6Thread > __ZN6webrtc8internal21SynchronousMethodCallC1EPN3rtc14MessageHandlerE > __ZN6webrtc8internal21SynchronousMethodCallD1Ev > __ZN7cricket17MediaTypeToStringENS_9MediaTypeE >-__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE > __ZNK6webrtc10VideoFrame18video_frame_bufferEv > __ZNK6webrtc10VideoFrame5widthEv > __ZNK6webrtc10VideoFrame6heightEv >@@ -59,9 +50,6 @@ __ZNK6webrtc14RTCStatsReport13ConstIteratorneERKS1_ > __ZNK6webrtc14RTCStatsReport13ConstIteratorptEv > __ZNK6webrtc14RTCStatsReport3endEv > __ZNK6webrtc14RTCStatsReport5beginEv >-__ZNK6webrtc20CoreVideoFrameBuffer4typeEv >-__ZNK6webrtc20CoreVideoFrameBuffer5widthEv >-__ZNK6webrtc20CoreVideoFrameBuffer6heightEv > __ZNK6webrtc8RTCStats6ToJsonEv > __ZTVN3rtc14MessageHandlerE > _ConvertToI420 >@@ -95,13 +83,11 @@ __ZN3rtc13SocketAddressC1ERKS0_ > __ZN3rtc13SocketAddressaSERKS0_ > __ZNK3rtc13SocketAddress6ipaddrEv > __ZNK3rtc18NetworkManagerBase11GetNetworksEPNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEE >-__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc22PacketTimeUpdateParamsC1Ev > __ZN3rtc17AsyncPacketSocketD2Ev > __ZN3rtc9ProxyInfoD1Ev > __ZN3rtc18NetworkManagerBaseC2Ev > __ZN3rtc7NetworkD1Ev >-__ZTVN3rtc19PacketSocketFactoryE > __ZN3rtc22PacketTimeUpdateParamsD1Ev > __ZN3rtc22AsyncResolverInterfaceC2Ev > __ZN3rtc18NetworkManagerBase16MergeNetworkListERKNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEEPb >@@ -118,9 +104,6 @@ __ZN6webrtc32CreateBuiltinAudioDecoderFactoryEv > __ZN6webrtc32CreateBuiltinAudioEncoderFactoryEv > __ZN6webrtc27SessionDescriptionInterface16RemoveCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE > __ZNK6webrtc21IceCandidateInterface10server_urlEv >-__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >-__ZTVN6webrtc21IceCandidateInterfaceE >-__ZTVN6webrtc27SessionDescriptionInterfaceE > __ZN6webrtc20setApplicationStatusEb > __ZN6webrtc32createVideoToolboxDecoderFactoryEv > __ZN6webrtc32createVideoToolboxEncoderFactoryEv >@@ -128,6 +111,98 @@ __ZN6webrtc29setH264HardwareEncoderAllowedEb > __ZN6webrtc20pixelBufferFromFrameERKNS_10VideoFrameE > __ZN6webrtc18pixelBufferToFrameEP10__CVBuffer > __ZN3rtc24BasicPacketSocketFactory19CreateAsyncResolverEv >-__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc24BasicPacketSocketFactoryC2Ev > __ZN3rtc24BasicPacketSocketFactoryD2Ev >+__ZNK3rtc6Thread9IsCurrentEv >+__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE >+__ZN3rtc5EventD1Ev >+__ZN3rtc5EventC1Ebb >+__ZN3rtc5Event4WaitEi >+__ZN3rtc5Event3SetEv >+__ZN3rtc18CreateRandomStringEm >+__ZN6webrtc8RTCError2OKEv >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZTVN6webrtc32CreateSessionDescriptionObserverE >+__ZTVN6webrtc30PeerConnectionFactoryInterfaceE >+__ZTVN6webrtc29SetSessionDescriptionObserverE >+__ZNK3rtc17ThreadCheckerImpl19CalledOnValidThreadEv >+__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE >+__ZN7cricket12AudioOptionsD1Ev >+__ZN6webrtc32CreateSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerE >+__ZN6webrtc29SetSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc28RtpHeaderExtensionCapabilityD1Ev >+__ZN6webrtc26PeerConnectionDependenciesD1Ev >+__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationD1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface9IceServerC1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerD1Ev >+__ZN6webrtc26PeerConnectionDependenciesC1EOS0_ >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZTVN6webrtc27SessionDescriptionInterfaceE >+__ZTVN6webrtc23PeerConnectionInterfaceE >+__ZTVN6webrtc21IceCandidateInterfaceE >+__ZTVN6webrtc20DataChannelInterfaceE >+__ZTVN6webrtc19VideoTrackInterfaceE >+__ZTVN6webrtc19AudioTrackInterfaceE >+__ZNK6webrtc30PeerConnectionFactoryInterface26GetRtpReceiverCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc30PeerConnectionFactoryInterface24GetRtpSenderCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >+__ZNK6webrtc23PeerConnectionInterface26pending_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface26current_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25pending_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25current_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface15GetTransceiversEv >+__ZNK6webrtc23PeerConnectionInterface12GetReceiversEv >+__ZNK6webrtc23PeerConnectionInterface10GetSendersEv >+__ZNK6webrtc20DataChannelInterface8protocolEv >+__ZNK6webrtc20DataChannelInterface17maxRetransmitTimeEv >+__ZNK6webrtc20DataChannelInterface14maxRetransmitsEv >+__ZNK6webrtc20DataChannelInterface10negotiatedEv >+__ZNK6webrtc19VideoTrackInterface12content_hintEv >+__ZN6webrtc30PeerConnectionFactoryInterface20CreatePeerConnectionERKNS_23PeerConnectionInterface16RTCConfigurationENS_26PeerConnectionDependenciesE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface19RemoveIceCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogEix >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogENSt3__110unique_ptrINS_17RtcEventLogOutputENS1_14default_deleteIS3_EEEEx >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationEPNS_8RTCErrorE >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationE >+__ZN6webrtc19AudioTrackInterface14GetSignalLevelEPi >+__ZN6webrtc19AudioTrackInterface17GetAudioProcessorEv >+__ZN6webrtc23PeerConnectionInterface10SetBitrateERKNS_15BitrateSettingsE >+__ZN6webrtc23PeerConnectionInterface12CreateSenderERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface16GetConfigurationEv >+__ZN6webrtc23PeerConnectionInterface14RemoveTrackNewEN3rtc13scoped_refptrINS_18RtpSenderInterfaceEEE >+__ZN3rtc10SentPacketC1Exx >+__ZN3rtc13PacketOptionsC1ERKS0_ >+__ZN3rtc10PacketInfoD1Ev >+__ZN3rtc10PacketInfoC1ERKS0_ >+__ZTVN3rtc19PacketSocketFactoryE >+__ZN3rtc13PacketOptionsD1Ev >+__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN3rtc13PacketOptionsC1Ev >+__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE >diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOSsim.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOSsim.exp >index 89f4e8b8a9c..8478b284152 100644 >--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOSsim.exp >+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.iOSsim.exp >@@ -1,7 +1,4 @@ > __ZN3rtc10LogMessage10LogToDebugENS_15LoggingSeverityE >-__ZN3rtc12FatalMessageC1EPKci >-__ZN3rtc12FatalMessageC1EPKciPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE >-__ZN3rtc12FatalMessageD1Ev > __ZN3rtc14MessageHandlerD2Ev > __ZN3rtc14VideoSinkWantsC1Ev > __ZN3rtc14VideoSinkWantsD1Ev >@@ -9,7 +6,6 @@ __ZN3rtc17CopyOnWriteBuffer21CloneDataIfReferencedEm > __ZN3rtc17CopyOnWriteBufferC1ERKS0_ > __ZN3rtc17CopyOnWriteBufferC1Emm > __ZN3rtc17CopyOnWriteBufferD1Ev >-__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE > __ZN3rtc6Thread22CreateWithSocketServerEv > __ZN3rtc6Thread5StartEPNS_8RunnableE > __ZN3rtc6Thread6CreateEv >@@ -34,15 +30,11 @@ __ZN6webrtc16ConvertVideoTypeENS_9VideoTypeE > __ZN6webrtc18CreateIceCandidateERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_PNS_13SdpParseErrorE > __ZN6webrtc19RTCCertificateStats5kTypeE > __ZN6webrtc19RTCDataChannelStats5kTypeE >-__ZN6webrtc20CoreVideoFrameBuffer6ToI420Ev >-__ZN6webrtc20CoreVideoFrameBufferC2EP10__CVBuffer >-__ZN6webrtc20CoreVideoFrameBufferD2Ev > __ZN6webrtc24CreateSessionDescriptionERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_PNS_13SdpParseErrorE > __ZN6webrtc24RTCIceCandidatePairStats5kTypeE > __ZN6webrtc24RTCInboundRTPStreamStats5kTypeE > __ZN6webrtc24RTCMediaStreamTrackStats5kTypeE > __ZN6webrtc25RTCOutboundRTPStreamStats5kTypeE >-__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE > __ZN6webrtc27SessionDescriptionInterface6kOfferE > __ZN6webrtc27SessionDescriptionInterface7kAnswerE > __ZN6webrtc27SessionDescriptionInterface9kPrAnswerE >@@ -50,7 +42,6 @@ __ZN6webrtc8internal21SynchronousMethodCall6InvokeERKN3rtc8LocationEPNS2_6Thread > __ZN6webrtc8internal21SynchronousMethodCallC1EPN3rtc14MessageHandlerE > __ZN6webrtc8internal21SynchronousMethodCallD1Ev > __ZN7cricket17MediaTypeToStringENS_9MediaTypeE >-__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE > __ZNK6webrtc10VideoFrame18video_frame_bufferEv > __ZNK6webrtc10VideoFrame5widthEv > __ZNK6webrtc10VideoFrame6heightEv >@@ -59,9 +50,6 @@ __ZNK6webrtc14RTCStatsReport13ConstIteratorneERKS1_ > __ZNK6webrtc14RTCStatsReport13ConstIteratorptEv > __ZNK6webrtc14RTCStatsReport3endEv > __ZNK6webrtc14RTCStatsReport5beginEv >-__ZNK6webrtc20CoreVideoFrameBuffer4typeEv >-__ZNK6webrtc20CoreVideoFrameBuffer5widthEv >-__ZNK6webrtc20CoreVideoFrameBuffer6heightEv > __ZNK6webrtc8RTCStats6ToJsonEv > __ZTVN3rtc14MessageHandlerE > _ConvertToI420 >@@ -95,13 +83,11 @@ __ZN3rtc13SocketAddressC1ERKS0_ > __ZN3rtc13SocketAddressaSERKS0_ > __ZNK3rtc13SocketAddress6ipaddrEv > __ZNK3rtc18NetworkManagerBase11GetNetworksEPNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEE >-__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc22PacketTimeUpdateParamsC1Ev > __ZN3rtc17AsyncPacketSocketD2Ev > __ZN3rtc9ProxyInfoD1Ev > __ZN3rtc18NetworkManagerBaseC2Ev > __ZN3rtc7NetworkD1Ev >-__ZTVN3rtc19PacketSocketFactoryE > __ZN3rtc22PacketTimeUpdateParamsD1Ev > __ZN3rtc22AsyncResolverInterfaceC2Ev > __ZN3rtc18NetworkManagerBase16MergeNetworkListERKNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEEPb >@@ -118,9 +104,6 @@ __ZN6webrtc32CreateBuiltinAudioDecoderFactoryEv > __ZN6webrtc32CreateBuiltinAudioEncoderFactoryEv > __ZN6webrtc27SessionDescriptionInterface16RemoveCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE > __ZNK6webrtc21IceCandidateInterface10server_urlEv >-__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >-__ZTVN6webrtc21IceCandidateInterfaceE >-__ZTVN6webrtc27SessionDescriptionInterfaceE > __ZN6webrtc20setApplicationStatusEb > __ZN6webrtc32createVideoToolboxDecoderFactoryEv > __ZN6webrtc32createVideoToolboxEncoderFactoryEv >@@ -128,6 +111,98 @@ __ZN6webrtc29setH264HardwareEncoderAllowedEb > __ZN6webrtc20pixelBufferFromFrameERKNS_10VideoFrameE > __ZN6webrtc18pixelBufferToFrameEP10__CVBuffer > __ZN3rtc24BasicPacketSocketFactory19CreateAsyncResolverEv >-__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc24BasicPacketSocketFactoryC2Ev > __ZN3rtc24BasicPacketSocketFactoryD2Ev >+__ZNK3rtc6Thread9IsCurrentEv >+__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE >+__ZN3rtc5EventD1Ev >+__ZN3rtc5EventC1Ebb >+__ZN3rtc5Event4WaitEi >+__ZN3rtc5Event3SetEv >+__ZN3rtc18CreateRandomStringEm >+__ZN6webrtc8RTCError2OKEv >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZTVN6webrtc32CreateSessionDescriptionObserverE >+__ZTVN6webrtc30PeerConnectionFactoryInterfaceE >+__ZTVN6webrtc29SetSessionDescriptionObserverE >+__ZNK3rtc17ThreadCheckerImpl19CalledOnValidThreadEv >+__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE >+__ZN7cricket12AudioOptionsD1Ev >+__ZN6webrtc32CreateSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerE >+__ZN6webrtc29SetSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc28RtpHeaderExtensionCapabilityD1Ev >+__ZN6webrtc26PeerConnectionDependenciesD1Ev >+__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationD1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface9IceServerC1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerD1Ev >+__ZN6webrtc26PeerConnectionDependenciesC1EOS0_ >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZTVN6webrtc27SessionDescriptionInterfaceE >+__ZTVN6webrtc23PeerConnectionInterfaceE >+__ZTVN6webrtc21IceCandidateInterfaceE >+__ZTVN6webrtc20DataChannelInterfaceE >+__ZTVN6webrtc19VideoTrackInterfaceE >+__ZTVN6webrtc19AudioTrackInterfaceE >+__ZNK6webrtc30PeerConnectionFactoryInterface26GetRtpReceiverCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc30PeerConnectionFactoryInterface24GetRtpSenderCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >+__ZNK6webrtc23PeerConnectionInterface26pending_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface26current_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25pending_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25current_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface15GetTransceiversEv >+__ZNK6webrtc23PeerConnectionInterface12GetReceiversEv >+__ZNK6webrtc23PeerConnectionInterface10GetSendersEv >+__ZNK6webrtc20DataChannelInterface8protocolEv >+__ZNK6webrtc20DataChannelInterface17maxRetransmitTimeEv >+__ZNK6webrtc20DataChannelInterface14maxRetransmitsEv >+__ZNK6webrtc20DataChannelInterface10negotiatedEv >+__ZNK6webrtc19VideoTrackInterface12content_hintEv >+__ZN6webrtc30PeerConnectionFactoryInterface20CreatePeerConnectionERKNS_23PeerConnectionInterface16RTCConfigurationENS_26PeerConnectionDependenciesE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface19RemoveIceCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogEix >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogENSt3__110unique_ptrINS_17RtcEventLogOutputENS1_14default_deleteIS3_EEEEx >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationEPNS_8RTCErrorE >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationE >+__ZN6webrtc19AudioTrackInterface14GetSignalLevelEPi >+__ZN6webrtc19AudioTrackInterface17GetAudioProcessorEv >+__ZN6webrtc23PeerConnectionInterface10SetBitrateERKNS_15BitrateSettingsE >+__ZN6webrtc23PeerConnectionInterface12CreateSenderERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface16GetConfigurationEv >+__ZN6webrtc23PeerConnectionInterface14RemoveTrackNewEN3rtc13scoped_refptrINS_18RtpSenderInterfaceEEE >+__ZN3rtc10SentPacketC1Exx >+__ZN3rtc13PacketOptionsC1ERKS0_ >+__ZN3rtc10PacketInfoD1Ev >+__ZN3rtc10PacketInfoC1ERKS0_ >+__ZTVN3rtc19PacketSocketFactoryE >+__ZN3rtc13PacketOptionsD1Ev >+__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN3rtc13PacketOptionsC1Ev >+__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE >diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp >index 89f4e8b8a9c..8478b284152 100644 >--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp >+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp >@@ -1,7 +1,4 @@ > __ZN3rtc10LogMessage10LogToDebugENS_15LoggingSeverityE >-__ZN3rtc12FatalMessageC1EPKci >-__ZN3rtc12FatalMessageC1EPKciPNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE >-__ZN3rtc12FatalMessageD1Ev > __ZN3rtc14MessageHandlerD2Ev > __ZN3rtc14VideoSinkWantsC1Ev > __ZN3rtc14VideoSinkWantsD1Ev >@@ -9,7 +6,6 @@ __ZN3rtc17CopyOnWriteBuffer21CloneDataIfReferencedEm > __ZN3rtc17CopyOnWriteBufferC1ERKS0_ > __ZN3rtc17CopyOnWriteBufferC1Emm > __ZN3rtc17CopyOnWriteBufferD1Ev >-__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE > __ZN3rtc6Thread22CreateWithSocketServerEv > __ZN3rtc6Thread5StartEPNS_8RunnableE > __ZN3rtc6Thread6CreateEv >@@ -34,15 +30,11 @@ __ZN6webrtc16ConvertVideoTypeENS_9VideoTypeE > __ZN6webrtc18CreateIceCandidateERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_PNS_13SdpParseErrorE > __ZN6webrtc19RTCCertificateStats5kTypeE > __ZN6webrtc19RTCDataChannelStats5kTypeE >-__ZN6webrtc20CoreVideoFrameBuffer6ToI420Ev >-__ZN6webrtc20CoreVideoFrameBufferC2EP10__CVBuffer >-__ZN6webrtc20CoreVideoFrameBufferD2Ev > __ZN6webrtc24CreateSessionDescriptionERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_PNS_13SdpParseErrorE > __ZN6webrtc24RTCIceCandidatePairStats5kTypeE > __ZN6webrtc24RTCInboundRTPStreamStats5kTypeE > __ZN6webrtc24RTCMediaStreamTrackStats5kTypeE > __ZN6webrtc25RTCOutboundRTPStreamStats5kTypeE >-__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE > __ZN6webrtc27SessionDescriptionInterface6kOfferE > __ZN6webrtc27SessionDescriptionInterface7kAnswerE > __ZN6webrtc27SessionDescriptionInterface9kPrAnswerE >@@ -50,7 +42,6 @@ __ZN6webrtc8internal21SynchronousMethodCall6InvokeERKN3rtc8LocationEPNS2_6Thread > __ZN6webrtc8internal21SynchronousMethodCallC1EPN3rtc14MessageHandlerE > __ZN6webrtc8internal21SynchronousMethodCallD1Ev > __ZN7cricket17MediaTypeToStringENS_9MediaTypeE >-__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE > __ZNK6webrtc10VideoFrame18video_frame_bufferEv > __ZNK6webrtc10VideoFrame5widthEv > __ZNK6webrtc10VideoFrame6heightEv >@@ -59,9 +50,6 @@ __ZNK6webrtc14RTCStatsReport13ConstIteratorneERKS1_ > __ZNK6webrtc14RTCStatsReport13ConstIteratorptEv > __ZNK6webrtc14RTCStatsReport3endEv > __ZNK6webrtc14RTCStatsReport5beginEv >-__ZNK6webrtc20CoreVideoFrameBuffer4typeEv >-__ZNK6webrtc20CoreVideoFrameBuffer5widthEv >-__ZNK6webrtc20CoreVideoFrameBuffer6heightEv > __ZNK6webrtc8RTCStats6ToJsonEv > __ZTVN3rtc14MessageHandlerE > _ConvertToI420 >@@ -95,13 +83,11 @@ __ZN3rtc13SocketAddressC1ERKS0_ > __ZN3rtc13SocketAddressaSERKS0_ > __ZNK3rtc13SocketAddress6ipaddrEv > __ZNK3rtc18NetworkManagerBase11GetNetworksEPNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEE >-__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc22PacketTimeUpdateParamsC1Ev > __ZN3rtc17AsyncPacketSocketD2Ev > __ZN3rtc9ProxyInfoD1Ev > __ZN3rtc18NetworkManagerBaseC2Ev > __ZN3rtc7NetworkD1Ev >-__ZTVN3rtc19PacketSocketFactoryE > __ZN3rtc22PacketTimeUpdateParamsD1Ev > __ZN3rtc22AsyncResolverInterfaceC2Ev > __ZN3rtc18NetworkManagerBase16MergeNetworkListERKNSt3__16vectorIPNS_7NetworkENS1_9allocatorIS4_EEEEPb >@@ -118,9 +104,6 @@ __ZN6webrtc32CreateBuiltinAudioDecoderFactoryEv > __ZN6webrtc32CreateBuiltinAudioEncoderFactoryEv > __ZN6webrtc27SessionDescriptionInterface16RemoveCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE > __ZNK6webrtc21IceCandidateInterface10server_urlEv >-__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >-__ZTVN6webrtc21IceCandidateInterfaceE >-__ZTVN6webrtc27SessionDescriptionInterfaceE > __ZN6webrtc20setApplicationStatusEb > __ZN6webrtc32createVideoToolboxDecoderFactoryEv > __ZN6webrtc32createVideoToolboxEncoderFactoryEv >@@ -128,6 +111,98 @@ __ZN6webrtc29setH264HardwareEncoderAllowedEb > __ZN6webrtc20pixelBufferFromFrameERKNS_10VideoFrameE > __ZN6webrtc18pixelBufferToFrameEP10__CVBuffer > __ZN3rtc24BasicPacketSocketFactory19CreateAsyncResolverEv >-__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE > __ZN3rtc24BasicPacketSocketFactoryC2Ev > __ZN3rtc24BasicPacketSocketFactoryD2Ev >+__ZNK3rtc6Thread9IsCurrentEv >+__ZN3rtc6Thread14InvokeInternalERKNS_8LocationEPNS_14MessageHandlerE >+__ZN3rtc5EventD1Ev >+__ZN3rtc5EventC1Ebb >+__ZN3rtc5Event4WaitEi >+__ZN3rtc5Event3SetEv >+__ZN3rtc18CreateRandomStringEm >+__ZN6webrtc8RTCError2OKEv >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZTVN6webrtc32CreateSessionDescriptionObserverE >+__ZTVN6webrtc30PeerConnectionFactoryInterfaceE >+__ZTVN6webrtc29SetSessionDescriptionObserverE >+__ZNK3rtc17ThreadCheckerImpl19CalledOnValidThreadEv >+__ZN7cricket18BasicPortAllocatorC1EPN3rtc14NetworkManagerEPNS1_19PacketSocketFactoryEPN6webrtc14TurnCustomizerEPNS_25RelayPortFactoryInterfaceE >+__ZN7cricket12AudioOptionsD1Ev >+__ZN6webrtc32CreateSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceEPN7cricket13VideoCapturerE >+__ZN6webrtc29SetSessionDescriptionObserver9OnFailureENS_8RTCErrorE >+__ZN6webrtc28RtpHeaderExtensionCapabilityD1Ev >+__ZN6webrtc26PeerConnectionDependenciesD1Ev >+__ZN3rtc24BasicPacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationD1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerC1ERKS1_ >+__ZN6webrtc23PeerConnectionInterface9IceServerC1Ev >+__ZN6webrtc23PeerConnectionInterface9IceServerD1Ev >+__ZN6webrtc26PeerConnectionDependenciesC1EOS0_ >+__ZN3rtc18webrtc_checks_impl8FatalLogEPKciS2_PKNS0_12CheckArgTypeEz >+__ZN6webrtc12RtcpFeedbackC1ERKS0_ >+__ZN6webrtc12RtcpFeedbackD1Ev >+__ZN6webrtc14I420BufferPoolC1Ev >+__ZN6webrtc14I420BufferPoolD1Ev >+__ZN6webrtc15RtpCapabilitiesC1Ev >+__ZN6webrtc15RtpCapabilitiesD1Ev >+__ZN6webrtc18RtpCodecCapabilityD1Ev >+__ZN6webrtc23PeerConnectionInterface16RTCConfigurationC1ERKS1_ >+__ZTVN6webrtc27SessionDescriptionInterfaceE >+__ZTVN6webrtc23PeerConnectionInterfaceE >+__ZTVN6webrtc21IceCandidateInterfaceE >+__ZTVN6webrtc20DataChannelInterfaceE >+__ZTVN6webrtc19VideoTrackInterfaceE >+__ZTVN6webrtc19AudioTrackInterfaceE >+__ZNK6webrtc30PeerConnectionFactoryInterface26GetRtpReceiverCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc30PeerConnectionFactoryInterface24GetRtpSenderCapabilitiesEN7cricket9MediaTypeE >+__ZNK6webrtc27SessionDescriptionInterface7GetTypeEv >+__ZNK6webrtc23PeerConnectionInterface26pending_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface26current_remote_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25pending_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface25current_local_descriptionEv >+__ZNK6webrtc23PeerConnectionInterface15GetTransceiversEv >+__ZNK6webrtc23PeerConnectionInterface12GetReceiversEv >+__ZNK6webrtc23PeerConnectionInterface10GetSendersEv >+__ZNK6webrtc20DataChannelInterface8protocolEv >+__ZNK6webrtc20DataChannelInterface17maxRetransmitTimeEv >+__ZNK6webrtc20DataChannelInterface14maxRetransmitsEv >+__ZNK6webrtc20DataChannelInterface10negotiatedEv >+__ZNK6webrtc19VideoTrackInterface12content_hintEv >+__ZN6webrtc30PeerConnectionFactoryInterface20CreatePeerConnectionERKNS_23PeerConnectionInterface16RTCConfigurationENS_26PeerConnectionDependenciesE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEEPKNS_25MediaConstraintsInterfaceE >+__ZN6webrtc30PeerConnectionFactoryInterface17CreateVideoSourceENSt3__110unique_ptrIN7cricket13VideoCapturerENS1_14default_deleteIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface19RemoveIceCandidatesERKNSt3__16vectorIN7cricket9CandidateENS1_9allocatorIS4_EEEE >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogEix >+__ZN6webrtc23PeerConnectionInterface16StartRtcEventLogENSt3__110unique_ptrINS_17RtcEventLogOutputENS1_14default_deleteIS3_EEEEx >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationEPNS_8RTCErrorE >+__ZN6webrtc23PeerConnectionInterface16SetConfigurationERKNS0_16RTCConfigurationE >+__ZN6webrtc19AudioTrackInterface14GetSignalLevelEPi >+__ZN6webrtc19AudioTrackInterface17GetAudioProcessorEv >+__ZN6webrtc23PeerConnectionInterface10SetBitrateERKNS_15BitrateSettingsE >+__ZN6webrtc23PeerConnectionInterface12CreateSenderERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_ >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN3rtc13scoped_refptrINS_25MediaStreamTrackInterfaceEEERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeE >+__ZN6webrtc23PeerConnectionInterface14AddTransceiverEN7cricket9MediaTypeERKNS_18RtpTransceiverInitE >+__ZN6webrtc23PeerConnectionInterface16GetConfigurationEv >+__ZN6webrtc23PeerConnectionInterface14RemoveTrackNewEN3rtc13scoped_refptrINS_18RtpSenderInterfaceEEE >+__ZN3rtc10SentPacketC1Exx >+__ZN3rtc13PacketOptionsC1ERKS0_ >+__ZN3rtc10PacketInfoD1Ev >+__ZN3rtc10PacketInfoC1ERKS0_ >+__ZTVN3rtc19PacketSocketFactoryE >+__ZN3rtc13PacketOptionsD1Ev >+__ZN3rtc19PacketSocketFactory21CreateClientTcpSocketERKNS_13SocketAddressES3_RKNS_9ProxyInfoERKNSt3__112basic_stringIcNS7_11char_traitsIcEENS7_9allocatorIcEEEERKNS_22PacketSocketTcpOptionsE >+__ZN3rtc13PacketOptionsC1Ev >+__ZN6webrtc27CreatePeerConnectionFactoryEPN3rtc6ThreadES2_S2_NS0_13scoped_refptrINS_17AudioDeviceModuleEEENS3_INS_19AudioEncoderFactoryEEENS3_INS_19AudioDecoderFactoryEEENSt3__110unique_ptrINS_19VideoEncoderFactoryENSA_14default_deleteISC_EEEENSB_INS_19VideoDecoderFactoryENSD_ISG_EEEENS3_INS_10AudioMixerEEENS3_INS_15AudioProcessingEEE >diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig >index 0306586af6b..62a1196e337 100644 >--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig >+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig >@@ -26,7 +26,7 @@ INSTALLHDRS_SCRIPT_PHASE = YES; > WARNING_CFLAGS = -Wno-deprecated-declarations $(inherited); > > // FIXME: Set WEBRTC_USE_BUILTIN_ISAC_FIX and WEBRTC_USE_BUILTIN_ISAC_FLOAT for iOS and Mac >-GCC_PREPROCESSOR_DEFINITIONS = GTEST_RELATIVE_PATH WEBRTC_OPUS_SUPPORT_120MS_PTIME=0 WEBRTC_POSIX WEBRTC_MAC SSL_USE_OPENSSL FEATURE_ENABLE_SSL HAVE_SRTP HAVE_OPENSSL_SSL_H SCTP_PROCESS_LEVEL_LOCKS SCTP_SIMPLE_ALLOCATOR SCTP_USE_OPENSSL_SHA1 __Userspace__ HAVE_SA_LEN HAVE_SCONN_LEN __APPLE_USE_RFC_2292 __Userspace_os_Darwin NON_WINDOWS_DEFINE HAVE_WEBRTC_VIDEO HAVE_WEBRTC_VOICE WEBRTC_INTELLIGIBILITY_ENHANCER=0 WEBRTC_APM_DEBUG_DUMP=0 WEBRTC_NS_FLOAT WEBRTC_USE_BUILTIN_ILBC WEBRTC_CODEC_ILBC WEBRTC_USE_BUILTIN_OPUS WEBRTC_CODEC_OPUS WEBRTC_CODEC_ISAC WEBRTC_CODEC_RED RTC_DISABLE_VP9 RTC_DISABLE_VP8 HAVE_STDINT_H HAVE_STDLIB_H HAVE_UINT64_T OPENSSL HAVE_CONFIG_H WEBRTC_WEBKIT_BUILD HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE HAVE_SCTP WEBRTC_CODEC_G711 WEBRTC_CODEC_G722 WEBRTC_OPUS_VARIABLE_COMPLEXITY=0 WEBRTC_USE_BUILTIN_ISAC_FIX=1 WEBRTC_USE_BUILTIN_ISAC_FLOAT=0 $(inherited); >+GCC_PREPROCESSOR_DEFINITIONS = GTEST_RELATIVE_PATH WEBRTC_OPUS_SUPPORT_120MS_PTIME=0 WEBRTC_POSIX WEBRTC_MAC SSL_USE_OPENSSL FEATURE_ENABLE_SSL HAVE_SRTP HAVE_OPENSSL_SSL_H SCTP_PROCESS_LEVEL_LOCKS SCTP_SIMPLE_ALLOCATOR SCTP_USE_OPENSSL_SHA1 __Userspace__ HAVE_SA_LEN HAVE_SCONN_LEN __APPLE_USE_RFC_2292 __Userspace_os_Darwin NON_WINDOWS_DEFINE HAVE_WEBRTC_VIDEO HAVE_WEBRTC_VOICE WEBRTC_INTELLIGIBILITY_ENHANCER=0 WEBRTC_APM_DEBUG_DUMP=0 WEBRTC_NS_FLOAT WEBRTC_USE_BUILTIN_ILBC WEBRTC_CODEC_ILBC WEBRTC_USE_BUILTIN_OPUS WEBRTC_CODEC_OPUS WEBRTC_CODEC_ISAC WEBRTC_CODEC_RED RTC_DISABLE_VP9 RTC_DISABLE_VP8 HAVE_STDINT_H HAVE_STDLIB_H HAVE_UINT64_T OPENSSL HAVE_CONFIG_H WEBRTC_WEBKIT_BUILD HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE HAVE_SCTP WEBRTC_CODEC_G711 WEBRTC_CODEC_G722 WEBRTC_OPUS_VARIABLE_COMPLEXITY=0 WEBRTC_USE_BUILTIN_ISAC_FIX=1 WEBRTC_USE_BUILTIN_ISAC_FLOAT=0 USE_BUILTIN_SW_CODECS $(inherited); > > GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*] = $(inherited) WEBRTC_USE_VTB_HARDWARE_ENCODER; > GCC_PREPROCESSOR_DEFINITIONS[sdk=iphoneos*] = $(inherited) WEBRTC_IOS; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/ABSEIL_ISSUE_TEMPLATE.md b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/ABSEIL_ISSUE_TEMPLATE.md >new file mode 100644 >index 00000000000..ed5461f166c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/ABSEIL_ISSUE_TEMPLATE.md >@@ -0,0 +1,22 @@ >+Please submit a new Abseil Issue using the template below: >+ >+## [Short title of proposed API change(s)] >+ >+-------------------------------------------------------------------------------- >+-------------------------------------------------------------------------------- >+ >+## Background >+ >+[Provide the background information that is required in order to evaluate the >+proposed API changes. No controversial claims should be made here. If there are >+design constraints that need to be considered, they should be presented here >+**along with justification for those constraints**. Linking to other docs is >+good, but please keep the **pertinent information as self contained** as >+possible in this section.] >+ >+## Proposed API Change (s) >+ >+[Please clearly describe the API change(s) being proposed. If multiple changes, >+please keep them clearly distinguished. When possible, **use example code >+snippets to illustrate before-after API usages**. List pros-n-cons. Highlight >+the main questions that you want to be answered. Given the Abseil project compatibility requirements, describe why the API change is safe.] >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/AUTHORS b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/AUTHORS >new file mode 100644 >index 00000000000..976d31defc2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/AUTHORS >@@ -0,0 +1,6 @@ >+# This is the list of Abseil authors for copyright purposes. >+# >+# This does not necessarily list everyone who has contributed code, since in >+# some cases, their employer may be the copyright holder. To see the full list >+# of contributors, see the revision history in source control. >+Google Inc. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/BUILD.gn >new file mode 100644 >index 00000000000..253a602e2f1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/BUILD.gn >@@ -0,0 +1,77 @@ >+# Copyright (c) 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+# Flags specified here must not impact ABI. Code compiled with and without these >+# opts will be linked together, and in some cases headers compiled with and >+# without these options will be part of the same program. >+ >+import("//build/toolchain/toolchain.gni") >+ >+group("default") { >+ deps = [ >+ "absl/types:any", >+ "absl/types:bad_any_cast", >+ "absl/types:span", >+ "absl/types:optional", >+ "absl/types:bad_optional_access", >+ ] >+} >+ >+config("absl_include_config") { >+ include_dirs = [ "." ] >+} >+ >+config("absl_define_config") { >+ defines = [ "ABSL_ALLOCATOR_NOTHROW=1" ] >+} >+ >+config("absl_default_cflags_cc") { >+ cflags_cc = [] >+ if (is_clang) { >+ cflags_cc += [ >+ # TODO(crbug.com/588506): Explicitly enable conversion warnings. >+ "-Wbool-conversion", >+ "-Wconstant-conversion", >+ "-Wenum-conversion", >+ "-Wint-conversion", >+ "-Wliteral-conversion", >+ "-Wnon-literal-null-conversion", >+ "-Wnull-conversion", >+ "-Wobjc-literal-conversion", >+ "-Wno-sign-conversion", >+ "-Wstring-conversion", >+ ] >+ if (!is_nacl && !use_xcode_clang) { >+ cflags_cc += [ "-Wbitfield-enum-conversion" ] >+ } >+ } >+ if (is_win) { >+ cflags_cc += [ >+ "/wd4005", # macro-redefinition >+ "/wd4018", # sign-compare >+ "/wd4068", # unknown pragma >+ "/wd4702", # unreachable code >+ ] >+ } >+} >+ >+config("absl_test_cflags_cc") { >+ cflags_cc = [] >+ if (is_clang || !is_win) { >+ cflags_cc += [ >+ "-Wno-conversion-null", >+ "-Wno-missing-declarations", >+ "-Wno-sign-compare", >+ "-Wno-unused-function", >+ "-Wno-unused-parameter", >+ "-Wno-unused-private-field", >+ ] >+ } >+ if (is_win) { >+ cflags_cc += [ >+ "/wd4018", # signed/unsigned mismatch >+ "/wd4101", # unreferenced local variable >+ ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/AbseilHelpers.cmake b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/AbseilHelpers.cmake >new file mode 100644 >index 00000000000..e4eafe49e47 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/AbseilHelpers.cmake >@@ -0,0 +1,170 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+include(CMakeParseArguments) >+ >+# The IDE folder for Abseil that will be used if Abseil is included in a CMake >+# project that sets >+# set_property(GLOBAL PROPERTY USE_FOLDERS ON) >+# For example, Visual Studio supports folders. >+set(ABSL_IDE_FOLDER Abseil) >+ >+# >+# create a library in the absl namespace >+# >+# parameters >+# SOURCES : sources files for the library >+# PUBLIC_LIBRARIES: targets and flags for linking phase >+# PRIVATE_COMPILE_FLAGS: compile flags for the library. Will not be exported. >+# EXPORT_NAME: export name for the absl:: target export >+# TARGET: target name >+# >+# create a target associated to <NAME> >+# libraries are installed under CMAKE_INSTALL_FULL_LIBDIR by default >+# >+function(absl_library) >+ cmake_parse_arguments(ABSL_LIB >+ "DISABLE_INSTALL" # keep that in case we want to support installation one day >+ "TARGET;EXPORT_NAME" >+ "SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS" >+ ${ARGN} >+ ) >+ >+ set(_NAME ${ABSL_LIB_TARGET}) >+ string(TOUPPER ${_NAME} _UPPER_NAME) >+ >+ add_library(${_NAME} STATIC ${ABSL_LIB_SOURCES}) >+ >+ target_compile_options(${_NAME} PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_LIB_PRIVATE_COMPILE_FLAGS}) >+ target_link_libraries(${_NAME} PUBLIC ${ABSL_LIB_PUBLIC_LIBRARIES}) >+ target_include_directories(${_NAME} >+ PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_LIB_PUBLIC_INCLUDE_DIRS} >+ PRIVATE ${ABSL_LIB_PRIVATE_INCLUDE_DIRS} >+ ) >+ # Add all Abseil targets to a a folder in the IDE for organization. >+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) >+ >+ if(ABSL_LIB_EXPORT_NAME) >+ add_library(absl::${ABSL_LIB_EXPORT_NAME} ALIAS ${_NAME}) >+ endif() >+endfunction() >+ >+ >+ >+# >+# header only virtual target creation >+# >+function(absl_header_library) >+ cmake_parse_arguments(ABSL_HO_LIB >+ "DISABLE_INSTALL" >+ "EXPORT_NAME;TARGET" >+ "PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS;PRIVATE_INCLUDE_DIRS" >+ ${ARGN} >+ ) >+ >+ set(_NAME ${ABSL_HO_LIB_TARGET}) >+ >+ set(__dummy_header_only_lib_file "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}_header_only_dummy.cc") >+ >+ if(NOT EXISTS ${__dummy_header_only_lib_file}) >+ file(WRITE ${__dummy_header_only_lib_file} >+ "/* generated file for header-only cmake target */ >+ >+ namespace absl { >+ >+ // single meaningless symbol >+ void ${_NAME}__header_fakesym() {} >+ } // namespace absl >+ " >+ ) >+ endif() >+ >+ >+ add_library(${_NAME} ${__dummy_header_only_lib_file}) >+ target_link_libraries(${_NAME} PUBLIC ${ABSL_HO_LIB_PUBLIC_LIBRARIES}) >+ target_include_directories(${_NAME} >+ PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_HO_LIB_PUBLIC_INCLUDE_DIRS} >+ PRIVATE ${ABSL_HO_LIB_PRIVATE_INCLUDE_DIRS} >+ ) >+ >+ # Add all Abseil targets to a a folder in the IDE for organization. >+ set_property(TARGET ${_NAME} PROPERTY FOLDER ${ABSL_IDE_FOLDER}) >+ >+ if(ABSL_HO_LIB_EXPORT_NAME) >+ add_library(absl::${ABSL_HO_LIB_EXPORT_NAME} ALIAS ${_NAME}) >+ endif() >+ >+endfunction() >+ >+ >+# >+# create an abseil unit_test and add it to the executed test list >+# >+# parameters >+# TARGET: target name prefix >+# SOURCES: sources files for the tests >+# PUBLIC_LIBRARIES: targets and flags for linking phase. >+# PRIVATE_COMPILE_FLAGS: compile flags for the test. Will not be exported. >+# >+# create a target associated to <NAME>_bin >+# >+# all tests will be register for execution with add_test() >+# >+# test compilation and execution is disable when BUILD_TESTING=OFF >+# >+function(absl_test) >+ >+ cmake_parse_arguments(ABSL_TEST >+ "" >+ "TARGET" >+ "SOURCES;PUBLIC_LIBRARIES;PRIVATE_COMPILE_FLAGS;PUBLIC_INCLUDE_DIRS" >+ ${ARGN} >+ ) >+ >+ >+ if(BUILD_TESTING) >+ >+ set(_NAME ${ABSL_TEST_TARGET}) >+ string(TOUPPER ${_NAME} _UPPER_NAME) >+ >+ add_executable(${_NAME}_bin ${ABSL_TEST_SOURCES}) >+ >+ target_compile_options(${_NAME}_bin PRIVATE ${ABSL_COMPILE_CXXFLAGS} ${ABSL_TEST_PRIVATE_COMPILE_FLAGS}) >+ target_link_libraries(${_NAME}_bin PUBLIC ${ABSL_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COMMON_LIBRARIES}) >+ target_include_directories(${_NAME}_bin >+ PUBLIC ${ABSL_COMMON_INCLUDE_DIRS} ${ABSL_TEST_PUBLIC_INCLUDE_DIRS} >+ PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} >+ ) >+ >+ # Add all Abseil targets to a a folder in the IDE for organization. >+ set_property(TARGET ${_NAME}_bin PROPERTY FOLDER ${ABSL_IDE_FOLDER}) >+ >+ add_test(${_NAME} ${_NAME}_bin) >+ endif(BUILD_TESTING) >+ >+endfunction() >+ >+ >+ >+ >+function(check_target my_target) >+ >+ if(NOT TARGET ${my_target}) >+ message(FATAL_ERROR " ABSL: compiling absl requires a ${my_target} CMake target in your project, >+ see CMake/README.md for more details") >+ endif(NOT TARGET ${my_target}) >+ >+endfunction() >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/CMakeLists.txt.in b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/CMakeLists.txt.in >new file mode 100644 >index 00000000000..d60a33e9ac6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/CMakeLists.txt.in >@@ -0,0 +1,15 @@ >+cmake_minimum_required(VERSION 2.8.2) >+ >+project(googletest-download NONE) >+ >+include(ExternalProject) >+ExternalProject_Add(googletest >+ GIT_REPOSITORY https://github.com/google/googletest.git >+ GIT_TAG master >+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" >+ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build" >+ CONFIGURE_COMMAND "" >+ BUILD_COMMAND "" >+ INSTALL_COMMAND "" >+ TEST_COMMAND "" >+) >\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/DownloadGTest.cmake b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/DownloadGTest.cmake >new file mode 100644 >index 00000000000..9d4132158b8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/DownloadGTest.cmake >@@ -0,0 +1,32 @@ >+# Downloads and unpacks googletest at configure time. Based on the instructions >+# at https://github.com/google/googletest/tree/master/googletest#incorporating-into-an-existing-cmake-project >+ >+# Download the latest googletest from Github master >+configure_file( >+ ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in >+ googletest-download/CMakeLists.txt >+) >+ >+# Configure and build the downloaded googletest source >+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . >+ RESULT_VARIABLE result >+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download ) >+if(result) >+ message(FATAL_ERROR "CMake step for googletest failed: ${result}") >+endif() >+ >+execute_process(COMMAND ${CMAKE_COMMAND} --build . >+ RESULT_VARIABLE result >+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download) >+if(result) >+ message(FATAL_ERROR "Build step for googletest failed: ${result}") >+endif() >+ >+# Prevent overriding the parent project's compiler/linker settings on Windows >+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) >+ >+# Add googletest directly to our build. This defines the gtest and gtest_main >+# targets. >+add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src >+ ${CMAKE_BINARY_DIR}/googletest-build >+ EXCLUDE_FROM_ALL) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/README.md b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/README.md >new file mode 100644 >index 00000000000..79bbe24d5ad >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMake/README.md >@@ -0,0 +1,107 @@ >+# Abseil CMake Build Instructions >+ >+Abseil comes with a CMake build script ([CMakeLists.txt](../CMakeLists.txt)) >+that can be used on a wide range of platforms ("C" stands for cross-platform.). >+If you don't have CMake installed already, you can download it for free from >+<http://www.cmake.org/>. >+ >+CMake works by generating native makefiles or build projects that can >+be used in the compiler environment of your choice. >+ >+For API/ABI compatibility reasons, we strongly recommend building Abseil in a >+subdirectory of your project or as an embedded dependency. >+ >+## Incorporating Abseil Into a CMake Project >+ >+The recommendations below are similar to those for using CMake within the >+googletest framework >+(<https://github.com/google/googletest/blob/master/googletest/README.md#incorporating-into-an-existing-cmake-project>) >+ >+### Step-by-Step Instructions >+ >+1. If you want to build the Abseil tests, integrate the Abseil dependency >+[Google Test](https://github.com/google/googletest) into your CMake project. To disable Abseil tests, you have to pass >+`-DBUILD_TESTING=OFF` when configuring your project with CMake. >+ >+2. Download Abseil and copy it into a subdirectory in your CMake project or add >+Abseil as a [git submodule](https://git-scm.com/docs/git-submodule) in your >+CMake project. >+ >+3. You can then use the CMake command >+[`add_subdirectory()`](https://cmake.org/cmake/help/latest/command/add_subdirectory.html) >+to include Abseil directly in your CMake project. >+ >+4. Add the **absl::** target you wish to use to the >+[`target_link_libraries()`](https://cmake.org/cmake/help/latest/command/target_link_libraries.html) >+section of your executable or of your library.<br> >+Here is a short CMakeLists.txt example of a project file using Abseil. >+ >+```cmake >+cmake_minimum_required(VERSION 2.8.12) >+project(my_project) >+ >+set(CMAKE_CXX_FLAGS "-std=c++11 -stdlib=libc++ ${CMAKE_CXX_FLAGS}") >+ >+if(MSVC) >+ # /wd4005 macro-redefinition >+ # /wd4068 unknown pragma >+ # /wd4244 conversion from 'type1' to 'type2' >+ # /wd4267 conversion from 'size_t' to 'type2' >+ # /wd4800 force value to bool 'true' or 'false' (performance warning) >+ add_compile_options(/wd4005 /wd4068 /wd4244 /wd4267 /wd4800) >+ add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS) >+endif() >+ >+add_subdirectory(abseil-cpp) >+ >+add_executable(my_exe source.cpp) >+target_link_libraries(my_exe absl::base absl::synchronization absl::strings) >+``` >+ >+### Running Abseil Tests with CMake >+ >+Use the `-DABSL_RUN_TESTS=ON` flag to run Abseil tests. Note that if the `-DBUILD_TESTING=OFF` flag is passed then Abseil tests will not be run. >+ >+You will need to provide Abseil with a Googletest dependency. There are two >+options for how to do this: >+ >+* Use `-DABSL_USE_GOOGLETEST_HEAD`. This will automatically download the latest >+Googletest source into the build directory at configure time. Googletest will >+then be compiled directly alongside Abseil's tests. >+* Manually integrate Googletest with your build. See >+https://github.com/google/googletest/blob/master/googletest/README.md#using-cmake >+for more information on using Googletest in a CMake project. >+ >+For example, to run just the Abseil tests, you could use this script: >+ >+``` >+cd path/to/abseil-cpp >+mkdir build >+cd build >+cmake -DABSL_USE_GOOGLETEST_HEAD=ON -DABSL_RUN_TESTS=ON .. >+make -j >+ctest >+``` >+ >+Currently, we only run our tests with CMake in a Linux environment, but we are >+working on the rest of our supported platforms. See >+https://github.com/abseil/abseil-cpp/projects/1 and >+https://github.com/abseil/abseil-cpp/issues/109 for more information. >+ >+### Available Abseil CMake Public Targets >+ >+Here's a non-exhaustive list of Abseil CMake public targets: >+ >+```cmake >+absl::base >+absl::algorithm >+absl::container >+absl::debugging >+absl::memory >+absl::meta >+absl::numeric >+absl::strings >+absl::synchronization >+absl::time >+absl::utility >+``` >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMakeLists.txt >new file mode 100644 >index 00000000000..89a3386f7e2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CMakeLists.txt >@@ -0,0 +1,98 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+# We require 3.0 for modern, target-based CMake. We require 3.1 for the use of >+# CXX_STANDARD in our targets. >+cmake_minimum_required(VERSION 3.1) >+project(absl) >+ >+list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake) >+ >+include(GNUInstallDirs) >+include(AbseilHelpers) >+ >+ >+# config options >+if (MSVC) >+ # /wd4005 macro-redefinition >+ # /wd4068 unknown pragma >+ # /wd4244 conversion from 'type1' to 'type2' >+ # /wd4267 conversion from 'size_t' to 'type2' >+ # /wd4800 force value to bool 'true' or 'false' (performance warning) >+ add_compile_options(/W3 /WX /wd4005 /wd4068 /wd4244 /wd4267 /wd4800) >+ add_definitions(/DNOMINMAX /DWIN32_LEAN_AND_MEAN=1 /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS) >+else() >+ set(ABSL_STD_CXX_FLAG "-std=c++11" CACHE STRING "c++ std flag (default: c++11)") >+endif() >+ >+ >+ >+## >+## Using absl targets >+## >+## all public absl targets are >+## exported with the absl:: prefix >+## >+## e.g absl::base absl::synchronization absl::strings .... >+## >+## DO NOT rely on the internal targets outside of the prefix >+ >+ >+# include current path >+list(APPEND ABSL_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) >+ >+# -std=X >+set(CMAKE_CXX_FLAGS "${ABSL_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}") >+ >+# -fexceptions >+set(ABSL_EXCEPTIONS_FLAG "${CMAKE_CXX_EXCEPTIONS}") >+ >+# find dependencies >+## pthread >+find_package(Threads REQUIRED) >+ >+option(ABSL_USE_GOOGLETEST_HEAD >+ "If ON, abseil will download HEAD from googletest at config time." OFF) >+ >+option(ABSL_RUN_TESTS "If ON, Abseil tests will be run." OFF) >+ >+if(${ABSL_RUN_TESTS}) >+ # enable CTest. This will set BUILD_TESTING to ON unless otherwise specified >+ # on the command line >+ include(CTest) >+ enable_testing() >+endif() >+ >+## check targets >+if(BUILD_TESTING) >+ >+ if(${ABSL_USE_GOOGLETEST_HEAD}) >+ include(CMake/DownloadGTest.cmake) >+ endif() >+ >+ check_target(gtest) >+ check_target(gtest_main) >+ check_target(gmock) >+ >+ list(APPEND ABSL_TEST_COMMON_LIBRARIES >+ gtest_main >+ gtest >+ gmock >+ ${CMAKE_THREAD_LIBS_INIT} >+ ) >+endif() >+ >+add_subdirectory(absl) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CONTRIBUTING.md b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CONTRIBUTING.md >new file mode 100644 >index 00000000000..40351ddcfaa >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/CONTRIBUTING.md >@@ -0,0 +1,91 @@ >+# How to Contribute to Abseil >+ >+We'd love to accept your patches and contributions to this project. There are >+just a few small guidelines you need to follow. >+ >+NOTE: If you are new to GitHub, please start by reading [Pull Request >+howto](https://help.github.com/articles/about-pull-requests/) >+ >+## Contributor License Agreement >+ >+Contributions to this project must be accompanied by a Contributor License >+Agreement. You (or your employer) retain the copyright to your contribution, >+this simply gives us permission to use and redistribute your contributions as >+part of the project. Head over to <https://cla.developers.google.com/> to see >+your current agreements on file or to sign a new one. >+ >+You generally only need to submit a CLA once, so if you've already submitted one >+(even if it was for a different project), you probably don't need to do it >+again. >+ >+## Coding Style >+ >+To keep the source consistent, readable, diffable and easy to merge, we use a >+fairly rigid coding style, as defined by the >+[google-styleguide](https://github.com/google/styleguide) project. All patches >+will be expected to conform to the style outlined >+[here](https://google.github.io/styleguide/cppguide.html). >+ >+## Guidelines for Pull Requests >+ >+* If you are a Googler, it is preferable to first create an internal CL and >+ have it reviewed and submitted. The code propagation process will deliver >+ the change to GitHub. >+ >+* Create **small PRs** that are narrowly focused on **addressing a single >+ concern**. We often receive PRs that are trying to fix several things at a >+ time, but if only one fix is considered acceptable, nothing gets merged and >+ both author's & review's time is wasted. Create more PRs to address >+ different concerns and everyone will be happy. >+ >+* For speculative changes, consider opening an [Abseil >+ issue](https://github.com/abseil/abseil-cpp/issues) and discussing it first. >+ If you are suggesting a behavioral or API change, consider starting with an >+ [Abseil proposal template](ABSEIL_ISSUE_TEMPLATE.md). >+ >+* Provide a good **PR description** as a record of **what** change is being >+ made and **why** it was made. Link to a GitHub issue if it exists. >+ >+* Don't fix code style and formatting unless you are already changing that >+ line to address an issue. Formatting of modified lines may be done using >+ `git clang-format`. PRs with irrelevant changes won't be merged. If >+ you do want to fix formatting or style, do that in a separate PR. >+ >+* Unless your PR is trivial, you should expect there will be reviewer comments >+ that you'll need to address before merging. We expect you to be reasonably >+ responsive to those comments, otherwise the PR will be closed after 2-3 >+ weeks of inactivity. >+ >+* Maintain **clean commit history** and use **meaningful commit messages**. >+ PRs with messy commit history are difficult to review and won't be merged. >+ Use `rebase -i upstream/master` to curate your commit history and/or to >+ bring in latest changes from master (but avoid rebasing in the middle of a >+ code review). >+ >+* Keep your PR up to date with upstream/master (if there are merge conflicts, >+ we can't really merge your change). >+ >+* **All tests need to be passing** before your change can be merged. We >+ recommend you **run tests locally** (see below) >+ >+* Exceptions to the rules can be made if there's a compelling reason for doing >+ so. That is - the rules are here to serve us, not the other way around, and >+ the rules need to be serving their intended purpose to be valuable. >+ >+* All submissions, including submissions by project members, require review. >+ >+## Running Tests >+ >+Use "bazel test <>" functionality to run the unit tests. >+ >+Prerequisites for building and running tests are listed in >+[README.md](README.md) >+ >+## Abseil Committers >+ >+The current members of the Abseil engineering team are the only committers at >+present. >+ >+## Release Process >+ >+Abseil lives at head, where latest-and-greatest code can be found. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LICENSE b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LICENSE >new file mode 100644 >index 00000000000..fef7d967815 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LICENSE >@@ -0,0 +1,204 @@ >+ >+ Apache License >+ Version 2.0, January 2004 >+ http://www.apache.org/licenses/ >+ >+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION >+ >+ 1. Definitions. >+ >+ "License" shall mean the terms and conditions for use, reproduction, >+ and distribution as defined by Sections 1 through 9 of this document. >+ >+ "Licensor" shall mean the copyright owner or entity authorized by >+ the copyright owner that is granting the License. >+ >+ "Legal Entity" shall mean the union of the acting entity and all >+ other entities that control, are controlled by, or are under common >+ control with that entity. For the purposes of this definition, >+ "control" means (i) the power, direct or indirect, to cause the >+ direction or management of such entity, whether by contract or >+ otherwise, or (ii) ownership of fifty percent (50%) or more of the >+ outstanding shares, or (iii) beneficial ownership of such entity. >+ >+ "You" (or "Your") shall mean an individual or Legal Entity >+ exercising permissions granted by this License. >+ >+ "Source" form shall mean the preferred form for making modifications, >+ including but not limited to software source code, documentation >+ source, and configuration files. >+ >+ "Object" form shall mean any form resulting from mechanical >+ transformation or translation of a Source form, including but >+ not limited to compiled object code, generated documentation, >+ and conversions to other media types. >+ >+ "Work" shall mean the work of authorship, whether in Source or >+ Object form, made available under the License, as indicated by a >+ copyright notice that is included in or attached to the work >+ (an example is provided in the Appendix below). >+ >+ "Derivative Works" shall mean any work, whether in Source or Object >+ form, that is based on (or derived from) the Work and for which the >+ editorial revisions, annotations, elaborations, or other modifications >+ represent, as a whole, an original work of authorship. For the purposes >+ of this License, Derivative Works shall not include works that remain >+ separable from, or merely link (or bind by name) to the interfaces of, >+ the Work and Derivative Works thereof. >+ >+ "Contribution" shall mean any work of authorship, including >+ the original version of the Work and any modifications or additions >+ to that Work or Derivative Works thereof, that is intentionally >+ submitted to Licensor for inclusion in the Work by the copyright owner >+ or by an individual or Legal Entity authorized to submit on behalf of >+ the copyright owner. For the purposes of this definition, "submitted" >+ means any form of electronic, verbal, or written communication sent >+ to the Licensor or its representatives, including but not limited to >+ communication on electronic mailing lists, source code control systems, >+ and issue tracking systems that are managed by, or on behalf of, the >+ Licensor for the purpose of discussing and improving the Work, but >+ excluding communication that is conspicuously marked or otherwise >+ designated in writing by the copyright owner as "Not a Contribution." >+ >+ "Contributor" shall mean Licensor and any individual or Legal Entity >+ on behalf of whom a Contribution has been received by Licensor and >+ subsequently incorporated within the Work. >+ >+ 2. Grant of Copyright License. Subject to the terms and conditions of >+ this License, each Contributor hereby grants to You a perpetual, >+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable >+ copyright license to reproduce, prepare Derivative Works of, >+ publicly display, publicly perform, sublicense, and distribute the >+ Work and such Derivative Works in Source or Object form. >+ >+ 3. Grant of Patent License. Subject to the terms and conditions of >+ this License, each Contributor hereby grants to You a perpetual, >+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable >+ (except as stated in this section) patent license to make, have made, >+ use, offer to sell, sell, import, and otherwise transfer the Work, >+ where such license applies only to those patent claims licensable >+ by such Contributor that are necessarily infringed by their >+ Contribution(s) alone or by combination of their Contribution(s) >+ with the Work to which such Contribution(s) was submitted. If You >+ institute patent litigation against any entity (including a >+ cross-claim or counterclaim in a lawsuit) alleging that the Work >+ or a Contribution incorporated within the Work constitutes direct >+ or contributory patent infringement, then any patent licenses >+ granted to You under this License for that Work shall terminate >+ as of the date such litigation is filed. >+ >+ 4. Redistribution. You may reproduce and distribute copies of the >+ Work or Derivative Works thereof in any medium, with or without >+ modifications, and in Source or Object form, provided that You >+ meet the following conditions: >+ >+ (a) You must give any other recipients of the Work or >+ Derivative Works a copy of this License; and >+ >+ (b) You must cause any modified files to carry prominent notices >+ stating that You changed the files; and >+ >+ (c) You must retain, in the Source form of any Derivative Works >+ that You distribute, all copyright, patent, trademark, and >+ attribution notices from the Source form of the Work, >+ excluding those notices that do not pertain to any part of >+ the Derivative Works; and >+ >+ (d) If the Work includes a "NOTICE" text file as part of its >+ distribution, then any Derivative Works that You distribute must >+ include a readable copy of the attribution notices contained >+ within such NOTICE file, excluding those notices that do not >+ pertain to any part of the Derivative Works, in at least one >+ of the following places: within a NOTICE text file distributed >+ as part of the Derivative Works; within the Source form or >+ documentation, if provided along with the Derivative Works; or, >+ within a display generated by the Derivative Works, if and >+ wherever such third-party notices normally appear. The contents >+ of the NOTICE file are for informational purposes only and >+ do not modify the License. You may add Your own attribution >+ notices within Derivative Works that You distribute, alongside >+ or as an addendum to the NOTICE text from the Work, provided >+ that such additional attribution notices cannot be construed >+ as modifying the License. >+ >+ You may add Your own copyright statement to Your modifications and >+ may provide additional or different license terms and conditions >+ for use, reproduction, or distribution of Your modifications, or >+ for any such Derivative Works as a whole, provided Your use, >+ reproduction, and distribution of the Work otherwise complies with >+ the conditions stated in this License. >+ >+ 5. Submission of Contributions. Unless You explicitly state otherwise, >+ any Contribution intentionally submitted for inclusion in the Work >+ by You to the Licensor shall be under the terms and conditions of >+ this License, without any additional terms or conditions. >+ Notwithstanding the above, nothing herein shall supersede or modify >+ the terms of any separate license agreement you may have executed >+ with Licensor regarding such Contributions. >+ >+ 6. Trademarks. This License does not grant permission to use the trade >+ names, trademarks, service marks, or product names of the Licensor, >+ except as required for reasonable and customary use in describing the >+ origin of the Work and reproducing the content of the NOTICE file. >+ >+ 7. Disclaimer of Warranty. Unless required by applicable law or >+ agreed to in writing, Licensor provides the Work (and each >+ Contributor provides its Contributions) on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or >+ implied, including, without limitation, any warranties or conditions >+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A >+ PARTICULAR PURPOSE. You are solely responsible for determining the >+ appropriateness of using or redistributing the Work and assume any >+ risks associated with Your exercise of permissions under this License. >+ >+ 8. Limitation of Liability. In no event and under no legal theory, >+ whether in tort (including negligence), contract, or otherwise, >+ unless required by applicable law (such as deliberate and grossly >+ negligent acts) or agreed to in writing, shall any Contributor be >+ liable to You for damages, including any direct, indirect, special, >+ incidental, or consequential damages of any character arising as a >+ result of this License or out of the use or inability to use the >+ Work (including but not limited to damages for loss of goodwill, >+ work stoppage, computer failure or malfunction, or any and all >+ other commercial damages or losses), even if such Contributor >+ has been advised of the possibility of such damages. >+ >+ 9. Accepting Warranty or Additional Liability. While redistributing >+ the Work or Derivative Works thereof, You may choose to offer, >+ and charge a fee for, acceptance of support, warranty, indemnity, >+ or other liability obligations and/or rights consistent with this >+ License. However, in accepting such obligations, You may act only >+ on Your own behalf and on Your sole responsibility, not on behalf >+ of any other Contributor, and only if You agree to indemnify, >+ defend, and hold each Contributor harmless for any liability >+ incurred by, or claims asserted against, such Contributor by reason >+ of your accepting any such warranty or additional liability. >+ >+ END OF TERMS AND CONDITIONS >+ >+ APPENDIX: How to apply the Apache License to your work. >+ >+ To apply the Apache License to your work, attach the following >+ boilerplate notice, with the fields enclosed by brackets "[]" >+ replaced with your own identifying information. (Don't include >+ the brackets!) The text should be enclosed in the appropriate >+ comment syntax for the file format. We also recommend that a >+ file or class name and description of purpose be included on the >+ same "printed page" as the copyright notice for easier >+ identification within third-party archives. >+ >+ Copyright [yyyy] [name of copyright owner] >+ >+ Licensed under the Apache License, Version 2.0 (the "License"); >+ you may not use this file except in compliance with the License. >+ You may obtain a copy of the License at >+ >+ http://www.apache.org/licenses/LICENSE-2.0 >+ >+ Unless required by applicable law or agreed to in writing, software >+ distributed under the License is distributed on an "AS IS" BASIS, >+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ See the License for the specific language governing permissions and >+ limitations under the License. >+ >+ >\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LTS.md b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LTS.md >new file mode 100644 >index 00000000000..385b4f062bf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/LTS.md >@@ -0,0 +1,13 @@ >+# Long Term Support (LTS) Branches >+ >+This repository contains periodic snapshots of the Abseil codebase that are >+Long Term Support (LTS) branches. An LTS branch allows you to use a known >+version of Abseil without interfering with other projects which may also, in >+turn, use Abseil. (For more information about our releases, see the >+[Abseil Release Management](https://abseil.io/about/releases) guide.) >+ >+## LTS Branches >+ >+The following lists LTS branches and the dates on which they have been released: >+ >+* [LTS Branch June 20, 2018](https://github.com/abseil/abseil-cpp/tree/lts_2018_06_20/) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/OWNERS b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/OWNERS >new file mode 100644 >index 00000000000..ceca4a8ba2c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/OWNERS >@@ -0,0 +1,2 @@ >+mbonadei@chromium.org >+phoglund@chromium.org >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.chromium b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.chromium >new file mode 100644 >index 00000000000..91d6d381a47 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.chromium >@@ -0,0 +1,34 @@ >+Name: Abseil >+Short Name: absl >+URL: https://github.com/abseil/abseil-cpp >+License: Apache 2.0 >+License File: LICENSE >+Version: 0 >+Revision: bea85b52733022294eef108a2e42d77b616ddca2 >+Security Critical: yes >+ >+Description: >+This directory contains the source code of Abseil for C++. This can be used by >+Chromium's dependencies, but shouldn't be used by Chromium itself. >+See: https://goo.gl/TgnJb8. >+ >+How to update Abseil: >+ >+1. Download the code from the Abseil git repository (see URL). >+ >+2. Copy the content of the Abseil git repo to //third_party/abseil-cpp. >+ >+3. From //third_party/abseil-cpp/ launch ./rename_dynamic_annotations.sh. >+ This script will rewrite dynamic_annotations macros and function inside >+ Abseil in order to avoid ODR violations and macro clashing with Chromium >+ (see: https://github.com/abseil/abseil-cpp/issues/122). >+ >+Local Modifications: >+ >+* absl/copts.bzl has been translated to //third_party/absl-cpp/BUILD.gn. Both >+ files contain lists of compiler flags in order to reduce duplication. >+ >+* All the BUILD.bazel files has been translated to BUILD.gn files. >+ >+* Functions and macros in absl/base/dynamic_annotations.{h,cc} have been renamed >+ to avoid ODR violations (see step 3). >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.md b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.md >new file mode 100644 >index 00000000000..8eed5751bf5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/README.md >@@ -0,0 +1,108 @@ >+# Abseil - C++ Common Libraries >+ >+The repository contains the Abseil C++ library code. Abseil is an open-source >+collection of C++ code (compliant to C++11) designed to augment the C++ >+standard library. >+ >+## Table of Contents >+ >+- [About Abseil](#about) >+- [Quickstart](#quickstart) >+- [Building Abseil](#build) >+- [Codemap](#codemap) >+- [License](#license) >+- [Links](#links) >+ >+<a name="about"></a> >+## About Abseil >+ >+Abseil is an open-source collection of C++ library code designed to augment >+the C++ standard library. The Abseil library code is collected from Google's >+own C++ code base, has been extensively tested and used in production, and >+is the same code we depend on in our daily coding lives. >+ >+In some cases, Abseil provides pieces missing from the C++ standard; in >+others, Abseil provides alternatives to the standard for special needs >+we've found through usage in the Google code base. We denote those cases >+clearly within the library code we provide you. >+ >+Abseil is not meant to be a competitor to the standard library; we've >+just found that many of these utilities serve a purpose within our code >+base, and we now want to provide those resources to the C++ community as >+a whole. >+ >+<a name="quickstart"></a> >+## Quickstart >+ >+If you want to just get started, make sure you at least run through the >+[Abseil Quickstart](https://abseil.io/docs/cpp/quickstart). The Quickstart >+contains information about setting up your development environment, downloading >+the Abseil code, running tests, and getting a simple binary working. >+ >+<a name="build"></a> >+## Building Abseil >+ >+[Bazel](http://bazel.build) is the official build system for Abseil, >+which is supported on most major platforms (Linux, Windows, MacOS, for example) >+and compilers. See the [quickstart](https://abseil.io/docs/cpp/quickstart) for >+more information on building Abseil using the Bazel build system. >+ >+<a name="cmake"></a> >+If you require CMake support, please check the >+[CMake build instructions](CMake/README.md). >+ >+## Codemap >+ >+Abseil contains the following C++ library components: >+ >+* [`base`](absl/base/) Abseil Fundamentals >+ <br /> The `base` library contains initialization code and other code which >+ all other Abseil code depends on. Code within `base` may not depend on any >+ other code (other than the C++ standard library). >+* [`algorithm`](absl/algorithm/) >+ <br /> The `algorithm` library contains additions to the C++ `<algorithm>` >+ library and container-based versions of such algorithms. >+* [`container`](absl/container/) >+ <br /> The `container` library contains additional STL-style containers. >+* [`debugging`](absl/debugging/) >+ <br /> The `debugging` library contains code useful for enabling leak >+ checks. Future updates will add stacktrace and symbolization utilities. >+* [`memory`](absl/memory/) >+ <br /> The `memory` library contains C++11-compatible versions of >+ `std::make_unique()` and related memory management facilities. >+* [`meta`](absl/meta/) >+ <br /> The `meta` library contains C++11-compatible versions of type checks >+ available within C++14 and C++17 versions of the C++ `<type_traits>` library. >+* [`numeric`](absl/numeric/) >+ <br /> The `numeric` library contains C++11-compatible 128-bit integers. >+* [`strings`](absl/strings/) >+ <br /> The `strings` library contains a variety of strings routines and >+ utilities, including a C++11-compatible version of the C++17 >+ `std::string_view` type. >+* [`synchronization`](absl/synchronization/) >+ <br /> The `synchronization` library contains concurrency primitives (Abseil's >+ `absl::Mutex` class, an alternative to `std::mutex`) and a variety of >+ synchronization abstractions. >+* [`time`](absl/time/) >+ <br /> The `time` library contains abstractions for computing with absolute >+ points in time, durations of time, and formatting and parsing time within >+ time zones. >+* [`types`](absl/types/) >+ <br /> The `types` library contains non-container utility types, like a >+ C++11-compatible version of the C++17 `std::optional` type. >+ >+## License >+ >+The Abseil C++ library is licensed under the terms of the Apache >+license. See [LICENSE](LICENSE) for more information. >+ >+## Links >+ >+For more information about Abseil: >+ >+* Consult our [Abseil Introduction](http://abseil.io/about/intro) >+* Read [Why Adopt Abseil](http://abseil.io/about/philosophy) to understand our >+ design philosophy. >+* Peruse our >+ [Abseil Compatibility Guarantees](http://abseil.io/about/compatibility) to >+ understand both what we promise to you, and what we expect of you in return. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/WORKSPACE b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/WORKSPACE >new file mode 100644 >index 00000000000..e4a911978dc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/WORKSPACE >@@ -0,0 +1,29 @@ >+workspace(name = "com_google_absl") >+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") >+ >+# Bazel toolchains >+http_archive( >+ name = "bazel_toolchains", >+ urls = [ >+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/287b64e0a211fb7c23b74695f8d5f5205b61f4eb.tar.gz", >+ "https://github.com/bazelbuild/bazel-toolchains/archive/287b64e0a211fb7c23b74695f8d5f5205b61f4eb.tar.gz", >+ ], >+ strip_prefix = "bazel-toolchains-287b64e0a211fb7c23b74695f8d5f5205b61f4eb", >+ sha256 = "aca8ac6afd7745027ee4a43032b51a725a61a75a30f02cc58681ee87e4dcdf4b", >+) >+ >+# GoogleTest/GoogleMock framework. Used by most unit-tests. >+http_archive( >+ name = "com_google_googletest", >+ urls = ["https://github.com/google/googletest/archive/b4d4438df9479675a632b2f11125e57133822ece.zip"], # 2018-07-16 >+ strip_prefix = "googletest-b4d4438df9479675a632b2f11125e57133822ece", >+ sha256 = "5aaa5d566517cae711e2a3505ea9a6438be1b37fcaae0ebcb96ccba9aa56f23a", >+) >+ >+# Google benchmark. >+http_archive( >+ name = "com_github_google_benchmark", >+ urls = ["https://github.com/google/benchmark/archive/16703ff83c1ae6d53e5155df3bb3ab0bc96083be.zip"], >+ strip_prefix = "benchmark-16703ff83c1ae6d53e5155df3bb3ab0bc96083be", >+ sha256 = "59f918c8ccd4d74b6ac43484467b500f1d64b40cc1010daa055375b322a43ba3", >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/BUILD.bazel >new file mode 100644 >index 00000000000..edd0274c5d8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/BUILD.bazel >@@ -0,0 +1,51 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+load(":compiler_config_setting.bzl", "create_llvm_config") >+ >+create_llvm_config( >+ name = "llvm_compiler", >+ visibility = [":__subpackages__"], >+) >+ >+# following configs are based on mapping defined in: https://git.io/v5Ijz >+config_setting( >+ name = "ios", >+ values = { >+ "cpu": "darwin", >+ }, >+ visibility = [":__subpackages__"], >+) >+ >+config_setting( >+ name = "windows", >+ values = { >+ "cpu": "x64_windows", >+ }, >+ visibility = [":__subpackages__"], >+) >+ >+config_setting( >+ name = "ppc", >+ values = { >+ "cpu": "ppc", >+ }, >+ visibility = [":__subpackages__"], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/CMakeLists.txt >new file mode 100644 >index 00000000000..689f64e258b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/CMakeLists.txt >@@ -0,0 +1,30 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+ >+ >+add_subdirectory(base) >+add_subdirectory(algorithm) >+add_subdirectory(container) >+add_subdirectory(debugging) >+add_subdirectory(memory) >+add_subdirectory(meta) >+add_subdirectory(numeric) >+add_subdirectory(strings) >+add_subdirectory(synchronization) >+add_subdirectory(time) >+add_subdirectory(types) >+add_subdirectory(utility) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.bazel >new file mode 100644 >index 00000000000..d04dc71206e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.bazel >@@ -0,0 +1,81 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "algorithm", >+ hdrs = ["algorithm.h"], >+ copts = ABSL_DEFAULT_COPTS, >+) >+ >+cc_test( >+ name = "algorithm_test", >+ size = "small", >+ srcs = ["algorithm_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":algorithm", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "algorithm_benchmark", >+ srcs = ["equal_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ deps = [ >+ ":algorithm", >+ "//absl/base:core_headers", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_library( >+ name = "container", >+ hdrs = [ >+ "container.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":algorithm", >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ ], >+) >+ >+cc_test( >+ name = "container_test", >+ srcs = ["container_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":container", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "//absl/types:span", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.gn >new file mode 100644 >index 00000000000..37ec665764d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/BUILD.gn >@@ -0,0 +1,44 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("algorithm") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "algorithm.h", >+ ] >+} >+ >+source_set("container") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "container.h", >+ ] >+ deps = [ >+ ":algorithm", >+ "../base:core_headers", >+ "../meta:type_traits", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt >new file mode 100644 >index 00000000000..fdf45c55ed6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/CMakeLists.txt >@@ -0,0 +1,63 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND ALGORITHM_PUBLIC_HEADERS >+ "algorithm.h" >+ "container.h" >+) >+ >+ >+# >+## TESTS >+# >+ >+# test algorithm_test >+list(APPEND ALGORITHM_TEST_SRC >+ "algorithm_test.cc" >+ ${ALGORITHM_PUBLIC_HEADERS} >+ ${ALGORITHM_INTERNAL_HEADERS} >+) >+ >+absl_header_library( >+ TARGET >+ absl_algorithm >+ EXPORT_NAME >+ algorithm >+) >+ >+absl_test( >+ TARGET >+ algorithm_test >+ SOURCES >+ ${ALGORITHM_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl::algorithm >+) >+ >+ >+ >+ >+# test container_test >+set(CONTAINER_TEST_SRC "container_test.cc") >+ >+absl_test( >+ TARGET >+ container_test >+ SOURCES >+ ${CONTAINER_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl::algorithm >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm.h >new file mode 100644 >index 00000000000..3d6586439fe >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm.h >@@ -0,0 +1,150 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: algorithm.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains Google extensions to the standard <algorithm> C++ >+// header. >+ >+#ifndef ABSL_ALGORITHM_ALGORITHM_H_ >+#define ABSL_ALGORITHM_ALGORITHM_H_ >+ >+#include <algorithm> >+#include <iterator> >+#include <type_traits> >+ >+namespace absl { >+ >+namespace algorithm_internal { >+ >+// Performs comparisons with operator==, similar to C++14's `std::equal_to<>`. >+struct EqualTo { >+ template <typename T, typename U> >+ bool operator()(const T& a, const U& b) const { >+ return a == b; >+ } >+}; >+ >+template <typename InputIter1, typename InputIter2, typename Pred> >+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, >+ InputIter2 last2, Pred pred, std::input_iterator_tag, >+ std::input_iterator_tag) { >+ while (true) { >+ if (first1 == last1) return first2 == last2; >+ if (first2 == last2) return false; >+ if (!pred(*first1, *first2)) return false; >+ ++first1; >+ ++first2; >+ } >+} >+ >+template <typename InputIter1, typename InputIter2, typename Pred> >+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, >+ InputIter2 last2, Pred&& pred, std::random_access_iterator_tag, >+ std::random_access_iterator_tag) { >+ return (last1 - first1 == last2 - first2) && >+ std::equal(first1, last1, first2, std::forward<Pred>(pred)); >+} >+ >+// When we are using our own internal predicate that just applies operator==, we >+// forward to the non-predicate form of std::equal. This enables an optimization >+// in libstdc++ that can result in std::memcmp being used for integer types. >+template <typename InputIter1, typename InputIter2> >+bool EqualImpl(InputIter1 first1, InputIter1 last1, InputIter2 first2, >+ InputIter2 last2, algorithm_internal::EqualTo /* unused */, >+ std::random_access_iterator_tag, >+ std::random_access_iterator_tag) { >+ return (last1 - first1 == last2 - first2) && >+ std::equal(first1, last1, first2); >+} >+ >+template <typename It> >+It RotateImpl(It first, It middle, It last, std::true_type) { >+ return std::rotate(first, middle, last); >+} >+ >+template <typename It> >+It RotateImpl(It first, It middle, It last, std::false_type) { >+ std::rotate(first, middle, last); >+ return std::next(first, std::distance(middle, last)); >+} >+ >+} // namespace algorithm_internal >+ >+// Compares the equality of two ranges specified by pairs of iterators, using >+// the given predicate, returning true iff for each corresponding iterator i1 >+// and i2 in the first and second range respectively, pred(*i1, *i2) == true >+// >+// This comparison takes at most min(`last1` - `first1`, `last2` - `first2`) >+// invocations of the predicate. Additionally, if InputIter1 and InputIter2 are >+// both random-access iterators, and `last1` - `first1` != `last2` - `first2`, >+// then the predicate is never invoked and the function returns false. >+// >+// This is a C++11-compatible implementation of C++14 `std::equal`. See >+// http://en.cppreference.com/w/cpp/algorithm/equal for more information. >+template <typename InputIter1, typename InputIter2, typename Pred> >+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, >+ InputIter2 last2, Pred&& pred) { >+ return algorithm_internal::EqualImpl( >+ first1, last1, first2, last2, std::forward<Pred>(pred), >+ typename std::iterator_traits<InputIter1>::iterator_category{}, >+ typename std::iterator_traits<InputIter2>::iterator_category{}); >+} >+ >+// Performs comparison of two ranges specified by pairs of iterators using >+// operator==. >+template <typename InputIter1, typename InputIter2> >+bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, >+ InputIter2 last2) { >+ return absl::equal(first1, last1, first2, last2, >+ algorithm_internal::EqualTo{}); >+} >+ >+// Performs a linear search for `value` using the iterator `first` up to >+// but not including `last`, returning true if [`first`, `last`) contains an >+// element equal to `value`. >+// >+// A linear search is of O(n) complexity which is guaranteed to make at most >+// n = (`last` - `first`) comparisons. A linear search over short containers >+// may be faster than a binary search, even when the container is sorted. >+template <typename InputIterator, typename EqualityComparable> >+bool linear_search(InputIterator first, InputIterator last, >+ const EqualityComparable& value) { >+ return std::find(first, last, value) != last; >+} >+ >+// Performs a left rotation on a range of elements (`first`, `last`) such that >+// `middle` is now the first element. `rotate()` returns an iterator pointing to >+// the first element before rotation. This function is exactly the same as >+// `std::rotate`, but fixes a bug in gcc >+// <= 4.9 where `std::rotate` returns `void` instead of an iterator. >+// >+// The complexity of this algorithm is the same as that of `std::rotate`, but if >+// `ForwardIterator` is not a random-access iterator, then `absl::rotate` >+// performs an additional pass over the range to construct the return value. >+ >+template <typename ForwardIterator> >+ForwardIterator rotate(ForwardIterator first, ForwardIterator middle, >+ ForwardIterator last) { >+ return algorithm_internal::RotateImpl( >+ first, middle, last, >+ std::is_same<decltype(std::rotate(first, middle, last)), >+ ForwardIterator>()); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_ALGORITHM_ALGORITHM_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc >new file mode 100644 >index 00000000000..e4322bc4f20 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/algorithm_test.cc >@@ -0,0 +1,182 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/algorithm/algorithm.h" >+ >+#include <algorithm> >+#include <list> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace { >+ >+TEST(EqualTest, DefaultComparisonRandomAccess) { >+ std::vector<int> v1{1, 2, 3}; >+ std::vector<int> v2 = v1; >+ std::vector<int> v3 = {1, 2}; >+ std::vector<int> v4 = {1, 2, 4}; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); >+} >+ >+TEST(EqualTest, DefaultComparison) { >+ std::list<int> lst1{1, 2, 3}; >+ std::list<int> lst2 = lst1; >+ std::list<int> lst3{1, 2}; >+ std::list<int> lst4{1, 2, 4}; >+ >+ EXPECT_TRUE(absl::equal(lst1.begin(), lst1.end(), lst2.begin(), lst2.end())); >+ EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst3.begin(), lst3.end())); >+ EXPECT_FALSE(absl::equal(lst1.begin(), lst1.end(), lst4.begin(), lst4.end())); >+} >+ >+TEST(EqualTest, EmptyRange) { >+ std::vector<int> v1{1, 2, 3}; >+ std::vector<int> empty1; >+ std::vector<int> empty2; >+ >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), empty1.begin(), empty1.end())); >+ EXPECT_FALSE(absl::equal(empty1.begin(), empty1.end(), v1.begin(), v1.end())); >+ EXPECT_TRUE( >+ absl::equal(empty1.begin(), empty1.end(), empty2.begin(), empty2.end())); >+} >+ >+TEST(EqualTest, MixedIterTypes) { >+ std::vector<int> v1{1, 2, 3}; >+ std::list<int> lst1{v1.begin(), v1.end()}; >+ std::list<int> lst2{1, 2, 4}; >+ std::list<int> lst3{1, 2}; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), lst1.begin(), lst1.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst2.begin(), lst2.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), lst3.begin(), lst3.end())); >+} >+ >+TEST(EqualTest, MixedValueTypes) { >+ std::vector<int> v1{1, 2, 3}; >+ std::vector<char> v2{1, 2, 3}; >+ std::vector<char> v3{1, 2}; >+ std::vector<char> v4{1, 2, 4}; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); >+} >+ >+TEST(EqualTest, WeirdIterators) { >+ std::vector<bool> v1{true, false}; >+ std::vector<bool> v2 = v1; >+ std::vector<bool> v3{true}; >+ std::vector<bool> v4{true, true, true}; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end())); >+} >+ >+TEST(EqualTest, CustomComparison) { >+ int n[] = {1, 2, 3, 4}; >+ std::vector<int*> v1{&n[0], &n[1], &n[2]}; >+ std::vector<int*> v2 = v1; >+ std::vector<int*> v3{&n[0], &n[1], &n[3]}; >+ std::vector<int*> v4{&n[0], &n[1]}; >+ >+ auto eq = [](int* a, int* b) { return *a == *b; }; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), eq)); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), eq)); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v4.begin(), v4.end(), eq)); >+} >+ >+TEST(EqualTest, MoveOnlyPredicate) { >+ std::vector<int> v1{1, 2, 3}; >+ std::vector<int> v2{4, 5, 6}; >+ >+ // move-only equality predicate >+ struct Eq { >+ Eq() = default; >+ Eq(Eq &&) = default; >+ Eq(const Eq &) = delete; >+ Eq &operator=(const Eq &) = delete; >+ bool operator()(const int a, const int b) const { return a == b; } >+ }; >+ >+ EXPECT_TRUE(absl::equal(v1.begin(), v1.end(), v1.begin(), v1.end(), Eq())); >+ EXPECT_FALSE(absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), Eq())); >+} >+ >+struct CountingTrivialPred { >+ int* count; >+ bool operator()(int, int) const { >+ ++*count; >+ return true; >+ } >+}; >+ >+TEST(EqualTest, RandomAccessComplexity) { >+ std::vector<int> v1{1, 1, 3}; >+ std::vector<int> v2 = v1; >+ std::vector<int> v3{1, 2}; >+ >+ do { >+ int count = 0; >+ absl::equal(v1.begin(), v1.end(), v2.begin(), v2.end(), >+ CountingTrivialPred{&count}); >+ EXPECT_LE(count, 3); >+ } while (std::next_permutation(v2.begin(), v2.end())); >+ >+ int count = 0; >+ absl::equal(v1.begin(), v1.end(), v3.begin(), v3.end(), >+ CountingTrivialPred{&count}); >+ EXPECT_EQ(count, 0); >+} >+ >+class LinearSearchTest : public testing::Test { >+ protected: >+ LinearSearchTest() : container_{1, 2, 3} {} >+ >+ static bool Is3(int n) { return n == 3; } >+ static bool Is4(int n) { return n == 4; } >+ >+ std::vector<int> container_; >+}; >+ >+TEST_F(LinearSearchTest, linear_search) { >+ EXPECT_TRUE(absl::linear_search(container_.begin(), container_.end(), 3)); >+ EXPECT_FALSE(absl::linear_search(container_.begin(), container_.end(), 4)); >+} >+ >+TEST_F(LinearSearchTest, linear_searchConst) { >+ const std::vector<int> *const const_container = &container_; >+ EXPECT_TRUE( >+ absl::linear_search(const_container->begin(), const_container->end(), 3)); >+ EXPECT_FALSE( >+ absl::linear_search(const_container->begin(), const_container->end(), 4)); >+} >+ >+TEST(RotateTest, Rotate) { >+ std::vector<int> v{0, 1, 2, 3, 4}; >+ EXPECT_EQ(*absl::rotate(v.begin(), v.begin() + 2, v.end()), 0); >+ EXPECT_THAT(v, testing::ElementsAreArray({2, 3, 4, 0, 1})); >+ >+ std::list<int> l{0, 1, 2, 3, 4}; >+ EXPECT_EQ(*absl::rotate(l.begin(), std::next(l.begin(), 3), l.end()), 0); >+ EXPECT_THAT(l, testing::ElementsAreArray({3, 4, 0, 1, 2})); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container.h >new file mode 100644 >index 00000000000..6af8c09799e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container.h >@@ -0,0 +1,1642 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: container.h >+// ----------------------------------------------------------------------------- >+// >+// This header file provides Container-based versions of algorithmic functions >+// within the C++ standard library. The following standard library sets of >+// functions are covered within this file: >+// >+// * Algorithmic <iterator> functions >+// * Algorithmic <numeric> functions >+// * <algorithm> functions >+// >+// The standard library functions operate on iterator ranges; the functions >+// within this API operate on containers, though many return iterator ranges. >+// >+// All functions within this API are named with a `c_` prefix. Calls such as >+// `absl::c_xx(container, ...) are equivalent to std:: functions such as >+// `std::xx(std::begin(cont), std::end(cont), ...)`. Functions that act on >+// iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`) >+// have no equivalent here. >+// >+// For template parameter and variable naming, `C` indicates the container type >+// to which the function is applied, `Pred` indicates the predicate object type >+// to be used by the function and `T` indicates the applicable element type. >+// >+ >+#ifndef ABSL_ALGORITHM_CONTAINER_H_ >+#define ABSL_ALGORITHM_CONTAINER_H_ >+ >+#include <algorithm> >+#include <cassert> >+#include <iterator> >+#include <numeric> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "absl/algorithm/algorithm.h" >+#include "absl/base/macros.h" >+#include "absl/meta/type_traits.h" >+ >+namespace absl { >+ >+namespace container_algorithm_internal { >+ >+// NOTE: it is important to defer to ADL lookup for building with C++ modules, >+// especially for headers like <valarray> which are not visible from this file >+// but specialize std::begin and std::end. >+using std::begin; >+using std::end; >+ >+// The type of the iterator given by begin(c) (possibly std::begin(c)). >+// ContainerIter<const vector<T>> gives vector<T>::const_iterator, >+// while ContainerIter<vector<T>> gives vector<T>::iterator. >+template <typename C> >+using ContainerIter = decltype(begin(std::declval<C&>())); >+ >+// An MSVC bug involving template parameter substitution requires us to use >+// decltype() here instead of just std::pair. >+template <typename C1, typename C2> >+using ContainerIterPairType = >+ decltype(std::make_pair(ContainerIter<C1>(), ContainerIter<C2>())); >+ >+template <typename C> >+using ContainerDifferenceType = >+ decltype(std::distance(std::declval<ContainerIter<C>>(), >+ std::declval<ContainerIter<C>>())); >+ >+template <typename C> >+using ContainerPointerType = >+ typename std::iterator_traits<ContainerIter<C>>::pointer; >+ >+// container_algorithm_internal::c_begin and >+// container_algorithm_internal::c_end are abbreviations for proper ADL >+// lookup of std::begin and std::end, i.e. >+// using std::begin; >+// using std::end; >+// std::foo(begin(c), end(c); >+// becomes >+// std::foo(container_algorithm_internal::begin(c), >+// container_algorithm_internal::end(c)); >+// These are meant for internal use only. >+ >+template <typename C> >+ContainerIter<C> c_begin(C& c) { return begin(c); } >+ >+template <typename C> >+ContainerIter<C> c_end(C& c) { return end(c); } >+ >+} // namespace container_algorithm_internal >+ >+// PUBLIC API >+ >+//------------------------------------------------------------------------------ >+// Abseil algorithm.h functions >+//------------------------------------------------------------------------------ >+ >+// c_linear_search() >+// >+// Container-based version of absl::linear_search() for performing a linear >+// search within a container. >+template <typename C, typename EqualityComparable> >+bool c_linear_search(const C& c, EqualityComparable&& value) { >+ return linear_search(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<EqualityComparable>(value)); >+} >+ >+//------------------------------------------------------------------------------ >+// <iterator> algorithms >+//------------------------------------------------------------------------------ >+ >+// c_distance() >+// >+// Container-based version of the <iterator> `std::distance()` function to >+// return the number of elements within a container. >+template <typename C> >+container_algorithm_internal::ContainerDifferenceType<const C> c_distance( >+ const C& c) { >+ return std::distance(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Non-modifying sequence operations >+//------------------------------------------------------------------------------ >+ >+// c_all_of() >+// >+// Container-based version of the <algorithm> `std::all_of()` function to >+// test a condition on all elements within a container. >+template <typename C, typename Pred> >+bool c_all_of(const C& c, Pred&& pred) { >+ return std::all_of(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_any_of() >+// >+// Container-based version of the <algorithm> `std::any_of()` function to >+// test if any element in a container fulfills a condition. >+template <typename C, typename Pred> >+bool c_any_of(const C& c, Pred&& pred) { >+ return std::any_of(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_none_of() >+// >+// Container-based version of the <algorithm> `std::none_of()` function to >+// test if no elements in a container fulfil a condition. >+template <typename C, typename Pred> >+bool c_none_of(const C& c, Pred&& pred) { >+ return std::none_of(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_for_each() >+// >+// Container-based version of the <algorithm> `std::for_each()` function to >+// apply a function to a container's elements. >+template <typename C, typename Function> >+decay_t<Function> c_for_each(C&& c, Function&& f) { >+ return std::for_each(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Function>(f)); >+} >+ >+// c_find() >+// >+// Container-based version of the <algorithm> `std::find()` function to find >+// the first element containing the passed value within a container value. >+template <typename C, typename T> >+container_algorithm_internal::ContainerIter<C> c_find(C& c, T&& value) { >+ return std::find(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<T>(value)); >+} >+ >+// c_find_if() >+// >+// Container-based version of the <algorithm> `std::find_if()` function to find >+// the first element in a container matching the given condition. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerIter<C> c_find_if(C& c, Pred&& pred) { >+ return std::find_if(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_find_if_not() >+// >+// Container-based version of the <algorithm> `std::find_if_not()` function to >+// find the first element in a container not matching the given condition. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerIter<C> c_find_if_not(C& c, >+ Pred&& pred) { >+ return std::find_if_not(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_find_end() >+// >+// Container-based version of the <algorithm> `std::find_end()` function to >+// find the last subsequence within a container. >+template <typename Sequence1, typename Sequence2> >+container_algorithm_internal::ContainerIter<Sequence1> c_find_end( >+ Sequence1& sequence, Sequence2& subsequence) { >+ return std::find_end(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(subsequence), >+ container_algorithm_internal::c_end(subsequence)); >+} >+ >+// Overload of c_find_end() for using a predicate evaluation other than `==` as >+// the function's test condition. >+template <typename Sequence1, typename Sequence2, typename BinaryPredicate> >+container_algorithm_internal::ContainerIter<Sequence1> c_find_end( >+ Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) { >+ return std::find_end(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(subsequence), >+ container_algorithm_internal::c_end(subsequence), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_find_first_of() >+// >+// Container-based version of the <algorithm> `std::find_first_of()` function to >+// find the first elements in an ordered set within a container. >+template <typename C1, typename C2> >+container_algorithm_internal::ContainerIter<C1> c_find_first_of(C1& container, >+ C2& options) { >+ return std::find_first_of(container_algorithm_internal::c_begin(container), >+ container_algorithm_internal::c_end(container), >+ container_algorithm_internal::c_begin(options), >+ container_algorithm_internal::c_end(options)); >+} >+ >+// Overload of c_find_first_of() for using a predicate evaluation other than >+// `==` as the function's test condition. >+template <typename C1, typename C2, typename BinaryPredicate> >+container_algorithm_internal::ContainerIter<C1> c_find_first_of( >+ C1& container, C2& options, BinaryPredicate&& pred) { >+ return std::find_first_of(container_algorithm_internal::c_begin(container), >+ container_algorithm_internal::c_end(container), >+ container_algorithm_internal::c_begin(options), >+ container_algorithm_internal::c_end(options), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_adjacent_find() >+// >+// Container-based version of the <algorithm> `std::adjacent_find()` function to >+// find equal adjacent elements within a container. >+template <typename Sequence> >+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( >+ Sequence& sequence) { >+ return std::adjacent_find(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_adjacent_find() for using a predicate evaluation other than >+// `==` as the function's test condition. >+template <typename Sequence, typename BinaryPredicate> >+container_algorithm_internal::ContainerIter<Sequence> c_adjacent_find( >+ Sequence& sequence, BinaryPredicate&& pred) { >+ return std::adjacent_find(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_count() >+// >+// Container-based version of the <algorithm> `std::count()` function to count >+// values that match within a container. >+template <typename C, typename T> >+container_algorithm_internal::ContainerDifferenceType<const C> c_count( >+ const C& c, T&& value) { >+ return std::count(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<T>(value)); >+} >+ >+// c_count_if() >+// >+// Container-based version of the <algorithm> `std::count_if()` function to >+// count values matching a condition within a container. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerDifferenceType<const C> c_count_if( >+ const C& c, Pred&& pred) { >+ return std::count_if(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_mismatch() >+// >+// Container-based version of the <algorithm> `std::mismatch()` function to >+// return the first element where two ordered containers differ. >+template <typename C1, typename C2> >+container_algorithm_internal::ContainerIterPairType<C1, C2> >+c_mismatch(C1& c1, C2& c2) { >+ return std::mismatch(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2)); >+} >+ >+// Overload of c_mismatch() for using a predicate evaluation other than `==` as >+// the function's test condition. >+template <typename C1, typename C2, typename BinaryPredicate> >+container_algorithm_internal::ContainerIterPairType<C1, C2> >+c_mismatch(C1& c1, C2& c2, BinaryPredicate&& pred) { >+ return std::mismatch(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_equal() >+// >+// Container-based version of the <algorithm> `std::equal()` function to >+// test whether two containers are equal. >+// >+// NOTE: the semantics of c_equal() are slightly different than those of >+// equal(): while the latter iterates over the second container only up to the >+// size of the first container, c_equal() also checks whether the container >+// sizes are equal. This better matches expectations about c_equal() based on >+// its signature. >+// >+// Example: >+// vector v1 = <1, 2, 3>; >+// vector v2 = <1, 2, 3, 4>; >+// equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true >+// c_equal(v1, v2) returns false >+ >+template <typename C1, typename C2> >+bool c_equal(const C1& c1, const C2& c2) { >+ return ((c1.size() == c2.size()) && >+ std::equal(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2))); >+} >+ >+// Overload of c_equal() for using a predicate evaluation other than `==` as >+// the function's test condition. >+template <typename C1, typename C2, typename BinaryPredicate> >+bool c_equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) { >+ return ((c1.size() == c2.size()) && >+ std::equal(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ std::forward<BinaryPredicate>(pred))); >+} >+ >+// c_is_permutation() >+// >+// Container-based version of the <algorithm> `std::is_permutation()` function >+// to test whether a container is a permutation of another. >+template <typename C1, typename C2> >+bool c_is_permutation(const C1& c1, const C2& c2) { >+ using std::begin; >+ using std::end; >+ return c1.size() == c2.size() && >+ std::is_permutation(begin(c1), end(c1), begin(c2)); >+} >+ >+// Overload of c_is_permutation() for using a predicate evaluation other than >+// `==` as the function's test condition. >+template <typename C1, typename C2, typename BinaryPredicate> >+bool c_is_permutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) { >+ using std::begin; >+ using std::end; >+ return c1.size() == c2.size() && >+ std::is_permutation(begin(c1), end(c1), begin(c2), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_search() >+// >+// Container-based version of the <algorithm> `std::search()` function to search >+// a container for a subsequence. >+template <typename Sequence1, typename Sequence2> >+container_algorithm_internal::ContainerIter<Sequence1> c_search( >+ Sequence1& sequence, Sequence2& subsequence) { >+ return std::search(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(subsequence), >+ container_algorithm_internal::c_end(subsequence)); >+} >+ >+// Overload of c_search() for using a predicate evaluation other than >+// `==` as the function's test condition. >+template <typename Sequence1, typename Sequence2, typename BinaryPredicate> >+container_algorithm_internal::ContainerIter<Sequence1> c_search( >+ Sequence1& sequence, Sequence2& subsequence, BinaryPredicate&& pred) { >+ return std::search(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(subsequence), >+ container_algorithm_internal::c_end(subsequence), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_search_n() >+// >+// Container-based version of the <algorithm> `std::search_n()` function to >+// search a container for the first sequence of N elements. >+template <typename Sequence, typename Size, typename T> >+container_algorithm_internal::ContainerIter<Sequence> c_search_n( >+ Sequence& sequence, Size count, T&& value) { >+ return std::search_n(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), count, >+ std::forward<T>(value)); >+} >+ >+// Overload of c_search_n() for using a predicate evaluation other than >+// `==` as the function's test condition. >+template <typename Sequence, typename Size, typename T, >+ typename BinaryPredicate> >+container_algorithm_internal::ContainerIter<Sequence> c_search_n( >+ Sequence& sequence, Size count, T&& value, BinaryPredicate&& pred) { >+ return std::search_n(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), count, >+ std::forward<T>(value), >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Modifying sequence operations >+//------------------------------------------------------------------------------ >+ >+// c_copy() >+// >+// Container-based version of the <algorithm> `std::copy()` function to copy a >+// container's elements into an iterator. >+template <typename InputSequence, typename OutputIterator> >+OutputIterator c_copy(const InputSequence& input, OutputIterator output) { >+ return std::copy(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), output); >+} >+ >+// c_copy_n() >+// >+// Container-based version of the <algorithm> `std::copy_n()` function to copy a >+// container's first N elements into an iterator. >+template <typename C, typename Size, typename OutputIterator> >+OutputIterator c_copy_n(const C& input, Size n, OutputIterator output) { >+ return std::copy_n(container_algorithm_internal::c_begin(input), n, output); >+} >+ >+// c_copy_if() >+// >+// Container-based version of the <algorithm> `std::copy_if()` function to copy >+// a container's elements satisfying some condition into an iterator. >+template <typename InputSequence, typename OutputIterator, typename Pred> >+OutputIterator c_copy_if(const InputSequence& input, OutputIterator output, >+ Pred&& pred) { >+ return std::copy_if(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), output, >+ std::forward<Pred>(pred)); >+} >+ >+// c_copy_backward() >+// >+// Container-based version of the <algorithm> `std::copy_backward()` function to >+// copy a container's elements in reverse order into an iterator. >+template <typename C, typename BidirectionalIterator> >+BidirectionalIterator c_copy_backward(const C& src, >+ BidirectionalIterator dest) { >+ return std::copy_backward(container_algorithm_internal::c_begin(src), >+ container_algorithm_internal::c_end(src), dest); >+} >+ >+// c_move() >+// >+// Container-based version of the <algorithm> `std::move()` function to move >+// a container's elements into an iterator. >+template <typename C, typename OutputIterator> >+OutputIterator c_move(C& src, OutputIterator dest) { >+ return std::move(container_algorithm_internal::c_begin(src), >+ container_algorithm_internal::c_end(src), dest); >+} >+ >+// c_swap_ranges() >+// >+// Container-based version of the <algorithm> `std::swap_ranges()` function to >+// swap a container's elements with another container's elements. >+template <typename C1, typename C2> >+container_algorithm_internal::ContainerIter<C2> c_swap_ranges(C1& c1, C2& c2) { >+ return std::swap_ranges(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2)); >+} >+ >+// c_transform() >+// >+// Container-based version of the <algorithm> `std::transform()` function to >+// transform a container's elements using the unary operation, storing the >+// result in an iterator pointing to the last transformed element in the output >+// range. >+template <typename InputSequence, typename OutputIterator, typename UnaryOp> >+OutputIterator c_transform(const InputSequence& input, OutputIterator output, >+ UnaryOp&& unary_op) { >+ return std::transform(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), output, >+ std::forward<UnaryOp>(unary_op)); >+} >+ >+// Overload of c_transform() for performing a transformation using a binary >+// predicate. >+template <typename InputSequence1, typename InputSequence2, >+ typename OutputIterator, typename BinaryOp> >+OutputIterator c_transform(const InputSequence1& input1, >+ const InputSequence2& input2, OutputIterator output, >+ BinaryOp&& binary_op) { >+ return std::transform(container_algorithm_internal::c_begin(input1), >+ container_algorithm_internal::c_end(input1), >+ container_algorithm_internal::c_begin(input2), output, >+ std::forward<BinaryOp>(binary_op)); >+} >+ >+// c_replace() >+// >+// Container-based version of the <algorithm> `std::replace()` function to >+// replace a container's elements of some value with a new value. The container >+// is modified in place. >+template <typename Sequence, typename T> >+void c_replace(Sequence& sequence, const T& old_value, const T& new_value) { >+ std::replace(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), old_value, >+ new_value); >+} >+ >+// c_replace_if() >+// >+// Container-based version of the <algorithm> `std::replace_if()` function to >+// replace a container's elements of some value with a new value based on some >+// condition. The container is modified in place. >+template <typename C, typename Pred, typename T> >+void c_replace_if(C& c, Pred&& pred, T&& new_value) { >+ std::replace_if(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred), std::forward<T>(new_value)); >+} >+ >+// c_replace_copy() >+// >+// Container-based version of the <algorithm> `std::replace_copy()` function to >+// replace a container's elements of some value with a new value and return the >+// results within an iterator. >+template <typename C, typename OutputIterator, typename T> >+OutputIterator c_replace_copy(const C& c, OutputIterator result, T&& old_value, >+ T&& new_value) { >+ return std::replace_copy(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result, >+ std::forward<T>(old_value), >+ std::forward<T>(new_value)); >+} >+ >+// c_replace_copy_if() >+// >+// Container-based version of the <algorithm> `std::replace_copy_if()` function >+// to replace a container's elements of some value with a new value based on >+// some condition, and return the results within an iterator. >+template <typename C, typename OutputIterator, typename Pred, typename T> >+OutputIterator c_replace_copy_if(const C& c, OutputIterator result, Pred&& pred, >+ T&& new_value) { >+ return std::replace_copy_if(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result, >+ std::forward<Pred>(pred), >+ std::forward<T>(new_value)); >+} >+ >+// c_fill() >+// >+// Container-based version of the <algorithm> `std::fill()` function to fill a >+// container with some value. >+template <typename C, typename T> >+void c_fill(C& c, T&& value) { >+ std::fill(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), std::forward<T>(value)); >+} >+ >+// c_fill_n() >+// >+// Container-based version of the <algorithm> `std::fill_n()` function to fill >+// the first N elements in a container with some value. >+template <typename C, typename Size, typename T> >+void c_fill_n(C& c, Size n, T&& value) { >+ std::fill_n(container_algorithm_internal::c_begin(c), n, >+ std::forward<T>(value)); >+} >+ >+// c_generate() >+// >+// Container-based version of the <algorithm> `std::generate()` function to >+// assign a container's elements to the values provided by the given generator. >+template <typename C, typename Generator> >+void c_generate(C& c, Generator&& gen) { >+ std::generate(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Generator>(gen)); >+} >+ >+// c_generate_n() >+// >+// Container-based version of the <algorithm> `std::generate_n()` function to >+// assign a container's first N elements to the values provided by the given >+// generator. >+template <typename C, typename Size, typename Generator> >+container_algorithm_internal::ContainerIter<C> c_generate_n(C& c, Size n, >+ Generator&& gen) { >+ return std::generate_n(container_algorithm_internal::c_begin(c), n, >+ std::forward<Generator>(gen)); >+} >+ >+// Note: `c_xx()` <algorithm> container versions for `remove()`, `remove_if()`, >+// and `unique()` are omitted, because it's not clear whether or not such >+// functions should call erase on their supplied sequences afterwards. Either >+// behavior would be surprising for a different set of users. >+// >+ >+// c_remove_copy() >+// >+// Container-based version of the <algorithm> `std::remove_copy()` function to >+// copy a container's elements while removing any elements matching the given >+// `value`. >+template <typename C, typename OutputIterator, typename T> >+OutputIterator c_remove_copy(const C& c, OutputIterator result, T&& value) { >+ return std::remove_copy(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result, >+ std::forward<T>(value)); >+} >+ >+// c_remove_copy_if() >+// >+// Container-based version of the <algorithm> `std::remove_copy_if()` function >+// to copy a container's elements while removing any elements matching the given >+// condition. >+template <typename C, typename OutputIterator, typename Pred> >+OutputIterator c_remove_copy_if(const C& c, OutputIterator result, >+ Pred&& pred) { >+ return std::remove_copy_if(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result, >+ std::forward<Pred>(pred)); >+} >+ >+// c_unique_copy() >+// >+// Container-based version of the <algorithm> `std::unique_copy()` function to >+// copy a container's elements while removing any elements containing duplicate >+// values. >+template <typename C, typename OutputIterator> >+OutputIterator c_unique_copy(const C& c, OutputIterator result) { >+ return std::unique_copy(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result); >+} >+ >+// Overload of c_unique_copy() for using a predicate evaluation other than >+// `==` for comparing uniqueness of the element values. >+template <typename C, typename OutputIterator, typename BinaryPredicate> >+OutputIterator c_unique_copy(const C& c, OutputIterator result, >+ BinaryPredicate&& pred) { >+ return std::unique_copy(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), result, >+ std::forward<BinaryPredicate>(pred)); >+} >+ >+// c_reverse() >+// >+// Container-based version of the <algorithm> `std::reverse()` function to >+// reverse a container's elements. >+template <typename Sequence> >+void c_reverse(Sequence& sequence) { >+ std::reverse(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// c_reverse_copy() >+// >+// Container-based version of the <algorithm> `std::reverse()` function to >+// reverse a container's elements and write them to an iterator range. >+template <typename C, typename OutputIterator> >+OutputIterator c_reverse_copy(const C& sequence, OutputIterator result) { >+ return std::reverse_copy(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ result); >+} >+ >+// c_rotate() >+// >+// Container-based version of the <algorithm> `std::rotate()` function to >+// shift a container's elements leftward such that the `middle` element becomes >+// the first element in the container. >+template <typename C, >+ typename Iterator = container_algorithm_internal::ContainerIter<C>> >+Iterator c_rotate(C& sequence, Iterator middle) { >+ return absl::rotate(container_algorithm_internal::c_begin(sequence), middle, >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// c_rotate_copy() >+// >+// Container-based version of the <algorithm> `std::rotate_copy()` function to >+// shift a container's elements leftward such that the `middle` element becomes >+// the first element in a new iterator range. >+template <typename C, typename OutputIterator> >+OutputIterator c_rotate_copy( >+ const C& sequence, >+ container_algorithm_internal::ContainerIter<const C> middle, >+ OutputIterator result) { >+ return std::rotate_copy(container_algorithm_internal::c_begin(sequence), >+ middle, container_algorithm_internal::c_end(sequence), >+ result); >+} >+ >+// c_shuffle() >+// >+// Container-based version of the <algorithm> `std::shuffle()` function to >+// randomly shuffle elements within the container using a `gen()` uniform random >+// number generator. >+template <typename RandomAccessContainer, typename UniformRandomBitGenerator> >+void c_shuffle(RandomAccessContainer& c, UniformRandomBitGenerator&& gen) { >+ std::shuffle(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<UniformRandomBitGenerator>(gen)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Partition functions >+//------------------------------------------------------------------------------ >+ >+// c_is_partitioned() >+// >+// Container-based version of the <algorithm> `std::is_partitioned()` function >+// to test whether all elements in the container for which `pred` returns `true` >+// precede those for which `pred` is `false`. >+template <typename C, typename Pred> >+bool c_is_partitioned(const C& c, Pred&& pred) { >+ return std::is_partitioned(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_partition() >+// >+// Container-based version of the <algorithm> `std::partition()` function >+// to rearrange all elements in a container in such a way that all elements for >+// which `pred` returns `true` precede all those for which it returns `false`, >+// returning an iterator to the first element of the second group. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerIter<C> c_partition(C& c, Pred&& pred) { >+ return std::partition(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_stable_partition() >+// >+// Container-based version of the <algorithm> `std::stable_partition()` function >+// to rearrange all elements in a container in such a way that all elements for >+// which `pred` returns `true` precede all those for which it returns `false`, >+// preserving the relative ordering between the two groups. The function returns >+// an iterator to the first element of the second group. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerIter<C> c_stable_partition(C& c, >+ Pred&& pred) { >+ return std::stable_partition(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+// c_partition_copy() >+// >+// Container-based version of the <algorithm> `std::partition_copy()` function >+// to partition a container's elements and return them into two iterators: one >+// for which `pred` returns `true`, and one for which `pred` returns `false.` >+ >+template <typename C, typename OutputIterator1, typename OutputIterator2, >+ typename Pred> >+std::pair<OutputIterator1, OutputIterator2> c_partition_copy( >+ const C& c, OutputIterator1 out_true, OutputIterator2 out_false, >+ Pred&& pred) { >+ return std::partition_copy(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), out_true, >+ out_false, std::forward<Pred>(pred)); >+} >+ >+// c_partition_point() >+// >+// Container-based version of the <algorithm> `std::partition_point()` function >+// to return the first element of an already partitioned container for which >+// the given `pred` is not `true`. >+template <typename C, typename Pred> >+container_algorithm_internal::ContainerIter<C> c_partition_point(C& c, >+ Pred&& pred) { >+ return std::partition_point(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Pred>(pred)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Sorting functions >+//------------------------------------------------------------------------------ >+ >+// c_sort() >+// >+// Container-based version of the <algorithm> `std::sort()` function >+// to sort elements in ascending order of their values. >+template <typename C> >+void c_sort(C& c) { >+ std::sort(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_sort() for performing a `comp` comparison other than the >+// default `operator<`. >+template <typename C, typename Compare> >+void c_sort(C& c, Compare&& comp) { >+ std::sort(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_stable_sort() >+// >+// Container-based version of the <algorithm> `std::stable_sort()` function >+// to sort elements in ascending order of their values, preserving the order >+// of equivalents. >+template <typename C> >+void c_stable_sort(C& c) { >+ std::stable_sort(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_stable_sort() for performing a `comp` comparison other than the >+// default `operator<`. >+template <typename C, typename Compare> >+void c_stable_sort(C& c, Compare&& comp) { >+ std::stable_sort(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_is_sorted() >+// >+// Container-based version of the <algorithm> `std::is_sorted()` function >+// to evaluate whether the given container is sorted in ascending order. >+template <typename C> >+bool c_is_sorted(const C& c) { >+ return std::is_sorted(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// c_is_sorted() overload for performing a `comp` comparison other than the >+// default `operator<`. >+template <typename C, typename Compare> >+bool c_is_sorted(const C& c, Compare&& comp) { >+ return std::is_sorted(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_partial_sort() >+// >+// Container-based version of the <algorithm> `std::partial_sort()` function >+// to rearrange elements within a container such that elements before `middle` >+// are sorted in ascending order. >+template <typename RandomAccessContainer> >+void c_partial_sort( >+ RandomAccessContainer& sequence, >+ container_algorithm_internal::ContainerIter<RandomAccessContainer> middle) { >+ std::partial_sort(container_algorithm_internal::c_begin(sequence), middle, >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_partial_sort() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename RandomAccessContainer, typename Compare> >+void c_partial_sort( >+ RandomAccessContainer& sequence, >+ container_algorithm_internal::ContainerIter<RandomAccessContainer> middle, >+ Compare&& comp) { >+ std::partial_sort(container_algorithm_internal::c_begin(sequence), middle, >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_partial_sort_copy() >+// >+// Container-based version of the <algorithm> `std::partial_sort_copy()` >+// function to sort elements within a container such that elements before >+// `middle` are sorted in ascending order, and return the result within an >+// iterator. >+template <typename C, typename RandomAccessContainer> >+container_algorithm_internal::ContainerIter<RandomAccessContainer> >+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result) { >+ return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(result), >+ container_algorithm_internal::c_end(result)); >+} >+ >+// Overload of c_partial_sort_copy() for performing a `comp` comparison other >+// than the default `operator<`. >+template <typename C, typename RandomAccessContainer, typename Compare> >+container_algorithm_internal::ContainerIter<RandomAccessContainer> >+c_partial_sort_copy(const C& sequence, RandomAccessContainer& result, >+ Compare&& comp) { >+ return std::partial_sort_copy(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ container_algorithm_internal::c_begin(result), >+ container_algorithm_internal::c_end(result), >+ std::forward<Compare>(comp)); >+} >+ >+// c_is_sorted_until() >+// >+// Container-based version of the <algorithm> `std::is_sorted_until()` function >+// to return the first element within a container that is not sorted in >+// ascending order as an iterator. >+template <typename C> >+container_algorithm_internal::ContainerIter<C> c_is_sorted_until(C& c) { >+ return std::is_sorted_until(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_is_sorted_until() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename C, typename Compare> >+container_algorithm_internal::ContainerIter<C> c_is_sorted_until( >+ C& c, Compare&& comp) { >+ return std::is_sorted_until(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_nth_element() >+// >+// Container-based version of the <algorithm> `std::nth_element()` function >+// to rearrange the elements within a container such that the `nth` element >+// would be in that position in an ordered sequence; other elements may be in >+// any order, except that all preceding `nth` will be less than that element, >+// and all following `nth` will be greater than that element. >+template <typename RandomAccessContainer> >+void c_nth_element( >+ RandomAccessContainer& sequence, >+ container_algorithm_internal::ContainerIter<RandomAccessContainer> nth) { >+ std::nth_element(container_algorithm_internal::c_begin(sequence), nth, >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_nth_element() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename RandomAccessContainer, typename Compare> >+void c_nth_element( >+ RandomAccessContainer& sequence, >+ container_algorithm_internal::ContainerIter<RandomAccessContainer> nth, >+ Compare&& comp) { >+ std::nth_element(container_algorithm_internal::c_begin(sequence), nth, >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Binary Search >+//------------------------------------------------------------------------------ >+ >+// c_lower_bound() >+// >+// Container-based version of the <algorithm> `std::lower_bound()` function >+// to return an iterator pointing to the first element in a sorted container >+// which does not compare less than `value`. >+template <typename Sequence, typename T> >+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound( >+ Sequence& sequence, T&& value) { >+ return std::lower_bound(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value)); >+} >+ >+// Overload of c_lower_bound() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename Sequence, typename T, typename Compare> >+container_algorithm_internal::ContainerIter<Sequence> c_lower_bound( >+ Sequence& sequence, T&& value, Compare&& comp) { >+ return std::lower_bound(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value), std::forward<Compare>(comp)); >+} >+ >+// c_upper_bound() >+// >+// Container-based version of the <algorithm> `std::upper_bound()` function >+// to return an iterator pointing to the first element in a sorted container >+// which is greater than `value`. >+template <typename Sequence, typename T> >+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound( >+ Sequence& sequence, T&& value) { >+ return std::upper_bound(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value)); >+} >+ >+// Overload of c_upper_bound() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename Sequence, typename T, typename Compare> >+container_algorithm_internal::ContainerIter<Sequence> c_upper_bound( >+ Sequence& sequence, T&& value, Compare&& comp) { >+ return std::upper_bound(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value), std::forward<Compare>(comp)); >+} >+ >+// c_equal_range() >+// >+// Container-based version of the <algorithm> `std::equal_range()` function >+// to return an iterator pair pointing to the first and last elements in a >+// sorted container which compare equal to `value`. >+template <typename Sequence, typename T> >+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence> >+c_equal_range(Sequence& sequence, T&& value) { >+ return std::equal_range(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value)); >+} >+ >+// Overload of c_equal_range() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename Sequence, typename T, typename Compare> >+container_algorithm_internal::ContainerIterPairType<Sequence, Sequence> >+c_equal_range(Sequence& sequence, T&& value, Compare&& comp) { >+ return std::equal_range(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value), std::forward<Compare>(comp)); >+} >+ >+// c_binary_search() >+// >+// Container-based version of the <algorithm> `std::binary_search()` function >+// to test if any element in the sorted container contains a value equivalent to >+// 'value'. >+template <typename Sequence, typename T> >+bool c_binary_search(Sequence&& sequence, T&& value) { >+ return std::binary_search(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value)); >+} >+ >+// Overload of c_binary_search() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename Sequence, typename T, typename Compare> >+bool c_binary_search(Sequence&& sequence, T&& value, Compare&& comp) { >+ return std::binary_search(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value), >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Merge functions >+//------------------------------------------------------------------------------ >+ >+// c_merge() >+// >+// Container-based version of the <algorithm> `std::merge()` function >+// to merge two sorted containers into a single sorted iterator. >+template <typename C1, typename C2, typename OutputIterator> >+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result) { >+ return std::merge(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), result); >+} >+ >+// Overload of c_merge() for performing a `comp` comparison other than >+// the default `operator<`. >+template <typename C1, typename C2, typename OutputIterator, typename Compare> >+OutputIterator c_merge(const C1& c1, const C2& c2, OutputIterator result, >+ Compare&& comp) { >+ return std::merge(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), result, >+ std::forward<Compare>(comp)); >+} >+ >+// c_inplace_merge() >+// >+// Container-based version of the <algorithm> `std::inplace_merge()` function >+// to merge a supplied iterator `middle` into a container. >+template <typename C> >+void c_inplace_merge(C& c, >+ container_algorithm_internal::ContainerIter<C> middle) { >+ std::inplace_merge(container_algorithm_internal::c_begin(c), middle, >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_inplace_merge() for performing a merge using a `comp` other >+// than `operator<`. >+template <typename C, typename Compare> >+void c_inplace_merge(C& c, >+ container_algorithm_internal::ContainerIter<C> middle, >+ Compare&& comp) { >+ std::inplace_merge(container_algorithm_internal::c_begin(c), middle, >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_includes() >+// >+// Container-based version of the <algorithm> `std::includes()` function >+// to test whether a sorted container `c1` entirely contains another sorted >+// container `c2`. >+template <typename C1, typename C2> >+bool c_includes(const C1& c1, const C2& c2) { >+ return std::includes(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2)); >+} >+ >+// Overload of c_includes() for performing a merge using a `comp` other than >+// `operator<`. >+template <typename C1, typename C2, typename Compare> >+bool c_includes(const C1& c1, const C2& c2, Compare&& comp) { >+ return std::includes(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), >+ std::forward<Compare>(comp)); >+} >+ >+// c_set_union() >+// >+// Container-based version of the <algorithm> `std::set_union()` function >+// to return an iterator containing the union of two containers; duplicate >+// values are not copied into the output. >+template <typename C1, typename C2, typename OutputIterator> >+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output) { >+ return std::set_union(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output); >+} >+ >+// Overload of c_set_union() for performing a merge using a `comp` other than >+// `operator<`. >+template <typename C1, typename C2, typename OutputIterator, typename Compare> >+OutputIterator c_set_union(const C1& c1, const C2& c2, OutputIterator output, >+ Compare&& comp) { >+ return std::set_union(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output, >+ std::forward<Compare>(comp)); >+} >+ >+// c_set_intersection() >+// >+// Container-based version of the <algorithm> `std::set_intersection()` function >+// to return an iterator containing the intersection of two containers. >+template <typename C1, typename C2, typename OutputIterator> >+OutputIterator c_set_intersection(const C1& c1, const C2& c2, >+ OutputIterator output) { >+ return std::set_intersection(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output); >+} >+ >+// Overload of c_set_intersection() for performing a merge using a `comp` other >+// than `operator<`. >+template <typename C1, typename C2, typename OutputIterator, typename Compare> >+OutputIterator c_set_intersection(const C1& c1, const C2& c2, >+ OutputIterator output, Compare&& comp) { >+ return std::set_intersection(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output, >+ std::forward<Compare>(comp)); >+} >+ >+// c_set_difference() >+// >+// Container-based version of the <algorithm> `std::set_difference()` function >+// to return an iterator containing elements present in the first container but >+// not in the second. >+template <typename C1, typename C2, typename OutputIterator> >+OutputIterator c_set_difference(const C1& c1, const C2& c2, >+ OutputIterator output) { >+ return std::set_difference(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output); >+} >+ >+// Overload of c_set_difference() for performing a merge using a `comp` other >+// than `operator<`. >+template <typename C1, typename C2, typename OutputIterator, typename Compare> >+OutputIterator c_set_difference(const C1& c1, const C2& c2, >+ OutputIterator output, Compare&& comp) { >+ return std::set_difference(container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output, >+ std::forward<Compare>(comp)); >+} >+ >+// c_set_symmetric_difference() >+// >+// Container-based version of the <algorithm> `std::set_symmetric_difference()` >+// function to return an iterator containing elements present in either one >+// container or the other, but not both. >+template <typename C1, typename C2, typename OutputIterator> >+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, >+ OutputIterator output) { >+ return std::set_symmetric_difference( >+ container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output); >+} >+ >+// Overload of c_set_symmetric_difference() for performing a merge using a >+// `comp` other than `operator<`. >+template <typename C1, typename C2, typename OutputIterator, typename Compare> >+OutputIterator c_set_symmetric_difference(const C1& c1, const C2& c2, >+ OutputIterator output, >+ Compare&& comp) { >+ return std::set_symmetric_difference( >+ container_algorithm_internal::c_begin(c1), >+ container_algorithm_internal::c_end(c1), >+ container_algorithm_internal::c_begin(c2), >+ container_algorithm_internal::c_end(c2), output, >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Heap functions >+//------------------------------------------------------------------------------ >+ >+// c_push_heap() >+// >+// Container-based version of the <algorithm> `std::push_heap()` function >+// to push a value onto a container heap. >+template <typename RandomAccessContainer> >+void c_push_heap(RandomAccessContainer& sequence) { >+ std::push_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_push_heap() for performing a push operation on a heap using a >+// `comp` other than `operator<`. >+template <typename RandomAccessContainer, typename Compare> >+void c_push_heap(RandomAccessContainer& sequence, Compare&& comp) { >+ std::push_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_pop_heap() >+// >+// Container-based version of the <algorithm> `std::pop_heap()` function >+// to pop a value from a heap container. >+template <typename RandomAccessContainer> >+void c_pop_heap(RandomAccessContainer& sequence) { >+ std::pop_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_pop_heap() for performing a pop operation on a heap using a >+// `comp` other than `operator<`. >+template <typename RandomAccessContainer, typename Compare> >+void c_pop_heap(RandomAccessContainer& sequence, Compare&& comp) { >+ std::pop_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_make_heap() >+// >+// Container-based version of the <algorithm> `std::make_heap()` function >+// to make a container a heap. >+template <typename RandomAccessContainer> >+void c_make_heap(RandomAccessContainer& sequence) { >+ std::make_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_make_heap() for performing heap comparisons using a >+// `comp` other than `operator<` >+template <typename RandomAccessContainer, typename Compare> >+void c_make_heap(RandomAccessContainer& sequence, Compare&& comp) { >+ std::make_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_sort_heap() >+// >+// Container-based version of the <algorithm> `std::sort_heap()` function >+// to sort a heap into ascending order (after which it is no longer a heap). >+template <typename RandomAccessContainer> >+void c_sort_heap(RandomAccessContainer& sequence) { >+ std::sort_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_sort_heap() for performing heap comparisons using a >+// `comp` other than `operator<` >+template <typename RandomAccessContainer, typename Compare> >+void c_sort_heap(RandomAccessContainer& sequence, Compare&& comp) { >+ std::sort_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_is_heap() >+// >+// Container-based version of the <algorithm> `std::is_heap()` function >+// to check whether the given container is a heap. >+template <typename RandomAccessContainer> >+bool c_is_heap(const RandomAccessContainer& sequence) { >+ return std::is_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_is_heap() for performing heap comparisons using a >+// `comp` other than `operator<` >+template <typename RandomAccessContainer, typename Compare> >+bool c_is_heap(const RandomAccessContainer& sequence, Compare&& comp) { >+ return std::is_heap(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_is_heap_until() >+// >+// Container-based version of the <algorithm> `std::is_heap_until()` function >+// to find the first element in a given container which is not in heap order. >+template <typename RandomAccessContainer> >+container_algorithm_internal::ContainerIter<RandomAccessContainer> >+c_is_heap_until(RandomAccessContainer& sequence) { >+ return std::is_heap_until(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_is_heap_until() for performing heap comparisons using a >+// `comp` other than `operator<` >+template <typename RandomAccessContainer, typename Compare> >+container_algorithm_internal::ContainerIter<RandomAccessContainer> >+c_is_heap_until(RandomAccessContainer& sequence, Compare&& comp) { >+ return std::is_heap_until(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Min/max >+//------------------------------------------------------------------------------ >+ >+// c_min_element() >+// >+// Container-based version of the <algorithm> `std::min_element()` function >+// to return an iterator pointing to the element with the smallest value, using >+// `operator<` to make the comparisons. >+template <typename Sequence> >+container_algorithm_internal::ContainerIter<Sequence> c_min_element( >+ Sequence& sequence) { >+ return std::min_element(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_min_element() for performing a `comp` comparison other than >+// `operator<`. >+template <typename Sequence, typename Compare> >+container_algorithm_internal::ContainerIter<Sequence> c_min_element( >+ Sequence& sequence, Compare&& comp) { >+ return std::min_element(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_max_element() >+// >+// Container-based version of the <algorithm> `std::max_element()` function >+// to return an iterator pointing to the element with the largest value, using >+// `operator<` to make the comparisons. >+template <typename Sequence> >+container_algorithm_internal::ContainerIter<Sequence> c_max_element( >+ Sequence& sequence) { >+ return std::max_element(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence)); >+} >+ >+// Overload of c_max_element() for performing a `comp` comparison other than >+// `operator<`. >+template <typename Sequence, typename Compare> >+container_algorithm_internal::ContainerIter<Sequence> c_max_element( >+ Sequence& sequence, Compare&& comp) { >+ return std::max_element(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<Compare>(comp)); >+} >+ >+// c_minmax_element() >+// >+// Container-based version of the <algorithm> `std::minmax_element()` function >+// to return a pair of iterators pointing to the elements containing the >+// smallest and largest values, respectively, using `operator<` to make the >+// comparisons. >+template <typename C> >+container_algorithm_internal::ContainerIterPairType<C, C> >+c_minmax_element(C& c) { >+ return std::minmax_element(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_minmax_element() for performing `comp` comparisons other than >+// `operator<`. >+template <typename C, typename Compare> >+container_algorithm_internal::ContainerIterPairType<C, C> >+c_minmax_element(C& c, Compare&& comp) { >+ return std::minmax_element(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <algorithm> Lexicographical Comparisons >+//------------------------------------------------------------------------------ >+ >+// c_lexicographical_compare() >+// >+// Container-based version of the <algorithm> `std::lexicographical_compare()` >+// function to lexicographically compare (e.g. sort words alphabetically) two >+// container sequences. The comparison is performed using `operator<`. Note >+// that capital letters ("A-Z") have ASCII values less than lowercase letters >+// ("a-z"). >+template <typename Sequence1, typename Sequence2> >+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2) { >+ return std::lexicographical_compare( >+ container_algorithm_internal::c_begin(sequence1), >+ container_algorithm_internal::c_end(sequence1), >+ container_algorithm_internal::c_begin(sequence2), >+ container_algorithm_internal::c_end(sequence2)); >+} >+ >+// Overload of c_lexicographical_compare() for performing a lexicographical >+// comparison using a `comp` operator instead of `operator<`. >+template <typename Sequence1, typename Sequence2, typename Compare> >+bool c_lexicographical_compare(Sequence1&& sequence1, Sequence2&& sequence2, >+ Compare&& comp) { >+ return std::lexicographical_compare( >+ container_algorithm_internal::c_begin(sequence1), >+ container_algorithm_internal::c_end(sequence1), >+ container_algorithm_internal::c_begin(sequence2), >+ container_algorithm_internal::c_end(sequence2), >+ std::forward<Compare>(comp)); >+} >+ >+// c_next_permutation() >+// >+// Container-based version of the <algorithm> `std::next_permutation()` function >+// to rearrange a container's elements into the next lexicographically greater >+// permutation. >+template <typename C> >+bool c_next_permutation(C& c) { >+ return std::next_permutation(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_next_permutation() for performing a lexicographical >+// comparison using a `comp` operator instead of `operator<`. >+template <typename C, typename Compare> >+bool c_next_permutation(C& c, Compare&& comp) { >+ return std::next_permutation(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+// c_prev_permutation() >+// >+// Container-based version of the <algorithm> `std::prev_permutation()` function >+// to rearrange a container's elements into the next lexicographically lesser >+// permutation. >+template <typename C> >+bool c_prev_permutation(C& c) { >+ return std::prev_permutation(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c)); >+} >+ >+// Overload of c_prev_permutation() for performing a lexicographical >+// comparison using a `comp` operator instead of `operator<`. >+template <typename C, typename Compare> >+bool c_prev_permutation(C& c, Compare&& comp) { >+ return std::prev_permutation(container_algorithm_internal::c_begin(c), >+ container_algorithm_internal::c_end(c), >+ std::forward<Compare>(comp)); >+} >+ >+//------------------------------------------------------------------------------ >+// <numeric> algorithms >+//------------------------------------------------------------------------------ >+ >+// c_iota() >+// >+// Container-based version of the <algorithm> `std::iota()` function >+// to compute successive values of `value`, as if incremented with `++value` >+// after each element is written. and write them to the container. >+template <typename Sequence, typename T> >+void c_iota(Sequence& sequence, T&& value) { >+ std::iota(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(value)); >+} >+// c_accumulate() >+// >+// Container-based version of the <algorithm> `std::accumulate()` function >+// to accumulate the element values of a container to `init` and return that >+// accumulation by value. >+// >+// Note: Due to a language technicality this function has return type >+// absl::decay_t<T>. As a user of this function you can casually read >+// this as "returns T by value" and assume it does the right thing. >+template <typename Sequence, typename T> >+decay_t<T> c_accumulate(const Sequence& sequence, T&& init) { >+ return std::accumulate(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(init)); >+} >+ >+// Overload of c_accumulate() for using a binary operations other than >+// addition for computing the accumulation. >+template <typename Sequence, typename T, typename BinaryOp> >+decay_t<T> c_accumulate(const Sequence& sequence, T&& init, >+ BinaryOp&& binary_op) { >+ return std::accumulate(container_algorithm_internal::c_begin(sequence), >+ container_algorithm_internal::c_end(sequence), >+ std::forward<T>(init), >+ std::forward<BinaryOp>(binary_op)); >+} >+ >+// c_inner_product() >+// >+// Container-based version of the <algorithm> `std::inner_product()` function >+// to compute the cumulative inner product of container element pairs. >+// >+// Note: Due to a language technicality this function has return type >+// absl::decay_t<T>. As a user of this function you can casually read >+// this as "returns T by value" and assume it does the right thing. >+template <typename Sequence1, typename Sequence2, typename T> >+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2, >+ T&& sum) { >+ return std::inner_product(container_algorithm_internal::c_begin(factors1), >+ container_algorithm_internal::c_end(factors1), >+ container_algorithm_internal::c_begin(factors2), >+ std::forward<T>(sum)); >+} >+ >+// Overload of c_inner_product() for using binary operations other than >+// `operator+` (for computing the accumulation) and `operator*` (for computing >+// the product between the two container's element pair). >+template <typename Sequence1, typename Sequence2, typename T, >+ typename BinaryOp1, typename BinaryOp2> >+decay_t<T> c_inner_product(const Sequence1& factors1, const Sequence2& factors2, >+ T&& sum, BinaryOp1&& op1, BinaryOp2&& op2) { >+ return std::inner_product(container_algorithm_internal::c_begin(factors1), >+ container_algorithm_internal::c_end(factors1), >+ container_algorithm_internal::c_begin(factors2), >+ std::forward<T>(sum), std::forward<BinaryOp1>(op1), >+ std::forward<BinaryOp2>(op2)); >+} >+ >+// c_adjacent_difference() >+// >+// Container-based version of the <algorithm> `std::adjacent_difference()` >+// function to compute the difference between each element and the one preceding >+// it and write it to an iterator. >+template <typename InputSequence, typename OutputIt> >+OutputIt c_adjacent_difference(const InputSequence& input, >+ OutputIt output_first) { >+ return std::adjacent_difference(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), >+ output_first); >+} >+ >+// Overload of c_adjacent_difference() for using a binary operation other than >+// subtraction to compute the adjacent difference. >+template <typename InputSequence, typename OutputIt, typename BinaryOp> >+OutputIt c_adjacent_difference(const InputSequence& input, >+ OutputIt output_first, BinaryOp&& op) { >+ return std::adjacent_difference(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), >+ output_first, std::forward<BinaryOp>(op)); >+} >+ >+// c_partial_sum() >+// >+// Container-based version of the <algorithm> `std::partial_sum()` function >+// to compute the partial sum of the elements in a sequence and write them >+// to an iterator. The partial sum is the sum of all element values so far in >+// the sequence. >+template <typename InputSequence, typename OutputIt> >+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first) { >+ return std::partial_sum(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), >+ output_first); >+} >+ >+// Overload of c_partial_sum() for using a binary operation other than addition >+// to compute the "partial sum". >+template <typename InputSequence, typename OutputIt, typename BinaryOp> >+OutputIt c_partial_sum(const InputSequence& input, OutputIt output_first, >+ BinaryOp&& op) { >+ return std::partial_sum(container_algorithm_internal::c_begin(input), >+ container_algorithm_internal::c_end(input), >+ output_first, std::forward<BinaryOp>(op)); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_ALGORITHM_CONTAINER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container_test.cc >new file mode 100644 >index 00000000000..de66f14680f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/container_test.cc >@@ -0,0 +1,997 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/algorithm/container.h" >+ >+#include <functional> >+#include <initializer_list> >+#include <iterator> >+#include <list> >+#include <memory> >+#include <ostream> >+#include <random> >+#include <set> >+#include <unordered_set> >+#include <utility> >+#include <valarray> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/casts.h" >+#include "absl/base/macros.h" >+#include "absl/memory/memory.h" >+#include "absl/types/span.h" >+ >+namespace { >+ >+using ::testing::Each; >+using ::testing::ElementsAre; >+using ::testing::Gt; >+using ::testing::IsNull; >+using ::testing::Lt; >+using ::testing::Pointee; >+using ::testing::Truly; >+using ::testing::UnorderedElementsAre; >+ >+// Most of these tests just check that the code compiles, not that it >+// does the right thing. That's fine since the functions just forward >+// to the STL implementation. >+class NonMutatingTest : public testing::Test { >+ protected: >+ std::unordered_set<int> container_ = {1, 2, 3}; >+ std::list<int> sequence_ = {1, 2, 3}; >+ std::vector<int> vector_ = {1, 2, 3}; >+ int array_[3] = {1, 2, 3}; >+}; >+ >+struct AccumulateCalls { >+ void operator()(int value) { >+ calls.push_back(value); >+ } >+ std::vector<int> calls; >+}; >+ >+bool Predicate(int value) { return value < 3; } >+bool BinPredicate(int v1, int v2) { return v1 < v2; } >+bool Equals(int v1, int v2) { return v1 == v2; } >+bool IsOdd(int x) { return x % 2 != 0; } >+ >+ >+TEST_F(NonMutatingTest, Distance) { >+ EXPECT_EQ(container_.size(), absl::c_distance(container_)); >+ EXPECT_EQ(sequence_.size(), absl::c_distance(sequence_)); >+ EXPECT_EQ(vector_.size(), absl::c_distance(vector_)); >+ EXPECT_EQ(ABSL_ARRAYSIZE(array_), absl::c_distance(array_)); >+ >+ // Works with a temporary argument. >+ EXPECT_EQ(vector_.size(), absl::c_distance(std::vector<int>(vector_))); >+} >+ >+TEST_F(NonMutatingTest, Distance_OverloadedBeginEnd) { >+ // Works with classes which have custom ADL-selected overloads of std::begin >+ // and std::end. >+ std::initializer_list<int> a = {1, 2, 3}; >+ std::valarray<int> b = {1, 2, 3}; >+ EXPECT_EQ(3, absl::c_distance(a)); >+ EXPECT_EQ(3, absl::c_distance(b)); >+ >+ // It is assumed that other c_* functions use the same mechanism for >+ // ADL-selecting begin/end overloads. >+} >+ >+TEST_F(NonMutatingTest, ForEach) { >+ AccumulateCalls c = absl::c_for_each(container_, AccumulateCalls()); >+ // Don't rely on the unordered_set's order. >+ std::sort(c.calls.begin(), c.calls.end()); >+ EXPECT_EQ(vector_, c.calls); >+ >+ // Works with temporary container, too. >+ AccumulateCalls c2 = >+ absl::c_for_each(std::unordered_set<int>(container_), AccumulateCalls()); >+ std::sort(c2.calls.begin(), c2.calls.end()); >+ EXPECT_EQ(vector_, c2.calls); >+} >+ >+TEST_F(NonMutatingTest, FindReturnsCorrectType) { >+ auto it = absl::c_find(container_, 3); >+ EXPECT_EQ(3, *it); >+ absl::c_find(absl::implicit_cast<const std::list<int>&>(sequence_), 3); >+} >+ >+TEST_F(NonMutatingTest, FindIf) { absl::c_find_if(container_, Predicate); } >+ >+TEST_F(NonMutatingTest, FindIfNot) { >+ absl::c_find_if_not(container_, Predicate); >+} >+ >+TEST_F(NonMutatingTest, FindEnd) { >+ absl::c_find_end(sequence_, vector_); >+ absl::c_find_end(vector_, sequence_); >+} >+ >+TEST_F(NonMutatingTest, FindEndWithPredicate) { >+ absl::c_find_end(sequence_, vector_, BinPredicate); >+ absl::c_find_end(vector_, sequence_, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, FindFirstOf) { >+ absl::c_find_first_of(container_, sequence_); >+ absl::c_find_first_of(sequence_, container_); >+} >+ >+TEST_F(NonMutatingTest, FindFirstOfWithPredicate) { >+ absl::c_find_first_of(container_, sequence_, BinPredicate); >+ absl::c_find_first_of(sequence_, container_, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, AdjacentFind) { absl::c_adjacent_find(sequence_); } >+ >+TEST_F(NonMutatingTest, AdjacentFindWithPredicate) { >+ absl::c_adjacent_find(sequence_, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, Count) { EXPECT_EQ(1, absl::c_count(container_, 3)); } >+ >+TEST_F(NonMutatingTest, CountIf) { >+ EXPECT_EQ(2, absl::c_count_if(container_, Predicate)); >+ const std::unordered_set<int>& const_container = container_; >+ EXPECT_EQ(2, absl::c_count_if(const_container, Predicate)); >+} >+ >+TEST_F(NonMutatingTest, Mismatch) { >+ absl::c_mismatch(container_, sequence_); >+ absl::c_mismatch(sequence_, container_); >+} >+ >+TEST_F(NonMutatingTest, MismatchWithPredicate) { >+ absl::c_mismatch(container_, sequence_, BinPredicate); >+ absl::c_mismatch(sequence_, container_, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, Equal) { >+ EXPECT_TRUE(absl::c_equal(vector_, sequence_)); >+ EXPECT_TRUE(absl::c_equal(sequence_, vector_)); >+ >+ // Test that behavior appropriately differs from that of equal(). >+ std::vector<int> vector_plus = {1, 2, 3}; >+ vector_plus.push_back(4); >+ EXPECT_FALSE(absl::c_equal(vector_plus, sequence_)); >+ EXPECT_FALSE(absl::c_equal(sequence_, vector_plus)); >+} >+ >+TEST_F(NonMutatingTest, EqualWithPredicate) { >+ EXPECT_TRUE(absl::c_equal(vector_, sequence_, Equals)); >+ EXPECT_TRUE(absl::c_equal(sequence_, vector_, Equals)); >+ >+ // Test that behavior appropriately differs from that of equal(). >+ std::vector<int> vector_plus = {1, 2, 3}; >+ vector_plus.push_back(4); >+ EXPECT_FALSE(absl::c_equal(vector_plus, sequence_, Equals)); >+ EXPECT_FALSE(absl::c_equal(sequence_, vector_plus, Equals)); >+} >+ >+TEST_F(NonMutatingTest, IsPermutation) { >+ auto vector_permut_ = vector_; >+ std::next_permutation(vector_permut_.begin(), vector_permut_.end()); >+ EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_)); >+ EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_)); >+ >+ // Test that behavior appropriately differs from that of is_permutation(). >+ std::vector<int> vector_plus = {1, 2, 3}; >+ vector_plus.push_back(4); >+ EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_)); >+ EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus)); >+} >+ >+TEST_F(NonMutatingTest, IsPermutationWithPredicate) { >+ auto vector_permut_ = vector_; >+ std::next_permutation(vector_permut_.begin(), vector_permut_.end()); >+ EXPECT_TRUE(absl::c_is_permutation(vector_permut_, sequence_, Equals)); >+ EXPECT_TRUE(absl::c_is_permutation(sequence_, vector_permut_, Equals)); >+ >+ // Test that behavior appropriately differs from that of is_permutation(). >+ std::vector<int> vector_plus = {1, 2, 3}; >+ vector_plus.push_back(4); >+ EXPECT_FALSE(absl::c_is_permutation(vector_plus, sequence_, Equals)); >+ EXPECT_FALSE(absl::c_is_permutation(sequence_, vector_plus, Equals)); >+} >+ >+TEST_F(NonMutatingTest, Search) { >+ absl::c_search(sequence_, vector_); >+ absl::c_search(vector_, sequence_); >+ absl::c_search(array_, sequence_); >+} >+ >+TEST_F(NonMutatingTest, SearchWithPredicate) { >+ absl::c_search(sequence_, vector_, BinPredicate); >+ absl::c_search(vector_, sequence_, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, SearchN) { absl::c_search_n(sequence_, 3, 1); } >+ >+TEST_F(NonMutatingTest, SearchNWithPredicate) { >+ absl::c_search_n(sequence_, 3, 1, BinPredicate); >+} >+ >+TEST_F(NonMutatingTest, LowerBound) { >+ std::list<int>::iterator i = absl::c_lower_bound(sequence_, 3); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(2, std::distance(sequence_.begin(), i)); >+ EXPECT_EQ(3, *i); >+} >+ >+TEST_F(NonMutatingTest, LowerBoundWithPredicate) { >+ std::vector<int> v(vector_); >+ std::sort(v.begin(), v.end(), std::greater<int>()); >+ std::vector<int>::iterator i = absl::c_lower_bound(v, 3, std::greater<int>()); >+ EXPECT_TRUE(i == v.begin()); >+ EXPECT_EQ(3, *i); >+} >+ >+TEST_F(NonMutatingTest, UpperBound) { >+ std::list<int>::iterator i = absl::c_upper_bound(sequence_, 1); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(1, std::distance(sequence_.begin(), i)); >+ EXPECT_EQ(2, *i); >+} >+ >+TEST_F(NonMutatingTest, UpperBoundWithPredicate) { >+ std::vector<int> v(vector_); >+ std::sort(v.begin(), v.end(), std::greater<int>()); >+ std::vector<int>::iterator i = absl::c_upper_bound(v, 1, std::greater<int>()); >+ EXPECT_EQ(3, i - v.begin()); >+ EXPECT_TRUE(i == v.end()); >+} >+ >+TEST_F(NonMutatingTest, EqualRange) { >+ std::pair<std::list<int>::iterator, std::list<int>::iterator> p = >+ absl::c_equal_range(sequence_, 2); >+ EXPECT_EQ(1, std::distance(sequence_.begin(), p.first)); >+ EXPECT_EQ(2, std::distance(sequence_.begin(), p.second)); >+} >+ >+TEST_F(NonMutatingTest, EqualRangeArray) { >+ auto p = absl::c_equal_range(array_, 2); >+ EXPECT_EQ(1, std::distance(std::begin(array_), p.first)); >+ EXPECT_EQ(2, std::distance(std::begin(array_), p.second)); >+} >+ >+TEST_F(NonMutatingTest, EqualRangeWithPredicate) { >+ std::vector<int> v(vector_); >+ std::sort(v.begin(), v.end(), std::greater<int>()); >+ std::pair<std::vector<int>::iterator, std::vector<int>::iterator> p = >+ absl::c_equal_range(v, 2, std::greater<int>()); >+ EXPECT_EQ(1, std::distance(v.begin(), p.first)); >+ EXPECT_EQ(2, std::distance(v.begin(), p.second)); >+} >+ >+TEST_F(NonMutatingTest, BinarySearch) { >+ EXPECT_TRUE(absl::c_binary_search(vector_, 2)); >+ EXPECT_TRUE(absl::c_binary_search(std::vector<int>(vector_), 2)); >+} >+ >+TEST_F(NonMutatingTest, BinarySearchWithPredicate) { >+ std::vector<int> v(vector_); >+ std::sort(v.begin(), v.end(), std::greater<int>()); >+ EXPECT_TRUE(absl::c_binary_search(v, 2, std::greater<int>())); >+ EXPECT_TRUE( >+ absl::c_binary_search(std::vector<int>(v), 2, std::greater<int>())); >+} >+ >+TEST_F(NonMutatingTest, MinElement) { >+ std::list<int>::iterator i = absl::c_min_element(sequence_); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(*i, 1); >+} >+ >+TEST_F(NonMutatingTest, MinElementWithPredicate) { >+ std::list<int>::iterator i = >+ absl::c_min_element(sequence_, std::greater<int>()); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(*i, 3); >+} >+ >+TEST_F(NonMutatingTest, MaxElement) { >+ std::list<int>::iterator i = absl::c_max_element(sequence_); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(*i, 3); >+} >+ >+TEST_F(NonMutatingTest, MaxElementWithPredicate) { >+ std::list<int>::iterator i = >+ absl::c_max_element(sequence_, std::greater<int>()); >+ ASSERT_TRUE(i != sequence_.end()); >+ EXPECT_EQ(*i, 1); >+} >+ >+TEST_F(NonMutatingTest, LexicographicalCompare) { >+ EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_)); >+ >+ std::vector<int> v; >+ v.push_back(1); >+ v.push_back(2); >+ v.push_back(4); >+ >+ EXPECT_TRUE(absl::c_lexicographical_compare(sequence_, v)); >+ EXPECT_TRUE(absl::c_lexicographical_compare(std::list<int>(sequence_), v)); >+} >+ >+TEST_F(NonMutatingTest, LexicographicalCopmareWithPredicate) { >+ EXPECT_FALSE(absl::c_lexicographical_compare(sequence_, sequence_, >+ std::greater<int>())); >+ >+ std::vector<int> v; >+ v.push_back(1); >+ v.push_back(2); >+ v.push_back(4); >+ >+ EXPECT_TRUE( >+ absl::c_lexicographical_compare(v, sequence_, std::greater<int>())); >+ EXPECT_TRUE(absl::c_lexicographical_compare( >+ std::vector<int>(v), std::list<int>(sequence_), std::greater<int>())); >+} >+ >+TEST_F(NonMutatingTest, Includes) { >+ std::set<int> s(vector_.begin(), vector_.end()); >+ s.insert(4); >+ EXPECT_TRUE(absl::c_includes(s, vector_)); >+} >+ >+TEST_F(NonMutatingTest, IncludesWithPredicate) { >+ std::vector<int> v = {3, 2, 1}; >+ std::set<int, std::greater<int>> s(v.begin(), v.end()); >+ s.insert(4); >+ EXPECT_TRUE(absl::c_includes(s, v, std::greater<int>())); >+} >+ >+class NumericMutatingTest : public testing::Test { >+ protected: >+ std::list<int> list_ = {1, 2, 3}; >+ std::vector<int> output_; >+}; >+ >+TEST_F(NumericMutatingTest, Iota) { >+ absl::c_iota(list_, 5); >+ std::list<int> expected{5, 6, 7}; >+ EXPECT_EQ(list_, expected); >+} >+ >+TEST_F(NonMutatingTest, Accumulate) { >+ EXPECT_EQ(absl::c_accumulate(sequence_, 4), 1 + 2 + 3 + 4); >+} >+ >+TEST_F(NonMutatingTest, AccumulateWithBinaryOp) { >+ EXPECT_EQ(absl::c_accumulate(sequence_, 4, std::multiplies<int>()), >+ 1 * 2 * 3 * 4); >+} >+ >+TEST_F(NonMutatingTest, AccumulateLvalueInit) { >+ int lvalue = 4; >+ EXPECT_EQ(absl::c_accumulate(sequence_, lvalue), 1 + 2 + 3 + 4); >+} >+ >+TEST_F(NonMutatingTest, AccumulateWithBinaryOpLvalueInit) { >+ int lvalue = 4; >+ EXPECT_EQ(absl::c_accumulate(sequence_, lvalue, std::multiplies<int>()), >+ 1 * 2 * 3 * 4); >+} >+ >+TEST_F(NonMutatingTest, InnerProduct) { >+ EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 1000), >+ 1000 + 1 * 1 + 2 * 2 + 3 * 3); >+} >+ >+TEST_F(NonMutatingTest, InnerProductWithBinaryOps) { >+ EXPECT_EQ(absl::c_inner_product(sequence_, vector_, 10, >+ std::multiplies<int>(), std::plus<int>()), >+ 10 * (1 + 1) * (2 + 2) * (3 + 3)); >+} >+ >+TEST_F(NonMutatingTest, InnerProductLvalueInit) { >+ int lvalue = 1000; >+ EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue), >+ 1000 + 1 * 1 + 2 * 2 + 3 * 3); >+} >+ >+TEST_F(NonMutatingTest, InnerProductWithBinaryOpsLvalueInit) { >+ int lvalue = 10; >+ EXPECT_EQ(absl::c_inner_product(sequence_, vector_, lvalue, >+ std::multiplies<int>(), std::plus<int>()), >+ 10 * (1 + 1) * (2 + 2) * (3 + 3)); >+} >+ >+TEST_F(NumericMutatingTest, AdjacentDifference) { >+ auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_)); >+ *last = 1000; >+ std::vector<int> expected{1, 2 - 1, 3 - 2, 1000}; >+ EXPECT_EQ(output_, expected); >+} >+ >+TEST_F(NumericMutatingTest, AdjacentDifferenceWithBinaryOp) { >+ auto last = absl::c_adjacent_difference(list_, std::back_inserter(output_), >+ std::multiplies<int>()); >+ *last = 1000; >+ std::vector<int> expected{1, 2 * 1, 3 * 2, 1000}; >+ EXPECT_EQ(output_, expected); >+} >+ >+TEST_F(NumericMutatingTest, PartialSum) { >+ auto last = absl::c_partial_sum(list_, std::back_inserter(output_)); >+ *last = 1000; >+ std::vector<int> expected{1, 1 + 2, 1 + 2 + 3, 1000}; >+ EXPECT_EQ(output_, expected); >+} >+ >+TEST_F(NumericMutatingTest, PartialSumWithBinaryOp) { >+ auto last = absl::c_partial_sum(list_, std::back_inserter(output_), >+ std::multiplies<int>()); >+ *last = 1000; >+ std::vector<int> expected{1, 1 * 2, 1 * 2 * 3, 1000}; >+ EXPECT_EQ(output_, expected); >+} >+ >+TEST_F(NonMutatingTest, LinearSearch) { >+ EXPECT_TRUE(absl::c_linear_search(container_, 3)); >+ EXPECT_FALSE(absl::c_linear_search(container_, 4)); >+} >+ >+TEST_F(NonMutatingTest, AllOf) { >+ const std::vector<int>& v = vector_; >+ EXPECT_FALSE(absl::c_all_of(v, [](int x) { return x > 1; })); >+ EXPECT_TRUE(absl::c_all_of(v, [](int x) { return x > 0; })); >+} >+ >+TEST_F(NonMutatingTest, AnyOf) { >+ const std::vector<int>& v = vector_; >+ EXPECT_TRUE(absl::c_any_of(v, [](int x) { return x > 2; })); >+ EXPECT_FALSE(absl::c_any_of(v, [](int x) { return x > 5; })); >+} >+ >+TEST_F(NonMutatingTest, NoneOf) { >+ const std::vector<int>& v = vector_; >+ EXPECT_FALSE(absl::c_none_of(v, [](int x) { return x > 2; })); >+ EXPECT_TRUE(absl::c_none_of(v, [](int x) { return x > 5; })); >+} >+ >+TEST_F(NonMutatingTest, MinMaxElementLess) { >+ std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator> >+ p = absl::c_minmax_element(vector_, std::less<int>()); >+ EXPECT_TRUE(p.first == vector_.begin()); >+ EXPECT_TRUE(p.second == vector_.begin() + 2); >+} >+ >+TEST_F(NonMutatingTest, MinMaxElementGreater) { >+ std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator> >+ p = absl::c_minmax_element(vector_, std::greater<int>()); >+ EXPECT_TRUE(p.first == vector_.begin() + 2); >+ EXPECT_TRUE(p.second == vector_.begin()); >+} >+ >+TEST_F(NonMutatingTest, MinMaxElementNoPredicate) { >+ std::pair<std::vector<int>::const_iterator, std::vector<int>::const_iterator> >+ p = absl::c_minmax_element(vector_); >+ EXPECT_TRUE(p.first == vector_.begin()); >+ EXPECT_TRUE(p.second == vector_.begin() + 2); >+} >+ >+class SortingTest : public testing::Test { >+ protected: >+ std::list<int> sorted_ = {1, 2, 3, 4}; >+ std::list<int> unsorted_ = {2, 4, 1, 3}; >+ std::list<int> reversed_ = {4, 3, 2, 1}; >+}; >+ >+TEST_F(SortingTest, IsSorted) { >+ EXPECT_TRUE(absl::c_is_sorted(sorted_)); >+ EXPECT_FALSE(absl::c_is_sorted(unsorted_)); >+ EXPECT_FALSE(absl::c_is_sorted(reversed_)); >+} >+ >+TEST_F(SortingTest, IsSortedWithPredicate) { >+ EXPECT_FALSE(absl::c_is_sorted(sorted_, std::greater<int>())); >+ EXPECT_FALSE(absl::c_is_sorted(unsorted_, std::greater<int>())); >+ EXPECT_TRUE(absl::c_is_sorted(reversed_, std::greater<int>())); >+} >+ >+TEST_F(SortingTest, IsSortedUntil) { >+ EXPECT_EQ(1, *absl::c_is_sorted_until(unsorted_)); >+ EXPECT_EQ(4, *absl::c_is_sorted_until(unsorted_, std::greater<int>())); >+} >+ >+TEST_F(SortingTest, NthElement) { >+ std::vector<int> unsorted = {2, 4, 1, 3}; >+ absl::c_nth_element(unsorted, unsorted.begin() + 2); >+ EXPECT_THAT(unsorted, >+ ElementsAre(Lt(3), Lt(3), 3, Gt(3))); >+ absl::c_nth_element(unsorted, unsorted.begin() + 2, std::greater<int>()); >+ EXPECT_THAT(unsorted, >+ ElementsAre(Gt(2), Gt(2), 2, Lt(2))); >+} >+ >+TEST(MutatingTest, IsPartitioned) { >+ EXPECT_TRUE( >+ absl::c_is_partitioned(std::vector<int>{1, 3, 5, 2, 4, 6}, IsOdd)); >+ EXPECT_FALSE( >+ absl::c_is_partitioned(std::vector<int>{1, 2, 3, 4, 5, 6}, IsOdd)); >+ EXPECT_FALSE( >+ absl::c_is_partitioned(std::vector<int>{2, 4, 6, 1, 3, 5}, IsOdd)); >+} >+ >+TEST(MutatingTest, Partition) { >+ std::vector<int> actual = {1, 2, 3, 4, 5}; >+ absl::c_partition(actual, IsOdd); >+ EXPECT_THAT(actual, Truly([](const std::vector<int>& c) { >+ return absl::c_is_partitioned(c, IsOdd); >+ })); >+} >+ >+TEST(MutatingTest, StablePartition) { >+ std::vector<int> actual = {1, 2, 3, 4, 5}; >+ absl::c_stable_partition(actual, IsOdd); >+ EXPECT_THAT(actual, ElementsAre(1, 3, 5, 2, 4)); >+} >+ >+TEST(MutatingTest, PartitionCopy) { >+ const std::vector<int> initial = {1, 2, 3, 4, 5}; >+ std::vector<int> odds, evens; >+ auto ends = absl::c_partition_copy(initial, back_inserter(odds), >+ back_inserter(evens), IsOdd); >+ *ends.first = 7; >+ *ends.second = 6; >+ EXPECT_THAT(odds, ElementsAre(1, 3, 5, 7)); >+ EXPECT_THAT(evens, ElementsAre(2, 4, 6)); >+} >+ >+TEST(MutatingTest, PartitionPoint) { >+ const std::vector<int> initial = {1, 3, 5, 2, 4}; >+ auto middle = absl::c_partition_point(initial, IsOdd); >+ EXPECT_EQ(2, *middle); >+} >+ >+TEST(MutatingTest, CopyMiddle) { >+ const std::vector<int> initial = {4, -1, -2, -3, 5}; >+ const std::list<int> input = {1, 2, 3}; >+ const std::vector<int> expected = {4, 1, 2, 3, 5}; >+ >+ std::list<int> test_list(initial.begin(), initial.end()); >+ absl::c_copy(input, ++test_list.begin()); >+ EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list); >+ >+ std::vector<int> test_vector = initial; >+ absl::c_copy(input, test_vector.begin() + 1); >+ EXPECT_EQ(expected, test_vector); >+} >+ >+TEST(MutatingTest, CopyFrontInserter) { >+ const std::list<int> initial = {4, 5}; >+ const std::list<int> input = {1, 2, 3}; >+ const std::list<int> expected = {3, 2, 1, 4, 5}; >+ >+ std::list<int> test_list = initial; >+ absl::c_copy(input, std::front_inserter(test_list)); >+ EXPECT_EQ(expected, test_list); >+} >+ >+TEST(MutatingTest, CopyBackInserter) { >+ const std::vector<int> initial = {4, 5}; >+ const std::list<int> input = {1, 2, 3}; >+ const std::vector<int> expected = {4, 5, 1, 2, 3}; >+ >+ std::list<int> test_list(initial.begin(), initial.end()); >+ absl::c_copy(input, std::back_inserter(test_list)); >+ EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list); >+ >+ std::vector<int> test_vector = initial; >+ absl::c_copy(input, std::back_inserter(test_vector)); >+ EXPECT_EQ(expected, test_vector); >+} >+ >+TEST(MutatingTest, CopyN) { >+ const std::vector<int> initial = {1, 2, 3, 4, 5}; >+ const std::vector<int> expected = {1, 2}; >+ std::vector<int> actual; >+ absl::c_copy_n(initial, 2, back_inserter(actual)); >+ EXPECT_EQ(expected, actual); >+} >+ >+TEST(MutatingTest, CopyIf) { >+ const std::list<int> input = {1, 2, 3}; >+ std::vector<int> output; >+ absl::c_copy_if(input, std::back_inserter(output), >+ [](int i) { return i != 2; }); >+ EXPECT_THAT(output, ElementsAre(1, 3)); >+} >+ >+TEST(MutatingTest, CopyBackward) { >+ std::vector<int> actual = {1, 2, 3, 4, 5}; >+ std::vector<int> expected = {1, 2, 1, 2, 3}; >+ absl::c_copy_backward(absl::MakeSpan(actual.data(), 3), actual.end()); >+ EXPECT_EQ(expected, actual); >+} >+ >+TEST(MutatingTest, Move) { >+ std::vector<std::unique_ptr<int>> src; >+ src.emplace_back(absl::make_unique<int>(1)); >+ src.emplace_back(absl::make_unique<int>(2)); >+ src.emplace_back(absl::make_unique<int>(3)); >+ src.emplace_back(absl::make_unique<int>(4)); >+ src.emplace_back(absl::make_unique<int>(5)); >+ >+ std::vector<std::unique_ptr<int>> dest = {}; >+ absl::c_move(src, std::back_inserter(dest)); >+ EXPECT_THAT(src, Each(IsNull())); >+ EXPECT_THAT(dest, ElementsAre(Pointee(1), Pointee(2), Pointee(3), Pointee(4), >+ Pointee(5))); >+} >+ >+TEST(MutatingTest, SwapRanges) { >+ std::vector<int> odds = {2, 4, 6}; >+ std::vector<int> evens = {1, 3, 5}; >+ absl::c_swap_ranges(odds, evens); >+ EXPECT_THAT(odds, ElementsAre(1, 3, 5)); >+ EXPECT_THAT(evens, ElementsAre(2, 4, 6)); >+} >+ >+TEST_F(NonMutatingTest, Transform) { >+ std::vector<int> x{0, 2, 4}, y, z; >+ auto end = absl::c_transform(x, back_inserter(y), std::negate<int>()); >+ EXPECT_EQ(std::vector<int>({0, -2, -4}), y); >+ *end = 7; >+ EXPECT_EQ(std::vector<int>({0, -2, -4, 7}), y); >+ >+ y = {1, 3, 0}; >+ end = absl::c_transform(x, y, back_inserter(z), std::plus<int>()); >+ EXPECT_EQ(std::vector<int>({1, 5, 4}), z); >+ *end = 7; >+ EXPECT_EQ(std::vector<int>({1, 5, 4, 7}), z); >+} >+ >+TEST(MutatingTest, Replace) { >+ const std::vector<int> initial = {1, 2, 3, 1, 4, 5}; >+ const std::vector<int> expected = {4, 2, 3, 4, 4, 5}; >+ >+ std::vector<int> test_vector = initial; >+ absl::c_replace(test_vector, 1, 4); >+ EXPECT_EQ(expected, test_vector); >+ >+ std::list<int> test_list(initial.begin(), initial.end()); >+ absl::c_replace(test_list, 1, 4); >+ EXPECT_EQ(std::list<int>(expected.begin(), expected.end()), test_list); >+} >+ >+TEST(MutatingTest, ReplaceIf) { >+ std::vector<int> actual = {1, 2, 3, 4, 5}; >+ const std::vector<int> expected = {0, 2, 0, 4, 0}; >+ >+ absl::c_replace_if(actual, IsOdd, 0); >+ EXPECT_EQ(expected, actual); >+} >+ >+TEST(MutatingTest, ReplaceCopy) { >+ const std::vector<int> initial = {1, 2, 3, 1, 4, 5}; >+ const std::vector<int> expected = {4, 2, 3, 4, 4, 5}; >+ >+ std::vector<int> actual; >+ absl::c_replace_copy(initial, back_inserter(actual), 1, 4); >+ EXPECT_EQ(expected, actual); >+} >+ >+TEST(MutatingTest, Sort) { >+ std::vector<int> test_vector = {2, 3, 1, 4}; >+ absl::c_sort(test_vector); >+ EXPECT_THAT(test_vector, ElementsAre(1, 2, 3, 4)); >+} >+ >+TEST(MutatingTest, SortWithPredicate) { >+ std::vector<int> test_vector = {2, 3, 1, 4}; >+ absl::c_sort(test_vector, std::greater<int>()); >+ EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); >+} >+ >+// For absl::c_stable_sort tests. Needs an operator< that does not cover all >+// fields so that the test can check the sort preserves order of equal elements. >+struct Element { >+ int key; >+ int value; >+ friend bool operator<(const Element& e1, const Element& e2) { >+ return e1.key < e2.key; >+ } >+ // Make gmock print useful diagnostics. >+ friend std::ostream& operator<<(std::ostream& o, const Element& e) { >+ return o << "{" << e.key << ", " << e.value << "}"; >+ } >+}; >+ >+MATCHER_P2(IsElement, key, value, "") { >+ return arg.key == key && arg.value == value; >+} >+ >+TEST(MutatingTest, StableSort) { >+ std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; >+ absl::c_stable_sort(test_vector); >+ EXPECT_THAT( >+ test_vector, >+ ElementsAre(IsElement(1, 1), IsElement(1, 0), IsElement(2, 1), >+ IsElement(2, 0), IsElement(2, 2))); >+} >+ >+TEST(MutatingTest, StableSortWithPredicate) { >+ std::vector<Element> test_vector = {{1, 1}, {2, 1}, {2, 0}, {1, 0}, {2, 2}}; >+ absl::c_stable_sort(test_vector, [](const Element& e1, const Element& e2) { >+ return e2 < e1; >+ }); >+ EXPECT_THAT( >+ test_vector, >+ ElementsAre(IsElement(2, 1), IsElement(2, 0), IsElement(2, 2), >+ IsElement(1, 1), IsElement(1, 0))); >+} >+ >+TEST(MutatingTest, ReplaceCopyIf) { >+ const std::vector<int> initial = {1, 2, 3, 4, 5}; >+ const std::vector<int> expected = {0, 2, 0, 4, 0}; >+ >+ std::vector<int> actual; >+ absl::c_replace_copy_if(initial, back_inserter(actual), IsOdd, 0); >+ EXPECT_EQ(expected, actual); >+} >+ >+TEST(MutatingTest, Fill) { >+ std::vector<int> actual(5); >+ absl::c_fill(actual, 1); >+ EXPECT_THAT(actual, ElementsAre(1, 1, 1, 1, 1)); >+} >+ >+TEST(MutatingTest, FillN) { >+ std::vector<int> actual(5, 0); >+ absl::c_fill_n(actual, 2, 1); >+ EXPECT_THAT(actual, ElementsAre(1, 1, 0, 0, 0)); >+} >+ >+TEST(MutatingTest, Generate) { >+ std::vector<int> actual(5); >+ int x = 0; >+ absl::c_generate(actual, [&x]() { return ++x; }); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); >+} >+ >+TEST(MutatingTest, GenerateN) { >+ std::vector<int> actual(5, 0); >+ int x = 0; >+ absl::c_generate_n(actual, 3, [&x]() { return ++x; }); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 0, 0)); >+} >+ >+TEST(MutatingTest, RemoveCopy) { >+ std::vector<int> actual; >+ absl::c_remove_copy(std::vector<int>{1, 2, 3}, back_inserter(actual), 2); >+ EXPECT_THAT(actual, ElementsAre(1, 3)); >+} >+ >+TEST(MutatingTest, RemoveCopyIf) { >+ std::vector<int> actual; >+ absl::c_remove_copy_if(std::vector<int>{1, 2, 3}, back_inserter(actual), >+ IsOdd); >+ EXPECT_THAT(actual, ElementsAre(2)); >+} >+ >+TEST(MutatingTest, UniqueCopy) { >+ std::vector<int> actual; >+ absl::c_unique_copy(std::vector<int>{1, 2, 2, 2, 3, 3, 2}, >+ back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 2)); >+} >+ >+TEST(MutatingTest, UniqueCopyWithPredicate) { >+ std::vector<int> actual; >+ absl::c_unique_copy(std::vector<int>{1, 2, 3, -1, -2, -3, 1}, >+ back_inserter(actual), >+ [](int x, int y) { return (x < 0) == (y < 0); }); >+ EXPECT_THAT(actual, ElementsAre(1, -1, 1)); >+} >+ >+TEST(MutatingTest, Reverse) { >+ std::vector<int> test_vector = {1, 2, 3, 4}; >+ absl::c_reverse(test_vector); >+ EXPECT_THAT(test_vector, ElementsAre(4, 3, 2, 1)); >+ >+ std::list<int> test_list = {1, 2, 3, 4}; >+ absl::c_reverse(test_list); >+ EXPECT_THAT(test_list, ElementsAre(4, 3, 2, 1)); >+} >+ >+TEST(MutatingTest, ReverseCopy) { >+ std::vector<int> actual; >+ absl::c_reverse_copy(std::vector<int>{1, 2, 3, 4}, back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(4, 3, 2, 1)); >+} >+ >+TEST(MutatingTest, Rotate) { >+ std::vector<int> actual = {1, 2, 3, 4}; >+ auto it = absl::c_rotate(actual, actual.begin() + 2); >+ EXPECT_THAT(actual, testing::ElementsAreArray({3, 4, 1, 2})); >+ EXPECT_EQ(*it, 1); >+} >+ >+TEST(MutatingTest, RotateCopy) { >+ std::vector<int> initial = {1, 2, 3, 4}; >+ std::vector<int> actual; >+ auto end = >+ absl::c_rotate_copy(initial, initial.begin() + 2, back_inserter(actual)); >+ *end = 5; >+ EXPECT_THAT(actual, ElementsAre(3, 4, 1, 2, 5)); >+} >+ >+TEST(MutatingTest, Shuffle) { >+ std::vector<int> actual = {1, 2, 3, 4, 5}; >+ absl::c_shuffle(actual, std::random_device()); >+ EXPECT_THAT(actual, UnorderedElementsAre(1, 2, 3, 4, 5)); >+} >+ >+TEST(MutatingTest, PartialSort) { >+ std::vector<int> sequence{5, 3, 42, 0}; >+ absl::c_partial_sort(sequence, sequence.begin() + 2); >+ EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(0, 3)); >+ absl::c_partial_sort(sequence, sequence.begin() + 2, std::greater<int>()); >+ EXPECT_THAT(absl::MakeSpan(sequence.data(), 2), ElementsAre(42, 5)); >+} >+ >+TEST(MutatingTest, PartialSortCopy) { >+ const std::vector<int> initial = {5, 3, 42, 0}; >+ std::vector<int> actual(2); >+ absl::c_partial_sort_copy(initial, actual); >+ EXPECT_THAT(actual, ElementsAre(0, 3)); >+ absl::c_partial_sort_copy(initial, actual, std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(42, 5)); >+} >+ >+TEST(MutatingTest, Merge) { >+ std::vector<int> actual; >+ absl::c_merge(std::vector<int>{1, 3, 5}, std::vector<int>{2, 4}, >+ back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); >+} >+ >+TEST(MutatingTest, MergeWithComparator) { >+ std::vector<int> actual; >+ absl::c_merge(std::vector<int>{5, 3, 1}, std::vector<int>{4, 2}, >+ back_inserter(actual), std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1)); >+} >+ >+TEST(MutatingTest, InplaceMerge) { >+ std::vector<int> actual = {1, 3, 5, 2, 4}; >+ absl::c_inplace_merge(actual, actual.begin() + 3); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 4, 5)); >+} >+ >+TEST(MutatingTest, InplaceMergeWithComparator) { >+ std::vector<int> actual = {5, 3, 1, 4, 2}; >+ absl::c_inplace_merge(actual, actual.begin() + 3, std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(5, 4, 3, 2, 1)); >+} >+ >+class SetOperationsTest : public testing::Test { >+ protected: >+ std::vector<int> a_ = {1, 2, 3}; >+ std::vector<int> b_ = {1, 3, 5}; >+ >+ std::vector<int> a_reversed_ = {3, 2, 1}; >+ std::vector<int> b_reversed_ = {5, 3, 1}; >+}; >+ >+TEST_F(SetOperationsTest, SetUnion) { >+ std::vector<int> actual; >+ absl::c_set_union(a_, b_, back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(1, 2, 3, 5)); >+} >+ >+TEST_F(SetOperationsTest, SetUnionWithComparator) { >+ std::vector<int> actual; >+ absl::c_set_union(a_reversed_, b_reversed_, back_inserter(actual), >+ std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(5, 3, 2, 1)); >+} >+ >+TEST_F(SetOperationsTest, SetIntersection) { >+ std::vector<int> actual; >+ absl::c_set_intersection(a_, b_, back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(1, 3)); >+} >+ >+TEST_F(SetOperationsTest, SetIntersectionWithComparator) { >+ std::vector<int> actual; >+ absl::c_set_intersection(a_reversed_, b_reversed_, back_inserter(actual), >+ std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(3, 1)); >+} >+ >+TEST_F(SetOperationsTest, SetDifference) { >+ std::vector<int> actual; >+ absl::c_set_difference(a_, b_, back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(2)); >+} >+ >+TEST_F(SetOperationsTest, SetDifferenceWithComparator) { >+ std::vector<int> actual; >+ absl::c_set_difference(a_reversed_, b_reversed_, back_inserter(actual), >+ std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(2)); >+} >+ >+TEST_F(SetOperationsTest, SetSymmetricDifference) { >+ std::vector<int> actual; >+ absl::c_set_symmetric_difference(a_, b_, back_inserter(actual)); >+ EXPECT_THAT(actual, ElementsAre(2, 5)); >+} >+ >+TEST_F(SetOperationsTest, SetSymmetricDifferenceWithComparator) { >+ std::vector<int> actual; >+ absl::c_set_symmetric_difference(a_reversed_, b_reversed_, >+ back_inserter(actual), std::greater<int>()); >+ EXPECT_THAT(actual, ElementsAre(5, 2)); >+} >+ >+TEST(HeapOperationsTest, WithoutComparator) { >+ std::vector<int> heap = {1, 2, 3}; >+ EXPECT_FALSE(absl::c_is_heap(heap)); >+ absl::c_make_heap(heap); >+ EXPECT_TRUE(absl::c_is_heap(heap)); >+ heap.push_back(4); >+ EXPECT_EQ(3, absl::c_is_heap_until(heap) - heap.begin()); >+ absl::c_push_heap(heap); >+ EXPECT_EQ(4, heap[0]); >+ absl::c_pop_heap(heap); >+ EXPECT_EQ(4, heap[3]); >+ absl::c_make_heap(heap); >+ absl::c_sort_heap(heap); >+ EXPECT_THAT(heap, ElementsAre(1, 2, 3, 4)); >+ EXPECT_FALSE(absl::c_is_heap(heap)); >+} >+ >+TEST(HeapOperationsTest, WithComparator) { >+ using greater = std::greater<int>; >+ std::vector<int> heap = {3, 2, 1}; >+ EXPECT_FALSE(absl::c_is_heap(heap, greater())); >+ absl::c_make_heap(heap, greater()); >+ EXPECT_TRUE(absl::c_is_heap(heap, greater())); >+ heap.push_back(0); >+ EXPECT_EQ(3, absl::c_is_heap_until(heap, greater()) - heap.begin()); >+ absl::c_push_heap(heap, greater()); >+ EXPECT_EQ(0, heap[0]); >+ absl::c_pop_heap(heap, greater()); >+ EXPECT_EQ(0, heap[3]); >+ absl::c_make_heap(heap, greater()); >+ absl::c_sort_heap(heap, greater()); >+ EXPECT_THAT(heap, ElementsAre(3, 2, 1, 0)); >+ EXPECT_FALSE(absl::c_is_heap(heap, greater())); >+} >+ >+TEST(MutatingTest, PermutationOperations) { >+ std::vector<int> initial = {1, 2, 3, 4}; >+ std::vector<int> permuted = initial; >+ >+ absl::c_next_permutation(permuted); >+ EXPECT_TRUE(absl::c_is_permutation(initial, permuted)); >+ EXPECT_TRUE(absl::c_is_permutation(initial, permuted, std::equal_to<int>())); >+ >+ std::vector<int> permuted2 = initial; >+ absl::c_prev_permutation(permuted2, std::greater<int>()); >+ EXPECT_EQ(permuted, permuted2); >+ >+ absl::c_prev_permutation(permuted); >+ EXPECT_EQ(initial, permuted); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc >new file mode 100644 >index 00000000000..19c0780ccd1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/algorithm/equal_benchmark.cc >@@ -0,0 +1,126 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstdint> >+#include <cstring> >+ >+#include "benchmark/benchmark.h" >+#include "absl/algorithm/algorithm.h" >+ >+namespace { >+ >+// The range of sequence sizes to benchmark. >+constexpr int kMinBenchmarkSize = 1024; >+constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024; >+ >+// A user-defined type for use in equality benchmarks. Note that we expect >+// std::memcmp to win for this type: libstdc++'s std::equal only defers to >+// memcmp for integral types. This is because it is not straightforward to >+// guarantee that std::memcmp would produce a result "as-if" compared by >+// operator== for other types (example gotchas: NaN floats, structs with >+// padding). >+struct EightBits { >+ explicit EightBits(int /* unused */) : data(0) {} >+ bool operator==(const EightBits& rhs) const { return data == rhs.data; } >+ uint8_t data; >+}; >+ >+template <typename T> >+void BM_absl_equal_benchmark(benchmark::State& state) { >+ std::vector<T> xs(state.range(0), T(0)); >+ std::vector<T> ys = xs; >+ while (state.KeepRunning()) { >+ const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end()); >+ benchmark::DoNotOptimize(same); >+ } >+} >+ >+template <typename T> >+void BM_std_equal_benchmark(benchmark::State& state) { >+ std::vector<T> xs(state.range(0), T(0)); >+ std::vector<T> ys = xs; >+ while (state.KeepRunning()) { >+ const bool same = std::equal(xs.begin(), xs.end(), ys.begin()); >+ benchmark::DoNotOptimize(same); >+ } >+} >+ >+template <typename T> >+void BM_memcmp_benchmark(benchmark::State& state) { >+ std::vector<T> xs(state.range(0), T(0)); >+ std::vector<T> ys = xs; >+ while (state.KeepRunning()) { >+ const bool same = >+ std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0; >+ benchmark::DoNotOptimize(same); >+ } >+} >+ >+// The expectation is that the compiler should be able to elide the equality >+// comparison altogether for sufficiently simple types. >+template <typename T> >+void BM_absl_equal_self_benchmark(benchmark::State& state) { >+ std::vector<T> xs(state.range(0), T(0)); >+ while (state.KeepRunning()) { >+ const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end()); >+ benchmark::DoNotOptimize(same); >+ } >+} >+ >+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+ >+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+ >+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+ >+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+ >+BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits) >+ ->Range(kMinBenchmarkSize, kMaxBenchmarkSize); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.bazel >new file mode 100644 >index 00000000000..06d092ebdfa >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.bazel >@@ -0,0 +1,423 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+ "ABSL_EXCEPTIONS_FLAG", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "spinlock_wait", >+ srcs = [ >+ "internal/spinlock_akaros.inc", >+ "internal/spinlock_posix.inc", >+ "internal/spinlock_wait.cc", >+ "internal/spinlock_win32.inc", >+ ], >+ hdrs = [ >+ "internal/scheduling_mode.h", >+ "internal/spinlock_wait.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl/base:__pkg__", >+ ], >+ deps = [":core_headers"], >+) >+ >+cc_library( >+ name = "config", >+ hdrs = [ >+ "config.h", >+ "policy_checks.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+) >+ >+cc_library( >+ name = "dynamic_annotations", >+ srcs = ["dynamic_annotations.cc"], >+ hdrs = ["dynamic_annotations.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ defines = ["__CLANG_SUPPORT_DYN_ANNOTATION__"], >+) >+ >+cc_library( >+ name = "core_headers", >+ hdrs = [ >+ "attributes.h", >+ "macros.h", >+ "optimization.h", >+ "port.h", >+ "thread_annotations.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":config", >+ ":dynamic_annotations", >+ ], >+) >+ >+cc_library( >+ name = "malloc_internal", >+ srcs = [ >+ "internal/low_level_alloc.cc", >+ ], >+ hdrs = [ >+ "internal/direct_mmap.h", >+ "internal/low_level_alloc.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+ deps = [ >+ ":base", >+ ":config", >+ ":core_headers", >+ ":dynamic_annotations", >+ ":spinlock_wait", >+ ], >+) >+ >+cc_library( >+ name = "base_internal", >+ hdrs = [ >+ "internal/hide_ptr.h", >+ "internal/identity.h", >+ "internal/inline_variable.h", >+ "internal/invoke.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+) >+ >+cc_library( >+ name = "base", >+ srcs = [ >+ "internal/cycleclock.cc", >+ "internal/raw_logging.cc", >+ "internal/spinlock.cc", >+ "internal/sysinfo.cc", >+ "internal/thread_identity.cc", >+ "internal/unscaledcycleclock.cc", >+ ], >+ hdrs = [ >+ "call_once.h", >+ "casts.h", >+ "internal/atomic_hook.h", >+ "internal/cycleclock.h", >+ "internal/low_level_scheduling.h", >+ "internal/per_thread_tls.h", >+ "internal/raw_logging.h", >+ "internal/spinlock.h", >+ "internal/sysinfo.h", >+ "internal/thread_identity.h", >+ "internal/tsan_mutex_interface.h", >+ "internal/unscaledcycleclock.h", >+ "log_severity.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":base_internal", >+ ":config", >+ ":core_headers", >+ ":dynamic_annotations", >+ ":spinlock_wait", >+ ], >+) >+ >+cc_test( >+ name = "atomic_hook_test", >+ size = "small", >+ srcs = ["internal/atomic_hook_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "bit_cast_test", >+ size = "small", >+ srcs = [ >+ "bit_cast_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "throw_delegate", >+ srcs = ["internal/throw_delegate.cc"], >+ hdrs = ["internal/throw_delegate.h"], >+ copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+ deps = [ >+ ":base", >+ ":config", >+ ":core_headers", >+ ], >+) >+ >+cc_test( >+ name = "throw_delegate_test", >+ srcs = ["throw_delegate_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":throw_delegate", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "exception_testing", >+ testonly = 1, >+ hdrs = ["internal/exception_testing.h"], >+ copts = ABSL_TEST_COPTS, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+ deps = [ >+ ":config", >+ "@com_google_googletest//:gtest", >+ ], >+) >+ >+cc_library( >+ name = "pretty_function", >+ hdrs = ["internal/pretty_function.h"], >+ visibility = ["//absl:__subpackages__"], >+) >+ >+cc_library( >+ name = "exception_safety_testing", >+ testonly = 1, >+ srcs = ["internal/exception_safety_testing.cc"], >+ hdrs = ["internal/exception_safety_testing.h"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":base", >+ ":config", >+ ":pretty_function", >+ "//absl/memory", >+ "//absl/meta:type_traits", >+ "//absl/strings", >+ "//absl/types:optional", >+ "@com_google_googletest//:gtest", >+ ], >+) >+ >+cc_test( >+ name = "exception_safety_testing_test", >+ srcs = ["exception_safety_testing_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":exception_safety_testing", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "inline_variable_test", >+ size = "small", >+ srcs = [ >+ "inline_variable_test.cc", >+ "inline_variable_test_a.cc", >+ "inline_variable_test_b.cc", >+ "internal/inline_variable_testing.h", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base_internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "invoke_test", >+ size = "small", >+ srcs = ["invoke_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base_internal", >+ "//absl/memory", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+# Common test library made available for use in non-absl code that overrides >+# AbslInternalSpinLockDelay and AbslInternalSpinLockWake. >+cc_library( >+ name = "spinlock_test_common", >+ testonly = 1, >+ srcs = ["spinlock_test_common.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":core_headers", >+ ":spinlock_wait", >+ "//absl/synchronization", >+ "@com_google_googletest//:gtest", >+ ], >+ alwayslink = 1, >+) >+ >+cc_test( >+ name = "spinlock_test", >+ size = "medium", >+ srcs = ["spinlock_test_common.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":core_headers", >+ ":spinlock_wait", >+ "//absl/synchronization", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "endian", >+ hdrs = [ >+ "internal/endian.h", >+ "internal/unaligned_access.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":config", >+ ":core_headers", >+ ], >+) >+ >+cc_test( >+ name = "endian_test", >+ srcs = ["internal/endian_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":config", >+ ":endian", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "config_test", >+ srcs = ["config_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":config", >+ "//absl/synchronization:thread_pool", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "call_once_test", >+ srcs = ["call_once_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ ":core_headers", >+ "//absl/synchronization", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "raw_logging_test", >+ srcs = ["raw_logging_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "sysinfo_test", >+ size = "small", >+ srcs = ["internal/sysinfo_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":base", >+ "//absl/synchronization", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "low_level_alloc_test", >+ size = "small", >+ srcs = ["internal/low_level_alloc_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ linkopts = select({ >+ "//absl:windows": [], >+ "//conditions:default": ["-pthread"], >+ }), >+ tags = ["no_test_ios_x86_64"], >+ deps = [":malloc_internal"], >+) >+ >+cc_test( >+ name = "thread_identity_test", >+ size = "small", >+ srcs = ["internal/thread_identity_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ linkopts = select({ >+ "//absl:windows": [], >+ "//conditions:default": ["-pthread"], >+ }), >+ deps = [ >+ ":base", >+ ":core_headers", >+ "//absl/synchronization", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "thread_identity_benchmark", >+ srcs = ["internal/thread_identity_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":base", >+ "//absl/synchronization", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.gn >new file mode 100644 >index 00000000000..a7146564622 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/BUILD.gn >@@ -0,0 +1,298 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("spinlock_wait") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/spinlock_akaros.inc", >+ "internal/spinlock_posix.inc", >+ "internal/spinlock_wait.cc", >+ "internal/spinlock_win32.inc", >+ ] >+ public = [ >+ "internal/scheduling_mode.h", >+ "internal/spinlock_wait.h", >+ ] >+ deps = [ >+ ":core_headers", >+ ] >+ visibility = [] >+ visibility += [ "../base:*" ] >+} >+ >+source_set("config") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "config.h", >+ "policy_checks.h", >+ ] >+} >+ >+config("clang_support_dynamic_annotations") { >+ cflags_cc = [ "-D__CLANG_SUPPORT_DYN_ANNOTATION__" ] >+} >+ >+source_set("dynamic_annotations") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ >+ ":clang_support_dynamic_annotations", >+ "//third_party/abseil-cpp:absl_include_config", >+ ] >+ sources = [ >+ "dynamic_annotations.cc", >+ ] >+ public = [ >+ "dynamic_annotations.h", >+ ] >+ # Abseil's dynamic annotations are only visible inside Abseil because >+ # their usage is deprecated in Chromium (see README.chromium for more info). >+ visibility = [] >+ visibility = [ "../*" ] >+} >+ >+source_set("core_headers") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "attributes.h", >+ "macros.h", >+ "optimization.h", >+ "port.h", >+ "thread_annotations.h", >+ ] >+ deps = [ >+ ":config", >+ ":dynamic_annotations", >+ ] >+} >+ >+source_set("malloc_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/low_level_alloc.cc", >+ ] >+ public = [ >+ "internal/direct_mmap.h", >+ "internal/low_level_alloc.h", >+ ] >+ deps = [ >+ ":base", >+ ":config", >+ ":core_headers", >+ ":dynamic_annotations", >+ ":spinlock_wait", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+source_set("base_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/hide_ptr.h", >+ "internal/identity.h", >+ "internal/inline_variable.h", >+ "internal/invoke.h", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+source_set("base") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/cycleclock.cc", >+ "internal/raw_logging.cc", >+ "internal/spinlock.cc", >+ "internal/sysinfo.cc", >+ "internal/thread_identity.cc", >+ "internal/unscaledcycleclock.cc", >+ ] >+ public = [ >+ "call_once.h", >+ "casts.h", >+ "internal/atomic_hook.h", >+ "internal/cycleclock.h", >+ "internal/low_level_scheduling.h", >+ "internal/per_thread_tls.h", >+ "internal/raw_logging.h", >+ "internal/spinlock.h", >+ "internal/sysinfo.h", >+ "internal/thread_identity.h", >+ "internal/tsan_mutex_interface.h", >+ "internal/unscaledcycleclock.h", >+ "log_severity.h", >+ ] >+ deps = [ >+ ":base_internal", >+ ":config", >+ ":core_headers", >+ ":dynamic_annotations", >+ ":spinlock_wait", >+ ] >+} >+ >+source_set("throw_delegate") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/throw_delegate.cc", >+ ] >+ public = [ >+ "internal/throw_delegate.h", >+ ] >+ deps = [ >+ ":base", >+ ":config", >+ ":core_headers", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+source_set("exception_testing") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_test_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/exception_testing.h", >+ ] >+ deps = [ >+ ":config", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+source_set("pretty_function") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/pretty_function.h", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+# TODO(mbonadei): This target throws by design. We should probably >+# just remove it. >+# source_set("exception_safety_testing") { >+# testonly = true >+# configs -= [ "//build/config/compiler:chromium_code" ] >+# configs += [ >+# "//build/config/compiler:no_chromium_code", >+# "//third_party/abseil-cpp:absl_test_cflags_cc", >+# ] >+# public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+# sources = [ >+# "internal/exception_safety_testing.cc", >+# ] >+# public = [ >+# "internal/exception_safety_testing.h", >+# ] >+# deps = [ >+# ":base", >+# ":config", >+# ":pretty_function", >+# "../memory", >+# "../meta:type_traits", >+# "../strings", >+# "../types:optional", >+# "//testing/gtest", >+# ] >+# } >+ >+source_set("spinlock_test_common") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_test_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "spinlock_test_common.cc", >+ ] >+ deps = [ >+ ":base", >+ ":core_headers", >+ ":spinlock_wait", >+ "../synchronization", >+ "//testing/gtest", >+ ] >+} >+ >+source_set("endian") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/endian.h", >+ "internal/unaligned_access.h", >+ ] >+ deps = [ >+ ":config", >+ ":core_headers", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/CMakeLists.txt >new file mode 100644 >index 00000000000..01d2af085f5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/CMakeLists.txt >@@ -0,0 +1,386 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND BASE_PUBLIC_HEADERS >+ "attributes.h" >+ "call_once.h" >+ "casts.h" >+ "config.h" >+ "dynamic_annotations.h" >+ "log_severity.h" >+ "macros.h" >+ "optimization.h" >+ "policy_checks.h" >+ "port.h" >+ "thread_annotations.h" >+) >+ >+ >+list(APPEND BASE_INTERNAL_HEADERS >+ "internal/atomic_hook.h" >+ "internal/cycleclock.h" >+ "internal/direct_mmap.h" >+ "internal/endian.h" >+ "internal/exception_testing.h" >+ "internal/exception_safety_testing.h" >+ "internal/hide_ptr.h" >+ "internal/identity.h" >+ "internal/invoke.h" >+ "internal/inline_variable.h" >+ "internal/low_level_alloc.h" >+ "internal/low_level_scheduling.h" >+ "internal/per_thread_tls.h" >+ "internal/pretty_function.h" >+ "internal/raw_logging.h" >+ "internal/scheduling_mode.h" >+ "internal/spinlock.h" >+ "internal/spinlock_wait.h" >+ "internal/sysinfo.h" >+ "internal/thread_identity.h" >+ "internal/throw_delegate.h" >+ "internal/tsan_mutex_interface.h" >+ "internal/unaligned_access.h" >+ "internal/unscaledcycleclock.h" >+) >+ >+ >+# absl_base main library >+list(APPEND BASE_SRC >+ "internal/cycleclock.cc" >+ "internal/raw_logging.cc" >+ "internal/spinlock.cc" >+ "internal/sysinfo.cc" >+ "internal/thread_identity.cc" >+ "internal/unscaledcycleclock.cc" >+ "internal/low_level_alloc.cc" >+ ${BASE_PUBLIC_HEADERS} >+ ${BASE_INTERNAL_HEADERS} >+) >+ >+absl_library( >+ TARGET >+ absl_base >+ SOURCES >+ ${BASE_SRC} >+ PUBLIC_LIBRARIES >+ absl_dynamic_annotations >+ absl_spinlock_wait >+ EXPORT_NAME >+ base >+) >+ >+# throw delegate library >+set(THROW_DELEGATE_SRC "internal/throw_delegate.cc") >+ >+absl_library( >+ TARGET >+ absl_throw_delegate >+ SOURCES >+ ${THROW_DELEGATE_SRC} >+ PUBLIC_LIBRARIES >+ ${THROW_DELEGATE_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+ EXPORT_NAME >+ throw_delegate >+) >+ >+if(BUILD_TESTING) >+ # exception-safety testing library >+ set(EXCEPTION_SAFETY_TESTING_SRC >+ "internal/exception_safety_testing.h" >+ "internal/exception_safety_testing.cc" >+ ) >+ set(EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES >+ ${ABSL_TEST_COMMON_LIBRARIES} >+ absl::base >+ absl::memory >+ absl::meta >+ absl::strings >+ absl::optional >+ gtest >+ ) >+ >+absl_library( >+ TARGET >+ absl_base_internal_exception_safety_testing >+ SOURCES >+ ${EXCEPTION_SAFETY_TESTING_SRC} >+ PUBLIC_LIBRARIES >+ ${EXCEPTION_SAFETY_TESTING_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+endif() >+ >+ >+# dynamic_annotations library >+set(DYNAMIC_ANNOTATIONS_SRC "dynamic_annotations.cc") >+ >+absl_library( >+ TARGET >+ absl_dynamic_annotations >+ SOURCES >+ ${DYNAMIC_ANNOTATIONS_SRC} >+) >+ >+ >+# spinlock_wait library >+set(SPINLOCK_WAIT_SRC "internal/spinlock_wait.cc") >+ >+absl_library( >+ TARGET >+ absl_spinlock_wait >+ SOURCES >+ ${SPINLOCK_WAIT_SRC} >+) >+ >+ >+# malloc_internal library >+list(APPEND MALLOC_INTERNAL_SRC >+ "internal/low_level_alloc.cc" >+) >+ >+absl_library( >+ TARGET >+ absl_malloc_internal >+ SOURCES >+ ${MALLOC_INTERNAL_SRC} >+ PUBLIC_LIBRARIES >+ absl_dynamic_annotations >+) >+ >+ >+ >+# >+## TESTS >+# >+ >+# call once test >+set(ATOMIC_HOOK_TEST_SRC "internal/atomic_hook_test.cc") >+set(ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES absl::base) >+ >+absl_test( >+ TARGET >+ atomic_hook_test >+ SOURCES >+ ${ATOMIC_HOOK_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ATOMIC_HOOK_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# call once test >+set(CALL_ONCE_TEST_SRC "call_once_test.cc") >+set(CALL_ONCE_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) >+ >+absl_test( >+ TARGET >+ call_once_test >+ SOURCES >+ ${CALL_ONCE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CALL_ONCE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test bit_cast_test >+set(BIT_CAST_TEST_SRC "bit_cast_test.cc") >+ >+absl_test( >+ TARGET >+ bit_cast_test >+ SOURCES >+ ${BIT_CAST_TEST_SRC} >+) >+ >+ >+# test absl_throw_delegate_test >+set(THROW_DELEGATE_TEST_SRC "throw_delegate_test.cc") >+set(THROW_DELEGATE_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate) >+ >+absl_test( >+ TARGET >+ throw_delegate_test >+ SOURCES >+ ${THROW_DELEGATE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${THROW_DELEGATE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test invoke_test >+set(INVOKE_TEST_SRC "invoke_test.cc") >+set(INVOKE_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ invoke_test >+ SOURCES >+ ${INVOKE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${INVOKE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test inline_variable_test >+list(APPEND INLINE_VARIABLE_TEST_SRC >+ "internal/inline_variable_testing.h" >+ "inline_variable_test.cc" >+ "inline_variable_test_a.cc" >+ "inline_variable_test_b.cc" >+) >+ >+set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base) >+ >+absl_test( >+ TARGET >+ inline_variable_test >+ SOURCES >+ ${INLINE_VARIABLE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test spinlock_test_common >+set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc") >+set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization) >+ >+absl_test( >+ TARGET >+ spinlock_test_common >+ SOURCES >+ ${SPINLOCK_TEST_COMMON_SRC} >+ PUBLIC_LIBRARIES >+ ${SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES} >+) >+ >+ >+# test spinlock_test >+set(SPINLOCK_TEST_SRC "spinlock_test_common.cc") >+set(SPINLOCK_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) >+ >+absl_test( >+ TARGET >+ spinlock_test >+ SOURCES >+ ${SPINLOCK_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${SPINLOCK_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test endian_test >+set(ENDIAN_TEST_SRC "internal/endian_test.cc") >+ >+absl_test( >+ TARGET >+ endian_test >+ SOURCES >+ ${ENDIAN_TEST_SRC} >+) >+ >+ >+# test config_test >+set(CONFIG_TEST_SRC "config_test.cc") >+set(CONFIG_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) >+absl_test( >+ TARGET >+ config_test >+ SOURCES >+ ${CONFIG_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CONFIG_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test raw_logging_test >+set(RAW_LOGGING_TEST_SRC "raw_logging_test.cc") >+set(RAW_LOGGING_TEST_PUBLIC_LIBRARIES absl::base absl::strings) >+ >+absl_test( >+ TARGET >+ raw_logging_test >+ SOURCES >+ ${RAW_LOGGING_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${RAW_LOGGING_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test sysinfo_test >+set(SYSINFO_TEST_SRC "internal/sysinfo_test.cc") >+set(SYSINFO_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) >+ >+absl_test( >+ TARGET >+ sysinfo_test >+ SOURCES >+ ${SYSINFO_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${SYSINFO_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test low_level_alloc_test >+set(LOW_LEVEL_ALLOC_TEST_SRC "internal/low_level_alloc_test.cc") >+set(LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES absl::base) >+ >+absl_test( >+ TARGET >+ low_level_alloc_test >+ SOURCES >+ ${LOW_LEVEL_ALLOC_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${LOW_LEVEL_ALLOC_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test thread_identity_test >+set(THREAD_IDENTITY_TEST_SRC "internal/thread_identity_test.cc") >+set(THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES absl::base absl::synchronization) >+ >+absl_test( >+ TARGET >+ thread_identity_test >+ SOURCES >+ ${THREAD_IDENTITY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${THREAD_IDENTITY_TEST_PUBLIC_LIBRARIES} >+) >+ >+#test exceptions_safety_testing_test >+set(EXCEPTION_SAFETY_TESTING_TEST_SRC "exception_safety_testing_test.cc") >+set(EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES >+ absl::base >+ absl_base_internal_exception_safety_testing >+ absl::memory >+ absl::meta >+ absl::strings >+ absl::optional >+) >+ >+absl_test( >+ TARGET >+ absl_exception_safety_testing_test >+ SOURCES >+ ${EXCEPTION_SAFETY_TESTING_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${EXCEPTION_SAFETY_TESTING_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/attributes.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/attributes.h >new file mode 100644 >index 00000000000..b1883b6d752 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/attributes.h >@@ -0,0 +1,568 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This header file defines macros for declaring attributes for functions, >+// types, and variables. >+// >+// These macros are used within Abseil and allow the compiler to optimize, where >+// applicable, certain function calls. >+// >+// This file is used for both C and C++! >+// >+// Most macros here are exposing GCC or Clang features, and are stubbed out for >+// other compilers. >+// >+// GCC attributes documentation: >+// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html >+// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html >+// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html >+// >+// Most attributes in this file are already supported by GCC 4.7. However, some >+// of them are not supported in older version of Clang. Thus, we check >+// `__has_attribute()` first. If the check fails, we check if we are on GCC and >+// assume the attribute exists on GCC (which is verified on GCC 4.7). >+// >+// ----------------------------------------------------------------------------- >+// Sanitizer Attributes >+// ----------------------------------------------------------------------------- >+// >+// Sanitizer-related attributes are not "defined" in this file (and indeed >+// are not defined as such in any file). To utilize the following >+// sanitizer-related attributes within your builds, define the following macros >+// within your build using a `-D` flag, along with the given value for >+// `-fsanitize`: >+// >+// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8) >+// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only) >+// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+) >+// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+) >+// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only) >+// >+// Example: >+// >+// // Enable branches in the Abseil code that are tagged for ASan: >+// $ bazel build --copt=-DADDRESS_SANITIZER --copt=-fsanitize=address >+// --linkopt=-fsanitize=address *target* >+// >+// Since these macro names are only supported by GCC and Clang, we only check >+// for `__GNUC__` (GCC or Clang) and the above macros. >+#ifndef ABSL_BASE_ATTRIBUTES_H_ >+#define ABSL_BASE_ATTRIBUTES_H_ >+ >+// ABSL_HAVE_ATTRIBUTE >+// >+// A function-like feature checking macro that is a wrapper around >+// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a >+// nonzero constant integer if the attribute is supported or 0 if not. >+// >+// It evaluates to zero if `__has_attribute` is not defined by the compiler. >+// >+// GCC: https://gcc.gnu.org/gcc-5/changes.html >+// Clang: https://clang.llvm.org/docs/LanguageExtensions.html >+#ifdef __has_attribute >+#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x) >+#else >+#define ABSL_HAVE_ATTRIBUTE(x) 0 >+#endif >+ >+// ABSL_HAVE_CPP_ATTRIBUTE >+// >+// A function-like feature checking macro that accepts C++11 style attributes. >+// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6 >+// (http://en.cppreference.com/w/cpp/experimental/feature_test). If we don't >+// find `__has_cpp_attribute`, will evaluate to 0. >+#if defined(__cplusplus) && defined(__has_cpp_attribute) >+// NOTE: requiring __cplusplus above should not be necessary, but >+// works around https://bugs.llvm.org/show_bug.cgi?id=23435. >+#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) >+#else >+#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0 >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Function Attributes >+// ----------------------------------------------------------------------------- >+// >+// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html >+// Clang: https://clang.llvm.org/docs/AttributeReference.html >+ >+// ABSL_PRINTF_ATTRIBUTE >+// ABSL_SCANF_ATTRIBUTE >+// >+// Tells the compiler to perform `printf` format std::string checking if the >+// compiler supports it; see the 'format' attribute in >+// <http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>. >+// >+// Note: As the GCC manual states, "[s]ince non-static C++ methods >+// have an implicit 'this' argument, the arguments of such methods >+// should be counted from two, not one." >+#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \ >+ __attribute__((__format__(__printf__, string_index, first_to_check))) >+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \ >+ __attribute__((__format__(__scanf__, string_index, first_to_check))) >+#else >+#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) >+#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) >+#endif >+ >+// ABSL_ATTRIBUTE_ALWAYS_INLINE >+// ABSL_ATTRIBUTE_NOINLINE >+// >+// Forces functions to either inline or not inline. Introduced in gcc 3.1. >+#if ABSL_HAVE_ATTRIBUTE(always_inline) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) >+#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1 >+#else >+#define ABSL_ATTRIBUTE_ALWAYS_INLINE >+#endif >+ >+#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline)) >+#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1 >+#else >+#define ABSL_ATTRIBUTE_NOINLINE >+#endif >+ >+// ABSL_ATTRIBUTE_NO_TAIL_CALL >+// >+// Prevents the compiler from optimizing away stack frames for functions which >+// end in a call to another function. >+#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls) >+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 >+#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls)) >+#elif defined(__GNUC__) && !defined(__clang__) >+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1 >+#define ABSL_ATTRIBUTE_NO_TAIL_CALL \ >+ __attribute__((optimize("no-optimize-sibling-calls"))) >+#else >+#define ABSL_ATTRIBUTE_NO_TAIL_CALL >+#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0 >+#endif >+ >+// ABSL_ATTRIBUTE_WEAK >+// >+// Tags a function as weak for the purposes of compilation and linking. >+#if ABSL_HAVE_ATTRIBUTE(weak) || (defined(__GNUC__) && !defined(__clang__)) >+#undef ABSL_ATTRIBUTE_WEAK >+#define ABSL_ATTRIBUTE_WEAK __attribute__((weak)) >+#define ABSL_HAVE_ATTRIBUTE_WEAK 1 >+#else >+#define ABSL_ATTRIBUTE_WEAK >+#define ABSL_HAVE_ATTRIBUTE_WEAK 0 >+#endif >+ >+// ABSL_ATTRIBUTE_NONNULL >+// >+// Tells the compiler either (a) that a particular function parameter >+// should be a non-null pointer, or (b) that all pointer arguments should >+// be non-null. >+// >+// Note: As the GCC manual states, "[s]ince non-static C++ methods >+// have an implicit 'this' argument, the arguments of such methods >+// should be counted from two, not one." >+// >+// Args are indexed starting at 1. >+// >+// For non-static class member functions, the implicit `this` argument >+// is arg 1, and the first explicit argument is arg 2. For static class member >+// functions, there is no implicit `this`, and the first explicit argument is >+// arg 1. >+// >+// Example: >+// >+// /* arg_a cannot be null, but arg_b can */ >+// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1); >+// >+// class C { >+// /* arg_a cannot be null, but arg_b can */ >+// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2); >+// >+// /* arg_a cannot be null, but arg_b can */ >+// static void StaticMethod(void* arg_a, void* arg_b) >+// ABSL_ATTRIBUTE_NONNULL(1); >+// }; >+// >+// If no arguments are provided, then all pointer arguments should be non-null. >+// >+// /* No pointer arguments may be null. */ >+// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL(); >+// >+// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but >+// ABSL_ATTRIBUTE_NONNULL does not. >+#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index))) >+#else >+#define ABSL_ATTRIBUTE_NONNULL(...) >+#endif >+ >+// ABSL_ATTRIBUTE_NORETURN >+// >+// Tells the compiler that a given function never returns. >+#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn)) >+#elif defined(_MSC_VER) >+#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn) >+#else >+#define ABSL_ATTRIBUTE_NORETURN >+#endif >+ >+// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS >+// >+// Tells the AddressSanitizer (or other memory testing tools) to ignore a given >+// function. Useful for cases when a function reads random locations on stack, >+// calls _exit from a cloned subprocess, deliberately accesses buffer >+// out of bounds or does other scary things with memory. >+// NOTE: GCC supports AddressSanitizer(asan) since 4.8. >+// https://gcc.gnu.org/gcc-4.8/changes.html >+#if defined(__GNUC__) && defined(ADDRESS_SANITIZER) >+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) >+#else >+#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS >+#endif >+ >+// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY >+// >+// Tells the MemorySanitizer to relax the handling of a given function. All >+// "Use of uninitialized value" warnings from such functions will be suppressed, >+// and all values loaded from memory will be considered fully initialized. >+// This attribute is similar to the ADDRESS_SANITIZER attribute above, but deals >+// with initialized-ness rather than addressability issues. >+// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC. >+#if defined(__GNUC__) && defined(MEMORY_SANITIZER) >+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) >+#else >+#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY >+#endif >+ >+// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD >+// >+// Tells the ThreadSanitizer to not instrument a given function. >+// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8. >+// https://gcc.gnu.org/gcc-4.8/changes.html >+#if defined(__GNUC__) && defined(THREAD_SANITIZER) >+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread)) >+#else >+#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD >+#endif >+ >+// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED >+// >+// Tells the UndefinedSanitizer to ignore a given function. Useful for cases >+// where certain behavior (eg. division by zero) is being used intentionally. >+// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9. >+// https://gcc.gnu.org/gcc-4.9/changes.html >+#if defined(__GNUC__) && \ >+ (defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER)) >+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \ >+ __attribute__((no_sanitize("undefined"))) >+#else >+#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED >+#endif >+ >+// ABSL_ATTRIBUTE_NO_SANITIZE_CFI >+// >+// Tells the ControlFlowIntegrity sanitizer to not instrument a given function. >+// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details. >+#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY) >+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi"))) >+#else >+#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI >+#endif >+ >+// ABSL_ATTRIBUTE_RETURNS_NONNULL >+// >+// Tells the compiler that a particular function never returns a null pointer. >+#if ABSL_HAVE_ATTRIBUTE(returns_nonnull) || \ >+ (defined(__GNUC__) && \ >+ (__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \ >+ !defined(__clang__)) >+#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) >+#else >+#define ABSL_ATTRIBUTE_RETURNS_NONNULL >+#endif >+ >+// ABSL_HAVE_ATTRIBUTE_SECTION >+// >+// Indicates whether labeled sections are supported. Labeled sections are not >+// supported on Darwin/iOS. >+#ifdef ABSL_HAVE_ATTRIBUTE_SECTION >+#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set >+#elif (ABSL_HAVE_ATTRIBUTE(section) || \ >+ (defined(__GNUC__) && !defined(__clang__))) && \ >+ !defined(__APPLE__) >+#define ABSL_HAVE_ATTRIBUTE_SECTION 1 >+ >+// ABSL_ATTRIBUTE_SECTION >+// >+// Tells the compiler/linker to put a given function into a section and define >+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. >+// This functionality is supported by GNU linker. Any function annotated with >+// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into >+// whatever section its caller is placed into. >+// >+#ifndef ABSL_ATTRIBUTE_SECTION >+#define ABSL_ATTRIBUTE_SECTION(name) \ >+ __attribute__((section(#name))) __attribute__((noinline)) >+#endif >+ >+ >+// ABSL_ATTRIBUTE_SECTION_VARIABLE >+// >+// Tells the compiler/linker to put a given variable into a section and define >+// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section. >+// This functionality is supported by GNU linker. >+#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE >+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name))) >+#endif >+ >+// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS >+// >+// A weak section declaration to be used as a global declaration >+// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link >+// even without functions with ABSL_ATTRIBUTE_SECTION(name). >+// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's >+// a no-op on ELF but not on Mach-O. >+// >+#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS >+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \ >+ extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \ >+ extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK >+#endif >+#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS >+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) >+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) >+#endif >+ >+// ABSL_ATTRIBUTE_SECTION_START >+// >+// Returns `void*` pointers to start/end of a section of code with >+// functions having ABSL_ATTRIBUTE_SECTION(name). >+// Returns 0 if no such functions exist. >+// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and >+// link. >+// >+#define ABSL_ATTRIBUTE_SECTION_START(name) \ >+ (reinterpret_cast<void *>(__start_##name)) >+#define ABSL_ATTRIBUTE_SECTION_STOP(name) \ >+ (reinterpret_cast<void *>(__stop_##name)) >+ >+#else // !ABSL_HAVE_ATTRIBUTE_SECTION >+ >+#define ABSL_HAVE_ATTRIBUTE_SECTION 0 >+ >+// provide dummy definitions >+#define ABSL_ATTRIBUTE_SECTION(name) >+#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) >+#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name) >+#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name) >+#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) >+#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0)) >+#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0)) >+ >+#endif // ABSL_ATTRIBUTE_SECTION >+ >+// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC >+// >+// Support for aligning the stack on 32-bit x86. >+#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+#if defined(__i386__) >+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \ >+ __attribute__((force_align_arg_pointer)) >+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) >+#elif defined(__x86_64__) >+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1) >+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC >+#else // !__i386__ && !__x86_64 >+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) >+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC >+#endif // __i386__ >+#else >+#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC >+#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0) >+#endif >+ >+// ABSL_MUST_USE_RESULT >+// >+// Tells the compiler to warn about unused return values for functions declared >+// with this macro. The macro must appear as the very first part of a function >+// declaration or definition: >+// >+// Example: >+// >+// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket(); >+// >+// This placement has the broadest compatibility with GCC, Clang, and MSVC, with >+// both defs and decls, and with GCC-style attributes, MSVC declspec, C++11 >+// and C++17 attributes. >+// >+// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result >+// warning. For that, warn_unused_result is used only for clang but not for gcc. >+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 >+// >+// Note: past advice was to place the macro after the argument list. >+#if ABSL_HAVE_ATTRIBUTE(nodiscard) >+#define ABSL_MUST_USE_RESULT [[nodiscard]] >+#elif defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result) >+#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result)) >+#else >+#define ABSL_MUST_USE_RESULT >+#endif >+ >+// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD >+// >+// Tells GCC that a function is hot or cold. GCC can use this information to >+// improve static analysis, i.e. a conditional branch to a cold function >+// is likely to be not-taken. >+// This annotation is used for function declarations. >+// >+// Example: >+// >+// int foo() ABSL_ATTRIBUTE_HOT; >+#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_HOT __attribute__((hot)) >+#else >+#define ABSL_ATTRIBUTE_HOT >+#endif >+ >+#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_COLD __attribute__((cold)) >+#else >+#define ABSL_ATTRIBUTE_COLD >+#endif >+ >+// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS >+// >+// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT >+// macro used as an attribute to mark functions that must always or never be >+// instrumented by XRay. Currently, this is only supported in Clang/LLVM. >+// >+// For reference on the LLVM XRay instrumentation, see >+// http://llvm.org/docs/XRay.html. >+// >+// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration >+// will always get the XRay instrumentation sleds. These sleds may introduce >+// some binary size and runtime overhead and must be used sparingly. >+// >+// These attributes only take effect when the following conditions are met: >+// >+// * The file/target is built in at least C++11 mode, with a Clang compiler >+// that supports XRay attributes. >+// * The file/target is built with the -fxray-instrument flag set for the >+// Clang/LLVM compiler. >+// * The function is defined in the translation unit (the compiler honors the >+// attribute in either the definition or the declaration, and must match). >+// >+// There are cases when, even when building with XRay instrumentation, users >+// might want to control specifically which functions are instrumented for a >+// particular build using special-case lists provided to the compiler. These >+// special case lists are provided to Clang via the >+// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The >+// attributes in source take precedence over these special-case lists. >+// >+// To disable the XRay attributes at build-time, users may define >+// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific >+// packages/targets, as this may lead to conflicting definitions of functions at >+// link-time. >+// >+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \ >+ !defined(ABSL_NO_XRAY_ATTRIBUTES) >+#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]] >+#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]] >+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args) >+#define ABSL_XRAY_LOG_ARGS(N) \ >+ [[clang::xray_always_instrument, clang::xray_log_args(N)]] >+#else >+#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]] >+#endif >+#else >+#define ABSL_XRAY_ALWAYS_INSTRUMENT >+#define ABSL_XRAY_NEVER_INSTRUMENT >+#define ABSL_XRAY_LOG_ARGS(N) >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Variable Attributes >+// ----------------------------------------------------------------------------- >+ >+// ABSL_ATTRIBUTE_UNUSED >+// >+// Prevents the compiler from complaining about or optimizing away variables >+// that appear unused. >+#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__)) >+#undef ABSL_ATTRIBUTE_UNUSED >+#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__)) >+#else >+#define ABSL_ATTRIBUTE_UNUSED >+#endif >+ >+// ABSL_ATTRIBUTE_INITIAL_EXEC >+// >+// Tells the compiler to use "initial-exec" mode for a thread-local variable. >+// See http://people.redhat.com/drepper/tls.pdf for the gory details. >+#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec"))) >+#else >+#define ABSL_ATTRIBUTE_INITIAL_EXEC >+#endif >+ >+// ABSL_ATTRIBUTE_PACKED >+// >+// Prevents the compiler from padding a structure to natural alignment >+#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__)) >+#else >+#define ABSL_ATTRIBUTE_PACKED >+#endif >+ >+// ABSL_ATTRIBUTE_FUNC_ALIGN >+// >+// Tells the compiler to align the function start at least to certain >+// alignment boundary >+#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes))) >+#else >+#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) >+#endif >+ >+// ABSL_CONST_INIT >+// >+// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will >+// not compile (on supported platforms) unless the variable has a constant >+// initializer. This is useful for variables with static and thread storage >+// duration, because it guarantees that they will not suffer from the so-called >+// "static init order fiasco". Prefer to put this attribute on the most visible >+// declaration of the variable, if there's more than one, because code that >+// accesses the variable can then use the attribute for optimization. >+// >+// Example: >+// >+// class MyClass { >+// public: >+// ABSL_CONST_INIT static MyType my_var; >+// }; >+// >+// MyType MyClass::my_var = MakeMyType(...); >+// >+// Note that this attribute is redundant if the variable is declared constexpr. >+#if ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) >+// NOLINTNEXTLINE(whitespace/braces) >+#define ABSL_CONST_INIT [[clang::require_constant_initialization]] >+#else >+#define ABSL_CONST_INIT >+#endif // ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization) >+ >+#endif // ABSL_BASE_ATTRIBUTES_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/bit_cast_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/bit_cast_test.cc >new file mode 100644 >index 00000000000..8cd878d756e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/bit_cast_test.cc >@@ -0,0 +1,107 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit test for bit_cast template. >+ >+#include <cstdint> >+#include <cstring> >+ >+#include "gtest/gtest.h" >+#include "absl/base/casts.h" >+#include "absl/base/macros.h" >+ >+namespace absl { >+namespace { >+ >+template <int N> >+struct marshall { char buf[N]; }; >+ >+template <typename T> >+void TestMarshall(const T values[], int num_values) { >+ for (int i = 0; i < num_values; ++i) { >+ T t0 = values[i]; >+ marshall<sizeof(T)> m0 = absl::bit_cast<marshall<sizeof(T)> >(t0); >+ T t1 = absl::bit_cast<T>(m0); >+ marshall<sizeof(T)> m1 = absl::bit_cast<marshall<sizeof(T)> >(t1); >+ ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T))); >+ ASSERT_EQ(0, memcmp(&m0, &m1, sizeof(T))); >+ } >+} >+ >+// Convert back and forth to an integral type. The C++ standard does >+// not guarantee this will work, but we test that this works on all the >+// platforms we support. >+// >+// Likewise, we below make assumptions about sizeof(float) and >+// sizeof(double) which the standard does not guarantee, but which hold on the >+// platforms we support. >+ >+template <typename T, typename I> >+void TestIntegral(const T values[], int num_values) { >+ for (int i = 0; i < num_values; ++i) { >+ T t0 = values[i]; >+ I i0 = absl::bit_cast<I>(t0); >+ T t1 = absl::bit_cast<T>(i0); >+ I i1 = absl::bit_cast<I>(t1); >+ ASSERT_EQ(0, memcmp(&t0, &t1, sizeof(T))); >+ ASSERT_EQ(i0, i1); >+ } >+} >+ >+TEST(BitCast, Bool) { >+ static const bool bool_list[] = { false, true }; >+ TestMarshall<bool>(bool_list, ABSL_ARRAYSIZE(bool_list)); >+} >+ >+TEST(BitCast, Int32) { >+ static const int32_t int_list[] = >+ { 0, 1, 100, 2147483647, -1, -100, -2147483647, -2147483647-1 }; >+ TestMarshall<int32_t>(int_list, ABSL_ARRAYSIZE(int_list)); >+} >+ >+TEST(BitCast, Int64) { >+ static const int64_t int64_list[] = >+ { 0, 1, 1LL << 40, -1, -(1LL<<40) }; >+ TestMarshall<int64_t>(int64_list, ABSL_ARRAYSIZE(int64_list)); >+} >+ >+TEST(BitCast, Uint64) { >+ static const uint64_t uint64_list[] = >+ { 0, 1, 1LLU << 40, 1LLU << 63 }; >+ TestMarshall<uint64_t>(uint64_list, ABSL_ARRAYSIZE(uint64_list)); >+} >+ >+TEST(BitCast, Float) { >+ static const float float_list[] = >+ { 0.0f, 1.0f, -1.0f, 10.0f, -10.0f, >+ 1e10f, 1e20f, 1e-10f, 1e-20f, >+ 2.71828f, 3.14159f }; >+ TestMarshall<float>(float_list, ABSL_ARRAYSIZE(float_list)); >+ TestIntegral<float, int>(float_list, ABSL_ARRAYSIZE(float_list)); >+ TestIntegral<float, unsigned>(float_list, ABSL_ARRAYSIZE(float_list)); >+} >+ >+TEST(BitCast, Double) { >+ static const double double_list[] = >+ { 0.0, 1.0, -1.0, 10.0, -10.0, >+ 1e10, 1e100, 1e-10, 1e-100, >+ 2.718281828459045, >+ 3.141592653589793238462643383279502884197169399375105820974944 }; >+ TestMarshall<double>(double_list, ABSL_ARRAYSIZE(double_list)); >+ TestIntegral<double, int64_t>(double_list, ABSL_ARRAYSIZE(double_list)); >+ TestIntegral<double, uint64_t>(double_list, ABSL_ARRAYSIZE(double_list)); >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once.h >new file mode 100644 >index 00000000000..532ee2e38bb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once.h >@@ -0,0 +1,216 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: call_once.h >+// ----------------------------------------------------------------------------- >+// >+// This header file provides an Abseil version of `std::call_once` for invoking >+// a given function at most once, across all threads. This Abseil version is >+// faster than the C++11 version and incorporates the C++17 argument-passing >+// fix, so that (for example) non-const references may be passed to the invoked >+// function. >+ >+#ifndef ABSL_BASE_CALL_ONCE_H_ >+#define ABSL_BASE_CALL_ONCE_H_ >+ >+#include <algorithm> >+#include <atomic> >+#include <cstdint> >+#include <type_traits> >+ >+#include "absl/base/internal/invoke.h" >+#include "absl/base/internal/low_level_scheduling.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/internal/spinlock_wait.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+ >+class once_flag; >+ >+namespace base_internal { >+std::atomic<uint32_t>* ControlWord(absl::once_flag* flag); >+} // namespace base_internal >+ >+// call_once() >+// >+// For all invocations using a given `once_flag`, invokes a given `fn` exactly >+// once across all threads. The first call to `call_once()` with a particular >+// `once_flag` argument (that does not throw an exception) will run the >+// specified function with the provided `args`; other calls with the same >+// `once_flag` argument will not run the function, but will wait >+// for the provided function to finish running (if it is still running). >+// >+// This mechanism provides a safe, simple, and fast mechanism for one-time >+// initialization in a multi-threaded process. >+// >+// Example: >+// >+// class MyInitClass { >+// public: >+// ... >+// mutable absl::once_flag once_; >+// >+// MyInitClass* init() const { >+// absl::call_once(once_, &MyInitClass::Init, this); >+// return ptr_; >+// } >+// >+template <typename Callable, typename... Args> >+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args); >+ >+// once_flag >+// >+// Objects of this type are used to distinguish calls to `call_once()` and >+// ensure the provided function is only invoked once across all threads. This >+// type is not copyable or movable. However, it has a `constexpr` >+// constructor, and is safe to use as a namespace-scoped global variable. >+class once_flag { >+ public: >+ constexpr once_flag() : control_(0) {} >+ once_flag(const once_flag&) = delete; >+ once_flag& operator=(const once_flag&) = delete; >+ >+ private: >+ friend std::atomic<uint32_t>* base_internal::ControlWord(once_flag* flag); >+ std::atomic<uint32_t> control_; >+}; >+ >+//------------------------------------------------------------------------------ >+// End of public interfaces. >+// Implementation details follow. >+//------------------------------------------------------------------------------ >+ >+namespace base_internal { >+ >+// Like call_once, but uses KERNEL_ONLY scheduling. Intended to be used to >+// initialize entities used by the scheduler implementation. >+template <typename Callable, typename... Args> >+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args); >+ >+// Disables scheduling while on stack when scheduling mode is non-cooperative. >+// No effect for cooperative scheduling modes. >+class SchedulingHelper { >+ public: >+ explicit SchedulingHelper(base_internal::SchedulingMode mode) : mode_(mode) { >+ if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) { >+ guard_result_ = base_internal::SchedulingGuard::DisableRescheduling(); >+ } >+ } >+ >+ ~SchedulingHelper() { >+ if (mode_ == base_internal::SCHEDULE_KERNEL_ONLY) { >+ base_internal::SchedulingGuard::EnableRescheduling(guard_result_); >+ } >+ } >+ >+ private: >+ base_internal::SchedulingMode mode_; >+ bool guard_result_; >+}; >+ >+// Bit patterns for call_once state machine values. Internal implementation >+// detail, not for use by clients. >+// >+// The bit patterns are arbitrarily chosen from unlikely values, to aid in >+// debugging. However, kOnceInit must be 0, so that a zero-initialized >+// once_flag will be valid for immediate use. >+enum { >+ kOnceInit = 0, >+ kOnceRunning = 0x65C2937B, >+ kOnceWaiter = 0x05A308D2, >+ // A very small constant is chosen for kOnceDone so that it fit in a single >+ // compare with immediate instruction for most common ISAs. This is verified >+ // for x86, POWER and ARM. >+ kOnceDone = 221, // Random Number >+}; >+ >+template <typename Callable, typename... Args> >+void CallOnceImpl(std::atomic<uint32_t>* control, >+ base_internal::SchedulingMode scheduling_mode, Callable&& fn, >+ Args&&... args) { >+#ifndef NDEBUG >+ { >+ uint32_t old_control = control->load(std::memory_order_acquire); >+ if (old_control != kOnceInit && >+ old_control != kOnceRunning && >+ old_control != kOnceWaiter && >+ old_control != kOnceDone) { >+ ABSL_RAW_LOG( >+ FATAL, >+ "Unexpected value for control word: %lx. Either the control word " >+ "has non-static storage duration (where GoogleOnceDynamic might " >+ "be appropriate), or there's been a memory corruption.", >+ static_cast<unsigned long>(old_control)); // NOLINT >+ } >+ } >+#endif // NDEBUG >+ static const base_internal::SpinLockWaitTransition trans[] = { >+ {kOnceInit, kOnceRunning, true}, >+ {kOnceRunning, kOnceWaiter, false}, >+ {kOnceDone, kOnceDone, true}}; >+ >+ // Must do this before potentially modifying control word's state. >+ base_internal::SchedulingHelper maybe_disable_scheduling(scheduling_mode); >+ // Short circuit the simplest case to avoid procedure call overhead. >+ uint32_t old_control = kOnceInit; >+ if (control->compare_exchange_strong(old_control, kOnceRunning, >+ std::memory_order_acquire, >+ std::memory_order_relaxed) || >+ base_internal::SpinLockWait(control, ABSL_ARRAYSIZE(trans), trans, >+ scheduling_mode) == kOnceInit) { >+ base_internal::Invoke(std::forward<Callable>(fn), >+ std::forward<Args>(args)...); >+ old_control = control->load(std::memory_order_relaxed); >+ control->store(base_internal::kOnceDone, std::memory_order_release); >+ if (old_control == base_internal::kOnceWaiter) { >+ base_internal::SpinLockWake(control, true); >+ } >+ } // else *control is already kOnceDone >+} >+ >+inline std::atomic<uint32_t>* ControlWord(once_flag* flag) { >+ return &flag->control_; >+} >+ >+template <typename Callable, typename... Args> >+void LowLevelCallOnce(absl::once_flag* flag, Callable&& fn, Args&&... args) { >+ std::atomic<uint32_t>* once = base_internal::ControlWord(flag); >+ uint32_t s = once->load(std::memory_order_acquire); >+ if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) { >+ base_internal::CallOnceImpl(once, base_internal::SCHEDULE_KERNEL_ONLY, >+ std::forward<Callable>(fn), >+ std::forward<Args>(args)...); >+ } >+} >+ >+} // namespace base_internal >+ >+template <typename Callable, typename... Args> >+void call_once(absl::once_flag& flag, Callable&& fn, Args&&... args) { >+ std::atomic<uint32_t>* once = base_internal::ControlWord(&flag); >+ uint32_t s = once->load(std::memory_order_acquire); >+ if (ABSL_PREDICT_FALSE(s != base_internal::kOnceDone)) { >+ base_internal::CallOnceImpl( >+ once, base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL, >+ std::forward<Callable>(fn), std::forward<Args>(args)...); >+ } >+} >+ >+} // namespace absl >+ >+#endif // ABSL_BASE_CALL_ONCE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once_test.cc >new file mode 100644 >index 00000000000..cd58ee19f08 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/call_once_test.cc >@@ -0,0 +1,102 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/call_once.h" >+ >+#include <thread> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+namespace { >+ >+absl::once_flag once; >+Mutex counters_mu; >+ >+int running_thread_count GUARDED_BY(counters_mu) = 0; >+int call_once_invoke_count GUARDED_BY(counters_mu) = 0; >+int call_once_finished_count GUARDED_BY(counters_mu) = 0; >+int call_once_return_count GUARDED_BY(counters_mu) = 0; >+bool done_blocking GUARDED_BY(counters_mu) = false; >+ >+// Function to be called from absl::call_once. Waits for a notification. >+void WaitAndIncrement() { >+ counters_mu.Lock(); >+ ++call_once_invoke_count; >+ counters_mu.Unlock(); >+ >+ counters_mu.LockWhen(Condition(&done_blocking)); >+ ++call_once_finished_count; >+ counters_mu.Unlock(); >+} >+ >+void ThreadBody() { >+ counters_mu.Lock(); >+ ++running_thread_count; >+ counters_mu.Unlock(); >+ >+ absl::call_once(once, WaitAndIncrement); >+ >+ counters_mu.Lock(); >+ ++call_once_return_count; >+ counters_mu.Unlock(); >+} >+ >+// Returns true if all threads are set up for the test. >+bool ThreadsAreSetup(void*) EXCLUSIVE_LOCKS_REQUIRED(counters_mu) { >+ // All ten threads must be running, and WaitAndIncrement should be blocked. >+ return running_thread_count == 10 && call_once_invoke_count == 1; >+} >+ >+TEST(CallOnceTest, ExecutionCount) { >+ std::vector<std::thread> threads; >+ >+ // Start 10 threads all calling call_once on the same once_flag. >+ for (int i = 0; i < 10; ++i) { >+ threads.emplace_back(ThreadBody); >+ } >+ >+ >+ // Wait until all ten threads have started, and WaitAndIncrement has been >+ // invoked. >+ counters_mu.LockWhen(Condition(ThreadsAreSetup, nullptr)); >+ >+ // WaitAndIncrement should have been invoked by exactly one call_once() >+ // instance. That thread should be blocking on a notification, and all other >+ // call_once instances should be blocking as well. >+ EXPECT_EQ(call_once_invoke_count, 1); >+ EXPECT_EQ(call_once_finished_count, 0); >+ EXPECT_EQ(call_once_return_count, 0); >+ >+ // Allow WaitAndIncrement to finish executing. Once it does, the other >+ // call_once waiters will be unblocked. >+ done_blocking = true; >+ counters_mu.Unlock(); >+ >+ for (std::thread& thread : threads) { >+ thread.join(); >+ } >+ >+ counters_mu.Lock(); >+ EXPECT_EQ(call_once_invoke_count, 1); >+ EXPECT_EQ(call_once_finished_count, 1); >+ EXPECT_EQ(call_once_return_count, 10); >+ counters_mu.Unlock(); >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/casts.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/casts.h >new file mode 100644 >index 00000000000..20fd34da701 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/casts.h >@@ -0,0 +1,189 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: casts.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines casting templates to fit use cases not covered by >+// the standard casts provided in the C++ standard. As with all cast operations, >+// use these with caution and only if alternatives do not exist. >+ >+#ifndef ABSL_BASE_CASTS_H_ >+#define ABSL_BASE_CASTS_H_ >+ >+#include <cstring> >+#include <memory> >+#include <type_traits> >+ >+#include "absl/base/internal/identity.h" >+#include "absl/base/macros.h" >+ >+namespace absl { >+ >+namespace internal_casts { >+ >+// NOTE: Not a fully compliant implementation of `std::is_trivially_copyable`. >+// TODO(calabrese) Branch on implementations that directly provide >+// `std::is_trivially_copyable`, create a more rigorous workaround, and publicly >+// expose in meta/type_traits. >+template <class T> >+struct is_trivially_copyable >+ : std::integral_constant< >+ bool, std::is_destructible<T>::value&& __has_trivial_destructor(T) && >+ __has_trivial_copy(T) && __has_trivial_assign(T)> {}; >+ >+template <class Dest, class Source> >+struct is_bitcastable >+ : std::integral_constant<bool, >+ sizeof(Dest) == sizeof(Source) && >+ is_trivially_copyable<Source>::value && >+ is_trivially_copyable<Dest>::value && >+ std::is_default_constructible<Dest>::value> {}; >+ >+} // namespace internal_casts >+ >+// implicit_cast() >+// >+// Performs an implicit conversion between types following the language >+// rules for implicit conversion; if an implicit conversion is otherwise >+// allowed by the language in the given context, this function performs such an >+// implicit conversion. >+// >+// Example: >+// >+// // If the context allows implicit conversion: >+// From from; >+// To to = from; >+// >+// // Such code can be replaced by: >+// implicit_cast<To>(from); >+// >+// An `implicit_cast()` may also be used to annotate numeric type conversions >+// that, although safe, may produce compiler warnings (such as `long` to `int`). >+// Additionally, an `implicit_cast()` is also useful within return statements to >+// indicate a specific implicit conversion is being undertaken. >+// >+// Example: >+// >+// return implicit_cast<double>(size_in_bytes) / capacity_; >+// >+// Annotating code with `implicit_cast()` allows you to explicitly select >+// particular overloads and template instantiations, while providing a safer >+// cast than `reinterpret_cast()` or `static_cast()`. >+// >+// Additionally, an `implicit_cast()` can be used to allow upcasting within a >+// type hierarchy where incorrect use of `static_cast()` could accidentally >+// allow downcasting. >+// >+// Finally, an `implicit_cast()` can be used to perform implicit conversions >+// from unrelated types that otherwise couldn't be implicitly cast directly; >+// C++ will normally only implicitly cast "one step" in such conversions. >+// >+// That is, if C is a type which can be implicitly converted to B, with B being >+// a type that can be implicitly converted to A, an `implicit_cast()` can be >+// used to convert C to B (which the compiler can then implicitly convert to A >+// using language rules). >+// >+// Example: >+// >+// // Assume an object C is convertible to B, which is implicitly convertible >+// // to A >+// A a = implicit_cast<B>(C); >+// >+// Such implicit cast chaining may be useful within template logic. >+template <typename To> >+inline To implicit_cast(typename absl::internal::identity_t<To> to) { >+ return to; >+} >+ >+// bit_cast() >+// >+// Performs a bitwise cast on a type without changing the underlying bit >+// representation of that type's value. The two types must be of the same size >+// and both types must be trivially copyable. As with most casts, use with >+// caution. A `bit_cast()` might be needed when you need to temporarily treat a >+// type as some other type, such as in the following cases: >+// >+// * Serialization (casting temporarily to `char *` for those purposes is >+// always allowed by the C++ standard) >+// * Managing the individual bits of a type within mathematical operations >+// that are not normally accessible through that type >+// * Casting non-pointer types to pointer types (casting the other way is >+// allowed by `reinterpret_cast()` but round-trips cannot occur the other >+// way). >+// >+// Example: >+// >+// float f = 3.14159265358979; >+// int i = bit_cast<int32_t>(f); >+// // i = 0x40490fdb >+// >+// Casting non-pointer types to pointer types and then dereferencing them >+// traditionally produces undefined behavior. >+// >+// Example: >+// >+// // WRONG >+// float f = 3.14159265358979; // WRONG >+// int i = * reinterpret_cast<int*>(&f); // WRONG >+// >+// The address-casting method produces undefined behavior according to the ISO >+// C++ specification section [basic.lval]. Roughly, this section says: if an >+// object in memory has one type, and a program accesses it with a different >+// type, the result is undefined behavior for most values of "different type". >+// >+// Such casting results in type punning: holding an object in memory of one type >+// and reading its bits back using a different type. A `bit_cast()` avoids this >+// issue by implementing its casts using `memcpy()`, which avoids introducing >+// this undefined behavior. >+// >+// NOTE: The requirements here are more strict than the bit_cast of standard >+// proposal p0476 due to the need for workarounds and lack of intrinsics. >+// Specifically, this implementation also requires `Dest` to be >+// default-constructible. >+template < >+ typename Dest, typename Source, >+ typename std::enable_if<internal_casts::is_bitcastable<Dest, Source>::value, >+ int>::type = 0> >+inline Dest bit_cast(const Source& source) { >+ Dest dest; >+ memcpy(static_cast<void*>(std::addressof(dest)), >+ static_cast<const void*>(std::addressof(source)), sizeof(dest)); >+ return dest; >+} >+ >+// NOTE: This overload is only picked if the requirements of bit_cast are not >+// met. It is therefore UB, but is provided temporarily as previous versions of >+// this function template were unchecked. Do not use this in new code. >+template < >+ typename Dest, typename Source, >+ typename std::enable_if< >+ !internal_casts::is_bitcastable<Dest, Source>::value, int>::type = 0> >+ABSL_DEPRECATED( >+ "absl::bit_cast type requirements were violated. Update the types being " >+ "used such that they are the same size and are both TriviallyCopyable.") >+inline Dest bit_cast(const Source& source) { >+ static_assert(sizeof(Dest) == sizeof(Source), >+ "Source and destination types should have equal sizes."); >+ >+ Dest dest; >+ memcpy(&dest, &source, sizeof(dest)); >+ return dest; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_BASE_CASTS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config.h >new file mode 100644 >index 00000000000..6890e313bf2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config.h >@@ -0,0 +1,427 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: config.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines a set of macros for checking the presence of >+// important compiler and platform features. Such macros can be used to >+// produce portable code by parameterizing compilation based on the presence or >+// lack of a given feature. >+// >+// We define a "feature" as some interface we wish to program to: for example, >+// a library function or system call. A value of `1` indicates support for >+// that feature; any other value indicates the feature support is undefined. >+// >+// Example: >+// >+// Suppose a programmer wants to write a program that uses the 'mmap()' system >+// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to >+// selectively include the `mmap.h` header and bracket code using that feature >+// in the macro: >+// >+// #include "absl/base/config.h" >+// >+// #ifdef ABSL_HAVE_MMAP >+// #include "sys/mman.h" >+// #endif //ABSL_HAVE_MMAP >+// >+// ... >+// #ifdef ABSL_HAVE_MMAP >+// void *ptr = mmap(...); >+// ... >+// #endif // ABSL_HAVE_MMAP >+ >+#ifndef ABSL_BASE_CONFIG_H_ >+#define ABSL_BASE_CONFIG_H_ >+ >+// Included for the __GLIBC__ macro (or similar macros on other systems). >+#include <limits.h> >+ >+#ifdef __cplusplus >+// Included for __GLIBCXX__, _LIBCPP_VERSION >+#include <cstddef> >+#endif // __cplusplus >+ >+#if defined(__APPLE__) >+// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED, >+// __IPHONE_8_0. >+#include <Availability.h> >+#include <TargetConditionals.h> >+#endif >+ >+#include "absl/base/policy_checks.h" >+ >+// ----------------------------------------------------------------------------- >+// Compiler Feature Checks >+// ----------------------------------------------------------------------------- >+ >+// ABSL_HAVE_BUILTIN() >+// >+// Checks whether the compiler supports a Clang Feature Checking Macro, and if >+// so, checks whether it supports the provided builtin function "x" where x >+// is one of the functions noted in >+// https://clang.llvm.org/docs/LanguageExtensions.html >+// >+// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check. >+// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html >+#ifdef __has_builtin >+#define ABSL_HAVE_BUILTIN(x) __has_builtin(x) >+#else >+#define ABSL_HAVE_BUILTIN(x) 0 >+#endif >+ >+// ABSL_HAVE_TLS is defined to 1 when __thread should be supported. >+// We assume __thread is supported on Linux when compiled with Clang or compiled >+// against libstdc++ with _GLIBCXX_HAVE_TLS defined. >+#ifdef ABSL_HAVE_TLS >+#error ABSL_HAVE_TLS cannot be directly set >+#elif defined(__linux__) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS)) >+#define ABSL_HAVE_TLS 1 >+#endif >+ >+// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE >+// >+// Checks whether `std::is_trivially_destructible<T>` is supported. >+// >+// Notes: All supported compilers using libc++ support this feature, as does >+// gcc >= 4.8.1 using libstdc++, and Visual Studio. >+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE >+#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set >+#elif defined(_LIBCPP_VERSION) || \ >+ (!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && \ >+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || \ >+ defined(_MSC_VER) >+#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1 >+#endif >+ >+// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE >+// >+// Checks whether `std::is_trivially_default_constructible<T>` and >+// `std::is_trivially_copy_constructible<T>` are supported. >+ >+// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE >+// >+// Checks whether `std::is_trivially_copy_assignable<T>` is supported. >+ >+// Notes: Clang with libc++ supports these features, as does gcc >= 5.1 with >+// either libc++ or libstdc++, and Visual Studio. >+#if defined(ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE) >+#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set >+#elif defined(ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE) >+#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set >+#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \ >+ (!defined(__clang__) && defined(__GNUC__) && \ >+ (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1)) && \ >+ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \ >+ defined(_MSC_VER) >+#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1 >+#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1 >+#endif >+ >+// ABSL_HAVE_THREAD_LOCAL >+// >+// Checks whether C++11's `thread_local` storage duration specifier is >+// supported. >+#ifdef ABSL_HAVE_THREAD_LOCAL >+#error ABSL_HAVE_THREAD_LOCAL cannot be directly set >+#elif defined(__APPLE__) >+// Notes: Xcode's clang did not support `thread_local` until version >+// 8, and even then not for all iOS < 9.0. Also, Xcode 9.3 started disallowing >+// `thread_local` for 32-bit iOS simulator targeting iOS 9.x. >+// `__has_feature` is only supported by Clang so it has be inside >+// `defined(__APPLE__)` check. >+#if __has_feature(cxx_thread_local) >+#define ABSL_HAVE_THREAD_LOCAL 1 >+#endif >+#else // !defined(__APPLE__) >+#define ABSL_HAVE_THREAD_LOCAL 1 >+#endif >+ >+// There are platforms for which TLS should not be used even though the compiler >+// makes it seem like it's supported (Android NDK < r12b for example). >+// This is primarily because of linker problems and toolchain misconfiguration: >+// Abseil does not intend to support this indefinitely. Currently, the newest >+// toolchain that we intend to support that requires this behavior is the >+// r11 NDK - allowing for a 5 year support window on that means this option >+// is likely to be removed around June of 2021. >+// TLS isn't supported until NDK r12b per >+// https://developer.android.com/ndk/downloads/revision_history.html >+// Since NDK r16, `__NDK_MAJOR__` and `__NDK_MINOR__` are defined in >+// <android/ndk-version.h>. For NDK < r16, users should define these macros, >+// e.g. `-D__NDK_MAJOR__=11 -D__NKD_MINOR__=0` for NDK r11. >+#if defined(__ANDROID__) && defined(__clang__) >+#if __has_include(<android/ndk-version.h>) >+#include <android/ndk-version.h> >+#endif // __has_include(<android/ndk-version.h>) >+#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \ >+ defined(__NDK_MINOR__) && \ >+ ((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1))) >+#undef ABSL_HAVE_TLS >+#undef ABSL_HAVE_THREAD_LOCAL >+#endif >+#endif // defined(__ANDROID__) && defined(__clang__) >+ >+// ABSL_HAVE_INTRINSIC_INT128 >+// >+// Checks whether the __int128 compiler extension for a 128-bit integral type is >+// supported. >+// >+// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is >+// supported, but we avoid using it in certain cases: >+// * On Clang: >+// * Building using Clang for Windows, where the Clang runtime library has >+// 128-bit support only on LP64 architectures, but Windows is LLP64. >+// * Building for aarch64, where __int128 exists but has exhibits a sporadic >+// compiler crashing bug. >+// * On Nvidia's nvcc: >+// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions >+// actually support __int128. >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set >+#elif defined(__SIZEOF_INT128__) >+#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \ >+ (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ >+ (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) >+#define ABSL_HAVE_INTRINSIC_INT128 1 >+#elif defined(__CUDACC__) >+// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a >+// std::string explaining that it has been removed starting with CUDA 9. We use >+// nested #ifs because there is no short-circuiting in the preprocessor. >+// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined. >+#if __CUDACC_VER__ >= 70000 >+#define ABSL_HAVE_INTRINSIC_INT128 1 >+#endif // __CUDACC_VER__ >= 70000 >+#endif // defined(__CUDACC__) >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+// ABSL_HAVE_EXCEPTIONS >+// >+// Checks whether the compiler both supports and enables exceptions. Many >+// compilers support a "no exceptions" mode that disables exceptions. >+// >+// Generally, when ABSL_HAVE_EXCEPTIONS is not defined: >+// >+// * Code using `throw` and `try` may not compile. >+// * The `noexcept` specifier will still compile and behave as normal. >+// * The `noexcept` operator may still return `false`. >+// >+// For further details, consult the compiler's documentation. >+#ifdef ABSL_HAVE_EXCEPTIONS >+#error ABSL_HAVE_EXCEPTIONS cannot be directly set. >+ >+#elif defined(__clang__) >+// TODO(calabrese) >+// Switch to using __cpp_exceptions when we no longer support versions < 3.6. >+// For details on this check, see: >+// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro >+#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) >+#define ABSL_HAVE_EXCEPTIONS 1 >+#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions) >+ >+// Handle remaining special cases and default to exceptions being supported. >+#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \ >+ !(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \ >+ !(defined(_MSC_VER) && !defined(_CPPUNWIND)) >+#define ABSL_HAVE_EXCEPTIONS 1 >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Platform Feature Checks >+// ----------------------------------------------------------------------------- >+ >+// Currently supported operating systems and associated preprocessor >+// symbols: >+// >+// Linux and Linux-derived __linux__ >+// Android __ANDROID__ (implies __linux__) >+// Linux (non-Android) __linux__ && !__ANDROID__ >+// Darwin (Mac OS X and iOS) __APPLE__ >+// Akaros (http://akaros.org) __ros__ >+// Windows _WIN32 >+// NaCL __native_client__ >+// AsmJS __asmjs__ >+// WebAssembly __wasm__ >+// Fuchsia __Fuchsia__ >+// >+// Note that since Android defines both __ANDROID__ and __linux__, one >+// may probe for either Linux or Android by simply testing for __linux__. >+ >+// ABSL_HAVE_MMAP >+// >+// Checks whether the platform has an mmap(2) implementation as defined in >+// POSIX.1-2001. >+#ifdef ABSL_HAVE_MMAP >+#error ABSL_HAVE_MMAP cannot be directly set >+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ >+ defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \ >+ defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) >+#define ABSL_HAVE_MMAP 1 >+#endif >+ >+// ABSL_HAVE_PTHREAD_GETSCHEDPARAM >+// >+// Checks whether the platform implements the pthread_(get|set)schedparam(3) >+// functions as defined in POSIX.1-2001. >+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM >+#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set >+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ >+ defined(__ros__) >+#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1 >+#endif >+ >+// ABSL_HAVE_SCHED_YIELD >+// >+// Checks whether the platform implements sched_yield(2) as defined in >+// POSIX.1-2001. >+#ifdef ABSL_HAVE_SCHED_YIELD >+#error ABSL_HAVE_SCHED_YIELD cannot be directly set >+#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) >+#define ABSL_HAVE_SCHED_YIELD 1 >+#endif >+ >+// ABSL_HAVE_SEMAPHORE_H >+// >+// Checks whether the platform supports the <semaphore.h> header and sem_open(3) >+// family of functions as standardized in POSIX.1-2001. >+// >+// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is >+// explicitly deprecated and will cause build failures if enabled for those >+// platforms. We side-step the issue by not defining it here for Apple >+// platforms. >+#ifdef ABSL_HAVE_SEMAPHORE_H >+#error ABSL_HAVE_SEMAPHORE_H cannot be directly set >+#elif defined(__linux__) || defined(__ros__) >+#define ABSL_HAVE_SEMAPHORE_H 1 >+#endif >+ >+// ABSL_HAVE_ALARM >+// >+// Checks whether the platform supports the <signal.h> header and alarm(2) >+// function as standardized in POSIX.1-2001. >+#ifdef ABSL_HAVE_ALARM >+#error ABSL_HAVE_ALARM cannot be directly set >+#elif defined(__GOOGLE_GRTE_VERSION__) >+// feature tests for Google's GRTE >+#define ABSL_HAVE_ALARM 1 >+#elif defined(__GLIBC__) >+// feature test for glibc >+#define ABSL_HAVE_ALARM 1 >+#elif defined(_MSC_VER) >+// feature tests for Microsoft's library >+#elif defined(__native_client__) >+#else >+// other standard libraries >+#define ABSL_HAVE_ALARM 1 >+#endif >+ >+// ABSL_IS_LITTLE_ENDIAN >+// ABSL_IS_BIG_ENDIAN >+// >+// Checks the endianness of the platform. >+// >+// Notes: uses the built in endian macros provided by GCC (since 4.6) and >+// Clang (since 3.2); see >+// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html. >+// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error. >+#if defined(ABSL_IS_BIG_ENDIAN) >+#error "ABSL_IS_BIG_ENDIAN cannot be directly set." >+#endif >+#if defined(ABSL_IS_LITTLE_ENDIAN) >+#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set." >+#endif >+ >+#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ >+ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) >+#define ABSL_IS_LITTLE_ENDIAN 1 >+#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ >+ __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ >+#define ABSL_IS_BIG_ENDIAN 1 >+#elif defined(_WIN32) >+#define ABSL_IS_LITTLE_ENDIAN 1 >+#else >+#error "absl endian detection needs to be set up for your compiler" >+#endif >+ >+// ABSL_HAVE_STD_ANY >+// >+// Checks whether C++17 std::any is available by checking whether <any> exists. >+#ifdef ABSL_HAVE_STD_ANY >+#error "ABSL_HAVE_STD_ANY cannot be directly set." >+#endif >+ >+#ifdef __has_include >+#if __has_include(<any>) && __cplusplus >= 201703L >+#define ABSL_HAVE_STD_ANY 1 >+#endif >+#endif >+ >+// ABSL_HAVE_STD_OPTIONAL >+// >+// Checks whether C++17 std::optional is available. >+#ifdef ABSL_HAVE_STD_OPTIONAL >+#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set." >+#endif >+ >+#ifdef __has_include >+#if __has_include(<optional>) && __cplusplus >= 201703L >+#define ABSL_HAVE_STD_OPTIONAL 1 >+#endif >+#endif >+ >+// ABSL_HAVE_STD_VARIANT >+// >+// Checks whether C++17 std::variant is available. >+#ifdef ABSL_HAVE_STD_VARIANT >+#error "ABSL_HAVE_STD_VARIANT cannot be directly set." >+#endif >+ >+#ifdef __has_include >+#if __has_include(<variant>) && __cplusplus >= 201703L >+#define ABSL_HAVE_STD_VARIANT 1 >+#endif >+#endif >+ >+// ABSL_HAVE_STD_STRING_VIEW >+// >+// Checks whether C++17 std::string_view is available. >+#ifdef ABSL_HAVE_STD_STRING_VIEW >+#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set." >+#endif >+ >+#ifdef __has_include >+#if __has_include(<string_view>) && __cplusplus >= 201703L >+#define ABSL_HAVE_STD_STRING_VIEW 1 >+#endif >+#endif >+ >+// For MSVC, `__has_include` is supported in VS 2017 15.3, which is later than >+// the support for <optional>, <any>, <string_view>, <variant>. So we use >+// _MSC_VER to check whether we have VS 2017 RTM (when <optional>, <any>, >+// <string_view>, <variant> is implemented) or higher. Also, `__cplusplus` is >+// not correctly set by MSVC, so we use `_MSVC_LANG` to check the language >+// version. >+// TODO(zhangxy): fix tests before enabling aliasing for `std::any`, >+// `std::string_view`. >+#if defined(_MSC_VER) && _MSC_VER >= 1910 && \ >+ ((defined(_MSVC_LANG) && _MSVC_LANG > 201402) || __cplusplus > 201402) >+// #define ABSL_HAVE_STD_ANY 1 >+#define ABSL_HAVE_STD_OPTIONAL 1 >+#define ABSL_HAVE_STD_VARIANT 1 >+// #define ABSL_HAVE_STD_STRING_VIEW 1 >+#endif >+ >+#endif // ABSL_BASE_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config_test.cc >new file mode 100644 >index 00000000000..c839712a537 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/config_test.cc >@@ -0,0 +1,60 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/config.h" >+ >+#include <cstdint> >+ >+#include "gtest/gtest.h" >+#include "absl/synchronization/internal/thread_pool.h" >+ >+namespace { >+ >+TEST(ConfigTest, Endianness) { >+ union { >+ uint32_t value; >+ uint8_t data[sizeof(uint32_t)]; >+ } number; >+ number.data[0] = 0x00; >+ number.data[1] = 0x01; >+ number.data[2] = 0x02; >+ number.data[3] = 0x03; >+#if defined(ABSL_IS_LITTLE_ENDIAN) && defined(ABSL_IS_BIG_ENDIAN) >+#error Both ABSL_IS_LITTLE_ENDIAN and ABSL_IS_BIG_ENDIAN are defined >+#elif defined(ABSL_IS_LITTLE_ENDIAN) >+ EXPECT_EQ(UINT32_C(0x03020100), number.value); >+#elif defined(ABSL_IS_BIG_ENDIAN) >+ EXPECT_EQ(UINT32_C(0x00010203), number.value); >+#else >+#error Unknown endianness >+#endif >+} >+ >+#if defined(ABSL_HAVE_THREAD_LOCAL) >+TEST(ConfigTest, ThreadLocal) { >+ static thread_local int mine_mine_mine = 16; >+ EXPECT_EQ(16, mine_mine_mine); >+ { >+ absl::synchronization_internal::ThreadPool pool(1); >+ pool.Schedule([&] { >+ EXPECT_EQ(16, mine_mine_mine); >+ mine_mine_mine = 32; >+ EXPECT_EQ(32, mine_mine_mine); >+ }); >+ } >+ EXPECT_EQ(16, mine_mine_mine); >+} >+#endif >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.cc >new file mode 100644 >index 00000000000..b97fa3a8b4a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.cc >@@ -0,0 +1,129 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <stdlib.h> >+#include <string.h> >+ >+#include "absl/base/dynamic_annotations.h" >+ >+#ifndef __has_feature >+#define __has_feature(x) 0 >+#endif >+ >+/* Compiler-based ThreadSanitizer defines >+ ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1 >+ and provides its own definitions of the functions. */ >+ >+#ifndef ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL >+# define ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0 >+#endif >+ >+/* Each function is empty and called (via a macro) only in debug mode. >+ The arguments are captured by dynamic tools at runtime. */ >+ >+#if ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 && !defined(__native_client__) >+ >+#if __has_feature(memory_sanitizer) >+#include <sanitizer/msan_interface.h> >+#endif >+ >+#ifdef __cplusplus >+extern "C" { >+#endif >+ >+void AbslAnnotateRWLockCreate(const char *, int, >+ const volatile void *){} >+void AbslAnnotateRWLockDestroy(const char *, int, >+ const volatile void *){} >+void AbslAnnotateRWLockAcquired(const char *, int, >+ const volatile void *, long){} >+void AbslAnnotateRWLockReleased(const char *, int, >+ const volatile void *, long){} >+void AbslAnnotateBenignRace(const char *, int, >+ const volatile void *, >+ const char *){} >+void AbslAnnotateBenignRaceSized(const char *, int, >+ const volatile void *, >+ size_t, >+ const char *) {} >+void AbslAnnotateThreadName(const char *, int, >+ const char *){} >+void AbslAnnotateIgnoreReadsBegin(const char *, int){} >+void AbslAnnotateIgnoreReadsEnd(const char *, int){} >+void AbslAnnotateIgnoreWritesBegin(const char *, int){} >+void AbslAnnotateIgnoreWritesEnd(const char *, int){} >+void AbslAnnotateEnableRaceDetection(const char *, int, int){} >+void AbslAnnotateMemoryIsInitialized(const char *, int, >+ const volatile void *mem, size_t size) { >+#if __has_feature(memory_sanitizer) >+ __msan_unpoison(mem, size); >+#else >+ (void)mem; >+ (void)size; >+#endif >+} >+ >+void AbslAnnotateMemoryIsUninitialized(const char *, int, >+ const volatile void *mem, size_t size) { >+#if __has_feature(memory_sanitizer) >+ __msan_allocated_memory(mem, size); >+#else >+ (void)mem; >+ (void)size; >+#endif >+} >+ >+static int AbslGetRunningOnValgrind(void) { >+#ifdef RUNNING_ON_VALGRIND >+ if (RUNNING_ON_VALGRIND) return 1; >+#endif >+ char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND"); >+ if (running_on_valgrind_str) { >+ return strcmp(running_on_valgrind_str, "0") != 0; >+ } >+ return 0; >+} >+ >+/* See the comments in dynamic_annotations.h */ >+int AbslRunningOnValgrind(void) { >+ static volatile int running_on_valgrind = -1; >+ int local_running_on_valgrind = running_on_valgrind; >+ /* C doesn't have thread-safe initialization of statics, and we >+ don't want to depend on pthread_once here, so hack it. */ >+ ABSL_ANNOTATE_BENIGN_RACE(&running_on_valgrind, "safe hack"); >+ if (local_running_on_valgrind == -1) >+ running_on_valgrind = local_running_on_valgrind = AbslGetRunningOnValgrind(); >+ return local_running_on_valgrind; >+} >+ >+/* See the comments in dynamic_annotations.h */ >+double AbslValgrindSlowdown(void) { >+ /* Same initialization hack as in AbslRunningOnValgrind(). */ >+ static volatile double slowdown = 0.0; >+ double local_slowdown = slowdown; >+ ABSL_ANNOTATE_BENIGN_RACE(&slowdown, "safe hack"); >+ if (AbslRunningOnValgrind() == 0) { >+ return 1.0; >+ } >+ if (local_slowdown == 0.0) { >+ char *env = getenv("VALGRIND_SLOWDOWN"); >+ slowdown = local_slowdown = env ? atof(env) : 50.0; >+ } >+ return local_slowdown; >+} >+ >+#ifdef __cplusplus >+} // extern "C" >+#endif >+#endif /* ABSL_DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.h >new file mode 100644 >index 00000000000..88048b0fbb1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/dynamic_annotations.h >@@ -0,0 +1,388 @@ >+/* >+ * Copyright 2017 The Abseil Authors. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+/* This file defines dynamic annotations for use with dynamic analysis >+ tool such as valgrind, PIN, etc. >+ >+ Dynamic annotation is a source code annotation that affects >+ the generated code (that is, the annotation is not a comment). >+ Each such annotation is attached to a particular >+ instruction and/or to a particular object (address) in the program. >+ >+ The annotations that should be used by users are macros in all upper-case >+ (e.g., ABSL_ANNOTATE_THREAD_NAME). >+ >+ Actual implementation of these macros may differ depending on the >+ dynamic analysis tool being used. >+ >+ This file supports the following configurations: >+ - Dynamic Annotations enabled (with static thread-safety warnings disabled). >+ In this case, macros expand to functions implemented by Thread Sanitizer, >+ when building with TSan. When not provided an external implementation, >+ dynamic_annotations.cc provides no-op implementations. >+ >+ - Static Clang thread-safety warnings enabled. >+ When building with a Clang compiler that supports thread-safety warnings, >+ a subset of annotations can be statically-checked at compile-time. We >+ expand these macros to static-inline functions that can be analyzed for >+ thread-safety, but afterwards elided when building the final binary. >+ >+ - All annotations are disabled. >+ If neither Dynamic Annotations nor Clang thread-safety warnings are >+ enabled, then all annotation-macros expand to empty. */ >+ >+#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ >+#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ >+ >+#ifndef ABSL_DYNAMIC_ANNOTATIONS_ENABLED >+# define ABSL_DYNAMIC_ANNOTATIONS_ENABLED 0 >+#endif >+ >+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 >+ >+ /* ------------------------------------------------------------- >+ Annotations that suppress errors. It is usually better to express the >+ program's synchronization using the other annotations, but these can >+ be used when all else fails. */ >+ >+ /* Report that we may have a benign race at "pointer", with size >+ "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the >+ point where "pointer" has been allocated, preferably close to the point >+ where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC. */ >+ #define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \ >+ AbslAnnotateBenignRaceSized(__FILE__, __LINE__, pointer, \ >+ sizeof(*(pointer)), description) >+ >+ /* Same as ABSL_ANNOTATE_BENIGN_RACE(address, description), but applies to >+ the memory range [address, address+size). */ >+ #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \ >+ AbslAnnotateBenignRaceSized(__FILE__, __LINE__, address, size, description) >+ >+ /* Enable (enable!=0) or disable (enable==0) race detection for all threads. >+ This annotation could be useful if you want to skip expensive race analysis >+ during some period of program execution, e.g. during initialization. */ >+ #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \ >+ AbslAnnotateEnableRaceDetection(__FILE__, __LINE__, enable) >+ >+ /* ------------------------------------------------------------- >+ Annotations useful for debugging. */ >+ >+ /* Report the current thread name to a race detector. */ >+ #define ABSL_ANNOTATE_THREAD_NAME(name) \ >+ AbslAnnotateThreadName(__FILE__, __LINE__, name) >+ >+ /* ------------------------------------------------------------- >+ Annotations useful when implementing locks. They are not >+ normally needed by modules that merely use locks. >+ The "lock" argument is a pointer to the lock object. */ >+ >+ /* Report that a lock has been created at address "lock". */ >+ #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \ >+ AbslAnnotateRWLockCreate(__FILE__, __LINE__, lock) >+ >+ /* Report that a linker initialized lock has been created at address "lock". >+ */ >+#ifdef THREAD_SANITIZER >+ #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \ >+ AbslAnnotateRWLockCreateStatic(__FILE__, __LINE__, lock) >+#else >+ #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) ABSL_ANNOTATE_RWLOCK_CREATE(lock) >+#endif >+ >+ /* Report that the lock at address "lock" is about to be destroyed. */ >+ #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \ >+ AbslAnnotateRWLockDestroy(__FILE__, __LINE__, lock) >+ >+ /* Report that the lock at address "lock" has been acquired. >+ is_w=1 for writer lock, is_w=0 for reader lock. */ >+ #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \ >+ AbslAnnotateRWLockAcquired(__FILE__, __LINE__, lock, is_w) >+ >+ /* Report that the lock at address "lock" is about to be released. */ >+ #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \ >+ AbslAnnotateRWLockReleased(__FILE__, __LINE__, lock, is_w) >+ >+#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */ >+ >+ #define ABSL_ANNOTATE_RWLOCK_CREATE(lock) /* empty */ >+ #define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) /* empty */ >+ #define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) /* empty */ >+ #define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */ >+ #define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */ >+ #define ABSL_ANNOTATE_BENIGN_RACE(address, description) /* empty */ >+ #define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */ >+ #define ABSL_ANNOTATE_THREAD_NAME(name) /* empty */ >+ #define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */ >+ >+#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */ >+ >+/* These annotations are also made available to LLVM's Memory Sanitizer */ >+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 1 || defined(MEMORY_SANITIZER) >+ #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \ >+ AbslAnnotateMemoryIsInitialized(__FILE__, __LINE__, address, size) >+ >+ #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \ >+ AbslAnnotateMemoryIsUninitialized(__FILE__, __LINE__, address, size) >+#else >+ #define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */ >+ #define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) /* empty */ >+#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED || MEMORY_SANITIZER */ >+/* TODO(delesley) -- Replace __CLANG_SUPPORT_DYN_ANNOTATION__ with the >+ appropriate feature ID. */ >+#if defined(__clang__) && (!defined(SWIG)) \ >+ && defined(__CLANG_SUPPORT_DYN_ANNOTATION__) >+ >+ #if ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 >+ #define ABSL_ANNOTALYSIS_ENABLED >+ #endif >+ >+ /* When running in opt-mode, GCC will issue a warning, if these attributes are >+ compiled. Only include them when compiling using Clang. */ >+ #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN \ >+ __attribute((exclusive_lock_function("*"))) >+ #define ABSL_ATTRIBUTE_IGNORE_READS_END \ >+ __attribute((unlock_function("*"))) >+#else >+ #define ABSL_ATTRIBUTE_IGNORE_READS_BEGIN /* empty */ >+ #define ABSL_ATTRIBUTE_IGNORE_READS_END /* empty */ >+#endif /* defined(__clang__) && ... */ >+ >+#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) || defined(ABSL_ANNOTALYSIS_ENABLED) >+ #define ABSL_ANNOTATIONS_ENABLED >+#endif >+ >+#if (ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0) >+ >+ /* Request the analysis tool to ignore all reads in the current thread >+ until ABSL_ANNOTATE_IGNORE_READS_END is called. >+ Useful to ignore intentional racey reads, while still checking >+ other reads and all writes. >+ See also ABSL_ANNOTATE_UNPROTECTED_READ. */ >+ #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ >+ AbslAnnotateIgnoreReadsBegin(__FILE__, __LINE__) >+ >+ /* Stop ignoring reads. */ >+ #define ABSL_ANNOTATE_IGNORE_READS_END() \ >+ AbslAnnotateIgnoreReadsEnd(__FILE__, __LINE__) >+ >+ /* Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead. */ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ >+ AbslAnnotateIgnoreWritesBegin(__FILE__, __LINE__) >+ >+ /* Stop ignoring writes. */ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ >+ AbslAnnotateIgnoreWritesEnd(__FILE__, __LINE__) >+ >+/* Clang provides limited support for static thread-safety analysis >+ through a feature called Annotalysis. We configure macro-definitions >+ according to whether Annotalysis support is available. */ >+#elif defined(ABSL_ANNOTALYSIS_ENABLED) >+ >+ #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \ >+ AbslStaticAnnotateIgnoreReadsBegin(__FILE__, __LINE__) >+ >+ #define ABSL_ANNOTATE_IGNORE_READS_END() \ >+ AbslStaticAnnotateIgnoreReadsEnd(__FILE__, __LINE__) >+ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \ >+ AbslStaticAnnotateIgnoreWritesBegin(__FILE__, __LINE__) >+ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_END() \ >+ AbslStaticAnnotateIgnoreWritesEnd(__FILE__, __LINE__) >+ >+#else >+ #define ABSL_ANNOTATE_IGNORE_READS_BEGIN() /* empty */ >+ #define ABSL_ANNOTATE_IGNORE_READS_END() /* empty */ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */ >+ #define ABSL_ANNOTATE_IGNORE_WRITES_END() /* empty */ >+#endif >+ >+/* Implement the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more >+ primitive annotations defined above. */ >+#if defined(ABSL_ANNOTATIONS_ENABLED) >+ >+ /* Start ignoring all memory accesses (both reads and writes). */ >+ #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \ >+ do { \ >+ ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \ >+ ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \ >+ }while (0) >+ >+ /* Stop ignoring both reads and writes. */ >+ #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \ >+ do { \ >+ ABSL_ANNOTATE_IGNORE_WRITES_END(); \ >+ ABSL_ANNOTATE_IGNORE_READS_END(); \ >+ }while (0) >+ >+#else >+ #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */ >+ #define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */ >+#endif >+ >+/* Use the macros above rather than using these functions directly. */ >+#include <stddef.h> >+#ifdef __cplusplus >+extern "C" { >+#endif >+void AbslAnnotateRWLockCreate(const char *file, int line, >+ const volatile void *lock); >+void AbslAnnotateRWLockCreateStatic(const char *file, int line, >+ const volatile void *lock); >+void AbslAnnotateRWLockDestroy(const char *file, int line, >+ const volatile void *lock); >+void AbslAnnotateRWLockAcquired(const char *file, int line, >+ const volatile void *lock, long is_w); /* NOLINT */ >+void AbslAnnotateRWLockReleased(const char *file, int line, >+ const volatile void *lock, long is_w); /* NOLINT */ >+void AbslAnnotateBenignRace(const char *file, int line, >+ const volatile void *address, >+ const char *description); >+void AbslAnnotateBenignRaceSized(const char *file, int line, >+ const volatile void *address, >+ size_t size, >+ const char *description); >+void AbslAnnotateThreadName(const char *file, int line, >+ const char *name); >+void AbslAnnotateEnableRaceDetection(const char *file, int line, int enable); >+void AbslAnnotateMemoryIsInitialized(const char *file, int line, >+ const volatile void *mem, size_t size); >+void AbslAnnotateMemoryIsUninitialized(const char *file, int line, >+ const volatile void *mem, size_t size); >+ >+/* Annotations expand to these functions, when Dynamic Annotations are enabled. >+ These functions are either implemented as no-op calls, if no Sanitizer is >+ attached, or provided with externally-linked implementations by a library >+ like ThreadSanitizer. */ >+void AbslAnnotateIgnoreReadsBegin(const char *file, int line) >+ ABSL_ATTRIBUTE_IGNORE_READS_BEGIN; >+void AbslAnnotateIgnoreReadsEnd(const char *file, int line) >+ ABSL_ATTRIBUTE_IGNORE_READS_END; >+void AbslAnnotateIgnoreWritesBegin(const char *file, int line); >+void AbslAnnotateIgnoreWritesEnd(const char *file, int line); >+ >+#if defined(ABSL_ANNOTALYSIS_ENABLED) >+/* When Annotalysis is enabled without Dynamic Annotations, the use of >+ static-inline functions allows the annotations to be read at compile-time, >+ while still letting the compiler elide the functions from the final build. >+ >+ TODO(delesley) -- The exclusive lock here ignores writes as well, but >+ allows IGNORE_READS_AND_WRITES to work properly. */ >+#pragma GCC diagnostic push >+#pragma GCC diagnostic ignored "-Wunused-function" >+static inline void AbslStaticAnnotateIgnoreReadsBegin(const char *file, int line) >+ ABSL_ATTRIBUTE_IGNORE_READS_BEGIN { (void)file; (void)line; } >+static inline void AbslStaticAnnotateIgnoreReadsEnd(const char *file, int line) >+ ABSL_ATTRIBUTE_IGNORE_READS_END { (void)file; (void)line; } >+static inline void AbslStaticAnnotateIgnoreWritesBegin( >+ const char *file, int line) { (void)file; (void)line; } >+static inline void AbslStaticAnnotateIgnoreWritesEnd( >+ const char *file, int line) { (void)file; (void)line; } >+#pragma GCC diagnostic pop >+#endif >+ >+/* Return non-zero value if running under valgrind. >+ >+ If "valgrind.h" is included into dynamic_annotations.cc, >+ the regular valgrind mechanism will be used. >+ See http://valgrind.org/docs/manual/manual-core-adv.html about >+ RUNNING_ON_VALGRIND and other valgrind "client requests". >+ The file "valgrind.h" may be obtained by doing >+ svn co svn://svn.valgrind.org/valgrind/trunk/include >+ >+ If for some reason you can't use "valgrind.h" or want to fake valgrind, >+ there are two ways to make this function return non-zero: >+ - Use environment variable: export RUNNING_ON_VALGRIND=1 >+ - Make your tool intercept the function AbslRunningOnValgrind() and >+ change its return value. >+ */ >+int AbslRunningOnValgrind(void); >+ >+/* AbslValgrindSlowdown returns: >+ * 1.0, if (AbslRunningOnValgrind() == 0) >+ * 50.0, if (AbslRunningOnValgrind() != 0 && getenv("VALGRIND_SLOWDOWN") == NULL) >+ * atof(getenv("VALGRIND_SLOWDOWN")) otherwise >+ This function can be used to scale timeout values: >+ EXAMPLE: >+ for (;;) { >+ DoExpensiveBackgroundTask(); >+ SleepForSeconds(5 * AbslValgrindSlowdown()); >+ } >+ */ >+double AbslValgrindSlowdown(void); >+ >+#ifdef __cplusplus >+} >+#endif >+ >+/* ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads. >+ >+ Instead of doing >+ ABSL_ANNOTATE_IGNORE_READS_BEGIN(); >+ ... = x; >+ ABSL_ANNOTATE_IGNORE_READS_END(); >+ one can use >+ ... = ABSL_ANNOTATE_UNPROTECTED_READ(x); */ >+#if defined(__cplusplus) && defined(ABSL_ANNOTATIONS_ENABLED) >+template <typename T> >+inline T ABSL_ANNOTATE_UNPROTECTED_READ(const volatile T &x) { /* NOLINT */ >+ ABSL_ANNOTATE_IGNORE_READS_BEGIN(); >+ T res = x; >+ ABSL_ANNOTATE_IGNORE_READS_END(); >+ return res; >+ } >+#else >+ #define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x) >+#endif >+ >+#if ABSL_DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus) >+ /* Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable. */ >+ #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \ >+ namespace { \ >+ class static_var ## _annotator { \ >+ public: \ >+ static_var ## _annotator() { \ >+ ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, \ >+ sizeof(static_var), \ >+ # static_var ": " description); \ >+ } \ >+ }; \ >+ static static_var ## _annotator the ## static_var ## _annotator;\ >+ } // namespace >+#else /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED == 0 */ >+ #define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */ >+#endif /* ABSL_DYNAMIC_ANNOTATIONS_ENABLED */ >+ >+#ifdef ADDRESS_SANITIZER >+/* Describe the current state of a contiguous container such as e.g. >+ * std::vector or std::string. For more details see >+ * sanitizer/common_interface_defs.h, which is provided by the compiler. */ >+#include <sanitizer/common_interface_defs.h> >+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \ >+ __sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid) >+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \ >+ struct { char x[8] __attribute__ ((aligned (8))); } name >+#else >+#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) >+#define ABSL_ADDRESS_SANITIZER_REDZONE(name) >+#endif // ADDRESS_SANITIZER >+ >+/* Undefine the macros intended only in this file. */ >+#undef ABSL_ANNOTALYSIS_ENABLED >+#undef ABSL_ANNOTATIONS_ENABLED >+#undef ABSL_ATTRIBUTE_IGNORE_READS_BEGIN >+#undef ABSL_ATTRIBUTE_IGNORE_READS_END >+ >+#endif /* ABSL_BASE_DYNAMIC_ANNOTATIONS_H_ */ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc >new file mode 100644 >index 00000000000..97c8d6f8318 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/exception_safety_testing_test.cc >@@ -0,0 +1,942 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/exception_safety_testing.h" >+ >+#include <cstddef> >+#include <exception> >+#include <iostream> >+#include <list> >+#include <type_traits> >+#include <vector> >+ >+#include "gtest/gtest-spi.h" >+#include "gtest/gtest.h" >+#include "absl/memory/memory.h" >+ >+namespace testing { >+ >+namespace { >+ >+using ::testing::exceptions_internal::SetCountdown; >+using ::testing::exceptions_internal::TestException; >+using ::testing::exceptions_internal::UnsetCountdown; >+ >+// EXPECT_NO_THROW can't inspect the thrown inspection in general. >+template <typename F> >+void ExpectNoThrow(const F& f) { >+ try { >+ f(); >+ } catch (TestException e) { >+ ADD_FAILURE() << "Unexpected exception thrown from " << e.what(); >+ } >+} >+ >+TEST(ThrowingValueTest, Throws) { >+ SetCountdown(); >+ EXPECT_THROW(ThrowingValue<> bomb, TestException); >+ >+ // It's not guaranteed that every operator only throws *once*. The default >+ // ctor only throws once, though, so use it to make sure we only throw when >+ // the countdown hits 0 >+ SetCountdown(2); >+ ExpectNoThrow([]() { ThrowingValue<> bomb; }); >+ ExpectNoThrow([]() { ThrowingValue<> bomb; }); >+ EXPECT_THROW(ThrowingValue<> bomb, TestException); >+ >+ UnsetCountdown(); >+} >+ >+// Tests that an operation throws when the countdown is at 0, doesn't throw when >+// the countdown doesn't hit 0, and doesn't modify the state of the >+// ThrowingValue if it throws >+template <typename F> >+void TestOp(const F& f) { >+ ExpectNoThrow(f); >+ >+ SetCountdown(); >+ EXPECT_THROW(f(), TestException); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, ThrowingCtors) { >+ ThrowingValue<> bomb; >+ >+ TestOp([]() { ThrowingValue<> bomb(1); }); >+ TestOp([&]() { ThrowingValue<> bomb1 = bomb; }); >+ TestOp([&]() { ThrowingValue<> bomb1 = std::move(bomb); }); >+} >+ >+TEST(ThrowingValueTest, ThrowingAssignment) { >+ ThrowingValue<> bomb, bomb1; >+ >+ TestOp([&]() { bomb = bomb1; }); >+ TestOp([&]() { bomb = std::move(bomb1); }); >+ >+ // Test that when assignment throws, the assignment should fail (lhs != rhs) >+ // and strong guarantee fails (lhs != lhs_copy). >+ { >+ ThrowingValue<> lhs(39), rhs(42); >+ ThrowingValue<> lhs_copy(lhs); >+ SetCountdown(); >+ EXPECT_THROW(lhs = rhs, TestException); >+ UnsetCountdown(); >+ EXPECT_NE(lhs, rhs); >+ EXPECT_NE(lhs_copy, lhs); >+ } >+ { >+ ThrowingValue<> lhs(39), rhs(42); >+ ThrowingValue<> lhs_copy(lhs), rhs_copy(rhs); >+ SetCountdown(); >+ EXPECT_THROW(lhs = std::move(rhs), TestException); >+ UnsetCountdown(); >+ EXPECT_NE(lhs, rhs_copy); >+ EXPECT_NE(lhs_copy, lhs); >+ } >+} >+ >+TEST(ThrowingValueTest, ThrowingComparisons) { >+ ThrowingValue<> bomb1, bomb2; >+ TestOp([&]() { return bomb1 == bomb2; }); >+ TestOp([&]() { return bomb1 != bomb2; }); >+ TestOp([&]() { return bomb1 < bomb2; }); >+ TestOp([&]() { return bomb1 <= bomb2; }); >+ TestOp([&]() { return bomb1 > bomb2; }); >+ TestOp([&]() { return bomb1 >= bomb2; }); >+} >+ >+TEST(ThrowingValueTest, ThrowingArithmeticOps) { >+ ThrowingValue<> bomb1(1), bomb2(2); >+ >+ TestOp([&bomb1]() { +bomb1; }); >+ TestOp([&bomb1]() { -bomb1; }); >+ TestOp([&bomb1]() { ++bomb1; }); >+ TestOp([&bomb1]() { bomb1++; }); >+ TestOp([&bomb1]() { --bomb1; }); >+ TestOp([&bomb1]() { bomb1--; }); >+ >+ TestOp([&]() { bomb1 + bomb2; }); >+ TestOp([&]() { bomb1 - bomb2; }); >+ TestOp([&]() { bomb1* bomb2; }); >+ TestOp([&]() { bomb1 / bomb2; }); >+ TestOp([&]() { bomb1 << 1; }); >+ TestOp([&]() { bomb1 >> 1; }); >+} >+ >+TEST(ThrowingValueTest, ThrowingLogicalOps) { >+ ThrowingValue<> bomb1, bomb2; >+ >+ TestOp([&bomb1]() { !bomb1; }); >+ TestOp([&]() { bomb1&& bomb2; }); >+ TestOp([&]() { bomb1 || bomb2; }); >+} >+ >+TEST(ThrowingValueTest, ThrowingBitwiseOps) { >+ ThrowingValue<> bomb1, bomb2; >+ >+ TestOp([&bomb1]() { ~bomb1; }); >+ TestOp([&]() { bomb1& bomb2; }); >+ TestOp([&]() { bomb1 | bomb2; }); >+ TestOp([&]() { bomb1 ^ bomb2; }); >+} >+ >+TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) { >+ ThrowingValue<> bomb1(1), bomb2(2); >+ >+ TestOp([&]() { bomb1 += bomb2; }); >+ TestOp([&]() { bomb1 -= bomb2; }); >+ TestOp([&]() { bomb1 *= bomb2; }); >+ TestOp([&]() { bomb1 /= bomb2; }); >+ TestOp([&]() { bomb1 %= bomb2; }); >+ TestOp([&]() { bomb1 &= bomb2; }); >+ TestOp([&]() { bomb1 |= bomb2; }); >+ TestOp([&]() { bomb1 ^= bomb2; }); >+ TestOp([&]() { bomb1 *= bomb2; }); >+} >+ >+TEST(ThrowingValueTest, ThrowingStreamOps) { >+ ThrowingValue<> bomb; >+ >+ TestOp([&]() { >+ std::istringstream stream; >+ stream >> bomb; >+ }); >+ TestOp([&]() { >+ std::stringstream stream; >+ stream << bomb; >+ }); >+} >+ >+// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit >+// a nonfatal failure that contains the std::string representation of the Thrower >+TEST(ThrowingValueTest, StreamOpsOutput) { >+ using ::testing::TypeSpec; >+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); >+ >+ // Test default spec list (kEverythingThrows) >+ EXPECT_NONFATAL_FAILURE( >+ { >+ using Thrower = ThrowingValue<TypeSpec{}>; >+ auto thrower = Thrower(123); >+ thrower.~Thrower(); >+ }, >+ "ThrowingValue<>(123)"); >+ >+ // Test with one item in spec list (kNoThrowCopy) >+ EXPECT_NONFATAL_FAILURE( >+ { >+ using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>; >+ auto thrower = Thrower(234); >+ thrower.~Thrower(); >+ }, >+ "ThrowingValue<kNoThrowCopy>(234)"); >+ >+ // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew) >+ EXPECT_NONFATAL_FAILURE( >+ { >+ using Thrower = >+ ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>; >+ auto thrower = Thrower(345); >+ thrower.~Thrower(); >+ }, >+ "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)"); >+ >+ // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew) >+ EXPECT_NONFATAL_FAILURE( >+ { >+ using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>; >+ auto thrower = Thrower(456); >+ thrower.~Thrower(); >+ }, >+ "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)"); >+} >+ >+template <typename F> >+void TestAllocatingOp(const F& f) { >+ ExpectNoThrow(f); >+ >+ SetCountdown(); >+ EXPECT_THROW(f(), exceptions_internal::TestBadAllocException); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, ThrowingAllocatingOps) { >+ // make_unique calls unqualified operator new, so these exercise the >+ // ThrowingValue overloads. >+ TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>>(1); }); >+ TestAllocatingOp([]() { return absl::make_unique<ThrowingValue<>[]>(2); }); >+} >+ >+TEST(ThrowingValueTest, NonThrowingMoveCtor) { >+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow_ctor; >+ >+ SetCountdown(); >+ ExpectNoThrow([¬hrow_ctor]() { >+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow1 = std::move(nothrow_ctor); >+ }); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, NonThrowingMoveAssign) { >+ ThrowingValue<TypeSpec::kNoThrowMove> nothrow_assign1, nothrow_assign2; >+ >+ SetCountdown(); >+ ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { >+ nothrow_assign1 = std::move(nothrow_assign2); >+ }); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, ThrowingCopyCtor) { >+ ThrowingValue<> tv; >+ >+ TestOp([&]() { ThrowingValue<> tv_copy(tv); }); >+} >+ >+TEST(ThrowingValueTest, ThrowingCopyAssign) { >+ ThrowingValue<> tv1, tv2; >+ >+ TestOp([&]() { tv1 = tv2; }); >+} >+ >+TEST(ThrowingValueTest, NonThrowingCopyCtor) { >+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_ctor; >+ >+ SetCountdown(); >+ ExpectNoThrow([¬hrow_ctor]() { >+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow1(nothrow_ctor); >+ }); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, NonThrowingCopyAssign) { >+ ThrowingValue<TypeSpec::kNoThrowCopy> nothrow_assign1, nothrow_assign2; >+ >+ SetCountdown(); >+ ExpectNoThrow([¬hrow_assign1, ¬hrow_assign2]() { >+ nothrow_assign1 = nothrow_assign2; >+ }); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, ThrowingSwap) { >+ ThrowingValue<> bomb1, bomb2; >+ TestOp([&]() { std::swap(bomb1, bomb2); }); >+} >+ >+TEST(ThrowingValueTest, NonThrowingSwap) { >+ ThrowingValue<TypeSpec::kNoThrowMove> bomb1, bomb2; >+ ExpectNoThrow([&]() { std::swap(bomb1, bomb2); }); >+} >+ >+TEST(ThrowingValueTest, NonThrowingAllocation) { >+ ThrowingValue<TypeSpec::kNoThrowNew>* allocated; >+ ThrowingValue<TypeSpec::kNoThrowNew>* array; >+ >+ ExpectNoThrow([&allocated]() { >+ allocated = new ThrowingValue<TypeSpec::kNoThrowNew>(1); >+ delete allocated; >+ }); >+ ExpectNoThrow([&array]() { >+ array = new ThrowingValue<TypeSpec::kNoThrowNew>[2]; >+ delete[] array; >+ }); >+} >+ >+TEST(ThrowingValueTest, NonThrowingDelete) { >+ auto* allocated = new ThrowingValue<>(1); >+ auto* array = new ThrowingValue<>[2]; >+ >+ SetCountdown(); >+ ExpectNoThrow([allocated]() { delete allocated; }); >+ SetCountdown(); >+ ExpectNoThrow([array]() { delete[] array; }); >+ >+ UnsetCountdown(); >+} >+ >+using Storage = >+ absl::aligned_storage_t<sizeof(ThrowingValue<>), alignof(ThrowingValue<>)>; >+ >+TEST(ThrowingValueTest, NonThrowingPlacementDelete) { >+ constexpr int kArrayLen = 2; >+ // We intentionally create extra space to store the tag allocated by placement >+ // new[]. >+ constexpr int kStorageLen = 4; >+ >+ Storage buf; >+ Storage array_buf[kStorageLen]; >+ auto* placed = new (&buf) ThrowingValue<>(1); >+ auto placed_array = new (&array_buf) ThrowingValue<>[kArrayLen]; >+ >+ SetCountdown(); >+ ExpectNoThrow([placed, &buf]() { >+ placed->~ThrowingValue<>(); >+ ThrowingValue<>::operator delete(placed, &buf); >+ }); >+ >+ SetCountdown(); >+ ExpectNoThrow([&, placed_array]() { >+ for (int i = 0; i < kArrayLen; ++i) placed_array[i].~ThrowingValue<>(); >+ ThrowingValue<>::operator delete[](placed_array, &array_buf); >+ }); >+ >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingValueTest, NonThrowingDestructor) { >+ auto* allocated = new ThrowingValue<>(); >+ >+ SetCountdown(); >+ ExpectNoThrow([allocated]() { delete allocated; }); >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingBoolTest, ThrowingBool) { >+ ThrowingBool t = true; >+ >+ // Test that it's contextually convertible to bool >+ if (t) { // NOLINT(whitespace/empty_if_body) >+ } >+ EXPECT_TRUE(t); >+ >+ TestOp([&]() { (void)!t; }); >+} >+ >+TEST(ThrowingAllocatorTest, MemoryManagement) { >+ // Just exercise the memory management capabilities under LSan to make sure we >+ // don't leak. >+ ThrowingAllocator<int> int_alloc; >+ int* ip = int_alloc.allocate(1); >+ int_alloc.deallocate(ip, 1); >+ int* i_array = int_alloc.allocate(2); >+ int_alloc.deallocate(i_array, 2); >+ >+ ThrowingAllocator<ThrowingValue<>> tv_alloc; >+ ThrowingValue<>* ptr = tv_alloc.allocate(1); >+ tv_alloc.deallocate(ptr, 1); >+ ThrowingValue<>* tv_array = tv_alloc.allocate(2); >+ tv_alloc.deallocate(tv_array, 2); >+} >+ >+TEST(ThrowingAllocatorTest, CallsGlobalNew) { >+ ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> nothrow_alloc; >+ ThrowingValue<>* ptr; >+ >+ SetCountdown(); >+ // This will only throw if ThrowingValue::new is called. >+ ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); >+ nothrow_alloc.deallocate(ptr, 1); >+ >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingAllocatorTest, ThrowingConstructors) { >+ ThrowingAllocator<int> int_alloc; >+ int* ip = nullptr; >+ >+ SetCountdown(); >+ EXPECT_THROW(ip = int_alloc.allocate(1), TestException); >+ ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); >+ >+ *ip = 1; >+ SetCountdown(); >+ EXPECT_THROW(int_alloc.construct(ip, 2), TestException); >+ EXPECT_EQ(*ip, 1); >+ int_alloc.deallocate(ip, 1); >+ >+ UnsetCountdown(); >+} >+ >+TEST(ThrowingAllocatorTest, NonThrowingConstruction) { >+ { >+ ThrowingAllocator<int, AllocSpec::kNoThrowAllocate> int_alloc; >+ int* ip = nullptr; >+ >+ SetCountdown(); >+ ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); >+ >+ SetCountdown(); >+ ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); >+ >+ EXPECT_EQ(*ip, 2); >+ int_alloc.deallocate(ip, 1); >+ >+ UnsetCountdown(); >+ } >+ >+ { >+ ThrowingAllocator<int> int_alloc; >+ int* ip = nullptr; >+ ExpectNoThrow([&]() { ip = int_alloc.allocate(1); }); >+ ExpectNoThrow([&]() { int_alloc.construct(ip, 2); }); >+ EXPECT_EQ(*ip, 2); >+ int_alloc.deallocate(ip, 1); >+ } >+ >+ { >+ ThrowingAllocator<ThrowingValue<>, AllocSpec::kNoThrowAllocate> >+ nothrow_alloc; >+ ThrowingValue<>* ptr; >+ >+ SetCountdown(); >+ ExpectNoThrow([&]() { ptr = nothrow_alloc.allocate(1); }); >+ >+ SetCountdown(); >+ ExpectNoThrow( >+ [&]() { nothrow_alloc.construct(ptr, 2, testing::nothrow_ctor); }); >+ >+ EXPECT_EQ(ptr->Get(), 2); >+ nothrow_alloc.destroy(ptr); >+ nothrow_alloc.deallocate(ptr, 1); >+ >+ UnsetCountdown(); >+ } >+ >+ { >+ ThrowingAllocator<int> a; >+ >+ SetCountdown(); >+ ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = a; }); >+ >+ SetCountdown(); >+ ExpectNoThrow([&]() { ThrowingAllocator<double> a1 = std::move(a); }); >+ >+ UnsetCountdown(); >+ } >+} >+ >+TEST(ThrowingAllocatorTest, ThrowingAllocatorConstruction) { >+ ThrowingAllocator<int> a; >+ TestOp([]() { ThrowingAllocator<int> a; }); >+ TestOp([&]() { a.select_on_container_copy_construction(); }); >+} >+ >+TEST(ThrowingAllocatorTest, State) { >+ ThrowingAllocator<int> a1, a2; >+ EXPECT_NE(a1, a2); >+ >+ auto a3 = a1; >+ EXPECT_EQ(a3, a1); >+ int* ip = a1.allocate(1); >+ EXPECT_EQ(a3, a1); >+ a3.deallocate(ip, 1); >+ EXPECT_EQ(a3, a1); >+} >+ >+TEST(ThrowingAllocatorTest, InVector) { >+ std::vector<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> v; >+ for (int i = 0; i < 20; ++i) v.push_back({}); >+ for (int i = 0; i < 20; ++i) v.pop_back(); >+} >+ >+TEST(ThrowingAllocatorTest, InList) { >+ std::list<ThrowingValue<>, ThrowingAllocator<ThrowingValue<>>> l; >+ for (int i = 0; i < 20; ++i) l.push_back({}); >+ for (int i = 0; i < 20; ++i) l.pop_back(); >+ for (int i = 0; i < 20; ++i) l.push_front({}); >+ for (int i = 0; i < 20; ++i) l.pop_front(); >+} >+ >+template <typename TesterInstance, typename = void> >+struct NullaryTestValidator : public std::false_type {}; >+ >+template <typename TesterInstance> >+struct NullaryTestValidator< >+ TesterInstance, >+ absl::void_t<decltype(std::declval<TesterInstance>().Test())>> >+ : public std::true_type {}; >+ >+template <typename TesterInstance> >+bool HasNullaryTest(const TesterInstance&) { >+ return NullaryTestValidator<TesterInstance>::value; >+} >+ >+void DummyOp(void*) {} >+ >+template <typename TesterInstance, typename = void> >+struct UnaryTestValidator : public std::false_type {}; >+ >+template <typename TesterInstance> >+struct UnaryTestValidator< >+ TesterInstance, >+ absl::void_t<decltype(std::declval<TesterInstance>().Test(DummyOp))>> >+ : public std::true_type {}; >+ >+template <typename TesterInstance> >+bool HasUnaryTest(const TesterInstance&) { >+ return UnaryTestValidator<TesterInstance>::value; >+} >+ >+TEST(ExceptionSafetyTesterTest, IncompleteTypesAreNotTestable) { >+ using T = exceptions_internal::UninitializedT; >+ auto op = [](T* t) {}; >+ auto inv = [](T*) { return testing::AssertionSuccess(); }; >+ auto fac = []() { return absl::make_unique<T>(); }; >+ >+ // Test that providing operation and inveriants still does not allow for the >+ // the invocation of .Test() and .Test(op) because it lacks a factory >+ auto without_fac = >+ testing::MakeExceptionSafetyTester().WithOperation(op).WithInvariants( >+ inv, testing::strong_guarantee); >+ EXPECT_FALSE(HasNullaryTest(without_fac)); >+ EXPECT_FALSE(HasUnaryTest(without_fac)); >+ >+ // Test that providing invariants and factory allows the invocation of >+ // .Test(op) but does not allow for .Test() because it lacks an operation >+ auto without_op = testing::MakeExceptionSafetyTester() >+ .WithInvariants(inv, testing::strong_guarantee) >+ .WithFactory(fac); >+ EXPECT_FALSE(HasNullaryTest(without_op)); >+ EXPECT_TRUE(HasUnaryTest(without_op)); >+ >+ // Test that providing operation and factory still does not allow for the >+ // the invocation of .Test() and .Test(op) because it lacks invariants >+ auto without_inv = >+ testing::MakeExceptionSafetyTester().WithOperation(op).WithFactory(fac); >+ EXPECT_FALSE(HasNullaryTest(without_inv)); >+ EXPECT_FALSE(HasUnaryTest(without_inv)); >+} >+ >+struct ExampleStruct {}; >+ >+std::unique_ptr<ExampleStruct> ExampleFunctionFactory() { >+ return absl::make_unique<ExampleStruct>(); >+} >+ >+void ExampleFunctionOperation(ExampleStruct*) {} >+ >+testing::AssertionResult ExampleFunctionInvariant(ExampleStruct*) { >+ return testing::AssertionSuccess(); >+} >+ >+struct { >+ std::unique_ptr<ExampleStruct> operator()() const { >+ return ExampleFunctionFactory(); >+ } >+} example_struct_factory; >+ >+struct { >+ void operator()(ExampleStruct*) const {} >+} example_struct_operation; >+ >+struct { >+ testing::AssertionResult operator()(ExampleStruct* example_struct) const { >+ return ExampleFunctionInvariant(example_struct); >+ } >+} example_struct_invariant; >+ >+auto example_lambda_factory = []() { return ExampleFunctionFactory(); }; >+ >+auto example_lambda_operation = [](ExampleStruct*) {}; >+ >+auto example_lambda_invariant = [](ExampleStruct* example_struct) { >+ return ExampleFunctionInvariant(example_struct); >+}; >+ >+// Testing that function references, pointers, structs with operator() and >+// lambdas can all be used with ExceptionSafetyTester >+TEST(ExceptionSafetyTesterTest, MixedFunctionTypes) { >+ // function reference >+ EXPECT_TRUE(testing::MakeExceptionSafetyTester() >+ .WithFactory(ExampleFunctionFactory) >+ .WithOperation(ExampleFunctionOperation) >+ .WithInvariants(ExampleFunctionInvariant) >+ .Test()); >+ >+ // function pointer >+ EXPECT_TRUE(testing::MakeExceptionSafetyTester() >+ .WithFactory(&ExampleFunctionFactory) >+ .WithOperation(&ExampleFunctionOperation) >+ .WithInvariants(&ExampleFunctionInvariant) >+ .Test()); >+ >+ // struct >+ EXPECT_TRUE(testing::MakeExceptionSafetyTester() >+ .WithFactory(example_struct_factory) >+ .WithOperation(example_struct_operation) >+ .WithInvariants(example_struct_invariant) >+ .Test()); >+ >+ // lambda >+ EXPECT_TRUE(testing::MakeExceptionSafetyTester() >+ .WithFactory(example_lambda_factory) >+ .WithOperation(example_lambda_operation) >+ .WithInvariants(example_lambda_invariant) >+ .Test()); >+} >+ >+struct NonNegative { >+ bool operator==(const NonNegative& other) const { return i == other.i; } >+ int i; >+}; >+ >+testing::AssertionResult CheckNonNegativeInvariants(NonNegative* g) { >+ if (g->i >= 0) { >+ return testing::AssertionSuccess(); >+ } >+ return testing::AssertionFailure() >+ << "i should be non-negative but is " << g->i; >+} >+ >+struct { >+ template <typename T> >+ void operator()(T* t) const { >+ (*t)(); >+ } >+} invoker; >+ >+auto tester = >+ testing::MakeExceptionSafetyTester().WithOperation(invoker).WithInvariants( >+ CheckNonNegativeInvariants); >+auto strong_tester = tester.WithInvariants(testing::strong_guarantee); >+ >+struct FailsBasicGuarantee : public NonNegative { >+ void operator()() { >+ --i; >+ ThrowingValue<> bomb; >+ ++i; >+ } >+}; >+ >+TEST(ExceptionCheckTest, BasicGuaranteeFailure) { >+ EXPECT_FALSE(tester.WithInitialValue(FailsBasicGuarantee{}).Test()); >+} >+ >+struct FollowsBasicGuarantee : public NonNegative { >+ void operator()() { >+ ++i; >+ ThrowingValue<> bomb; >+ } >+}; >+ >+TEST(ExceptionCheckTest, BasicGuarantee) { >+ EXPECT_TRUE(tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); >+} >+ >+TEST(ExceptionCheckTest, StrongGuaranteeFailure) { >+ EXPECT_FALSE(strong_tester.WithInitialValue(FailsBasicGuarantee{}).Test()); >+ EXPECT_FALSE(strong_tester.WithInitialValue(FollowsBasicGuarantee{}).Test()); >+} >+ >+struct BasicGuaranteeWithExtraInvariants : public NonNegative { >+ // After operator(), i is incremented. If operator() throws, i is set to 9999 >+ void operator()() { >+ int old_i = i; >+ i = kExceptionSentinel; >+ ThrowingValue<> bomb; >+ i = ++old_i; >+ } >+ >+ static constexpr int kExceptionSentinel = 9999; >+}; >+constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel; >+ >+TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) { >+ auto tester_with_val = >+ tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{}); >+ EXPECT_TRUE(tester_with_val.Test()); >+ EXPECT_TRUE( >+ tester_with_val >+ .WithInvariants([](BasicGuaranteeWithExtraInvariants* o) { >+ if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) { >+ return testing::AssertionSuccess(); >+ } >+ return testing::AssertionFailure() >+ << "i should be " >+ << BasicGuaranteeWithExtraInvariants::kExceptionSentinel >+ << ", but is " << o->i; >+ }) >+ .Test()); >+} >+ >+struct FollowsStrongGuarantee : public NonNegative { >+ void operator()() { ThrowingValue<> bomb; } >+}; >+ >+TEST(ExceptionCheckTest, StrongGuarantee) { >+ EXPECT_TRUE(tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); >+ EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}).Test()); >+} >+ >+struct HasReset : public NonNegative { >+ void operator()() { >+ i = -1; >+ ThrowingValue<> bomb; >+ i = 1; >+ } >+ >+ void reset() { i = 0; } >+}; >+ >+testing::AssertionResult CheckHasResetInvariants(HasReset* h) { >+ h->reset(); >+ return testing::AssertionResult(h->i == 0); >+} >+ >+TEST(ExceptionCheckTest, ModifyingChecker) { >+ auto set_to_1000 = [](FollowsBasicGuarantee* g) { >+ g->i = 1000; >+ return testing::AssertionSuccess(); >+ }; >+ auto is_1000 = [](FollowsBasicGuarantee* g) { >+ return testing::AssertionResult(g->i == 1000); >+ }; >+ auto increment = [](FollowsStrongGuarantee* g) { >+ ++g->i; >+ return testing::AssertionSuccess(); >+ }; >+ >+ EXPECT_FALSE(tester.WithInitialValue(FollowsBasicGuarantee{}) >+ .WithInvariants(set_to_1000, is_1000) >+ .Test()); >+ EXPECT_TRUE(strong_tester.WithInitialValue(FollowsStrongGuarantee{}) >+ .WithInvariants(increment) >+ .Test()); >+ EXPECT_TRUE(testing::MakeExceptionSafetyTester() >+ .WithInitialValue(HasReset{}) >+ .WithInvariants(CheckHasResetInvariants) >+ .Test(invoker)); >+} >+ >+struct NonCopyable : public NonNegative { >+ NonCopyable(const NonCopyable&) = delete; >+ NonCopyable() : NonNegative{0} {} >+ >+ void operator()() { ThrowingValue<> bomb; } >+}; >+ >+TEST(ExceptionCheckTest, NonCopyable) { >+ auto factory = []() { return absl::make_unique<NonCopyable>(); }; >+ EXPECT_TRUE(tester.WithFactory(factory).Test()); >+ EXPECT_TRUE(strong_tester.WithFactory(factory).Test()); >+} >+ >+struct NonEqualityComparable : public NonNegative { >+ void operator()() { ThrowingValue<> bomb; } >+ >+ void ModifyOnThrow() { >+ ++i; >+ ThrowingValue<> bomb; >+ static_cast<void>(bomb); >+ --i; >+ } >+}; >+ >+TEST(ExceptionCheckTest, NonEqualityComparable) { >+ auto nec_is_strong = [](NonEqualityComparable* nec) { >+ return testing::AssertionResult(nec->i == NonEqualityComparable().i); >+ }; >+ auto strong_nec_tester = tester.WithInitialValue(NonEqualityComparable{}) >+ .WithInvariants(nec_is_strong); >+ >+ EXPECT_TRUE(strong_nec_tester.Test()); >+ EXPECT_FALSE(strong_nec_tester.Test( >+ [](NonEqualityComparable* n) { n->ModifyOnThrow(); })); >+} >+ >+template <typename T> >+struct ExhaustivenessTester { >+ void operator()() { >+ successes |= 1; >+ T b1; >+ static_cast<void>(b1); >+ successes |= (1 << 1); >+ T b2; >+ static_cast<void>(b2); >+ successes |= (1 << 2); >+ T b3; >+ static_cast<void>(b3); >+ successes |= (1 << 3); >+ } >+ >+ bool operator==(const ExhaustivenessTester<ThrowingValue<>>&) const { >+ return true; >+ } >+ >+ static unsigned char successes; >+}; >+ >+struct { >+ template <typename T> >+ testing::AssertionResult operator()(ExhaustivenessTester<T>*) const { >+ return testing::AssertionSuccess(); >+ } >+} CheckExhaustivenessTesterInvariants; >+ >+template <typename T> >+unsigned char ExhaustivenessTester<T>::successes = 0; >+ >+TEST(ExceptionCheckTest, Exhaustiveness) { >+ auto exhaust_tester = testing::MakeExceptionSafetyTester() >+ .WithInvariants(CheckExhaustivenessTesterInvariants) >+ .WithOperation(invoker); >+ >+ EXPECT_TRUE( >+ exhaust_tester.WithInitialValue(ExhaustivenessTester<int>{}).Test()); >+ EXPECT_EQ(ExhaustivenessTester<int>::successes, 0xF); >+ >+ EXPECT_TRUE( >+ exhaust_tester.WithInitialValue(ExhaustivenessTester<ThrowingValue<>>{}) >+ .WithInvariants(testing::strong_guarantee) >+ .Test()); >+ EXPECT_EQ(ExhaustivenessTester<ThrowingValue<>>::successes, 0xF); >+} >+ >+struct LeaksIfCtorThrows : private exceptions_internal::TrackedObject { >+ LeaksIfCtorThrows() : TrackedObject(ABSL_PRETTY_FUNCTION) { >+ ++counter; >+ ThrowingValue<> v; >+ static_cast<void>(v); >+ --counter; >+ } >+ LeaksIfCtorThrows(const LeaksIfCtorThrows&) noexcept >+ : TrackedObject(ABSL_PRETTY_FUNCTION) {} >+ static int counter; >+}; >+int LeaksIfCtorThrows::counter = 0; >+ >+TEST(ExceptionCheckTest, TestLeakyCtor) { >+ testing::TestThrowingCtor<LeaksIfCtorThrows>(); >+ EXPECT_EQ(LeaksIfCtorThrows::counter, 1); >+ LeaksIfCtorThrows::counter = 0; >+} >+ >+struct Tracked : private exceptions_internal::TrackedObject { >+ Tracked() : TrackedObject(ABSL_PRETTY_FUNCTION) {} >+}; >+ >+TEST(ConstructorTrackerTest, CreatedBefore) { >+ Tracked a, b, c; >+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); >+} >+ >+TEST(ConstructorTrackerTest, CreatedAfter) { >+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); >+ Tracked a, b, c; >+} >+ >+TEST(ConstructorTrackerTest, NotDestroyedAfter) { >+ absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage; >+ EXPECT_NONFATAL_FAILURE( >+ { >+ exceptions_internal::ConstructorTracker ct( >+ exceptions_internal::countdown); >+ new (&storage) Tracked; >+ }, >+ "not destroyed"); >+} >+ >+TEST(ConstructorTrackerTest, DestroyedTwice) { >+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); >+ EXPECT_NONFATAL_FAILURE( >+ { >+ Tracked t; >+ t.~Tracked(); >+ }, >+ "re-destroyed"); >+} >+ >+TEST(ConstructorTrackerTest, ConstructedTwice) { >+ exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown); >+ absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage; >+ EXPECT_NONFATAL_FAILURE( >+ { >+ new (&storage) Tracked; >+ new (&storage) Tracked; >+ reinterpret_cast<Tracked*>(&storage)->~Tracked(); >+ }, >+ "re-constructed"); >+} >+ >+TEST(ThrowingValueTraitsTest, RelationalOperators) { >+ ThrowingValue<> a, b; >+ EXPECT_TRUE((std::is_convertible<decltype(a == b), bool>::value)); >+ EXPECT_TRUE((std::is_convertible<decltype(a != b), bool>::value)); >+ EXPECT_TRUE((std::is_convertible<decltype(a < b), bool>::value)); >+ EXPECT_TRUE((std::is_convertible<decltype(a <= b), bool>::value)); >+ EXPECT_TRUE((std::is_convertible<decltype(a > b), bool>::value)); >+ EXPECT_TRUE((std::is_convertible<decltype(a >= b), bool>::value)); >+} >+ >+TEST(ThrowingAllocatorTraitsTest, Assignablility) { >+ EXPECT_TRUE(std::is_move_assignable<ThrowingAllocator<int>>::value); >+ EXPECT_TRUE(std::is_copy_assignable<ThrowingAllocator<int>>::value); >+ EXPECT_TRUE(std::is_nothrow_move_assignable<ThrowingAllocator<int>>::value); >+ EXPECT_TRUE(std::is_nothrow_copy_assignable<ThrowingAllocator<int>>::value); >+} >+ >+} // namespace >+ >+} // namespace testing >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test.cc >new file mode 100644 >index 00000000000..5499189a3da >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test.cc >@@ -0,0 +1,62 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <type_traits> >+ >+#include "absl/base/internal/inline_variable.h" >+#include "absl/base/internal/inline_variable_testing.h" >+ >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace inline_variable_testing_internal { >+namespace { >+ >+TEST(InlineVariableTest, Constexpr) { >+ static_assert(inline_variable_foo.value == 5, ""); >+ static_assert(other_inline_variable_foo.value == 5, ""); >+ static_assert(inline_variable_int == 5, ""); >+ static_assert(other_inline_variable_int == 5, ""); >+} >+ >+TEST(InlineVariableTest, DefaultConstructedIdentityEquality) { >+ EXPECT_EQ(get_foo_a().value, 5); >+ EXPECT_EQ(get_foo_b().value, 5); >+ EXPECT_EQ(&get_foo_a(), &get_foo_b()); >+} >+ >+TEST(InlineVariableTest, DefaultConstructedIdentityInequality) { >+ EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo); >+} >+ >+TEST(InlineVariableTest, InitializedIdentityEquality) { >+ EXPECT_EQ(get_int_a(), 5); >+ EXPECT_EQ(get_int_b(), 5); >+ EXPECT_EQ(&get_int_a(), &get_int_b()); >+} >+ >+TEST(InlineVariableTest, InitializedIdentityInequality) { >+ EXPECT_NE(&inline_variable_int, &other_inline_variable_int); >+} >+ >+TEST(InlineVariableTest, FunPtrType) { >+ static_assert( >+ std::is_same<void(*)(), >+ std::decay<decltype(inline_variable_fun_ptr)>::type>::value, >+ ""); >+} >+ >+} // namespace >+} // namespace inline_variable_testing_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc >new file mode 100644 >index 00000000000..a3bf3b68b3c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_a.cc >@@ -0,0 +1,25 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/inline_variable_testing.h" >+ >+namespace absl { >+namespace inline_variable_testing_internal { >+ >+const Foo& get_foo_a() { return inline_variable_foo; } >+ >+const int& get_int_a() { return inline_variable_int; } >+ >+} // namespace inline_variable_testing_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc >new file mode 100644 >index 00000000000..b4b9393a558 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/inline_variable_test_b.cc >@@ -0,0 +1,25 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/inline_variable_testing.h" >+ >+namespace absl { >+namespace inline_variable_testing_internal { >+ >+const Foo& get_foo_b() { return inline_variable_foo; } >+ >+const int& get_int_b() { return inline_variable_int; } >+ >+} // namespace inline_variable_testing_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook.h >new file mode 100644 >index 00000000000..b458511b0c7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook.h >@@ -0,0 +1,165 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ >+#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ >+ >+#include <atomic> >+#include <cassert> >+#include <cstdint> >+#include <utility> >+ >+#ifdef _MSC_FULL_VER >+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0 >+#else >+#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1 >+#endif >+ >+namespace absl { >+namespace base_internal { >+ >+template <typename T> >+class AtomicHook; >+ >+// AtomicHook is a helper class, templatized on a raw function pointer type, for >+// implementing Abseil customization hooks. It is a callable object that >+// dispatches to the registered hook. >+// >+// A default constructed object performs a no-op (and returns a default >+// constructed object) if no hook has been registered. >+// >+// Hooks can be pre-registered via constant initialization, for example, >+// ABSL_CONST_INIT static AtomicHook<void(*)()> my_hook(DefaultAction); >+// and then changed at runtime via a call to Store(). >+// >+// Reads and writes guarantee memory_order_acquire/memory_order_release >+// semantics. >+template <typename ReturnType, typename... Args> >+class AtomicHook<ReturnType (*)(Args...)> { >+ public: >+ using FnPtr = ReturnType (*)(Args...); >+ >+ // Constructs an object that by default performs a no-op (and >+ // returns a default constructed object) when no hook as been registered. >+ constexpr AtomicHook() : AtomicHook(DummyFunction) {} >+ >+ // Constructs an object that by default dispatches to/returns the >+ // pre-registered default_fn when no hook has been registered at runtime. >+#if ABSL_HAVE_WORKING_ATOMIC_POINTER >+ explicit constexpr AtomicHook(FnPtr default_fn) >+ : hook_(default_fn), default_fn_(default_fn) {} >+#else >+ explicit constexpr AtomicHook(FnPtr default_fn) >+ : hook_(kUninitialized), default_fn_(default_fn) {} >+#endif >+ >+ // Stores the provided function pointer as the value for this hook. >+ // >+ // This is intended to be called once. Multiple calls are legal only if the >+ // same function pointer is provided for each call. The store is implemented >+ // as a memory_order_release operation, and read accesses are implemented as >+ // memory_order_acquire. >+ void Store(FnPtr fn) { >+ bool success = DoStore(fn); >+ static_cast<void>(success); >+ assert(success); >+ } >+ >+ // Invokes the registered callback. If no callback has yet been registered, a >+ // default-constructed object of the appropriate type is returned instead. >+ template <typename... CallArgs> >+ ReturnType operator()(CallArgs&&... args) const { >+ return DoLoad()(std::forward<CallArgs>(args)...); >+ } >+ >+ // Returns the registered callback, or nullptr if none has been registered. >+ // Useful if client code needs to conditionalize behavior based on whether a >+ // callback was registered. >+ // >+ // Note that atomic_hook.Load()() and atomic_hook() have different semantics: >+ // operator()() will perform a no-op if no callback was registered, while >+ // Load()() will dereference a null function pointer. Prefer operator()() to >+ // Load()() unless you must conditionalize behavior on whether a hook was >+ // registered. >+ FnPtr Load() const { >+ FnPtr ptr = DoLoad(); >+ return (ptr == DummyFunction) ? nullptr : ptr; >+ } >+ >+ private: >+ static ReturnType DummyFunction(Args...) { >+ return ReturnType(); >+ } >+ >+ // Current versions of MSVC (as of September 2017) have a broken >+ // implementation of std::atomic<T*>: Its constructor attempts to do the >+ // equivalent of a reinterpret_cast in a constexpr context, which is not >+ // allowed. >+ // >+ // This causes an issue when building with LLVM under Windows. To avoid this, >+ // we use a less-efficient, intptr_t-based implementation on Windows. >+#if ABSL_HAVE_WORKING_ATOMIC_POINTER >+ // Return the stored value, or DummyFunction if no value has been stored. >+ FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); } >+ >+ // Store the given value. Returns false if a different value was already >+ // stored to this object. >+ bool DoStore(FnPtr fn) { >+ assert(fn); >+ FnPtr expected = default_fn_; >+ const bool store_succeeded = hook_.compare_exchange_strong( >+ expected, fn, std::memory_order_acq_rel, std::memory_order_acquire); >+ const bool same_value_already_stored = (expected == fn); >+ return store_succeeded || same_value_already_stored; >+ } >+ >+ std::atomic<FnPtr> hook_; >+#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER >+ // Use a sentinel value unlikely to be the address of an actual function. >+ static constexpr intptr_t kUninitialized = 0; >+ >+ static_assert(sizeof(intptr_t) >= sizeof(FnPtr), >+ "intptr_t can't contain a function pointer"); >+ >+ FnPtr DoLoad() const { >+ const intptr_t value = hook_.load(std::memory_order_acquire); >+ if (value == kUninitialized) { >+ return default_fn_; >+ } >+ return reinterpret_cast<FnPtr>(value); >+ } >+ >+ bool DoStore(FnPtr fn) { >+ assert(fn); >+ const auto value = reinterpret_cast<intptr_t>(fn); >+ intptr_t expected = kUninitialized; >+ const bool store_succeeded = hook_.compare_exchange_strong( >+ expected, value, std::memory_order_acq_rel, std::memory_order_acquire); >+ const bool same_value_already_stored = (expected == value); >+ return store_succeeded || same_value_already_stored; >+ } >+ >+ std::atomic<intptr_t> hook_; >+#endif >+ >+ const FnPtr default_fn_; >+}; >+ >+#undef ABSL_HAVE_WORKING_ATOMIC_POINTER >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc >new file mode 100644 >index 00000000000..cf7407573a5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/atomic_hook_test.cc >@@ -0,0 +1,70 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/atomic_hook.h" >+ >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+ >+namespace { >+ >+int value = 0; >+void TestHook(int x) { value = x; } >+ >+TEST(AtomicHookTest, NoDefaultFunction) { >+ ABSL_CONST_INIT static absl::base_internal::AtomicHook<void(*)(int)> hook; >+ value = 0; >+ >+ // Test the default DummyFunction. >+ EXPECT_TRUE(hook.Load() == nullptr); >+ EXPECT_EQ(value, 0); >+ hook(1); >+ EXPECT_EQ(value, 0); >+ >+ // Test a stored hook. >+ hook.Store(TestHook); >+ EXPECT_TRUE(hook.Load() == TestHook); >+ EXPECT_EQ(value, 0); >+ hook(1); >+ EXPECT_EQ(value, 1); >+ >+ // Calling Store() with the same hook should not crash. >+ hook.Store(TestHook); >+ EXPECT_TRUE(hook.Load() == TestHook); >+ EXPECT_EQ(value, 1); >+ hook(2); >+ EXPECT_EQ(value, 2); >+} >+ >+TEST(AtomicHookTest, WithDefaultFunction) { >+ // Set the default value to TestHook at compile-time. >+ ABSL_CONST_INIT static absl::base_internal::AtomicHook<void (*)(int)> hook( >+ TestHook); >+ value = 0; >+ >+ // Test the default value is TestHook. >+ EXPECT_TRUE(hook.Load() == TestHook); >+ EXPECT_EQ(value, 0); >+ hook(1); >+ EXPECT_EQ(value, 1); >+ >+ // Calling Store() with the same hook should not crash. >+ hook.Store(TestHook); >+ EXPECT_TRUE(hook.Load() == TestHook); >+ EXPECT_EQ(value, 1); >+ hook(2); >+ EXPECT_EQ(value, 2); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.cc >new file mode 100644 >index 00000000000..a742df01f94 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.cc >@@ -0,0 +1,81 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// The implementation of CycleClock::Frequency. >+// >+// NOTE: only i386 and x86_64 have been well tested. >+// PPC, sparc, alpha, and ia64 are based on >+// http://peter.kuscsik.com/wordpress/?p=14 >+// with modifications by m3b. See also >+// https://setisvn.ssl.berkeley.edu/svn/lib/fftw-3.0.1/kernel/cycle.h >+ >+#include "absl/base/internal/cycleclock.h" >+ >+#include <chrono> // NOLINT(build/c++11) >+ >+#include "absl/base/internal/unscaledcycleclock.h" >+ >+namespace absl { >+namespace base_internal { >+ >+#if ABSL_USE_UNSCALED_CYCLECLOCK >+ >+namespace { >+ >+#ifdef NDEBUG >+#ifdef ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY >+// Not debug mode and the UnscaledCycleClock frequency is the CPU >+// frequency. Scale the CycleClock to prevent overflow if someone >+// tries to represent the time as cycles since the Unix epoch. >+static constexpr int32_t kShift = 1; >+#else >+// Not debug mode and the UnscaledCycleClock isn't operating at the >+// raw CPU frequency. There is no need to do any scaling, so don't >+// needlessly sacrifice precision. >+static constexpr int32_t kShift = 0; >+#endif >+#else >+// In debug mode use a different shift to discourage depending on a >+// particular shift value. >+static constexpr int32_t kShift = 2; >+#endif >+ >+static constexpr double kFrequencyScale = 1.0 / (1 << kShift); >+ >+} // namespace >+ >+int64_t CycleClock::Now() { >+ return base_internal::UnscaledCycleClock::Now() >> kShift; >+} >+ >+double CycleClock::Frequency() { >+ return kFrequencyScale * base_internal::UnscaledCycleClock::Frequency(); >+} >+ >+#else >+ >+int64_t CycleClock::Now() { >+ return std::chrono::duration_cast<std::chrono::nanoseconds>( >+ std::chrono::steady_clock::now().time_since_epoch()) >+ .count(); >+} >+ >+double CycleClock::Frequency() { >+ return 1e9; >+} >+ >+#endif >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.h >new file mode 100644 >index 00000000000..60e971583c5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/cycleclock.h >@@ -0,0 +1,77 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// ----------------------------------------------------------------------------- >+// File: cycleclock.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines a `CycleClock`, which yields the value and frequency >+// of a cycle counter that increments at a rate that is approximately constant. >+// >+// NOTE: >+// >+// The cycle counter frequency is not necessarily related to the core clock >+// frequency and should not be treated as such. That is, `CycleClock` cycles are >+// not necessarily "CPU cycles" and code should not rely on that behavior, even >+// if experimentally observed. >+// >+// >+// An arbitrary offset may have been added to the counter at power on. >+// >+// On some platforms, the rate and offset of the counter may differ >+// slightly when read from different CPUs of a multiprocessor. Usually, >+// we try to ensure that the operating system adjusts values periodically >+// so that values agree approximately. If you need stronger guarantees, >+// consider using alternate interfaces. >+// >+// The CPU is not required to maintain the ordering of a cycle counter read >+// with respect to surrounding instructions. >+ >+#ifndef ABSL_BASE_INTERNAL_CYCLECLOCK_H_ >+#define ABSL_BASE_INTERNAL_CYCLECLOCK_H_ >+ >+#include <cstdint> >+ >+namespace absl { >+namespace base_internal { >+ >+// ----------------------------------------------------------------------------- >+// CycleClock >+// ----------------------------------------------------------------------------- >+class CycleClock { >+ public: >+ // CycleClock::Now() >+ // >+ // Returns the value of a cycle counter that counts at a rate that is >+ // approximately constant. >+ static int64_t Now(); >+ >+ // CycleClock::Frequency() >+ // >+ // Returns the amount by which `CycleClock::Now()` increases per second. Note >+ // that this value may not necessarily match the core CPU clock frequency. >+ static double Frequency(); >+ >+ private: >+ CycleClock() = delete; // no instances >+ CycleClock(const CycleClock&) = delete; >+ CycleClock& operator=(const CycleClock&) = delete; >+}; >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_CYCLECLOCK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/direct_mmap.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/direct_mmap.h >new file mode 100644 >index 00000000000..0426e11890b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/direct_mmap.h >@@ -0,0 +1,153 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Functions for directly invoking mmap() via syscall, avoiding the case where >+// mmap() has been locally overridden. >+ >+#ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ >+#define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ >+ >+#include "absl/base/config.h" >+ >+#if ABSL_HAVE_MMAP >+ >+#include <sys/mman.h> >+ >+#ifdef __linux__ >+ >+#include <sys/types.h> >+#ifdef __BIONIC__ >+#include <sys/syscall.h> >+#else >+#include <syscall.h> >+#endif >+ >+#include <linux/unistd.h> >+#include <unistd.h> >+#include <cerrno> >+#include <cstdarg> >+#include <cstdint> >+ >+#ifdef __mips__ >+// Include definitions of the ABI currently in use. >+#ifdef __BIONIC__ >+// Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the >+// definitions we need. >+#include <asm/sgidefs.h> >+#else >+#include <sgidefs.h> >+#endif // __BIONIC__ >+#endif // __mips__ >+ >+// SYS_mmap and SYS_munmap are not defined in Android. >+#ifdef __BIONIC__ >+extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); >+#if defined(__NR_mmap) && !defined(SYS_mmap) >+#define SYS_mmap __NR_mmap >+#endif >+#ifndef SYS_munmap >+#define SYS_munmap __NR_munmap >+#endif >+#endif // __BIONIC__ >+ >+namespace absl { >+namespace base_internal { >+ >+// Platform specific logic extracted from >+// https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h >+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, >+ off64_t offset) noexcept { >+#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ >+ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ >+ (defined(__PPC__) && !defined(__PPC64__)) || \ >+ (defined(__s390__) && !defined(__s390x__)) >+ // On these architectures, implement mmap with mmap2. >+ static int pagesize = 0; >+ if (pagesize == 0) { >+ pagesize = getpagesize(); >+ } >+ if (offset < 0 || offset % pagesize != 0) { >+ errno = EINVAL; >+ return MAP_FAILED; >+ } >+#ifdef __BIONIC__ >+ // SYS_mmap2 has problems on Android API level <= 16. >+ // Workaround by invoking __mmap2() instead. >+ return __mmap2(start, length, prot, flags, fd, offset / pagesize); >+#else >+ return reinterpret_cast<void*>( >+ syscall(SYS_mmap2, start, length, prot, flags, fd, >+ static_cast<off_t>(offset / pagesize))); >+#endif >+#elif defined(__s390x__) >+ // On s390x, mmap() arguments are passed in memory. >+ unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT >+ static_cast<unsigned long>(length), // NOLINT >+ static_cast<unsigned long>(prot), // NOLINT >+ static_cast<unsigned long>(flags), // NOLINT >+ static_cast<unsigned long>(fd), // NOLINT >+ static_cast<unsigned long>(offset)}; // NOLINT >+ return reinterpret_cast<void*>(syscall(SYS_mmap, buf)); >+#elif defined(__x86_64__) >+// The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. >+// We need to explicitly cast to an unsigned 64 bit type to avoid implicit >+// sign extension. We can't cast pointers directly because those are >+// 32 bits, and gcc will dump ugly warnings about casting from a pointer >+// to an integer of a different size. We also need to make sure __off64_t >+// isn't truncated to 32-bits under x32. >+#define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x)) >+ return reinterpret_cast<void*>( >+ syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length), >+ MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags), >+ MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset))); >+#undef MMAP_SYSCALL_ARG >+#else // Remaining 64-bit aritectures. >+ static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit"); >+ return reinterpret_cast<void*>( >+ syscall(SYS_mmap, start, length, prot, flags, fd, offset)); >+#endif >+} >+ >+inline int DirectMunmap(void* start, size_t length) { >+ return static_cast<int>(syscall(SYS_munmap, start, length)); >+} >+ >+} // namespace base_internal >+} // namespace absl >+ >+#else // !__linux__ >+ >+// For non-linux platforms where we have mmap, just dispatch directly to the >+// actual mmap()/munmap() methods. >+ >+namespace absl { >+namespace base_internal { >+ >+inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, >+ off_t offset) { >+ return mmap(start, length, prot, flags, fd, offset); >+} >+ >+inline int DirectMunmap(void* start, size_t length) { >+ return munmap(start, length); >+} >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // __linux__ >+ >+#endif // ABSL_HAVE_MMAP >+ >+#endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian.h >new file mode 100644 >index 00000000000..edc10f10a5a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian.h >@@ -0,0 +1,269 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_ENDIAN_H_ >+#define ABSL_BASE_INTERNAL_ENDIAN_H_ >+ >+// The following guarantees declaration of the byte swap functions >+#ifdef _MSC_VER >+#include <stdlib.h> // NOLINT(build/include) >+#elif defined(__APPLE__) >+// Mac OS X / Darwin features >+#include <libkern/OSByteOrder.h> >+#elif defined(__FreeBSD__) >+#include <sys/endian.h> >+#elif defined(__GLIBC__) >+#include <byteswap.h> // IWYU pragma: export >+#endif >+ >+#include <cstdint> >+#include "absl/base/config.h" >+#include "absl/base/internal/unaligned_access.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+ >+// Use compiler byte-swapping intrinsics if they are available. 32-bit >+// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0. >+// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0. >+// For simplicity, we enable them all only for GCC 4.8.0 or later. >+#if defined(__clang__) || \ >+ (defined(__GNUC__) && \ >+ ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5)) >+inline uint64_t gbswap_64(uint64_t host_int) { >+ return __builtin_bswap64(host_int); >+} >+inline uint32_t gbswap_32(uint32_t host_int) { >+ return __builtin_bswap32(host_int); >+} >+inline uint16_t gbswap_16(uint16_t host_int) { >+ return __builtin_bswap16(host_int); >+} >+ >+#elif defined(_MSC_VER) >+inline uint64_t gbswap_64(uint64_t host_int) { >+ return _byteswap_uint64(host_int); >+} >+inline uint32_t gbswap_32(uint32_t host_int) { >+ return _byteswap_ulong(host_int); >+} >+inline uint16_t gbswap_16(uint16_t host_int) { >+ return _byteswap_ushort(host_int); >+} >+ >+#elif defined(__APPLE__) >+inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); } >+inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); } >+inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); } >+ >+#else >+inline uint64_t gbswap_64(uint64_t host_int) { >+#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__) >+ // Adapted from /usr/include/byteswap.h. Not available on Mac. >+ if (__builtin_constant_p(host_int)) { >+ return __bswap_constant_64(host_int); >+ } else { >+ register uint64_t result; >+ __asm__("bswap %0" : "=r"(result) : "0"(host_int)); >+ return result; >+ } >+#elif defined(__GLIBC__) >+ return bswap_64(host_int); >+#else >+ return (((x & uint64_t{(0xFF}) << 56) | >+ ((x & uint64_t{(0xFF00}) << 40) | >+ ((x & uint64_t{(0xFF0000}) << 24) | >+ ((x & uint64_t{(0xFF000000}) << 8) | >+ ((x & uint64_t{(0xFF00000000}) >> 8) | >+ ((x & uint64_t{(0xFF0000000000}) >> 24) | >+ ((x & uint64_t{(0xFF000000000000}) >> 40) | >+ ((x & uint64_t{(0xFF00000000000000}) >> 56)); >+#endif // bswap_64 >+} >+ >+inline uint32_t gbswap_32(uint32_t host_int) { >+#if defined(__GLIBC__) >+ return bswap_32(host_int); >+#else >+ return (((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | >+ ((x & 0xFF000000) >> 24)); >+#endif >+} >+ >+inline uint16_t gbswap_16(uint16_t host_int) { >+#if defined(__GLIBC__) >+ return bswap_16(host_int); >+#else >+ return uint16_t{((x & 0xFF) << 8) | ((x & 0xFF00) >> 8)}; >+#endif >+} >+ >+#endif // intrinics available >+ >+#ifdef ABSL_IS_LITTLE_ENDIAN >+ >+// Definitions for ntohl etc. that don't require us to include >+// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather >+// than just #defining them because in debug mode, gcc doesn't >+// correctly handle the (rather involved) definitions of bswap_32. >+// gcc guarantees that inline functions are as fast as macros, so >+// this isn't a performance hit. >+inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); } >+inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); } >+inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); } >+ >+#elif defined ABSL_IS_BIG_ENDIAN >+ >+// These definitions are simpler on big-endian machines >+// These are functions instead of macros to avoid self-assignment warnings >+// on calls such as "i = ghtnol(i);". This also provides type checking. >+inline uint16_t ghtons(uint16_t x) { return x; } >+inline uint32_t ghtonl(uint32_t x) { return x; } >+inline uint64_t ghtonll(uint64_t x) { return x; } >+ >+#else >+#error \ >+ "Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \ >+ "ABSL_IS_LITTLE_ENDIAN must be defined" >+#endif // byte order >+ >+inline uint16_t gntohs(uint16_t x) { return ghtons(x); } >+inline uint32_t gntohl(uint32_t x) { return ghtonl(x); } >+inline uint64_t gntohll(uint64_t x) { return ghtonll(x); } >+ >+// Utilities to convert numbers between the current hosts's native byte >+// order and little-endian byte order >+// >+// Load/Store methods are alignment safe >+namespace little_endian { >+// Conversion functions. >+#ifdef ABSL_IS_LITTLE_ENDIAN >+ >+inline uint16_t FromHost16(uint16_t x) { return x; } >+inline uint16_t ToHost16(uint16_t x) { return x; } >+ >+inline uint32_t FromHost32(uint32_t x) { return x; } >+inline uint32_t ToHost32(uint32_t x) { return x; } >+ >+inline uint64_t FromHost64(uint64_t x) { return x; } >+inline uint64_t ToHost64(uint64_t x) { return x; } >+ >+inline constexpr bool IsLittleEndian() { return true; } >+ >+#elif defined ABSL_IS_BIG_ENDIAN >+ >+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } >+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } >+ >+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } >+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } >+ >+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } >+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } >+ >+inline constexpr bool IsLittleEndian() { return false; } >+ >+#endif /* ENDIAN */ >+ >+// Functions to do unaligned loads and stores in little-endian order. >+inline uint16_t Load16(const void *p) { >+ return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); >+} >+ >+inline void Store16(void *p, uint16_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); >+} >+ >+inline uint32_t Load32(const void *p) { >+ return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); >+} >+ >+inline void Store32(void *p, uint32_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); >+} >+ >+inline uint64_t Load64(const void *p) { >+ return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); >+} >+ >+inline void Store64(void *p, uint64_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); >+} >+ >+} // namespace little_endian >+ >+// Utilities to convert numbers between the current hosts's native byte >+// order and big-endian byte order (same as network byte order) >+// >+// Load/Store methods are alignment safe >+namespace big_endian { >+#ifdef ABSL_IS_LITTLE_ENDIAN >+ >+inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); } >+inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); } >+ >+inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); } >+inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); } >+ >+inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); } >+inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); } >+ >+inline constexpr bool IsLittleEndian() { return true; } >+ >+#elif defined ABSL_IS_BIG_ENDIAN >+ >+inline uint16_t FromHost16(uint16_t x) { return x; } >+inline uint16_t ToHost16(uint16_t x) { return x; } >+ >+inline uint32_t FromHost32(uint32_t x) { return x; } >+inline uint32_t ToHost32(uint32_t x) { return x; } >+ >+inline uint64_t FromHost64(uint64_t x) { return x; } >+inline uint64_t ToHost64(uint64_t x) { return x; } >+ >+inline constexpr bool IsLittleEndian() { return false; } >+ >+#endif /* ENDIAN */ >+ >+// Functions to do unaligned loads and stores in big-endian order. >+inline uint16_t Load16(const void *p) { >+ return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p)); >+} >+ >+inline void Store16(void *p, uint16_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v)); >+} >+ >+inline uint32_t Load32(const void *p) { >+ return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p)); >+} >+ >+inline void Store32(void *p, uint32_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v)); >+} >+ >+inline uint64_t Load64(const void *p) { >+ return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p)); >+} >+ >+inline void Store64(void *p, uint64_t v) { >+ ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v)); >+} >+ >+} // namespace big_endian >+ >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_ENDIAN_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian_test.cc >new file mode 100644 >index 00000000000..e27691553bc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/endian_test.cc >@@ -0,0 +1,263 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/endian.h" >+ >+#include <algorithm> >+#include <cstdint> >+#include <limits> >+#include <random> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+ >+namespace absl { >+namespace { >+ >+const uint64_t kInitialNumber{0x0123456789abcdef}; >+const uint64_t k64Value{kInitialNumber}; >+const uint32_t k32Value{0x01234567}; >+const uint16_t k16Value{0x0123}; >+const int kNumValuesToTest = 1000000; >+const int kRandomSeed = 12345; >+ >+#if defined(ABSL_IS_BIG_ENDIAN) >+const uint64_t kInitialInNetworkOrder{kInitialNumber}; >+const uint64_t k64ValueLE{0xefcdab8967452301}; >+const uint32_t k32ValueLE{0x67452301}; >+const uint16_t k16ValueLE{0x2301}; >+ >+const uint64_t k64ValueBE{kInitialNumber}; >+const uint32_t k32ValueBE{k32Value}; >+const uint16_t k16ValueBE{k16Value}; >+#elif defined(ABSL_IS_LITTLE_ENDIAN) >+const uint64_t kInitialInNetworkOrder{0xefcdab8967452301}; >+const uint64_t k64ValueLE{kInitialNumber}; >+const uint32_t k32ValueLE{k32Value}; >+const uint16_t k16ValueLE{k16Value}; >+ >+const uint64_t k64ValueBE{0xefcdab8967452301}; >+const uint32_t k32ValueBE{0x67452301}; >+const uint16_t k16ValueBE{0x2301}; >+#endif >+ >+template<typename T> >+std::vector<T> GenerateAllValuesForType() { >+ std::vector<T> result; >+ T next = std::numeric_limits<T>::min(); >+ while (true) { >+ result.push_back(next); >+ if (next == std::numeric_limits<T>::max()) { >+ return result; >+ } >+ ++next; >+ } >+} >+ >+template<typename T> >+std::vector<T> GenerateRandomIntegers(size_t numValuesToTest) { >+ std::vector<T> result; >+ std::mt19937_64 rng(kRandomSeed); >+ for (size_t i = 0; i < numValuesToTest; ++i) { >+ result.push_back(rng()); >+ } >+ return result; >+} >+ >+void ManualByteSwap(char* bytes, int length) { >+ if (length == 1) >+ return; >+ >+ EXPECT_EQ(0, length % 2); >+ for (int i = 0; i < length / 2; ++i) { >+ int j = (length - 1) - i; >+ using std::swap; >+ swap(bytes[i], bytes[j]); >+ } >+} >+ >+template<typename T> >+inline T UnalignedLoad(const char* p) { >+ static_assert( >+ sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, >+ "Unexpected type size"); >+ >+ switch (sizeof(T)) { >+ case 1: return *reinterpret_cast<const T*>(p); >+ case 2: >+ return ABSL_INTERNAL_UNALIGNED_LOAD16(p); >+ case 4: >+ return ABSL_INTERNAL_UNALIGNED_LOAD32(p); >+ case 8: >+ return ABSL_INTERNAL_UNALIGNED_LOAD64(p); >+ default: >+ // Suppresses invalid "not all control paths return a value" on MSVC >+ return {}; >+ } >+} >+ >+template <typename T, typename ByteSwapper> >+static void GBSwapHelper(const std::vector<T>& host_values_to_test, >+ const ByteSwapper& byte_swapper) { >+ // Test byte_swapper against a manual byte swap. >+ for (typename std::vector<T>::const_iterator it = host_values_to_test.begin(); >+ it != host_values_to_test.end(); ++it) { >+ T host_value = *it; >+ >+ char actual_value[sizeof(host_value)]; >+ memcpy(actual_value, &host_value, sizeof(host_value)); >+ byte_swapper(actual_value); >+ >+ char expected_value[sizeof(host_value)]; >+ memcpy(expected_value, &host_value, sizeof(host_value)); >+ ManualByteSwap(expected_value, sizeof(host_value)); >+ >+ ASSERT_EQ(0, memcmp(actual_value, expected_value, sizeof(host_value))) >+ << "Swap output for 0x" << std::hex << host_value << " does not match. " >+ << "Expected: 0x" << UnalignedLoad<T>(expected_value) << "; " >+ << "actual: 0x" << UnalignedLoad<T>(actual_value); >+ } >+} >+ >+void Swap16(char* bytes) { >+ ABSL_INTERNAL_UNALIGNED_STORE16( >+ bytes, gbswap_16(ABSL_INTERNAL_UNALIGNED_LOAD16(bytes))); >+} >+ >+void Swap32(char* bytes) { >+ ABSL_INTERNAL_UNALIGNED_STORE32( >+ bytes, gbswap_32(ABSL_INTERNAL_UNALIGNED_LOAD32(bytes))); >+} >+ >+void Swap64(char* bytes) { >+ ABSL_INTERNAL_UNALIGNED_STORE64( >+ bytes, gbswap_64(ABSL_INTERNAL_UNALIGNED_LOAD64(bytes))); >+} >+ >+TEST(EndianessTest, Uint16) { >+ GBSwapHelper(GenerateAllValuesForType<uint16_t>(), &Swap16); >+} >+ >+TEST(EndianessTest, Uint32) { >+ GBSwapHelper(GenerateRandomIntegers<uint32_t>(kNumValuesToTest), &Swap32); >+} >+ >+TEST(EndianessTest, Uint64) { >+ GBSwapHelper(GenerateRandomIntegers<uint64_t>(kNumValuesToTest), &Swap64); >+} >+ >+TEST(EndianessTest, ghtonll_gntohll) { >+ // Test that absl::ghtonl compiles correctly >+ uint32_t test = 0x01234567; >+ EXPECT_EQ(absl::gntohl(absl::ghtonl(test)), test); >+ >+ uint64_t comp = absl::ghtonll(kInitialNumber); >+ EXPECT_EQ(comp, kInitialInNetworkOrder); >+ comp = absl::gntohll(kInitialInNetworkOrder); >+ EXPECT_EQ(comp, kInitialNumber); >+ >+ // Test that htonll and ntohll are each others' inverse functions on a >+ // somewhat assorted batch of numbers. 37 is chosen to not be anything >+ // particularly nice base 2. >+ uint64_t value = 1; >+ for (int i = 0; i < 100; ++i) { >+ comp = absl::ghtonll(absl::gntohll(value)); >+ EXPECT_EQ(value, comp); >+ comp = absl::gntohll(absl::ghtonll(value)); >+ EXPECT_EQ(value, comp); >+ value *= 37; >+ } >+} >+ >+TEST(EndianessTest, little_endian) { >+ // Check little_endian uint16_t. >+ uint64_t comp = little_endian::FromHost16(k16Value); >+ EXPECT_EQ(comp, k16ValueLE); >+ comp = little_endian::ToHost16(k16ValueLE); >+ EXPECT_EQ(comp, k16Value); >+ >+ // Check little_endian uint32_t. >+ comp = little_endian::FromHost32(k32Value); >+ EXPECT_EQ(comp, k32ValueLE); >+ comp = little_endian::ToHost32(k32ValueLE); >+ EXPECT_EQ(comp, k32Value); >+ >+ // Check little_endian uint64_t. >+ comp = little_endian::FromHost64(k64Value); >+ EXPECT_EQ(comp, k64ValueLE); >+ comp = little_endian::ToHost64(k64ValueLE); >+ EXPECT_EQ(comp, k64Value); >+ >+ // Check little-endian Load and store functions. >+ uint16_t u16Buf; >+ uint32_t u32Buf; >+ uint64_t u64Buf; >+ >+ little_endian::Store16(&u16Buf, k16Value); >+ EXPECT_EQ(u16Buf, k16ValueLE); >+ comp = little_endian::Load16(&u16Buf); >+ EXPECT_EQ(comp, k16Value); >+ >+ little_endian::Store32(&u32Buf, k32Value); >+ EXPECT_EQ(u32Buf, k32ValueLE); >+ comp = little_endian::Load32(&u32Buf); >+ EXPECT_EQ(comp, k32Value); >+ >+ little_endian::Store64(&u64Buf, k64Value); >+ EXPECT_EQ(u64Buf, k64ValueLE); >+ comp = little_endian::Load64(&u64Buf); >+ EXPECT_EQ(comp, k64Value); >+} >+ >+TEST(EndianessTest, big_endian) { >+ // Check big-endian Load and store functions. >+ uint16_t u16Buf; >+ uint32_t u32Buf; >+ uint64_t u64Buf; >+ >+ unsigned char buffer[10]; >+ big_endian::Store16(&u16Buf, k16Value); >+ EXPECT_EQ(u16Buf, k16ValueBE); >+ uint64_t comp = big_endian::Load16(&u16Buf); >+ EXPECT_EQ(comp, k16Value); >+ >+ big_endian::Store32(&u32Buf, k32Value); >+ EXPECT_EQ(u32Buf, k32ValueBE); >+ comp = big_endian::Load32(&u32Buf); >+ EXPECT_EQ(comp, k32Value); >+ >+ big_endian::Store64(&u64Buf, k64Value); >+ EXPECT_EQ(u64Buf, k64ValueBE); >+ comp = big_endian::Load64(&u64Buf); >+ EXPECT_EQ(comp, k64Value); >+ >+ big_endian::Store16(buffer + 1, k16Value); >+ EXPECT_EQ(u16Buf, k16ValueBE); >+ comp = big_endian::Load16(buffer + 1); >+ EXPECT_EQ(comp, k16Value); >+ >+ big_endian::Store32(buffer + 1, k32Value); >+ EXPECT_EQ(u32Buf, k32ValueBE); >+ comp = big_endian::Load32(buffer + 1); >+ EXPECT_EQ(comp, k32Value); >+ >+ big_endian::Store64(buffer + 1, k64Value); >+ EXPECT_EQ(u64Buf, k64ValueBE); >+ comp = big_endian::Load64(buffer + 1); >+ EXPECT_EQ(comp, k64Value); >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc >new file mode 100644 >index 00000000000..f1d081f7e50 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.cc >@@ -0,0 +1,71 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/exception_safety_testing.h" >+ >+#include "gtest/gtest.h" >+#include "absl/meta/type_traits.h" >+ >+namespace testing { >+ >+exceptions_internal::NoThrowTag nothrow_ctor; >+ >+exceptions_internal::StrongGuaranteeTagType strong_guarantee; >+ >+namespace exceptions_internal { >+ >+int countdown = -1; >+ >+ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr; >+ >+void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) { >+ if (countdown-- == 0) { >+ if (throw_bad_alloc) throw TestBadAllocException(msg); >+ throw TestException(msg); >+ } >+} >+ >+testing::AssertionResult FailureMessage(const TestException& e, >+ int countdown) noexcept { >+ return testing::AssertionFailure() << "Exception thrown from " << e.what(); >+} >+ >+std::string GetSpecString(TypeSpec spec) { >+ std::string out; >+ absl::string_view sep; >+ const auto append = [&](absl::string_view s) { >+ absl::StrAppend(&out, sep, s); >+ sep = " | "; >+ }; >+ if (static_cast<bool>(TypeSpec::kNoThrowCopy & spec)) { >+ append("kNoThrowCopy"); >+ } >+ if (static_cast<bool>(TypeSpec::kNoThrowMove & spec)) { >+ append("kNoThrowMove"); >+ } >+ if (static_cast<bool>(TypeSpec::kNoThrowNew & spec)) { >+ append("kNoThrowNew"); >+ } >+ return out; >+} >+ >+std::string GetSpecString(AllocSpec spec) { >+ return static_cast<bool>(AllocSpec::kNoThrowAllocate & spec) >+ ? "kNoThrowAllocate" >+ : ""; >+} >+ >+} // namespace exceptions_internal >+ >+} // namespace testing >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h >new file mode 100644 >index 00000000000..8c2f5093fc4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_safety_testing.h >@@ -0,0 +1,1109 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Utilities for testing exception-safety >+ >+#ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ >+#define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ >+ >+#include <cstddef> >+#include <cstdint> >+#include <functional> >+#include <initializer_list> >+#include <iosfwd> >+#include <string> >+#include <tuple> >+#include <unordered_map> >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/pretty_function.h" >+#include "absl/memory/memory.h" >+#include "absl/meta/type_traits.h" >+#include "absl/strings/string_view.h" >+#include "absl/strings/substitute.h" >+#include "absl/types/optional.h" >+ >+namespace testing { >+ >+enum class TypeSpec; >+enum class AllocSpec; >+ >+constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) { >+ using T = absl::underlying_type_t<TypeSpec>; >+ return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b)); >+} >+ >+constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) { >+ using T = absl::underlying_type_t<TypeSpec>; >+ return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b)); >+} >+ >+constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) { >+ using T = absl::underlying_type_t<AllocSpec>; >+ return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b)); >+} >+ >+constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) { >+ using T = absl::underlying_type_t<AllocSpec>; >+ return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b)); >+} >+ >+namespace exceptions_internal { >+ >+std::string GetSpecString(TypeSpec); >+std::string GetSpecString(AllocSpec); >+ >+struct NoThrowTag {}; >+struct StrongGuaranteeTagType {}; >+ >+// A simple exception class. We throw this so that test code can catch >+// exceptions specifically thrown by ThrowingValue. >+class TestException { >+ public: >+ explicit TestException(absl::string_view msg) : msg_(msg) {} >+ virtual ~TestException() {} >+ virtual const char* what() const noexcept { return msg_.c_str(); } >+ >+ private: >+ std::string msg_; >+}; >+ >+// TestBadAllocException exists because allocation functions must throw an >+// exception which can be caught by a handler of std::bad_alloc. We use a child >+// class of std::bad_alloc so we can customise the error message, and also >+// derive from TestException so we don't accidentally end up catching an actual >+// bad_alloc exception in TestExceptionSafety. >+class TestBadAllocException : public std::bad_alloc, public TestException { >+ public: >+ explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {} >+ using TestException::what; >+}; >+ >+extern int countdown; >+ >+// Allows the countdown variable to be set manually (defaulting to the initial >+// value of 0) >+inline void SetCountdown(int i = 0) { countdown = i; } >+// Sets the countdown to the terminal value -1 >+inline void UnsetCountdown() { SetCountdown(-1); } >+ >+void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false); >+ >+testing::AssertionResult FailureMessage(const TestException& e, >+ int countdown) noexcept; >+ >+struct TrackedAddress { >+ bool is_alive; >+ std::string description; >+}; >+ >+// Inspects the constructions and destructions of anything inheriting from >+// TrackedObject. This allows us to safely "leak" TrackedObjects, as >+// ConstructorTracker will destroy everything left over in its destructor. >+class ConstructorTracker { >+ public: >+ explicit ConstructorTracker(int count) : countdown_(count) { >+ assert(current_tracker_instance_ == nullptr); >+ current_tracker_instance_ = this; >+ } >+ >+ ~ConstructorTracker() { >+ assert(current_tracker_instance_ == this); >+ current_tracker_instance_ = nullptr; >+ >+ for (auto& it : address_map_) { >+ void* address = it.first; >+ TrackedAddress& tracked_address = it.second; >+ if (tracked_address.is_alive) { >+ ADD_FAILURE() << "Object at address " << address >+ << " with countdown of " << countdown_ >+ << " was not destroyed [" << tracked_address.description >+ << "]"; >+ } >+ } >+ } >+ >+ static void ObjectConstructed(void* address, std::string description) { >+ if (!CurrentlyTracking()) return; >+ >+ TrackedAddress& tracked_address = >+ current_tracker_instance_->address_map_[address]; >+ if (tracked_address.is_alive) { >+ ADD_FAILURE() << "Object at address " << address << " with countdown of " >+ << current_tracker_instance_->countdown_ >+ << " was re-constructed. Previously: [" >+ << tracked_address.description << "] Now: [" << description >+ << "]"; >+ } >+ tracked_address = {true, std::move(description)}; >+ } >+ >+ static void ObjectDestructed(void* address) { >+ if (!CurrentlyTracking()) return; >+ >+ auto it = current_tracker_instance_->address_map_.find(address); >+ // Not tracked. Ignore. >+ if (it == current_tracker_instance_->address_map_.end()) return; >+ >+ TrackedAddress& tracked_address = it->second; >+ if (!tracked_address.is_alive) { >+ ADD_FAILURE() << "Object at address " << address << " with countdown of " >+ << current_tracker_instance_->countdown_ >+ << " was re-destroyed or created prior to construction " >+ << "tracking [" << tracked_address.description << "]"; >+ } >+ tracked_address.is_alive = false; >+ } >+ >+ private: >+ static bool CurrentlyTracking() { >+ return current_tracker_instance_ != nullptr; >+ } >+ >+ std::unordered_map<void*, TrackedAddress> address_map_; >+ int countdown_; >+ >+ static ConstructorTracker* current_tracker_instance_; >+}; >+ >+class TrackedObject { >+ public: >+ TrackedObject(const TrackedObject&) = delete; >+ TrackedObject(TrackedObject&&) = delete; >+ >+ protected: >+ explicit TrackedObject(std::string description) { >+ ConstructorTracker::ObjectConstructed(this, std::move(description)); >+ } >+ >+ ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); } >+}; >+ >+template <typename Factory, typename Operation, typename Invariant> >+absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl( >+ const Factory& factory, const Operation& operation, int count, >+ const Invariant& invariant) { >+ auto t_ptr = factory(); >+ absl::optional<testing::AssertionResult> current_res; >+ SetCountdown(count); >+ try { >+ operation(t_ptr.get()); >+ } catch (const exceptions_internal::TestException& e) { >+ current_res.emplace(invariant(t_ptr.get())); >+ if (!current_res.value()) { >+ *current_res << e.what() << " failed invariant check"; >+ } >+ } >+ UnsetCountdown(); >+ return current_res; >+} >+ >+template <typename Factory, typename Operation> >+absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl( >+ const Factory& factory, const Operation& operation, int count, >+ StrongGuaranteeTagType) { >+ using TPtr = typename decltype(factory())::pointer; >+ auto t_is_strong = [&](TPtr t) { return *t == *factory(); }; >+ return TestSingleInvariantAtCountdownImpl(factory, operation, count, >+ t_is_strong); >+} >+ >+template <typename Factory, typename Operation, typename Invariant> >+int TestSingleInvariantAtCountdown( >+ const Factory& factory, const Operation& operation, int count, >+ const Invariant& invariant, >+ absl::optional<testing::AssertionResult>* reduced_res) { >+ // If reduced_res is empty, it means the current call to >+ // TestSingleInvariantAtCountdown(...) is the first test being run so we do >+ // want to run it. Alternatively, if it's not empty (meaning a previous test >+ // has run) we want to check if it passed. If the previous test did pass, we >+ // want to contine running tests so we do want to run the current one. If it >+ // failed, we want to short circuit so as not to overwrite the AssertionResult >+ // output. If that's the case, we do not run the current test and instead we >+ // simply return. >+ if (!reduced_res->has_value() || reduced_res->value()) { >+ *reduced_res = TestSingleInvariantAtCountdownImpl(factory, operation, count, >+ invariant); >+ } >+ return 0; >+} >+ >+template <typename Factory, typename Operation, typename... Invariants> >+inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown( >+ const Factory& factory, const Operation& operation, int count, >+ const Invariants&... invariants) { >+ absl::optional<testing::AssertionResult> reduced_res; >+ >+ // Run each checker, short circuiting after the first failure >+ int dummy[] = { >+ 0, (TestSingleInvariantAtCountdown(factory, operation, count, invariants, >+ &reduced_res))...}; >+ static_cast<void>(dummy); >+ return reduced_res; >+} >+ >+} // namespace exceptions_internal >+ >+extern exceptions_internal::NoThrowTag nothrow_ctor; >+ >+extern exceptions_internal::StrongGuaranteeTagType strong_guarantee; >+ >+// A test class which is convertible to bool. The conversion can be >+// instrumented to throw at a controlled time. >+class ThrowingBool { >+ public: >+ ThrowingBool(bool b) noexcept : b_(b) {} // NOLINT(runtime/explicit) >+ operator bool() const { // NOLINT >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return b_; >+ } >+ >+ private: >+ bool b_; >+}; >+ >+/* >+ * Configuration enum for the ThrowingValue type that defines behavior for the >+ * lifetime of the instance. Use testing::nothrow_ctor to prevent the integer >+ * constructor from throwing. >+ * >+ * kEverythingThrows: Every operation can throw an exception >+ * kNoThrowCopy: Copy construction and copy assignment will not throw >+ * kNoThrowMove: Move construction and move assignment will not throw >+ * kNoThrowNew: Overloaded operators new and new[] will not throw >+ */ >+enum class TypeSpec { >+ kEverythingThrows = 0, >+ kNoThrowCopy = 1, >+ kNoThrowMove = 1 << 1, >+ kNoThrowNew = 1 << 2, >+}; >+ >+/* >+ * A testing class instrumented to throw an exception at a controlled time. >+ * >+ * ThrowingValue implements a slightly relaxed version of the Regular concept -- >+ * that is it's a value type with the expected semantics. It also implements >+ * arithmetic operations. It doesn't implement member and pointer operators >+ * like operator-> or operator[]. >+ * >+ * ThrowingValue can be instrumented to have certain operations be noexcept by >+ * using compile-time bitfield template arguments. That is, to make an >+ * ThrowingValue which has noexcept move construction/assignment and noexcept >+ * copy construction/assignment, use the following: >+ * ThrowingValue<testing::kNoThrowMove | testing::kNoThrowCopy> my_thrwr{val}; >+ */ >+template <TypeSpec Spec = TypeSpec::kEverythingThrows> >+class ThrowingValue : private exceptions_internal::TrackedObject { >+ static constexpr bool IsSpecified(TypeSpec spec) { >+ return static_cast<bool>(Spec & spec); >+ } >+ >+ static constexpr int kDefaultValue = 0; >+ static constexpr int kBadValue = 938550620; >+ >+ public: >+ ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ = kDefaultValue; >+ } >+ >+ ThrowingValue(const ThrowingValue& other) noexcept( >+ IsSpecified(TypeSpec::kNoThrowCopy)) >+ : TrackedObject(GetInstanceString(other.dummy_)) { >+ if (!IsSpecified(TypeSpec::kNoThrowCopy)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ } >+ dummy_ = other.dummy_; >+ } >+ >+ ThrowingValue(ThrowingValue&& other) noexcept( >+ IsSpecified(TypeSpec::kNoThrowMove)) >+ : TrackedObject(GetInstanceString(other.dummy_)) { >+ if (!IsSpecified(TypeSpec::kNoThrowMove)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ } >+ dummy_ = other.dummy_; >+ } >+ >+ explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ = i; >+ } >+ >+ ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept >+ : TrackedObject(GetInstanceString(i)), dummy_(i) {} >+ >+ // absl expects nothrow destructors >+ ~ThrowingValue() noexcept = default; >+ >+ ThrowingValue& operator=(const ThrowingValue& other) noexcept( >+ IsSpecified(TypeSpec::kNoThrowCopy)) { >+ dummy_ = kBadValue; >+ if (!IsSpecified(TypeSpec::kNoThrowCopy)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ } >+ dummy_ = other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator=(ThrowingValue&& other) noexcept( >+ IsSpecified(TypeSpec::kNoThrowMove)) { >+ dummy_ = kBadValue; >+ if (!IsSpecified(TypeSpec::kNoThrowMove)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ } >+ dummy_ = other.dummy_; >+ return *this; >+ } >+ >+ // Arithmetic Operators >+ ThrowingValue operator+(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator+() const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator-(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator-() const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(-dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue& operator++() { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ ++dummy_; >+ return *this; >+ } >+ >+ ThrowingValue operator++(int) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ auto out = ThrowingValue(dummy_, nothrow_ctor); >+ ++dummy_; >+ return out; >+ } >+ >+ ThrowingValue& operator--() { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ --dummy_; >+ return *this; >+ } >+ >+ ThrowingValue operator--(int) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ auto out = ThrowingValue(dummy_, nothrow_ctor); >+ --dummy_; >+ return out; >+ } >+ >+ ThrowingValue operator*(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator/(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator%(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator<<(int shift) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ << shift, nothrow_ctor); >+ } >+ >+ ThrowingValue operator>>(int shift) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ >> shift, nothrow_ctor); >+ } >+ >+ // Comparison Operators >+ // NOTE: We use `ThrowingBool` instead of `bool` because most STL >+ // types/containers requires T to be convertible to bool. >+ friend ThrowingBool operator==(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ == b.dummy_; >+ } >+ friend ThrowingBool operator!=(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ != b.dummy_; >+ } >+ friend ThrowingBool operator<(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ < b.dummy_; >+ } >+ friend ThrowingBool operator<=(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ <= b.dummy_; >+ } >+ friend ThrowingBool operator>(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ > b.dummy_; >+ } >+ friend ThrowingBool operator>=(const ThrowingValue& a, >+ const ThrowingValue& b) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return a.dummy_ >= b.dummy_; >+ } >+ >+ // Logical Operators >+ ThrowingBool operator!() const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return !dummy_; >+ } >+ >+ ThrowingBool operator&&(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return dummy_ && other.dummy_; >+ } >+ >+ ThrowingBool operator||(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return dummy_ || other.dummy_; >+ } >+ >+ // Bitwise Logical Operators >+ ThrowingValue operator~() const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(~dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator&(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator|(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor); >+ } >+ >+ ThrowingValue operator^(const ThrowingValue& other) const { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor); >+ } >+ >+ // Compound Assignment operators >+ ThrowingValue& operator+=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ += other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator-=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ -= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator*=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ *= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator/=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ /= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator%=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ %= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator&=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ &= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator|=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ |= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator^=(const ThrowingValue& other) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ ^= other.dummy_; >+ return *this; >+ } >+ >+ ThrowingValue& operator<<=(int shift) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ <<= shift; >+ return *this; >+ } >+ >+ ThrowingValue& operator>>=(int shift) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ >>= shift; >+ return *this; >+ } >+ >+ // Pointer operators >+ void operator&() const = delete; // NOLINT(runtime/operator) >+ >+ // Stream operators >+ friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return os << GetInstanceString(tv.dummy_); >+ } >+ >+ friend std::istream& operator>>(std::istream& is, const ThrowingValue&) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ return is; >+ } >+ >+ // Memory management operators >+ // Args.. allows us to overload regular and placement new in one shot >+ template <typename... Args> >+ static void* operator new(size_t s, Args&&... args) noexcept( >+ IsSpecified(TypeSpec::kNoThrowNew)) { >+ if (!IsSpecified(TypeSpec::kNoThrowNew)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); >+ } >+ return ::operator new(s, std::forward<Args>(args)...); >+ } >+ >+ template <typename... Args> >+ static void* operator new[](size_t s, Args&&... args) noexcept( >+ IsSpecified(TypeSpec::kNoThrowNew)) { >+ if (!IsSpecified(TypeSpec::kNoThrowNew)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); >+ } >+ return ::operator new[](s, std::forward<Args>(args)...); >+ } >+ >+ // Abseil doesn't support throwing overloaded operator delete. These are >+ // provided so a throwing operator-new can clean up after itself. >+ // >+ // We provide both regular and templated operator delete because if only the >+ // templated version is provided as we did with operator new, the compiler has >+ // no way of knowing which overload of operator delete to call. See >+ // http://en.cppreference.com/w/cpp/memory/new/operator_delete and >+ // http://en.cppreference.com/w/cpp/language/delete for the gory details. >+ void operator delete(void* p) noexcept { ::operator delete(p); } >+ >+ template <typename... Args> >+ void operator delete(void* p, Args&&... args) noexcept { >+ ::operator delete(p, std::forward<Args>(args)...); >+ } >+ >+ void operator delete[](void* p) noexcept { return ::operator delete[](p); } >+ >+ template <typename... Args> >+ void operator delete[](void* p, Args&&... args) noexcept { >+ return ::operator delete[](p, std::forward<Args>(args)...); >+ } >+ >+ // Non-standard access to the actual contained value. No need for this to >+ // throw. >+ int& Get() noexcept { return dummy_; } >+ const int& Get() const noexcept { return dummy_; } >+ >+ private: >+ static std::string GetInstanceString(int dummy) { >+ return absl::StrCat("ThrowingValue<", >+ exceptions_internal::GetSpecString(Spec), ">(", dummy, >+ ")"); >+ } >+ >+ int dummy_; >+}; >+// While not having to do with exceptions, explicitly delete comma operator, to >+// make sure we don't use it on user-supplied types. >+template <TypeSpec Spec, typename T> >+void operator,(const ThrowingValue<Spec>&, T&&) = delete; >+template <TypeSpec Spec, typename T> >+void operator,(T&&, const ThrowingValue<Spec>&) = delete; >+ >+/* >+ * Configuration enum for the ThrowingAllocator type that defines behavior for >+ * the lifetime of the instance. >+ * >+ * kEverythingThrows: Calls to the member functions may throw >+ * kNoThrowAllocate: Calls to the member functions will not throw >+ */ >+enum class AllocSpec { >+ kEverythingThrows = 0, >+ kNoThrowAllocate = 1, >+}; >+ >+/* >+ * An allocator type which is instrumented to throw at a controlled time, or not >+ * to throw, using AllocSpec. The supported settings are the default of every >+ * function which is allowed to throw in a conforming allocator possibly >+ * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS >+ * configuration macro. >+ */ >+template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows> >+class ThrowingAllocator : private exceptions_internal::TrackedObject { >+ static constexpr bool IsSpecified(AllocSpec spec) { >+ return static_cast<bool>(Spec & spec); >+ } >+ >+ public: >+ using pointer = T*; >+ using const_pointer = const T*; >+ using reference = T&; >+ using const_reference = const T&; >+ using void_pointer = void*; >+ using const_void_pointer = const void*; >+ using value_type = T; >+ using size_type = size_t; >+ using difference_type = ptrdiff_t; >+ >+ using is_nothrow = >+ std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>; >+ using propagate_on_container_copy_assignment = std::true_type; >+ using propagate_on_container_move_assignment = std::true_type; >+ using propagate_on_container_swap = std::true_type; >+ using is_always_equal = std::false_type; >+ >+ ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) { >+ exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); >+ dummy_ = std::make_shared<const int>(next_id_++); >+ } >+ >+ template <typename U> >+ ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept // NOLINT >+ : TrackedObject(GetInstanceString(*other.State())), >+ dummy_(other.State()) {} >+ >+ // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of >+ // allocator shall not exit via an exception, thus they are marked noexcept. >+ ThrowingAllocator(const ThrowingAllocator& other) noexcept >+ : TrackedObject(GetInstanceString(*other.State())), >+ dummy_(other.State()) {} >+ >+ template <typename U> >+ ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept // NOLINT >+ : TrackedObject(GetInstanceString(*other.State())), >+ dummy_(std::move(other.State())) {} >+ >+ ThrowingAllocator(ThrowingAllocator&& other) noexcept >+ : TrackedObject(GetInstanceString(*other.State())), >+ dummy_(std::move(other.State())) {} >+ >+ ~ThrowingAllocator() noexcept = default; >+ >+ ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept { >+ dummy_ = other.State(); >+ return *this; >+ } >+ >+ template <typename U> >+ ThrowingAllocator& operator=( >+ const ThrowingAllocator<U, Spec>& other) noexcept { >+ dummy_ = other.State(); >+ return *this; >+ } >+ >+ template <typename U> >+ ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept { >+ dummy_ = std::move(other.State()); >+ return *this; >+ } >+ >+ template <typename U> >+ struct rebind { >+ using other = ThrowingAllocator<U, Spec>; >+ }; >+ >+ pointer allocate(size_type n) noexcept( >+ IsSpecified(AllocSpec::kNoThrowAllocate)) { >+ ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); >+ return static_cast<pointer>(::operator new(n * sizeof(T))); >+ } >+ >+ pointer allocate(size_type n, const_void_pointer) noexcept( >+ IsSpecified(AllocSpec::kNoThrowAllocate)) { >+ return allocate(n); >+ } >+ >+ void deallocate(pointer ptr, size_type) noexcept { >+ ReadState(); >+ ::operator delete(static_cast<void*>(ptr)); >+ } >+ >+ template <typename U, typename... Args> >+ void construct(U* ptr, Args&&... args) noexcept( >+ IsSpecified(AllocSpec::kNoThrowAllocate)) { >+ ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); >+ ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...); >+ } >+ >+ template <typename U> >+ void destroy(U* p) noexcept { >+ ReadState(); >+ p->~U(); >+ } >+ >+ size_type max_size() const noexcept { >+ return std::numeric_limits<difference_type>::max() / sizeof(value_type); >+ } >+ >+ ThrowingAllocator select_on_container_copy_construction() noexcept( >+ IsSpecified(AllocSpec::kNoThrowAllocate)) { >+ auto& out = *this; >+ ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); >+ return out; >+ } >+ >+ template <typename U> >+ bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept { >+ return dummy_ == other.dummy_; >+ } >+ >+ template <typename U> >+ bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept { >+ return dummy_ != other.dummy_; >+ } >+ >+ template <typename, AllocSpec> >+ friend class ThrowingAllocator; >+ >+ private: >+ static std::string GetInstanceString(int dummy) { >+ return absl::StrCat("ThrowingAllocator<", >+ exceptions_internal::GetSpecString(Spec), ">(", dummy, >+ ")"); >+ } >+ >+ const std::shared_ptr<const int>& State() const { return dummy_; } >+ std::shared_ptr<const int>& State() { return dummy_; } >+ >+ void ReadState() { >+ // we know that this will never be true, but the compiler doesn't, so this >+ // should safely force a read of the value. >+ if (*dummy_ < 0) std::abort(); >+ } >+ >+ void ReadStateAndMaybeThrow(absl::string_view msg) const { >+ if (!IsSpecified(AllocSpec::kNoThrowAllocate)) { >+ exceptions_internal::MaybeThrow( >+ absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg)); >+ } >+ } >+ >+ static int next_id_; >+ std::shared_ptr<const int> dummy_; >+}; >+ >+template <typename T, AllocSpec Spec> >+int ThrowingAllocator<T, Spec>::next_id_ = 0; >+ >+// Tests for resource leaks by attempting to construct a T using args repeatedly >+// until successful, using the countdown method. Side effects can then be >+// tested for resource leaks. >+template <typename T, typename... Args> >+void TestThrowingCtor(Args&&... args) { >+ struct Cleanup { >+ ~Cleanup() { exceptions_internal::UnsetCountdown(); } >+ } c; >+ for (int count = 0;; ++count) { >+ exceptions_internal::ConstructorTracker ct(count); >+ exceptions_internal::SetCountdown(count); >+ try { >+ T temp(std::forward<Args>(args)...); >+ static_cast<void>(temp); >+ break; >+ } catch (const exceptions_internal::TestException&) { >+ } >+ } >+} >+ >+// Tests the nothrow guarantee of the provided nullary operation. If the an >+// exception is thrown, the result will be AssertionFailure(). Otherwise, it >+// will be AssertionSuccess(). >+template <typename Operation> >+testing::AssertionResult TestNothrowOp(const Operation& operation) { >+ struct Cleanup { >+ Cleanup() { exceptions_internal::SetCountdown(); } >+ ~Cleanup() { exceptions_internal::UnsetCountdown(); } >+ } c; >+ try { >+ operation(); >+ return testing::AssertionSuccess(); >+ } catch (exceptions_internal::TestException) { >+ return testing::AssertionFailure() >+ << "TestException thrown during call to operation() when nothrow " >+ "guarantee was expected."; >+ } catch (...) { >+ return testing::AssertionFailure() >+ << "Unknown exception thrown during call to operation() when " >+ "nothrow guarantee was expected."; >+ } >+} >+ >+namespace exceptions_internal { >+ >+// Dummy struct for ExceptionSafetyTester<> partial state. >+struct UninitializedT {}; >+ >+template <typename T> >+class DefaultFactory { >+ public: >+ explicit DefaultFactory(const T& t) : t_(t) {} >+ std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); } >+ >+ private: >+ T t_; >+}; >+ >+template <size_t LazyInvariantsCount, typename LazyFactory, >+ typename LazyOperation> >+using EnableIfTestable = typename absl::enable_if_t< >+ LazyInvariantsCount != 0 && >+ !std::is_same<LazyFactory, UninitializedT>::value && >+ !std::is_same<LazyOperation, UninitializedT>::value>; >+ >+template <typename Factory = UninitializedT, >+ typename Operation = UninitializedT, typename... Invariants> >+class ExceptionSafetyTester; >+ >+} // namespace exceptions_internal >+ >+exceptions_internal::ExceptionSafetyTester<> MakeExceptionSafetyTester(); >+ >+namespace exceptions_internal { >+ >+/* >+ * Builds a tester object that tests if performing a operation on a T follows >+ * exception safety guarantees. Verification is done via invariant assertion >+ * callbacks applied to T instances post-throw. >+ * >+ * Template parameters for ExceptionSafetyTester: >+ * >+ * - Factory: The factory object (passed in via tester.WithFactory(...) or >+ * tester.WithInitialValue(...)) must be invocable with the signature >+ * `std::unique_ptr<T> operator()() const` where T is the type being tested. >+ * It is used for reliably creating identical T instances to test on. >+ * >+ * - Operation: The operation object (passsed in via tester.WithOperation(...) >+ * or tester.Test(...)) must be invocable with the signature >+ * `void operator()(T*) const` where T is the type being tested. It is used >+ * for performing steps on a T instance that may throw and that need to be >+ * checked for exception safety. Each call to the operation will receive a >+ * fresh T instance so it's free to modify and destroy the T instances as it >+ * pleases. >+ * >+ * - Invariants...: The invariant assertion callback objects (passed in via >+ * tester.WithInvariants(...)) must be invocable with the signature >+ * `testing::AssertionResult operator()(T*) const` where T is the type being >+ * tested. Invariant assertion callbacks are provided T instances post-throw. >+ * They must return testing::AssertionSuccess when the type invariants of the >+ * provided T instance hold. If the type invariants of the T instance do not >+ * hold, they must return testing::AssertionFailure. Execution order of >+ * Invariants... is unspecified. They will each individually get a fresh T >+ * instance so they are free to modify and destroy the T instances as they >+ * please. >+ */ >+template <typename Factory, typename Operation, typename... Invariants> >+class ExceptionSafetyTester { >+ public: >+ /* >+ * Returns a new ExceptionSafetyTester with an included T factory based on the >+ * provided T instance. The existing factory will not be included in the newly >+ * created tester instance. The created factory returns a new T instance by >+ * copy-constructing the provided const T& t. >+ * >+ * Preconditions for tester.WithInitialValue(const T& t): >+ * >+ * - The const T& t object must be copy-constructible where T is the type >+ * being tested. For non-copy-constructible objects, use the method >+ * tester.WithFactory(...). >+ */ >+ template <typename T> >+ ExceptionSafetyTester<DefaultFactory<T>, Operation, Invariants...> >+ WithInitialValue(const T& t) const { >+ return WithFactory(DefaultFactory<T>(t)); >+ } >+ >+ /* >+ * Returns a new ExceptionSafetyTester with the provided T factory included. >+ * The existing factory will not be included in the newly-created tester >+ * instance. This method is intended for use with types lacking a copy >+ * constructor. Types that can be copy-constructed should instead use the >+ * method tester.WithInitialValue(...). >+ */ >+ template <typename NewFactory> >+ ExceptionSafetyTester<absl::decay_t<NewFactory>, Operation, Invariants...> >+ WithFactory(const NewFactory& new_factory) const { >+ return {new_factory, operation_, invariants_}; >+ } >+ >+ /* >+ * Returns a new ExceptionSafetyTester with the provided testable operation >+ * included. The existing operation will not be included in the newly created >+ * tester. >+ */ >+ template <typename NewOperation> >+ ExceptionSafetyTester<Factory, absl::decay_t<NewOperation>, Invariants...> >+ WithOperation(const NewOperation& new_operation) const { >+ return {factory_, new_operation, invariants_}; >+ } >+ >+ /* >+ * Returns a new ExceptionSafetyTester with the provided MoreInvariants... >+ * combined with the Invariants... that were already included in the instance >+ * on which the method was called. Invariants... cannot be removed or replaced >+ * once added to an ExceptionSafetyTester instance. A fresh object must be >+ * created in order to get an empty Invariants... list. >+ * >+ * In addition to passing in custom invariant assertion callbacks, this method >+ * accepts `testing::strong_guarantee` as an argument which checks T instances >+ * post-throw against freshly created T instances via operator== to verify >+ * that any state changes made during the execution of the operation were >+ * properly rolled back. >+ */ >+ template <typename... MoreInvariants> >+ ExceptionSafetyTester<Factory, Operation, Invariants..., >+ absl::decay_t<MoreInvariants>...> >+ WithInvariants(const MoreInvariants&... more_invariants) const { >+ return {factory_, operation_, >+ std::tuple_cat(invariants_, >+ std::tuple<absl::decay_t<MoreInvariants>...>( >+ more_invariants...))}; >+ } >+ >+ /* >+ * Returns a testing::AssertionResult that is the reduced result of the >+ * exception safety algorithm. The algorithm short circuits and returns >+ * AssertionFailure after the first invariant callback returns an >+ * AssertionFailure. Otherwise, if all invariant callbacks return an >+ * AssertionSuccess, the reduced result is AssertionSuccess. >+ * >+ * The passed-in testable operation will not be saved in a new tester instance >+ * nor will it modify/replace the existing tester instance. This is useful >+ * when each operation being tested is unique and does not need to be reused. >+ * >+ * Preconditions for tester.Test(const NewOperation& new_operation): >+ * >+ * - May only be called after at least one invariant assertion callback and a >+ * factory or initial value have been provided. >+ */ >+ template < >+ typename NewOperation, >+ typename = EnableIfTestable<sizeof...(Invariants), Factory, NewOperation>> >+ testing::AssertionResult Test(const NewOperation& new_operation) const { >+ return TestImpl(new_operation, absl::index_sequence_for<Invariants...>()); >+ } >+ >+ /* >+ * Returns a testing::AssertionResult that is the reduced result of the >+ * exception safety algorithm. The algorithm short circuits and returns >+ * AssertionFailure after the first invariant callback returns an >+ * AssertionFailure. Otherwise, if all invariant callbacks return an >+ * AssertionSuccess, the reduced result is AssertionSuccess. >+ * >+ * Preconditions for tester.Test(): >+ * >+ * - May only be called after at least one invariant assertion callback, a >+ * factory or initial value and a testable operation have been provided. >+ */ >+ template <typename LazyOperation = Operation, >+ typename = >+ EnableIfTestable<sizeof...(Invariants), Factory, LazyOperation>> >+ testing::AssertionResult Test() const { >+ return TestImpl(operation_, absl::index_sequence_for<Invariants...>()); >+ } >+ >+ private: >+ template <typename, typename, typename...> >+ friend class ExceptionSafetyTester; >+ >+ friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester(); >+ >+ ExceptionSafetyTester() {} >+ >+ ExceptionSafetyTester(const Factory& f, const Operation& o, >+ const std::tuple<Invariants...>& i) >+ : factory_(f), operation_(o), invariants_(i) {} >+ >+ template <typename SelectedOperation, size_t... Indices> >+ testing::AssertionResult TestImpl(const SelectedOperation& selected_operation, >+ absl::index_sequence<Indices...>) const { >+ // Starting from 0 and counting upwards until one of the exit conditions is >+ // hit... >+ for (int count = 0;; ++count) { >+ exceptions_internal::ConstructorTracker ct(count); >+ >+ // Run the full exception safety test algorithm for the current countdown >+ auto reduced_res = >+ TestAllInvariantsAtCountdown(factory_, selected_operation, count, >+ std::get<Indices>(invariants_)...); >+ // If there is no value in the optional, no invariants were run because no >+ // exception was thrown. This means that the test is complete and the loop >+ // can exit successfully. >+ if (!reduced_res.has_value()) { >+ return testing::AssertionSuccess(); >+ } >+ // If the optional is not empty and the value is falsy, an invariant check >+ // failed so the test must exit to propegate the failure. >+ if (!reduced_res.value()) { >+ return reduced_res.value(); >+ } >+ // If the optional is not empty and the value is not falsy, it means >+ // exceptions were thrown but the invariants passed so the test must >+ // continue to run. >+ } >+ } >+ >+ Factory factory_; >+ Operation operation_; >+ std::tuple<Invariants...> invariants_; >+}; >+ >+} // namespace exceptions_internal >+ >+/* >+ * Constructs an empty ExceptionSafetyTester. All ExceptionSafetyTester >+ * objects are immutable and all With[thing] mutation methods return new >+ * instances of ExceptionSafetyTester. >+ * >+ * In order to test a T for exception safety, a factory for that T, a testable >+ * operation, and at least one invariant callback returning an assertion >+ * result must be applied using the respective methods. >+ */ >+inline exceptions_internal::ExceptionSafetyTester<> >+MakeExceptionSafetyTester() { >+ return {}; >+} >+ >+} // namespace testing >+ >+#endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_testing.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_testing.h >new file mode 100644 >index 00000000000..0cf7918e4c6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/exception_testing.h >@@ -0,0 +1,42 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Testing utilities for ABSL types which throw exceptions. >+ >+#ifndef ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ >+#define ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+ >+// ABSL_BASE_INTERNAL_EXPECT_FAIL tests either for a specified thrown exception >+// if exceptions are enabled, or for death with a specified text in the error >+// message >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ >+ EXPECT_THROW(expr, exception_t) >+ >+#elif defined(__ANDROID__) >+// Android asserts do not log anywhere that gtest can currently inspect. >+// So we expect exit, but cannot match the message. >+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ >+ EXPECT_DEATH(expr, ".*") >+#else >+#define ABSL_BASE_INTERNAL_EXPECT_FAIL(expr, exception_t, text) \ >+ EXPECT_DEATH_IF_SUPPORTED(expr, text) >+ >+#endif >+ >+#endif // ABSL_BASE_INTERNAL_EXCEPTION_TESTING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/hide_ptr.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/hide_ptr.h >new file mode 100644 >index 00000000000..45cf438912c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/hide_ptr.h >@@ -0,0 +1,47 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INTERNAL_HIDE_PTR_H_ >+#define ABSL_BASE_INTERNAL_HIDE_PTR_H_ >+ >+#include <cstdint> >+ >+namespace absl { >+namespace base_internal { >+ >+// Arbitrary value with high bits set. Xor'ing with it is unlikely >+// to map one valid pointer to another valid pointer. >+constexpr uintptr_t HideMask() { >+ return (uintptr_t{0xF03A5F7BU} << (sizeof(uintptr_t) - 4) * 8) | 0xF03A5F7BU; >+} >+ >+// Hide a pointer from the leak checker. For internal use only. >+// Differs from absl::IgnoreLeak(ptr) in that absl::IgnoreLeak(ptr) causes ptr >+// and all objects reachable from ptr to be ignored by the leak checker. >+template <class T> >+inline uintptr_t HidePtr(T* ptr) { >+ return reinterpret_cast<uintptr_t>(ptr) ^ HideMask(); >+} >+ >+// Return a pointer that has been hidden from the leak checker. >+// For internal use only. >+template <class T> >+inline T* UnhidePtr(uintptr_t hidden) { >+ return reinterpret_cast<T*>(hidden ^ HideMask()); >+} >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_HIDE_PTR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/identity.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/identity.h >new file mode 100644 >index 00000000000..a1a5d70a84d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/identity.h >@@ -0,0 +1,33 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_IDENTITY_H_ >+#define ABSL_BASE_INTERNAL_IDENTITY_H_ >+ >+namespace absl { >+namespace internal { >+ >+template <typename T> >+struct identity { >+ typedef T type; >+}; >+ >+template <typename T> >+using identity_t = typename identity<T>::type; >+ >+} // namespace internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_IDENTITY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable.h >new file mode 100644 >index 00000000000..f7bb8c56525 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable.h >@@ -0,0 +1,107 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ >+#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ >+ >+#include <type_traits> >+ >+#include "absl/base/internal/identity.h" >+ >+// File: >+// This file define a macro that allows the creation of or emulation of C++17 >+// inline variables based on whether or not the feature is supported. >+ >+//////////////////////////////////////////////////////////////////////////////// >+// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) >+// >+// Description: >+// Expands to the equivalent of an inline constexpr instance of the specified >+// `type` and `name`, initialized to the value `init`. If the compiler being >+// used is detected as supporting actual inline variables as a language >+// feature, then the macro expands to an actual inline variable definition. >+// >+// Requires: >+// `type` is a type that is usable in an extern variable declaration. >+// >+// Requires: `name` is a valid identifier >+// >+// Requires: >+// `init` is an expression that can be used in the following definition: >+// constexpr type name = init; >+// >+// Usage: >+// >+// // Equivalent to: `inline constexpr size_t variant_npos = -1;` >+// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); >+// >+// Differences in implementation: >+// For a direct, language-level inline variable, decltype(name) will be the >+// type that was specified along with const qualification, whereas for >+// emulated inline variables, decltype(name) may be different (in practice >+// it will likely be a reference type). >+//////////////////////////////////////////////////////////////////////////////// >+ >+#ifdef __cpp_inline_variables >+ >+// Clang's -Wmissing-variable-declarations option erroneously warned that >+// inline constexpr objects need to be pre-declared. This has now been fixed, >+// but we will need to support this workaround for people building with older >+// versions of clang. >+// >+// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862 >+// >+// Note: >+// identity_t is used here so that the const and name are in the >+// appropriate place for pointer types, reference types, function pointer >+// types, etc.. >+#if defined(__clang__) >+#define ABSL_INTERNAL_EXTERN_DECL(type, name) \ >+ extern const ::absl::internal::identity_t<type> name; >+#else // Otherwise, just define the macro to do nothing. >+#define ABSL_INTERNAL_EXTERN_DECL(type, name) >+#endif // defined(__clang__) >+ >+// See above comment at top of file for details. >+#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \ >+ ABSL_INTERNAL_EXTERN_DECL(type, name) \ >+ inline constexpr ::absl::internal::identity_t<type> name = init >+ >+#else >+ >+// See above comment at top of file for details. >+// >+// Note: >+// identity_t is used here so that the const and name are in the >+// appropriate place for pointer types, reference types, function pointer >+// types, etc.. >+#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \ >+ template <class /*AbslInternalDummy*/ = void> \ >+ struct AbslInternalInlineVariableHolder##name { \ >+ static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \ >+ }; \ >+ \ >+ template <class AbslInternalDummy> \ >+ constexpr ::absl::internal::identity_t<var_type> \ >+ AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \ >+ \ >+ static constexpr const ::absl::internal::identity_t<var_type>& \ >+ name = /* NOLINT */ \ >+ AbslInternalInlineVariableHolder##name<>::kInstance; \ >+ static_assert(sizeof(void (*)(decltype(name))) != 0, \ >+ "Silence unused variable warnings.") >+ >+#endif // __cpp_inline_variables >+ >+#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h >new file mode 100644 >index 00000000000..a0dd2bb28a4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/inline_variable_testing.h >@@ -0,0 +1,44 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_ >+#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_ >+ >+#include "absl/base/internal/inline_variable.h" >+ >+namespace absl { >+namespace inline_variable_testing_internal { >+ >+struct Foo { >+ int value = 5; >+}; >+ >+ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {}); >+ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {}); >+ >+ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5); >+ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5); >+ >+ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr); >+ >+const Foo& get_foo_a(); >+const Foo& get_foo_b(); >+ >+const int& get_int_a(); >+const int& get_int_b(); >+ >+} // namespace inline_variable_testing_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/invoke.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/invoke.h >new file mode 100644 >index 00000000000..8c3f4f60637 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/invoke.h >@@ -0,0 +1,188 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// absl::base_internal::Invoke(f, args...) is an implementation of >+// INVOKE(f, args...) from section [func.require] of the C++ standard. >+// >+// [func.require] >+// Define INVOKE (f, t1, t2, ..., tN) as follows: >+// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T >+// and t1 is an object of type T or a reference to an object of type T or a >+// reference to an object of a type derived from T; >+// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a >+// class T and t1 is not one of the types described in the previous item; >+// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is >+// an object of type T or a reference to an object of type T or a reference >+// to an object of a type derived from T; >+// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 >+// is not one of the types described in the previous item; >+// 5. f(t1, t2, ..., tN) in all other cases. >+// >+// The implementation is SFINAE-friendly: substitution failure within Invoke() >+// isn't an error. >+ >+#ifndef ABSL_BASE_INTERNAL_INVOKE_H_ >+#define ABSL_BASE_INTERNAL_INVOKE_H_ >+ >+#include <algorithm> >+#include <type_traits> >+#include <utility> >+ >+// The following code is internal implementation detail. See the comment at the >+// top of this file for the API documentation. >+ >+namespace absl { >+namespace base_internal { >+ >+// The five classes below each implement one of the clauses from the definition >+// of INVOKE. The inner class template Accept<F, Args...> checks whether the >+// clause is applicable; static function template Invoke(f, args...) does the >+// invocation. >+// >+// By separating the clause selection logic from invocation we make sure that >+// Invoke() does exactly what the standard says. >+ >+template <typename Derived> >+struct StrippedAccept { >+ template <typename... Args> >+ struct Accept : Derived::template AcceptImpl<typename std::remove_cv< >+ typename std::remove_reference<Args>::type>::type...> {}; >+}; >+ >+// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T >+// and t1 is an object of type T or a reference to an object of type T or a >+// reference to an object of a type derived from T. >+struct MemFunAndRef : StrippedAccept<MemFunAndRef> { >+ template <typename... Args> >+ struct AcceptImpl : std::false_type {}; >+ >+ template <typename R, typename C, typename... Params, typename Obj, >+ typename... Args> >+ struct AcceptImpl<R (C::*)(Params...), Obj, Args...> >+ : std::is_base_of<C, Obj> {}; >+ >+ template <typename R, typename C, typename... Params, typename Obj, >+ typename... Args> >+ struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...> >+ : std::is_base_of<C, Obj> {}; >+ >+ template <typename MemFun, typename Obj, typename... Args> >+ static decltype((std::declval<Obj>().* >+ std::declval<MemFun>())(std::declval<Args>()...)) >+ Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) { >+ return (std::forward<Obj>(obj).* >+ std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); >+ } >+}; >+ >+// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a >+// class T and t1 is not one of the types described in the previous item. >+struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> { >+ template <typename... Args> >+ struct AcceptImpl : std::false_type {}; >+ >+ template <typename R, typename C, typename... Params, typename Ptr, >+ typename... Args> >+ struct AcceptImpl<R (C::*)(Params...), Ptr, Args...> >+ : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; >+ >+ template <typename R, typename C, typename... Params, typename Ptr, >+ typename... Args> >+ struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...> >+ : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; >+ >+ template <typename MemFun, typename Ptr, typename... Args> >+ static decltype(((*std::declval<Ptr>()).* >+ std::declval<MemFun>())(std::declval<Args>()...)) >+ Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) { >+ return ((*std::forward<Ptr>(ptr)).* >+ std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...); >+ } >+}; >+ >+// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is >+// an object of type T or a reference to an object of type T or a reference >+// to an object of a type derived from T. >+struct DataMemAndRef : StrippedAccept<DataMemAndRef> { >+ template <typename... Args> >+ struct AcceptImpl : std::false_type {}; >+ >+ template <typename R, typename C, typename Obj> >+ struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {}; >+ >+ template <typename DataMem, typename Ref> >+ static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke( >+ DataMem&& data_mem, Ref&& ref) { >+ return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem); >+ } >+}; >+ >+// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 >+// is not one of the types described in the previous item. >+struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> { >+ template <typename... Args> >+ struct AcceptImpl : std::false_type {}; >+ >+ template <typename R, typename C, typename Ptr> >+ struct AcceptImpl<R C::*, Ptr> >+ : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {}; >+ >+ template <typename DataMem, typename Ptr> >+ static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke( >+ DataMem&& data_mem, Ptr&& ptr) { >+ return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem); >+ } >+}; >+ >+// f(t1, t2, ..., tN) in all other cases. >+struct Callable { >+ // Callable doesn't have Accept because it's the last clause that gets picked >+ // when none of the previous clauses are applicable. >+ template <typename F, typename... Args> >+ static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke( >+ F&& f, Args&&... args) { >+ return std::forward<F>(f)(std::forward<Args>(args)...); >+ } >+}; >+ >+// Resolves to the first matching clause. >+template <typename... Args> >+struct Invoker { >+ typedef typename std::conditional< >+ MemFunAndRef::Accept<Args...>::value, MemFunAndRef, >+ typename std::conditional< >+ MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr, >+ typename std::conditional< >+ DataMemAndRef::Accept<Args...>::value, DataMemAndRef, >+ typename std::conditional<DataMemAndPtr::Accept<Args...>::value, >+ DataMemAndPtr, Callable>::type>::type>:: >+ type>::type type; >+}; >+ >+// The result type of Invoke<F, Args...>. >+template <typename F, typename... Args> >+using InvokeT = decltype(Invoker<F, Args...>::type::Invoke( >+ std::declval<F>(), std::declval<Args>()...)); >+ >+// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section >+// [func.require] of the C++ standard. >+template <typename F, typename... Args> >+InvokeT<F, Args...> Invoke(F&& f, Args&&... args) { >+ return Invoker<F, Args...>::type::Invoke(std::forward<F>(f), >+ std::forward<Args>(args)...); >+} >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_INVOKE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc >new file mode 100644 >index 00000000000..0626cd5478d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.cc >@@ -0,0 +1,604 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// A low-level allocator that can be used by other low-level >+// modules without introducing dependency cycles. >+// This allocator is slow and wasteful of memory; >+// it should not be used when performance is key. >+ >+#include "absl/base/internal/low_level_alloc.h" >+ >+#include <type_traits> >+ >+#include "absl/base/call_once.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/direct_mmap.h" >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/macros.h" >+#include "absl/base/thread_annotations.h" >+ >+// LowLevelAlloc requires that the platform support low-level >+// allocation of virtual memory. Platforms lacking this cannot use >+// LowLevelAlloc. >+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING >+ >+#ifndef _WIN32 >+#include <pthread.h> >+#include <signal.h> >+#include <sys/mman.h> >+#include <unistd.h> >+#else >+#include <windows.h> >+#endif >+ >+#include <string.h> >+#include <algorithm> >+#include <atomic> >+#include <cerrno> >+#include <cstddef> >+#include <new> // for placement-new >+ >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+ >+// MAP_ANONYMOUS >+#if defined(__APPLE__) >+// For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANON is >+// deprecated. In Darwin, MAP_ANON is all there is. >+#if !defined MAP_ANONYMOUS >+#define MAP_ANONYMOUS MAP_ANON >+#endif // !MAP_ANONYMOUS >+#endif // __APPLE__ >+ >+namespace absl { >+namespace base_internal { >+ >+// A first-fit allocator with amortized logarithmic free() time. >+ >+// --------------------------------------------------------------------------- >+static const int kMaxLevel = 30; >+ >+namespace { >+// This struct describes one allocated block, or one free block. >+struct AllocList { >+ struct Header { >+ // Size of entire region, including this field. Must be >+ // first. Valid in both allocated and unallocated blocks. >+ uintptr_t size; >+ >+ // kMagicAllocated or kMagicUnallocated xor this. >+ uintptr_t magic; >+ >+ // Pointer to parent arena. >+ LowLevelAlloc::Arena *arena; >+ >+ // Aligns regions to 0 mod 2*sizeof(void*). >+ void *dummy_for_alignment; >+ } header; >+ >+ // Next two fields: in unallocated blocks: freelist skiplist data >+ // in allocated blocks: overlaps with client data >+ >+ // Levels in skiplist used. >+ int levels; >+ >+ // Actually has levels elements. The AllocList node may not have room >+ // for all kMaxLevel entries. See max_fit in LLA_SkiplistLevels(). >+ AllocList *next[kMaxLevel]; >+}; >+} // namespace >+ >+// --------------------------------------------------------------------------- >+// A trivial skiplist implementation. This is used to keep the freelist >+// in address order while taking only logarithmic time per insert and delete. >+ >+// An integer approximation of log2(size/base) >+// Requires size >= base. >+static int IntLog2(size_t size, size_t base) { >+ int result = 0; >+ for (size_t i = size; i > base; i >>= 1) { // i == floor(size/2**result) >+ result++; >+ } >+ // floor(size / 2**result) <= base < floor(size / 2**(result-1)) >+ // => log2(size/(base+1)) <= result < 1+log2(size/base) >+ // => result ~= log2(size/base) >+ return result; >+} >+ >+// Return a random integer n: p(n)=1/(2**n) if 1 <= n; p(n)=0 if n < 1. >+static int Random(uint32_t *state) { >+ uint32_t r = *state; >+ int result = 1; >+ while ((((r = r*1103515245 + 12345) >> 30) & 1) == 0) { >+ result++; >+ } >+ *state = r; >+ return result; >+} >+ >+// Return a number of skiplist levels for a node of size bytes, where >+// base is the minimum node size. Compute level=log2(size / base)+n >+// where n is 1 if random is false and otherwise a random number generated with >+// the standard distribution for a skiplist: See Random() above. >+// Bigger nodes tend to have more skiplist levels due to the log2(size / base) >+// term, so first-fit searches touch fewer nodes. "level" is clipped so >+// level<kMaxLevel and next[level-1] will fit in the node. >+// 0 < LLA_SkiplistLevels(x,y,false) <= LLA_SkiplistLevels(x,y,true) < kMaxLevel >+static int LLA_SkiplistLevels(size_t size, size_t base, uint32_t *random) { >+ // max_fit is the maximum number of levels that will fit in a node for the >+ // given size. We can't return more than max_fit, no matter what the >+ // random number generator says. >+ size_t max_fit = (size - offsetof(AllocList, next)) / sizeof(AllocList *); >+ int level = IntLog2(size, base) + (random != nullptr ? Random(random) : 1); >+ if (static_cast<size_t>(level) > max_fit) level = static_cast<int>(max_fit); >+ if (level > kMaxLevel-1) level = kMaxLevel - 1; >+ ABSL_RAW_CHECK(level >= 1, "block not big enough for even one level"); >+ return level; >+} >+ >+// Return "atleast", the first element of AllocList *head s.t. *atleast >= *e. >+// For 0 <= i < head->levels, set prev[i] to "no_greater", where no_greater >+// points to the last element at level i in the AllocList less than *e, or is >+// head if no such element exists. >+static AllocList *LLA_SkiplistSearch(AllocList *head, >+ AllocList *e, AllocList **prev) { >+ AllocList *p = head; >+ for (int level = head->levels - 1; level >= 0; level--) { >+ for (AllocList *n; (n = p->next[level]) != nullptr && n < e; p = n) { >+ } >+ prev[level] = p; >+ } >+ return (head->levels == 0) ? nullptr : prev[0]->next[0]; >+} >+ >+// Insert element *e into AllocList *head. Set prev[] as LLA_SkiplistSearch. >+// Requires that e->levels be previously set by the caller (using >+// LLA_SkiplistLevels()) >+static void LLA_SkiplistInsert(AllocList *head, AllocList *e, >+ AllocList **prev) { >+ LLA_SkiplistSearch(head, e, prev); >+ for (; head->levels < e->levels; head->levels++) { // extend prev pointers >+ prev[head->levels] = head; // to all *e's levels >+ } >+ for (int i = 0; i != e->levels; i++) { // add element to list >+ e->next[i] = prev[i]->next[i]; >+ prev[i]->next[i] = e; >+ } >+} >+ >+// Remove element *e from AllocList *head. Set prev[] as LLA_SkiplistSearch(). >+// Requires that e->levels be previous set by the caller (using >+// LLA_SkiplistLevels()) >+static void LLA_SkiplistDelete(AllocList *head, AllocList *e, >+ AllocList **prev) { >+ AllocList *found = LLA_SkiplistSearch(head, e, prev); >+ ABSL_RAW_CHECK(e == found, "element not in freelist"); >+ for (int i = 0; i != e->levels && prev[i]->next[i] == e; i++) { >+ prev[i]->next[i] = e->next[i]; >+ } >+ while (head->levels > 0 && head->next[head->levels - 1] == nullptr) { >+ head->levels--; // reduce head->levels if level unused >+ } >+} >+ >+// --------------------------------------------------------------------------- >+// Arena implementation >+ >+// Metadata for an LowLevelAlloc arena instance. >+struct LowLevelAlloc::Arena { >+ // Constructs an arena with the given LowLevelAlloc flags. >+ explicit Arena(uint32_t flags_value); >+ >+ base_internal::SpinLock mu; >+ // Head of free list, sorted by address >+ AllocList freelist GUARDED_BY(mu); >+ // Count of allocated blocks >+ int32_t allocation_count GUARDED_BY(mu); >+ // flags passed to NewArena >+ const uint32_t flags; >+ // Result of getpagesize() >+ const size_t pagesize; >+ // Lowest power of two >= max(16, sizeof(AllocList)) >+ const size_t roundup; >+ // Smallest allocation block size >+ const size_t min_size; >+ // PRNG state >+ uint32_t random GUARDED_BY(mu); >+}; >+ >+namespace { >+using ArenaStorage = std::aligned_storage<sizeof(LowLevelAlloc::Arena), >+ alignof(LowLevelAlloc::Arena)>::type; >+ >+// Static storage space for the lazily-constructed, default global arena >+// instances. We require this space because the whole point of LowLevelAlloc >+// is to avoid relying on malloc/new. >+ArenaStorage default_arena_storage; >+ArenaStorage unhooked_arena_storage; >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ArenaStorage unhooked_async_sig_safe_arena_storage; >+#endif >+ >+// We must use LowLevelCallOnce here to construct the global arenas, rather than >+// using function-level statics, to avoid recursively invoking the scheduler. >+absl::once_flag create_globals_once; >+ >+void CreateGlobalArenas() { >+ new (&default_arena_storage) >+ LowLevelAlloc::Arena(LowLevelAlloc::kCallMallocHook); >+ new (&unhooked_arena_storage) LowLevelAlloc::Arena(0); >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ new (&unhooked_async_sig_safe_arena_storage) >+ LowLevelAlloc::Arena(LowLevelAlloc::kAsyncSignalSafe); >+#endif >+} >+ >+// Returns a global arena that does not call into hooks. Used by NewArena() >+// when kCallMallocHook is not set. >+LowLevelAlloc::Arena* UnhookedArena() { >+ base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas); >+ return reinterpret_cast<LowLevelAlloc::Arena*>(&unhooked_arena_storage); >+} >+ >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+// Returns a global arena that is async-signal safe. Used by NewArena() when >+// kAsyncSignalSafe is set. >+LowLevelAlloc::Arena *UnhookedAsyncSigSafeArena() { >+ base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas); >+ return reinterpret_cast<LowLevelAlloc::Arena *>( >+ &unhooked_async_sig_safe_arena_storage); >+} >+#endif >+ >+} // namespace >+ >+// Returns the default arena, as used by LowLevelAlloc::Alloc() and friends. >+LowLevelAlloc::Arena *LowLevelAlloc::DefaultArena() { >+ base_internal::LowLevelCallOnce(&create_globals_once, CreateGlobalArenas); >+ return reinterpret_cast<LowLevelAlloc::Arena*>(&default_arena_storage); >+} >+ >+// magic numbers to identify allocated and unallocated blocks >+static const uintptr_t kMagicAllocated = 0x4c833e95U; >+static const uintptr_t kMagicUnallocated = ~kMagicAllocated; >+ >+namespace { >+class SCOPED_LOCKABLE ArenaLock { >+ public: >+ explicit ArenaLock(LowLevelAlloc::Arena *arena) >+ EXCLUSIVE_LOCK_FUNCTION(arena->mu) >+ : arena_(arena) { >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { >+ sigset_t all; >+ sigfillset(&all); >+ mask_valid_ = pthread_sigmask(SIG_BLOCK, &all, &mask_) == 0; >+ } >+#endif >+ arena_->mu.Lock(); >+ } >+ ~ArenaLock() { ABSL_RAW_CHECK(left_, "haven't left Arena region"); } >+ void Leave() UNLOCK_FUNCTION() { >+ arena_->mu.Unlock(); >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ if (mask_valid_) { >+ pthread_sigmask(SIG_SETMASK, &mask_, nullptr); >+ } >+#endif >+ left_ = true; >+ } >+ >+ private: >+ bool left_ = false; // whether left region >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ bool mask_valid_ = false; >+ sigset_t mask_; // old mask of blocked signals >+#endif >+ LowLevelAlloc::Arena *arena_; >+ ArenaLock(const ArenaLock &) = delete; >+ ArenaLock &operator=(const ArenaLock &) = delete; >+}; >+} // namespace >+ >+// create an appropriate magic number for an object at "ptr" >+// "magic" should be kMagicAllocated or kMagicUnallocated >+inline static uintptr_t Magic(uintptr_t magic, AllocList::Header *ptr) { >+ return magic ^ reinterpret_cast<uintptr_t>(ptr); >+} >+ >+namespace { >+size_t GetPageSize() { >+#ifdef _WIN32 >+ SYSTEM_INFO system_info; >+ GetSystemInfo(&system_info); >+ return std::max(system_info.dwPageSize, system_info.dwAllocationGranularity); >+#else >+ return getpagesize(); >+#endif >+} >+ >+size_t RoundedUpBlockSize() { >+ // Round up block sizes to a power of two close to the header size. >+ size_t roundup = 16; >+ while (roundup < sizeof(AllocList::Header)) { >+ roundup += roundup; >+ } >+ return roundup; >+} >+ >+} // namespace >+ >+LowLevelAlloc::Arena::Arena(uint32_t flags_value) >+ : mu(base_internal::SCHEDULE_KERNEL_ONLY), >+ allocation_count(0), >+ flags(flags_value), >+ pagesize(GetPageSize()), >+ roundup(RoundedUpBlockSize()), >+ min_size(2 * roundup), >+ random(0) { >+ freelist.header.size = 0; >+ freelist.header.magic = >+ Magic(kMagicUnallocated, &freelist.header); >+ freelist.header.arena = this; >+ freelist.levels = 0; >+ memset(freelist.next, 0, sizeof(freelist.next)); >+} >+ >+// L < meta_data_arena->mu >+LowLevelAlloc::Arena *LowLevelAlloc::NewArena(int32_t flags) { >+ Arena *meta_data_arena = DefaultArena(); >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ if ((flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { >+ meta_data_arena = UnhookedAsyncSigSafeArena(); >+ } else // NOLINT(readability/braces) >+#endif >+ if ((flags & LowLevelAlloc::kCallMallocHook) == 0) { >+ meta_data_arena = UnhookedArena(); >+ } >+ Arena *result = >+ new (AllocWithArena(sizeof (*result), meta_data_arena)) Arena(flags); >+ return result; >+} >+ >+// L < arena->mu, L < arena->arena->mu >+bool LowLevelAlloc::DeleteArena(Arena *arena) { >+ ABSL_RAW_CHECK( >+ arena != nullptr && arena != DefaultArena() && arena != UnhookedArena(), >+ "may not delete default arena"); >+ ArenaLock section(arena); >+ if (arena->allocation_count != 0) { >+ section.Leave(); >+ return false; >+ } >+ while (arena->freelist.next[0] != nullptr) { >+ AllocList *region = arena->freelist.next[0]; >+ size_t size = region->header.size; >+ arena->freelist.next[0] = region->next[0]; >+ ABSL_RAW_CHECK( >+ region->header.magic == Magic(kMagicUnallocated, ®ion->header), >+ "bad magic number in DeleteArena()"); >+ ABSL_RAW_CHECK(region->header.arena == arena, >+ "bad arena pointer in DeleteArena()"); >+ ABSL_RAW_CHECK(size % arena->pagesize == 0, >+ "empty arena has non-page-aligned block size"); >+ ABSL_RAW_CHECK(reinterpret_cast<uintptr_t>(region) % arena->pagesize == 0, >+ "empty arena has non-page-aligned block"); >+ int munmap_result; >+#ifdef _WIN32 >+ munmap_result = VirtualFree(region, 0, MEM_RELEASE); >+ ABSL_RAW_CHECK(munmap_result != 0, >+ "LowLevelAlloc::DeleteArena: VitualFree failed"); >+#else >+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) == 0) { >+ munmap_result = munmap(region, size); >+ } else { >+ munmap_result = base_internal::DirectMunmap(region, size); >+ } >+ if (munmap_result != 0) { >+ ABSL_RAW_LOG(FATAL, "LowLevelAlloc::DeleteArena: munmap failed: %d", >+ errno); >+ } >+#endif >+ } >+ section.Leave(); >+ arena->~Arena(); >+ Free(arena); >+ return true; >+} >+ >+// --------------------------------------------------------------------------- >+ >+// Addition, checking for overflow. The intent is to die if an external client >+// manages to push through a request that would cause arithmetic to fail. >+static inline uintptr_t CheckedAdd(uintptr_t a, uintptr_t b) { >+ uintptr_t sum = a + b; >+ ABSL_RAW_CHECK(sum >= a, "LowLevelAlloc arithmetic overflow"); >+ return sum; >+} >+ >+// Return value rounded up to next multiple of align. >+// align must be a power of two. >+static inline uintptr_t RoundUp(uintptr_t addr, uintptr_t align) { >+ return CheckedAdd(addr, align - 1) & ~(align - 1); >+} >+ >+// Equivalent to "return prev->next[i]" but with sanity checking >+// that the freelist is in the correct order, that it >+// consists of regions marked "unallocated", and that no two regions >+// are adjacent in memory (they should have been coalesced). >+// L < arena->mu >+static AllocList *Next(int i, AllocList *prev, LowLevelAlloc::Arena *arena) { >+ ABSL_RAW_CHECK(i < prev->levels, "too few levels in Next()"); >+ AllocList *next = prev->next[i]; >+ if (next != nullptr) { >+ ABSL_RAW_CHECK( >+ next->header.magic == Magic(kMagicUnallocated, &next->header), >+ "bad magic number in Next()"); >+ ABSL_RAW_CHECK(next->header.arena == arena, "bad arena pointer in Next()"); >+ if (prev != &arena->freelist) { >+ ABSL_RAW_CHECK(prev < next, "unordered freelist"); >+ ABSL_RAW_CHECK(reinterpret_cast<char *>(prev) + prev->header.size < >+ reinterpret_cast<char *>(next), >+ "malformed freelist"); >+ } >+ } >+ return next; >+} >+ >+// Coalesce list item "a" with its successor if they are adjacent. >+static void Coalesce(AllocList *a) { >+ AllocList *n = a->next[0]; >+ if (n != nullptr && reinterpret_cast<char *>(a) + a->header.size == >+ reinterpret_cast<char *>(n)) { >+ LowLevelAlloc::Arena *arena = a->header.arena; >+ a->header.size += n->header.size; >+ n->header.magic = 0; >+ n->header.arena = nullptr; >+ AllocList *prev[kMaxLevel]; >+ LLA_SkiplistDelete(&arena->freelist, n, prev); >+ LLA_SkiplistDelete(&arena->freelist, a, prev); >+ a->levels = LLA_SkiplistLevels(a->header.size, arena->min_size, >+ &arena->random); >+ LLA_SkiplistInsert(&arena->freelist, a, prev); >+ } >+} >+ >+// Adds block at location "v" to the free list >+// L >= arena->mu >+static void AddToFreelist(void *v, LowLevelAlloc::Arena *arena) { >+ AllocList *f = reinterpret_cast<AllocList *>( >+ reinterpret_cast<char *>(v) - sizeof (f->header)); >+ ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header), >+ "bad magic number in AddToFreelist()"); >+ ABSL_RAW_CHECK(f->header.arena == arena, >+ "bad arena pointer in AddToFreelist()"); >+ f->levels = LLA_SkiplistLevels(f->header.size, arena->min_size, >+ &arena->random); >+ AllocList *prev[kMaxLevel]; >+ LLA_SkiplistInsert(&arena->freelist, f, prev); >+ f->header.magic = Magic(kMagicUnallocated, &f->header); >+ Coalesce(f); // maybe coalesce with successor >+ Coalesce(prev[0]); // maybe coalesce with predecessor >+} >+ >+// Frees storage allocated by LowLevelAlloc::Alloc(). >+// L < arena->mu >+void LowLevelAlloc::Free(void *v) { >+ if (v != nullptr) { >+ AllocList *f = reinterpret_cast<AllocList *>( >+ reinterpret_cast<char *>(v) - sizeof (f->header)); >+ ABSL_RAW_CHECK(f->header.magic == Magic(kMagicAllocated, &f->header), >+ "bad magic number in Free()"); >+ LowLevelAlloc::Arena *arena = f->header.arena; >+ ArenaLock section(arena); >+ AddToFreelist(v, arena); >+ ABSL_RAW_CHECK(arena->allocation_count > 0, "nothing in arena to free"); >+ arena->allocation_count--; >+ section.Leave(); >+ } >+} >+ >+// allocates and returns a block of size bytes, to be freed with Free() >+// L < arena->mu >+static void *DoAllocWithArena(size_t request, LowLevelAlloc::Arena *arena) { >+ void *result = nullptr; >+ if (request != 0) { >+ AllocList *s; // will point to region that satisfies request >+ ArenaLock section(arena); >+ // round up with header >+ size_t req_rnd = RoundUp(CheckedAdd(request, sizeof (s->header)), >+ arena->roundup); >+ for (;;) { // loop until we find a suitable region >+ // find the minimum levels that a block of this size must have >+ int i = LLA_SkiplistLevels(req_rnd, arena->min_size, nullptr) - 1; >+ if (i < arena->freelist.levels) { // potential blocks exist >+ AllocList *before = &arena->freelist; // predecessor of s >+ while ((s = Next(i, before, arena)) != nullptr && >+ s->header.size < req_rnd) { >+ before = s; >+ } >+ if (s != nullptr) { // we found a region >+ break; >+ } >+ } >+ // we unlock before mmap() both because mmap() may call a callback hook, >+ // and because it may be slow. >+ arena->mu.Unlock(); >+ // mmap generous 64K chunks to decrease >+ // the chances/impact of fragmentation: >+ size_t new_pages_size = RoundUp(req_rnd, arena->pagesize * 16); >+ void *new_pages; >+#ifdef _WIN32 >+ new_pages = VirtualAlloc(0, new_pages_size, >+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); >+ ABSL_RAW_CHECK(new_pages != nullptr, "VirtualAlloc failed"); >+#else >+ if ((arena->flags & LowLevelAlloc::kAsyncSignalSafe) != 0) { >+ new_pages = base_internal::DirectMmap(nullptr, new_pages_size, >+ PROT_WRITE|PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); >+ } else { >+ new_pages = mmap(nullptr, new_pages_size, PROT_WRITE | PROT_READ, >+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); >+ } >+ if (new_pages == MAP_FAILED) { >+ ABSL_RAW_LOG(FATAL, "mmap error: %d", errno); >+ } >+#endif >+ arena->mu.Lock(); >+ s = reinterpret_cast<AllocList *>(new_pages); >+ s->header.size = new_pages_size; >+ // Pretend the block is allocated; call AddToFreelist() to free it. >+ s->header.magic = Magic(kMagicAllocated, &s->header); >+ s->header.arena = arena; >+ AddToFreelist(&s->levels, arena); // insert new region into free list >+ } >+ AllocList *prev[kMaxLevel]; >+ LLA_SkiplistDelete(&arena->freelist, s, prev); // remove from free list >+ // s points to the first free region that's big enough >+ if (CheckedAdd(req_rnd, arena->min_size) <= s->header.size) { >+ // big enough to split >+ AllocList *n = reinterpret_cast<AllocList *> >+ (req_rnd + reinterpret_cast<char *>(s)); >+ n->header.size = s->header.size - req_rnd; >+ n->header.magic = Magic(kMagicAllocated, &n->header); >+ n->header.arena = arena; >+ s->header.size = req_rnd; >+ AddToFreelist(&n->levels, arena); >+ } >+ s->header.magic = Magic(kMagicAllocated, &s->header); >+ ABSL_RAW_CHECK(s->header.arena == arena, ""); >+ arena->allocation_count++; >+ section.Leave(); >+ result = &s->levels; >+ } >+ ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, request); >+ return result; >+} >+ >+void *LowLevelAlloc::Alloc(size_t request) { >+ void *result = DoAllocWithArena(request, DefaultArena()); >+ return result; >+} >+ >+void *LowLevelAlloc::AllocWithArena(size_t request, Arena *arena) { >+ ABSL_RAW_CHECK(arena != nullptr, "must pass a valid arena"); >+ void *result = DoAllocWithArena(request, arena); >+ return result; >+} >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.h >new file mode 100644 >index 00000000000..3c15605bed3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc.h >@@ -0,0 +1,119 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ >+#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ >+ >+// A simple thread-safe memory allocator that does not depend on >+// mutexes or thread-specific data. It is intended to be used >+// sparingly, and only when malloc() would introduce an unwanted >+// dependency, such as inside the heap-checker, or the Mutex >+// implementation. >+ >+// IWYU pragma: private, include "base/low_level_alloc.h" >+ >+#include <sys/types.h> >+#include <cstdint> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/config.h" >+ >+// LowLevelAlloc requires that the platform support low-level >+// allocation of virtual memory. Platforms lacking this cannot use >+// LowLevelAlloc. >+#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING >+#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set >+#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32) >+#define ABSL_LOW_LEVEL_ALLOC_MISSING 1 >+#endif >+ >+// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows. >+#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set >+#elif defined(_WIN32) >+#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1 >+#endif >+ >+#include <cstddef> >+ >+#include "absl/base/port.h" >+ >+namespace absl { >+namespace base_internal { >+ >+class LowLevelAlloc { >+ public: >+ struct Arena; // an arena from which memory may be allocated >+ >+ // Returns a pointer to a block of at least "request" bytes >+ // that have been newly allocated from the specific arena. >+ // for Alloc() call the DefaultArena() is used. >+ // Returns 0 if passed request==0. >+ // Does not return 0 under other circumstances; it crashes if memory >+ // is not available. >+ static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook); >+ static void *AllocWithArena(size_t request, Arena *arena) >+ ABSL_ATTRIBUTE_SECTION(malloc_hook); >+ >+ // Deallocates a region of memory that was previously allocated with >+ // Alloc(). Does nothing if passed 0. "s" must be either 0, >+ // or must have been returned from a call to Alloc() and not yet passed to >+ // Free() since that call to Alloc(). The space is returned to the arena >+ // from which it was allocated. >+ static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook); >+ >+ // ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free >+ // are to put all callers of MallocHook::Invoke* in this module >+ // into special section, >+ // so that MallocHook::GetCallerStackTrace can function accurately. >+ >+ // Create a new arena. >+ // The root metadata for the new arena is allocated in the >+ // meta_data_arena; the DefaultArena() can be passed for meta_data_arena. >+ // These values may be ored into flags: >+ enum { >+ // Report calls to Alloc() and Free() via the MallocHook interface. >+ // Set in the DefaultArena. >+ kCallMallocHook = 0x0001, >+ >+#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING >+ // Make calls to Alloc(), Free() be async-signal-safe. Not set in >+ // DefaultArena(). Not supported on all platforms. >+ kAsyncSignalSafe = 0x0002, >+#endif >+ }; >+ // Construct a new arena. The allocation of the underlying metadata honors >+ // the provided flags. For example, the call NewArena(kAsyncSignalSafe) >+ // is itself async-signal-safe, as well as generatating an arena that provides >+ // async-signal-safe Alloc/Free. >+ static Arena *NewArena(int32_t flags); >+ >+ // Destroys an arena allocated by NewArena and returns true, >+ // provided no allocated blocks remain in the arena. >+ // If allocated blocks remain in the arena, does nothing and >+ // returns false. >+ // It is illegal to attempt to destroy the DefaultArena(). >+ static bool DeleteArena(Arena *arena); >+ >+ // The default arena that always exists. >+ static Arena *DefaultArena(); >+ >+ private: >+ LowLevelAlloc(); // no instances >+}; >+ >+} // namespace base_internal >+} // namespace absl >+#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc >new file mode 100644 >index 00000000000..cf2b363299f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_alloc_test.cc >@@ -0,0 +1,157 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/low_level_alloc.h" >+ >+#include <stdint.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <thread> // NOLINT(build/c++11) >+#include <unordered_map> >+#include <utility> >+ >+namespace absl { >+namespace base_internal { >+namespace { >+ >+// This test doesn't use gtest since it needs to test that everything >+// works before main(). >+#define TEST_ASSERT(x) \ >+ if (!(x)) { \ >+ printf("TEST_ASSERT(%s) FAILED ON LINE %d\n", #x, __LINE__); \ >+ abort(); \ >+ } >+ >+// a block of memory obtained from the allocator >+struct BlockDesc { >+ char *ptr; // pointer to memory >+ int len; // number of bytes >+ int fill; // filled with data starting with this >+}; >+ >+// Check that the pattern placed in the block d >+// by RandomizeBlockDesc is still there. >+static void CheckBlockDesc(const BlockDesc &d) { >+ for (int i = 0; i != d.len; i++) { >+ TEST_ASSERT((d.ptr[i] & 0xff) == ((d.fill + i) & 0xff)); >+ } >+} >+ >+// Fill the block "*d" with a pattern >+// starting with a random byte. >+static void RandomizeBlockDesc(BlockDesc *d) { >+ d->fill = rand() & 0xff; >+ for (int i = 0; i != d->len; i++) { >+ d->ptr[i] = (d->fill + i) & 0xff; >+ } >+} >+ >+// Use to indicate to the malloc hooks that >+// this calls is from LowLevelAlloc. >+static bool using_low_level_alloc = false; >+ >+// n times, toss a coin, and based on the outcome >+// either allocate a new block or deallocate an old block. >+// New blocks are placed in a std::unordered_map with a random key >+// and initialized with RandomizeBlockDesc(). >+// If keys conflict, the older block is freed. >+// Old blocks are always checked with CheckBlockDesc() >+// before being freed. At the end of the run, >+// all remaining allocated blocks are freed. >+// If use_new_arena is true, use a fresh arena, and then delete it. >+// If call_malloc_hook is true and user_arena is true, >+// allocations and deallocations are reported via the MallocHook >+// interface. >+static void Test(bool use_new_arena, bool call_malloc_hook, int n) { >+ typedef std::unordered_map<int, BlockDesc> AllocMap; >+ AllocMap allocated; >+ AllocMap::iterator it; >+ BlockDesc block_desc; >+ int rnd; >+ LowLevelAlloc::Arena *arena = 0; >+ if (use_new_arena) { >+ int32_t flags = call_malloc_hook ? LowLevelAlloc::kCallMallocHook : 0; >+ arena = LowLevelAlloc::NewArena(flags); >+ } >+ for (int i = 0; i != n; i++) { >+ if (i != 0 && i % 10000 == 0) { >+ printf("."); >+ fflush(stdout); >+ } >+ >+ switch (rand() & 1) { // toss a coin >+ case 0: // coin came up heads: add a block >+ using_low_level_alloc = true; >+ block_desc.len = rand() & 0x3fff; >+ block_desc.ptr = >+ reinterpret_cast<char *>( >+ arena == 0 >+ ? LowLevelAlloc::Alloc(block_desc.len) >+ : LowLevelAlloc::AllocWithArena(block_desc.len, arena)); >+ using_low_level_alloc = false; >+ RandomizeBlockDesc(&block_desc); >+ rnd = rand(); >+ it = allocated.find(rnd); >+ if (it != allocated.end()) { >+ CheckBlockDesc(it->second); >+ using_low_level_alloc = true; >+ LowLevelAlloc::Free(it->second.ptr); >+ using_low_level_alloc = false; >+ it->second = block_desc; >+ } else { >+ allocated[rnd] = block_desc; >+ } >+ break; >+ case 1: // coin came up tails: remove a block >+ it = allocated.begin(); >+ if (it != allocated.end()) { >+ CheckBlockDesc(it->second); >+ using_low_level_alloc = true; >+ LowLevelAlloc::Free(it->second.ptr); >+ using_low_level_alloc = false; >+ allocated.erase(it); >+ } >+ break; >+ } >+ } >+ // remove all remaining blocks >+ while ((it = allocated.begin()) != allocated.end()) { >+ CheckBlockDesc(it->second); >+ using_low_level_alloc = true; >+ LowLevelAlloc::Free(it->second.ptr); >+ using_low_level_alloc = false; >+ allocated.erase(it); >+ } >+ if (use_new_arena) { >+ TEST_ASSERT(LowLevelAlloc::DeleteArena(arena)); >+ } >+} >+// LowLevelAlloc is designed to be safe to call before main(). >+static struct BeforeMain { >+ BeforeMain() { >+ Test(false, false, 50000); >+ Test(true, false, 50000); >+ Test(true, true, 50000); >+ } >+} before_main; >+ >+} // namespace >+} // namespace base_internal >+} // namespace absl >+ >+int main(int argc, char *argv[]) { >+ // The actual test runs in the global constructor of `before_main`. >+ printf("PASS\n"); >+ return 0; >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h >new file mode 100644 >index 00000000000..e716f2b49fa >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/low_level_scheduling.h >@@ -0,0 +1,104 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Core interfaces and definitions used by by low-level interfaces such as >+// SpinLock. >+ >+#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ >+#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ >+ >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/macros.h" >+ >+// The following two declarations exist so SchedulingGuard may friend them with >+// the appropriate language linkage. These callbacks allow libc internals, such >+// as function level statics, to schedule cooperatively when locking. >+extern "C" bool __google_disable_rescheduling(void); >+extern "C" void __google_enable_rescheduling(bool disable_result); >+ >+namespace absl { >+namespace base_internal { >+ >+class SchedulingHelper; // To allow use of SchedulingGuard. >+class SpinLock; // To allow use of SchedulingGuard. >+ >+// SchedulingGuard >+// Provides guard semantics that may be used to disable cooperative rescheduling >+// of the calling thread within specific program blocks. This is used to >+// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative >+// scheduling depends on. >+// >+// Domain implementations capable of rescheduling in reaction to involuntary >+// kernel thread actions (e.g blocking due to a pagefault or syscall) must >+// guarantee that an annotated thread is not allowed to (cooperatively) >+// reschedule until the annotated region is complete. >+// >+// It is an error to attempt to use a cooperatively scheduled resource (e.g. >+// Mutex) within a rescheduling-disabled region. >+// >+// All methods are async-signal safe. >+class SchedulingGuard { >+ public: >+ // Returns true iff the calling thread may be cooperatively rescheduled. >+ static bool ReschedulingIsAllowed(); >+ >+ private: >+ // Disable cooperative rescheduling of the calling thread. It may still >+ // initiate scheduling operations (e.g. wake-ups), however, it may not itself >+ // reschedule. Nestable. The returned result is opaque, clients should not >+ // attempt to interpret it. >+ // REQUIRES: Result must be passed to a pairing EnableScheduling(). >+ static bool DisableRescheduling(); >+ >+ // Marks the end of a rescheduling disabled region, previously started by >+ // DisableRescheduling(). >+ // REQUIRES: Pairs with innermost call (and result) of DisableRescheduling(). >+ static void EnableRescheduling(bool disable_result); >+ >+ // A scoped helper for {Disable, Enable}Rescheduling(). >+ // REQUIRES: destructor must run in same thread as constructor. >+ struct ScopedDisable { >+ ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); } >+ ~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); } >+ >+ bool disabled; >+ }; >+ >+ // Access to SchedulingGuard is explicitly white-listed. >+ friend class SchedulingHelper; >+ friend class SpinLock; >+ >+ SchedulingGuard(const SchedulingGuard&) = delete; >+ SchedulingGuard& operator=(const SchedulingGuard&) = delete; >+}; >+ >+//------------------------------------------------------------------------------ >+// End of public interfaces. >+//------------------------------------------------------------------------------ >+inline bool SchedulingGuard::ReschedulingIsAllowed() { >+ return false; >+} >+ >+inline bool SchedulingGuard::DisableRescheduling() { >+ return false; >+} >+ >+inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { >+ return; >+} >+ >+ >+} // namespace base_internal >+} // namespace absl >+#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/per_thread_tls.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/per_thread_tls.h >new file mode 100644 >index 00000000000..2428bdc1238 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/per_thread_tls.h >@@ -0,0 +1,48 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ >+#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ >+ >+// This header defines two macros: >+// If the platform supports thread-local storage: >+// ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a >+// thread-local variable ABSL_PER_THREAD_TLS is 1 >+// >+// Otherwise: >+// ABSL_PER_THREAD_TLS_KEYWORD is empty >+// ABSL_PER_THREAD_TLS is 0 >+// >+// Microsoft C supports thread-local storage. >+// GCC supports it if the appropriate version of glibc is available, >+// which the programmer can indicate by defining ABSL_HAVE_TLS >+ >+#include "absl/base/port.h" // For ABSL_HAVE_TLS >+ >+#if defined(ABSL_PER_THREAD_TLS) >+#error ABSL_PER_THREAD_TLS cannot be directly set >+#elif defined(ABSL_PER_THREAD_TLS_KEYWORD) >+#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set >+#elif defined(ABSL_HAVE_TLS) >+#define ABSL_PER_THREAD_TLS_KEYWORD __thread >+#define ABSL_PER_THREAD_TLS 1 >+#elif defined(_MSC_VER) >+#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread) >+#define ABSL_PER_THREAD_TLS 1 >+#else >+#define ABSL_PER_THREAD_TLS_KEYWORD >+#define ABSL_PER_THREAD_TLS 0 >+#endif >+ >+#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/pretty_function.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/pretty_function.h >new file mode 100644 >index 00000000000..01b0547bd08 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/pretty_function.h >@@ -0,0 +1,33 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_ >+#define ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_ >+ >+// ABSL_PRETTY_FUNCTION >+// >+// In C++11, __func__ gives the undecorated name of the current function. That >+// is, "main", not "int main()". Various compilers give extra macros to get the >+// decorated function name, including return type and arguments, to >+// differentiate between overload sets. ABSL_PRETTY_FUNCTION is a portable >+// version of these macros which forwards to the correct macro on each compiler. >+#if defined(_MSC_VER) >+#define ABSL_PRETTY_FUNCTION __FUNCSIG__ >+#elif defined(__GNUC__) >+#define ABSL_PRETTY_FUNCTION __PRETTY_FUNCTION__ >+#else >+#error "Unsupported compiler" >+#endif >+ >+#endif // ABSL_BASE_INTERNAL_PRETTY_FUNCTION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.cc >new file mode 100644 >index 00000000000..d9485a66cc6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.cc >@@ -0,0 +1,234 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/raw_logging.h" >+ >+#include <stddef.h> >+#include <cstdarg> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/atomic_hook.h" >+#include "absl/base/log_severity.h" >+ >+// We know how to perform low-level writes to stderr in POSIX and Windows. For >+// these platforms, we define the token ABSL_LOW_LEVEL_WRITE_SUPPORTED. >+// Much of raw_logging.cc becomes a no-op when we can't output messages, >+// although a FATAL ABSL_RAW_LOG message will still abort the process. >+ >+// ABSL_HAVE_POSIX_WRITE is defined when the platform provides posix write() >+// (as from unistd.h) >+// >+// This preprocessor token is also defined in raw_io.cc. If you need to copy >+// this, consider moving both to config.h instead. >+#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \ >+ defined(__Fuchsia__) || defined(__native_client__) >+#include <unistd.h> >+ >+ >+#define ABSL_HAVE_POSIX_WRITE 1 >+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1 >+#else >+#undef ABSL_HAVE_POSIX_WRITE >+#endif >+ >+// ABSL_HAVE_SYSCALL_WRITE is defined when the platform provides the syscall >+// syscall(SYS_write, /*int*/ fd, /*char* */ buf, /*size_t*/ len); >+// for low level operations that want to avoid libc. >+#if (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__) >+#include <sys/syscall.h> >+#define ABSL_HAVE_SYSCALL_WRITE 1 >+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1 >+#else >+#undef ABSL_HAVE_SYSCALL_WRITE >+#endif >+ >+#ifdef _WIN32 >+#include <io.h> >+ >+#define ABSL_HAVE_RAW_IO 1 >+#define ABSL_LOW_LEVEL_WRITE_SUPPORTED 1 >+#else >+#undef ABSL_HAVE_RAW_IO >+#endif >+ >+// TODO(gfalcon): We want raw-logging to work on as many platforms as possible. >+// Explicitly #error out when not ABSL_LOW_LEVEL_WRITE_SUPPORTED, except for a >+// whitelisted set of platforms for which we expect not to be able to raw log. >+ >+ABSL_CONST_INIT static absl::base_internal::AtomicHook< >+ absl::raw_logging_internal::LogPrefixHook> log_prefix_hook; >+ABSL_CONST_INIT static absl::base_internal::AtomicHook< >+ absl::raw_logging_internal::AbortHook> abort_hook; >+ >+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED >+static const char kTruncated[] = " ... (message truncated)\n"; >+ >+// sprintf the format to the buffer, adjusting *buf and *size to reflect the >+// consumed bytes, and return whether the message fit without truncation. If >+// truncation occurred, if possible leave room in the buffer for the message >+// kTruncated[]. >+inline static bool VADoRawLog(char** buf, int* size, const char* format, >+ va_list ap) ABSL_PRINTF_ATTRIBUTE(3, 0); >+inline static bool VADoRawLog(char** buf, int* size, >+ const char* format, va_list ap) { >+ int n = vsnprintf(*buf, *size, format, ap); >+ bool result = true; >+ if (n < 0 || n > *size) { >+ result = false; >+ if (static_cast<size_t>(*size) > sizeof(kTruncated)) { >+ n = *size - sizeof(kTruncated); // room for truncation message >+ } else { >+ n = 0; // no room for truncation message >+ } >+ } >+ *size -= n; >+ *buf += n; >+ return result; >+} >+#endif // ABSL_LOW_LEVEL_WRITE_SUPPORTED >+ >+static constexpr int kLogBufSize = 3000; >+ >+namespace { >+ >+// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths >+// that invoke malloc() and getenv() that might acquire some locks. >+ >+// Helper for RawLog below. >+// *DoRawLog writes to *buf of *size and move them past the written portion. >+// It returns true iff there was no overflow or error. >+bool DoRawLog(char** buf, int* size, const char* format, ...) >+ ABSL_PRINTF_ATTRIBUTE(3, 4); >+bool DoRawLog(char** buf, int* size, const char* format, ...) { >+ va_list ap; >+ va_start(ap, format); >+ int n = vsnprintf(*buf, *size, format, ap); >+ va_end(ap); >+ if (n < 0 || n > *size) return false; >+ *size -= n; >+ *buf += n; >+ return true; >+} >+ >+void RawLogVA(absl::LogSeverity severity, const char* file, int line, >+ const char* format, va_list ap) ABSL_PRINTF_ATTRIBUTE(4, 0); >+void RawLogVA(absl::LogSeverity severity, const char* file, int line, >+ const char* format, va_list ap) { >+ char buffer[kLogBufSize]; >+ char* buf = buffer; >+ int size = sizeof(buffer); >+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED >+ bool enabled = true; >+#else >+ bool enabled = false; >+#endif >+ >+#ifdef ABSL_MIN_LOG_LEVEL >+ if (severity < static_cast<absl::LogSeverity>(ABSL_MIN_LOG_LEVEL) && >+ severity < absl::LogSeverity::kFatal) { >+ enabled = false; >+ } >+#endif >+ >+ auto log_prefix_hook_ptr = log_prefix_hook.Load(); >+ if (log_prefix_hook_ptr) { >+ enabled = log_prefix_hook_ptr(severity, file, line, &buf, &size); >+ } else { >+ if (enabled) { >+ DoRawLog(&buf, &size, "[%s : %d] RAW: ", file, line); >+ } >+ } >+ const char* const prefix_end = buf; >+ >+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED >+ if (enabled) { >+ bool no_chop = VADoRawLog(&buf, &size, format, ap); >+ if (no_chop) { >+ DoRawLog(&buf, &size, "\n"); >+ } else { >+ DoRawLog(&buf, &size, "%s", kTruncated); >+ } >+ absl::raw_logging_internal::SafeWriteToStderr(buffer, strlen(buffer)); >+ } >+#else >+ static_cast<void>(format); >+ static_cast<void>(ap); >+#endif >+ >+ // Abort the process after logging a FATAL message, even if the output itself >+ // was suppressed. >+ if (severity == absl::LogSeverity::kFatal) { >+ abort_hook(file, line, buffer, prefix_end, buffer + kLogBufSize); >+ abort(); >+ } >+} >+ >+} // namespace >+ >+namespace absl { >+namespace raw_logging_internal { >+void SafeWriteToStderr(const char *s, size_t len) { >+#if defined(ABSL_HAVE_SYSCALL_WRITE) >+ syscall(SYS_write, STDERR_FILENO, s, len); >+#elif defined(ABSL_HAVE_POSIX_WRITE) >+ write(STDERR_FILENO, s, len); >+#elif defined(ABSL_HAVE_RAW_IO) >+ _write(/* stderr */ 2, s, len); >+#else >+ // stderr logging unsupported on this platform >+ (void) s; >+ (void) len; >+#endif >+} >+ >+void RawLog(absl::LogSeverity severity, const char* file, int line, >+ const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); >+void RawLog(absl::LogSeverity severity, const char* file, int line, >+ const char* format, ...) { >+ va_list ap; >+ va_start(ap, format); >+ RawLogVA(severity, file, line, format, ap); >+ va_end(ap); >+} >+ >+// Non-formatting version of RawLog(). >+// >+// TODO(gfalcon): When string_view no longer depends on base, change this >+// interface to take its message as a string_view instead. >+static void DefaultInternalLog(absl::LogSeverity severity, const char* file, >+ int line, const std::string& message) { >+ RawLog(severity, file, line, "%s", message.c_str()); >+} >+ >+bool RawLoggingFullySupported() { >+#ifdef ABSL_LOW_LEVEL_WRITE_SUPPORTED >+ return true; >+#else // !ABSL_LOW_LEVEL_WRITE_SUPPORTED >+ return false; >+#endif // !ABSL_LOW_LEVEL_WRITE_SUPPORTED >+} >+ >+ABSL_CONST_INIT absl::base_internal::AtomicHook<InternalLogFunction> >+ internal_log_function(DefaultInternalLog); >+ >+void RegisterInternalLogFunction(InternalLogFunction func) { >+ internal_log_function.Store(func); >+} >+ >+} // namespace raw_logging_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.h >new file mode 100644 >index 00000000000..67abfd30798 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/raw_logging.h >@@ -0,0 +1,180 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Thread-safe logging routines that do not allocate any memory or >+// acquire any locks, and can therefore be used by low-level memory >+// allocation, synchronization, and signal-handling code. >+ >+#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_ >+#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_ >+ >+#include <string> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/atomic_hook.h" >+#include "absl/base/log_severity.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+// This is similar to LOG(severity) << format..., but >+// * it is to be used ONLY by low-level modules that can't use normal LOG() >+// * it is designed to be a low-level logger that does not allocate any >+// memory and does not need any locks, hence: >+// * it logs straight and ONLY to STDERR w/o buffering >+// * it uses an explicit printf-format and arguments list >+// * it will silently chop off really long message strings >+// Usage example: >+// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error); >+// This will print an almost standard log line like this to stderr only: >+// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file >+#define ABSL_RAW_LOG(severity, ...) \ >+ do { \ >+ constexpr const char* absl_raw_logging_internal_basename = \ >+ ::absl::raw_logging_internal::Basename(__FILE__, \ >+ sizeof(__FILE__) - 1); \ >+ ::absl::raw_logging_internal::RawLog(ABSL_RAW_LOGGING_INTERNAL_##severity, \ >+ absl_raw_logging_internal_basename, \ >+ __LINE__, __VA_ARGS__); \ >+ } while (0) >+ >+// Similar to CHECK(condition) << message, but for low-level modules: >+// we use only ABSL_RAW_LOG that does not allocate memory. >+// We do not want to provide args list here to encourage this usage: >+// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args); >+// so that the args are not computed when not needed. >+#define ABSL_RAW_CHECK(condition, message) \ >+ do { \ >+ if (ABSL_PREDICT_FALSE(!(condition))) { \ >+ ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \ >+ } \ >+ } while (0) >+ >+// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above, >+// except that if the richer log library is linked into the binary, we dispatch >+// to that instead. This is potentially useful for internal logging and >+// assertions, where we are using RAW_LOG neither for its async-signal-safety >+// nor for its non-allocating nature, but rather because raw logging has very >+// few other dependencies. >+// >+// The API is a subset of the above: each macro only takes two arguments. Use >+// StrCat if you need to build a richer message. >+#define ABSL_INTERNAL_LOG(severity, message) \ >+ do { \ >+ constexpr const char* absl_raw_logging_internal_basename = \ >+ ::absl::raw_logging_internal::Basename(__FILE__, \ >+ sizeof(__FILE__) - 1); \ >+ ::absl::raw_logging_internal::internal_log_function( \ >+ ABSL_RAW_LOGGING_INTERNAL_##severity, \ >+ absl_raw_logging_internal_basename, __LINE__, message); \ >+ } while (0) >+ >+#define ABSL_INTERNAL_CHECK(condition, message) \ >+ do { \ >+ if (ABSL_PREDICT_FALSE(!(condition))) { \ >+ std::string death_message = "Check " #condition " failed: "; \ >+ death_message += std::string(message); \ >+ ABSL_INTERNAL_LOG(FATAL, death_message); \ >+ } \ >+ } while (0) >+ >+#define ABSL_RAW_LOGGING_INTERNAL_INFO ::absl::LogSeverity::kInfo >+#define ABSL_RAW_LOGGING_INTERNAL_WARNING ::absl::LogSeverity::kWarning >+#define ABSL_RAW_LOGGING_INTERNAL_ERROR ::absl::LogSeverity::kError >+#define ABSL_RAW_LOGGING_INTERNAL_FATAL ::absl::LogSeverity::kFatal >+#define ABSL_RAW_LOGGING_INTERNAL_LEVEL(severity) \ >+ ::absl::NormalizeLogSeverity(severity) >+ >+namespace absl { >+namespace raw_logging_internal { >+ >+// Helper function to implement ABSL_RAW_LOG >+// Logs format... at "severity" level, reporting it >+// as called from file:line. >+// This does not allocate memory or acquire locks. >+void RawLog(absl::LogSeverity severity, const char* file, int line, >+ const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5); >+ >+// Writes the provided buffer directly to stderr, in a safe, low-level manner. >+// >+// In POSIX this means calling write(), which is async-signal safe and does >+// not malloc. If the platform supports the SYS_write syscall, we invoke that >+// directly to side-step any libc interception. >+void SafeWriteToStderr(const char *s, size_t len); >+ >+// compile-time function to get the "base" filename, that is, the part of >+// a filename after the last "/" or "\" path separator. The search starts at >+// the end of the std::string; the second parameter is the length of the std::string. >+constexpr const char* Basename(const char* fname, int offset) { >+ return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\' >+ ? fname + offset >+ : Basename(fname, offset - 1); >+} >+ >+// For testing only. >+// Returns true if raw logging is fully supported. When it is not >+// fully supported, no messages will be emitted, but a log at FATAL >+// severity will cause an abort. >+// >+// TODO(gfalcon): Come up with a better name for this method. >+bool RawLoggingFullySupported(); >+ >+// Function type for a raw_logging customization hook for suppressing messages >+// by severity, and for writing custom prefixes on non-suppressed messages. >+// >+// The installed hook is called for every raw log invocation. The message will >+// be logged to stderr only if the hook returns true. FATAL errors will cause >+// the process to abort, even if writing to stderr is suppressed. The hook is >+// also provided with an output buffer, where it can write a custom log message >+// prefix. >+// >+// The raw_logging system does not allocate memory or grab locks. User-provided >+// hooks must avoid these operations, and must not throw exceptions. >+// >+// 'severity' is the severity level of the message being written. >+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro >+// was located. >+// 'buffer' and 'buf_size' are pointers to the buffer and buffer size. If the >+// hook writes a prefix, it must increment *buffer and decrement *buf_size >+// accordingly. >+using LogPrefixHook = bool (*)(absl::LogSeverity severity, const char* file, >+ int line, char** buffer, int* buf_size); >+ >+// Function type for a raw_logging customization hook called to abort a process >+// when a FATAL message is logged. If the provided AbortHook() returns, the >+// logging system will call abort(). >+// >+// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro >+// was located. >+// The null-terminated logged message lives in the buffer between 'buf_start' >+// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the >+// buffer (as written by the LogPrefixHook.) >+using AbortHook = void (*)(const char* file, int line, const char* buf_start, >+ const char* prefix_end, const char* buf_end); >+ >+// Internal logging function for ABSL_INTERNAL_LOG to dispatch to. >+// >+// TODO(gfalcon): When string_view no longer depends on base, change this >+// interface to take its message as a string_view instead. >+using InternalLogFunction = void (*)(absl::LogSeverity severity, >+ const char* file, int line, >+ const std::string& message); >+ >+extern base_internal::AtomicHook<InternalLogFunction> internal_log_function; >+ >+void RegisterInternalLogFunction(InternalLogFunction func); >+ >+} // namespace raw_logging_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/scheduling_mode.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/scheduling_mode.h >new file mode 100644 >index 00000000000..1b6497ad875 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/scheduling_mode.h >@@ -0,0 +1,54 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Core interfaces and definitions used by by low-level interfaces such as >+// SpinLock. >+ >+#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ >+#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ >+ >+namespace absl { >+namespace base_internal { >+ >+// Used to describe how a thread may be scheduled. Typically associated with >+// the declaration of a resource supporting synchronized access. >+// >+// SCHEDULE_COOPERATIVE_AND_KERNEL: >+// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may >+// reschedule (using base::scheduling semantics); allowing other cooperative >+// threads to proceed. >+// >+// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative") >+// Specifies that no cooperative scheduling semantics may be used, even if the >+// current thread is itself cooperatively scheduled. This means that >+// cooperative threads will NOT allow other cooperative threads to execute in >+// their place while waiting for a resource of this type. Host operating system >+// semantics (e.g. a futex) may still be used. >+// >+// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL >+// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which >+// base::scheduling (e.g. the implementation of a Scheduler) may depend. >+// >+// NOTE: Cooperative resources may not be nested below non-cooperative ones. >+// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL >+// resource if a SCHEDULE_KERNEL_ONLY resource is already held. >+enum SchedulingMode { >+ SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS. >+ SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling. >+}; >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.cc >new file mode 100644 >index 00000000000..1b97efbccc5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.cc >@@ -0,0 +1,228 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/spinlock.h" >+ >+#include <algorithm> >+#include <atomic> >+#include <limits> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/atomic_hook.h" >+#include "absl/base/internal/cycleclock.h" >+#include "absl/base/internal/spinlock_wait.h" >+#include "absl/base/internal/sysinfo.h" /* For NumCPUs() */ >+#include "absl/base/call_once.h" >+ >+// Description of lock-word: >+// 31..00: [............................3][2][1][0] >+// >+// [0]: kSpinLockHeld >+// [1]: kSpinLockCooperative >+// [2]: kSpinLockDisabledScheduling >+// [31..3]: ONLY kSpinLockSleeper OR >+// Wait time in cycles >> PROFILE_TIMESTAMP_SHIFT >+// >+// Detailed descriptions: >+// >+// Bit [0]: The lock is considered held iff kSpinLockHeld is set. >+// >+// Bit [1]: Eligible waiters (e.g. Fibers) may co-operatively reschedule when >+// contended iff kSpinLockCooperative is set. >+// >+// Bit [2]: This bit is exclusive from bit [1]. It is used only by a >+// non-cooperative lock. When set, indicates that scheduling was >+// successfully disabled when the lock was acquired. May be unset, >+// even if non-cooperative, if a ThreadIdentity did not yet exist at >+// time of acquisition. >+// >+// Bit [3]: If this is the only upper bit ([31..3]) set then this lock was >+// acquired without contention, however, at least one waiter exists. >+// >+// Otherwise, bits [31..3] represent the time spent by the current lock >+// holder to acquire the lock. There may be outstanding waiter(s). >+ >+namespace absl { >+namespace base_internal { >+ >+ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock, >+ int64_t wait_cycles)> >+ submit_profile_data; >+ >+void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock, >+ int64_t wait_cycles)) { >+ submit_profile_data.Store(fn); >+} >+ >+// Uncommon constructors. >+SpinLock::SpinLock(base_internal::SchedulingMode mode) >+ : lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) { >+ ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); >+} >+ >+SpinLock::SpinLock(base_internal::LinkerInitialized, >+ base_internal::SchedulingMode mode) { >+ ABSL_TSAN_MUTEX_CREATE(this, 0); >+ if (IsCooperative(mode)) { >+ InitLinkerInitializedAndCooperative(); >+ } >+ // Otherwise, lockword_ is already initialized. >+} >+ >+// Static (linker initialized) spinlocks always start life as functional >+// non-cooperative locks. When their static constructor does run, it will call >+// this initializer to augment the lockword with the cooperative bit. By >+// actually taking the lock when we do this we avoid the need for an atomic >+// operation in the regular unlock path. >+// >+// SlowLock() must be careful to re-test for this bit so that any outstanding >+// waiters may be upgraded to cooperative status. >+void SpinLock::InitLinkerInitializedAndCooperative() { >+ Lock(); >+ lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed); >+ Unlock(); >+} >+ >+// Monitor the lock to see if its value changes within some time period >+// (adaptive_spin_count loop iterations). A timestamp indicating >+// when the thread initially started waiting for the lock is passed in via >+// the initial_wait_timestamp value. The total wait time in cycles for the >+// lock is returned in the wait_cycles parameter. The last value read >+// from the lock is returned from the method. >+uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp, >+ uint32_t *wait_cycles) { >+ // We are already in the slow path of SpinLock, initialize the >+ // adaptive_spin_count here. >+ ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count; >+ ABSL_CONST_INIT static int adaptive_spin_count = 0; >+ base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() { >+ adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1; >+ }); >+ >+ int c = adaptive_spin_count; >+ uint32_t lock_value; >+ do { >+ lock_value = lockword_.load(std::memory_order_relaxed); >+ } while ((lock_value & kSpinLockHeld) != 0 && --c > 0); >+ uint32_t spin_loop_wait_cycles = >+ EncodeWaitCycles(initial_wait_timestamp, CycleClock::Now()); >+ *wait_cycles = spin_loop_wait_cycles; >+ >+ return TryLockInternal(lock_value, spin_loop_wait_cycles); >+} >+ >+void SpinLock::SlowLock() { >+ // The lock was not obtained initially, so this thread needs to wait for >+ // it. Record the current timestamp in the local variable wait_start_time >+ // so the total wait time can be stored in the lockword once this thread >+ // obtains the lock. >+ int64_t wait_start_time = CycleClock::Now(); >+ uint32_t wait_cycles; >+ uint32_t lock_value = SpinLoop(wait_start_time, &wait_cycles); >+ >+ int lock_wait_call_count = 0; >+ while ((lock_value & kSpinLockHeld) != 0) { >+ // If the lock is currently held, but not marked as having a sleeper, mark >+ // it as having a sleeper. >+ if ((lock_value & kWaitTimeMask) == 0) { >+ // Here, just "mark" that the thread is going to sleep. Don't store the >+ // lock wait time in the lock as that will cause the current lock >+ // owner to think it experienced contention. >+ if (lockword_.compare_exchange_strong( >+ lock_value, lock_value | kSpinLockSleeper, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ // Successfully transitioned to kSpinLockSleeper. Pass >+ // kSpinLockSleeper to the SpinLockWait routine to properly indicate >+ // the last lock_value observed. >+ lock_value |= kSpinLockSleeper; >+ } else if ((lock_value & kSpinLockHeld) == 0) { >+ // Lock is free again, so try and acquire it before sleeping. The >+ // new lock state will be the number of cycles this thread waited if >+ // this thread obtains the lock. >+ lock_value = TryLockInternal(lock_value, wait_cycles); >+ continue; // Skip the delay at the end of the loop. >+ } >+ } >+ >+ base_internal::SchedulingMode scheduling_mode; >+ if ((lock_value & kSpinLockCooperative) != 0) { >+ scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL; >+ } else { >+ scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY; >+ } >+ // SpinLockDelay() calls into fiber scheduler, we need to see >+ // synchronization there to avoid false positives. >+ ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); >+ // Wait for an OS specific delay. >+ base_internal::SpinLockDelay(&lockword_, lock_value, ++lock_wait_call_count, >+ scheduling_mode); >+ ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); >+ // Spin again after returning from the wait routine to give this thread >+ // some chance of obtaining the lock. >+ lock_value = SpinLoop(wait_start_time, &wait_cycles); >+ } >+} >+ >+void SpinLock::SlowUnlock(uint32_t lock_value) { >+ base_internal::SpinLockWake(&lockword_, >+ false); // wake waiter if necessary >+ >+ // If our acquisition was contended, collect contentionz profile info. We >+ // reserve a unitary wait time to represent that a waiter exists without our >+ // own acquisition having been contended. >+ if ((lock_value & kWaitTimeMask) != kSpinLockSleeper) { >+ const uint64_t wait_cycles = DecodeWaitCycles(lock_value); >+ ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); >+ submit_profile_data(this, wait_cycles); >+ ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); >+ } >+} >+ >+// We use the upper 29 bits of the lock word to store the time spent waiting to >+// acquire this lock. This is reported by contentionz profiling. Since the >+// lower bits of the cycle counter wrap very quickly on high-frequency >+// processors we divide to reduce the granularity to 2^PROFILE_TIMESTAMP_SHIFT >+// sized units. On a 4Ghz machine this will lose track of wait times greater >+// than (2^29/4 Ghz)*128 =~ 17.2 seconds. Such waits should be extremely rare. >+enum { PROFILE_TIMESTAMP_SHIFT = 7 }; >+enum { LOCKWORD_RESERVED_SHIFT = 3 }; // We currently reserve the lower 3 bits. >+ >+uint32_t SpinLock::EncodeWaitCycles(int64_t wait_start_time, >+ int64_t wait_end_time) { >+ static const int64_t kMaxWaitTime = >+ std::numeric_limits<uint32_t>::max() >> LOCKWORD_RESERVED_SHIFT; >+ int64_t scaled_wait_time = >+ (wait_end_time - wait_start_time) >> PROFILE_TIMESTAMP_SHIFT; >+ >+ // Return a representation of the time spent waiting that can be stored in >+ // the lock word's upper bits. bit_cast is required as Atomic32 is signed. >+ const uint32_t clamped = static_cast<uint32_t>( >+ std::min(scaled_wait_time, kMaxWaitTime) << LOCKWORD_RESERVED_SHIFT); >+ >+ // bump up value if necessary to avoid returning kSpinLockSleeper. >+ const uint32_t after_spinlock_sleeper = >+ kSpinLockSleeper + (1 << LOCKWORD_RESERVED_SHIFT); >+ return clamped == kSpinLockSleeper ? after_spinlock_sleeper : clamped; >+} >+ >+uint64_t SpinLock::DecodeWaitCycles(uint32_t lock_value) { >+ // Cast to uint32_t first to ensure bits [63:32] are cleared. >+ const uint64_t scaled_wait_time = >+ static_cast<uint32_t>(lock_value & kWaitTimeMask); >+ return scaled_wait_time >+ << (PROFILE_TIMESTAMP_SHIFT - LOCKWORD_RESERVED_SHIFT); >+} >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.h >new file mode 100644 >index 00000000000..212abc669e6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock.h >@@ -0,0 +1,239 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// Most users requiring mutual exclusion should use Mutex. >+// SpinLock is provided for use in three situations: >+// - for use in code that Mutex itself depends on >+// - to get a faster fast-path release under low contention (without an >+// atomic read-modify-write) In return, SpinLock has worse behaviour under >+// contention, which is why Mutex is preferred in most situations. >+// - for async signal safety (see below) >+ >+// SpinLock is async signal safe. If a spinlock is used within a signal >+// handler, all code that acquires the lock must ensure that the signal cannot >+// arrive while they are holding the lock. Typically, this is done by blocking >+// the signal. >+ >+#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_ >+#define ABSL_BASE_INTERNAL_SPINLOCK_H_ >+ >+#include <stdint.h> >+#include <sys/types.h> >+#include <atomic> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/low_level_scheduling.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/internal/tsan_mutex_interface.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/base/thread_annotations.h" >+ >+namespace absl { >+namespace base_internal { >+ >+class LOCKABLE SpinLock { >+ public: >+ SpinLock() : lockword_(kSpinLockCooperative) { >+ ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); >+ } >+ >+ // Special constructor for use with static SpinLock objects. E.g., >+ // >+ // static SpinLock lock(base_internal::kLinkerInitialized); >+ // >+ // When intialized using this constructor, we depend on the fact >+ // that the linker has already initialized the memory appropriately. >+ // A SpinLock constructed like this can be freely used from global >+ // initializers without worrying about the order in which global >+ // initializers run. >+ explicit SpinLock(base_internal::LinkerInitialized) { >+ // Does nothing; lockword_ is already initialized >+ ABSL_TSAN_MUTEX_CREATE(this, 0); >+ } >+ >+ // Constructors that allow non-cooperative spinlocks to be created for use >+ // inside thread schedulers. Normal clients should not use these. >+ explicit SpinLock(base_internal::SchedulingMode mode); >+ SpinLock(base_internal::LinkerInitialized, >+ base_internal::SchedulingMode mode); >+ >+ ~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); } >+ >+ // Acquire this SpinLock. >+ inline void Lock() EXCLUSIVE_LOCK_FUNCTION() { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); >+ if (!TryLockImpl()) { >+ SlowLock(); >+ } >+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); >+ } >+ >+ // Try to acquire this SpinLock without blocking and return true if the >+ // acquisition was successful. If the lock was not acquired, false is >+ // returned. If this SpinLock is free at the time of the call, TryLock >+ // will return true with high probability. >+ inline bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock); >+ bool res = TryLockImpl(); >+ ABSL_TSAN_MUTEX_POST_LOCK( >+ this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed), >+ 0); >+ return res; >+ } >+ >+ // Release this SpinLock, which must be held by the calling thread. >+ inline void Unlock() UNLOCK_FUNCTION() { >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); >+ uint32_t lock_value = lockword_.load(std::memory_order_relaxed); >+ lockword_.store(lock_value & kSpinLockCooperative, >+ std::memory_order_release); >+ >+ if ((lock_value & kSpinLockDisabledScheduling) != 0) { >+ base_internal::SchedulingGuard::EnableRescheduling(true); >+ } >+ if ((lock_value & kWaitTimeMask) != 0) { >+ // Collect contentionz profile info, and speed the wakeup of any waiter. >+ // The wait_cycles value indicates how long this thread spent waiting >+ // for the lock. >+ SlowUnlock(lock_value); >+ } >+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0); >+ } >+ >+ // Determine if the lock is held. When the lock is held by the invoking >+ // thread, true will always be returned. Intended to be used as >+ // CHECK(lock.IsHeld()). >+ inline bool IsHeld() const { >+ return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0; >+ } >+ >+ protected: >+ // These should not be exported except for testing. >+ >+ // Store number of cycles between wait_start_time and wait_end_time in a >+ // lock value. >+ static uint32_t EncodeWaitCycles(int64_t wait_start_time, >+ int64_t wait_end_time); >+ >+ // Extract number of wait cycles in a lock value. >+ static uint64_t DecodeWaitCycles(uint32_t lock_value); >+ >+ // Provide access to protected method above. Use for testing only. >+ friend struct SpinLockTest; >+ >+ private: >+ // lockword_ is used to store the following: >+ // >+ // bit[0] encodes whether a lock is being held. >+ // bit[1] encodes whether a lock uses cooperative scheduling. >+ // bit[2] encodes whether a lock disables scheduling. >+ // bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int. >+ enum { kSpinLockHeld = 1 }; >+ enum { kSpinLockCooperative = 2 }; >+ enum { kSpinLockDisabledScheduling = 4 }; >+ enum { kSpinLockSleeper = 8 }; >+ enum { kWaitTimeMask = // Includes kSpinLockSleeper. >+ ~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling) }; >+ >+ // Returns true if the provided scheduling mode is cooperative. >+ static constexpr bool IsCooperative( >+ base_internal::SchedulingMode scheduling_mode) { >+ return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL; >+ } >+ >+ uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles); >+ void InitLinkerInitializedAndCooperative(); >+ void SlowLock() ABSL_ATTRIBUTE_COLD; >+ void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD; >+ uint32_t SpinLoop(int64_t initial_wait_timestamp, uint32_t* wait_cycles); >+ >+ inline bool TryLockImpl() { >+ uint32_t lock_value = lockword_.load(std::memory_order_relaxed); >+ return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0; >+ } >+ >+ std::atomic<uint32_t> lockword_; >+ >+ SpinLock(const SpinLock&) = delete; >+ SpinLock& operator=(const SpinLock&) = delete; >+}; >+ >+// Corresponding locker object that arranges to acquire a spinlock for >+// the duration of a C++ scope. >+class SCOPED_LOCKABLE SpinLockHolder { >+ public: >+ inline explicit SpinLockHolder(SpinLock* l) EXCLUSIVE_LOCK_FUNCTION(l) >+ : lock_(l) { >+ l->Lock(); >+ } >+ inline ~SpinLockHolder() UNLOCK_FUNCTION() { lock_->Unlock(); } >+ >+ SpinLockHolder(const SpinLockHolder&) = delete; >+ SpinLockHolder& operator=(const SpinLockHolder&) = delete; >+ >+ private: >+ SpinLock* lock_; >+}; >+ >+// Register a hook for profiling support. >+// >+// The function pointer registered here will be called whenever a spinlock is >+// contended. The callback is given an opaque handle to the contended spinlock >+// and the number of wait cycles. This is thread-safe, but only a single >+// profiler can be registered. It is an error to call this function multiple >+// times with different arguments. >+void RegisterSpinLockProfiler(void (*fn)(const void* lock, >+ int64_t wait_cycles)); >+ >+//------------------------------------------------------------------------------ >+// Public interface ends here. >+//------------------------------------------------------------------------------ >+ >+// If (result & kSpinLockHeld) == 0, then *this was successfully locked. >+// Otherwise, returns last observed value for lockword_. >+inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value, >+ uint32_t wait_cycles) { >+ if ((lock_value & kSpinLockHeld) != 0) { >+ return lock_value; >+ } >+ >+ uint32_t sched_disabled_bit = 0; >+ if ((lock_value & kSpinLockCooperative) == 0) { >+ // For non-cooperative locks we must make sure we mark ourselves as >+ // non-reschedulable before we attempt to CompareAndSwap. >+ if (base_internal::SchedulingGuard::DisableRescheduling()) { >+ sched_disabled_bit = kSpinLockDisabledScheduling; >+ } >+ } >+ >+ if (lockword_.compare_exchange_strong( >+ lock_value, >+ kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ } else { >+ base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0); >+ } >+ >+ return lock_value; >+} >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc >new file mode 100644 >index 00000000000..051c8cf87fb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_akaros.inc >@@ -0,0 +1,35 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file is an Akaros-specific part of spinlock_wait.cc >+ >+#include <atomic> >+ >+#include "absl/base/internal/scheduling_mode.h" >+ >+extern "C" { >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( >+ std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, >+ int /* loop */, absl::base_internal::SchedulingMode /* mode */) { >+ // In Akaros, one must take care not to call anything that could cause a >+ // malloc(), a blocking system call, or a uthread_yield() while holding a >+ // spinlock. Our callers assume will not call into libraries or other >+ // arbitrary code. >+} >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( >+ std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} >+ >+} // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc >new file mode 100644 >index 00000000000..0098c1c7601 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_posix.inc >@@ -0,0 +1,46 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file is a Posix-specific part of spinlock_wait.cc >+ >+#include <sched.h> >+#include <atomic> >+#include <ctime> >+#include <cerrno> >+ >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/port.h" >+ >+extern "C" { >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockDelay( >+ std::atomic<uint32_t>* /* lock_word */, uint32_t /* value */, int loop, >+ absl::base_internal::SchedulingMode /* mode */) { >+ int save_errno = errno; >+ if (loop == 0) { >+ } else if (loop == 1) { >+ sched_yield(); >+ } else { >+ struct timespec tm; >+ tm.tv_sec = 0; >+ tm.tv_nsec = absl::base_internal::SpinLockSuggestedDelayNS(loop); >+ nanosleep(&tm, nullptr); >+ } >+ errno = save_errno; >+} >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalSpinLockWake( >+ std::atomic<uint32_t>* /* lock_word */, bool /* all */) {} >+ >+} // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc >new file mode 100644 >index 00000000000..9f6e9911e10 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.cc >@@ -0,0 +1,79 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// The OS-specific header included below must provide two calls: >+// base::subtle::SpinLockDelay() and base::subtle::SpinLockWake(). >+// See spinlock_wait.h for the specs. >+ >+#include <atomic> >+#include <cstdint> >+ >+#include "absl/base/internal/spinlock_wait.h" >+ >+#if defined(_WIN32) >+#include "absl/base/internal/spinlock_win32.inc" >+#elif defined(__akaros__) >+#include "absl/base/internal/spinlock_akaros.inc" >+#else >+#include "absl/base/internal/spinlock_posix.inc" >+#endif >+ >+namespace absl { >+namespace base_internal { >+ >+// See spinlock_wait.h for spec. >+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, >+ const SpinLockWaitTransition trans[], >+ base_internal::SchedulingMode scheduling_mode) { >+ for (int loop = 0; ; loop++) { >+ uint32_t v = w->load(std::memory_order_acquire); >+ int i; >+ for (i = 0; i != n && v != trans[i].from; i++) { >+ } >+ if (i == n) { >+ SpinLockDelay(w, v, loop, scheduling_mode); // no matching transition >+ } else if (trans[i].to == v || // null transition >+ w->compare_exchange_strong(v, trans[i].to, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ if (trans[i].done) return v; >+ } >+ } >+} >+ >+static std::atomic<uint64_t> delay_rand; >+ >+// Return a suggested delay in nanoseconds for iteration number "loop" >+int SpinLockSuggestedDelayNS(int loop) { >+ // Weak pseudo-random number generator to get some spread between threads >+ // when many are spinning. >+ uint64_t r = delay_rand.load(std::memory_order_relaxed); >+ r = 0x5deece66dLL * r + 0xb; // numbers from nrand48() >+ delay_rand.store(r, std::memory_order_relaxed); >+ >+ r <<= 16; // 48-bit random number now in top 48-bits. >+ if (loop < 0 || loop > 32) { // limit loop to 0..32 >+ loop = 32; >+ } >+ // loop>>3 cannot exceed 4 because loop cannot exceed 32. >+ // Select top 20..24 bits of lower 48 bits, >+ // giving approximately 0ms to 16ms. >+ // Mean is exponential in loop for first 32 iterations, then 8ms. >+ // The futex path multiplies this by 16, since we expect explicit wakeups >+ // almost always on that path. >+ return static_cast<int>(r >> (44 - (loop >> 3))); >+} >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h >new file mode 100644 >index 00000000000..5c6cc7fdba4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_wait.h >@@ -0,0 +1,91 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ >+#define ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ >+ >+// Operations to make atomic transitions on a word, and to allow >+// waiting for those transitions to become possible. >+ >+#include <stdint.h> >+#include <atomic> >+ >+#include "absl/base/internal/scheduling_mode.h" >+ >+namespace absl { >+namespace base_internal { >+ >+// SpinLockWait() waits until it can perform one of several transitions from >+// "from" to "to". It returns when it performs a transition where done==true. >+struct SpinLockWaitTransition { >+ uint32_t from; >+ uint32_t to; >+ bool done; >+}; >+ >+// Wait until *w can transition from trans[i].from to trans[i].to for some i >+// satisfying 0<=i<n && trans[i].done, atomically make the transition, >+// then return the old value of *w. Make any other atomic transitions >+// where !trans[i].done, but continue waiting. >+uint32_t SpinLockWait(std::atomic<uint32_t> *w, int n, >+ const SpinLockWaitTransition trans[], >+ SchedulingMode scheduling_mode); >+ >+// If possible, wake some thread that has called SpinLockDelay(w, ...). If >+// "all" is true, wake all such threads. This call is a hint, and on some >+// systems it may be a no-op; threads calling SpinLockDelay() will always wake >+// eventually even if SpinLockWake() is never called. >+void SpinLockWake(std::atomic<uint32_t> *w, bool all); >+ >+// Wait for an appropriate spin delay on iteration "loop" of a >+// spin loop on location *w, whose previously observed value was "value". >+// SpinLockDelay() may do nothing, may yield the CPU, may sleep a clock tick, >+// or may wait for a delay that can be truncated by a call to SpinLockWake(w). >+// In all cases, it must return in bounded time even if SpinLockWake() is not >+// called. >+void SpinLockDelay(std::atomic<uint32_t> *w, uint32_t value, int loop, >+ base_internal::SchedulingMode scheduling_mode); >+ >+// Helper used by AbslInternalSpinLockDelay. >+// Returns a suggested delay in nanoseconds for iteration number "loop". >+int SpinLockSuggestedDelayNS(int loop); >+ >+} // namespace base_internal >+} // namespace absl >+ >+// In some build configurations we pass --detect-odr-violations to the >+// gold linker. This causes it to flag weak symbol overrides as ODR >+// violations. Because ODR only applies to C++ and not C, >+// --detect-odr-violations ignores symbols not mangled with C++ names. >+// By changing our extension points to be extern "C", we dodge this >+// check. >+extern "C" { >+void AbslInternalSpinLockWake(std::atomic<uint32_t> *w, bool all); >+void AbslInternalSpinLockDelay( >+ std::atomic<uint32_t> *w, uint32_t value, int loop, >+ absl::base_internal::SchedulingMode scheduling_mode); >+} >+ >+inline void absl::base_internal::SpinLockWake(std::atomic<uint32_t> *w, >+ bool all) { >+ AbslInternalSpinLockWake(w, all); >+} >+ >+inline void absl::base_internal::SpinLockDelay( >+ std::atomic<uint32_t> *w, uint32_t value, int loop, >+ absl::base_internal::SchedulingMode scheduling_mode) { >+ AbslInternalSpinLockDelay(w, value, loop, scheduling_mode); >+} >+ >+#endif // ABSL_BASE_INTERNAL_SPINLOCK_WAIT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc >new file mode 100644 >index 00000000000..32c8fc0bb51 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/spinlock_win32.inc >@@ -0,0 +1,37 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file is a Win32-specific part of spinlock_wait.cc >+ >+#include <windows.h> >+#include <atomic> >+#include "absl/base/internal/scheduling_mode.h" >+ >+extern "C" { >+ >+void AbslInternalSpinLockDelay(std::atomic<uint32_t>* /* lock_word */, >+ uint32_t /* value */, int loop, >+ absl::base_internal::SchedulingMode /* mode */) { >+ if (loop == 0) { >+ } else if (loop == 1) { >+ Sleep(0); >+ } else { >+ Sleep(absl::base_internal::SpinLockSuggestedDelayNS(loop) / 1000000); >+ } >+} >+ >+void AbslInternalSpinLockWake(std::atomic<uint32_t>* /* lock_word */, >+ bool /* all */) {} >+ >+} // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.cc >new file mode 100644 >index 00000000000..db41bacc844 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.cc >@@ -0,0 +1,404 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/sysinfo.h" >+ >+#include "absl/base/attributes.h" >+ >+#ifdef _WIN32 >+#include <shlwapi.h> >+#include <windows.h> >+#else >+#include <fcntl.h> >+#include <pthread.h> >+#include <sys/stat.h> >+#include <sys/types.h> >+#include <unistd.h> >+#endif >+ >+#ifdef __linux__ >+#include <sys/syscall.h> >+#endif >+ >+#if defined(__APPLE__) || defined(__FreeBSD__) >+#include <sys/sysctl.h> >+#endif >+ >+#if defined(__myriad2__) >+#include <rtems.h> >+#endif >+ >+#include <string.h> >+#include <cassert> >+#include <cstdint> >+#include <cstdio> >+#include <cstdlib> >+#include <ctime> >+#include <limits> >+#include <thread> // NOLINT(build/c++11) >+#include <utility> >+#include <vector> >+ >+#include "absl/base/call_once.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/internal/unscaledcycleclock.h" >+ >+namespace absl { >+namespace base_internal { >+ >+static once_flag init_system_info_once; >+static int num_cpus = 0; >+static double nominal_cpu_frequency = 1.0; // 0.0 might be dangerous. >+ >+static int GetNumCPUs() { >+#if defined(__myriad2__) >+ return 1; >+#else >+ // Other possibilities: >+ // - Read /sys/devices/system/cpu/online and use cpumask_parse() >+ // - sysconf(_SC_NPROCESSORS_ONLN) >+ return std::thread::hardware_concurrency(); >+#endif >+} >+ >+#if defined(_WIN32) >+ >+static double GetNominalCPUFrequency() { >+ DWORD data; >+ DWORD data_size = sizeof(data); >+ #pragma comment(lib, "shlwapi.lib") // For SHGetValue(). >+ if (SUCCEEDED( >+ SHGetValueA(HKEY_LOCAL_MACHINE, >+ "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", >+ "~MHz", nullptr, &data, &data_size))) { >+ return data * 1e6; // Value is MHz. >+ } >+ return 1.0; >+} >+ >+#elif defined(CTL_HW) && defined(HW_CPU_FREQ) >+ >+static double GetNominalCPUFrequency() { >+ unsigned freq; >+ size_t size = sizeof(freq); >+ int mib[2] = {CTL_HW, HW_CPU_FREQ}; >+ if (sysctl(mib, 2, &freq, &size, nullptr, 0) == 0) { >+ return static_cast<double>(freq); >+ } >+ return 1.0; >+} >+ >+#else >+ >+// Helper function for reading a long from a file. Returns true if successful >+// and the memory location pointed to by value is set to the value read. >+static bool ReadLongFromFile(const char *file, long *value) { >+ bool ret = false; >+ int fd = open(file, O_RDONLY); >+ if (fd != -1) { >+ char line[1024]; >+ char *err; >+ memset(line, '\0', sizeof(line)); >+ int len = read(fd, line, sizeof(line) - 1); >+ if (len <= 0) { >+ ret = false; >+ } else { >+ const long temp_value = strtol(line, &err, 10); >+ if (line[0] != '\0' && (*err == '\n' || *err == '\0')) { >+ *value = temp_value; >+ ret = true; >+ } >+ } >+ close(fd); >+ } >+ return ret; >+} >+ >+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY) >+ >+// Reads a monotonic time source and returns a value in >+// nanoseconds. The returned value uses an arbitrary epoch, not the >+// Unix epoch. >+static int64_t ReadMonotonicClockNanos() { >+ struct timespec t; >+#ifdef CLOCK_MONOTONIC_RAW >+ int rc = clock_gettime(CLOCK_MONOTONIC_RAW, &t); >+#else >+ int rc = clock_gettime(CLOCK_MONOTONIC, &t); >+#endif >+ if (rc != 0) { >+ perror("clock_gettime() failed"); >+ abort(); >+ } >+ return int64_t{t.tv_sec} * 1000000000 + t.tv_nsec; >+} >+ >+class UnscaledCycleClockWrapperForInitializeFrequency { >+ public: >+ static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); } >+}; >+ >+struct TimeTscPair { >+ int64_t time; // From ReadMonotonicClockNanos(). >+ int64_t tsc; // From UnscaledCycleClock::Now(). >+}; >+ >+// Returns a pair of values (monotonic kernel time, TSC ticks) that >+// approximately correspond to each other. This is accomplished by >+// doing several reads and picking the reading with the lowest >+// latency. This approach is used to minimize the probability that >+// our thread was preempted between clock reads. >+static TimeTscPair GetTimeTscPair() { >+ int64_t best_latency = std::numeric_limits<int64_t>::max(); >+ TimeTscPair best; >+ for (int i = 0; i < 10; ++i) { >+ int64_t t0 = ReadMonotonicClockNanos(); >+ int64_t tsc = UnscaledCycleClockWrapperForInitializeFrequency::Now(); >+ int64_t t1 = ReadMonotonicClockNanos(); >+ int64_t latency = t1 - t0; >+ if (latency < best_latency) { >+ best_latency = latency; >+ best.time = t0; >+ best.tsc = tsc; >+ } >+ } >+ return best; >+} >+ >+// Measures and returns the TSC frequency by taking a pair of >+// measurements approximately `sleep_nanoseconds` apart. >+static double MeasureTscFrequencyWithSleep(int sleep_nanoseconds) { >+ auto t0 = GetTimeTscPair(); >+ struct timespec ts; >+ ts.tv_sec = 0; >+ ts.tv_nsec = sleep_nanoseconds; >+ while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {} >+ auto t1 = GetTimeTscPair(); >+ double elapsed_ticks = t1.tsc - t0.tsc; >+ double elapsed_time = (t1.time - t0.time) * 1e-9; >+ return elapsed_ticks / elapsed_time; >+} >+ >+// Measures and returns the TSC frequency by calling >+// MeasureTscFrequencyWithSleep(), doubling the sleep interval until the >+// frequency measurement stabilizes. >+static double MeasureTscFrequency() { >+ double last_measurement = -1.0; >+ int sleep_nanoseconds = 1000000; // 1 millisecond. >+ for (int i = 0; i < 8; ++i) { >+ double measurement = MeasureTscFrequencyWithSleep(sleep_nanoseconds); >+ if (measurement * 0.99 < last_measurement && >+ last_measurement < measurement * 1.01) { >+ // Use the current measurement if it is within 1% of the >+ // previous measurement. >+ return measurement; >+ } >+ last_measurement = measurement; >+ sleep_nanoseconds *= 2; >+ } >+ return last_measurement; >+} >+ >+#endif // ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY >+ >+static double GetNominalCPUFrequency() { >+ long freq = 0; >+ >+ // Google's production kernel has a patch to export the TSC >+ // frequency through sysfs. If the kernel is exporting the TSC >+ // frequency use that. There are issues where cpuinfo_max_freq >+ // cannot be relied on because the BIOS may be exporting an invalid >+ // p-state (on x86) or p-states may be used to put the processor in >+ // a new mode (turbo mode). Essentially, those frequencies cannot >+ // always be relied upon. The same reasons apply to /proc/cpuinfo as >+ // well. >+ if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) { >+ return freq * 1e3; // Value is kHz. >+ } >+ >+#if defined(ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY) >+ // On these platforms, the TSC frequency is the nominal CPU >+ // frequency. But without having the kernel export it directly >+ // though /sys/devices/system/cpu/cpu0/tsc_freq_khz, there is no >+ // other way to reliably get the TSC frequency, so we have to >+ // measure it ourselves. Some CPUs abuse cpuinfo_max_freq by >+ // exporting "fake" frequencies for implementing new features. For >+ // example, Intel's turbo mode is enabled by exposing a p-state >+ // value with a higher frequency than that of the real TSC >+ // rate. Because of this, we prefer to measure the TSC rate >+ // ourselves on i386 and x86-64. >+ return MeasureTscFrequency(); >+#else >+ >+ // If CPU scaling is in effect, we want to use the *maximum* >+ // frequency, not whatever CPU speed some random processor happens >+ // to be using now. >+ if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", >+ &freq)) { >+ return freq * 1e3; // Value is kHz. >+ } >+ >+ return 1.0; >+#endif // !ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY >+} >+ >+#endif >+ >+// InitializeSystemInfo() may be called before main() and before >+// malloc is properly initialized, therefore this must not allocate >+// memory. >+static void InitializeSystemInfo() { >+ num_cpus = GetNumCPUs(); >+ nominal_cpu_frequency = GetNominalCPUFrequency(); >+} >+ >+int NumCPUs() { >+ base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo); >+ return num_cpus; >+} >+ >+double NominalCPUFrequency() { >+ base_internal::LowLevelCallOnce(&init_system_info_once, InitializeSystemInfo); >+ return nominal_cpu_frequency; >+} >+ >+#if defined(_WIN32) >+ >+pid_t GetTID() { >+ return GetCurrentThreadId(); >+} >+ >+#elif defined(__linux__) >+ >+#ifndef SYS_gettid >+#define SYS_gettid __NR_gettid >+#endif >+ >+pid_t GetTID() { >+ return syscall(SYS_gettid); >+} >+ >+#elif defined(__akaros__) >+ >+pid_t GetTID() { >+ // Akaros has a concept of "vcore context", which is the state the program >+ // is forced into when we need to make a user-level scheduling decision, or >+ // run a signal handler. This is analogous to the interrupt context that a >+ // CPU might enter if it encounters some kind of exception. >+ // >+ // There is no current thread context in vcore context, but we need to give >+ // a reasonable answer if asked for a thread ID (e.g., in a signal handler). >+ // Thread 0 always exists, so if we are in vcore context, we return that. >+ // >+ // Otherwise, we know (since we are using pthreads) that the uthread struct >+ // current_uthread is pointing to is the first element of a >+ // struct pthread_tcb, so we extract and return the thread ID from that. >+ // >+ // TODO(dcross): Akaros anticipates moving the thread ID to the uthread >+ // structure at some point. We should modify this code to remove the cast >+ // when that happens. >+ if (in_vcore_context()) >+ return 0; >+ return reinterpret_cast<struct pthread_tcb *>(current_uthread)->id; >+} >+ >+#elif defined(__myriad2__) >+ >+pid_t GetTID() { >+ uint32_t tid; >+ rtems_task_ident(RTEMS_SELF, 0, &tid); >+ return tid; >+} >+ >+#else >+ >+// Fallback implementation of GetTID using pthread_getspecific. >+static once_flag tid_once; >+static pthread_key_t tid_key; >+static absl::base_internal::SpinLock tid_lock( >+ absl::base_internal::kLinkerInitialized); >+ >+// We set a bit per thread in this array to indicate that an ID is in >+// use. ID 0 is unused because it is the default value returned by >+// pthread_getspecific(). >+static std::vector<uint32_t>* tid_array GUARDED_BY(tid_lock) = nullptr; >+static constexpr int kBitsPerWord = 32; // tid_array is uint32_t. >+ >+// Returns the TID to tid_array. >+static void FreeTID(void *v) { >+ intptr_t tid = reinterpret_cast<intptr_t>(v); >+ int word = tid / kBitsPerWord; >+ uint32_t mask = ~(1u << (tid % kBitsPerWord)); >+ absl::base_internal::SpinLockHolder lock(&tid_lock); >+ assert(0 <= word && static_cast<size_t>(word) < tid_array->size()); >+ (*tid_array)[word] &= mask; >+} >+ >+static void InitGetTID() { >+ if (pthread_key_create(&tid_key, FreeTID) != 0) { >+ // The logging system calls GetTID() so it can't be used here. >+ perror("pthread_key_create failed"); >+ abort(); >+ } >+ >+ // Initialize tid_array. >+ absl::base_internal::SpinLockHolder lock(&tid_lock); >+ tid_array = new std::vector<uint32_t>(1); >+ (*tid_array)[0] = 1; // ID 0 is never-allocated. >+} >+ >+// Return a per-thread small integer ID from pthread's thread-specific data. >+pid_t GetTID() { >+ absl::call_once(tid_once, InitGetTID); >+ >+ intptr_t tid = reinterpret_cast<intptr_t>(pthread_getspecific(tid_key)); >+ if (tid != 0) { >+ return tid; >+ } >+ >+ int bit; // tid_array[word] = 1u << bit; >+ size_t word; >+ { >+ // Search for the first unused ID. >+ absl::base_internal::SpinLockHolder lock(&tid_lock); >+ // First search for a word in the array that is not all ones. >+ word = 0; >+ while (word < tid_array->size() && ~(*tid_array)[word] == 0) { >+ ++word; >+ } >+ if (word == tid_array->size()) { >+ tid_array->push_back(0); // No space left, add kBitsPerWord more IDs. >+ } >+ // Search for a zero bit in the word. >+ bit = 0; >+ while (bit < kBitsPerWord && (((*tid_array)[word] >> bit) & 1) != 0) { >+ ++bit; >+ } >+ tid = (word * kBitsPerWord) + bit; >+ (*tid_array)[word] |= 1u << bit; // Mark the TID as allocated. >+ } >+ >+ if (pthread_setspecific(tid_key, reinterpret_cast<void *>(tid)) != 0) { >+ perror("pthread_setspecific failed"); >+ abort(); >+ } >+ >+ return static_cast<pid_t>(tid); >+} >+ >+#endif >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.h >new file mode 100644 >index 00000000000..5bd1c500bd5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo.h >@@ -0,0 +1,63 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file includes routines to find out characteristics >+// of the machine a program is running on. It is undoubtedly >+// system-dependent. >+ >+// Functions listed here that accept a pid_t as an argument act on the >+// current process if the pid_t argument is 0 >+// All functions here are thread-hostile due to file caching unless >+// commented otherwise. >+ >+#ifndef ABSL_BASE_INTERNAL_SYSINFO_H_ >+#define ABSL_BASE_INTERNAL_SYSINFO_H_ >+ >+#ifndef _WIN32 >+#include <sys/types.h> >+#else >+#include <intsafe.h> >+#endif >+ >+#include "absl/base/port.h" >+ >+namespace absl { >+namespace base_internal { >+ >+// Nominal core processor cycles per second of each processor. This is _not_ >+// necessarily the frequency of the CycleClock counter (see cycleclock.h) >+// Thread-safe. >+double NominalCPUFrequency(); >+ >+// Number of logical processors (hyperthreads) in system. Thread-safe. >+int NumCPUs(); >+ >+// Return the thread id of the current thread, as told by the system. >+// No two currently-live threads implemented by the OS shall have the same ID. >+// Thread ids of exited threads may be reused. Multiple user-level threads >+// may have the same thread ID if multiplexed on the same OS thread. >+// >+// On Linux, you may send a signal to the resulting ID with kill(). However, >+// it is recommended for portability that you use pthread_kill() instead. >+#ifdef _WIN32 >+// On Windows, process id and thread id are of the same type according to >+// the return types of GetProcessId() and GetThreadId() are both DWORD. >+using pid_t = DWORD; >+#endif >+pid_t GetTID(); >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_SYSINFO_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc >new file mode 100644 >index 00000000000..e0d9aab9bc2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/sysinfo_test.cc >@@ -0,0 +1,98 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/sysinfo.h" >+ >+#ifndef _WIN32 >+#include <sys/types.h> >+#include <unistd.h> >+#endif >+ >+#include <thread> // NOLINT(build/c++11) >+#include <unordered_set> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/synchronization/barrier.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+namespace base_internal { >+namespace { >+ >+TEST(SysinfoTest, NumCPUs) { >+ EXPECT_NE(NumCPUs(), 0) >+ << "NumCPUs() should not have the default value of 0"; >+} >+ >+TEST(SysinfoTest, NominalCPUFrequency) { >+#if !(defined(__aarch64__) && defined(__linux__)) >+ EXPECT_GE(NominalCPUFrequency(), 1000.0) >+ << "NominalCPUFrequency() did not return a reasonable value"; >+#else >+ // TODO(absl-team): Aarch64 cannot read the CPU frequency from sysfs, so we >+ // get back 1.0. Fix once the value is available. >+ EXPECT_EQ(NominalCPUFrequency(), 1.0) >+ << "CPU frequency detection was fixed! Please update unittest."; >+#endif >+} >+ >+TEST(SysinfoTest, GetTID) { >+ EXPECT_EQ(GetTID(), GetTID()); // Basic compile and equality test. >+#ifdef __native_client__ >+ // Native Client has a race condition bug that leads to memory >+ // exaustion when repeatedly creating and joining threads. >+ // https://bugs.chromium.org/p/nativeclient/issues/detail?id=1027 >+ return; >+#endif >+ // Test that TIDs are unique to each thread. >+ // Uses a few loops to exercise implementations that reallocate IDs. >+ for (int i = 0; i < 32; ++i) { >+ constexpr int kNumThreads = 64; >+ Barrier all_threads_done(kNumThreads); >+ std::vector<std::thread> threads; >+ >+ Mutex mutex; >+ std::unordered_set<pid_t> tids; >+ >+ for (int j = 0; j < kNumThreads; ++j) { >+ threads.push_back(std::thread([&]() { >+ pid_t id = GetTID(); >+ { >+ MutexLock lock(&mutex); >+ ASSERT_TRUE(tids.find(id) == tids.end()); >+ tids.insert(id); >+ } >+ // We can't simply join the threads here. The threads need to >+ // be alive otherwise the TID might have been reallocated to >+ // another live thread. >+ all_threads_done.Block(); >+ })); >+ } >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ } >+} >+ >+#ifdef __linux__ >+TEST(SysinfoTest, LinuxGetTID) { >+ // On Linux, for the main thread, GetTID()==getpid() is guaranteed by the API. >+ EXPECT_EQ(GetTID(), getpid()); >+} >+#endif >+ >+} // namespace >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.cc >new file mode 100644 >index 00000000000..678e8568d74 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.cc >@@ -0,0 +1,123 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/thread_identity.h" >+ >+#ifndef _WIN32 >+#include <pthread.h> >+#include <signal.h> >+#endif >+ >+#include <atomic> >+#include <cassert> >+#include <memory> >+ >+#include "absl/base/call_once.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+ >+namespace absl { >+namespace base_internal { >+ >+#if ABSL_THREAD_IDENTITY_MODE != ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+namespace { >+// Used to co-ordinate one-time creation of our pthread_key >+absl::once_flag init_thread_identity_key_once; >+pthread_key_t thread_identity_pthread_key; >+std::atomic<bool> pthread_key_initialized(false); >+ >+void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) { >+ pthread_key_create(&thread_identity_pthread_key, reclaimer); >+ pthread_key_initialized.store(true, std::memory_order_release); >+} >+} // namespace >+#endif >+ >+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ >+ ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+// The actual TLS storage for a thread's currently associated ThreadIdentity. >+// This is referenced by inline accessors in the header. >+// "protected" visibility ensures that if multiple instances of Abseil code >+// exist within a process (via dlopen() or similar), references to >+// thread_identity_ptr from each instance of the code will refer to >+// *different* instances of this ptr. >+#ifdef __GNUC__ >+__attribute__((visibility("protected"))) >+#endif // __GNUC__ >+ ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr; >+#endif // TLS or CPP11 >+ >+void SetCurrentThreadIdentity( >+ ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) { >+ assert(CurrentThreadIdentityIfPresent() == nullptr); >+ // Associate our destructor. >+ // NOTE: This call to pthread_setspecific is currently the only immovable >+ // barrier to CurrentThreadIdentity() always being async signal safe. >+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+ // NOTE: Not async-safe. But can be open-coded. >+ absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, >+ reclaimer); >+ // We must mask signals around the call to setspecific as with current glibc, >+ // a concurrent getspecific (needed for GetCurrentThreadIdentityIfPresent()) >+ // may zero our value. >+ // >+ // While not officially async-signal safe, getspecific within a signal handler >+ // is otherwise OK. >+ sigset_t all_signals; >+ sigset_t curr_signals; >+ sigfillset(&all_signals); >+ pthread_sigmask(SIG_SETMASK, &all_signals, &curr_signals); >+ pthread_setspecific(thread_identity_pthread_key, >+ reinterpret_cast<void*>(identity)); >+ pthread_sigmask(SIG_SETMASK, &curr_signals, nullptr); >+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS >+ // NOTE: Not async-safe. But can be open-coded. >+ absl::call_once(init_thread_identity_key_once, AllocateThreadIdentityKey, >+ reclaimer); >+ pthread_setspecific(thread_identity_pthread_key, >+ reinterpret_cast<void*>(identity)); >+ thread_identity_ptr = identity; >+#elif ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+ thread_local std::unique_ptr<ThreadIdentity, ThreadIdentityReclaimerFunction> >+ holder(identity, reclaimer); >+ thread_identity_ptr = identity; >+#else >+#error Unimplemented ABSL_THREAD_IDENTITY_MODE >+#endif >+} >+ >+void ClearCurrentThreadIdentity() { >+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ >+ ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+ thread_identity_ptr = nullptr; >+#elif ABSL_THREAD_IDENTITY_MODE == \ >+ ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+ // pthread_setspecific expected to clear value on destruction >+ assert(CurrentThreadIdentityIfPresent() == nullptr); >+#endif >+} >+ >+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+ThreadIdentity* CurrentThreadIdentityIfPresent() { >+ bool initialized = pthread_key_initialized.load(std::memory_order_acquire); >+ if (!initialized) { >+ return nullptr; >+ } >+ return reinterpret_cast<ThreadIdentity*>( >+ pthread_getspecific(thread_identity_pthread_key)); >+} >+#endif >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.h >new file mode 100644 >index 00000000000..a51722f9d82 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity.h >@@ -0,0 +1,240 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Each active thread has an ThreadIdentity that may represent the thread in >+// various level interfaces. ThreadIdentity objects are never deallocated. >+// When a thread terminates, its ThreadIdentity object may be reused for a >+// thread created later. >+ >+#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ >+#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ >+ >+#ifndef _WIN32 >+#include <pthread.h> >+// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when >+// supported. >+#include <unistd.h> >+#endif >+ >+#include <atomic> >+#include <cstdint> >+ >+#include "absl/base/internal/per_thread_tls.h" >+ >+namespace absl { >+ >+struct SynchLocksHeld; >+struct SynchWaitParams; >+ >+namespace base_internal { >+ >+class SpinLock; >+struct ThreadIdentity; >+ >+// Used by the implementation of base::Mutex and base::CondVar. >+struct PerThreadSynch { >+ // The internal representation of base::Mutex and base::CondVar rely >+ // on the alignment of PerThreadSynch. Both store the address of the >+ // PerThreadSynch in the high-order bits of their internal state, >+ // which means the low kLowZeroBits of the address of PerThreadSynch >+ // must be zero. >+ static constexpr int kLowZeroBits = 8; >+ static constexpr int kAlignment = 1 << kLowZeroBits; >+ >+ // Returns the associated ThreadIdentity. >+ // This can be implemented as a cast because we guarantee >+ // PerThreadSynch is the first element of ThreadIdentity. >+ ThreadIdentity* thread_identity() { >+ return reinterpret_cast<ThreadIdentity*>(this); >+ } >+ >+ PerThreadSynch *next; // Circular waiter queue; initialized to 0. >+ PerThreadSynch *skip; // If non-zero, all entries in Mutex queue >+ // up to and including "skip" have same >+ // condition as this, and will be woken later >+ bool may_skip; // if false while on mutex queue, a mutex unlocker >+ // is using this PerThreadSynch as a terminator. Its >+ // skip field must not be filled in because the loop >+ // might then skip over the terminator. >+ >+ // The wait parameters of the current wait. waitp is null if the >+ // thread is not waiting. Transitions from null to non-null must >+ // occur before the enqueue commit point (state = kQueued in >+ // Enqueue() and CondVarEnqueue()). Transitions from non-null to >+ // null must occur after the wait is finished (state = kAvailable in >+ // Mutex::Block() and CondVar::WaitCommon()). This field may be >+ // changed only by the thread that describes this PerThreadSynch. A >+ // special case is Fer(), which calls Enqueue() on another thread, >+ // but with an identical SynchWaitParams pointer, thus leaving the >+ // pointer unchanged. >+ SynchWaitParams *waitp; >+ >+ bool suppress_fatal_errors; // If true, try to proceed even in the face of >+ // broken invariants. This is used within fatal >+ // signal handlers to improve the chances of >+ // debug logging information being output >+ // successfully. >+ >+ intptr_t readers; // Number of readers in mutex. >+ int priority; // Priority of thread (updated every so often). >+ >+ // When priority will next be read (cycles). >+ int64_t next_priority_read_cycles; >+ >+ // State values: >+ // kAvailable: This PerThreadSynch is available. >+ // kQueued: This PerThreadSynch is unavailable, it's currently queued on a >+ // Mutex or CondVar waistlist. >+ // >+ // Transitions from kQueued to kAvailable require a release >+ // barrier. This is needed as a waiter may use "state" to >+ // independently observe that it's no longer queued. >+ // >+ // Transitions from kAvailable to kQueued require no barrier, they >+ // are externally ordered by the Mutex. >+ enum State { >+ kAvailable, >+ kQueued >+ }; >+ std::atomic<State> state; >+ >+ bool maybe_unlocking; // Valid at head of Mutex waiter queue; >+ // true if UnlockSlow could be searching >+ // for a waiter to wake. Used for an optimization >+ // in Enqueue(). true is always a valid value. >+ // Can be reset to false when the unlocker or any >+ // writer releases the lock, or a reader fully releases >+ // the lock. It may not be set to false by a reader >+ // that decrements the count to non-zero. >+ // protected by mutex spinlock >+ >+ bool wake; // This thread is to be woken from a Mutex. >+ >+ // If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the >+ // waiter is waiting on the mutex as part of a CV Wait or Mutex Await. >+ // >+ // The value of "x->cond_waiter" is meaningless if "x" is not on a >+ // Mutex waiter list. >+ bool cond_waiter; >+ >+ // Locks held; used during deadlock detection. >+ // Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity(). >+ SynchLocksHeld *all_locks; >+}; >+ >+struct ThreadIdentity { >+ // Must be the first member. The Mutex implementation requires that >+ // the PerThreadSynch object associated with each thread is >+ // PerThreadSynch::kAlignment aligned. We provide this alignment on >+ // ThreadIdentity itself. >+ PerThreadSynch per_thread_synch; >+ >+ // Private: Reserved for absl::synchronization_internal::Waiter. >+ struct WaiterState { >+ char data[128]; >+ } waiter_state; >+ >+ // Used by PerThreadSem::{Get,Set}ThreadBlockedCounter(). >+ std::atomic<int>* blocked_count_ptr; >+ >+ // The following variables are mostly read/written just by the >+ // thread itself. The only exception is that these are read by >+ // a ticker thread as a hint. >+ std::atomic<int> ticker; // Tick counter, incremented once per second. >+ std::atomic<int> wait_start; // Ticker value when thread started waiting. >+ std::atomic<bool> is_idle; // Has thread become idle yet? >+ >+ ThreadIdentity* next; >+}; >+ >+// Returns the ThreadIdentity object representing the calling thread; guaranteed >+// to be unique for its lifetime. The returned object will remain valid for the >+// program's lifetime; although it may be re-assigned to a subsequent thread. >+// If one does not exist, return nullptr instead. >+// >+// Does not malloc(*), and is async-signal safe. >+// [*] Technically pthread_setspecific() does malloc on first use; however this >+// is handled internally within tcmalloc's initialization already. >+// >+// New ThreadIdentity objects can be constructed and associated with a thread >+// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h. >+ThreadIdentity* CurrentThreadIdentityIfPresent(); >+ >+using ThreadIdentityReclaimerFunction = void (*)(void*); >+ >+// Sets the current thread identity to the given value. 'reclaimer' is a >+// pointer to the global function for cleaning up instances on thread >+// destruction. >+void SetCurrentThreadIdentity(ThreadIdentity* identity, >+ ThreadIdentityReclaimerFunction reclaimer); >+ >+// Removes the currently associated ThreadIdentity from the running thread. >+// This must be called from inside the ThreadIdentityReclaimerFunction, and only >+// from that function. >+void ClearCurrentThreadIdentity(); >+ >+// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode >+// index> >+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be direcly set >+#else >+#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0 >+#endif >+ >+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS >+#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be direcly set >+#else >+#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1 >+#endif >+ >+#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be direcly set >+#else >+#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2 >+#endif >+ >+#ifdef ABSL_THREAD_IDENTITY_MODE >+#error ABSL_THREAD_IDENTITY_MODE cannot be direcly set >+#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE) >+#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE >+#elif defined(_WIN32) >+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \ >+ (__GOOGLE_GRTE_VERSION__ >= 20140228L) >+// Support for async-safe TLS was specifically added in GRTEv4. It's not >+// present in the upstream eglibc. >+// Note: Current default for production systems. >+#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS >+#else >+#define ABSL_THREAD_IDENTITY_MODE \ >+ ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+#endif >+ >+#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \ >+ ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11 >+ >+extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr; >+ >+inline ThreadIdentity* CurrentThreadIdentityIfPresent() { >+ return thread_identity_ptr; >+} >+ >+#elif ABSL_THREAD_IDENTITY_MODE != \ >+ ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC >+#error Unknown ABSL_THREAD_IDENTITY_MODE >+#endif >+ >+} // namespace base_internal >+} // namespace absl >+#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc >new file mode 100644 >index 00000000000..242522b4418 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_benchmark.cc >@@ -0,0 +1,38 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/synchronization/internal/create_thread_identity.h" >+#include "absl/synchronization/internal/per_thread_sem.h" >+ >+namespace { >+ >+void BM_SafeCurrentThreadIdentity(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::synchronization_internal::GetOrCreateCurrentThreadIdentity()); >+ } >+} >+BENCHMARK(BM_SafeCurrentThreadIdentity); >+ >+void BM_UnsafeCurrentThreadIdentity(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::base_internal::CurrentThreadIdentityIfPresent()); >+ } >+} >+BENCHMARK(BM_UnsafeCurrentThreadIdentity); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc >new file mode 100644 >index 00000000000..ecb8af68982 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/thread_identity_test.cc >@@ -0,0 +1,126 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/thread_identity.h" >+ >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/macros.h" >+#include "absl/synchronization/internal/per_thread_sem.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+namespace base_internal { >+namespace { >+ >+// protects num_identities_reused >+static absl::base_internal::SpinLock map_lock( >+ absl::base_internal::kLinkerInitialized); >+static int num_identities_reused; >+ >+static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1); >+ >+static void TestThreadIdentityCurrent(const void* assert_no_identity) { >+ ThreadIdentity* identity; >+ >+ // We have to test this conditionally, because if the test framework relies >+ // on Abseil, then some previous action may have already allocated an >+ // identity. >+ if (assert_no_identity == kCheckNoIdentity) { >+ identity = CurrentThreadIdentityIfPresent(); >+ EXPECT_TRUE(identity == nullptr); >+ } >+ >+ identity = synchronization_internal::GetOrCreateCurrentThreadIdentity(); >+ EXPECT_TRUE(identity != nullptr); >+ ThreadIdentity* identity_no_init; >+ identity_no_init = CurrentThreadIdentityIfPresent(); >+ EXPECT_TRUE(identity == identity_no_init); >+ >+ // Check that per_thread_synch is correctly aligned. >+ EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) % >+ PerThreadSynch::kAlignment); >+ EXPECT_EQ(identity, identity->per_thread_synch.thread_identity()); >+ >+ absl::base_internal::SpinLockHolder l(&map_lock); >+ num_identities_reused++; >+} >+ >+TEST(ThreadIdentityTest, BasicIdentityWorks) { >+ // This tests for the main() thread. >+ TestThreadIdentityCurrent(nullptr); >+} >+ >+TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) { >+ // Now try the same basic test with multiple threads being created and >+ // destroyed. This makes sure that: >+ // - New threads are created without a ThreadIdentity. >+ // - We re-allocate ThreadIdentity objects from the free-list. >+ // - If a thread implementation chooses to recycle threads, that >+ // correct re-initialization occurs. >+ static const int kNumLoops = 3; >+ static const int kNumThreads = 400; >+ for (int iter = 0; iter < kNumLoops; iter++) { >+ std::vector<std::thread> threads; >+ for (int i = 0; i < kNumThreads; ++i) { >+ threads.push_back( >+ std::thread(TestThreadIdentityCurrent, kCheckNoIdentity)); >+ } >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ } >+ >+ // We should have recycled ThreadIdentity objects above; while (external) >+ // library threads allocating their own identities may preclude some >+ // reuse, we should have sufficient repetitions to exclude this. >+ EXPECT_LT(kNumThreads, num_identities_reused); >+} >+ >+TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) { >+ // This test repeatly creates and joins a series of threads, each of >+ // which acquires and releases shared Mutex locks. This verifies >+ // Mutex operations work correctly under a reused >+ // ThreadIdentity. Note that the most likely failure mode of this >+ // test is a crash or deadlock. >+ static const int kNumLoops = 10; >+ static const int kNumThreads = 12; >+ static const int kNumMutexes = 3; >+ static const int kNumLockLoops = 5; >+ >+ Mutex mutexes[kNumMutexes]; >+ for (int iter = 0; iter < kNumLoops; ++iter) { >+ std::vector<std::thread> threads; >+ for (int thread = 0; thread < kNumThreads; ++thread) { >+ threads.push_back(std::thread([&]() { >+ for (int l = 0; l < kNumLockLoops; ++l) { >+ for (int m = 0; m < kNumMutexes; ++m) { >+ MutexLock lock(&mutexes[m]); >+ } >+ } >+ })); >+ } >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ } >+} >+ >+} // namespace >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc >new file mode 100644 >index 00000000000..46dc573cfa8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.cc >@@ -0,0 +1,106 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/throw_delegate.h" >+ >+#include <cstdlib> >+#include <functional> >+#include <new> >+#include <stdexcept> >+#include "absl/base/config.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+namespace base_internal { >+ >+namespace { >+template <typename T> >+[[noreturn]] void Throw(const T& error) { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw error; >+#else >+ ABSL_RAW_LOG(ERROR, "%s", error.what()); >+ abort(); >+#endif >+} >+} // namespace >+ >+void ThrowStdLogicError(const std::string& what_arg) { >+ Throw(std::logic_error(what_arg)); >+} >+void ThrowStdLogicError(const char* what_arg) { >+ Throw(std::logic_error(what_arg)); >+} >+void ThrowStdInvalidArgument(const std::string& what_arg) { >+ Throw(std::invalid_argument(what_arg)); >+} >+void ThrowStdInvalidArgument(const char* what_arg) { >+ Throw(std::invalid_argument(what_arg)); >+} >+ >+void ThrowStdDomainError(const std::string& what_arg) { >+ Throw(std::domain_error(what_arg)); >+} >+void ThrowStdDomainError(const char* what_arg) { >+ Throw(std::domain_error(what_arg)); >+} >+ >+void ThrowStdLengthError(const std::string& what_arg) { >+ Throw(std::length_error(what_arg)); >+} >+void ThrowStdLengthError(const char* what_arg) { >+ Throw(std::length_error(what_arg)); >+} >+ >+void ThrowStdOutOfRange(const std::string& what_arg) { >+ Throw(std::out_of_range(what_arg)); >+} >+void ThrowStdOutOfRange(const char* what_arg) { >+ Throw(std::out_of_range(what_arg)); >+} >+ >+void ThrowStdRuntimeError(const std::string& what_arg) { >+ Throw(std::runtime_error(what_arg)); >+} >+void ThrowStdRuntimeError(const char* what_arg) { >+ Throw(std::runtime_error(what_arg)); >+} >+ >+void ThrowStdRangeError(const std::string& what_arg) { >+ Throw(std::range_error(what_arg)); >+} >+void ThrowStdRangeError(const char* what_arg) { >+ Throw(std::range_error(what_arg)); >+} >+ >+void ThrowStdOverflowError(const std::string& what_arg) { >+ Throw(std::overflow_error(what_arg)); >+} >+void ThrowStdOverflowError(const char* what_arg) { >+ Throw(std::overflow_error(what_arg)); >+} >+ >+void ThrowStdUnderflowError(const std::string& what_arg) { >+ Throw(std::underflow_error(what_arg)); >+} >+void ThrowStdUnderflowError(const char* what_arg) { >+ Throw(std::underflow_error(what_arg)); >+} >+ >+void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); } >+ >+void ThrowStdBadAlloc() { Throw(std::bad_alloc()); } >+ >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.h >new file mode 100644 >index 00000000000..70e2d7709e5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/throw_delegate.h >@@ -0,0 +1,71 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ >+#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ >+ >+#include <string> >+ >+namespace absl { >+namespace base_internal { >+ >+// Helper functions that allow throwing exceptions consistently from anywhere. >+// The main use case is for header-based libraries (eg templates), as they will >+// be built by many different targets with their own compiler options. >+// In particular, this will allow a safe way to throw exceptions even if the >+// caller is compiled with -fno-exceptions. This is intended for implementing >+// things like map<>::at(), which the standard documents as throwing an >+// exception on error. >+// >+// Using other techniques like #if tricks could lead to ODR violations. >+// >+// You shouldn't use it unless you're writing code that you know will be built >+// both with and without exceptions and you need to conform to an interface >+// that uses exceptions. >+ >+[[noreturn]] void ThrowStdLogicError(const std::string& what_arg); >+[[noreturn]] void ThrowStdLogicError(const char* what_arg); >+[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg); >+[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg); >+[[noreturn]] void ThrowStdDomainError(const std::string& what_arg); >+[[noreturn]] void ThrowStdDomainError(const char* what_arg); >+[[noreturn]] void ThrowStdLengthError(const std::string& what_arg); >+[[noreturn]] void ThrowStdLengthError(const char* what_arg); >+[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg); >+[[noreturn]] void ThrowStdOutOfRange(const char* what_arg); >+[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg); >+[[noreturn]] void ThrowStdRuntimeError(const char* what_arg); >+[[noreturn]] void ThrowStdRangeError(const std::string& what_arg); >+[[noreturn]] void ThrowStdRangeError(const char* what_arg); >+[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg); >+[[noreturn]] void ThrowStdOverflowError(const char* what_arg); >+[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg); >+[[noreturn]] void ThrowStdUnderflowError(const char* what_arg); >+ >+[[noreturn]] void ThrowStdBadFunctionCall(); >+[[noreturn]] void ThrowStdBadAlloc(); >+ >+// ThrowStdBadArrayNewLength() cannot be consistently supported because >+// std::bad_array_new_length is missing in libstdc++ until 4.9.0. >+// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html >+// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html >+// libcxx (as of 3.2) and msvc (as of 2015) both have it. >+// [[noreturn]] void ThrowStdBadArrayNewLength(); >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h >new file mode 100644 >index 00000000000..6bb4faedb87 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/tsan_mutex_interface.h >@@ -0,0 +1,66 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file is intended solely for spinlock.h. >+// It provides ThreadSanitizer annotations for custom mutexes. >+// See <sanitizer/tsan_interface.h> for meaning of these annotations. >+ >+#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ >+#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ >+ >+// ABSL_INTERNAL_HAVE_TSAN_INTERFACE >+// Macro intended only for internal use. >+// >+// Checks whether LLVM Thread Sanitizer interfaces are available. >+// First made available in LLVM 5.0 (Sep 2017). >+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE >+#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set." >+#endif >+ >+#if defined(THREAD_SANITIZER) && defined(__has_include) >+#if __has_include(<sanitizer/tsan_interface.h>) >+#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1 >+#endif >+#endif >+ >+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE >+#include <sanitizer/tsan_interface.h> >+ >+#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create >+#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy >+#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock >+#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock >+#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock >+#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock >+#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal >+#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal >+#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert >+#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert >+ >+#else >+ >+#define ABSL_TSAN_MUTEX_CREATE(...) >+#define ABSL_TSAN_MUTEX_DESTROY(...) >+#define ABSL_TSAN_MUTEX_PRE_LOCK(...) >+#define ABSL_TSAN_MUTEX_POST_LOCK(...) >+#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...) >+#define ABSL_TSAN_MUTEX_POST_UNLOCK(...) >+#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...) >+#define ABSL_TSAN_MUTEX_POST_SIGNAL(...) >+#define ABSL_TSAN_MUTEX_PRE_DIVERT(...) >+#define ABSL_TSAN_MUTEX_POST_DIVERT(...) >+ >+#endif >+ >+#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unaligned_access.h >new file mode 100644 >index 00000000000..5c7517abd71 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unaligned_access.h >@@ -0,0 +1,297 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ >+#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ >+ >+#include <string.h> >+#include <cstdint> >+ >+#include "absl/base/attributes.h" >+ >+// unaligned APIs >+ >+// Portable handling of unaligned loads, stores, and copies. >+// On some platforms, like ARM, the copy functions can be more efficient >+// then a load and a store. >+// >+// It is possible to implement all of these these using constant-length memcpy >+// calls, which is portable and will usually be inlined into simple loads and >+// stores if the architecture supports it. However, such inlining usually >+// happens in a pass that's quite late in compilation, which means the resulting >+// loads and stores cannot participate in many other optimizations, leading to >+// overall worse code. >+ >+// The unaligned API is C++ only. The declarations use C++ features >+// (namespaces, inline) which are absent or incompatible in C. >+#if defined(__cplusplus) >+ >+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\ >+ defined(MEMORY_SANITIZER) >+// Consider we have an unaligned load/store of 4 bytes from address 0x...05. >+// AddressSanitizer will treat it as a 3-byte access to the range 05:07 and >+// will miss a bug if 08 is the first unaddressable byte. >+// ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will >+// miss a race between this access and some other accesses to 08. >+// MemorySanitizer will correctly propagate the shadow on unaligned stores >+// and correctly report bugs on unaligned loads, but it may not properly >+// update and report the origin of the uninitialized memory. >+// For all three tools, replacing an unaligned access with a tool-specific >+// callback solves the problem. >+ >+// Make sure uint16_t/uint32_t/uint64_t are defined. >+#include <stdint.h> >+ >+extern "C" { >+uint16_t __sanitizer_unaligned_load16(const void *p); >+uint32_t __sanitizer_unaligned_load32(const void *p); >+uint64_t __sanitizer_unaligned_load64(const void *p); >+void __sanitizer_unaligned_store16(void *p, uint16_t v); >+void __sanitizer_unaligned_store32(void *p, uint32_t v); >+void __sanitizer_unaligned_store64(void *p, uint64_t v); >+} // extern "C" >+ >+namespace absl { >+ >+inline uint16_t UnalignedLoad16(const void *p) { >+ return __sanitizer_unaligned_load16(p); >+} >+ >+inline uint32_t UnalignedLoad32(const void *p) { >+ return __sanitizer_unaligned_load32(p); >+} >+ >+inline uint64_t UnalignedLoad64(const void *p) { >+ return __sanitizer_unaligned_load64(p); >+} >+ >+inline void UnalignedStore16(void *p, uint16_t v) { >+ __sanitizer_unaligned_store16(p, v); >+} >+ >+inline void UnalignedStore32(void *p, uint32_t v) { >+ __sanitizer_unaligned_store32(p, v); >+} >+ >+inline void UnalignedStore64(void *p, uint64_t v) { >+ __sanitizer_unaligned_store64(p, v); >+} >+ >+} // namespace absl >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) >+ >+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ >+ (absl::UnalignedStore16(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ >+ (absl::UnalignedStore32(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ >+ (absl::UnalignedStore64(_p, _val)) >+ >+#elif defined(UNDEFINED_BEHAVIOR_SANITIZER) >+ >+namespace absl { >+ >+inline uint16_t UnalignedLoad16(const void *p) { >+ uint16_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline uint32_t UnalignedLoad32(const void *p) { >+ uint32_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline uint64_t UnalignedLoad64(const void *p) { >+ uint64_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } >+ >+inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } >+ >+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } >+ >+} // namespace absl >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) >+ >+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ >+ (absl::UnalignedStore16(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ >+ (absl::UnalignedStore32(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ >+ (absl::UnalignedStore64(_p, _val)) >+ >+#elif defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \ >+ defined(_M_IX86) || defined(__ppc__) || defined(__PPC__) || \ >+ defined(__ppc64__) || defined(__PPC64__) >+ >+// x86 and x86-64 can perform unaligned loads/stores directly; >+// modern PowerPC hardware can also do unaligned integer loads and stores; >+// but note: the FPU still sends unaligned loads and stores to a trap handler! >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ >+ (*reinterpret_cast<const uint16_t *>(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ >+ (*reinterpret_cast<const uint32_t *>(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \ >+ (*reinterpret_cast<const uint64_t *>(_p)) >+ >+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ >+ (*reinterpret_cast<uint16_t *>(_p) = (_val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ >+ (*reinterpret_cast<uint32_t *>(_p) = (_val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ >+ (*reinterpret_cast<uint64_t *>(_p) = (_val)) >+ >+#elif defined(__arm__) && \ >+ !defined(__ARM_ARCH_5__) && \ >+ !defined(__ARM_ARCH_5T__) && \ >+ !defined(__ARM_ARCH_5TE__) && \ >+ !defined(__ARM_ARCH_5TEJ__) && \ >+ !defined(__ARM_ARCH_6__) && \ >+ !defined(__ARM_ARCH_6J__) && \ >+ !defined(__ARM_ARCH_6K__) && \ >+ !defined(__ARM_ARCH_6Z__) && \ >+ !defined(__ARM_ARCH_6ZK__) && \ >+ !defined(__ARM_ARCH_6T2__) >+ >+ >+// ARMv7 and newer support native unaligned accesses, but only of 16-bit >+// and 32-bit values (not 64-bit); older versions either raise a fatal signal, >+// do an unaligned read and rotate the words around a bit, or do the reads very >+// slowly (trip through kernel mode). There's no simple #define that says just >+// "ARMv7 or higher", so we have to filter away all ARMv5 and ARMv6 >+// sub-architectures. Newer gcc (>= 4.6) set an __ARM_FEATURE_ALIGNED #define, >+// so in time, maybe we can move on to that. >+// >+// This is a mess, but there's not much we can do about it. >+// >+// To further complicate matters, only LDR instructions (single reads) are >+// allowed to be unaligned, not LDRD (two reads) or LDM (many reads). Unless we >+// explicitly tell the compiler that these accesses can be unaligned, it can and >+// will combine accesses. On armcc, the way to signal this is done by accessing >+// through the type (uint32_t __packed *), but GCC has no such attribute >+// (it ignores __attribute__((packed)) on individual variables). However, >+// we can tell it that a _struct_ is unaligned, which has the same effect, >+// so we do that. >+ >+namespace absl { >+namespace internal { >+ >+struct Unaligned16Struct { >+ uint16_t value; >+ uint8_t dummy; // To make the size non-power-of-two. >+} ABSL_ATTRIBUTE_PACKED; >+ >+struct Unaligned32Struct { >+ uint32_t value; >+ uint8_t dummy; // To make the size non-power-of-two. >+} ABSL_ATTRIBUTE_PACKED; >+ >+} // namespace internal >+} // namespace absl >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \ >+ ((reinterpret_cast<const ::absl::internal::Unaligned16Struct *>(_p))->value) >+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \ >+ ((reinterpret_cast<const ::absl::internal::Unaligned32Struct *>(_p))->value) >+ >+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ >+ ((reinterpret_cast< ::absl::internal::Unaligned16Struct *>(_p))->value = \ >+ (_val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ >+ ((reinterpret_cast< ::absl::internal::Unaligned32Struct *>(_p))->value = \ >+ (_val)) >+ >+namespace absl { >+ >+inline uint64_t UnalignedLoad64(const void *p) { >+ uint64_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } >+ >+} // namespace absl >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) >+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ >+ (absl::UnalignedStore64(_p, _val)) >+ >+#else >+ >+// ABSL_INTERNAL_NEED_ALIGNED_LOADS is defined when the underlying platform >+// doesn't support unaligned access. >+#define ABSL_INTERNAL_NEED_ALIGNED_LOADS >+ >+// These functions are provided for architectures that don't support >+// unaligned loads and stores. >+ >+namespace absl { >+ >+inline uint16_t UnalignedLoad16(const void *p) { >+ uint16_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline uint32_t UnalignedLoad32(const void *p) { >+ uint32_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline uint64_t UnalignedLoad64(const void *p) { >+ uint64_t t; >+ memcpy(&t, p, sizeof t); >+ return t; >+} >+ >+inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); } >+ >+inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); } >+ >+inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } >+ >+} // namespace absl >+ >+#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) (absl::UnalignedLoad16(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) (absl::UnalignedLoad32(_p)) >+#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) (absl::UnalignedLoad64(_p)) >+ >+#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \ >+ (absl::UnalignedStore16(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \ >+ (absl::UnalignedStore32(_p, _val)) >+#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \ >+ (absl::UnalignedStore64(_p, _val)) >+ >+#endif >+ >+#endif // defined(__cplusplus), end of unaligned API >+ >+#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc >new file mode 100644 >index 00000000000..a12d68bd10a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc >@@ -0,0 +1,101 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/unscaledcycleclock.h" >+ >+#if ABSL_USE_UNSCALED_CYCLECLOCK >+ >+#if defined(_WIN32) >+#include <intrin.h> >+#endif >+ >+#if defined(__powerpc__) || defined(__ppc__) >+#include <sys/platform/ppc.h> >+#endif >+ >+#include "absl/base/internal/sysinfo.h" >+ >+namespace absl { >+namespace base_internal { >+ >+#if defined(__i386__) >+ >+int64_t UnscaledCycleClock::Now() { >+ int64_t ret; >+ __asm__ volatile("rdtsc" : "=A"(ret)); >+ return ret; >+} >+ >+double UnscaledCycleClock::Frequency() { >+ return base_internal::NominalCPUFrequency(); >+} >+ >+#elif defined(__x86_64__) >+ >+int64_t UnscaledCycleClock::Now() { >+ uint64_t low, high; >+ __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); >+ return (high << 32) | low; >+} >+ >+double UnscaledCycleClock::Frequency() { >+ return base_internal::NominalCPUFrequency(); >+} >+ >+#elif defined(__powerpc__) || defined(__ppc__) >+ >+int64_t UnscaledCycleClock::Now() { >+ return __ppc_get_timebase(); >+} >+ >+double UnscaledCycleClock::Frequency() { >+ return __ppc_get_timebase_freq(); >+} >+ >+#elif defined(__aarch64__) >+ >+// System timer of ARMv8 runs at a different frequency than the CPU's. >+// The frequency is fixed, typically in the range 1-50MHz. It can be >+// read at CNTFRQ special register. We assume the OS has set up >+// the virtual timer properly. >+int64_t UnscaledCycleClock::Now() { >+ int64_t virtual_timer_value; >+ asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); >+ return virtual_timer_value; >+} >+ >+double UnscaledCycleClock::Frequency() { >+ uint64_t aarch64_timer_frequency; >+ asm volatile("mrs %0, cntfrq_el0" : "=r"(aarch64_timer_frequency)); >+ return aarch64_timer_frequency; >+} >+ >+#elif defined(_M_IX86) || defined(_M_X64) >+ >+#pragma intrinsic(__rdtsc) >+ >+int64_t UnscaledCycleClock::Now() { >+ return __rdtsc(); >+} >+ >+double UnscaledCycleClock::Frequency() { >+ return base_internal::NominalCPUFrequency(); >+} >+ >+#endif >+ >+} // namespace base_internal >+} // namespace absl >+ >+#endif // ABSL_USE_UNSCALED_CYCLECLOCK >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h >new file mode 100644 >index 00000000000..049f1cace98 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.h >@@ -0,0 +1,119 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// UnscaledCycleClock >+// An UnscaledCycleClock yields the value and frequency of a cycle counter >+// that increments at a rate that is approximately constant. >+// This class is for internal / whitelisted use only, you should consider >+// using CycleClock instead. >+// >+// Notes: >+// The cycle counter frequency is not necessarily the core clock frequency. >+// That is, CycleCounter cycles are not necessarily "CPU cycles". >+// >+// An arbitrary offset may have been added to the counter at power on. >+// >+// On some platforms, the rate and offset of the counter may differ >+// slightly when read from different CPUs of a multiprocessor. Usually, >+// we try to ensure that the operating system adjusts values periodically >+// so that values agree approximately. If you need stronger guarantees, >+// consider using alternate interfaces. >+// >+// The CPU is not required to maintain the ordering of a cycle counter read >+// with respect to surrounding instructions. >+ >+#ifndef ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_ >+#define ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_ >+ >+#include <cstdint> >+ >+#if defined(__APPLE__) >+#include <TargetConditionals.h> >+#endif >+ >+#include "absl/base/port.h" >+ >+// The following platforms have an implementation of a hardware counter. >+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ >+ defined(__powerpc__) || defined(__ppc__) || \ >+ defined(_M_IX86) || defined(_M_X64) >+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 1 >+#else >+#define ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION 0 >+#endif >+ >+// The following platforms often disable access to the hardware >+// counter (through a sandbox) even if the underlying hardware has a >+// usable counter. The CycleTimer interface also requires a *scaled* >+// CycleClock that runs at atleast 1 MHz. We've found some Android >+// ARM64 devices where this is not the case, so we disable it by >+// default on Android ARM64. >+#if defined(__native_client__) || TARGET_OS_IPHONE || \ >+ (defined(__ANDROID__) && defined(__aarch64__)) >+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 0 >+#else >+#define ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT 1 >+#endif >+ >+// UnscaledCycleClock is an optional internal feature. >+// Use "#if ABSL_USE_UNSCALED_CYCLECLOCK" to test for its presence. >+// Can be overridden at compile-time via -DABSL_USE_UNSCALED_CYCLECLOCK=0|1 >+#if !defined(ABSL_USE_UNSCALED_CYCLECLOCK) >+#define ABSL_USE_UNSCALED_CYCLECLOCK \ >+ (ABSL_HAVE_UNSCALED_CYCLECLOCK_IMPLEMENTATION && \ >+ ABSL_USE_UNSCALED_CYCLECLOCK_DEFAULT) >+#endif >+ >+#if ABSL_USE_UNSCALED_CYCLECLOCK >+ >+// This macro can be used to test if UnscaledCycleClock::Frequency() >+// is NominalCPUFrequency() on a particular platform. >+#if (defined(__i386__) || defined(__x86_64__) || \ >+ defined(_M_IX86) || defined(_M_X64)) >+#define ABSL_INTERNAL_UNSCALED_CYCLECLOCK_FREQUENCY_IS_CPU_FREQUENCY >+#endif >+namespace absl { >+namespace time_internal { >+class UnscaledCycleClockWrapperForGetCurrentTime; >+} // namespace time_internal >+ >+namespace base_internal { >+class CycleClock; >+class UnscaledCycleClockWrapperForInitializeFrequency; >+ >+class UnscaledCycleClock { >+ private: >+ UnscaledCycleClock() = delete; >+ >+ // Return the value of a cycle counter that counts at a rate that is >+ // approximately constant. >+ static int64_t Now(); >+ >+ // Return the how much UnscaledCycleClock::Now() increases per second. >+ // This is not necessarily the core CPU clock frequency. >+ // It may be the nominal value report by the kernel, rather than a measured >+ // value. >+ static double Frequency(); >+ >+ // Whitelisted friends. >+ friend class base_internal::CycleClock; >+ friend class time_internal::UnscaledCycleClockWrapperForGetCurrentTime; >+ friend class base_internal::UnscaledCycleClockWrapperForInitializeFrequency; >+}; >+ >+} // namespace base_internal >+} // namespace absl >+#endif // ABSL_USE_UNSCALED_CYCLECLOCK >+ >+#endif // ABSL_BASE_INTERNAL_UNSCALEDCYCLECLOCK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/invoke_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/invoke_test.cc >new file mode 100644 >index 00000000000..466bf114a58 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/invoke_test.cc >@@ -0,0 +1,200 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/invoke.h" >+ >+#include <functional> >+#include <memory> >+#include <string> >+#include <utility> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/memory/memory.h" >+#include "absl/strings/str_cat.h" >+ >+namespace absl { >+namespace base_internal { >+namespace { >+ >+int Function(int a, int b) { return a - b; } >+ >+int Sink(std::unique_ptr<int> p) { >+ return *p; >+} >+ >+std::unique_ptr<int> Factory(int n) { >+ return make_unique<int>(n); >+} >+ >+void NoOp() {} >+ >+struct ConstFunctor { >+ int operator()(int a, int b) const { return a - b; } >+}; >+ >+struct MutableFunctor { >+ int operator()(int a, int b) { return a - b; } >+}; >+ >+struct EphemeralFunctor { >+ int operator()(int a, int b) && { return a - b; } >+}; >+ >+struct OverloadedFunctor { >+ template <typename... Args> >+ std::string operator()(const Args&... args) & { >+ return StrCat("&", args...); >+ } >+ template <typename... Args> >+ std::string operator()(const Args&... args) const& { >+ return StrCat("const&", args...); >+ } >+ template <typename... Args> >+ std::string operator()(const Args&... args) && { >+ return StrCat("&&", args...); >+ } >+}; >+ >+struct Class { >+ int Method(int a, int b) { return a - b; } >+ int ConstMethod(int a, int b) const { return a - b; } >+ >+ int member; >+}; >+ >+struct FlipFlop { >+ int ConstMethod() const { return member; } >+ FlipFlop operator*() const { return {-member}; } >+ >+ int member; >+}; >+ >+// CallMaybeWithArg(f) resolves either to Invoke(f) or Invoke(f, 42), depending >+// on which one is valid. >+template <typename F> >+decltype(Invoke(std::declval<const F&>())) CallMaybeWithArg(const F& f) { >+ return Invoke(f); >+} >+ >+template <typename F> >+decltype(Invoke(std::declval<const F&>(), 42)) CallMaybeWithArg(const F& f) { >+ return Invoke(f, 42); >+} >+ >+TEST(InvokeTest, Function) { >+ EXPECT_EQ(1, Invoke(Function, 3, 2)); >+ EXPECT_EQ(1, Invoke(&Function, 3, 2)); >+} >+ >+TEST(InvokeTest, NonCopyableArgument) { >+ EXPECT_EQ(42, Invoke(Sink, make_unique<int>(42))); >+} >+ >+TEST(InvokeTest, NonCopyableResult) { >+ EXPECT_THAT(Invoke(Factory, 42), ::testing::Pointee(42)); >+} >+ >+TEST(InvokeTest, VoidResult) { >+ Invoke(NoOp); >+} >+ >+TEST(InvokeTest, ConstFunctor) { >+ EXPECT_EQ(1, Invoke(ConstFunctor(), 3, 2)); >+} >+ >+TEST(InvokeTest, MutableFunctor) { >+ MutableFunctor f; >+ EXPECT_EQ(1, Invoke(f, 3, 2)); >+ EXPECT_EQ(1, Invoke(MutableFunctor(), 3, 2)); >+} >+ >+TEST(InvokeTest, EphemeralFunctor) { >+ EphemeralFunctor f; >+ EXPECT_EQ(1, Invoke(std::move(f), 3, 2)); >+ EXPECT_EQ(1, Invoke(EphemeralFunctor(), 3, 2)); >+} >+ >+TEST(InvokeTest, OverloadedFunctor) { >+ OverloadedFunctor f; >+ const OverloadedFunctor& cf = f; >+ >+ EXPECT_EQ("&", Invoke(f)); >+ EXPECT_EQ("& 42", Invoke(f, " 42")); >+ >+ EXPECT_EQ("const&", Invoke(cf)); >+ EXPECT_EQ("const& 42", Invoke(cf, " 42")); >+ >+ EXPECT_EQ("&&", Invoke(std::move(f))); >+ EXPECT_EQ("&& 42", Invoke(std::move(f), " 42")); >+} >+ >+TEST(InvokeTest, ReferenceWrapper) { >+ ConstFunctor cf; >+ MutableFunctor mf; >+ EXPECT_EQ(1, Invoke(std::cref(cf), 3, 2)); >+ EXPECT_EQ(1, Invoke(std::ref(cf), 3, 2)); >+ EXPECT_EQ(1, Invoke(std::ref(mf), 3, 2)); >+} >+ >+TEST(InvokeTest, MemberFunction) { >+ std::unique_ptr<Class> p(new Class); >+ std::unique_ptr<const Class> cp(new Class); >+ EXPECT_EQ(1, Invoke(&Class::Method, p, 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::Method, p.get(), 3, 2)); >+ >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, p, 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, p.get(), 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, *p, 3, 2)); >+ >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp, 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, cp.get(), 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, *cp, 3, 2)); >+ >+ EXPECT_EQ(1, Invoke(&Class::Method, make_unique<Class>(), 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<Class>(), 3, 2)); >+ EXPECT_EQ(1, Invoke(&Class::ConstMethod, make_unique<const Class>(), 3, 2)); >+} >+ >+TEST(InvokeTest, DataMember) { >+ std::unique_ptr<Class> p(new Class{42}); >+ std::unique_ptr<const Class> cp(new Class{42}); >+ EXPECT_EQ(42, Invoke(&Class::member, p)); >+ EXPECT_EQ(42, Invoke(&Class::member, *p)); >+ EXPECT_EQ(42, Invoke(&Class::member, p.get())); >+ >+ Invoke(&Class::member, p) = 42; >+ Invoke(&Class::member, p.get()) = 42; >+ >+ EXPECT_EQ(42, Invoke(&Class::member, cp)); >+ EXPECT_EQ(42, Invoke(&Class::member, *cp)); >+ EXPECT_EQ(42, Invoke(&Class::member, cp.get())); >+} >+ >+TEST(InvokeTest, FlipFlop) { >+ FlipFlop obj = {42}; >+ // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or >+ // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former. >+ EXPECT_EQ(42, Invoke(&FlipFlop::ConstMethod, obj)); >+ EXPECT_EQ(42, Invoke(&FlipFlop::member, obj)); >+} >+ >+TEST(InvokeTest, SfinaeFriendly) { >+ CallMaybeWithArg(NoOp); >+ EXPECT_THAT(CallMaybeWithArg(Factory), ::testing::Pointee(42)); >+} >+ >+} // namespace >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/log_severity.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/log_severity.h >new file mode 100644 >index 00000000000..e2931c34d1d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/log_severity.h >@@ -0,0 +1,67 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ >+#define ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ >+ >+#include <array> >+ >+#include "absl/base/attributes.h" >+ >+namespace absl { >+ >+// Four severity levels are defined. Logging APIs should terminate the program >+// when a message is logged at severity `kFatal`; the other levels have no >+// special semantics. >+enum class LogSeverity : int { >+ kInfo = 0, >+ kWarning = 1, >+ kError = 2, >+ kFatal = 3, >+}; >+ >+// Returns an iterable of all standard `absl::LogSeverity` values, ordered from >+// least to most severe. >+constexpr std::array<absl::LogSeverity, 4> LogSeverities() { >+ return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning, >+ absl::LogSeverity::kError, absl::LogSeverity::kFatal}}; >+} >+ >+// Returns the all-caps std::string representation (e.g. "INFO") of the specified >+// severity level if it is one of the normal levels and "UNKNOWN" otherwise. >+constexpr const char* LogSeverityName(absl::LogSeverity s) { >+ return s == absl::LogSeverity::kInfo >+ ? "INFO" >+ : s == absl::LogSeverity::kWarning >+ ? "WARNING" >+ : s == absl::LogSeverity::kError >+ ? "ERROR" >+ : s == absl::LogSeverity::kFatal ? "FATAL" : "UNKNOWN"; >+} >+ >+// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal` >+// normalize to `kError` (**NOT** `kFatal`). >+constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) { >+ return s < absl::LogSeverity::kInfo >+ ? absl::LogSeverity::kInfo >+ : s > absl::LogSeverity::kFatal ? absl::LogSeverity::kError : s; >+} >+constexpr absl::LogSeverity NormalizeLogSeverity(int s) { >+ return NormalizeLogSeverity(static_cast<absl::LogSeverity>(s)); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_BASE_INTERNAL_LOG_SEVERITY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/macros.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/macros.h >new file mode 100644 >index 00000000000..ca3d5edb653 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/macros.h >@@ -0,0 +1,202 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: macros.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines the set of language macros used within Abseil code. >+// For the set of macros used to determine supported compilers and platforms, >+// see absl/base/config.h instead. >+// >+// This code is compiled directly on many platforms, including client >+// platforms like Windows, Mac, and embedded systems. Before making >+// any changes here, make sure that you're not breaking any platforms. >+// >+ >+#ifndef ABSL_BASE_MACROS_H_ >+#define ABSL_BASE_MACROS_H_ >+ >+#include <cassert> >+#include <cstddef> >+ >+#include "absl/base/port.h" >+ >+// ABSL_ARRAYSIZE() >+// >+// Returns the number of elements in an array as a compile-time constant, which >+// can be used in defining new arrays. If you use this macro on a pointer by >+// mistake, you will get a compile-time error. >+#define ABSL_ARRAYSIZE(array) \ >+ (sizeof(::absl::macros_internal::ArraySizeHelper(array))) >+ >+namespace absl { >+namespace macros_internal { >+// Note: this internal template function declaration is used by ABSL_ARRAYSIZE. >+// The function doesn't need a definition, as we only use its type. >+template <typename T, size_t N> >+auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N]; >+} // namespace macros_internal >+} // namespace absl >+ >+// kLinkerInitialized >+// >+// An enum used only as a constructor argument to indicate that a variable has >+// static storage duration, and that the constructor should do nothing to its >+// state. Use of this macro indicates to the reader that it is legal to >+// declare a static instance of the class, provided the constructor is given >+// the absl::base_internal::kLinkerInitialized argument. >+// >+// Normally, it is unsafe to declare a static variable that has a constructor or >+// a destructor because invocation order is undefined. However, if the type can >+// be zero-initialized (which the loader does for static variables) into a valid >+// state and the type's destructor does not affect storage, then a constructor >+// for static initialization can be declared. >+// >+// Example: >+// // Declaration >+// explicit MyClass(absl::base_internal:LinkerInitialized x) {} >+// >+// // Invocation >+// static MyClass my_global(absl::base_internal::kLinkerInitialized); >+namespace absl { >+namespace base_internal { >+enum LinkerInitialized { >+ kLinkerInitialized = 0, >+}; >+} // namespace base_internal >+} // namespace absl >+ >+// ABSL_FALLTHROUGH_INTENDED >+// >+// Annotates implicit fall-through between switch labels, allowing a case to >+// indicate intentional fallthrough and turn off warnings about any lack of a >+// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by >+// a semicolon and can be used in most places where `break` can, provided that >+// no statements exist between it and the next switch label. >+// >+// Example: >+// >+// switch (x) { >+// case 40: >+// case 41: >+// if (truth_is_out_there) { >+// ++x; >+// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations >+// // in comments >+// } else { >+// return x; >+// } >+// case 42: >+// ... >+// >+// Notes: when compiled with clang in C++11 mode, the ABSL_FALLTHROUGH_INTENDED >+// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed >+// when performing switch labels fall-through diagnostic >+// (`-Wimplicit-fallthrough`). See clang documentation on language extensions >+// for details: >+// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough >+// >+// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro >+// has no effect on diagnostics. In any case this macro has no effect on runtime >+// behavior and performance of code. >+#ifdef ABSL_FALLTHROUGH_INTENDED >+#error "ABSL_FALLTHROUGH_INTENDED should not be defined." >+#endif >+ >+// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported. >+#if defined(__clang__) && defined(__has_warning) >+#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") >+#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]] >+#endif >+#elif defined(__GNUC__) && __GNUC__ >= 7 >+#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]] >+#endif >+ >+#ifndef ABSL_FALLTHROUGH_INTENDED >+#define ABSL_FALLTHROUGH_INTENDED \ >+ do { \ >+ } while (0) >+#endif >+ >+// ABSL_DEPRECATED() >+// >+// Marks a deprecated class, struct, enum, function, method and variable >+// declarations. The macro argument is used as a custom diagnostic message (e.g. >+// suggestion of a better alternative). >+// >+// Example: >+// >+// class ABSL_DEPRECATED("Use Bar instead") Foo {...}; >+// ABSL_DEPRECATED("Use Baz instead") void Bar() {...} >+// >+// Every usage of a deprecated entity will trigger a warning when compiled with >+// clang's `-Wdeprecated-declarations` option. This option is turned off by >+// default, but the warnings will be reported by clang-tidy. >+#if defined(__clang__) && __cplusplus >= 201103L >+#define ABSL_DEPRECATED(message) __attribute__((deprecated(message))) >+#endif >+ >+#ifndef ABSL_DEPRECATED >+#define ABSL_DEPRECATED(message) >+#endif >+ >+// ABSL_BAD_CALL_IF() >+// >+// Used on a function overload to trap bad calls: any call that matches the >+// overload will cause a compile-time error. This macro uses a clang-specific >+// "enable_if" attribute, as described at >+// http://clang.llvm.org/docs/AttributeReference.html#enable-if >+// >+// Overloads which use this macro should be bracketed by >+// `#ifdef ABSL_BAD_CALL_IF`. >+// >+// Example: >+// >+// int isdigit(int c); >+// #ifdef ABSL_BAD_CALL_IF >+// int isdigit(int c) >+// ABSL_BAD_CALL_IF(c <= -1 || c > 255, >+// "'c' must have the value of an unsigned char or EOF"); >+// #endif // ABSL_BAD_CALL_IF >+ >+#if defined(__clang__) >+# if __has_attribute(enable_if) >+# define ABSL_BAD_CALL_IF(expr, msg) \ >+ __attribute__((enable_if(expr, "Bad call trap"), unavailable(msg))) >+# endif >+#endif >+ >+// ABSL_ASSERT() >+// >+// In C++11, `assert` can't be used portably within constexpr functions. >+// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr >+// functions. Example: >+// >+// constexpr double Divide(double a, double b) { >+// return ABSL_ASSERT(b != 0), a / b; >+// } >+// >+// This macro is inspired by >+// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/ >+#if defined(NDEBUG) >+#define ABSL_ASSERT(expr) (false ? (void)(expr) : (void)0) >+#else >+#define ABSL_ASSERT(expr) \ >+ (ABSL_PREDICT_TRUE((expr)) ? (void)0 \ >+ : [] { assert(false && #expr); }()) // NOLINT >+#endif >+ >+#endif // ABSL_BASE_MACROS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/optimization.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/optimization.h >new file mode 100644 >index 00000000000..2fddfc800c1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/optimization.h >@@ -0,0 +1,165 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: optimization.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines portable macros for performance optimization. >+ >+#ifndef ABSL_BASE_OPTIMIZATION_H_ >+#define ABSL_BASE_OPTIMIZATION_H_ >+ >+#include "absl/base/config.h" >+ >+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION >+// >+// Instructs the compiler to avoid optimizing tail-call recursion. Use of this >+// macro is useful when you wish to preserve the existing function order within >+// a stack trace for logging, debugging, or profiling purposes. >+// >+// Example: >+// >+// int f() { >+// int result = g(); >+// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); >+// return result; >+// } >+#if defined(__pnacl__) >+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } >+#elif defined(__clang__) >+// Clang will not tail call given inline volatile assembly. >+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") >+#elif defined(__GNUC__) >+// GCC will not tail call given inline volatile assembly. >+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("") >+#elif defined(_MSC_VER) >+#include <intrin.h> >+// The __nop() intrinsic blocks the optimisation. >+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop() >+#else >+#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; } >+#endif >+ >+// ABSL_CACHELINE_SIZE >+// >+// Explicitly defines the size of the L1 cache for purposes of alignment. >+// Setting the cacheline size allows you to specify that certain objects be >+// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations. >+// (See below.) >+// >+// NOTE: this macro should be replaced with the following C++17 features, when >+// those are generally available: >+// >+// * `std::hardware_constructive_interference_size` >+// * `std::hardware_destructive_interference_size` >+// >+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html >+// for more information. >+#if defined(__GNUC__) >+// Cache line alignment >+#if defined(__i386__) || defined(__x86_64__) >+#define ABSL_CACHELINE_SIZE 64 >+#elif defined(__powerpc64__) >+#define ABSL_CACHELINE_SIZE 128 >+#elif defined(__aarch64__) >+// We would need to read special register ctr_el0 to find out L1 dcache size. >+// This value is a good estimate based on a real aarch64 machine. >+#define ABSL_CACHELINE_SIZE 64 >+#elif defined(__arm__) >+// Cache line sizes for ARM: These values are not strictly correct since >+// cache line sizes depend on implementations, not architectures. There >+// are even implementations with cache line sizes configurable at boot >+// time. >+#if defined(__ARM_ARCH_5T__) >+#define ABSL_CACHELINE_SIZE 32 >+#elif defined(__ARM_ARCH_7A__) >+#define ABSL_CACHELINE_SIZE 64 >+#endif >+#endif >+ >+#ifndef ABSL_CACHELINE_SIZE >+// A reasonable default guess. Note that overestimates tend to waste more >+// space, while underestimates tend to waste more time. >+#define ABSL_CACHELINE_SIZE 64 >+#endif >+ >+// ABSL_CACHELINE_ALIGNED >+// >+// Indicates that the declared object be cache aligned using >+// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to >+// load a set of related objects in the L1 cache for performance improvements. >+// Cacheline aligning objects properly allows constructive memory sharing and >+// prevents destructive (or "false") memory sharing. >+// >+// NOTE: this macro should be replaced with usage of `alignas()` using >+// `std::hardware_constructive_interference_size` and/or >+// `std::hardware_destructive_interference_size` when available within C++17. >+// >+// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html >+// for more information. >+// >+// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to >+// `__attribute__((aligned(ABSL_CACHELINE_SIZE)))`. For compilers where this is >+// not known to work, the macro expands to nothing. >+// >+// No further guarantees are made here. The result of applying the macro >+// to variables and types is always implementation-defined. >+// >+// WARNING: It is easy to use this attribute incorrectly, even to the point >+// of causing bugs that are difficult to diagnose, crash, etc. It does not >+// of itself guarantee that objects are aligned to a cache line. >+// >+// Recommendations: >+// >+// 1) Consult compiler documentation; this comment is not kept in sync as >+// toolchains evolve. >+// 2) Verify your use has the intended effect. This often requires inspecting >+// the generated machine code. >+// 3) Prefer applying this attribute to individual variables. Avoid >+// applying it to types. This tends to localize the effect. >+#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE))) >+ >+#else // not GCC >+#define ABSL_CACHELINE_SIZE 64 >+#define ABSL_CACHELINE_ALIGNED >+#endif >+ >+// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE >+// >+// Enables the compiler to prioritize compilation using static analysis for >+// likely paths within a boolean branch. >+// >+// Example: >+// >+// if (ABSL_PREDICT_TRUE(expression)) { >+// return result; // Faster if more likely >+// } else { >+// return 0; >+// } >+// >+// Compilers can use the information that a certain branch is not likely to be >+// taken (for instance, a CHECK failure) to optimize for the common case in >+// the absence of better information (ie. compiling gcc with `-fprofile-arcs`). >+#if ABSL_HAVE_BUILTIN(__builtin_expect) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0)) >+#define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) >+#else >+#define ABSL_PREDICT_FALSE(x) (x) >+#define ABSL_PREDICT_TRUE(x) (x) >+#endif >+ >+#endif // ABSL_BASE_OPTIMIZATION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/policy_checks.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/policy_checks.h >new file mode 100644 >index 00000000000..0a07fc035e1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/policy_checks.h >@@ -0,0 +1,121 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: policy_checks.h >+// ----------------------------------------------------------------------------- >+// >+// This header enforces a minimum set of policies at build time, such as the >+// supported compiler and library versions. Unsupported configurations are >+// reported with `#error`. This enforcement is best effort, so successfully >+// compiling this header does not guarantee a supported configuration. >+ >+#ifndef ABSL_BASE_POLICY_CHECKS_H_ >+#define ABSL_BASE_POLICY_CHECKS_H_ >+ >+// Included for the __GLIBC_PREREQ macro used below. >+#include <limits.h> >+ >+// Included for the _STLPORT_VERSION macro used below. >+#if defined(__cplusplus) >+#include <cstddef> >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Operating System Check >+// ----------------------------------------------------------------------------- >+ >+#if defined(__CYGWIN__) >+#error "Cygwin is not supported." >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Compiler Check >+// ----------------------------------------------------------------------------- >+ >+// We support MSVC++ 14.0 update 2 and later. >+// This minimum will go up. >+#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__) >+#error "This package requires Visual Studio 2015 Update 2 or higher." >+#endif >+ >+// We support gcc 4.7 and later. >+// This minimum will go up. >+#if defined(__GNUC__) && !defined(__clang__) >+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) >+#error "This package requires gcc 4.7 or higher." >+#endif >+#endif >+ >+// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later. >+// This corresponds to Apple Xcode version 4.5. >+// This minimum will go up. >+#if defined(__apple_build_version__) && __apple_build_version__ < 4211165 >+#error "This package requires __apple_build_version__ of 4211165 or higher." >+#endif >+ >+// ----------------------------------------------------------------------------- >+// C++ Version Check >+// ----------------------------------------------------------------------------- >+ >+// Enforce C++11 as the minimum. Note that Visual Studio has not >+// advanced __cplusplus despite being good enough for our purposes, so >+// so we exempt it from the check. >+#if defined(__cplusplus) && !defined(_MSC_VER) >+#if __cplusplus < 201103L >+#error "C++ versions less than C++11 are not supported." >+#endif >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Standard Library Check >+// ----------------------------------------------------------------------------- >+ >+// We have chosen glibc 2.12 as the minimum as it was tagged for release >+// in May, 2010 and includes some functionality used in Google software >+// (for instance pthread_setname_np): >+// https://sourceware.org/ml/libc-alpha/2010-05/msg00000.html >+#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) >+#if !__GLIBC_PREREQ(2, 12) >+#error "Minimum required version of glibc is 2.12." >+#endif >+#endif >+ >+#if defined(_STLPORT_VERSION) >+#error "STLPort is not supported." >+#endif >+ >+// ----------------------------------------------------------------------------- >+// `char` Size Check >+// ----------------------------------------------------------------------------- >+ >+// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a >+// platform where this is not the case, please provide us with the details about >+// your platform so we can consider relaxing this requirement. >+#if CHAR_BIT != 8 >+#error "Abseil assumes CHAR_BIT == 8." >+#endif >+ >+// ----------------------------------------------------------------------------- >+// `int` Size Check >+// ----------------------------------------------------------------------------- >+ >+// Abseil currently assumes that an int is 4 bytes. If you would like to use >+// Abseil on a platform where this is not the case, please provide us with the >+// details about your platform so we can consider relaxing this requirement. >+#if INT_MAX < 2147483647 >+#error "Abseil assumes that int is at least 4 bytes. " >+#endif >+ >+#endif // ABSL_BASE_POLICY_CHECKS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/port.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/port.h >new file mode 100644 >index 00000000000..1c67257fd8f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/port.h >@@ -0,0 +1,26 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This files is a forwarding header for other headers containing various >+// portability macros and functions. >+// This file is used for both C and C++! >+ >+#ifndef ABSL_BASE_PORT_H_ >+#define ABSL_BASE_PORT_H_ >+ >+#include "absl/base/attributes.h" >+#include "absl/base/config.h" >+#include "absl/base/optimization.h" >+ >+#endif // ABSL_BASE_PORT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/raw_logging_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/raw_logging_test.cc >new file mode 100644 >index 00000000000..ebbc5db9067 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/raw_logging_test.cc >@@ -0,0 +1,79 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This test serves primarily as a compilation test for base/raw_logging.h. >+// Raw logging testing is covered by logging_unittest.cc, which is not as >+// portable as this test. >+ >+#include "absl/base/internal/raw_logging.h" >+ >+#include <tuple> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+TEST(RawLoggingCompilationTest, Log) { >+ ABSL_RAW_LOG(INFO, "RAW INFO: %d", 1); >+ ABSL_RAW_LOG(INFO, "RAW INFO: %d %d", 1, 2); >+ ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d", 1, 2, 3); >+ ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d", 1, 2, 3, 4); >+ ABSL_RAW_LOG(INFO, "RAW INFO: %d %d %d %d %d", 1, 2, 3, 4, 5); >+ ABSL_RAW_LOG(WARNING, "RAW WARNING: %d", 1); >+ ABSL_RAW_LOG(ERROR, "RAW ERROR: %d", 1); >+} >+ >+TEST(RawLoggingCompilationTest, PassingCheck) { >+ ABSL_RAW_CHECK(true, "RAW CHECK"); >+} >+ >+// Not all platforms support output from raw log, so we don't verify any >+// particular output for RAW check failures (expecting the empty std::string >+// accomplishes this). This test is primarily a compilation test, but we >+// are verifying process death when EXPECT_DEATH works for a platform. >+const char kExpectedDeathOutput[] = ""; >+ >+TEST(RawLoggingDeathTest, FailingCheck) { >+ EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_CHECK(1 == 0, "explanation"), >+ kExpectedDeathOutput); >+} >+ >+TEST(RawLoggingDeathTest, LogFatal) { >+ EXPECT_DEATH_IF_SUPPORTED(ABSL_RAW_LOG(FATAL, "my dog has fleas"), >+ kExpectedDeathOutput); >+} >+ >+TEST(InternalLog, CompilationTest) { >+ ABSL_INTERNAL_LOG(INFO, "Internal Log"); >+ std::string log_msg = "Internal Log"; >+ ABSL_INTERNAL_LOG(INFO, log_msg); >+ >+ ABSL_INTERNAL_LOG(INFO, log_msg + " 2"); >+ >+ float d = 1.1f; >+ ABSL_INTERNAL_LOG(INFO, absl::StrCat("Internal log ", 3, " + ", d)); >+} >+ >+TEST(InternalLogDeathTest, FailingCheck) { >+ EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_CHECK(1 == 0, "explanation"), >+ kExpectedDeathOutput); >+} >+ >+TEST(InternalLogDeathTest, LogFatal) { >+ EXPECT_DEATH_IF_SUPPORTED(ABSL_INTERNAL_LOG(FATAL, "my dog has fleas"), >+ kExpectedDeathOutput); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/spinlock_test_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/spinlock_test_common.cc >new file mode 100644 >index 00000000000..1b508848611 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/spinlock_test_common.cc >@@ -0,0 +1,266 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// A bunch of threads repeatedly hash an array of ints protected by a >+// spinlock. If the spinlock is working properly, all elements of the >+// array should be equal at the end of the test. >+ >+#include <cstdint> >+#include <limits> >+#include <random> >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/internal/low_level_scheduling.h" >+#include "absl/base/internal/scheduling_mode.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/internal/sysinfo.h" >+#include "absl/base/macros.h" >+#include "absl/synchronization/blocking_counter.h" >+#include "absl/synchronization/notification.h" >+ >+constexpr int32_t kNumThreads = 10; >+constexpr int32_t kIters = 1000; >+ >+namespace absl { >+namespace base_internal { >+ >+// This is defined outside of anonymous namespace so that it can be >+// a friend of SpinLock to access protected methods for testing. >+struct SpinLockTest { >+ static uint32_t EncodeWaitCycles(int64_t wait_start_time, >+ int64_t wait_end_time) { >+ return SpinLock::EncodeWaitCycles(wait_start_time, wait_end_time); >+ } >+ static uint64_t DecodeWaitCycles(uint32_t lock_value) { >+ return SpinLock::DecodeWaitCycles(lock_value); >+ } >+}; >+ >+namespace { >+ >+static constexpr int kArrayLength = 10; >+static uint32_t values[kArrayLength]; >+static SpinLock static_spinlock(base_internal::kLinkerInitialized); >+static SpinLock static_cooperative_spinlock( >+ base_internal::kLinkerInitialized, >+ base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); >+static SpinLock static_noncooperative_spinlock( >+ base_internal::kLinkerInitialized, base_internal::SCHEDULE_KERNEL_ONLY); >+ >+ >+// Simple integer hash function based on the public domain lookup2 hash. >+// http://burtleburtle.net/bob/c/lookup2.c >+static uint32_t Hash32(uint32_t a, uint32_t c) { >+ uint32_t b = 0x9e3779b9UL; // The golden ratio; an arbitrary value. >+ a -= b; a -= c; a ^= (c >> 13); >+ b -= c; b -= a; b ^= (a << 8); >+ c -= a; c -= b; c ^= (b >> 13); >+ a -= b; a -= c; a ^= (c >> 12); >+ b -= c; b -= a; b ^= (a << 16); >+ c -= a; c -= b; c ^= (b >> 5); >+ a -= b; a -= c; a ^= (c >> 3); >+ b -= c; b -= a; b ^= (a << 10); >+ c -= a; c -= b; c ^= (b >> 15); >+ return c; >+} >+ >+static void TestFunction(int thread_salt, SpinLock* spinlock) { >+ for (int i = 0; i < kIters; i++) { >+ SpinLockHolder h(spinlock); >+ for (int j = 0; j < kArrayLength; j++) { >+ const int index = (j + thread_salt) % kArrayLength; >+ values[index] = Hash32(values[index], thread_salt); >+ std::this_thread::yield(); >+ } >+ } >+} >+ >+static void ThreadedTest(SpinLock* spinlock) { >+ std::vector<std::thread> threads; >+ for (int i = 0; i < kNumThreads; ++i) { >+ threads.push_back(std::thread(TestFunction, i, spinlock)); >+ } >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ >+ SpinLockHolder h(spinlock); >+ for (int i = 1; i < kArrayLength; i++) { >+ EXPECT_EQ(values[0], values[i]); >+ } >+} >+ >+TEST(SpinLock, StackNonCooperativeDisablesScheduling) { >+ SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); >+ spinlock.Lock(); >+ EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed()); >+ spinlock.Unlock(); >+} >+ >+TEST(SpinLock, StaticNonCooperativeDisablesScheduling) { >+ static_noncooperative_spinlock.Lock(); >+ EXPECT_FALSE(base_internal::SchedulingGuard::ReschedulingIsAllowed()); >+ static_noncooperative_spinlock.Unlock(); >+} >+ >+TEST(SpinLock, WaitCyclesEncoding) { >+ // These are implementation details not exported by SpinLock. >+ const int kProfileTimestampShift = 7; >+ const int kLockwordReservedShift = 3; >+ const uint32_t kSpinLockSleeper = 8; >+ >+ // We should be able to encode up to (1^kMaxCycleBits - 1) without clamping >+ // but the lower kProfileTimestampShift will be dropped. >+ const int kMaxCyclesShift = >+ 32 - kLockwordReservedShift + kProfileTimestampShift; >+ const uint64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1; >+ >+ // These bits should be zero after encoding. >+ const uint32_t kLockwordReservedMask = (1 << kLockwordReservedShift) - 1; >+ >+ // These bits are dropped when wait cycles are encoded. >+ const uint64_t kProfileTimestampMask = (1 << kProfileTimestampShift) - 1; >+ >+ // Test a bunch of random values >+ std::default_random_engine generator; >+ // Shift to avoid overflow below. >+ std::uniform_int_distribution<uint64_t> time_distribution( >+ 0, std::numeric_limits<uint64_t>::max() >> 4); >+ std::uniform_int_distribution<uint64_t> cycle_distribution(0, kMaxCycles); >+ >+ for (int i = 0; i < 100; i++) { >+ int64_t start_time = time_distribution(generator); >+ int64_t cycles = cycle_distribution(generator); >+ int64_t end_time = start_time + cycles; >+ uint32_t lock_value = SpinLockTest::EncodeWaitCycles(start_time, end_time); >+ EXPECT_EQ(0, lock_value & kLockwordReservedMask); >+ uint64_t decoded = SpinLockTest::DecodeWaitCycles(lock_value); >+ EXPECT_EQ(0, decoded & kProfileTimestampMask); >+ EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded); >+ } >+ >+ // Test corner cases >+ int64_t start_time = time_distribution(generator); >+ EXPECT_EQ(0, SpinLockTest::EncodeWaitCycles(start_time, start_time)); >+ EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(0)); >+ EXPECT_EQ(0, SpinLockTest::DecodeWaitCycles(kLockwordReservedMask)); >+ EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask, >+ SpinLockTest::DecodeWaitCycles(~kLockwordReservedMask)); >+ >+ // Check that we cannot produce kSpinLockSleeper during encoding. >+ int64_t sleeper_cycles = >+ kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift); >+ uint32_t sleeper_value = >+ SpinLockTest::EncodeWaitCycles(start_time, start_time + sleeper_cycles); >+ EXPECT_NE(sleeper_value, kSpinLockSleeper); >+ >+ // Test clamping >+ uint32_t max_value = >+ SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles); >+ uint64_t max_value_decoded = SpinLockTest::DecodeWaitCycles(max_value); >+ uint64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask; >+ EXPECT_EQ(expected_max_value_decoded, max_value_decoded); >+ >+ const int64_t step = (1 << kProfileTimestampShift); >+ uint32_t after_max_value = >+ SpinLockTest::EncodeWaitCycles(start_time, start_time + kMaxCycles + step); >+ uint64_t after_max_value_decoded = >+ SpinLockTest::DecodeWaitCycles(after_max_value); >+ EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded); >+ >+ uint32_t before_max_value = SpinLockTest::EncodeWaitCycles( >+ start_time, start_time + kMaxCycles - step); >+ uint64_t before_max_value_decoded = >+ SpinLockTest::DecodeWaitCycles(before_max_value); >+ EXPECT_GT(expected_max_value_decoded, before_max_value_decoded); >+} >+TEST(SpinLockWithThreads, StaticSpinLock) { >+ ThreadedTest(&static_spinlock); >+} >+TEST(SpinLockWithThreads, StackSpinLock) { >+ SpinLock spinlock; >+ ThreadedTest(&spinlock); >+} >+ >+TEST(SpinLockWithThreads, StackCooperativeSpinLock) { >+ SpinLock spinlock(base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); >+ ThreadedTest(&spinlock); >+} >+ >+TEST(SpinLockWithThreads, StackNonCooperativeSpinLock) { >+ SpinLock spinlock(base_internal::SCHEDULE_KERNEL_ONLY); >+ ThreadedTest(&spinlock); >+} >+ >+TEST(SpinLockWithThreads, StaticCooperativeSpinLock) { >+ ThreadedTest(&static_cooperative_spinlock); >+} >+ >+TEST(SpinLockWithThreads, StaticNonCooperativeSpinLock) { >+ ThreadedTest(&static_noncooperative_spinlock); >+} >+ >+TEST(SpinLockWithThreads, DoesNotDeadlock) { >+ struct Helper { >+ static void NotifyThenLock(Notification* locked, SpinLock* spinlock, >+ BlockingCounter* b) { >+ locked->WaitForNotification(); // Wait for LockThenWait() to hold "s". >+ b->DecrementCount(); >+ SpinLockHolder l(spinlock); >+ } >+ >+ static void LockThenWait(Notification* locked, SpinLock* spinlock, >+ BlockingCounter* b) { >+ SpinLockHolder l(spinlock); >+ locked->Notify(); >+ b->Wait(); >+ } >+ >+ static void DeadlockTest(SpinLock* spinlock, int num_spinners) { >+ Notification locked; >+ BlockingCounter counter(num_spinners); >+ std::vector<std::thread> threads; >+ >+ threads.push_back( >+ std::thread(Helper::LockThenWait, &locked, spinlock, &counter)); >+ for (int i = 0; i < num_spinners; ++i) { >+ threads.push_back( >+ std::thread(Helper::NotifyThenLock, &locked, spinlock, &counter)); >+ } >+ >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ } >+ }; >+ >+ SpinLock stack_cooperative_spinlock( >+ base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL); >+ SpinLock stack_noncooperative_spinlock(base_internal::SCHEDULE_KERNEL_ONLY); >+ Helper::DeadlockTest(&stack_cooperative_spinlock, >+ base_internal::NumCPUs() * 2); >+ Helper::DeadlockTest(&stack_noncooperative_spinlock, >+ base_internal::NumCPUs() * 2); >+ Helper::DeadlockTest(&static_cooperative_spinlock, >+ base_internal::NumCPUs() * 2); >+ Helper::DeadlockTest(&static_noncooperative_spinlock, >+ base_internal::NumCPUs() * 2); >+} >+ >+} // namespace >+} // namespace base_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/thread_annotations.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/thread_annotations.h >new file mode 100644 >index 00000000000..fbb2797b825 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/thread_annotations.h >@@ -0,0 +1,257 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: thread_annotations.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains macro definitions for thread safety annotations >+// that allow developers to document the locking policies of multi-threaded >+// code. The annotations can also help program analysis tools to identify >+// potential thread safety issues. >+// >+// >+// These annotations are implemented using compiler attributes. Using the macros >+// defined here instead of raw attributes allow for portability and future >+// compatibility. >+// >+// When referring to mutexes in the arguments of the attributes, you should >+// use variable names or more complex expressions (e.g. my_object->mutex_) >+// that evaluate to a concrete mutex object whenever possible. If the mutex >+// you want to refer to is not in scope, you may use a member pointer >+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. >+ >+#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ >+#define ABSL_BASE_THREAD_ANNOTATIONS_H_ >+#if defined(__clang__) >+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) >+#else >+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op >+#endif >+ >+// GUARDED_BY() >+// >+// Documents if a shared field or global variable needs to be protected by a >+// mutex. GUARDED_BY() allows the user to specify a particular mutex that >+// should be held when accessing the annotated variable. >+// >+// Although this annotation (and PT_GUARDED_BY, below) cannot be applied to >+// local variables, a local variable and its associated mutex can often be >+// combined into a small class or struct, thereby allowing the annotation. >+// >+// Example: >+// >+// class Foo { >+// Mutex mu_; >+// int p1_ GUARDED_BY(mu_); >+// ... >+// }; >+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) >+ >+// PT_GUARDED_BY() >+// >+// Documents if the memory location pointed to by a pointer should be guarded >+// by a mutex when dereferencing the pointer. >+// >+// Example: >+// class Foo { >+// Mutex mu_; >+// int *p1_ PT_GUARDED_BY(mu_); >+// ... >+// }; >+// >+// Note that a pointer variable to a shared memory location could itself be a >+// shared variable. >+// >+// Example: >+// >+// // `q_`, guarded by `mu1_`, points to a shared memory location that is >+// // guarded by `mu2_`: >+// int *q_ GUARDED_BY(mu1_) PT_GUARDED_BY(mu2_); >+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) >+ >+// ACQUIRED_AFTER() / ACQUIRED_BEFORE() >+// >+// Documents the acquisition order between locks that can be held >+// simultaneously by a thread. For any two locks that need to be annotated >+// to establish an acquisition order, only one of them needs the annotation. >+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER >+// and ACQUIRED_BEFORE.) >+// >+// As with GUARDED_BY, this is only applicable to mutexes that are shared >+// fields or global variables. >+// >+// Example: >+// >+// Mutex m1_; >+// Mutex m2_ ACQUIRED_AFTER(m1_); >+#define ACQUIRED_AFTER(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) >+ >+#define ACQUIRED_BEFORE(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) >+ >+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED() >+// >+// Documents a function that expects a mutex to be held prior to entry. >+// The mutex is expected to be held both on entry to, and exit from, the >+// function. >+// >+// Example: >+// >+// Mutex mu1, mu2; >+// int a GUARDED_BY(mu1); >+// int b GUARDED_BY(mu2); >+// >+// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }; >+#define EXCLUSIVE_LOCKS_REQUIRED(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) >+ >+#define SHARED_LOCKS_REQUIRED(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) >+ >+// LOCKS_EXCLUDED() >+// >+// Documents the locks acquired in the body of the function. These locks >+// cannot be held when calling this function (as Abseil's `Mutex` locks are >+// non-reentrant). >+#define LOCKS_EXCLUDED(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) >+ >+// LOCK_RETURNED() >+// >+// Documents a function that returns a mutex without acquiring it. For example, >+// a public getter method that returns a pointer to a private mutex should >+// be annotated with LOCK_RETURNED. >+#define LOCK_RETURNED(x) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) >+ >+// LOCKABLE >+// >+// Documents if a class/type is a lockable type (such as the `Mutex` class). >+#define LOCKABLE \ >+ THREAD_ANNOTATION_ATTRIBUTE__(lockable) >+ >+// SCOPED_LOCKABLE >+// >+// Documents if a class does RAII locking (such as the `MutexLock` class). >+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is >+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no >+// arguments; the analysis will assume that the destructor unlocks whatever the >+// constructor locked. >+#define SCOPED_LOCKABLE \ >+ THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) >+ >+// EXCLUSIVE_LOCK_FUNCTION() >+// >+// Documents functions that acquire a lock in the body of a function, and do >+// not release it. >+#define EXCLUSIVE_LOCK_FUNCTION(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) >+ >+// SHARED_LOCK_FUNCTION() >+// >+// Documents functions that acquire a shared (reader) lock in the body of a >+// function, and do not release it. >+#define SHARED_LOCK_FUNCTION(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) >+ >+// UNLOCK_FUNCTION() >+// >+// Documents functions that expect a lock to be held on entry to the function, >+// and release it in the body of the function. >+#define UNLOCK_FUNCTION(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) >+ >+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION() >+// >+// Documents functions that try to acquire a lock, and return success or failure >+// (or a non-boolean value that can be interpreted as a boolean). >+// The first argument should be `true` for functions that return `true` on >+// success, or `false` for functions that return `false` on success. The second >+// argument specifies the mutex that is locked on success. If unspecified, this >+// mutex is assumed to be `this`. >+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) >+ >+#define SHARED_TRYLOCK_FUNCTION(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) >+ >+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK() >+// >+// Documents functions that dynamically check to see if a lock is held, and fail >+// if it is not held. >+#define ASSERT_EXCLUSIVE_LOCK(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) >+ >+#define ASSERT_SHARED_LOCK(...) \ >+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) >+ >+// NO_THREAD_SAFETY_ANALYSIS >+// >+// Turns off thread safety checking within the body of a particular function. >+// This annotation is used to mark functions that are known to be correct, but >+// the locking behavior is more complicated than the analyzer can handle. >+#define NO_THREAD_SAFETY_ANALYSIS \ >+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) >+ >+//------------------------------------------------------------------------------ >+// Tool-Supplied Annotations >+//------------------------------------------------------------------------------ >+ >+// TS_UNCHECKED should be placed around lock expressions that are not valid >+// C++ syntax, but which are present for documentation purposes. These >+// annotations will be ignored by the analysis. >+#define TS_UNCHECKED(x) "" >+ >+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax. >+// It is used by automated tools to mark and disable invalid expressions. >+// The annotation should either be fixed, or changed to TS_UNCHECKED. >+#define TS_FIXME(x) "" >+ >+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of >+// a particular function. However, this attribute is used to mark functions >+// that are incorrect and need to be fixed. It is used by automated tools to >+// avoid breaking the build when the analysis is updated. >+// Code owners are expected to eventually fix the routine. >+#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS >+ >+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY >+// annotation that needs to be fixed, because it is producing thread safety >+// warning. It disables the GUARDED_BY. >+#define GUARDED_BY_FIXME(x) >+ >+// Disables warnings for a single read operation. This can be used to avoid >+// warnings when it is known that the read is not actually involved in a race, >+// but the compiler cannot confirm that. >+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x) >+ >+ >+namespace thread_safety_analysis { >+ >+// Takes a reference to a guarded data member, and returns an unguarded >+// reference. >+template <typename T> >+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS { >+ return v; >+} >+ >+template <typename T> >+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS { >+ return v; >+} >+ >+} // namespace thread_safety_analysis >+ >+#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/throw_delegate_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/throw_delegate_test.cc >new file mode 100644 >index 00000000000..0f15df0492b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/base/throw_delegate_test.cc >@@ -0,0 +1,94 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/base/internal/throw_delegate.h" >+ >+#include <functional> >+#include <new> >+#include <stdexcept> >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+using absl::base_internal::ThrowStdLogicError; >+using absl::base_internal::ThrowStdInvalidArgument; >+using absl::base_internal::ThrowStdDomainError; >+using absl::base_internal::ThrowStdLengthError; >+using absl::base_internal::ThrowStdOutOfRange; >+using absl::base_internal::ThrowStdRuntimeError; >+using absl::base_internal::ThrowStdRangeError; >+using absl::base_internal::ThrowStdOverflowError; >+using absl::base_internal::ThrowStdUnderflowError; >+using absl::base_internal::ThrowStdBadFunctionCall; >+using absl::base_internal::ThrowStdBadAlloc; >+ >+constexpr const char* what_arg = "The quick brown fox jumps over the lazy dog"; >+ >+template <typename E> >+void ExpectThrowChar(void (*f)(const char*)) { >+ try { >+ f(what_arg); >+ FAIL() << "Didn't throw"; >+ } catch (const E& e) { >+ EXPECT_STREQ(e.what(), what_arg); >+ } >+} >+ >+template <typename E> >+void ExpectThrowString(void (*f)(const std::string&)) { >+ try { >+ f(what_arg); >+ FAIL() << "Didn't throw"; >+ } catch (const E& e) { >+ EXPECT_STREQ(e.what(), what_arg); >+ } >+} >+ >+template <typename E> >+void ExpectThrowNoWhat(void (*f)()) { >+ try { >+ f(); >+ FAIL() << "Didn't throw"; >+ } catch (const E& e) { >+ } >+} >+ >+TEST(ThrowHelper, Test) { >+ // Not using EXPECT_THROW because we want to check the .what() message too. >+ ExpectThrowChar<std::logic_error>(ThrowStdLogicError); >+ ExpectThrowChar<std::invalid_argument>(ThrowStdInvalidArgument); >+ ExpectThrowChar<std::domain_error>(ThrowStdDomainError); >+ ExpectThrowChar<std::length_error>(ThrowStdLengthError); >+ ExpectThrowChar<std::out_of_range>(ThrowStdOutOfRange); >+ ExpectThrowChar<std::runtime_error>(ThrowStdRuntimeError); >+ ExpectThrowChar<std::range_error>(ThrowStdRangeError); >+ ExpectThrowChar<std::overflow_error>(ThrowStdOverflowError); >+ ExpectThrowChar<std::underflow_error>(ThrowStdUnderflowError); >+ >+ ExpectThrowString<std::logic_error>(ThrowStdLogicError); >+ ExpectThrowString<std::invalid_argument>(ThrowStdInvalidArgument); >+ ExpectThrowString<std::domain_error>(ThrowStdDomainError); >+ ExpectThrowString<std::length_error>(ThrowStdLengthError); >+ ExpectThrowString<std::out_of_range>(ThrowStdOutOfRange); >+ ExpectThrowString<std::runtime_error>(ThrowStdRuntimeError); >+ ExpectThrowString<std::range_error>(ThrowStdRangeError); >+ ExpectThrowString<std::overflow_error>(ThrowStdOverflowError); >+ ExpectThrowString<std::underflow_error>(ThrowStdUnderflowError); >+ >+ ExpectThrowNoWhat<std::bad_function_call>(ThrowStdBadFunctionCall); >+ ExpectThrowNoWhat<std::bad_alloc>(ThrowStdBadAlloc); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/compiler_config_setting.bzl b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/compiler_config_setting.bzl >new file mode 100644 >index 00000000000..b77c4f563b9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/compiler_config_setting.bzl >@@ -0,0 +1,39 @@ >+# >+# Copyright 2018 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+"""Creates config_setting that allows selecting based on 'compiler' value.""" >+ >+def create_llvm_config(name, visibility): >+ # The "do_not_use_tools_cpp_compiler_present" attribute exists to >+ # distinguish between older versions of Bazel that do not support >+ # "@bazel_tools//tools/cpp:compiler" flag_value, and newer ones that do. >+ # In the future, the only way to select on the compiler will be through >+ # flag_values{"@bazel_tools//tools/cpp:compiler"} and the else branch can >+ # be removed. >+ if hasattr(cc_common, "do_not_use_tools_cpp_compiler_present"): >+ native.config_setting( >+ name = name, >+ flag_values = { >+ "@bazel_tools//tools/cpp:compiler": "llvm", >+ }, >+ visibility = visibility, >+ ) >+ else: >+ native.config_setting( >+ name = name, >+ values = {"compiler": "llvm"}, >+ visibility = visibility, >+ ) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.bazel >new file mode 100644 >index 00000000000..6d5c958f382 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.bazel >@@ -0,0 +1,183 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+ "ABSL_EXCEPTIONS_FLAG", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "compressed_tuple", >+ hdrs = ["internal/compressed_tuple.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/utility", >+ ], >+) >+ >+cc_test( >+ name = "compressed_tuple_test", >+ srcs = ["internal/compressed_tuple_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":compressed_tuple", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "fixed_array", >+ hdrs = ["fixed_array.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":compressed_tuple", >+ "//absl/algorithm", >+ "//absl/base:core_headers", >+ "//absl/base:dynamic_annotations", >+ "//absl/base:throw_delegate", >+ "//absl/memory", >+ ], >+) >+ >+cc_test( >+ name = "fixed_array_test", >+ srcs = ["fixed_array_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":fixed_array", >+ "//absl/base:exception_testing", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "fixed_array_test_noexceptions", >+ srcs = ["fixed_array_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":fixed_array", >+ "//absl/base:exception_testing", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "fixed_array_exception_safety_test", >+ srcs = ["fixed_array_exception_safety_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":fixed_array", >+ "//absl/base:exception_safety_testing", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "fixed_array_benchmark", >+ srcs = ["fixed_array_benchmark.cc"], >+ copts = ABSL_TEST_COPTS + ["$(STACK_FRAME_UNLIMITED)"], >+ tags = ["benchmark"], >+ deps = [ >+ ":fixed_array", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_library( >+ name = "inlined_vector", >+ hdrs = ["inlined_vector.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/algorithm", >+ "//absl/base:core_headers", >+ "//absl/base:throw_delegate", >+ "//absl/memory", >+ ], >+) >+ >+cc_test( >+ name = "inlined_vector_test", >+ srcs = ["inlined_vector_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":inlined_vector", >+ ":test_instance_tracker", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/base:exception_testing", >+ "//absl/memory", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "inlined_vector_test_noexceptions", >+ srcs = ["inlined_vector_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":inlined_vector", >+ ":test_instance_tracker", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/base:exception_testing", >+ "//absl/memory", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "inlined_vector_benchmark", >+ srcs = ["inlined_vector_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ deps = [ >+ ":inlined_vector", >+ "//absl/base", >+ "//absl/strings", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_library( >+ name = "test_instance_tracker", >+ testonly = 1, >+ srcs = ["internal/test_instance_tracker.cc"], >+ hdrs = ["internal/test_instance_tracker.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+) >+ >+cc_test( >+ name = "test_instance_tracker_test", >+ srcs = ["internal/test_instance_tracker_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":test_instance_tracker", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.gn >new file mode 100644 >index 00000000000..001a2a36d48 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/BUILD.gn >@@ -0,0 +1,86 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("compressed_tuple") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/compressed_tuple.h", >+ ] >+ deps = [ >+ "../utility", >+ ] >+} >+ >+source_set("fixed_array") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "fixed_array.h", >+ ] >+ deps = [ >+ ":compressed_tuple", >+ "../algorithm", >+ "../base:core_headers", >+ "../base:dynamic_annotations", >+ "../base:throw_delegate", >+ "../memory", >+ ] >+} >+ >+source_set("inlined_vector") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "inlined_vector.h", >+ ] >+ deps = [ >+ "../algorithm", >+ "../base:core_headers", >+ "../base:throw_delegate", >+ "../memory", >+ ] >+} >+ >+source_set("test_instance_tracker") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/test_instance_tracker.cc", >+ ] >+ public = [ >+ "internal/test_instance_tracker.h", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/CMakeLists.txt >new file mode 100644 >index 00000000000..123e4c4849a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/CMakeLists.txt >@@ -0,0 +1,144 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+ >+list(APPEND CONTAINER_PUBLIC_HEADERS >+ "fixed_array.h" >+ "inlined_vector.h" >+) >+ >+ >+list(APPEND CONTAINER_INTERNAL_HEADERS >+ "internal/test_instance_tracker.h" >+) >+ >+ >+absl_header_library( >+ TARGET >+ absl_container >+ EXPORT_NAME >+ container >+) >+ >+ >+# >+## TESTS >+# >+ >+list(APPEND TEST_INSTANCE_TRACKER_LIB_SRC >+ "internal/test_instance_tracker.cc" >+ ${CONTAINER_PUBLIC_HEADERS} >+ ${CONTAINER_INTERNAL_HEADERS} >+) >+ >+ >+absl_library( >+ TARGET >+ test_instance_tracker_lib >+ SOURCES >+ ${TEST_INSTANCE_TRACKER_LIB_SRC} >+ PUBLIC_LIBRARIES >+ absl::container >+) >+ >+ >+ >+# test fixed_array_test >+set(FIXED_ARRAY_TEST_SRC "fixed_array_test.cc") >+set(FIXED_ARRAY_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) >+ >+absl_test( >+ TARGET >+ fixed_array_test >+ SOURCES >+ ${FIXED_ARRAY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+ >+absl_test( >+ TARGET >+ fixed_array_test_noexceptions >+ SOURCES >+ ${FIXED_ARRAY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${FIXED_ARRAY_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test fixed_array_exception_safety_test >+set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc") >+set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES >+ absl::container >+ absl_base_internal_exception_safety_testing >+) >+ >+absl_test( >+ TARGET >+ fixed_array_exception_safety_test >+ SOURCES >+ ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+# test inlined_vector_test >+set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc") >+set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) >+ >+absl_test( >+ TARGET >+ inlined_vector_test >+ SOURCES >+ ${INLINED_VECTOR_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} >+) >+ >+absl_test( >+ TARGET >+ inlined_vector_test_noexceptions >+ SOURCES >+ ${INLINED_VECTOR_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${INLINED_VECTOR_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_NOEXCEPTION_CXXFLAGS} >+) >+ >+ >+# test test_instance_tracker_test >+set(TEST_INSTANCE_TRACKER_TEST_SRC "internal/test_instance_tracker_test.cc") >+set(TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) >+ >+ >+absl_test( >+ TARGET >+ test_instance_tracker_test >+ SOURCES >+ ${TEST_INSTANCE_TRACKER_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${TEST_INSTANCE_TRACKER_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array.h >new file mode 100644 >index 00000000000..182258f623e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array.h >@@ -0,0 +1,512 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: fixed_array.h >+// ----------------------------------------------------------------------------- >+// >+// A `FixedArray<T>` represents a non-resizable array of `T` where the length of >+// the array can be determined at run-time. It is a good replacement for >+// non-standard and deprecated uses of `alloca()` and variable length arrays >+// within the GCC extension. (See >+// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html). >+// >+// `FixedArray` allocates small arrays inline, keeping performance fast by >+// avoiding heap operations. It also helps reduce the chances of >+// accidentally overflowing your stack if large input is passed to >+// your function. >+ >+#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_ >+#define ABSL_CONTAINER_FIXED_ARRAY_H_ >+ >+#include <algorithm> >+#include <array> >+#include <cassert> >+#include <cstddef> >+#include <initializer_list> >+#include <iterator> >+#include <limits> >+#include <memory> >+#include <new> >+#include <type_traits> >+ >+#include "absl/algorithm/algorithm.h" >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/throw_delegate.h" >+#include "absl/base/macros.h" >+#include "absl/base/optimization.h" >+#include "absl/base/port.h" >+#include "absl/container/internal/compressed_tuple.h" >+#include "absl/memory/memory.h" >+ >+namespace absl { >+ >+constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1); >+ >+// ----------------------------------------------------------------------------- >+// FixedArray >+// ----------------------------------------------------------------------------- >+// >+// A `FixedArray` provides a run-time fixed-size array, allocating a small array >+// inline for efficiency. >+// >+// Most users should not specify an `inline_elements` argument and let >+// `FixedArray` automatically determine the number of elements >+// to store inline based on `sizeof(T)`. If `inline_elements` is specified, the >+// `FixedArray` implementation will use inline storage for arrays with a >+// length <= `inline_elements`. >+// >+// Note that a `FixedArray` constructed with a `size_type` argument will >+// default-initialize its values by leaving trivially constructible types >+// uninitialized (e.g. int, int[4], double), and others default-constructed. >+// This matches the behavior of c-style arrays and `std::array`, but not >+// `std::vector`. >+// >+// Note that `FixedArray` does not provide a public allocator; if it requires a >+// heap allocation, it will do so with global `::operator new[]()` and >+// `::operator delete[]()`, even if T provides class-scope overrides for these >+// operators. >+template <typename T, size_t N = kFixedArrayUseDefault, >+ typename A = std::allocator<T>> >+class FixedArray { >+ static_assert(!std::is_array<T>::value || std::extent<T>::value > 0, >+ "Arrays with unknown bounds cannot be used with FixedArray."); >+ >+ static constexpr size_t kInlineBytesDefault = 256; >+ >+ using AllocatorTraits = std::allocator_traits<A>; >+ // std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17, >+ // but this seems to be mostly pedantic. >+ template <typename Iterator> >+ using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible< >+ typename std::iterator_traits<Iterator>::iterator_category, >+ std::forward_iterator_tag>::value>; >+ static constexpr bool NoexceptCopyable() { >+ return std::is_nothrow_copy_constructible<StorageElement>::value && >+ absl::allocator_is_nothrow<allocator_type>::value; >+ } >+ static constexpr bool NoexceptMovable() { >+ return std::is_nothrow_move_constructible<StorageElement>::value && >+ absl::allocator_is_nothrow<allocator_type>::value; >+ } >+ static constexpr bool DefaultConstructorIsNonTrivial() { >+ return !absl::is_trivially_default_constructible<StorageElement>::value; >+ } >+ >+ public: >+ using allocator_type = typename AllocatorTraits::allocator_type; >+ using value_type = typename allocator_type::value_type; >+ using pointer = typename allocator_type::pointer; >+ using const_pointer = typename allocator_type::const_pointer; >+ using reference = typename allocator_type::reference; >+ using const_reference = typename allocator_type::const_reference; >+ using size_type = typename allocator_type::size_type; >+ using difference_type = typename allocator_type::difference_type; >+ using iterator = pointer; >+ using const_iterator = const_pointer; >+ using reverse_iterator = std::reverse_iterator<iterator>; >+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; >+ >+ static constexpr size_type inline_elements = >+ (N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type) >+ : static_cast<size_type>(N)); >+ >+ FixedArray( >+ const FixedArray& other, >+ const allocator_type& a = allocator_type()) noexcept(NoexceptCopyable()) >+ : FixedArray(other.begin(), other.end(), a) {} >+ >+ FixedArray( >+ FixedArray&& other, >+ const allocator_type& a = allocator_type()) noexcept(NoexceptMovable()) >+ : FixedArray(std::make_move_iterator(other.begin()), >+ std::make_move_iterator(other.end()), a) {} >+ >+ // Creates an array object that can store `n` elements. >+ // Note that trivially constructible elements will be uninitialized. >+ explicit FixedArray(size_type n, const allocator_type& a = allocator_type()) >+ : storage_(n, a) { >+ if (DefaultConstructorIsNonTrivial()) { >+ memory_internal::ConstructStorage(storage_.alloc(), storage_.begin(), >+ storage_.end()); >+ } >+ } >+ >+ // Creates an array initialized with `n` copies of `val`. >+ FixedArray(size_type n, const value_type& val, >+ const allocator_type& a = allocator_type()) >+ : storage_(n, a) { >+ memory_internal::ConstructStorage(storage_.alloc(), storage_.begin(), >+ storage_.end(), val); >+ } >+ >+ // Creates an array initialized with the size and contents of `init_list`. >+ FixedArray(std::initializer_list<value_type> init_list, >+ const allocator_type& a = allocator_type()) >+ : FixedArray(init_list.begin(), init_list.end(), a) {} >+ >+ // Creates an array initialized with the elements from the input >+ // range. The array's size will always be `std::distance(first, last)`. >+ // REQUIRES: Iterator must be a forward_iterator or better. >+ template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr> >+ FixedArray(Iterator first, Iterator last, >+ const allocator_type& a = allocator_type()) >+ : storage_(std::distance(first, last), a) { >+ memory_internal::CopyToStorageFromRange(storage_.alloc(), storage_.begin(), >+ first, last); >+ } >+ >+ ~FixedArray() noexcept { >+ for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) { >+ AllocatorTraits::destroy(*storage_.alloc(), cur); >+ } >+ } >+ >+ // Assignments are deleted because they break the invariant that the size of a >+ // `FixedArray` never changes. >+ void operator=(FixedArray&&) = delete; >+ void operator=(const FixedArray&) = delete; >+ >+ // FixedArray::size() >+ // >+ // Returns the length of the fixed array. >+ size_type size() const { return storage_.size(); } >+ >+ // FixedArray::max_size() >+ // >+ // Returns the largest possible value of `std::distance(begin(), end())` for a >+ // `FixedArray<T>`. This is equivalent to the most possible addressable bytes >+ // over the number of bytes taken by T. >+ constexpr size_type max_size() const { >+ return std::numeric_limits<difference_type>::max() / sizeof(value_type); >+ } >+ >+ // FixedArray::empty() >+ // >+ // Returns whether or not the fixed array is empty. >+ bool empty() const { return size() == 0; } >+ >+ // FixedArray::memsize() >+ // >+ // Returns the memory size of the fixed array in bytes. >+ size_t memsize() const { return size() * sizeof(value_type); } >+ >+ // FixedArray::data() >+ // >+ // Returns a const T* pointer to elements of the `FixedArray`. This pointer >+ // can be used to access (but not modify) the contained elements. >+ const_pointer data() const { return AsValueType(storage_.begin()); } >+ >+ // Overload of FixedArray::data() to return a T* pointer to elements of the >+ // fixed array. This pointer can be used to access and modify the contained >+ // elements. >+ pointer data() { return AsValueType(storage_.begin()); } >+ >+ // FixedArray::operator[] >+ // >+ // Returns a reference the ith element of the fixed array. >+ // REQUIRES: 0 <= i < size() >+ reference operator[](size_type i) { >+ assert(i < size()); >+ return data()[i]; >+ } >+ >+ // Overload of FixedArray::operator()[] to return a const reference to the >+ // ith element of the fixed array. >+ // REQUIRES: 0 <= i < size() >+ const_reference operator[](size_type i) const { >+ assert(i < size()); >+ return data()[i]; >+ } >+ >+ // FixedArray::at >+ // >+ // Bounds-checked access. Returns a reference to the ith element of the >+ // fiexed array, or throws std::out_of_range >+ reference at(size_type i) { >+ if (ABSL_PREDICT_FALSE(i >= size())) { >+ base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); >+ } >+ return data()[i]; >+ } >+ >+ // Overload of FixedArray::at() to return a const reference to the ith element >+ // of the fixed array. >+ const_reference at(size_type i) const { >+ if (ABSL_PREDICT_FALSE(i >= size())) { >+ base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check"); >+ } >+ return data()[i]; >+ } >+ >+ // FixedArray::front() >+ // >+ // Returns a reference to the first element of the fixed array. >+ reference front() { return *begin(); } >+ >+ // Overload of FixedArray::front() to return a reference to the first element >+ // of a fixed array of const values. >+ const_reference front() const { return *begin(); } >+ >+ // FixedArray::back() >+ // >+ // Returns a reference to the last element of the fixed array. >+ reference back() { return *(end() - 1); } >+ >+ // Overload of FixedArray::back() to return a reference to the last element >+ // of a fixed array of const values. >+ const_reference back() const { return *(end() - 1); } >+ >+ // FixedArray::begin() >+ // >+ // Returns an iterator to the beginning of the fixed array. >+ iterator begin() { return data(); } >+ >+ // Overload of FixedArray::begin() to return a const iterator to the >+ // beginning of the fixed array. >+ const_iterator begin() const { return data(); } >+ >+ // FixedArray::cbegin() >+ // >+ // Returns a const iterator to the beginning of the fixed array. >+ const_iterator cbegin() const { return begin(); } >+ >+ // FixedArray::end() >+ // >+ // Returns an iterator to the end of the fixed array. >+ iterator end() { return data() + size(); } >+ >+ // Overload of FixedArray::end() to return a const iterator to the end of the >+ // fixed array. >+ const_iterator end() const { return data() + size(); } >+ >+ // FixedArray::cend() >+ // >+ // Returns a const iterator to the end of the fixed array. >+ const_iterator cend() const { return end(); } >+ >+ // FixedArray::rbegin() >+ // >+ // Returns a reverse iterator from the end of the fixed array. >+ reverse_iterator rbegin() { return reverse_iterator(end()); } >+ >+ // Overload of FixedArray::rbegin() to return a const reverse iterator from >+ // the end of the fixed array. >+ const_reverse_iterator rbegin() const { >+ return const_reverse_iterator(end()); >+ } >+ >+ // FixedArray::crbegin() >+ // >+ // Returns a const reverse iterator from the end of the fixed array. >+ const_reverse_iterator crbegin() const { return rbegin(); } >+ >+ // FixedArray::rend() >+ // >+ // Returns a reverse iterator from the beginning of the fixed array. >+ reverse_iterator rend() { return reverse_iterator(begin()); } >+ >+ // Overload of FixedArray::rend() for returning a const reverse iterator >+ // from the beginning of the fixed array. >+ const_reverse_iterator rend() const { >+ return const_reverse_iterator(begin()); >+ } >+ >+ // FixedArray::crend() >+ // >+ // Returns a reverse iterator from the beginning of the fixed array. >+ const_reverse_iterator crend() const { return rend(); } >+ >+ // FixedArray::fill() >+ // >+ // Assigns the given `value` to all elements in the fixed array. >+ void fill(const value_type& val) { std::fill(begin(), end(), val); } >+ >+ // Relational operators. Equality operators are elementwise using >+ // `operator==`, while order operators order FixedArrays lexicographically. >+ friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) { >+ return absl::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); >+ } >+ >+ friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) { >+ return !(lhs == rhs); >+ } >+ >+ friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) { >+ return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), >+ rhs.end()); >+ } >+ >+ friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) { >+ return rhs < lhs; >+ } >+ >+ friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) { >+ return !(rhs < lhs); >+ } >+ >+ friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) { >+ return !(lhs < rhs); >+ } >+ private: >+ // StorageElement >+ // >+ // For FixedArrays with a C-style-array value_type, StorageElement is a POD >+ // wrapper struct called StorageElementWrapper that holds the value_type >+ // instance inside. This is needed for construction and destruction of the >+ // entire array regardless of how many dimensions it has. For all other cases, >+ // StorageElement is just an alias of value_type. >+ // >+ // Maintainer's Note: The simpler solution would be to simply wrap value_type >+ // in a struct whether it's an array or not. That causes some paranoid >+ // diagnostics to misfire, believing that 'data()' returns a pointer to a >+ // single element, rather than the packed array that it really is. >+ // e.g.: >+ // >+ // FixedArray<char> buf(1); >+ // sprintf(buf.data(), "foo"); >+ // >+ // error: call to int __builtin___sprintf_chk(etc...) >+ // will always overflow destination buffer [-Werror] >+ // >+ template <typename OuterT = value_type, >+ typename InnerT = absl::remove_extent_t<OuterT>, >+ size_t InnerN = std::extent<OuterT>::value> >+ struct StorageElementWrapper { >+ InnerT array[InnerN]; >+ }; >+ >+ using StorageElement = >+ absl::conditional_t<std::is_array<value_type>::value, >+ StorageElementWrapper<value_type>, value_type>; >+ using StorageElementBuffer = >+ absl::aligned_storage_t<sizeof(StorageElement), alignof(StorageElement)>; >+ >+ static pointer AsValueType(pointer ptr) { return ptr; } >+ static pointer AsValueType(StorageElementWrapper<value_type>* ptr) { >+ return std::addressof(ptr->array); >+ } >+ >+ static_assert(sizeof(StorageElement) == sizeof(value_type), ""); >+ static_assert(alignof(StorageElement) == alignof(value_type), ""); >+ >+ struct NonEmptyInlinedStorage { >+ StorageElement* data() { >+ return reinterpret_cast<StorageElement*>(inlined_storage_.data()); >+ } >+ >+#ifdef ADDRESS_SANITIZER >+ void* RedzoneBegin() { return &redzone_begin_; } >+ void* RedzoneEnd() { return &redzone_end_ + 1; } >+#endif // ADDRESS_SANITIZER >+ >+ void AnnotateConstruct(size_type); >+ void AnnotateDestruct(size_type); >+ >+ ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_); >+ std::array<StorageElementBuffer, inline_elements> inlined_storage_; >+ ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_); >+ }; >+ >+ struct EmptyInlinedStorage { >+ StorageElement* data() { return nullptr; } >+ void AnnotateConstruct(size_type) {} >+ void AnnotateDestruct(size_type) {} >+ }; >+ >+ using InlinedStorage = >+ absl::conditional_t<inline_elements == 0, EmptyInlinedStorage, >+ NonEmptyInlinedStorage>; >+ >+ // Storage >+ // >+ // An instance of Storage manages the inline and out-of-line memory for >+ // instances of FixedArray. This guarantees that even when construction of >+ // individual elements fails in the FixedArray constructor body, the >+ // destructor for Storage will still be called and out-of-line memory will be >+ // properly deallocated. >+ // >+ class Storage : public InlinedStorage { >+ public: >+ Storage(size_type n, const allocator_type& a) >+ : size_alloc_(n, a), data_(InitializeData()) {} >+ >+ ~Storage() noexcept { >+ if (UsingInlinedStorage(size())) { >+ InlinedStorage::AnnotateDestruct(size()); >+ } else { >+ AllocatorTraits::deallocate(*alloc(), AsValueType(begin()), size()); >+ } >+ } >+ >+ size_type size() const { return size_alloc_.template get<0>(); } >+ StorageElement* begin() const { return data_; } >+ StorageElement* end() const { return begin() + size(); } >+ allocator_type* alloc() { >+ return std::addressof(size_alloc_.template get<1>()); >+ } >+ >+ private: >+ static bool UsingInlinedStorage(size_type n) { >+ return n <= inline_elements; >+ } >+ >+ StorageElement* InitializeData() { >+ if (UsingInlinedStorage(size())) { >+ InlinedStorage::AnnotateConstruct(size()); >+ return InlinedStorage::data(); >+ } else { >+ return reinterpret_cast<StorageElement*>( >+ AllocatorTraits::allocate(*alloc(), size())); >+ } >+ } >+ >+ // `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s >+ container_internal::CompressedTuple<size_type, allocator_type> size_alloc_; >+ StorageElement* data_; >+ }; >+ >+ Storage storage_; >+}; >+ >+template <typename T, size_t N, typename A> >+constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault; >+ >+template <typename T, size_t N, typename A> >+constexpr typename FixedArray<T, N, A>::size_type >+ FixedArray<T, N, A>::inline_elements; >+ >+template <typename T, size_t N, typename A> >+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct( >+ typename FixedArray<T, N, A>::size_type n) { >+#ifdef ADDRESS_SANITIZER >+ if (!n) return; >+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(), data() + n); >+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(), RedzoneBegin()); >+#endif // ADDRESS_SANITIZER >+ static_cast<void>(n); // Mark used when not in asan mode >+} >+ >+template <typename T, size_t N, typename A> >+void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct( >+ typename FixedArray<T, N, A>::size_type n) { >+#ifdef ADDRESS_SANITIZER >+ if (!n) return; >+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n, RedzoneEnd()); >+ ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(), data()); >+#endif // ADDRESS_SANITIZER >+ static_cast<void>(n); // Mark used when not in asan mode >+} >+} // namespace absl >+#endif // ABSL_CONTAINER_FIXED_ARRAY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc >new file mode 100644 >index 00000000000..b4f0cf2aeb0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_benchmark.cc >@@ -0,0 +1,66 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/fixed_array.h" >+ >+#include <stddef.h> >+#include <string> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+// For benchmarking -- simple class with constructor and destructor that >+// set an int to a constant.. >+class SimpleClass { >+ public: >+ SimpleClass() : i(3) { } >+ ~SimpleClass() { i = 0; } >+ private: >+ int i; >+}; >+ >+template <typename C, size_t stack_size> >+void BM_FixedArray(benchmark::State& state) { >+ const int size = state.range(0); >+ for (auto _ : state) { >+ absl::FixedArray<C, stack_size> fa(size); >+ benchmark::DoNotOptimize(fa.data()); >+ } >+} >+BENCHMARK_TEMPLATE(BM_FixedArray, char, absl::kFixedArrayUseDefault) >+ ->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, char, 0)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, char, 1)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, char, 16)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, char, 256)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, char, 65536)->Range(0, 1 << 16); >+ >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, absl::kFixedArrayUseDefault) >+ ->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 0)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 1)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 16)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 256)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, SimpleClass, 65536)->Range(0, 1 << 16); >+ >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, absl::kFixedArrayUseDefault) >+ ->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 0)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 1)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 16)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 256)->Range(0, 1 << 16); >+BENCHMARK_TEMPLATE(BM_FixedArray, std::string, 65536)->Range(0, 1 << 16); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc >new file mode 100644 >index 00000000000..c123c2a1c0d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_exception_safety_test.cc >@@ -0,0 +1,117 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <initializer_list> >+ >+#include "absl/container/fixed_array.h" >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_safety_testing.h" >+ >+namespace absl { >+ >+namespace { >+ >+constexpr size_t kInlined = 25; >+constexpr size_t kSmallSize = kInlined / 2; >+constexpr size_t kLargeSize = kInlined * 2; >+ >+constexpr int kInitialValue = 5; >+constexpr int kUpdatedValue = 10; >+ >+using ::testing::TestThrowingCtor; >+ >+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; >+using FixedArr = absl::FixedArray<Thrower, kInlined>; >+ >+using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; >+using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>; >+ >+TEST(FixedArrayExceptionSafety, CopyConstructor) { >+ auto small = FixedArr(kSmallSize); >+ TestThrowingCtor<FixedArr>(small); >+ >+ auto large = FixedArr(kLargeSize); >+ TestThrowingCtor<FixedArr>(large); >+} >+ >+TEST(FixedArrayExceptionSafety, MoveConstructor) { >+ TestThrowingCtor<FixedArr>(FixedArr(kSmallSize)); >+ TestThrowingCtor<FixedArr>(FixedArr(kLargeSize)); >+ >+ // TypeSpec::kNoThrowMove >+ TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kSmallSize)); >+ TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize)); >+} >+ >+TEST(FixedArrayExceptionSafety, SizeConstructor) { >+ TestThrowingCtor<FixedArr>(kSmallSize); >+ TestThrowingCtor<FixedArr>(kLargeSize); >+} >+ >+TEST(FixedArrayExceptionSafety, SizeValueConstructor) { >+ TestThrowingCtor<FixedArr>(kSmallSize, Thrower()); >+ TestThrowingCtor<FixedArr>(kLargeSize, Thrower()); >+} >+ >+TEST(FixedArrayExceptionSafety, IteratorConstructor) { >+ auto small = FixedArr(kSmallSize); >+ TestThrowingCtor<FixedArr>(small.begin(), small.end()); >+ >+ auto large = FixedArr(kLargeSize); >+ TestThrowingCtor<FixedArr>(large.begin(), large.end()); >+} >+ >+TEST(FixedArrayExceptionSafety, InitListConstructor) { >+ constexpr int small_inlined = 3; >+ using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>; >+ >+ TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{}); >+ // Test inlined allocation >+ TestThrowingCtor<SmallFixedArr>( >+ std::initializer_list<Thrower>{Thrower{}, Thrower{}}); >+ // Test out of line allocation >+ TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{ >+ Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}}); >+} >+ >+testing::AssertionResult ReadMemory(FixedArr* fixed_arr) { >+ // Marked volatile to prevent optimization. Used for running asan tests. >+ volatile int sum = 0; >+ for (const auto& thrower : *fixed_arr) { >+ sum += thrower.Get(); >+ } >+ return testing::AssertionSuccess() << "Values sum to [" << sum << "]"; >+} >+ >+TEST(FixedArrayExceptionSafety, Fill) { >+ auto test_fill = testing::MakeExceptionSafetyTester() >+ .WithInvariants(ReadMemory) >+ .WithOperation([&](FixedArr* fixed_arr_ptr) { >+ auto thrower = >+ Thrower(kUpdatedValue, testing::nothrow_ctor); >+ fixed_arr_ptr->fill(thrower); >+ }); >+ >+ EXPECT_TRUE( >+ test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue))) >+ .Test()); >+ EXPECT_TRUE( >+ test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue))) >+ .Test()); >+} >+ >+} // namespace >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_test.cc >new file mode 100644 >index 00000000000..b07ebcb6d9c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/fixed_array_test.cc >@@ -0,0 +1,870 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/fixed_array.h" >+ >+#include <stdio.h> >+#include <cstring> >+#include <list> >+#include <memory> >+#include <numeric> >+#include <scoped_allocator> >+#include <stdexcept> >+#include <string> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_testing.h" >+#include "absl/memory/memory.h" >+ >+using ::testing::ElementsAreArray; >+ >+namespace { >+ >+// Helper routine to determine if a absl::FixedArray used stack allocation. >+template <typename ArrayType> >+static bool IsOnStack(const ArrayType& a) { >+ return a.size() <= ArrayType::inline_elements; >+} >+ >+class ConstructionTester { >+ public: >+ ConstructionTester() >+ : self_ptr_(this), >+ value_(0) { >+ constructions++; >+ } >+ ~ConstructionTester() { >+ assert(self_ptr_ == this); >+ self_ptr_ = nullptr; >+ destructions++; >+ } >+ >+ // These are incremented as elements are constructed and destructed so we can >+ // be sure all elements are properly cleaned up. >+ static int constructions; >+ static int destructions; >+ >+ void CheckConstructed() { >+ assert(self_ptr_ == this); >+ } >+ >+ void set(int value) { value_ = value; } >+ int get() { return value_; } >+ >+ private: >+ // self_ptr_ should always point to 'this' -- that's how we can be sure the >+ // constructor has been called. >+ ConstructionTester* self_ptr_; >+ int value_; >+}; >+ >+int ConstructionTester::constructions = 0; >+int ConstructionTester::destructions = 0; >+ >+// ThreeInts will initialize its three ints to the value stored in >+// ThreeInts::counter. The constructor increments counter so that each object >+// in an array of ThreeInts will have different values. >+class ThreeInts { >+ public: >+ ThreeInts() { >+ x_ = counter; >+ y_ = counter; >+ z_ = counter; >+ ++counter; >+ } >+ >+ static int counter; >+ >+ int x_, y_, z_; >+}; >+ >+int ThreeInts::counter = 0; >+ >+TEST(FixedArrayTest, CopyCtor) { >+ absl::FixedArray<int, 10> on_stack(5); >+ std::iota(on_stack.begin(), on_stack.end(), 0); >+ absl::FixedArray<int, 10> stack_copy = on_stack; >+ EXPECT_THAT(stack_copy, ElementsAreArray(on_stack)); >+ EXPECT_TRUE(IsOnStack(stack_copy)); >+ >+ absl::FixedArray<int, 10> allocated(15); >+ std::iota(allocated.begin(), allocated.end(), 0); >+ absl::FixedArray<int, 10> alloced_copy = allocated; >+ EXPECT_THAT(alloced_copy, ElementsAreArray(allocated)); >+ EXPECT_FALSE(IsOnStack(alloced_copy)); >+} >+ >+TEST(FixedArrayTest, MoveCtor) { >+ absl::FixedArray<std::unique_ptr<int>, 10> on_stack(5); >+ for (int i = 0; i < 5; ++i) { >+ on_stack[i] = absl::make_unique<int>(i); >+ } >+ >+ absl::FixedArray<std::unique_ptr<int>, 10> stack_copy = std::move(on_stack); >+ for (int i = 0; i < 5; ++i) EXPECT_EQ(*(stack_copy[i]), i); >+ EXPECT_EQ(stack_copy.size(), on_stack.size()); >+ >+ absl::FixedArray<std::unique_ptr<int>, 10> allocated(15); >+ for (int i = 0; i < 15; ++i) { >+ allocated[i] = absl::make_unique<int>(i); >+ } >+ >+ absl::FixedArray<std::unique_ptr<int>, 10> alloced_copy = >+ std::move(allocated); >+ for (int i = 0; i < 15; ++i) EXPECT_EQ(*(alloced_copy[i]), i); >+ EXPECT_EQ(allocated.size(), alloced_copy.size()); >+} >+ >+TEST(FixedArrayTest, SmallObjects) { >+ // Small object arrays >+ { >+ // Short arrays should be on the stack >+ absl::FixedArray<int> array(4); >+ EXPECT_TRUE(IsOnStack(array)); >+ } >+ >+ { >+ // Large arrays should be on the heap >+ absl::FixedArray<int> array(1048576); >+ EXPECT_FALSE(IsOnStack(array)); >+ } >+ >+ { >+ // Arrays of <= default size should be on the stack >+ absl::FixedArray<int, 100> array(100); >+ EXPECT_TRUE(IsOnStack(array)); >+ } >+ >+ { >+ // Arrays of > default size should be on the stack >+ absl::FixedArray<int, 100> array(101); >+ EXPECT_FALSE(IsOnStack(array)); >+ } >+ >+ { >+ // Arrays with different size elements should use approximately >+ // same amount of stack space >+ absl::FixedArray<int> array1(0); >+ absl::FixedArray<char> array2(0); >+ EXPECT_LE(sizeof(array1), sizeof(array2)+100); >+ EXPECT_LE(sizeof(array2), sizeof(array1)+100); >+ } >+ >+ { >+ // Ensure that vectors are properly constructed inside a fixed array. >+ absl::FixedArray<std::vector<int> > array(2); >+ EXPECT_EQ(0, array[0].size()); >+ EXPECT_EQ(0, array[1].size()); >+ } >+ >+ { >+ // Regardless of absl::FixedArray implementation, check that a type with a >+ // low alignment requirement and a non power-of-two size is initialized >+ // correctly. >+ ThreeInts::counter = 1; >+ absl::FixedArray<ThreeInts> array(2); >+ EXPECT_EQ(1, array[0].x_); >+ EXPECT_EQ(1, array[0].y_); >+ EXPECT_EQ(1, array[0].z_); >+ EXPECT_EQ(2, array[1].x_); >+ EXPECT_EQ(2, array[1].y_); >+ EXPECT_EQ(2, array[1].z_); >+ } >+} >+ >+TEST(FixedArrayTest, AtThrows) { >+ absl::FixedArray<int> a = {1, 2, 3}; >+ EXPECT_EQ(a.at(2), 3); >+ ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range, >+ "failed bounds check"); >+} >+ >+TEST(FixedArrayRelationalsTest, EqualArrays) { >+ for (int i = 0; i < 10; ++i) { >+ absl::FixedArray<int, 5> a1(i); >+ std::iota(a1.begin(), a1.end(), 0); >+ absl::FixedArray<int, 5> a2(a1.begin(), a1.end()); >+ >+ EXPECT_TRUE(a1 == a2); >+ EXPECT_FALSE(a1 != a2); >+ EXPECT_TRUE(a2 == a1); >+ EXPECT_FALSE(a2 != a1); >+ EXPECT_FALSE(a1 < a2); >+ EXPECT_FALSE(a1 > a2); >+ EXPECT_FALSE(a2 < a1); >+ EXPECT_FALSE(a2 > a1); >+ EXPECT_TRUE(a1 <= a2); >+ EXPECT_TRUE(a1 >= a2); >+ EXPECT_TRUE(a2 <= a1); >+ EXPECT_TRUE(a2 >= a1); >+ } >+} >+ >+TEST(FixedArrayRelationalsTest, UnequalArrays) { >+ for (int i = 1; i < 10; ++i) { >+ absl::FixedArray<int, 5> a1(i); >+ std::iota(a1.begin(), a1.end(), 0); >+ absl::FixedArray<int, 5> a2(a1.begin(), a1.end()); >+ --a2[i / 2]; >+ >+ EXPECT_FALSE(a1 == a2); >+ EXPECT_TRUE(a1 != a2); >+ EXPECT_FALSE(a2 == a1); >+ EXPECT_TRUE(a2 != a1); >+ EXPECT_FALSE(a1 < a2); >+ EXPECT_TRUE(a1 > a2); >+ EXPECT_TRUE(a2 < a1); >+ EXPECT_FALSE(a2 > a1); >+ EXPECT_FALSE(a1 <= a2); >+ EXPECT_TRUE(a1 >= a2); >+ EXPECT_TRUE(a2 <= a1); >+ EXPECT_FALSE(a2 >= a1); >+ } >+} >+ >+template <int stack_elements> >+static void TestArray(int n) { >+ SCOPED_TRACE(n); >+ SCOPED_TRACE(stack_elements); >+ ConstructionTester::constructions = 0; >+ ConstructionTester::destructions = 0; >+ { >+ absl::FixedArray<ConstructionTester, stack_elements> array(n); >+ >+ EXPECT_THAT(array.size(), n); >+ EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n); >+ EXPECT_THAT(array.begin() + n, array.end()); >+ >+ // Check that all elements were constructed >+ for (int i = 0; i < n; i++) { >+ array[i].CheckConstructed(); >+ } >+ // Check that no other elements were constructed >+ EXPECT_THAT(ConstructionTester::constructions, n); >+ >+ // Test operator[] >+ for (int i = 0; i < n; i++) { >+ array[i].set(i); >+ } >+ for (int i = 0; i < n; i++) { >+ EXPECT_THAT(array[i].get(), i); >+ EXPECT_THAT(array.data()[i].get(), i); >+ } >+ >+ // Test data() >+ for (int i = 0; i < n; i++) { >+ array.data()[i].set(i + 1); >+ } >+ for (int i = 0; i < n; i++) { >+ EXPECT_THAT(array[i].get(), i+1); >+ EXPECT_THAT(array.data()[i].get(), i+1); >+ } >+ } // Close scope containing 'array'. >+ >+ // Check that all constructed elements were destructed. >+ EXPECT_EQ(ConstructionTester::constructions, >+ ConstructionTester::destructions); >+} >+ >+template <int elements_per_inner_array, int inline_elements> >+static void TestArrayOfArrays(int n) { >+ SCOPED_TRACE(n); >+ SCOPED_TRACE(inline_elements); >+ SCOPED_TRACE(elements_per_inner_array); >+ ConstructionTester::constructions = 0; >+ ConstructionTester::destructions = 0; >+ { >+ using InnerArray = ConstructionTester[elements_per_inner_array]; >+ // Heap-allocate the FixedArray to avoid blowing the stack frame. >+ auto array_ptr = >+ absl::make_unique<absl::FixedArray<InnerArray, inline_elements>>(n); >+ auto& array = *array_ptr; >+ >+ ASSERT_EQ(array.size(), n); >+ ASSERT_EQ(array.memsize(), >+ sizeof(ConstructionTester) * elements_per_inner_array * n); >+ ASSERT_EQ(array.begin() + n, array.end()); >+ >+ // Check that all elements were constructed >+ for (int i = 0; i < n; i++) { >+ for (int j = 0; j < elements_per_inner_array; j++) { >+ (array[i])[j].CheckConstructed(); >+ } >+ } >+ // Check that no other elements were constructed >+ ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array); >+ >+ // Test operator[] >+ for (int i = 0; i < n; i++) { >+ for (int j = 0; j < elements_per_inner_array; j++) { >+ (array[i])[j].set(i * elements_per_inner_array + j); >+ } >+ } >+ for (int i = 0; i < n; i++) { >+ for (int j = 0; j < elements_per_inner_array; j++) { >+ ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j); >+ ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j); >+ } >+ } >+ >+ // Test data() >+ for (int i = 0; i < n; i++) { >+ for (int j = 0; j < elements_per_inner_array; j++) { >+ (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j); >+ } >+ } >+ for (int i = 0; i < n; i++) { >+ for (int j = 0; j < elements_per_inner_array; j++) { >+ ASSERT_EQ((array[i])[j].get(), >+ (i + 1) * elements_per_inner_array + j); >+ ASSERT_EQ((array.data()[i])[j].get(), >+ (i + 1) * elements_per_inner_array + j); >+ } >+ } >+ } // Close scope containing 'array'. >+ >+ // Check that all constructed elements were destructed. >+ EXPECT_EQ(ConstructionTester::constructions, >+ ConstructionTester::destructions); >+} >+ >+TEST(IteratorConstructorTest, NonInline) { >+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; >+ absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed( >+ kInput, kInput + ABSL_ARRAYSIZE(kInput)); >+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { >+ ASSERT_EQ(kInput[i], fixed[i]); >+ } >+} >+ >+TEST(IteratorConstructorTest, Inline) { >+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; >+ absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed( >+ kInput, kInput + ABSL_ARRAYSIZE(kInput)); >+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { >+ ASSERT_EQ(kInput[i], fixed[i]); >+ } >+} >+ >+TEST(IteratorConstructorTest, NonPod) { >+ char const* kInput[] = >+ { "red", "orange", "yellow", "green", "blue", "indigo", "violet" }; >+ absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput)); >+ ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size()); >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) { >+ ASSERT_EQ(kInput[i], fixed[i]); >+ } >+} >+ >+TEST(IteratorConstructorTest, FromEmptyVector) { >+ std::vector<int> const empty; >+ absl::FixedArray<int> const fixed(empty.begin(), empty.end()); >+ EXPECT_EQ(0, fixed.size()); >+ EXPECT_EQ(empty.size(), fixed.size()); >+} >+ >+TEST(IteratorConstructorTest, FromNonEmptyVector) { >+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; >+ std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput)); >+ absl::FixedArray<int> const fixed(items.begin(), items.end()); >+ ASSERT_EQ(items.size(), fixed.size()); >+ for (size_t i = 0; i < items.size(); ++i) { >+ ASSERT_EQ(items[i], fixed[i]); >+ } >+} >+ >+TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) { >+ int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; >+ std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput)); >+ absl::FixedArray<int> const fixed(items.begin(), items.end()); >+ EXPECT_THAT(fixed, testing::ElementsAreArray(kInput)); >+} >+ >+TEST(InitListConstructorTest, InitListConstruction) { >+ absl::FixedArray<int> fixed = {1, 2, 3}; >+ EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3})); >+} >+ >+TEST(FillConstructorTest, NonEmptyArrays) { >+ absl::FixedArray<int> stack_array(4, 1); >+ EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1})); >+ >+ absl::FixedArray<int, 0> heap_array(4, 1); >+ EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1})); >+} >+ >+TEST(FillConstructorTest, EmptyArray) { >+ absl::FixedArray<int> empty_fill(0, 1); >+ absl::FixedArray<int> empty_size(0); >+ EXPECT_EQ(empty_fill, empty_size); >+} >+ >+TEST(FillConstructorTest, NotTriviallyCopyable) { >+ std::string str = "abcd"; >+ absl::FixedArray<std::string> strings = {str, str, str, str}; >+ >+ absl::FixedArray<std::string> array(4, str); >+ EXPECT_EQ(array, strings); >+} >+ >+TEST(FillConstructorTest, Disambiguation) { >+ absl::FixedArray<size_t> a(1, 2); >+ EXPECT_THAT(a, testing::ElementsAre(2)); >+} >+ >+TEST(FixedArrayTest, ManySizedArrays) { >+ std::vector<int> sizes; >+ for (int i = 1; i < 100; i++) sizes.push_back(i); >+ for (int i = 100; i <= 1000; i += 100) sizes.push_back(i); >+ for (int n : sizes) { >+ TestArray<0>(n); >+ TestArray<1>(n); >+ TestArray<64>(n); >+ TestArray<1000>(n); >+ } >+} >+ >+TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) { >+ for (int n = 1; n < 1000; n++) { >+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n))); >+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n))); >+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n))); >+ ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n))); >+ } >+} >+ >+TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) { >+ for (int n = 1; n < 1000; n++) { >+ TestArrayOfArrays<2, 0>(n); >+ TestArrayOfArrays<2, 1>(n); >+ TestArrayOfArrays<2, 64>(n); >+ TestArrayOfArrays<2, 1000>(n); >+ } >+} >+ >+// If value_type is put inside of a struct container, >+// we might evoke this error in a hardened build unless data() is carefully >+// written, so check on that. >+// error: call to int __builtin___sprintf_chk(etc...) >+// will always overflow destination buffer [-Werror] >+TEST(FixedArrayTest, AvoidParanoidDiagnostics) { >+ absl::FixedArray<char, 32> buf(32); >+ sprintf(buf.data(), "foo"); // NOLINT(runtime/printf) >+} >+ >+TEST(FixedArrayTest, TooBigInlinedSpace) { >+ struct TooBig { >+ char c[1 << 20]; >+ }; // too big for even one on the stack >+ >+ // Simulate the data members of absl::FixedArray, a pointer and a size_t. >+ struct Data { >+ TooBig* p; >+ size_t size; >+ }; >+ >+ // Make sure TooBig objects are not inlined for 0 or default size. >+ static_assert(sizeof(absl::FixedArray<TooBig, 0>) == sizeof(Data), >+ "0-sized absl::FixedArray should have same size as Data."); >+ static_assert(alignof(absl::FixedArray<TooBig, 0>) == alignof(Data), >+ "0-sized absl::FixedArray should have same alignment as Data."); >+ static_assert(sizeof(absl::FixedArray<TooBig>) == sizeof(Data), >+ "default-sized absl::FixedArray should have same size as Data"); >+ static_assert( >+ alignof(absl::FixedArray<TooBig>) == alignof(Data), >+ "default-sized absl::FixedArray should have same alignment as Data."); >+} >+ >+// PickyDelete EXPECTs its class-scope deallocation funcs are unused. >+struct PickyDelete { >+ PickyDelete() {} >+ ~PickyDelete() {} >+ void operator delete(void* p) { >+ EXPECT_TRUE(false) << __FUNCTION__; >+ ::operator delete(p); >+ } >+ void operator delete[](void* p) { >+ EXPECT_TRUE(false) << __FUNCTION__; >+ ::operator delete[](p); >+ } >+}; >+ >+TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); } >+ >+ >+TEST(FixedArrayTest, Data) { >+ static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 }; >+ absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput)); >+ EXPECT_EQ(fa.data(), &*fa.begin()); >+ EXPECT_EQ(fa.data(), &fa[0]); >+ >+ const absl::FixedArray<int>& cfa = fa; >+ EXPECT_EQ(cfa.data(), &*cfa.begin()); >+ EXPECT_EQ(cfa.data(), &cfa[0]); >+} >+ >+TEST(FixedArrayTest, Empty) { >+ absl::FixedArray<int> empty(0); >+ absl::FixedArray<int> inline_filled(1); >+ absl::FixedArray<int, 0> heap_filled(1); >+ EXPECT_TRUE(empty.empty()); >+ EXPECT_FALSE(inline_filled.empty()); >+ EXPECT_FALSE(heap_filled.empty()); >+} >+ >+TEST(FixedArrayTest, FrontAndBack) { >+ absl::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3}; >+ EXPECT_EQ(inlined.front(), 1); >+ EXPECT_EQ(inlined.back(), 3); >+ >+ absl::FixedArray<int, 0> allocated = {1, 2, 3}; >+ EXPECT_EQ(allocated.front(), 1); >+ EXPECT_EQ(allocated.back(), 3); >+ >+ absl::FixedArray<int> one_element = {1}; >+ EXPECT_EQ(one_element.front(), one_element.back()); >+} >+ >+TEST(FixedArrayTest, ReverseIteratorInlined) { >+ absl::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4}; >+ >+ int counter = 5; >+ for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin(); >+ iter != a.rend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = 5; >+ for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin(); >+ iter != a.rend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = 5; >+ for (auto iter = a.crbegin(); iter != a.crend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+} >+ >+TEST(FixedArrayTest, ReverseIteratorAllocated) { >+ absl::FixedArray<int, 0> a = {0, 1, 2, 3, 4}; >+ >+ int counter = 5; >+ for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin(); >+ iter != a.rend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = 5; >+ for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin(); >+ iter != a.rend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = 5; >+ for (auto iter = a.crbegin(); iter != a.crend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+} >+ >+TEST(FixedArrayTest, Fill) { >+ absl::FixedArray<int, 5 * sizeof(int)> inlined(5); >+ int fill_val = 42; >+ inlined.fill(fill_val); >+ for (int i : inlined) EXPECT_EQ(i, fill_val); >+ >+ absl::FixedArray<int, 0> allocated(5); >+ allocated.fill(fill_val); >+ for (int i : allocated) EXPECT_EQ(i, fill_val); >+ >+ // It doesn't do anything, just make sure this compiles. >+ absl::FixedArray<int> empty(0); >+ empty.fill(fill_val); >+} >+ >+// TODO(johnsoncj): Investigate InlinedStorage default initialization in GCC 4.x >+#ifndef __GNUC__ >+TEST(FixedArrayTest, DefaultCtorDoesNotValueInit) { >+ using T = char; >+ constexpr auto capacity = 10; >+ using FixedArrType = absl::FixedArray<T, capacity>; >+ using FixedArrBuffType = >+ absl::aligned_storage_t<sizeof(FixedArrType), alignof(FixedArrType)>; >+ constexpr auto scrubbed_bits = 0x95; >+ constexpr auto length = capacity / 2; >+ >+ FixedArrBuffType buff; >+ std::memset(std::addressof(buff), scrubbed_bits, sizeof(FixedArrBuffType)); >+ >+ FixedArrType* arr = >+ ::new (static_cast<void*>(std::addressof(buff))) FixedArrType(length); >+ EXPECT_THAT(*arr, testing::Each(scrubbed_bits)); >+ arr->~FixedArrType(); >+} >+#endif // __GNUC__ >+ >+// This is a stateful allocator, but the state lives outside of the >+// allocator (in whatever test is using the allocator). This is odd >+// but helps in tests where the allocator is propagated into nested >+// containers - that chain of allocators uses the same state and is >+// thus easier to query for aggregate allocation information. >+template <typename T> >+class CountingAllocator : public std::allocator<T> { >+ public: >+ using Alloc = std::allocator<T>; >+ using pointer = typename Alloc::pointer; >+ using size_type = typename Alloc::size_type; >+ >+ CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {} >+ explicit CountingAllocator(int64_t* b) >+ : bytes_used_(b), instance_count_(nullptr) {} >+ CountingAllocator(int64_t* b, int64_t* a) >+ : bytes_used_(b), instance_count_(a) {} >+ >+ template <typename U> >+ explicit CountingAllocator(const CountingAllocator<U>& x) >+ : Alloc(x), >+ bytes_used_(x.bytes_used_), >+ instance_count_(x.instance_count_) {} >+ >+ pointer allocate(size_type n, const void* const hint = nullptr) { >+ assert(bytes_used_ != nullptr); >+ *bytes_used_ += n * sizeof(T); >+ return Alloc::allocate(n, hint); >+ } >+ >+ void deallocate(pointer p, size_type n) { >+ Alloc::deallocate(p, n); >+ assert(bytes_used_ != nullptr); >+ *bytes_used_ -= n * sizeof(T); >+ } >+ >+ template <typename... Args> >+ void construct(pointer p, Args&&... args) { >+ Alloc::construct(p, absl::forward<Args>(args)...); >+ if (instance_count_) { >+ *instance_count_ += 1; >+ } >+ } >+ >+ void destroy(pointer p) { >+ Alloc::destroy(p); >+ if (instance_count_) { >+ *instance_count_ -= 1; >+ } >+ } >+ >+ template <typename U> >+ class rebind { >+ public: >+ using other = CountingAllocator<U>; >+ }; >+ >+ int64_t* bytes_used_; >+ int64_t* instance_count_; >+}; >+ >+TEST(AllocatorSupportTest, CountInlineAllocations) { >+ constexpr size_t inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; >+ >+ int64_t allocated = 0; >+ int64_t active_instances = 0; >+ >+ { >+ const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7}; >+ >+ Alloc alloc(&allocated, &active_instances); >+ >+ AllocFxdArr arr(ia, ia + inlined_size, alloc); >+ static_cast<void>(arr); >+ } >+ >+ EXPECT_EQ(allocated, 0); >+ EXPECT_EQ(active_instances, 0); >+} >+ >+TEST(AllocatorSupportTest, CountOutoflineAllocations) { >+ constexpr size_t inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; >+ >+ int64_t allocated = 0; >+ int64_t active_instances = 0; >+ >+ { >+ const int ia[] = {0, 1, 2, 3, 4, 5, 6, 7}; >+ Alloc alloc(&allocated, &active_instances); >+ >+ AllocFxdArr arr(ia, ia + ABSL_ARRAYSIZE(ia), alloc); >+ >+ EXPECT_EQ(allocated, arr.size() * sizeof(int)); >+ static_cast<void>(arr); >+ } >+ >+ EXPECT_EQ(active_instances, 0); >+} >+ >+TEST(AllocatorSupportTest, CountCopyInlineAllocations) { >+ constexpr size_t inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; >+ >+ int64_t allocated1 = 0; >+ int64_t allocated2 = 0; >+ int64_t active_instances = 0; >+ Alloc alloc(&allocated1, &active_instances); >+ Alloc alloc2(&allocated2, &active_instances); >+ >+ { >+ int initial_value = 1; >+ >+ AllocFxdArr arr1(inlined_size / 2, initial_value, alloc); >+ >+ EXPECT_EQ(allocated1, 0); >+ >+ AllocFxdArr arr2(arr1, alloc2); >+ >+ EXPECT_EQ(allocated2, 0); >+ static_cast<void>(arr1); >+ static_cast<void>(arr2); >+ } >+ >+ EXPECT_EQ(active_instances, 0); >+} >+ >+TEST(AllocatorSupportTest, CountCopyOutoflineAllocations) { >+ constexpr size_t inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; >+ >+ int64_t allocated1 = 0; >+ int64_t allocated2 = 0; >+ int64_t active_instances = 0; >+ Alloc alloc(&allocated1, &active_instances); >+ Alloc alloc2(&allocated2, &active_instances); >+ >+ { >+ int initial_value = 1; >+ >+ AllocFxdArr arr1(inlined_size * 2, initial_value, alloc); >+ >+ EXPECT_EQ(allocated1, arr1.size() * sizeof(int)); >+ >+ AllocFxdArr arr2(arr1, alloc2); >+ >+ EXPECT_EQ(allocated2, inlined_size * 2 * sizeof(int)); >+ static_cast<void>(arr1); >+ static_cast<void>(arr2); >+ } >+ >+ EXPECT_EQ(active_instances, 0); >+} >+ >+TEST(AllocatorSupportTest, SizeValAllocConstructor) { >+ using testing::AllOf; >+ using testing::Each; >+ using testing::SizeIs; >+ >+ constexpr size_t inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocFxdArr = absl::FixedArray<int, inlined_size, Alloc>; >+ >+ { >+ auto len = inlined_size / 2; >+ auto val = 0; >+ int64_t allocated = 0; >+ AllocFxdArr arr(len, val, Alloc(&allocated)); >+ >+ EXPECT_EQ(allocated, 0); >+ EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0))); >+ } >+ >+ { >+ auto len = inlined_size * 2; >+ auto val = 0; >+ int64_t allocated = 0; >+ AllocFxdArr arr(len, val, Alloc(&allocated)); >+ >+ EXPECT_EQ(allocated, len * sizeof(int)); >+ EXPECT_THAT(arr, AllOf(SizeIs(len), Each(0))); >+ } >+} >+ >+#ifdef ADDRESS_SANITIZER >+TEST(FixedArrayTest, AddressSanitizerAnnotations1) { >+ absl::FixedArray<int, 32> a(10); >+ int *raw = a.data(); >+ raw[0] = 0; >+ raw[9] = 0; >+ EXPECT_DEATH(raw[-2] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[-1] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[10] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[31] = 0, "container-overflow"); >+} >+ >+TEST(FixedArrayTest, AddressSanitizerAnnotations2) { >+ absl::FixedArray<char, 17> a(12); >+ char *raw = a.data(); >+ raw[0] = 0; >+ raw[11] = 0; >+ EXPECT_DEATH(raw[-7] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[-1] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[12] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[17] = 0, "container-overflow"); >+} >+ >+TEST(FixedArrayTest, AddressSanitizerAnnotations3) { >+ absl::FixedArray<uint64_t, 20> a(20); >+ uint64_t *raw = a.data(); >+ raw[0] = 0; >+ raw[19] = 0; >+ EXPECT_DEATH(raw[-1] = 0, "container-overflow"); >+ EXPECT_DEATH(raw[20] = 0, "container-overflow"); >+} >+ >+TEST(FixedArrayTest, AddressSanitizerAnnotations4) { >+ absl::FixedArray<ThreeInts> a(10); >+ ThreeInts *raw = a.data(); >+ raw[0] = ThreeInts(); >+ raw[9] = ThreeInts(); >+ // Note: raw[-1] is pointing to 12 bytes before the container range. However, >+ // there is only a 8-byte red zone before the container range, so we only >+ // access the last 4 bytes of the struct to make sure it stays within the red >+ // zone. >+ EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow"); >+ EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow"); >+ // The actual size of storage is kDefaultBytes=256, 21*12 = 252, >+ // so reading raw[21] should still trigger the correct warning. >+ EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow"); >+} >+#endif // ADDRESS_SANITIZER >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector.h >new file mode 100644 >index 00000000000..ca36fd3699b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector.h >@@ -0,0 +1,1386 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: inlined_vector.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains the declaration and definition of an "inlined >+// vector" which behaves in an equivalent fashion to a `std::vector`, except >+// that storage for small sequences of the vector are provided inline without >+// requiring any heap allocation. >+ >+// An `absl::InlinedVector<T,N>` specifies the size N at which to inline as one >+// of its template parameters. Vectors of length <= N are provided inline. >+// Typically N is very small (e.g., 4) so that sequences that are expected to be >+// short do not require allocations. >+ >+// An `absl::InlinedVector` does not usually require a specific allocator; if >+// the inlined vector grows beyond its initial constraints, it will need to >+// allocate (as any normal `std::vector` would) and it will generally use the >+// default allocator in that case; optionally, a custom allocator may be >+// specified using an `absl::InlinedVector<T,N,A>` construction. >+ >+#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_ >+#define ABSL_CONTAINER_INLINED_VECTOR_H_ >+ >+#include <algorithm> >+#include <cassert> >+#include <cstddef> >+#include <cstdlib> >+#include <cstring> >+#include <initializer_list> >+#include <iterator> >+#include <memory> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/algorithm/algorithm.h" >+#include "absl/base/internal/throw_delegate.h" >+#include "absl/base/optimization.h" >+#include "absl/base/port.h" >+#include "absl/memory/memory.h" >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// InlinedVector >+// ----------------------------------------------------------------------------- >+// >+// An `absl::InlinedVector` is designed to be a drop-in replacement for >+// `std::vector` for use cases where the vector's size is sufficiently small >+// that it can be inlined. If the inlined vector does grow beyond its estimated >+// size, it will trigger an initial allocation on the heap, and will behave as a >+// `std:vector`. The API of the `absl::InlinedVector` within this file is >+// designed to cover the same API footprint as covered by `std::vector`. >+template <typename T, size_t N, typename A = std::allocator<T> > >+class InlinedVector { >+ using AllocatorTraits = std::allocator_traits<A>; >+ >+ public: >+ using allocator_type = A; >+ using value_type = typename allocator_type::value_type; >+ using pointer = typename allocator_type::pointer; >+ using const_pointer = typename allocator_type::const_pointer; >+ using reference = typename allocator_type::reference; >+ using const_reference = typename allocator_type::const_reference; >+ using size_type = typename allocator_type::size_type; >+ using difference_type = typename allocator_type::difference_type; >+ using iterator = pointer; >+ using const_iterator = const_pointer; >+ using reverse_iterator = std::reverse_iterator<iterator>; >+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; >+ >+ InlinedVector() noexcept(noexcept(allocator_type())) >+ : allocator_and_tag_(allocator_type()) {} >+ >+ explicit InlinedVector(const allocator_type& alloc) noexcept >+ : allocator_and_tag_(alloc) {} >+ >+ // Create a vector with n copies of value_type(). >+ explicit InlinedVector(size_type n, >+ const allocator_type& alloc = allocator_type()) >+ : allocator_and_tag_(alloc) { >+ InitAssign(n); >+ } >+ >+ // Create a vector with n copies of elem >+ InlinedVector(size_type n, const value_type& elem, >+ const allocator_type& alloc = allocator_type()) >+ : allocator_and_tag_(alloc) { >+ InitAssign(n, elem); >+ } >+ >+ // Create and initialize with the elements [first .. last). >+ // The unused enable_if argument restricts this constructor so that it is >+ // elided when value_type is an integral type. This prevents ambiguous >+ // interpretation between a call to this constructor with two integral >+ // arguments and a call to the preceding (n, elem) constructor. >+ template <typename InputIterator> >+ InlinedVector( >+ InputIterator first, InputIterator last, >+ const allocator_type& alloc = allocator_type(), >+ typename std::enable_if<!std::is_integral<InputIterator>::value>::type* = >+ nullptr) >+ : allocator_and_tag_(alloc) { >+ AppendRange(first, last); >+ } >+ >+ InlinedVector(std::initializer_list<value_type> init, >+ const allocator_type& alloc = allocator_type()) >+ : allocator_and_tag_(alloc) { >+ AppendRange(init.begin(), init.end()); >+ } >+ >+ InlinedVector(const InlinedVector& v); >+ InlinedVector(const InlinedVector& v, const allocator_type& alloc); >+ >+ // This move constructor does not allocate and only moves the underlying >+ // objects, so its `noexcept` specification depends on whether moving the >+ // underlying objects can throw or not. We assume >+ // a) move constructors should only throw due to allocation failure and >+ // b) if `value_type`'s move constructor allocates, it uses the same >+ // allocation function as the `InlinedVector`'s allocator, so the move >+ // constructor is non-throwing if the allocator is non-throwing or >+ // `value_type`'s move constructor is specified as `noexcept`. >+ InlinedVector(InlinedVector&& v) noexcept( >+ absl::allocator_is_nothrow<allocator_type>::value || >+ std::is_nothrow_move_constructible<value_type>::value); >+ >+ // This move constructor allocates and also moves the underlying objects, so >+ // its `noexcept` specification depends on whether the allocation can throw >+ // and whether moving the underlying objects can throw. Based on the same >+ // assumptions above, the `noexcept` specification is dominated by whether the >+ // allocation can throw regardless of whether `value_type`'s move constructor >+ // is specified as `noexcept`. >+ InlinedVector(InlinedVector&& v, const allocator_type& alloc) noexcept( >+ absl::allocator_is_nothrow<allocator_type>::value); >+ >+ ~InlinedVector() { clear(); } >+ >+ InlinedVector& operator=(const InlinedVector& v) { >+ if (this == &v) { >+ return *this; >+ } >+ // Optimized to avoid reallocation. >+ // Prefer reassignment to copy construction for elements. >+ if (size() < v.size()) { // grow >+ reserve(v.size()); >+ std::copy(v.begin(), v.begin() + size(), begin()); >+ std::copy(v.begin() + size(), v.end(), std::back_inserter(*this)); >+ } else { // maybe shrink >+ erase(begin() + v.size(), end()); >+ std::copy(v.begin(), v.end(), begin()); >+ } >+ return *this; >+ } >+ >+ InlinedVector& operator=(InlinedVector&& v) { >+ if (this == &v) { >+ return *this; >+ } >+ if (v.allocated()) { >+ clear(); >+ tag().set_allocated_size(v.size()); >+ init_allocation(v.allocation()); >+ v.tag() = Tag(); >+ } else { >+ if (allocated()) clear(); >+ // Both are inlined now. >+ if (size() < v.size()) { >+ auto mid = std::make_move_iterator(v.begin() + size()); >+ std::copy(std::make_move_iterator(v.begin()), mid, begin()); >+ UninitializedCopy(mid, std::make_move_iterator(v.end()), end()); >+ } else { >+ auto new_end = std::copy(std::make_move_iterator(v.begin()), >+ std::make_move_iterator(v.end()), begin()); >+ Destroy(new_end, end()); >+ } >+ tag().set_inline_size(v.size()); >+ } >+ return *this; >+ } >+ >+ InlinedVector& operator=(std::initializer_list<value_type> init) { >+ AssignRange(init.begin(), init.end()); >+ return *this; >+ } >+ >+ // InlinedVector::assign() >+ // >+ // Replaces the contents of the inlined vector with copies of those in the >+ // iterator range [first, last). >+ template <typename InputIterator> >+ void assign( >+ InputIterator first, InputIterator last, >+ typename std::enable_if<!std::is_integral<InputIterator>::value>::type* = >+ nullptr) { >+ AssignRange(first, last); >+ } >+ >+ // Overload of `InlinedVector::assign()` to take values from elements of an >+ // initializer list >+ void assign(std::initializer_list<value_type> init) { >+ AssignRange(init.begin(), init.end()); >+ } >+ >+ // Overload of `InlinedVector::assign()` to replace the first `n` elements of >+ // the inlined vector with `elem` values. >+ void assign(size_type n, const value_type& elem) { >+ if (n <= size()) { // Possibly shrink >+ std::fill_n(begin(), n, elem); >+ erase(begin() + n, end()); >+ return; >+ } >+ // Grow >+ reserve(n); >+ std::fill_n(begin(), size(), elem); >+ if (allocated()) { >+ UninitializedFill(allocated_space() + size(), allocated_space() + n, >+ elem); >+ tag().set_allocated_size(n); >+ } else { >+ UninitializedFill(inlined_space() + size(), inlined_space() + n, elem); >+ tag().set_inline_size(n); >+ } >+ } >+ >+ // InlinedVector::size() >+ // >+ // Returns the number of elements in the inlined vector. >+ size_type size() const noexcept { return tag().size(); } >+ >+ // InlinedVector::empty() >+ // >+ // Checks if the inlined vector has no elements. >+ bool empty() const noexcept { return (size() == 0); } >+ >+ // InlinedVector::capacity() >+ // >+ // Returns the number of elements that can be stored in an inlined vector >+ // without requiring a reallocation of underlying memory. Note that for >+ // most inlined vectors, `capacity()` should equal its initial size `N`; for >+ // inlined vectors which exceed this capacity, they will no longer be inlined, >+ // and `capacity()` will equal its capacity on the allocated heap. >+ size_type capacity() const noexcept { >+ return allocated() ? allocation().capacity() : N; >+ } >+ >+ // InlinedVector::max_size() >+ // >+ // Returns the maximum number of elements the vector can hold. >+ size_type max_size() const noexcept { >+ // One bit of the size storage is used to indicate whether the inlined >+ // vector is allocated; as a result, the maximum size of the container that >+ // we can express is half of the max for our size type. >+ return std::numeric_limits<size_type>::max() / 2; >+ } >+ >+ // InlinedVector::data() >+ // >+ // Returns a const T* pointer to elements of the inlined vector. This pointer >+ // can be used to access (but not modify) the contained elements. >+ // Only results within the range `[0,size())` are defined. >+ const_pointer data() const noexcept { >+ return allocated() ? allocated_space() : inlined_space(); >+ } >+ >+ // Overload of InlinedVector::data() to return a T* pointer to elements of the >+ // inlined vector. This pointer can be used to access and modify the contained >+ // elements. >+ pointer data() noexcept { >+ return allocated() ? allocated_space() : inlined_space(); >+ } >+ >+ // InlinedVector::clear() >+ // >+ // Removes all elements from the inlined vector. >+ void clear() noexcept { >+ size_type s = size(); >+ if (allocated()) { >+ Destroy(allocated_space(), allocated_space() + s); >+ allocation().Dealloc(allocator()); >+ } else if (s != 0) { // do nothing for empty vectors >+ Destroy(inlined_space(), inlined_space() + s); >+ } >+ tag() = Tag(); >+ } >+ >+ // InlinedVector::at() >+ // >+ // Returns the ith element of an inlined vector. >+ const value_type& at(size_type i) const { >+ if (ABSL_PREDICT_FALSE(i >= size())) { >+ base_internal::ThrowStdOutOfRange( >+ "InlinedVector::at failed bounds check"); >+ } >+ return data()[i]; >+ } >+ >+ // InlinedVector::operator[] >+ // >+ // Returns the ith element of an inlined vector using the array operator. >+ const value_type& operator[](size_type i) const { >+ assert(i < size()); >+ return data()[i]; >+ } >+ >+ // Overload of InlinedVector::at() to return the ith element of an inlined >+ // vector. >+ value_type& at(size_type i) { >+ if (i >= size()) { >+ base_internal::ThrowStdOutOfRange( >+ "InlinedVector::at failed bounds check"); >+ } >+ return data()[i]; >+ } >+ >+ // Overload of InlinedVector::operator[] to return the ith element of an >+ // inlined vector. >+ value_type& operator[](size_type i) { >+ assert(i < size()); >+ return data()[i]; >+ } >+ >+ // InlinedVector::back() >+ // >+ // Returns a reference to the last element of an inlined vector. >+ value_type& back() { >+ assert(!empty()); >+ return at(size() - 1); >+ } >+ >+ // Overload of InlinedVector::back() returns a reference to the last element >+ // of an inlined vector of const values. >+ const value_type& back() const { >+ assert(!empty()); >+ return at(size() - 1); >+ } >+ >+ // InlinedVector::front() >+ // >+ // Returns a reference to the first element of an inlined vector. >+ value_type& front() { >+ assert(!empty()); >+ return at(0); >+ } >+ >+ // Overload of InlinedVector::front() returns a reference to the first element >+ // of an inlined vector of const values. >+ const value_type& front() const { >+ assert(!empty()); >+ return at(0); >+ } >+ >+ // InlinedVector::emplace_back() >+ // >+ // Constructs and appends an object to the inlined vector. >+ // >+ // Returns a reference to the inserted element. >+ template <typename... Args> >+ value_type& emplace_back(Args&&... args) { >+ size_type s = size(); >+ assert(s <= capacity()); >+ if (ABSL_PREDICT_FALSE(s == capacity())) { >+ return GrowAndEmplaceBack(std::forward<Args>(args)...); >+ } >+ assert(s < capacity()); >+ >+ value_type* space; >+ if (allocated()) { >+ tag().set_allocated_size(s + 1); >+ space = allocated_space(); >+ } else { >+ tag().set_inline_size(s + 1); >+ space = inlined_space(); >+ } >+ return Construct(space + s, std::forward<Args>(args)...); >+ } >+ >+ // InlinedVector::push_back() >+ // >+ // Appends a const element to the inlined vector. >+ void push_back(const value_type& t) { emplace_back(t); } >+ >+ // Overload of InlinedVector::push_back() to append a move-only element to the >+ // inlined vector. >+ void push_back(value_type&& t) { emplace_back(std::move(t)); } >+ >+ // InlinedVector::pop_back() >+ // >+ // Removes the last element (which is destroyed) in the inlined vector. >+ void pop_back() { >+ assert(!empty()); >+ size_type s = size(); >+ if (allocated()) { >+ Destroy(allocated_space() + s - 1, allocated_space() + s); >+ tag().set_allocated_size(s - 1); >+ } else { >+ Destroy(inlined_space() + s - 1, inlined_space() + s); >+ tag().set_inline_size(s - 1); >+ } >+ } >+ >+ // InlinedVector::resize() >+ // >+ // Resizes the inlined vector to contain `n` elements. If `n` is smaller than >+ // the inlined vector's current size, extra elements are destroyed. If `n` is >+ // larger than the initial size, new elements are value-initialized. >+ void resize(size_type n); >+ >+ // Overload of InlinedVector::resize() to resize the inlined vector to contain >+ // `n` elements. If `n` is larger than the current size, enough copies of >+ // `elem` are appended to increase its size to `n`. >+ void resize(size_type n, const value_type& elem); >+ >+ // InlinedVector::begin() >+ // >+ // Returns an iterator to the beginning of the inlined vector. >+ iterator begin() noexcept { return data(); } >+ >+ // Overload of InlinedVector::begin() for returning a const iterator to the >+ // beginning of the inlined vector. >+ const_iterator begin() const noexcept { return data(); } >+ >+ // InlinedVector::cbegin() >+ // >+ // Returns a const iterator to the beginning of the inlined vector. >+ const_iterator cbegin() const noexcept { return begin(); } >+ >+ // InlinedVector::end() >+ // >+ // Returns an iterator to the end of the inlined vector. >+ iterator end() noexcept { return data() + size(); } >+ >+ // Overload of InlinedVector::end() for returning a const iterator to the end >+ // of the inlined vector. >+ const_iterator end() const noexcept { return data() + size(); } >+ >+ // InlinedVector::cend() >+ // >+ // Returns a const iterator to the end of the inlined vector. >+ const_iterator cend() const noexcept { return end(); } >+ >+ // InlinedVector::rbegin() >+ // >+ // Returns a reverse iterator from the end of the inlined vector. >+ reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } >+ >+ // Overload of InlinedVector::rbegin() for returning a const reverse iterator >+ // from the end of the inlined vector. >+ const_reverse_iterator rbegin() const noexcept { >+ return const_reverse_iterator(end()); >+ } >+ >+ // InlinedVector::crbegin() >+ // >+ // Returns a const reverse iterator from the end of the inlined vector. >+ const_reverse_iterator crbegin() const noexcept { return rbegin(); } >+ >+ // InlinedVector::rend() >+ // >+ // Returns a reverse iterator from the beginning of the inlined vector. >+ reverse_iterator rend() noexcept { return reverse_iterator(begin()); } >+ >+ // Overload of InlinedVector::rend() for returning a const reverse iterator >+ // from the beginning of the inlined vector. >+ const_reverse_iterator rend() const noexcept { >+ return const_reverse_iterator(begin()); >+ } >+ >+ // InlinedVector::crend() >+ // >+ // Returns a reverse iterator from the beginning of the inlined vector. >+ const_reverse_iterator crend() const noexcept { return rend(); } >+ >+ // InlinedVector::emplace() >+ // >+ // Constructs and inserts an object to the inlined vector at the given >+ // `position`, returning an iterator pointing to the newly emplaced element. >+ template <typename... Args> >+ iterator emplace(const_iterator position, Args&&... args); >+ >+ // InlinedVector::insert() >+ // >+ // Inserts an element of the specified value at `position`, returning an >+ // iterator pointing to the newly inserted element. >+ iterator insert(const_iterator position, const value_type& v) { >+ return emplace(position, v); >+ } >+ >+ // Overload of InlinedVector::insert() for inserting an element of the >+ // specified rvalue, returning an iterator pointing to the newly inserted >+ // element. >+ iterator insert(const_iterator position, value_type&& v) { >+ return emplace(position, std::move(v)); >+ } >+ >+ // Overload of InlinedVector::insert() for inserting `n` elements of the >+ // specified value at `position`, returning an iterator pointing to the first >+ // of the newly inserted elements. >+ iterator insert(const_iterator position, size_type n, const value_type& v) { >+ return InsertWithCount(position, n, v); >+ } >+ >+ // Overload of `InlinedVector::insert()` to disambiguate the two >+ // three-argument overloads of `insert()`, returning an iterator pointing to >+ // the first of the newly inserted elements. >+ template <typename InputIterator, >+ typename = typename std::enable_if<std::is_convertible< >+ typename std::iterator_traits<InputIterator>::iterator_category, >+ std::input_iterator_tag>::value>::type> >+ iterator insert(const_iterator position, InputIterator first, >+ InputIterator last) { >+ using IterType = >+ typename std::iterator_traits<InputIterator>::iterator_category; >+ return InsertWithRange(position, first, last, IterType()); >+ } >+ >+ // Overload of InlinedVector::insert() for inserting a list of elements at >+ // `position`, returning an iterator pointing to the first of the newly >+ // inserted elements. >+ iterator insert(const_iterator position, >+ std::initializer_list<value_type> init) { >+ return insert(position, init.begin(), init.end()); >+ } >+ >+ // InlinedVector::erase() >+ // >+ // Erases the element at `position` of the inlined vector, returning an >+ // iterator pointing to the following element or the container's end if the >+ // last element was erased. >+ iterator erase(const_iterator position) { >+ assert(position >= begin()); >+ assert(position < end()); >+ >+ iterator pos = const_cast<iterator>(position); >+ std::move(pos + 1, end(), pos); >+ pop_back(); >+ return pos; >+ } >+ >+ // Overload of InlinedVector::erase() for erasing all elements in the >+ // iterator range [first, last) in the inlined vector, returning an iterator >+ // pointing to the first element following the range erased, or the >+ // container's end if range included the container's last element. >+ iterator erase(const_iterator first, const_iterator last); >+ >+ // InlinedVector::reserve() >+ // >+ // Enlarges the underlying representation of the inlined vector so it can hold >+ // at least `n` elements. This method does not change `size()` or the actual >+ // contents of the vector. >+ // >+ // Note that if `n` does not exceed the inlined vector's initial size `N`, >+ // `reserve()` will have no effect; if it does exceed its initial size, >+ // `reserve()` will trigger an initial allocation and move the inlined vector >+ // onto the heap. If the vector already exists on the heap and the requested >+ // size exceeds it, a reallocation will be performed. >+ void reserve(size_type n) { >+ if (n > capacity()) { >+ // Make room for new elements >+ EnlargeBy(n - size()); >+ } >+ } >+ >+ // InlinedVector::shrink_to_fit() >+ // >+ // Reduces memory usage by freeing unused memory. >+ // After this call `capacity()` will be equal to `max(N, size())`. >+ // >+ // If `size() <= N` and the elements are currently stored on the heap, they >+ // will be moved to the inlined storage and the heap memory deallocated. >+ // If `size() > N` and `size() < capacity()` the elements will be moved to >+ // a reallocated storage on heap. >+ void shrink_to_fit() { >+ const auto s = size(); >+ if (!allocated() || s == capacity()) { >+ // There's nothing to deallocate. >+ return; >+ } >+ >+ if (s <= N) { >+ // Move the elements to the inlined storage. >+ // We have to do this using a temporary, because inlined_storage and >+ // allocation_storage are in a union field. >+ auto temp = std::move(*this); >+ assign(std::make_move_iterator(temp.begin()), >+ std::make_move_iterator(temp.end())); >+ return; >+ } >+ >+ // Reallocate storage and move elements. >+ // We can't simply use the same approach as above, because assign() would >+ // call into reserve() internally and reserve larger capacity than we need. >+ Allocation new_allocation(allocator(), s); >+ UninitializedCopy(std::make_move_iterator(allocated_space()), >+ std::make_move_iterator(allocated_space() + s), >+ new_allocation.buffer()); >+ ResetAllocation(new_allocation, s); >+ } >+ >+ // InlinedVector::swap() >+ // >+ // Swaps the contents of this inlined vector with the contents of `other`. >+ void swap(InlinedVector& other); >+ >+ // InlinedVector::get_allocator() >+ // >+ // Returns the allocator of this inlined vector. >+ allocator_type get_allocator() const { return allocator(); } >+ >+ private: >+ static_assert(N > 0, "inlined vector with nonpositive size"); >+ >+ // It holds whether the vector is allocated or not in the lowest bit. >+ // The size is held in the high bits: >+ // size_ = (size << 1) | is_allocated; >+ // >+ // Maintainer's Note: size_type is user defined. The contract is limited to >+ // arithmetic operators to avoid depending on compliant overloaded bitwise >+ // operators. >+ class Tag { >+ public: >+ Tag() : size_(0) {} >+ size_type size() const { return size_ / 2; } >+ void add_size(size_type n) { size_ += n * 2; } >+ void set_inline_size(size_type n) { size_ = n * 2; } >+ void set_allocated_size(size_type n) { size_ = (n * 2) + 1; } >+ bool allocated() const { return size_ % 2; } >+ >+ private: >+ size_type size_; >+ }; >+ >+ // Derives from allocator_type to use the empty base class optimization. >+ // If the allocator_type is stateless, we can 'store' >+ // our instance of it for free. >+ class AllocatorAndTag : private allocator_type { >+ public: >+ explicit AllocatorAndTag(const allocator_type& a, Tag t = Tag()) >+ : allocator_type(a), tag_(t) {} >+ Tag& tag() { return tag_; } >+ const Tag& tag() const { return tag_; } >+ allocator_type& allocator() { return *this; } >+ const allocator_type& allocator() const { return *this; } >+ >+ private: >+ Tag tag_; >+ }; >+ >+ class Allocation { >+ public: >+ Allocation(allocator_type& a, // NOLINT(runtime/references) >+ size_type capacity) >+ : capacity_(capacity), >+ buffer_(AllocatorTraits::allocate(a, capacity_)) {} >+ >+ void Dealloc(allocator_type& a) { // NOLINT(runtime/references) >+ AllocatorTraits::deallocate(a, buffer(), capacity()); >+ } >+ >+ size_type capacity() const { return capacity_; } >+ const value_type* buffer() const { return buffer_; } >+ value_type* buffer() { return buffer_; } >+ >+ private: >+ size_type capacity_; >+ value_type* buffer_; >+ }; >+ >+ const Tag& tag() const { return allocator_and_tag_.tag(); } >+ Tag& tag() { return allocator_and_tag_.tag(); } >+ >+ Allocation& allocation() { >+ return reinterpret_cast<Allocation&>(rep_.allocation_storage.allocation); >+ } >+ const Allocation& allocation() const { >+ return reinterpret_cast<const Allocation&>( >+ rep_.allocation_storage.allocation); >+ } >+ void init_allocation(const Allocation& allocation) { >+ new (&rep_.allocation_storage.allocation) Allocation(allocation); >+ } >+ >+ // TODO(absl-team): investigate whether the reinterpret_cast is appropriate. >+ value_type* inlined_space() { >+ return reinterpret_cast<value_type*>( >+ std::addressof(rep_.inlined_storage.inlined[0])); >+ } >+ const value_type* inlined_space() const { >+ return reinterpret_cast<const value_type*>( >+ std::addressof(rep_.inlined_storage.inlined[0])); >+ } >+ >+ value_type* allocated_space() { return allocation().buffer(); } >+ const value_type* allocated_space() const { return allocation().buffer(); } >+ >+ const allocator_type& allocator() const { >+ return allocator_and_tag_.allocator(); >+ } >+ allocator_type& allocator() { return allocator_and_tag_.allocator(); } >+ >+ bool allocated() const { return tag().allocated(); } >+ >+ // Enlarge the underlying representation so we can store size_ + delta elems. >+ // The size is not changed, and any newly added memory is not initialized. >+ void EnlargeBy(size_type delta); >+ >+ // Shift all elements from position to end() n places to the right. >+ // If the vector needs to be enlarged, memory will be allocated. >+ // Returns iterators pointing to the start of the previously-initialized >+ // portion and the start of the uninitialized portion of the created gap. >+ // The number of initialized spots is pair.second - pair.first; >+ // the number of raw spots is n - (pair.second - pair.first). >+ // >+ // Updates the size of the InlinedVector internally. >+ std::pair<iterator, iterator> ShiftRight(const_iterator position, >+ size_type n); >+ >+ void ResetAllocation(Allocation new_allocation, size_type new_size) { >+ if (allocated()) { >+ Destroy(allocated_space(), allocated_space() + size()); >+ assert(begin() == allocated_space()); >+ allocation().Dealloc(allocator()); >+ allocation() = new_allocation; >+ } else { >+ Destroy(inlined_space(), inlined_space() + size()); >+ init_allocation(new_allocation); // bug: only init once >+ } >+ tag().set_allocated_size(new_size); >+ } >+ >+ template <typename... Args> >+ value_type& GrowAndEmplaceBack(Args&&... args) { >+ assert(size() == capacity()); >+ const size_type s = size(); >+ >+ Allocation new_allocation(allocator(), 2 * capacity()); >+ >+ value_type& new_element = >+ Construct(new_allocation.buffer() + s, std::forward<Args>(args)...); >+ UninitializedCopy(std::make_move_iterator(data()), >+ std::make_move_iterator(data() + s), >+ new_allocation.buffer()); >+ >+ ResetAllocation(new_allocation, s + 1); >+ >+ return new_element; >+ } >+ >+ void InitAssign(size_type n); >+ void InitAssign(size_type n, const value_type& t); >+ >+ template <typename... Args> >+ value_type& Construct(pointer p, Args&&... args) { >+ AllocatorTraits::construct(allocator(), p, std::forward<Args>(args)...); >+ return *p; >+ } >+ >+ template <typename Iter> >+ void UninitializedCopy(Iter src, Iter src_last, value_type* dst) { >+ for (; src != src_last; ++dst, ++src) Construct(dst, *src); >+ } >+ >+ template <typename... Args> >+ void UninitializedFill(value_type* dst, value_type* dst_last, >+ const Args&... args) { >+ for (; dst != dst_last; ++dst) Construct(dst, args...); >+ } >+ >+ // Destroy [ptr, ptr_last) in place. >+ void Destroy(value_type* ptr, value_type* ptr_last); >+ >+ template <typename Iter> >+ void AppendRange(Iter first, Iter last, std::input_iterator_tag) { >+ std::copy(first, last, std::back_inserter(*this)); >+ } >+ >+ // Faster path for forward iterators. >+ template <typename Iter> >+ void AppendRange(Iter first, Iter last, std::forward_iterator_tag); >+ >+ template <typename Iter> >+ void AppendRange(Iter first, Iter last) { >+ using IterTag = typename std::iterator_traits<Iter>::iterator_category; >+ AppendRange(first, last, IterTag()); >+ } >+ >+ template <typename Iter> >+ void AssignRange(Iter first, Iter last, std::input_iterator_tag); >+ >+ // Faster path for forward iterators. >+ template <typename Iter> >+ void AssignRange(Iter first, Iter last, std::forward_iterator_tag); >+ >+ template <typename Iter> >+ void AssignRange(Iter first, Iter last) { >+ using IterTag = typename std::iterator_traits<Iter>::iterator_category; >+ AssignRange(first, last, IterTag()); >+ } >+ >+ iterator InsertWithCount(const_iterator position, size_type n, >+ const value_type& v); >+ >+ template <typename InputIter> >+ iterator InsertWithRange(const_iterator position, InputIter first, >+ InputIter last, std::input_iterator_tag); >+ template <typename ForwardIter> >+ iterator InsertWithRange(const_iterator position, ForwardIter first, >+ ForwardIter last, std::forward_iterator_tag); >+ >+ AllocatorAndTag allocator_and_tag_; >+ >+ // Either the inlined or allocated representation >+ union Rep { >+ // Use struct to perform indirection that solves a bizarre compilation >+ // error on Visual Studio (all known versions). >+ struct { >+ typename std::aligned_storage<sizeof(value_type), >+ alignof(value_type)>::type inlined[N]; >+ } inlined_storage; >+ struct { >+ typename std::aligned_storage<sizeof(Allocation), >+ alignof(Allocation)>::type allocation; >+ } allocation_storage; >+ } rep_; >+}; >+ >+// ----------------------------------------------------------------------------- >+// InlinedVector Non-Member Functions >+// ----------------------------------------------------------------------------- >+ >+// swap() >+// >+// Swaps the contents of two inlined vectors. This convenience function >+// simply calls InlinedVector::swap(other_inlined_vector). >+template <typename T, size_t N, typename A> >+void swap(InlinedVector<T, N, A>& a, >+ InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) { >+ a.swap(b); >+} >+ >+// operator==() >+// >+// Tests the equivalency of the contents of two inlined vectors. >+template <typename T, size_t N, typename A> >+bool operator==(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return absl::equal(a.begin(), a.end(), b.begin(), b.end()); >+} >+ >+// operator!=() >+// >+// Tests the inequality of the contents of two inlined vectors. >+template <typename T, size_t N, typename A> >+bool operator!=(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return !(a == b); >+} >+ >+// operator<() >+// >+// Tests whether the contents of one inlined vector are less than the contents >+// of another through a lexicographical comparison operation. >+template <typename T, size_t N, typename A> >+bool operator<(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); >+} >+ >+// operator>() >+// >+// Tests whether the contents of one inlined vector are greater than the >+// contents of another through a lexicographical comparison operation. >+template <typename T, size_t N, typename A> >+bool operator>(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return b < a; >+} >+ >+// operator<=() >+// >+// Tests whether the contents of one inlined vector are less than or equal to >+// the contents of another through a lexicographical comparison operation. >+template <typename T, size_t N, typename A> >+bool operator<=(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return !(b < a); >+} >+ >+// operator>=() >+// >+// Tests whether the contents of one inlined vector are greater than or equal to >+// the contents of another through a lexicographical comparison operation. >+template <typename T, size_t N, typename A> >+bool operator>=(const InlinedVector<T, N, A>& a, >+ const InlinedVector<T, N, A>& b) { >+ return !(a < b); >+} >+ >+// ----------------------------------------------------------------------------- >+// Implementation of InlinedVector >+// ----------------------------------------------------------------------------- >+// >+// Do not depend on any implementation details below this line. >+ >+template <typename T, size_t N, typename A> >+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v) >+ : allocator_and_tag_(v.allocator()) { >+ reserve(v.size()); >+ if (allocated()) { >+ UninitializedCopy(v.begin(), v.end(), allocated_space()); >+ tag().set_allocated_size(v.size()); >+ } else { >+ UninitializedCopy(v.begin(), v.end(), inlined_space()); >+ tag().set_inline_size(v.size()); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+InlinedVector<T, N, A>::InlinedVector(const InlinedVector& v, >+ const allocator_type& alloc) >+ : allocator_and_tag_(alloc) { >+ reserve(v.size()); >+ if (allocated()) { >+ UninitializedCopy(v.begin(), v.end(), allocated_space()); >+ tag().set_allocated_size(v.size()); >+ } else { >+ UninitializedCopy(v.begin(), v.end(), inlined_space()); >+ tag().set_inline_size(v.size()); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+InlinedVector<T, N, A>::InlinedVector(InlinedVector&& v) noexcept( >+ absl::allocator_is_nothrow<allocator_type>::value || >+ std::is_nothrow_move_constructible<value_type>::value) >+ : allocator_and_tag_(v.allocator_and_tag_) { >+ if (v.allocated()) { >+ // We can just steal the underlying buffer from the source. >+ // That leaves the source empty, so we clear its size. >+ init_allocation(v.allocation()); >+ v.tag() = Tag(); >+ } else { >+ UninitializedCopy(std::make_move_iterator(v.inlined_space()), >+ std::make_move_iterator(v.inlined_space() + v.size()), >+ inlined_space()); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+InlinedVector<T, N, A>::InlinedVector( >+ InlinedVector&& v, >+ const allocator_type& >+ alloc) noexcept(absl::allocator_is_nothrow<allocator_type>::value) >+ : allocator_and_tag_(alloc) { >+ if (v.allocated()) { >+ if (alloc == v.allocator()) { >+ // We can just steal the allocation from the source. >+ tag() = v.tag(); >+ init_allocation(v.allocation()); >+ v.tag() = Tag(); >+ } else { >+ // We need to use our own allocator >+ reserve(v.size()); >+ UninitializedCopy(std::make_move_iterator(v.begin()), >+ std::make_move_iterator(v.end()), allocated_space()); >+ tag().set_allocated_size(v.size()); >+ } >+ } else { >+ UninitializedCopy(std::make_move_iterator(v.inlined_space()), >+ std::make_move_iterator(v.inlined_space() + v.size()), >+ inlined_space()); >+ tag().set_inline_size(v.size()); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::InitAssign(size_type n, const value_type& t) { >+ if (n > static_cast<size_type>(N)) { >+ Allocation new_allocation(allocator(), n); >+ init_allocation(new_allocation); >+ UninitializedFill(allocated_space(), allocated_space() + n, t); >+ tag().set_allocated_size(n); >+ } else { >+ UninitializedFill(inlined_space(), inlined_space() + n, t); >+ tag().set_inline_size(n); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::InitAssign(size_type n) { >+ if (n > static_cast<size_type>(N)) { >+ Allocation new_allocation(allocator(), n); >+ init_allocation(new_allocation); >+ UninitializedFill(allocated_space(), allocated_space() + n); >+ tag().set_allocated_size(n); >+ } else { >+ UninitializedFill(inlined_space(), inlined_space() + n); >+ tag().set_inline_size(n); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::resize(size_type n) { >+ size_type s = size(); >+ if (n < s) { >+ erase(begin() + n, end()); >+ return; >+ } >+ reserve(n); >+ assert(capacity() >= n); >+ >+ // Fill new space with elements constructed in-place. >+ if (allocated()) { >+ UninitializedFill(allocated_space() + s, allocated_space() + n); >+ tag().set_allocated_size(n); >+ } else { >+ UninitializedFill(inlined_space() + s, inlined_space() + n); >+ tag().set_inline_size(n); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::resize(size_type n, const value_type& elem) { >+ size_type s = size(); >+ if (n < s) { >+ erase(begin() + n, end()); >+ return; >+ } >+ reserve(n); >+ assert(capacity() >= n); >+ >+ // Fill new space with copies of 'elem'. >+ if (allocated()) { >+ UninitializedFill(allocated_space() + s, allocated_space() + n, elem); >+ tag().set_allocated_size(n); >+ } else { >+ UninitializedFill(inlined_space() + s, inlined_space() + n, elem); >+ tag().set_inline_size(n); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+template <typename... Args> >+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::emplace( >+ const_iterator position, Args&&... args) { >+ assert(position >= begin()); >+ assert(position <= end()); >+ if (position == end()) { >+ emplace_back(std::forward<Args>(args)...); >+ return end() - 1; >+ } >+ >+ T new_t = T(std::forward<Args>(args)...); >+ >+ auto range = ShiftRight(position, 1); >+ if (range.first == range.second) { >+ // constructing into uninitialized memory >+ Construct(range.first, std::move(new_t)); >+ } else { >+ // assigning into moved-from object >+ *range.first = T(std::move(new_t)); >+ } >+ >+ return range.first; >+} >+ >+template <typename T, size_t N, typename A> >+typename InlinedVector<T, N, A>::iterator InlinedVector<T, N, A>::erase( >+ const_iterator first, const_iterator last) { >+ assert(begin() <= first); >+ assert(first <= last); >+ assert(last <= end()); >+ >+ iterator range_start = const_cast<iterator>(first); >+ iterator range_end = const_cast<iterator>(last); >+ >+ size_type s = size(); >+ ptrdiff_t erase_gap = std::distance(range_start, range_end); >+ if (erase_gap > 0) { >+ pointer space; >+ if (allocated()) { >+ space = allocated_space(); >+ tag().set_allocated_size(s - erase_gap); >+ } else { >+ space = inlined_space(); >+ tag().set_inline_size(s - erase_gap); >+ } >+ std::move(range_end, space + s, range_start); >+ Destroy(space + s - erase_gap, space + s); >+ } >+ return range_start; >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::swap(InlinedVector& other) { >+ using std::swap; // Augment ADL with std::swap. >+ if (&other == this) { >+ return; >+ } >+ if (allocated() && other.allocated()) { >+ // Both out of line, so just swap the tag, allocation, and allocator. >+ swap(tag(), other.tag()); >+ swap(allocation(), other.allocation()); >+ swap(allocator(), other.allocator()); >+ return; >+ } >+ if (!allocated() && !other.allocated()) { >+ // Both inlined: swap up to smaller size, then move remaining elements. >+ InlinedVector* a = this; >+ InlinedVector* b = &other; >+ if (size() < other.size()) { >+ swap(a, b); >+ } >+ >+ const size_type a_size = a->size(); >+ const size_type b_size = b->size(); >+ assert(a_size >= b_size); >+ // 'a' is larger. Swap the elements up to the smaller array size. >+ std::swap_ranges(a->inlined_space(), a->inlined_space() + b_size, >+ b->inlined_space()); >+ >+ // Move the remaining elements: A[b_size,a_size) -> B[b_size,a_size) >+ b->UninitializedCopy(a->inlined_space() + b_size, >+ a->inlined_space() + a_size, >+ b->inlined_space() + b_size); >+ a->Destroy(a->inlined_space() + b_size, a->inlined_space() + a_size); >+ >+ swap(a->tag(), b->tag()); >+ swap(a->allocator(), b->allocator()); >+ assert(b->size() == a_size); >+ assert(a->size() == b_size); >+ return; >+ } >+ // One is out of line, one is inline. >+ // We first move the elements from the inlined vector into the >+ // inlined space in the other vector. We then put the other vector's >+ // pointer/capacity into the originally inlined vector and swap >+ // the tags. >+ InlinedVector* a = this; >+ InlinedVector* b = &other; >+ if (a->allocated()) { >+ swap(a, b); >+ } >+ assert(!a->allocated()); >+ assert(b->allocated()); >+ const size_type a_size = a->size(); >+ const size_type b_size = b->size(); >+ // In an optimized build, b_size would be unused. >+ (void)b_size; >+ >+ // Made Local copies of size(), don't need tag() accurate anymore >+ swap(a->tag(), b->tag()); >+ >+ // Copy b_allocation out before b's union gets clobbered by inline_space. >+ Allocation b_allocation = b->allocation(); >+ >+ b->UninitializedCopy(a->inlined_space(), a->inlined_space() + a_size, >+ b->inlined_space()); >+ a->Destroy(a->inlined_space(), a->inlined_space() + a_size); >+ >+ a->allocation() = b_allocation; >+ >+ if (a->allocator() != b->allocator()) { >+ swap(a->allocator(), b->allocator()); >+ } >+ >+ assert(b->size() == a_size); >+ assert(a->size() == b_size); >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::EnlargeBy(size_type delta) { >+ const size_type s = size(); >+ assert(s <= capacity()); >+ >+ size_type target = std::max(static_cast<size_type>(N), s + delta); >+ >+ // Compute new capacity by repeatedly doubling current capacity >+ // TODO(psrc): Check and avoid overflow? >+ size_type new_capacity = capacity(); >+ while (new_capacity < target) { >+ new_capacity <<= 1; >+ } >+ >+ Allocation new_allocation(allocator(), new_capacity); >+ >+ UninitializedCopy(std::make_move_iterator(data()), >+ std::make_move_iterator(data() + s), >+ new_allocation.buffer()); >+ >+ ResetAllocation(new_allocation, s); >+} >+ >+template <typename T, size_t N, typename A> >+auto InlinedVector<T, N, A>::ShiftRight(const_iterator position, size_type n) >+ -> std::pair<iterator, iterator> { >+ iterator start_used = const_cast<iterator>(position); >+ iterator start_raw = const_cast<iterator>(position); >+ size_type s = size(); >+ size_type required_size = s + n; >+ >+ if (required_size > capacity()) { >+ // Compute new capacity by repeatedly doubling current capacity >+ size_type new_capacity = capacity(); >+ while (new_capacity < required_size) { >+ new_capacity <<= 1; >+ } >+ // Move everyone into the new allocation, leaving a gap of n for the >+ // requested shift. >+ Allocation new_allocation(allocator(), new_capacity); >+ size_type index = position - begin(); >+ UninitializedCopy(std::make_move_iterator(data()), >+ std::make_move_iterator(data() + index), >+ new_allocation.buffer()); >+ UninitializedCopy(std::make_move_iterator(data() + index), >+ std::make_move_iterator(data() + s), >+ new_allocation.buffer() + index + n); >+ ResetAllocation(new_allocation, s); >+ >+ // New allocation means our iterator is invalid, so we'll recalculate. >+ // Since the entire gap is in new space, there's no used space to reuse. >+ start_raw = begin() + index; >+ start_used = start_raw; >+ } else { >+ // If we had enough space, it's a two-part move. Elements going into >+ // previously-unoccupied space need an UninitializedCopy. Elements >+ // going into a previously-occupied space are just a move. >+ iterator pos = const_cast<iterator>(position); >+ iterator raw_space = end(); >+ size_type slots_in_used_space = raw_space - pos; >+ size_type new_elements_in_used_space = std::min(n, slots_in_used_space); >+ size_type new_elements_in_raw_space = n - new_elements_in_used_space; >+ size_type old_elements_in_used_space = >+ slots_in_used_space - new_elements_in_used_space; >+ >+ UninitializedCopy(std::make_move_iterator(pos + old_elements_in_used_space), >+ std::make_move_iterator(raw_space), >+ raw_space + new_elements_in_raw_space); >+ std::move_backward(pos, pos + old_elements_in_used_space, raw_space); >+ >+ // If the gap is entirely in raw space, the used space starts where the raw >+ // space starts, leaving no elements in used space. If the gap is entirely >+ // in used space, the raw space starts at the end of the gap, leaving all >+ // elements accounted for within the used space. >+ start_used = pos; >+ start_raw = pos + new_elements_in_used_space; >+ } >+ tag().add_size(n); >+ return std::make_pair(start_used, start_raw); >+} >+ >+template <typename T, size_t N, typename A> >+void InlinedVector<T, N, A>::Destroy(value_type* ptr, value_type* ptr_last) { >+ for (value_type* p = ptr; p != ptr_last; ++p) { >+ AllocatorTraits::destroy(allocator(), p); >+ } >+ >+ // Overwrite unused memory with 0xab so we can catch uninitialized usage. >+ // Cast to void* to tell the compiler that we don't care that we might be >+ // scribbling on a vtable pointer. >+#ifndef NDEBUG >+ if (ptr != ptr_last) { >+ memset(reinterpret_cast<void*>(ptr), 0xab, sizeof(*ptr) * (ptr_last - ptr)); >+ } >+#endif >+} >+ >+template <typename T, size_t N, typename A> >+template <typename Iter> >+void InlinedVector<T, N, A>::AppendRange(Iter first, Iter last, >+ std::forward_iterator_tag) { >+ using Length = typename std::iterator_traits<Iter>::difference_type; >+ Length length = std::distance(first, last); >+ reserve(size() + length); >+ if (allocated()) { >+ UninitializedCopy(first, last, allocated_space() + size()); >+ tag().set_allocated_size(size() + length); >+ } else { >+ UninitializedCopy(first, last, inlined_space() + size()); >+ tag().set_inline_size(size() + length); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+template <typename Iter> >+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last, >+ std::input_iterator_tag) { >+ // Optimized to avoid reallocation. >+ // Prefer reassignment to copy construction for elements. >+ iterator out = begin(); >+ for (; first != last && out != end(); ++first, ++out) { >+ *out = *first; >+ } >+ erase(out, end()); >+ std::copy(first, last, std::back_inserter(*this)); >+} >+ >+template <typename T, size_t N, typename A> >+template <typename Iter> >+void InlinedVector<T, N, A>::AssignRange(Iter first, Iter last, >+ std::forward_iterator_tag) { >+ using Length = typename std::iterator_traits<Iter>::difference_type; >+ Length length = std::distance(first, last); >+ // Prefer reassignment to copy construction for elements. >+ if (static_cast<size_type>(length) <= size()) { >+ erase(std::copy(first, last, begin()), end()); >+ return; >+ } >+ reserve(length); >+ iterator out = begin(); >+ for (; out != end(); ++first, ++out) *out = *first; >+ if (allocated()) { >+ UninitializedCopy(first, last, out); >+ tag().set_allocated_size(length); >+ } else { >+ UninitializedCopy(first, last, out); >+ tag().set_inline_size(length); >+ } >+} >+ >+template <typename T, size_t N, typename A> >+auto InlinedVector<T, N, A>::InsertWithCount(const_iterator position, >+ size_type n, const value_type& v) >+ -> iterator { >+ assert(position >= begin() && position <= end()); >+ if (n == 0) return const_cast<iterator>(position); >+ >+ value_type copy = v; >+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n); >+ std::fill(it_pair.first, it_pair.second, copy); >+ UninitializedFill(it_pair.second, it_pair.first + n, copy); >+ >+ return it_pair.first; >+} >+ >+template <typename T, size_t N, typename A> >+template <typename InputIter> >+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position, >+ InputIter first, InputIter last, >+ std::input_iterator_tag) >+ -> iterator { >+ assert(position >= begin() && position <= end()); >+ size_type index = position - cbegin(); >+ size_type i = index; >+ while (first != last) insert(begin() + i++, *first++); >+ return begin() + index; >+} >+ >+// Overload of InlinedVector::InsertWithRange() >+template <typename T, size_t N, typename A> >+template <typename ForwardIter> >+auto InlinedVector<T, N, A>::InsertWithRange(const_iterator position, >+ ForwardIter first, >+ ForwardIter last, >+ std::forward_iterator_tag) >+ -> iterator { >+ assert(position >= begin() && position <= end()); >+ if (first == last) { >+ return const_cast<iterator>(position); >+ } >+ using Length = typename std::iterator_traits<ForwardIter>::difference_type; >+ Length n = std::distance(first, last); >+ std::pair<iterator, iterator> it_pair = ShiftRight(position, n); >+ size_type used_spots = it_pair.second - it_pair.first; >+ ForwardIter open_spot = std::next(first, used_spots); >+ std::copy(first, open_spot, it_pair.first); >+ UninitializedCopy(open_spot, last, it_pair.second); >+ return it_pair.first; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_CONTAINER_INLINED_VECTOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc >new file mode 100644 >index 00000000000..24f2174928a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_benchmark.cc >@@ -0,0 +1,385 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/inlined_vector.h" >+ >+#include <string> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+using IntVec = absl::InlinedVector<int, 8>; >+ >+void BM_InlinedVectorFill(benchmark::State& state) { >+ const int len = state.range(0); >+ for (auto _ : state) { >+ IntVec v; >+ for (int i = 0; i < len; i++) { >+ v.push_back(i); >+ } >+ } >+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); >+} >+BENCHMARK(BM_InlinedVectorFill)->Range(0, 1024); >+ >+void BM_InlinedVectorFillRange(benchmark::State& state) { >+ const int len = state.range(0); >+ std::unique_ptr<int[]> ia(new int[len]); >+ for (int i = 0; i < len; i++) { >+ ia[i] = i; >+ } >+ for (auto _ : state) { >+ IntVec v(ia.get(), ia.get() + len); >+ benchmark::DoNotOptimize(v); >+ } >+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); >+} >+BENCHMARK(BM_InlinedVectorFillRange)->Range(0, 1024); >+ >+void BM_StdVectorFill(benchmark::State& state) { >+ const int len = state.range(0); >+ for (auto _ : state) { >+ std::vector<int> v; >+ for (int i = 0; i < len; i++) { >+ v.push_back(i); >+ } >+ } >+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); >+} >+BENCHMARK(BM_StdVectorFill)->Range(0, 1024); >+ >+// The purpose of the next two benchmarks is to verify that >+// absl::InlinedVector is efficient when moving is more efficent than >+// copying. To do so, we use strings that are larger than the short >+// std::string optimization. >+bool StringRepresentedInline(std::string s) { >+ const char* chars = s.data(); >+ std::string s1 = std::move(s); >+ return s1.data() != chars; >+} >+ >+int GetNonShortStringOptimizationSize() { >+ for (int i = 24; i <= 192; i *= 2) { >+ if (!StringRepresentedInline(std::string(i, 'A'))) { >+ return i; >+ } >+ } >+ ABSL_RAW_LOG( >+ FATAL, >+ "Failed to find a std::string larger than the short std::string optimization"); >+ return -1; >+} >+ >+void BM_InlinedVectorFillString(benchmark::State& state) { >+ const int len = state.range(0); >+ const int no_sso = GetNonShortStringOptimizationSize(); >+ std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), >+ std::string(no_sso, 'C'), std::string(no_sso, 'D')}; >+ >+ for (auto _ : state) { >+ absl::InlinedVector<std::string, 8> v; >+ for (int i = 0; i < len; i++) { >+ v.push_back(strings[i & 3]); >+ } >+ } >+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); >+} >+BENCHMARK(BM_InlinedVectorFillString)->Range(0, 1024); >+ >+void BM_StdVectorFillString(benchmark::State& state) { >+ const int len = state.range(0); >+ const int no_sso = GetNonShortStringOptimizationSize(); >+ std::string strings[4] = {std::string(no_sso, 'A'), std::string(no_sso, 'B'), >+ std::string(no_sso, 'C'), std::string(no_sso, 'D')}; >+ >+ for (auto _ : state) { >+ std::vector<std::string> v; >+ for (int i = 0; i < len; i++) { >+ v.push_back(strings[i & 3]); >+ } >+ } >+ state.SetItemsProcessed(static_cast<int64_t>(state.iterations()) * len); >+} >+BENCHMARK(BM_StdVectorFillString)->Range(0, 1024); >+ >+struct Buffer { // some arbitrary structure for benchmarking. >+ char* base; >+ int length; >+ int capacity; >+ void* user_data; >+}; >+ >+void BM_InlinedVectorTenAssignments(benchmark::State& state) { >+ const int len = state.range(0); >+ using BufferVec = absl::InlinedVector<Buffer, 2>; >+ >+ BufferVec src; >+ src.resize(len); >+ >+ BufferVec dst; >+ for (auto _ : state) { >+ for (int i = 0; i < 10; ++i) { >+ dst = src; >+ } >+ } >+} >+BENCHMARK(BM_InlinedVectorTenAssignments) >+ ->Arg(0)->Arg(1)->Arg(2)->Arg(3)->Arg(4)->Arg(20); >+ >+void BM_CreateFromContainer(benchmark::State& state) { >+ for (auto _ : state) { >+ absl::InlinedVector<int, 4> x(absl::InlinedVector<int, 4>{1, 2, 3}); >+ benchmark::DoNotOptimize(x); >+ } >+} >+BENCHMARK(BM_CreateFromContainer); >+ >+struct LargeCopyableOnly { >+ LargeCopyableOnly() : d(1024, 17) {} >+ LargeCopyableOnly(const LargeCopyableOnly& o) = default; >+ LargeCopyableOnly& operator=(const LargeCopyableOnly& o) = default; >+ >+ std::vector<int> d; >+}; >+ >+struct LargeCopyableSwappable { >+ LargeCopyableSwappable() : d(1024, 17) {} >+ LargeCopyableSwappable(const LargeCopyableSwappable& o) = default; >+ LargeCopyableSwappable(LargeCopyableSwappable&& o) = delete; >+ >+ LargeCopyableSwappable& operator=(LargeCopyableSwappable o) { >+ using std::swap; >+ swap(*this, o); >+ return *this; >+ } >+ LargeCopyableSwappable& operator=(LargeCopyableSwappable&& o) = delete; >+ >+ friend void swap(LargeCopyableSwappable& a, LargeCopyableSwappable& b) { >+ using std::swap; >+ swap(a.d, b.d); >+ } >+ >+ std::vector<int> d; >+}; >+ >+struct LargeCopyableMovable { >+ LargeCopyableMovable() : d(1024, 17) {} >+ // Use implicitly defined copy and move. >+ >+ std::vector<int> d; >+}; >+ >+struct LargeCopyableMovableSwappable { >+ LargeCopyableMovableSwappable() : d(1024, 17) {} >+ LargeCopyableMovableSwappable(const LargeCopyableMovableSwappable& o) = >+ default; >+ LargeCopyableMovableSwappable(LargeCopyableMovableSwappable&& o) = default; >+ >+ LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable o) { >+ using std::swap; >+ swap(*this, o); >+ return *this; >+ } >+ LargeCopyableMovableSwappable& operator=(LargeCopyableMovableSwappable&& o) = >+ default; >+ >+ friend void swap(LargeCopyableMovableSwappable& a, >+ LargeCopyableMovableSwappable& b) { >+ using std::swap; >+ swap(a.d, b.d); >+ } >+ >+ std::vector<int> d; >+}; >+ >+template <typename ElementType> >+void BM_SwapElements(benchmark::State& state) { >+ const int len = state.range(0); >+ using Vec = absl::InlinedVector<ElementType, 32>; >+ Vec a(len); >+ Vec b; >+ for (auto _ : state) { >+ using std::swap; >+ swap(a, b); >+ } >+} >+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableOnly)->Range(0, 1024); >+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableSwappable)->Range(0, 1024); >+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovable)->Range(0, 1024); >+BENCHMARK_TEMPLATE(BM_SwapElements, LargeCopyableMovableSwappable) >+ ->Range(0, 1024); >+ >+// The following benchmark is meant to track the efficiency of the vector size >+// as a function of stored type via the benchmark label. It is not meant to >+// output useful sizeof operator performance. The loop is a dummy operation >+// to fulfill the requirement of running the benchmark. >+template <typename VecType> >+void BM_Sizeof(benchmark::State& state) { >+ int size = 0; >+ for (auto _ : state) { >+ VecType vec; >+ size = sizeof(vec); >+ } >+ state.SetLabel(absl::StrCat("sz=", size)); >+} >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 1>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 4>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 7>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<char, 8>); >+ >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 1>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 4>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 7>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<int, 8>); >+ >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 1>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 4>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 7>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<void*, 8>); >+ >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 1>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 4>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 7>); >+BENCHMARK_TEMPLATE(BM_Sizeof, absl::InlinedVector<std::string, 8>); >+ >+void BM_InlinedVectorIndexInlined(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; >+ for (auto _ : state) { >+ for (int i = 0; i < 1000; ++i) { >+ benchmark::DoNotOptimize(v); >+ benchmark::DoNotOptimize(v[4]); >+ } >+ } >+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorIndexInlined); >+ >+void BM_InlinedVectorIndexExternal(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ for (int i = 0; i < 1000; ++i) { >+ benchmark::DoNotOptimize(v); >+ benchmark::DoNotOptimize(v[4]); >+ } >+ } >+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorIndexExternal); >+ >+void BM_StdVectorIndex(benchmark::State& state) { >+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ for (int i = 0; i < 1000; ++i) { >+ benchmark::DoNotOptimize(v); >+ benchmark::DoNotOptimize(v[4]); >+ } >+ } >+ state.SetItemsProcessed(1000 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_StdVectorIndex); >+ >+#define UNROLL_2(x) \ >+ benchmark::DoNotOptimize(x); \ >+ benchmark::DoNotOptimize(x); >+ >+#define UNROLL_4(x) UNROLL_2(x) UNROLL_2(x) >+#define UNROLL_8(x) UNROLL_4(x) UNROLL_4(x) >+#define UNROLL_16(x) UNROLL_8(x) UNROLL_8(x); >+ >+void BM_InlinedVectorDataInlined(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; >+ for (auto _ : state) { >+ UNROLL_16(v.data()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorDataInlined); >+ >+void BM_InlinedVectorDataExternal(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.data()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorDataExternal); >+ >+void BM_StdVectorData(benchmark::State& state) { >+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.data()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_StdVectorData); >+ >+void BM_InlinedVectorSizeInlined(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; >+ for (auto _ : state) { >+ UNROLL_16(v.size()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorSizeInlined); >+ >+void BM_InlinedVectorSizeExternal(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.size()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorSizeExternal); >+ >+void BM_StdVectorSize(benchmark::State& state) { >+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.size()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_StdVectorSize); >+ >+void BM_InlinedVectorEmptyInlined(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7}; >+ for (auto _ : state) { >+ UNROLL_16(v.empty()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorEmptyInlined); >+ >+void BM_InlinedVectorEmptyExternal(benchmark::State& state) { >+ absl::InlinedVector<int, 8> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.empty()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_InlinedVectorEmptyExternal); >+ >+void BM_StdVectorEmpty(benchmark::State& state) { >+ std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; >+ for (auto _ : state) { >+ UNROLL_16(v.empty()); >+ } >+ state.SetItemsProcessed(16 * static_cast<int64_t>(state.iterations())); >+} >+BENCHMARK(BM_StdVectorEmpty); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_test.cc >new file mode 100644 >index 00000000000..196a1bed976 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/inlined_vector_test.cc >@@ -0,0 +1,1791 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/inlined_vector.h" >+ >+#include <algorithm> >+#include <forward_list> >+#include <list> >+#include <memory> >+#include <scoped_allocator> >+#include <sstream> >+#include <stdexcept> >+#include <string> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/internal/exception_testing.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/macros.h" >+#include "absl/container/internal/test_instance_tracker.h" >+#include "absl/memory/memory.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+using absl::test_internal::CopyableMovableInstance; >+using absl::test_internal::CopyableOnlyInstance; >+using absl::test_internal::InstanceTracker; >+using testing::AllOf; >+using testing::Each; >+using testing::ElementsAre; >+using testing::ElementsAreArray; >+using testing::Eq; >+using testing::Gt; >+using testing::PrintToString; >+ >+using IntVec = absl::InlinedVector<int, 8>; >+ >+MATCHER_P(SizeIs, n, "") { >+ return testing::ExplainMatchResult(n, arg.size(), result_listener); >+} >+ >+MATCHER_P(CapacityIs, n, "") { >+ return testing::ExplainMatchResult(n, arg.capacity(), result_listener); >+} >+ >+MATCHER_P(ValueIs, e, "") { >+ return testing::ExplainMatchResult(e, arg.value(), result_listener); >+} >+ >+// TODO(bsamwel): Add support for movable-only types. >+ >+// Test fixture for typed tests on BaseCountedInstance derived classes, see >+// test_instance_tracker.h. >+template <typename T> >+class InstanceTest : public ::testing::Test {}; >+TYPED_TEST_CASE_P(InstanceTest); >+ >+// A simple reference counted class to make sure that the proper elements are >+// destroyed in the erase(begin, end) test. >+class RefCounted { >+ public: >+ RefCounted(int value, int* count) : value_(value), count_(count) { >+ Ref(); >+ } >+ >+ RefCounted(const RefCounted& v) >+ : value_(v.value_), count_(v.count_) { >+ Ref(); >+ } >+ >+ ~RefCounted() { >+ Unref(); >+ count_ = nullptr; >+ } >+ >+ friend void swap(RefCounted& a, RefCounted& b) { >+ using std::swap; >+ swap(a.value_, b.value_); >+ swap(a.count_, b.count_); >+ } >+ >+ RefCounted& operator=(RefCounted v) { >+ using std::swap; >+ swap(*this, v); >+ return *this; >+ } >+ >+ void Ref() const { >+ ABSL_RAW_CHECK(count_ != nullptr, ""); >+ ++(*count_); >+ } >+ >+ void Unref() const { >+ --(*count_); >+ ABSL_RAW_CHECK(*count_ >= 0, ""); >+ } >+ >+ int value_; >+ int* count_; >+}; >+ >+using RefCountedVec = absl::InlinedVector<RefCounted, 8>; >+ >+// A class with a vtable pointer >+class Dynamic { >+ public: >+ virtual ~Dynamic() {} >+}; >+ >+using DynamicVec = absl::InlinedVector<Dynamic, 8>; >+ >+// Append 0..len-1 to *v >+template <typename Container> >+static void Fill(Container* v, int len, int offset = 0) { >+ for (int i = 0; i < len; i++) { >+ v->push_back(i + offset); >+ } >+} >+ >+static IntVec Fill(int len, int offset = 0) { >+ IntVec v; >+ Fill(&v, len, offset); >+ return v; >+} >+ >+// This is a stateful allocator, but the state lives outside of the >+// allocator (in whatever test is using the allocator). This is odd >+// but helps in tests where the allocator is propagated into nested >+// containers - that chain of allocators uses the same state and is >+// thus easier to query for aggregate allocation information. >+template <typename T> >+class CountingAllocator : public std::allocator<T> { >+ public: >+ using Alloc = std::allocator<T>; >+ using pointer = typename Alloc::pointer; >+ using size_type = typename Alloc::size_type; >+ >+ CountingAllocator() : bytes_used_(nullptr) {} >+ explicit CountingAllocator(int64_t* b) : bytes_used_(b) {} >+ >+ template <typename U> >+ CountingAllocator(const CountingAllocator<U>& x) >+ : Alloc(x), bytes_used_(x.bytes_used_) {} >+ >+ pointer allocate(size_type n, >+ std::allocator<void>::const_pointer hint = nullptr) { >+ assert(bytes_used_ != nullptr); >+ *bytes_used_ += n * sizeof(T); >+ return Alloc::allocate(n, hint); >+ } >+ >+ void deallocate(pointer p, size_type n) { >+ Alloc::deallocate(p, n); >+ assert(bytes_used_ != nullptr); >+ *bytes_used_ -= n * sizeof(T); >+ } >+ >+ template<typename U> >+ class rebind { >+ public: >+ using other = CountingAllocator<U>; >+ }; >+ >+ friend bool operator==(const CountingAllocator& a, >+ const CountingAllocator& b) { >+ return a.bytes_used_ == b.bytes_used_; >+ } >+ >+ friend bool operator!=(const CountingAllocator& a, >+ const CountingAllocator& b) { >+ return !(a == b); >+ } >+ >+ int64_t* bytes_used_; >+}; >+ >+TEST(IntVec, SimpleOps) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v; >+ const IntVec& cv = v; // const alias >+ >+ Fill(&v, len); >+ EXPECT_EQ(len, v.size()); >+ EXPECT_LE(len, v.capacity()); >+ >+ for (int i = 0; i < len; i++) { >+ EXPECT_EQ(i, v[i]); >+ EXPECT_EQ(i, v.at(i)); >+ } >+ EXPECT_EQ(v.begin(), v.data()); >+ EXPECT_EQ(cv.begin(), cv.data()); >+ >+ int counter = 0; >+ for (IntVec::iterator iter = v.begin(); iter != v.end(); ++iter) { >+ EXPECT_EQ(counter, *iter); >+ counter++; >+ } >+ EXPECT_EQ(counter, len); >+ >+ counter = 0; >+ for (IntVec::const_iterator iter = v.begin(); iter != v.end(); ++iter) { >+ EXPECT_EQ(counter, *iter); >+ counter++; >+ } >+ EXPECT_EQ(counter, len); >+ >+ counter = 0; >+ for (IntVec::const_iterator iter = v.cbegin(); iter != v.cend(); ++iter) { >+ EXPECT_EQ(counter, *iter); >+ counter++; >+ } >+ EXPECT_EQ(counter, len); >+ >+ if (len > 0) { >+ EXPECT_EQ(0, v.front()); >+ EXPECT_EQ(len - 1, v.back()); >+ v.pop_back(); >+ EXPECT_EQ(len - 1, v.size()); >+ for (int i = 0; i < v.size(); ++i) { >+ EXPECT_EQ(i, v[i]); >+ EXPECT_EQ(i, v.at(i)); >+ } >+ } >+ } >+} >+ >+TEST(IntVec, AtThrows) { >+ IntVec v = {1, 2, 3}; >+ EXPECT_EQ(v.at(2), 3); >+ ABSL_BASE_INTERNAL_EXPECT_FAIL(v.at(3), std::out_of_range, >+ "failed bounds check"); >+} >+ >+TEST(IntVec, ReverseIterator) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v; >+ Fill(&v, len); >+ >+ int counter = len; >+ for (IntVec::reverse_iterator iter = v.rbegin(); iter != v.rend(); ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = len; >+ for (IntVec::const_reverse_iterator iter = v.rbegin(); iter != v.rend(); >+ ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ >+ counter = len; >+ for (IntVec::const_reverse_iterator iter = v.crbegin(); iter != v.crend(); >+ ++iter) { >+ counter--; >+ EXPECT_EQ(counter, *iter); >+ } >+ EXPECT_EQ(counter, 0); >+ } >+} >+ >+TEST(IntVec, Erase) { >+ for (int len = 1; len < 20; len++) { >+ for (int i = 0; i < len; ++i) { >+ IntVec v; >+ Fill(&v, len); >+ v.erase(v.begin() + i); >+ EXPECT_EQ(len - 1, v.size()); >+ for (int j = 0; j < i; ++j) { >+ EXPECT_EQ(j, v[j]); >+ } >+ for (int j = i; j < len - 1; ++j) { >+ EXPECT_EQ(j + 1, v[j]); >+ } >+ } >+ } >+} >+ >+// At the end of this test loop, the elements between [erase_begin, erase_end) >+// should have reference counts == 0, and all others elements should have >+// reference counts == 1. >+TEST(RefCountedVec, EraseBeginEnd) { >+ for (int len = 1; len < 20; ++len) { >+ for (int erase_begin = 0; erase_begin < len; ++erase_begin) { >+ for (int erase_end = erase_begin; erase_end <= len; ++erase_end) { >+ std::vector<int> counts(len, 0); >+ RefCountedVec v; >+ for (int i = 0; i < len; ++i) { >+ v.push_back(RefCounted(i, &counts[i])); >+ } >+ >+ int erase_len = erase_end - erase_begin; >+ >+ v.erase(v.begin() + erase_begin, v.begin() + erase_end); >+ >+ EXPECT_EQ(len - erase_len, v.size()); >+ >+ // Check the elements before the first element erased. >+ for (int i = 0; i < erase_begin; ++i) { >+ EXPECT_EQ(i, v[i].value_); >+ } >+ >+ // Check the elements after the first element erased. >+ for (int i = erase_begin; i < v.size(); ++i) { >+ EXPECT_EQ(i + erase_len, v[i].value_); >+ } >+ >+ // Check that the elements at the beginning are preserved. >+ for (int i = 0; i < erase_begin; ++i) { >+ EXPECT_EQ(1, counts[i]); >+ } >+ >+ // Check that the erased elements are destroyed >+ for (int i = erase_begin; i < erase_end; ++i) { >+ EXPECT_EQ(0, counts[i]); >+ } >+ >+ // Check that the elements at the end are preserved. >+ for (int i = erase_end; i< len; ++i) { >+ EXPECT_EQ(1, counts[i]); >+ } >+ } >+ } >+ } >+} >+ >+struct NoDefaultCtor { >+ explicit NoDefaultCtor(int) {} >+}; >+struct NoCopy { >+ NoCopy() {} >+ NoCopy(const NoCopy&) = delete; >+}; >+struct NoAssign { >+ NoAssign() {} >+ NoAssign& operator=(const NoAssign&) = delete; >+}; >+struct MoveOnly { >+ MoveOnly() {} >+ MoveOnly(MoveOnly&&) = default; >+ MoveOnly& operator=(MoveOnly&&) = default; >+}; >+TEST(InlinedVectorTest, NoDefaultCtor) { >+ absl::InlinedVector<NoDefaultCtor, 1> v(10, NoDefaultCtor(2)); >+ (void)v; >+} >+TEST(InlinedVectorTest, NoCopy) { >+ absl::InlinedVector<NoCopy, 1> v(10); >+ (void)v; >+} >+TEST(InlinedVectorTest, NoAssign) { >+ absl::InlinedVector<NoAssign, 1> v(10); >+ (void)v; >+} >+TEST(InlinedVectorTest, MoveOnly) { >+ absl::InlinedVector<MoveOnly, 2> v; >+ v.push_back(MoveOnly{}); >+ v.push_back(MoveOnly{}); >+ v.push_back(MoveOnly{}); >+ v.erase(v.begin()); >+ v.push_back(MoveOnly{}); >+ v.erase(v.begin(), v.begin() + 1); >+ v.insert(v.begin(), MoveOnly{}); >+ v.emplace(v.begin()); >+ v.emplace(v.begin(), MoveOnly{}); >+} >+TEST(InlinedVectorTest, Noexcept) { >+ EXPECT_TRUE(std::is_nothrow_move_constructible<IntVec>::value); >+ EXPECT_TRUE((std::is_nothrow_move_constructible< >+ absl::InlinedVector<MoveOnly, 2>>::value)); >+ >+ struct MoveCanThrow { >+ MoveCanThrow(MoveCanThrow&&) {} >+ }; >+ EXPECT_EQ(absl::default_allocator_is_nothrow::value, >+ (std::is_nothrow_move_constructible< >+ absl::InlinedVector<MoveCanThrow, 2>>::value)); >+} >+ >+TEST(InlinedVectorTest, EmplaceBack) { >+ absl::InlinedVector<std::pair<std::string, int>, 1> v; >+ >+ auto& inlined_element = v.emplace_back("answer", 42); >+ EXPECT_EQ(&inlined_element, &v[0]); >+ EXPECT_EQ(inlined_element.first, "answer"); >+ EXPECT_EQ(inlined_element.second, 42); >+ >+ auto& allocated_element = v.emplace_back("taxicab", 1729); >+ EXPECT_EQ(&allocated_element, &v[1]); >+ EXPECT_EQ(allocated_element.first, "taxicab"); >+ EXPECT_EQ(allocated_element.second, 1729); >+} >+ >+TEST(InlinedVectorTest, ShrinkToFitGrowingVector) { >+ absl::InlinedVector<std::pair<std::string, int>, 1> v; >+ >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 1); >+ >+ v.emplace_back("answer", 42); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 1); >+ >+ v.emplace_back("taxicab", 1729); >+ EXPECT_GE(v.capacity(), 2); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 2); >+ >+ v.reserve(100); >+ EXPECT_GE(v.capacity(), 100); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 2); >+} >+ >+TEST(InlinedVectorTest, ShrinkToFitEdgeCases) { >+ { >+ absl::InlinedVector<std::pair<std::string, int>, 1> v; >+ v.emplace_back("answer", 42); >+ v.emplace_back("taxicab", 1729); >+ EXPECT_GE(v.capacity(), 2); >+ v.pop_back(); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 1); >+ EXPECT_EQ(v[0].first, "answer"); >+ EXPECT_EQ(v[0].second, 42); >+ } >+ >+ { >+ absl::InlinedVector<std::string, 2> v(100); >+ v.resize(0); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 2); // inlined capacity >+ } >+ >+ { >+ absl::InlinedVector<std::string, 2> v(100); >+ v.resize(1); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 2); // inlined capacity >+ } >+ >+ { >+ absl::InlinedVector<std::string, 2> v(100); >+ v.resize(2); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 2); >+ } >+ >+ { >+ absl::InlinedVector<std::string, 2> v(100); >+ v.resize(3); >+ v.shrink_to_fit(); >+ EXPECT_EQ(v.capacity(), 3); >+ } >+} >+ >+TEST(IntVec, Insert) { >+ for (int len = 0; len < 20; len++) { >+ for (int pos = 0; pos <= len; pos++) { >+ { >+ // Single element >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ std_v.insert(std_v.begin() + pos, 9999); >+ IntVec::iterator it = v.insert(v.cbegin() + pos, 9999); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ { >+ // n elements >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ IntVec::size_type n = 5; >+ std_v.insert(std_v.begin() + pos, n, 9999); >+ IntVec::iterator it = v.insert(v.cbegin() + pos, n, 9999); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ { >+ // Iterator range (random access iterator) >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ const std::vector<int> input = {9999, 8888, 7777}; >+ std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend()); >+ IntVec::iterator it = >+ v.insert(v.cbegin() + pos, input.cbegin(), input.cend()); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ { >+ // Iterator range (forward iterator) >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ const std::forward_list<int> input = {9999, 8888, 7777}; >+ std_v.insert(std_v.begin() + pos, input.cbegin(), input.cend()); >+ IntVec::iterator it = >+ v.insert(v.cbegin() + pos, input.cbegin(), input.cend()); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ { >+ // Iterator range (input iterator) >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ std_v.insert(std_v.begin() + pos, {9999, 8888, 7777}); >+ std::istringstream input("9999 8888 7777"); >+ IntVec::iterator it = >+ v.insert(v.cbegin() + pos, std::istream_iterator<int>(input), >+ std::istream_iterator<int>()); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ { >+ // Initializer list >+ std::vector<int> std_v; >+ Fill(&std_v, len); >+ IntVec v; >+ Fill(&v, len); >+ >+ std_v.insert(std_v.begin() + pos, {9999, 8888}); >+ IntVec::iterator it = v.insert(v.cbegin() + pos, {9999, 8888}); >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ EXPECT_EQ(it, v.cbegin() + pos); >+ } >+ } >+ } >+} >+ >+TEST(RefCountedVec, InsertConstructorDestructor) { >+ // Make sure the proper construction/destruction happen during insert >+ // operations. >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ for (int pos = 0; pos <= len; pos++) { >+ SCOPED_TRACE(pos); >+ std::vector<int> counts(len, 0); >+ int inserted_count = 0; >+ RefCountedVec v; >+ for (int i = 0; i < len; ++i) { >+ SCOPED_TRACE(i); >+ v.push_back(RefCounted(i, &counts[i])); >+ } >+ >+ EXPECT_THAT(counts, Each(Eq(1))); >+ >+ RefCounted insert_element(9999, &inserted_count); >+ EXPECT_EQ(1, inserted_count); >+ v.insert(v.begin() + pos, insert_element); >+ EXPECT_EQ(2, inserted_count); >+ // Check that the elements at the end are preserved. >+ EXPECT_THAT(counts, Each(Eq(1))); >+ EXPECT_EQ(2, inserted_count); >+ } >+ } >+} >+ >+TEST(IntVec, Resize) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v; >+ Fill(&v, len); >+ >+ // Try resizing up and down by k elements >+ static const int kResizeElem = 1000000; >+ for (int k = 0; k < 10; k++) { >+ // Enlarging resize >+ v.resize(len+k, kResizeElem); >+ EXPECT_EQ(len+k, v.size()); >+ EXPECT_LE(len+k, v.capacity()); >+ for (int i = 0; i < len+k; i++) { >+ if (i < len) { >+ EXPECT_EQ(i, v[i]); >+ } else { >+ EXPECT_EQ(kResizeElem, v[i]); >+ } >+ } >+ >+ // Shrinking resize >+ v.resize(len, kResizeElem); >+ EXPECT_EQ(len, v.size()); >+ EXPECT_LE(len, v.capacity()); >+ for (int i = 0; i < len; i++) { >+ EXPECT_EQ(i, v[i]); >+ } >+ } >+ } >+} >+ >+TEST(IntVec, InitWithLength) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v(len, 7); >+ EXPECT_EQ(len, v.size()); >+ EXPECT_LE(len, v.capacity()); >+ for (int i = 0; i < len; i++) { >+ EXPECT_EQ(7, v[i]); >+ } >+ } >+} >+ >+TEST(IntVec, CopyConstructorAndAssignment) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v; >+ Fill(&v, len); >+ EXPECT_EQ(len, v.size()); >+ EXPECT_LE(len, v.capacity()); >+ >+ IntVec v2(v); >+ EXPECT_TRUE(v == v2) << PrintToString(v) << PrintToString(v2); >+ >+ for (int start_len = 0; start_len < 20; start_len++) { >+ IntVec v3; >+ Fill(&v3, start_len, 99); // Add dummy elements that should go away >+ v3 = v; >+ EXPECT_TRUE(v == v3) << PrintToString(v) << PrintToString(v3); >+ } >+ } >+} >+ >+TEST(IntVec, AliasingCopyAssignment) { >+ for (int len = 0; len < 20; ++len) { >+ IntVec original; >+ Fill(&original, len); >+ IntVec dup = original; >+ dup = *&dup; >+ EXPECT_EQ(dup, original); >+ } >+} >+ >+TEST(IntVec, MoveConstructorAndAssignment) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v_in; >+ const int inlined_capacity = v_in.capacity(); >+ Fill(&v_in, len); >+ EXPECT_EQ(len, v_in.size()); >+ EXPECT_LE(len, v_in.capacity()); >+ >+ { >+ IntVec v_temp(v_in); >+ auto* old_data = v_temp.data(); >+ IntVec v_out(std::move(v_temp)); >+ EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out); >+ if (v_in.size() > inlined_capacity) { >+ // Allocation is moved as a whole, data stays in place. >+ EXPECT_TRUE(v_out.data() == old_data); >+ } else { >+ EXPECT_FALSE(v_out.data() == old_data); >+ } >+ } >+ for (int start_len = 0; start_len < 20; start_len++) { >+ IntVec v_out; >+ Fill(&v_out, start_len, 99); // Add dummy elements that should go away >+ IntVec v_temp(v_in); >+ auto* old_data = v_temp.data(); >+ v_out = std::move(v_temp); >+ EXPECT_TRUE(v_in == v_out) << PrintToString(v_in) << PrintToString(v_out); >+ if (v_in.size() > inlined_capacity) { >+ // Allocation is moved as a whole, data stays in place. >+ EXPECT_TRUE(v_out.data() == old_data); >+ } else { >+ EXPECT_FALSE(v_out.data() == old_data); >+ } >+ } >+ } >+} >+ >+class NotTriviallyDestructible { >+ public: >+ NotTriviallyDestructible() : p_(new int(1)) {} >+ explicit NotTriviallyDestructible(int i) : p_(new int(i)) {} >+ >+ NotTriviallyDestructible(const NotTriviallyDestructible& other) >+ : p_(new int(*other.p_)) {} >+ >+ NotTriviallyDestructible& operator=(const NotTriviallyDestructible& other) { >+ p_ = absl::make_unique<int>(*other.p_); >+ return *this; >+ } >+ >+ bool operator==(const NotTriviallyDestructible& other) const { >+ return *p_ == *other.p_; >+ } >+ >+ private: >+ std::unique_ptr<int> p_; >+}; >+ >+TEST(AliasingTest, Emplace) { >+ for (int i = 2; i < 20; ++i) { >+ absl::InlinedVector<NotTriviallyDestructible, 10> vec; >+ for (int j = 0; j < i; ++j) { >+ vec.push_back(NotTriviallyDestructible(j)); >+ } >+ vec.emplace(vec.begin(), vec[0]); >+ EXPECT_EQ(vec[0], vec[1]); >+ vec.emplace(vec.begin() + i / 2, vec[i / 2]); >+ EXPECT_EQ(vec[i / 2], vec[i / 2 + 1]); >+ vec.emplace(vec.end() - 1, vec.back()); >+ EXPECT_EQ(vec[vec.size() - 2], vec.back()); >+ } >+} >+ >+TEST(AliasingTest, InsertWithCount) { >+ for (int i = 1; i < 20; ++i) { >+ absl::InlinedVector<NotTriviallyDestructible, 10> vec; >+ for (int j = 0; j < i; ++j) { >+ vec.push_back(NotTriviallyDestructible(j)); >+ } >+ for (int n = 0; n < 5; ++n) { >+ // We use back where we can because it's guaranteed to become invalidated >+ vec.insert(vec.begin(), n, vec.back()); >+ auto b = vec.begin(); >+ EXPECT_TRUE( >+ std::all_of(b, b + n, [&vec](const NotTriviallyDestructible& x) { >+ return x == vec.back(); >+ })); >+ >+ auto m_idx = vec.size() / 2; >+ vec.insert(vec.begin() + m_idx, n, vec.back()); >+ auto m = vec.begin() + m_idx; >+ EXPECT_TRUE( >+ std::all_of(m, m + n, [&vec](const NotTriviallyDestructible& x) { >+ return x == vec.back(); >+ })); >+ >+ // We want distinct values so the equality test is meaningful, >+ // vec[vec.size() - 1] is also almost always invalidated. >+ auto old_e = vec.size() - 1; >+ auto val = vec[old_e]; >+ vec.insert(vec.end(), n, vec[old_e]); >+ auto e = vec.begin() + old_e; >+ EXPECT_TRUE(std::all_of( >+ e, e + n, >+ [&val](const NotTriviallyDestructible& x) { return x == val; })); >+ } >+ } >+} >+ >+TEST(OverheadTest, Storage) { >+ // Check for size overhead. >+ // In particular, ensure that std::allocator doesn't cost anything to store. >+ // The union should be absorbing some of the allocation bookkeeping overhead >+ // in the larger vectors, leaving only the size_ field as overhead. >+ EXPECT_EQ(2 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 1>) - 1 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 2>) - 2 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 3>) - 3 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 4>) - 4 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 5>) - 5 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 6>) - 6 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 7>) - 7 * sizeof(int*)); >+ EXPECT_EQ(1 * sizeof(int*), >+ sizeof(absl::InlinedVector<int*, 8>) - 8 * sizeof(int*)); >+} >+ >+TEST(IntVec, Clear) { >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ IntVec v; >+ Fill(&v, len); >+ v.clear(); >+ EXPECT_EQ(0, v.size()); >+ EXPECT_EQ(v.begin(), v.end()); >+ } >+} >+ >+TEST(IntVec, Reserve) { >+ for (int len = 0; len < 20; len++) { >+ IntVec v; >+ Fill(&v, len); >+ >+ for (int newlen = 0; newlen < 100; newlen++) { >+ const int* start_rep = v.data(); >+ v.reserve(newlen); >+ const int* final_rep = v.data(); >+ if (newlen <= len) { >+ EXPECT_EQ(start_rep, final_rep); >+ } >+ EXPECT_LE(newlen, v.capacity()); >+ >+ // Filling up to newlen should not change rep >+ while (v.size() < newlen) { >+ v.push_back(0); >+ } >+ EXPECT_EQ(final_rep, v.data()); >+ } >+ } >+} >+ >+TEST(StringVec, SelfRefPushBack) { >+ std::vector<std::string> std_v; >+ absl::InlinedVector<std::string, 4> v; >+ const std::string s = "A quite long std::string to ensure heap."; >+ std_v.push_back(s); >+ v.push_back(s); >+ for (int i = 0; i < 20; ++i) { >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+ >+ v.push_back(v.back()); >+ std_v.push_back(std_v.back()); >+ } >+ EXPECT_THAT(v, ElementsAreArray(std_v)); >+} >+ >+TEST(StringVec, SelfRefPushBackWithMove) { >+ std::vector<std::string> std_v; >+ absl::InlinedVector<std::string, 4> v; >+ const std::string s = "A quite long std::string to ensure heap."; >+ std_v.push_back(s); >+ v.push_back(s); >+ for (int i = 0; i < 20; ++i) { >+ EXPECT_EQ(v.back(), std_v.back()); >+ >+ v.push_back(std::move(v.back())); >+ std_v.push_back(std::move(std_v.back())); >+ } >+ EXPECT_EQ(v.back(), std_v.back()); >+} >+ >+TEST(StringVec, SelfMove) { >+ const std::string s = "A quite long std::string to ensure heap."; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ absl::InlinedVector<std::string, 8> v; >+ for (int i = 0; i < len; ++i) { >+ SCOPED_TRACE(i); >+ v.push_back(s); >+ } >+ // Indirection necessary to avoid compiler warning. >+ v = std::move(*(&v)); >+ // Ensure that the inlined vector is still in a valid state by copying it. >+ // We don't expect specific contents since a self-move results in an >+ // unspecified valid state. >+ std::vector<std::string> copy(v.begin(), v.end()); >+ } >+} >+ >+TEST(IntVec, Swap) { >+ for (int l1 = 0; l1 < 20; l1++) { >+ SCOPED_TRACE(l1); >+ for (int l2 = 0; l2 < 20; l2++) { >+ SCOPED_TRACE(l2); >+ IntVec a = Fill(l1, 0); >+ IntVec b = Fill(l2, 100); >+ { >+ using std::swap; >+ swap(a, b); >+ } >+ EXPECT_EQ(l1, b.size()); >+ EXPECT_EQ(l2, a.size()); >+ for (int i = 0; i < l1; i++) { >+ SCOPED_TRACE(i); >+ EXPECT_EQ(i, b[i]); >+ } >+ for (int i = 0; i < l2; i++) { >+ SCOPED_TRACE(i); >+ EXPECT_EQ(100 + i, a[i]); >+ } >+ } >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, Swap) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ for (int l1 = 0; l1 < 20; l1++) { >+ SCOPED_TRACE(l1); >+ for (int l2 = 0; l2 < 20; l2++) { >+ SCOPED_TRACE(l2); >+ InstanceTracker tracker; >+ InstanceVec a, b; >+ const size_t inlined_capacity = a.capacity(); >+ for (int i = 0; i < l1; i++) a.push_back(Instance(i)); >+ for (int i = 0; i < l2; i++) b.push_back(Instance(100+i)); >+ EXPECT_EQ(tracker.instances(), l1 + l2); >+ tracker.ResetCopiesMovesSwaps(); >+ { >+ using std::swap; >+ swap(a, b); >+ } >+ EXPECT_EQ(tracker.instances(), l1 + l2); >+ if (a.size() > inlined_capacity && b.size() > inlined_capacity) { >+ EXPECT_EQ(tracker.swaps(), 0); // Allocations are swapped. >+ EXPECT_EQ(tracker.moves(), 0); >+ } else if (a.size() <= inlined_capacity && b.size() <= inlined_capacity) { >+ EXPECT_EQ(tracker.swaps(), std::min(l1, l2)); >+ // TODO(bsamwel): This should use moves when the type is movable. >+ EXPECT_EQ(tracker.copies(), std::max(l1, l2) - std::min(l1, l2)); >+ } else { >+ // One is allocated and the other isn't. The allocation is transferred >+ // without copying elements, and the inlined instances are copied/moved. >+ EXPECT_EQ(tracker.swaps(), 0); >+ // TODO(bsamwel): This should use moves when the type is movable. >+ EXPECT_EQ(tracker.copies(), std::min(l1, l2)); >+ } >+ >+ EXPECT_EQ(l1, b.size()); >+ EXPECT_EQ(l2, a.size()); >+ for (int i = 0; i < l1; i++) { >+ EXPECT_EQ(i, b[i].value()); >+ } >+ for (int i = 0; i < l2; i++) { >+ EXPECT_EQ(100 + i, a[i].value()); >+ } >+ } >+ } >+} >+ >+TEST(IntVec, EqualAndNotEqual) { >+ IntVec a, b; >+ EXPECT_TRUE(a == b); >+ EXPECT_FALSE(a != b); >+ >+ a.push_back(3); >+ EXPECT_FALSE(a == b); >+ EXPECT_TRUE(a != b); >+ >+ b.push_back(3); >+ EXPECT_TRUE(a == b); >+ EXPECT_FALSE(a != b); >+ >+ b.push_back(7); >+ EXPECT_FALSE(a == b); >+ EXPECT_TRUE(a != b); >+ >+ a.push_back(6); >+ EXPECT_FALSE(a == b); >+ EXPECT_TRUE(a != b); >+ >+ a.clear(); >+ b.clear(); >+ for (int i = 0; i < 100; i++) { >+ a.push_back(i); >+ b.push_back(i); >+ EXPECT_TRUE(a == b); >+ EXPECT_FALSE(a != b); >+ >+ b[i] = b[i] + 1; >+ EXPECT_FALSE(a == b); >+ EXPECT_TRUE(a != b); >+ >+ b[i] = b[i] - 1; // Back to before >+ EXPECT_TRUE(a == b); >+ EXPECT_FALSE(a != b); >+ } >+} >+ >+TEST(IntVec, RelationalOps) { >+ IntVec a, b; >+ EXPECT_FALSE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_FALSE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_TRUE(b <= a); >+ EXPECT_TRUE(a >= b); >+ EXPECT_TRUE(b >= a); >+ b.push_back(3); >+ EXPECT_TRUE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_TRUE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_FALSE(b <= a); >+ EXPECT_FALSE(a >= b); >+ EXPECT_TRUE(b >= a); >+} >+ >+TYPED_TEST_P(InstanceTest, CountConstructorsDestructors) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ InstanceTracker tracker; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ InstanceVec v; >+ const size_t inlined_capacity = v.capacity(); >+ for (int i = 0; i < len; i++) { >+ v.push_back(Instance(i)); >+ } >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len); // More due to reallocation. >+ tracker.ResetCopiesMovesSwaps(); >+ >+ // Enlarging resize() must construct some objects >+ tracker.ResetCopiesMovesSwaps(); >+ v.resize(len + 10, Instance(100)); >+ EXPECT_EQ(tracker.instances(), len + 10); >+ if (len <= inlined_capacity && len + 10 > inlined_capacity) { >+ EXPECT_EQ(tracker.copies() + tracker.moves(), 10 + len); >+ } else { >+ // Only specify a minimum number of copies + moves. We don't want to >+ // depend on the reallocation policy here. >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ 10); // More due to reallocation. >+ } >+ >+ // Shrinking resize() must destroy some objects >+ tracker.ResetCopiesMovesSwaps(); >+ v.resize(len, Instance(100)); >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), 0); >+ >+ // reserve() must not increase the number of initialized objects >+ SCOPED_TRACE("reserve"); >+ v.reserve(len+1000); >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_EQ(tracker.copies() + tracker.moves(), len); >+ >+ // pop_back() and erase() must destroy one object >+ if (len > 0) { >+ tracker.ResetCopiesMovesSwaps(); >+ v.pop_back(); >+ EXPECT_EQ(tracker.instances(), len - 1); >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), 0); >+ >+ if (!v.empty()) { >+ tracker.ResetCopiesMovesSwaps(); >+ v.erase(v.begin()); >+ EXPECT_EQ(tracker.instances(), len - 2); >+ EXPECT_EQ(tracker.copies() + tracker.moves(), len - 2); >+ } >+ } >+ >+ tracker.ResetCopiesMovesSwaps(); >+ int instances_before_empty_erase = tracker.instances(); >+ v.erase(v.begin(), v.begin()); >+ EXPECT_EQ(tracker.instances(), instances_before_empty_erase); >+ EXPECT_EQ(tracker.copies() + tracker.moves(), 0); >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnCopyConstruction) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ InstanceTracker tracker; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ InstanceVec v; >+ for (int i = 0; i < len; i++) { >+ v.push_back(Instance(i)); >+ } >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len); // More due to reallocation. >+ tracker.ResetCopiesMovesSwaps(); >+ { // Copy constructor should create 'len' more instances. >+ InstanceVec v_copy(v); >+ EXPECT_EQ(tracker.instances(), len + len); >+ EXPECT_EQ(tracker.copies(), len); >+ EXPECT_EQ(tracker.moves(), 0); >+ } >+ EXPECT_EQ(tracker.instances(), len); >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveConstruction) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ InstanceTracker tracker; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ InstanceVec v; >+ const size_t inlined_capacity = v.capacity(); >+ for (int i = 0; i < len; i++) { >+ v.push_back(Instance(i)); >+ } >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len); // More due to reallocation. >+ tracker.ResetCopiesMovesSwaps(); >+ { >+ InstanceVec v_copy(std::move(v)); >+ if (len > inlined_capacity) { >+ // Allocation is moved as a whole. >+ EXPECT_EQ(tracker.instances(), len); >+ EXPECT_EQ(tracker.live_instances(), len); >+ // Tests an implementation detail, don't rely on this in your code. >+ EXPECT_EQ(v.size(), 0); // NOLINT misc-use-after-move >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), 0); >+ } else { >+ EXPECT_EQ(tracker.instances(), len + len); >+ if (Instance::supports_move()) { >+ EXPECT_EQ(tracker.live_instances(), len); >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), len); >+ } else { >+ EXPECT_EQ(tracker.live_instances(), len + len); >+ EXPECT_EQ(tracker.copies(), len); >+ EXPECT_EQ(tracker.moves(), 0); >+ } >+ } >+ EXPECT_EQ(tracker.swaps(), 0); >+ } >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnAssignment) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ InstanceTracker tracker; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ for (int longorshort = 0; longorshort <= 1; ++longorshort) { >+ SCOPED_TRACE(longorshort); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ InstanceVec longer, shorter; >+ for (int i = 0; i < len; i++) { >+ longer.push_back(Instance(i)); >+ shorter.push_back(Instance(i)); >+ } >+ longer.push_back(Instance(len)); >+ EXPECT_EQ(tracker.instances(), len + len + 1); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len + len + 1); // More due to reallocation. >+ >+ tracker.ResetCopiesMovesSwaps(); >+ if (longorshort) { >+ shorter = longer; >+ EXPECT_EQ(tracker.instances(), (len + 1) + (len + 1)); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len + 1); // More due to reallocation. >+ } else { >+ longer = shorter; >+ EXPECT_EQ(tracker.instances(), len + len); >+ EXPECT_EQ(tracker.copies() + tracker.moves(), len); >+ } >+ } >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, CountConstructorsDestructorsOnMoveAssignment) { >+ using Instance = TypeParam; >+ using InstanceVec = absl::InlinedVector<Instance, 8>; >+ InstanceTracker tracker; >+ for (int len = 0; len < 20; len++) { >+ SCOPED_TRACE(len); >+ for (int longorshort = 0; longorshort <= 1; ++longorshort) { >+ SCOPED_TRACE(longorshort); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ InstanceVec longer, shorter; >+ const int inlined_capacity = longer.capacity(); >+ for (int i = 0; i < len; i++) { >+ longer.push_back(Instance(i)); >+ shorter.push_back(Instance(i)); >+ } >+ longer.push_back(Instance(len)); >+ EXPECT_EQ(tracker.instances(), len + len + 1); >+ EXPECT_GE(tracker.copies() + tracker.moves(), >+ len + len + 1); // More due to reallocation. >+ >+ tracker.ResetCopiesMovesSwaps(); >+ int src_len; >+ if (longorshort) { >+ src_len = len + 1; >+ shorter = std::move(longer); >+ } else { >+ src_len = len; >+ longer = std::move(shorter); >+ } >+ if (src_len > inlined_capacity) { >+ // Allocation moved as a whole. >+ EXPECT_EQ(tracker.instances(), src_len); >+ EXPECT_EQ(tracker.live_instances(), src_len); >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), 0); >+ } else { >+ // Elements are all copied. >+ EXPECT_EQ(tracker.instances(), src_len + src_len); >+ if (Instance::supports_move()) { >+ EXPECT_EQ(tracker.copies(), 0); >+ EXPECT_EQ(tracker.moves(), src_len); >+ EXPECT_EQ(tracker.live_instances(), src_len); >+ } else { >+ EXPECT_EQ(tracker.copies(), src_len); >+ EXPECT_EQ(tracker.moves(), 0); >+ EXPECT_EQ(tracker.live_instances(), src_len + src_len); >+ } >+ } >+ EXPECT_EQ(tracker.swaps(), 0); >+ } >+ } >+} >+ >+TEST(CountElemAssign, SimpleTypeWithInlineBacking) { >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<int> original_contents(original_size, 12345); >+ >+ absl::InlinedVector<int, 2> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(2, 123); >+ EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(123, 123))); >+ if (original_size <= 2) { >+ // If the original had inline backing, it should stay inline. >+ EXPECT_EQ(2, v.capacity()); >+ } >+ } >+} >+ >+TEST(CountElemAssign, SimpleTypeWithAllocation) { >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<int> original_contents(original_size, 12345); >+ >+ absl::InlinedVector<int, 2> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(3, 123); >+ EXPECT_THAT(v, AllOf(SizeIs(3), ElementsAre(123, 123, 123))); >+ EXPECT_LE(v.size(), v.capacity()); >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, CountElemAssignInlineBacking) { >+ using Instance = TypeParam; >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<Instance> original_contents(original_size, Instance(12345)); >+ >+ absl::InlinedVector<Instance, 2> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(2, Instance(123)); >+ EXPECT_THAT(v, AllOf(SizeIs(2), ElementsAre(ValueIs(123), ValueIs(123)))); >+ if (original_size <= 2) { >+ // If the original had inline backing, it should stay inline. >+ EXPECT_EQ(2, v.capacity()); >+ } >+ } >+} >+ >+template <typename Instance> >+void InstanceCountElemAssignWithAllocationTest() { >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<Instance> original_contents(original_size, Instance(12345)); >+ >+ absl::InlinedVector<Instance, 2> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(3, Instance(123)); >+ EXPECT_THAT(v, >+ AllOf(SizeIs(3), >+ ElementsAre(ValueIs(123), ValueIs(123), ValueIs(123)))); >+ EXPECT_LE(v.size(), v.capacity()); >+ } >+} >+TEST(CountElemAssign, WithAllocationCopyableInstance) { >+ InstanceCountElemAssignWithAllocationTest<CopyableOnlyInstance>(); >+} >+TEST(CountElemAssign, WithAllocationCopyableMovableInstance) { >+ InstanceCountElemAssignWithAllocationTest<CopyableMovableInstance>(); >+} >+ >+TEST(RangedConstructor, SimpleType) { >+ std::vector<int> source_v = {4, 5, 6}; >+ // First try to fit in inline backing >+ absl::InlinedVector<int, 4> v(source_v.begin(), source_v.end()); >+ EXPECT_EQ(3, v.size()); >+ EXPECT_EQ(4, v.capacity()); // Indication that we're still on inlined storage >+ EXPECT_EQ(4, v[0]); >+ EXPECT_EQ(5, v[1]); >+ EXPECT_EQ(6, v[2]); >+ >+ // Now, force a re-allocate >+ absl::InlinedVector<int, 2> realloc_v(source_v.begin(), source_v.end()); >+ EXPECT_EQ(3, realloc_v.size()); >+ EXPECT_LT(2, realloc_v.capacity()); >+ EXPECT_EQ(4, realloc_v[0]); >+ EXPECT_EQ(5, realloc_v[1]); >+ EXPECT_EQ(6, realloc_v[2]); >+} >+ >+// Test for ranged constructors using Instance as the element type and >+// SourceContainer as the source container type. >+template <typename Instance, typename SourceContainer, int inlined_capacity> >+void InstanceRangedConstructorTestForContainer() { >+ InstanceTracker tracker; >+ SourceContainer source_v = {Instance(0), Instance(1)}; >+ tracker.ResetCopiesMovesSwaps(); >+ absl::InlinedVector<Instance, inlined_capacity> v(source_v.begin(), >+ source_v.end()); >+ EXPECT_EQ(2, v.size()); >+ EXPECT_LT(1, v.capacity()); >+ EXPECT_EQ(0, v[0].value()); >+ EXPECT_EQ(1, v[1].value()); >+ EXPECT_EQ(tracker.copies(), 2); >+ EXPECT_EQ(tracker.moves(), 0); >+} >+ >+template <typename Instance, int inlined_capacity> >+void InstanceRangedConstructorTestWithCapacity() { >+ // Test with const and non-const, random access and non-random-access sources. >+ // TODO(bsamwel): Test with an input iterator source. >+ { >+ SCOPED_TRACE("std::list"); >+ InstanceRangedConstructorTestForContainer<Instance, std::list<Instance>, >+ inlined_capacity>(); >+ { >+ SCOPED_TRACE("const std::list"); >+ InstanceRangedConstructorTestForContainer< >+ Instance, const std::list<Instance>, inlined_capacity>(); >+ } >+ { >+ SCOPED_TRACE("std::vector"); >+ InstanceRangedConstructorTestForContainer<Instance, std::vector<Instance>, >+ inlined_capacity>(); >+ } >+ { >+ SCOPED_TRACE("const std::vector"); >+ InstanceRangedConstructorTestForContainer< >+ Instance, const std::vector<Instance>, inlined_capacity>(); >+ } >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, RangedConstructor) { >+ using Instance = TypeParam; >+ SCOPED_TRACE("capacity=1"); >+ InstanceRangedConstructorTestWithCapacity<Instance, 1>(); >+ SCOPED_TRACE("capacity=2"); >+ InstanceRangedConstructorTestWithCapacity<Instance, 2>(); >+} >+ >+TEST(RangedConstructor, ElementsAreConstructed) { >+ std::vector<std::string> source_v = {"cat", "dog"}; >+ >+ // Force expansion and re-allocation of v. Ensures that when the vector is >+ // expanded that new elements are constructed. >+ absl::InlinedVector<std::string, 1> v(source_v.begin(), source_v.end()); >+ EXPECT_EQ("cat", v[0]); >+ EXPECT_EQ("dog", v[1]); >+} >+ >+TEST(RangedAssign, SimpleType) { >+ // Test for all combinations of original sizes (empty and non-empty inline, >+ // and out of line) and target sizes. >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<int> original_contents(original_size, 12345); >+ >+ for (size_t target_size = 0; target_size <= 5; ++target_size) { >+ SCOPED_TRACE(target_size); >+ >+ // New contents are [3, 4, ...] >+ std::vector<int> new_contents; >+ for (size_t i = 0; i < target_size; ++i) { >+ new_contents.push_back(i + 3); >+ } >+ >+ absl::InlinedVector<int, 3> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(new_contents.begin(), new_contents.end()); >+ >+ EXPECT_EQ(new_contents.size(), v.size()); >+ EXPECT_LE(new_contents.size(), v.capacity()); >+ if (target_size <= 3 && original_size <= 3) { >+ // Storage should stay inline when target size is small. >+ EXPECT_EQ(3, v.capacity()); >+ } >+ EXPECT_THAT(v, ElementsAreArray(new_contents)); >+ } >+ } >+} >+ >+// Returns true if lhs and rhs have the same value. >+template <typename Instance> >+static bool InstanceValuesEqual(const Instance& lhs, const Instance& rhs) { >+ return lhs.value() == rhs.value(); >+} >+ >+// Test for ranged assign() using Instance as the element type and >+// SourceContainer as the source container type. >+template <typename Instance, typename SourceContainer> >+void InstanceRangedAssignTestForContainer() { >+ // Test for all combinations of original sizes (empty and non-empty inline, >+ // and out of line) and target sizes. >+ for (size_t original_size = 0; original_size <= 5; ++original_size) { >+ SCOPED_TRACE(original_size); >+ // Original contents are [12345, 12345, ...] >+ std::vector<Instance> original_contents(original_size, Instance(12345)); >+ >+ for (size_t target_size = 0; target_size <= 5; ++target_size) { >+ SCOPED_TRACE(target_size); >+ >+ // New contents are [3, 4, ...] >+ // Generate data using a non-const container, because SourceContainer >+ // itself may be const. >+ // TODO(bsamwel): Test with an input iterator. >+ std::vector<Instance> new_contents_in; >+ for (size_t i = 0; i < target_size; ++i) { >+ new_contents_in.push_back(Instance(i + 3)); >+ } >+ SourceContainer new_contents(new_contents_in.begin(), >+ new_contents_in.end()); >+ >+ absl::InlinedVector<Instance, 3> v(original_contents.begin(), >+ original_contents.end()); >+ v.assign(new_contents.begin(), new_contents.end()); >+ >+ EXPECT_EQ(new_contents.size(), v.size()); >+ EXPECT_LE(new_contents.size(), v.capacity()); >+ if (target_size <= 3 && original_size <= 3) { >+ // Storage should stay inline when target size is small. >+ EXPECT_EQ(3, v.capacity()); >+ } >+ EXPECT_TRUE(std::equal(v.begin(), v.end(), new_contents.begin(), >+ InstanceValuesEqual<Instance>)); >+ } >+ } >+} >+ >+TYPED_TEST_P(InstanceTest, RangedAssign) { >+ using Instance = TypeParam; >+ // Test with const and non-const, random access and non-random-access sources. >+ // TODO(bsamwel): Test with an input iterator source. >+ SCOPED_TRACE("std::list"); >+ InstanceRangedAssignTestForContainer<Instance, std::list<Instance>>(); >+ SCOPED_TRACE("const std::list"); >+ InstanceRangedAssignTestForContainer<Instance, const std::list<Instance>>(); >+ SCOPED_TRACE("std::vector"); >+ InstanceRangedAssignTestForContainer<Instance, std::vector<Instance>>(); >+ SCOPED_TRACE("const std::vector"); >+ InstanceRangedAssignTestForContainer<Instance, const std::vector<Instance>>(); >+} >+ >+TEST(InitializerListConstructor, SimpleTypeWithInlineBacking) { >+ EXPECT_THAT((absl::InlinedVector<int, 4>{4, 5, 6}), >+ AllOf(SizeIs(3), CapacityIs(4), ElementsAre(4, 5, 6))); >+} >+ >+TEST(InitializerListConstructor, SimpleTypeWithReallocationRequired) { >+ EXPECT_THAT((absl::InlinedVector<int, 2>{4, 5, 6}), >+ AllOf(SizeIs(3), CapacityIs(Gt(2)), ElementsAre(4, 5, 6))); >+} >+ >+TEST(InitializerListConstructor, DisparateTypesInList) { >+ EXPECT_THAT((absl::InlinedVector<int, 2>{-7, 8ULL}), ElementsAre(-7, 8)); >+ >+ EXPECT_THAT((absl::InlinedVector<std::string, 2>{"foo", std::string("bar")}), >+ ElementsAre("foo", "bar")); >+} >+ >+TEST(InitializerListConstructor, ComplexTypeWithInlineBacking) { >+ EXPECT_THAT((absl::InlinedVector<CopyableMovableInstance, 1>{ >+ CopyableMovableInstance(0)}), >+ AllOf(SizeIs(1), CapacityIs(1), ElementsAre(ValueIs(0)))); >+} >+ >+TEST(InitializerListConstructor, ComplexTypeWithReallocationRequired) { >+ EXPECT_THAT( >+ (absl::InlinedVector<CopyableMovableInstance, 1>{ >+ CopyableMovableInstance(0), CopyableMovableInstance(1)}), >+ AllOf(SizeIs(2), CapacityIs(Gt(1)), ElementsAre(ValueIs(0), ValueIs(1)))); >+} >+ >+TEST(InitializerListAssign, SimpleTypeFitsInlineBacking) { >+ for (size_t original_size = 0; original_size <= 4; ++original_size) { >+ SCOPED_TRACE(original_size); >+ >+ absl::InlinedVector<int, 2> v1(original_size, 12345); >+ const size_t original_capacity_v1 = v1.capacity(); >+ v1.assign({3}); >+ EXPECT_THAT( >+ v1, AllOf(SizeIs(1), CapacityIs(original_capacity_v1), ElementsAre(3))); >+ >+ absl::InlinedVector<int, 2> v2(original_size, 12345); >+ const size_t original_capacity_v2 = v2.capacity(); >+ v2 = {3}; >+ EXPECT_THAT( >+ v2, AllOf(SizeIs(1), CapacityIs(original_capacity_v2), ElementsAre(3))); >+ } >+} >+ >+TEST(InitializerListAssign, SimpleTypeDoesNotFitInlineBacking) { >+ for (size_t original_size = 0; original_size <= 4; ++original_size) { >+ SCOPED_TRACE(original_size); >+ absl::InlinedVector<int, 2> v1(original_size, 12345); >+ v1.assign({3, 4, 5}); >+ EXPECT_THAT(v1, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); >+ EXPECT_LE(3, v1.capacity()); >+ >+ absl::InlinedVector<int, 2> v2(original_size, 12345); >+ v2 = {3, 4, 5}; >+ EXPECT_THAT(v2, AllOf(SizeIs(3), ElementsAre(3, 4, 5))); >+ EXPECT_LE(3, v2.capacity()); >+ } >+} >+ >+TEST(InitializerListAssign, DisparateTypesInList) { >+ absl::InlinedVector<int, 2> v_int1; >+ v_int1.assign({-7, 8ULL}); >+ EXPECT_THAT(v_int1, ElementsAre(-7, 8)); >+ >+ absl::InlinedVector<int, 2> v_int2; >+ v_int2 = {-7, 8ULL}; >+ EXPECT_THAT(v_int2, ElementsAre(-7, 8)); >+ >+ absl::InlinedVector<std::string, 2> v_string1; >+ v_string1.assign({"foo", std::string("bar")}); >+ EXPECT_THAT(v_string1, ElementsAre("foo", "bar")); >+ >+ absl::InlinedVector<std::string, 2> v_string2; >+ v_string2 = {"foo", std::string("bar")}; >+ EXPECT_THAT(v_string2, ElementsAre("foo", "bar")); >+} >+ >+TYPED_TEST_P(InstanceTest, InitializerListAssign) { >+ using Instance = TypeParam; >+ for (size_t original_size = 0; original_size <= 4; ++original_size) { >+ SCOPED_TRACE(original_size); >+ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); >+ const size_t original_capacity = v.capacity(); >+ v.assign({Instance(3)}); >+ EXPECT_THAT(v, AllOf(SizeIs(1), CapacityIs(original_capacity), >+ ElementsAre(ValueIs(3)))); >+ } >+ for (size_t original_size = 0; original_size <= 4; ++original_size) { >+ SCOPED_TRACE(original_size); >+ absl::InlinedVector<Instance, 2> v(original_size, Instance(12345)); >+ v.assign({Instance(3), Instance(4), Instance(5)}); >+ EXPECT_THAT(v, AllOf(SizeIs(3), >+ ElementsAre(ValueIs(3), ValueIs(4), ValueIs(5)))); >+ EXPECT_LE(3, v.capacity()); >+ } >+} >+ >+REGISTER_TYPED_TEST_CASE_P(InstanceTest, Swap, CountConstructorsDestructors, >+ CountConstructorsDestructorsOnCopyConstruction, >+ CountConstructorsDestructorsOnMoveConstruction, >+ CountConstructorsDestructorsOnAssignment, >+ CountConstructorsDestructorsOnMoveAssignment, >+ CountElemAssignInlineBacking, RangedConstructor, >+ RangedAssign, InitializerListAssign); >+ >+using InstanceTypes = >+ ::testing::Types<CopyableOnlyInstance, CopyableMovableInstance>; >+INSTANTIATE_TYPED_TEST_CASE_P(InstanceTestOnTypes, InstanceTest, InstanceTypes); >+ >+TEST(DynamicVec, DynamicVecCompiles) { >+ DynamicVec v; >+ (void)v; >+} >+ >+TEST(AllocatorSupportTest, Constructors) { >+ using MyAlloc = CountingAllocator<int>; >+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>; >+ const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; >+ int64_t allocated = 0; >+ MyAlloc alloc(&allocated); >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v; } >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(alloc); } >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); } >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v({1, 2, 3}, alloc); } >+ >+ AllocVec v2; >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(v2, alloc); } >+ { AllocVec ABSL_ATTRIBUTE_UNUSED v(std::move(v2), alloc); } >+} >+ >+TEST(AllocatorSupportTest, CountAllocations) { >+ using MyAlloc = CountingAllocator<int>; >+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>; >+ const int ia[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; >+ int64_t allocated = 0; >+ MyAlloc alloc(&allocated); >+ { >+ AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + 4, alloc); >+ EXPECT_THAT(allocated, 0); >+ } >+ EXPECT_THAT(allocated, 0); >+ { >+ AllocVec ABSL_ATTRIBUTE_UNUSED v(ia, ia + ABSL_ARRAYSIZE(ia), alloc); >+ EXPECT_THAT(allocated, v.size() * sizeof(int)); >+ } >+ EXPECT_THAT(allocated, 0); >+ { >+ AllocVec v(4, 1, alloc); >+ EXPECT_THAT(allocated, 0); >+ >+ int64_t allocated2 = 0; >+ MyAlloc alloc2(&allocated2); >+ AllocVec v2(v, alloc2); >+ EXPECT_THAT(allocated2, 0); >+ >+ int64_t allocated3 = 0; >+ MyAlloc alloc3(&allocated3); >+ AllocVec v3(std::move(v), alloc3); >+ EXPECT_THAT(allocated3, 0); >+ } >+ EXPECT_THAT(allocated, 0); >+ { >+ AllocVec v(8, 2, alloc); >+ EXPECT_THAT(allocated, v.size() * sizeof(int)); >+ >+ int64_t allocated2 = 0; >+ MyAlloc alloc2(&allocated2); >+ AllocVec v2(v, alloc2); >+ EXPECT_THAT(allocated2, v2.size() * sizeof(int)); >+ >+ int64_t allocated3 = 0; >+ MyAlloc alloc3(&allocated3); >+ AllocVec v3(std::move(v), alloc3); >+ EXPECT_THAT(allocated3, v3.size() * sizeof(int)); >+ } >+ EXPECT_EQ(allocated, 0); >+ { >+ // Test shrink_to_fit deallocations. >+ AllocVec v(8, 2, alloc); >+ EXPECT_EQ(allocated, 8 * sizeof(int)); >+ v.resize(5); >+ EXPECT_EQ(allocated, 8 * sizeof(int)); >+ v.shrink_to_fit(); >+ EXPECT_EQ(allocated, 5 * sizeof(int)); >+ v.resize(4); >+ EXPECT_EQ(allocated, 5 * sizeof(int)); >+ v.shrink_to_fit(); >+ EXPECT_EQ(allocated, 0); >+ } >+} >+ >+TEST(AllocatorSupportTest, SwapBothAllocated) { >+ using MyAlloc = CountingAllocator<int>; >+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>; >+ int64_t allocated1 = 0; >+ int64_t allocated2 = 0; >+ { >+ const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; >+ const int ia2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; >+ MyAlloc a1(&allocated1); >+ MyAlloc a2(&allocated2); >+ AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); >+ AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); >+ EXPECT_LT(v1.capacity(), v2.capacity()); >+ EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); >+ EXPECT_THAT(allocated2, v2.capacity() * sizeof(int)); >+ v1.swap(v2); >+ EXPECT_THAT(v1, ElementsAreArray(ia2)); >+ EXPECT_THAT(v2, ElementsAreArray(ia1)); >+ EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); >+ EXPECT_THAT(allocated2, v1.capacity() * sizeof(int)); >+ } >+ EXPECT_THAT(allocated1, 0); >+ EXPECT_THAT(allocated2, 0); >+} >+ >+TEST(AllocatorSupportTest, SwapOneAllocated) { >+ using MyAlloc = CountingAllocator<int>; >+ using AllocVec = absl::InlinedVector<int, 4, MyAlloc>; >+ int64_t allocated1 = 0; >+ int64_t allocated2 = 0; >+ { >+ const int ia1[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; >+ const int ia2[] = { 0, 1, 2, 3 }; >+ MyAlloc a1(&allocated1); >+ MyAlloc a2(&allocated2); >+ AllocVec v1(ia1, ia1 + ABSL_ARRAYSIZE(ia1), a1); >+ AllocVec v2(ia2, ia2 + ABSL_ARRAYSIZE(ia2), a2); >+ EXPECT_THAT(allocated1, v1.capacity() * sizeof(int)); >+ EXPECT_THAT(allocated2, 0); >+ v1.swap(v2); >+ EXPECT_THAT(v1, ElementsAreArray(ia2)); >+ EXPECT_THAT(v2, ElementsAreArray(ia1)); >+ EXPECT_THAT(allocated1, v2.capacity() * sizeof(int)); >+ EXPECT_THAT(allocated2, 0); >+ EXPECT_TRUE(v2.get_allocator() == a1); >+ EXPECT_TRUE(v1.get_allocator() == a2); >+ } >+ EXPECT_THAT(allocated1, 0); >+ EXPECT_THAT(allocated2, 0); >+} >+ >+TEST(AllocatorSupportTest, ScopedAllocatorWorks) { >+ using StdVector = std::vector<int, CountingAllocator<int>>; >+ using MyAlloc = >+ std::scoped_allocator_adaptor<CountingAllocator<StdVector>>; >+ using AllocVec = absl::InlinedVector<StdVector, 4, MyAlloc>; >+ >+ int64_t allocated = 0; >+ AllocVec vec(MyAlloc{CountingAllocator<StdVector>{&allocated}}); >+ EXPECT_EQ(allocated, 0); >+ >+ // This default constructs a vector<int>, but the allocator should pass itself >+ // into the vector<int>. >+ // The absl::InlinedVector does not allocate any memory. >+ // The vector<int> does not allocate any memory. >+ vec.resize(1); >+ EXPECT_EQ(allocated, 0); >+ >+ // We make vector<int> allocate memory. >+ // It must go through the allocator even though we didn't construct the >+ // vector directly. >+ vec[0].push_back(1); >+ EXPECT_EQ(allocated, sizeof(int) * 1); >+ >+ // Another allocating vector. >+ vec.push_back(vec[0]); >+ EXPECT_EQ(allocated, sizeof(int) * 2); >+ >+ // Overflow the inlined memory. >+ // The absl::InlinedVector will now allocate. >+ vec.resize(5); >+ EXPECT_EQ(allocated, sizeof(int) * 2 + sizeof(StdVector) * 8); >+ >+ // Adding one more in external mode should also work. >+ vec.push_back(vec[0]); >+ EXPECT_EQ(allocated, sizeof(int) * 3 + sizeof(StdVector) * 8); >+ >+ // And extending these should still work. >+ vec[0].push_back(1); >+ EXPECT_EQ(allocated, sizeof(int) * 4 + sizeof(StdVector) * 8); >+ >+ vec.clear(); >+ EXPECT_EQ(allocated, 0); >+} >+ >+TEST(AllocatorSupportTest, SizeAllocConstructor) { >+ constexpr int inlined_size = 4; >+ using Alloc = CountingAllocator<int>; >+ using AllocVec = absl::InlinedVector<int, inlined_size, Alloc>; >+ >+ { >+ auto len = inlined_size / 2; >+ int64_t allocated = 0; >+ auto v = AllocVec(len, Alloc(&allocated)); >+ >+ // Inline storage used; allocator should not be invoked >+ EXPECT_THAT(allocated, 0); >+ EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); >+ } >+ >+ { >+ auto len = inlined_size * 2; >+ int64_t allocated = 0; >+ auto v = AllocVec(len, Alloc(&allocated)); >+ >+ // Out of line storage used; allocation of 8 elements expected >+ EXPECT_THAT(allocated, len * sizeof(int)); >+ EXPECT_THAT(v, AllOf(SizeIs(len), Each(0))); >+ } >+} >+} // anonymous namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h >new file mode 100644 >index 00000000000..cc52614f5b3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple.h >@@ -0,0 +1,175 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Helper class to perform the Empty Base Optimization. >+// Ts can contain classes and non-classes, empty or not. For the ones that >+// are empty classes, we perform the optimization. If all types in Ts are empty >+// classes, then CompressedTuple<Ts...> is itself an empty class. >+// >+// To access the members, use member get<N>() function. >+// >+// Eg: >+// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2, >+// t3); >+// assert(value.get<0>() == 7); >+// T1& t1 = value.get<1>(); >+// const T2& t2 = value.get<2>(); >+// ... >+// >+// http://en.cppreference.com/w/cpp/language/ebo >+ >+#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ >+#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ >+ >+#include <tuple> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/utility/utility.h" >+ >+#ifdef _MSC_VER >+// We need to mark these classes with this declspec to ensure that >+// CompressedTuple happens. >+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases) >+#else // _MSC_VER >+#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC >+#endif // _MSC_VER >+ >+namespace absl { >+namespace container_internal { >+ >+template <typename... Ts> >+class CompressedTuple; >+ >+namespace internal_compressed_tuple { >+ >+template <typename D, size_t I> >+struct Elem; >+template <typename... B, size_t I> >+struct Elem<CompressedTuple<B...>, I> >+ : std::tuple_element<I, std::tuple<B...>> {}; >+template <typename D, size_t I> >+using ElemT = typename Elem<D, I>::type; >+ >+// Use the __is_final intrinsic if available. Where it's not available, classes >+// declared with the 'final' specifier cannot be used as CompressedTuple >+// elements. >+// TODO(sbenza): Replace this with std::is_final in C++14. >+template <typename T> >+constexpr bool IsFinal() { >+#if defined(__clang__) || defined(__GNUC__) >+ return __is_final(T); >+#else >+ return false; >+#endif >+} >+ >+template <typename T> >+constexpr bool ShouldUseBase() { >+ return std::is_class<T>::value && std::is_empty<T>::value && !IsFinal<T>(); >+} >+ >+// The storage class provides two specializations: >+// - For empty classes, it stores T as a base class. >+// - For everything else, it stores T as a member. >+template <typename D, size_t I, bool = ShouldUseBase<ElemT<D, I>>()> >+struct Storage { >+ using T = ElemT<D, I>; >+ T value; >+ constexpr Storage() = default; >+ explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {} >+ constexpr const T& get() const { return value; } >+ T& get() { return value; } >+}; >+ >+template <typename D, size_t I> >+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true> >+ : ElemT<D, I> { >+ using T = internal_compressed_tuple::ElemT<D, I>; >+ constexpr Storage() = default; >+ explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {} >+ constexpr const T& get() const { return *this; } >+ T& get() { return *this; } >+}; >+ >+template <typename D, typename I> >+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl; >+ >+template <typename... Ts, size_t... I> >+struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC >+ CompressedTupleImpl<CompressedTuple<Ts...>, absl::index_sequence<I...>> >+ // We use the dummy identity function through std::integral_constant to >+ // convince MSVC of accepting and expanding I in that context. Without it >+ // you would get: >+ // error C3548: 'I': parameter pack cannot be used in this context >+ : Storage<CompressedTuple<Ts...>, >+ std::integral_constant<size_t, I>::value>... { >+ constexpr CompressedTupleImpl() = default; >+ explicit constexpr CompressedTupleImpl(Ts&&... args) >+ : Storage<CompressedTuple<Ts...>, I>(absl::forward<Ts>(args))... {} >+}; >+ >+} // namespace internal_compressed_tuple >+ >+// Helper class to perform the Empty Base Class Optimization. >+// Ts can contain classes and non-classes, empty or not. For the ones that >+// are empty classes, we perform the CompressedTuple. If all types in Ts are >+// empty classes, then CompressedTuple<Ts...> is itself an empty class. >+// >+// To access the members, use member .get<N>() function. >+// >+// Eg: >+// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2, >+// t3); >+// assert(value.get<0>() == 7); >+// T1& t1 = value.get<1>(); >+// const T2& t2 = value.get<2>(); >+// ... >+// >+// http://en.cppreference.com/w/cpp/language/ebo >+template <typename... Ts> >+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple >+ : private internal_compressed_tuple::CompressedTupleImpl< >+ CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>> { >+ private: >+ template <int I> >+ using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>; >+ >+ public: >+ constexpr CompressedTuple() = default; >+ explicit constexpr CompressedTuple(Ts... base) >+ : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {} >+ >+ template <int I> >+ ElemT<I>& get() { >+ return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); >+ } >+ >+ template <int I> >+ constexpr const ElemT<I>& get() const { >+ return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); >+ } >+}; >+ >+// Explicit specialization for a zero-element tuple >+// (needed to avoid ambiguous overloads for the default constructor). >+template <> >+class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {}; >+ >+} // namespace container_internal >+} // namespace absl >+ >+#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC >+ >+#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc >new file mode 100644 >index 00000000000..45030c675ee >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/compressed_tuple_test.cc >@@ -0,0 +1,166 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/internal/compressed_tuple.h" >+ >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace container_internal { >+namespace { >+ >+template <int> >+struct Empty {}; >+ >+template <typename T> >+struct NotEmpty { >+ T value; >+}; >+ >+template <typename T, typename U> >+struct TwoValues { >+ T value1; >+ U value2; >+}; >+ >+TEST(CompressedTupleTest, Sizeof) { >+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int>)); >+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>>)); >+ EXPECT_EQ(sizeof(int), sizeof(CompressedTuple<int, Empty<0>, Empty<1>>)); >+ EXPECT_EQ(sizeof(int), >+ sizeof(CompressedTuple<int, Empty<0>, Empty<1>, Empty<2>>)); >+ >+ EXPECT_EQ(sizeof(TwoValues<int, double>), >+ sizeof(CompressedTuple<int, NotEmpty<double>>)); >+ EXPECT_EQ(sizeof(TwoValues<int, double>), >+ sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>>)); >+ EXPECT_EQ(sizeof(TwoValues<int, double>), >+ sizeof(CompressedTuple<int, Empty<0>, NotEmpty<double>, Empty<1>>)); >+} >+ >+TEST(CompressedTupleTest, Access) { >+ struct S { >+ std::string x; >+ }; >+ CompressedTuple<int, Empty<0>, S> x(7, {}, S{"ABC"}); >+ EXPECT_EQ(sizeof(x), sizeof(TwoValues<int, S>)); >+ EXPECT_EQ(7, x.get<0>()); >+ EXPECT_EQ("ABC", x.get<2>().x); >+} >+ >+TEST(CompressedTupleTest, NonClasses) { >+ CompressedTuple<int, const char*> x(7, "ABC"); >+ EXPECT_EQ(7, x.get<0>()); >+ EXPECT_STREQ("ABC", x.get<1>()); >+} >+ >+TEST(CompressedTupleTest, MixClassAndNonClass) { >+ CompressedTuple<int, const char*, Empty<0>, NotEmpty<double>> x(7, "ABC", {}, >+ {1.25}); >+ struct Mock { >+ int v; >+ const char* p; >+ double d; >+ }; >+ EXPECT_EQ(sizeof(x), sizeof(Mock)); >+ EXPECT_EQ(7, x.get<0>()); >+ EXPECT_STREQ("ABC", x.get<1>()); >+ EXPECT_EQ(1.25, x.get<3>().value); >+} >+ >+TEST(CompressedTupleTest, Nested) { >+ CompressedTuple<int, CompressedTuple<int>, >+ CompressedTuple<int, CompressedTuple<int>>> >+ x(1, CompressedTuple<int>(2), >+ CompressedTuple<int, CompressedTuple<int>>(3, CompressedTuple<int>(4))); >+ EXPECT_EQ(1, x.get<0>()); >+ EXPECT_EQ(2, x.get<1>().get<0>()); >+ EXPECT_EQ(3, x.get<2>().get<0>()); >+ EXPECT_EQ(4, x.get<2>().get<1>().get<0>()); >+ >+ CompressedTuple<Empty<0>, Empty<0>, >+ CompressedTuple<Empty<0>, CompressedTuple<Empty<0>>>> >+ y; >+ std::set<Empty<0>*> empties{&y.get<0>(), &y.get<1>(), &y.get<2>().get<0>(), >+ &y.get<2>().get<1>().get<0>()}; >+#ifdef _MSC_VER >+ // MSVC has a bug where many instances of the same base class are layed out in >+ // the same address when using __declspec(empty_bases). >+ // This will be fixed in a future version of MSVC. >+ int expected = 1; >+#else >+ int expected = 4; >+#endif >+ EXPECT_EQ(expected, sizeof(y)); >+ EXPECT_EQ(expected, empties.size()); >+ EXPECT_EQ(sizeof(y), sizeof(Empty<0>) * empties.size()); >+ >+ EXPECT_EQ(4 * sizeof(char), >+ sizeof(CompressedTuple<CompressedTuple<char, char>, >+ CompressedTuple<char, char>>)); >+ EXPECT_TRUE( >+ (std::is_empty<CompressedTuple<CompressedTuple<Empty<0>>, >+ CompressedTuple<Empty<1>>>>::value)); >+} >+ >+TEST(CompressedTupleTest, Reference) { >+ int i = 7; >+ std::string s = "Very long std::string that goes in the heap"; >+ CompressedTuple<int, int&, std::string, std::string&> x(i, i, s, s); >+ >+ // Sanity check. We should have not moved from `s` >+ EXPECT_EQ(s, "Very long std::string that goes in the heap"); >+ >+ EXPECT_EQ(x.get<0>(), x.get<1>()); >+ EXPECT_NE(&x.get<0>(), &x.get<1>()); >+ EXPECT_EQ(&x.get<1>(), &i); >+ >+ EXPECT_EQ(x.get<2>(), x.get<3>()); >+ EXPECT_NE(&x.get<2>(), &x.get<3>()); >+ EXPECT_EQ(&x.get<3>(), &s); >+} >+ >+TEST(CompressedTupleTest, NoElements) { >+ CompressedTuple<> x; >+ static_cast<void>(x); // Silence -Wunused-variable. >+ EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value); >+} >+ >+TEST(CompressedTupleTest, Constexpr) { >+ constexpr CompressedTuple<int, double, CompressedTuple<int>> x( >+ 7, 1.25, CompressedTuple<int>(5)); >+ constexpr int x0 = x.get<0>(); >+ constexpr double x1 = x.get<1>(); >+ constexpr int x2 = x.get<2>().get<0>(); >+ EXPECT_EQ(x0, 7); >+ EXPECT_EQ(x1, 1.25); >+ EXPECT_EQ(x2, 5); >+} >+ >+#if defined(__clang__) || defined(__GNUC__) >+TEST(CompressedTupleTest, EmptyFinalClass) { >+ struct S final { >+ int f() const { return 5; } >+ }; >+ CompressedTuple<S> x; >+ EXPECT_EQ(x.get<0>().f(), 5); >+} >+#endif >+ >+} // namespace >+} // namespace container_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.cc >new file mode 100644 >index 00000000000..fe00aca8fb9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.cc >@@ -0,0 +1,26 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/internal/test_instance_tracker.h" >+ >+namespace absl { >+namespace test_internal { >+int BaseCountedInstance::num_instances_ = 0; >+int BaseCountedInstance::num_live_instances_ = 0; >+int BaseCountedInstance::num_moves_ = 0; >+int BaseCountedInstance::num_copies_ = 0; >+int BaseCountedInstance::num_swaps_ = 0; >+ >+} // namespace test_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.h >new file mode 100644 >index 00000000000..cf8f3a531e6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker.h >@@ -0,0 +1,220 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_ >+#define ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_ >+ >+#include <cstdlib> >+#include <ostream> >+ >+namespace absl { >+namespace test_internal { >+ >+// A type that counts number of occurences of the type, the live occurrences of >+// the type, as well as the number of copies, moves, and swaps that have >+// occurred on the type. This is used as a base class for the copyable, >+// copyable+movable, and movable types below that are used in actual tests. Use >+// InstanceTracker in tests to track the number of instances. >+class BaseCountedInstance { >+ public: >+ explicit BaseCountedInstance(int x) : value_(x) { >+ ++num_instances_; >+ ++num_live_instances_; >+ } >+ BaseCountedInstance(const BaseCountedInstance& x) >+ : value_(x.value_), is_live_(x.is_live_) { >+ ++num_instances_; >+ if (is_live_) ++num_live_instances_; >+ ++num_copies_; >+ } >+ BaseCountedInstance(BaseCountedInstance&& x) >+ : value_(x.value_), is_live_(x.is_live_) { >+ x.is_live_ = false; >+ ++num_instances_; >+ ++num_moves_; >+ } >+ ~BaseCountedInstance() { >+ --num_instances_; >+ if (is_live_) --num_live_instances_; >+ } >+ >+ BaseCountedInstance& operator=(const BaseCountedInstance& x) { >+ value_ = x.value_; >+ if (is_live_) --num_live_instances_; >+ is_live_ = x.is_live_; >+ if (is_live_) ++num_live_instances_; >+ ++num_copies_; >+ return *this; >+ } >+ BaseCountedInstance& operator=(BaseCountedInstance&& x) { >+ value_ = x.value_; >+ if (is_live_) --num_live_instances_; >+ is_live_ = x.is_live_; >+ x.is_live_ = false; >+ ++num_moves_; >+ return *this; >+ } >+ >+ int value() const { >+ if (!is_live_) std::abort(); >+ return value_; >+ } >+ >+ friend std::ostream& operator<<(std::ostream& o, >+ const BaseCountedInstance& v) { >+ return o << "[value:" << v.value() << "]"; >+ } >+ >+ // Implementation of efficient swap() that counts swaps. >+ static void SwapImpl( >+ BaseCountedInstance& lhs, // NOLINT(runtime/references) >+ BaseCountedInstance& rhs) { // NOLINT(runtime/references) >+ using std::swap; >+ swap(lhs.value_, rhs.value_); >+ swap(lhs.is_live_, rhs.is_live_); >+ ++BaseCountedInstance::num_swaps_; >+ } >+ >+ private: >+ friend class InstanceTracker; >+ >+ int value_; >+ >+ // Indicates if the value is live, ie it hasn't been moved away from. >+ bool is_live_ = true; >+ >+ // Number of instances. >+ static int num_instances_; >+ >+ // Number of live instances (those that have not been moved away from.) >+ static int num_live_instances_; >+ >+ // Number of times that BaseCountedInstance objects were moved. >+ static int num_moves_; >+ >+ // Number of times that BaseCountedInstance objects were copied. >+ static int num_copies_; >+ >+ // Number of times that BaseCountedInstance objects were swapped. >+ static int num_swaps_; >+}; >+ >+// Helper to track the BaseCountedInstance instance counters. Expects that the >+// number of instances and live_instances are the same when it is constructed >+// and when it is destructed. >+class InstanceTracker { >+ public: >+ InstanceTracker() >+ : start_instances_(BaseCountedInstance::num_instances_), >+ start_live_instances_(BaseCountedInstance::num_live_instances_) { >+ ResetCopiesMovesSwaps(); >+ } >+ ~InstanceTracker() { >+ if (instances() != 0) std::abort(); >+ if (live_instances() != 0) std::abort(); >+ } >+ >+ // Returns the number of BaseCountedInstance instances both containing valid >+ // values and those moved away from compared to when the InstanceTracker was >+ // constructed >+ int instances() const { >+ return BaseCountedInstance::num_instances_ - start_instances_; >+ } >+ >+ // Returns the number of live BaseCountedInstance instances compared to when >+ // the InstanceTracker was constructed >+ int live_instances() const { >+ return BaseCountedInstance::num_live_instances_ - start_live_instances_; >+ } >+ >+ // Returns the number of moves on BaseCountedInstance objects since >+ // construction or since the last call to ResetCopiesMovesSwaps(). >+ int moves() const { return BaseCountedInstance::num_moves_ - start_moves_; } >+ >+ // Returns the number of copies on BaseCountedInstance objects since >+ // construction or the last call to ResetCopiesMovesSwaps(). >+ int copies() const { >+ return BaseCountedInstance::num_copies_ - start_copies_; >+ } >+ >+ // Returns the number of swaps on BaseCountedInstance objects since >+ // construction or the last call to ResetCopiesMovesSwaps(). >+ int swaps() const { return BaseCountedInstance::num_swaps_ - start_swaps_; } >+ >+ // Resets the base values for moves, copies and swaps to the current values, >+ // so that subsequent Get*() calls for moves, copies and swaps will compare to >+ // the situation at the point of this call. >+ void ResetCopiesMovesSwaps() { >+ start_moves_ = BaseCountedInstance::num_moves_; >+ start_copies_ = BaseCountedInstance::num_copies_; >+ start_swaps_ = BaseCountedInstance::num_swaps_; >+ } >+ >+ private: >+ int start_instances_; >+ int start_live_instances_; >+ int start_moves_; >+ int start_copies_; >+ int start_swaps_; >+}; >+ >+// Copyable, not movable. >+class CopyableOnlyInstance : public BaseCountedInstance { >+ public: >+ explicit CopyableOnlyInstance(int x) : BaseCountedInstance(x) {} >+ CopyableOnlyInstance(const CopyableOnlyInstance& rhs) = default; >+ CopyableOnlyInstance& operator=(const CopyableOnlyInstance& rhs) = default; >+ >+ friend void swap(CopyableOnlyInstance& lhs, CopyableOnlyInstance& rhs) { >+ BaseCountedInstance::SwapImpl(lhs, rhs); >+ } >+ >+ static bool supports_move() { return false; } >+}; >+ >+// Copyable and movable. >+class CopyableMovableInstance : public BaseCountedInstance { >+ public: >+ explicit CopyableMovableInstance(int x) : BaseCountedInstance(x) {} >+ CopyableMovableInstance(const CopyableMovableInstance& rhs) = default; >+ CopyableMovableInstance(CopyableMovableInstance&& rhs) = default; >+ CopyableMovableInstance& operator=(const CopyableMovableInstance& rhs) = >+ default; >+ CopyableMovableInstance& operator=(CopyableMovableInstance&& rhs) = default; >+ >+ friend void swap(CopyableMovableInstance& lhs, CopyableMovableInstance& rhs) { >+ BaseCountedInstance::SwapImpl(lhs, rhs); >+ } >+ >+ static bool supports_move() { return true; } >+}; >+ >+// Only movable, not default-constructible. >+class MovableOnlyInstance : public BaseCountedInstance { >+ public: >+ explicit MovableOnlyInstance(int x) : BaseCountedInstance(x) {} >+ MovableOnlyInstance(MovableOnlyInstance&& other) = default; >+ MovableOnlyInstance& operator=(MovableOnlyInstance&& other) = default; >+ >+ friend void swap(MovableOnlyInstance& lhs, MovableOnlyInstance& rhs) { >+ BaseCountedInstance::SwapImpl(lhs, rhs); >+ } >+ >+ static bool supports_move() { return true; } >+}; >+ >+} // namespace test_internal >+} // namespace absl >+ >+#endif // ABSL_CONTAINER_INTERNAL_TEST_INSTANCE_TRACKER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker_test.cc >new file mode 100644 >index 00000000000..9efb6771cf0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/container/internal/test_instance_tracker_test.cc >@@ -0,0 +1,160 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/container/internal/test_instance_tracker.h" >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+using absl::test_internal::CopyableMovableInstance; >+using absl::test_internal::CopyableOnlyInstance; >+using absl::test_internal::InstanceTracker; >+using absl::test_internal::MovableOnlyInstance; >+ >+TEST(TestInstanceTracker, CopyableMovable) { >+ InstanceTracker tracker; >+ CopyableMovableInstance src(1); >+ EXPECT_EQ(1, src.value()) << src; >+ CopyableMovableInstance copy(src); >+ CopyableMovableInstance move(std::move(src)); >+ EXPECT_EQ(1, tracker.copies()); >+ EXPECT_EQ(1, tracker.moves()); >+ EXPECT_EQ(0, tracker.swaps()); >+ EXPECT_EQ(3, tracker.instances()); >+ EXPECT_EQ(2, tracker.live_instances()); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ CopyableMovableInstance copy_assign(1); >+ copy_assign = copy; >+ CopyableMovableInstance move_assign(1); >+ move_assign = std::move(move); >+ EXPECT_EQ(1, tracker.copies()); >+ EXPECT_EQ(1, tracker.moves()); >+ EXPECT_EQ(0, tracker.swaps()); >+ EXPECT_EQ(5, tracker.instances()); >+ EXPECT_EQ(3, tracker.live_instances()); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ { >+ using std::swap; >+ swap(move_assign, copy); >+ swap(copy, move_assign); >+ EXPECT_EQ(2, tracker.swaps()); >+ EXPECT_EQ(0, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ EXPECT_EQ(5, tracker.instances()); >+ EXPECT_EQ(3, tracker.live_instances()); >+ } >+} >+ >+TEST(TestInstanceTracker, CopyableOnly) { >+ InstanceTracker tracker; >+ CopyableOnlyInstance src(1); >+ EXPECT_EQ(1, src.value()) << src; >+ CopyableOnlyInstance copy(src); >+ CopyableOnlyInstance copy2(std::move(src)); // NOLINT >+ EXPECT_EQ(2, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ EXPECT_EQ(3, tracker.instances()); >+ EXPECT_EQ(3, tracker.live_instances()); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ CopyableOnlyInstance copy_assign(1); >+ copy_assign = copy; >+ CopyableOnlyInstance copy_assign2(1); >+ copy_assign2 = std::move(copy2); // NOLINT >+ EXPECT_EQ(2, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ EXPECT_EQ(5, tracker.instances()); >+ EXPECT_EQ(5, tracker.live_instances()); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ { >+ using std::swap; >+ swap(src, copy); >+ swap(copy, src); >+ EXPECT_EQ(2, tracker.swaps()); >+ EXPECT_EQ(0, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ EXPECT_EQ(5, tracker.instances()); >+ EXPECT_EQ(5, tracker.live_instances()); >+ } >+} >+ >+TEST(TestInstanceTracker, MovableOnly) { >+ InstanceTracker tracker; >+ MovableOnlyInstance src(1); >+ EXPECT_EQ(1, src.value()) << src; >+ MovableOnlyInstance move(std::move(src)); >+ MovableOnlyInstance move_assign(2); >+ move_assign = std::move(move); >+ EXPECT_EQ(3, tracker.instances()); >+ EXPECT_EQ(1, tracker.live_instances()); >+ EXPECT_EQ(2, tracker.moves()); >+ EXPECT_EQ(0, tracker.copies()); >+ tracker.ResetCopiesMovesSwaps(); >+ >+ { >+ using std::swap; >+ MovableOnlyInstance other(2); >+ swap(move_assign, other); >+ swap(other, move_assign); >+ EXPECT_EQ(2, tracker.swaps()); >+ EXPECT_EQ(0, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ EXPECT_EQ(4, tracker.instances()); >+ EXPECT_EQ(2, tracker.live_instances()); >+ } >+} >+ >+TEST(TestInstanceTracker, ExistingInstances) { >+ CopyableMovableInstance uncounted_instance(1); >+ CopyableMovableInstance uncounted_live_instance( >+ std::move(uncounted_instance)); >+ InstanceTracker tracker; >+ EXPECT_EQ(0, tracker.instances()); >+ EXPECT_EQ(0, tracker.live_instances()); >+ EXPECT_EQ(0, tracker.copies()); >+ { >+ CopyableMovableInstance instance1(1); >+ EXPECT_EQ(1, tracker.instances()); >+ EXPECT_EQ(1, tracker.live_instances()); >+ EXPECT_EQ(0, tracker.copies()); >+ EXPECT_EQ(0, tracker.moves()); >+ { >+ InstanceTracker tracker2; >+ CopyableMovableInstance instance2(instance1); >+ CopyableMovableInstance instance3(std::move(instance2)); >+ EXPECT_EQ(3, tracker.instances()); >+ EXPECT_EQ(2, tracker.live_instances()); >+ EXPECT_EQ(1, tracker.copies()); >+ EXPECT_EQ(1, tracker.moves()); >+ EXPECT_EQ(2, tracker2.instances()); >+ EXPECT_EQ(1, tracker2.live_instances()); >+ EXPECT_EQ(1, tracker2.copies()); >+ EXPECT_EQ(1, tracker2.moves()); >+ } >+ EXPECT_EQ(1, tracker.instances()); >+ EXPECT_EQ(1, tracker.live_instances()); >+ EXPECT_EQ(1, tracker.copies()); >+ EXPECT_EQ(1, tracker.moves()); >+ } >+ EXPECT_EQ(0, tracker.instances()); >+ EXPECT_EQ(0, tracker.live_instances()); >+ EXPECT_EQ(1, tracker.copies()); >+ EXPECT_EQ(1, tracker.moves()); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/copts.bzl b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/copts.bzl >new file mode 100644 >index 00000000000..0168ac5abdd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/copts.bzl >@@ -0,0 +1,154 @@ >+"""absl specific copts. >+ >+Flags specified here must not impact ABI. Code compiled with and without these >+opts will be linked together, and in some cases headers compiled with and >+without these options will be part of the same program. >+""" >+GCC_FLAGS = [ >+ "-Wall", >+ "-Wextra", >+ "-Wcast-qual", >+ "-Wconversion-null", >+ "-Wmissing-declarations", >+ "-Woverlength-strings", >+ "-Wpointer-arith", >+ "-Wunused-local-typedefs", >+ "-Wunused-result", >+ "-Wvarargs", >+ "-Wvla", # variable-length array >+ "-Wwrite-strings", >+ # Google style does not use unsigned integers, though STL containers >+ # have unsigned types. >+ "-Wno-sign-compare", >+] >+ >+GCC_TEST_FLAGS = [ >+ "-Wno-conversion-null", >+ "-Wno-missing-declarations", >+ "-Wno-sign-compare", >+ "-Wno-unused-function", >+ "-Wno-unused-parameter", >+ "-Wno-unused-private-field", >+] >+ >+# Docs on single flags is preceded by a comment. >+# Docs on groups of flags is preceded by ###. >+ >+LLVM_FLAGS = [ >+ # All warnings are treated as errors by implicit -Werror flag >+ "-Wall", >+ "-Wextra", >+ "-Weverything", >+ # Abseil does not support C++98 >+ "-Wno-c++98-compat-pedantic", >+ # Turns off all implicit conversion warnings. Most are re-enabled below. >+ "-Wno-conversion", >+ "-Wno-covered-switch-default", >+ "-Wno-deprecated", >+ "-Wno-disabled-macro-expansion", >+ "-Wno-double-promotion", >+ ### >+ # Turned off as they include valid C++ code. >+ "-Wno-comma", >+ "-Wno-extra-semi", >+ "-Wno-packed", >+ "-Wno-padded", >+ ### >+ "-Wno-float-conversion", >+ "-Wno-float-equal", >+ "-Wno-format-nonliteral", >+ # Too aggressive: warns on Clang extensions enclosed in Clang-only >+ # compilation paths. >+ "-Wno-gcc-compat", >+ ### >+ # Some internal globals are necessary. Don't do this at home. >+ "-Wno-global-constructors", >+ "-Wno-exit-time-destructors", >+ ### >+ "-Wno-nested-anon-types", >+ "-Wno-non-modular-include-in-module", >+ "-Wno-old-style-cast", >+ # Warns on preferred usage of non-POD types such as string_view >+ "-Wno-range-loop-analysis", >+ "-Wno-reserved-id-macro", >+ "-Wno-shorten-64-to-32", >+ "-Wno-switch-enum", >+ "-Wno-thread-safety-negative", >+ "-Wno-undef", >+ "-Wno-unknown-warning-option", >+ "-Wno-unreachable-code", >+ # Causes warnings on include guards >+ "-Wno-unused-macros", >+ "-Wno-weak-vtables", >+ ### >+ # Implicit conversion warnings turned off by -Wno-conversion >+ # which are re-enabled below. >+ "-Wbitfield-enum-conversion", >+ "-Wbool-conversion", >+ "-Wconstant-conversion", >+ "-Wenum-conversion", >+ "-Wint-conversion", >+ "-Wliteral-conversion", >+ "-Wnon-literal-null-conversion", >+ "-Wnull-conversion", >+ "-Wobjc-literal-conversion", >+ "-Wno-sign-conversion", >+ "-Wstring-conversion", >+ ### >+] >+ >+LLVM_TEST_FLAGS = [ >+ "-Wno-c99-extensions", >+ "-Wno-missing-noreturn", >+ "-Wno-missing-prototypes", >+ "-Wno-null-conversion", >+ "-Wno-shadow", >+ "-Wno-shift-sign-overflow", >+ "-Wno-sign-compare", >+ "-Wno-unused-function", >+ "-Wno-unused-member-function", >+ "-Wno-unused-parameter", >+ "-Wno-unused-private-field", >+ "-Wno-unused-template", >+ "-Wno-used-but-marked-unused", >+ "-Wno-zero-as-null-pointer-constant", >+] >+ >+MSVC_FLAGS = [ >+ "/W3", >+ "/WX", >+ "/wd4005", # macro-redefinition >+ "/wd4068", # unknown pragma >+ "/wd4244", # conversion from 'type1' to 'type2', possible loss of data >+ "/wd4267", # conversion from 'size_t' to 'type', possible loss of data >+ "/wd4800", # forcing value to bool 'true' or 'false' (performance warning) >+ "/DNOMINMAX", # Don't define min and max macros (windows.h) >+ "/DWIN32_LEAN_AND_MEAN", # Don't bloat namespace with incompatible winsock versions. >+ "/D_CRT_SECURE_NO_WARNINGS", # Don't warn about usage of insecure C functions >+] >+ >+MSVC_TEST_FLAGS = [ >+ "/wd4018", # signed/unsigned mismatch >+ "/wd4101", # unreferenced local variable >+ "/wd4503", # decorated name length exceeded, name was truncated >+] >+ >+# /Wall with msvc includes unhelpful warnings such as C4711, C4710, ... >+ABSL_DEFAULT_COPTS = select({ >+ "//absl:windows": MSVC_FLAGS, >+ "//absl:llvm_compiler": LLVM_FLAGS, >+ "//conditions:default": GCC_FLAGS, >+}) >+ >+# in absence of modules (--compiler=gcc or -c opt), cc_tests leak their copts >+# to their (included header) dependencies and fail to build outside absl >+ABSL_TEST_COPTS = ABSL_DEFAULT_COPTS + select({ >+ "//absl:windows": MSVC_TEST_FLAGS, >+ "//absl:llvm_compiler": LLVM_TEST_FLAGS, >+ "//conditions:default": GCC_TEST_FLAGS, >+}) >+ >+ABSL_EXCEPTIONS_FLAG = select({ >+ "//absl:windows": ["/U_HAS_EXCEPTIONS", "/D_HAS_EXCEPTIONS=1", "/EHsc"], >+ "//conditions:default": ["-fexceptions"], >+}) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.bazel >new file mode 100644 >index 00000000000..e1e7fced69f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.bazel >@@ -0,0 +1,305 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package( >+ default_visibility = ["//visibility:public"], >+) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "stacktrace", >+ srcs = [ >+ "stacktrace.cc", >+ ], >+ hdrs = ["stacktrace.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":debugging_internal", >+ "//absl/base", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_library( >+ name = "symbolize", >+ srcs = [ >+ "symbolize.cc", >+ "symbolize_elf.inc", >+ "symbolize_unimplemented.inc", >+ "symbolize_win32.inc", >+ ], >+ hdrs = [ >+ "internal/symbolize.h", >+ "symbolize.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":debugging_internal", >+ ":demangle_internal", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/base:malloc_internal", >+ ], >+) >+ >+cc_test( >+ name = "symbolize_test", >+ srcs = ["symbolize_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":stack_consumption", >+ ":symbolize", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "@com_google_googletest//:gtest", >+ ], >+) >+ >+cc_library( >+ name = "examine_stack", >+ srcs = [ >+ "internal/examine_stack.cc", >+ ], >+ hdrs = [ >+ "internal/examine_stack.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":stacktrace", >+ ":symbolize", >+ "//absl/base", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_library( >+ name = "failure_signal_handler", >+ srcs = ["failure_signal_handler.cc"], >+ hdrs = ["failure_signal_handler.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":examine_stack", >+ ":stacktrace", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_test( >+ name = "failure_signal_handler_test", >+ srcs = ["failure_signal_handler_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ linkopts = select({ >+ "//absl:windows": [], >+ "//conditions:default": ["-pthread"], >+ }), >+ deps = [ >+ ":failure_signal_handler", >+ ":stacktrace", >+ ":symbolize", >+ "//absl/base", >+ "//absl/strings", >+ "@com_google_googletest//:gtest", >+ ], >+) >+ >+cc_library( >+ name = "debugging_internal", >+ srcs = [ >+ "internal/address_is_readable.cc", >+ "internal/elf_mem_image.cc", >+ "internal/vdso_support.cc", >+ ], >+ hdrs = [ >+ "internal/address_is_readable.h", >+ "internal/elf_mem_image.h", >+ "internal/stacktrace_aarch64-inl.inc", >+ "internal/stacktrace_arm-inl.inc", >+ "internal/stacktrace_config.h", >+ "internal/stacktrace_generic-inl.inc", >+ "internal/stacktrace_powerpc-inl.inc", >+ "internal/stacktrace_unimplemented-inl.inc", >+ "internal/stacktrace_win32-inl.inc", >+ "internal/stacktrace_x86-inl.inc", >+ "internal/vdso_support.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base", >+ "//absl/base:dynamic_annotations", >+ ], >+) >+ >+cc_library( >+ name = "demangle_internal", >+ srcs = ["internal/demangle.cc"], >+ hdrs = ["internal/demangle.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_test( >+ name = "demangle_test", >+ srcs = ["internal/demangle_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":demangle_internal", >+ ":stack_consumption", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "leak_check", >+ srcs = select({ >+ # The leak checking interface depends on weak function >+ # declarations that may not necessarily have definitions. >+ # Windows doesn't support this, and ios requires >+ # guaranteed definitions for weak symbols. >+ "//absl:ios": [], >+ "//absl:windows": [], >+ "//conditions:default": [ >+ "leak_check.cc", >+ ], >+ }), >+ hdrs = select({ >+ "//absl:ios": [], >+ "//absl:windows": [], >+ "//conditions:default": ["leak_check.h"], >+ }), >+ deps = ["//absl/base:core_headers"], >+) >+ >+# Adding a dependency to leak_check_disable will disable >+# sanitizer leak checking (asan/lsan) in a test without >+# the need to mess around with build features. >+cc_library( >+ name = "leak_check_disable", >+ srcs = ["leak_check_disable.cc"], >+ linkstatic = 1, >+ alwayslink = 1, >+) >+ >+# These targets exists for use in tests only, explicitly configuring the >+# LEAK_SANITIZER macro. It must be linked with -fsanitize=leak for lsan. >+ABSL_LSAN_LINKOPTS = select({ >+ "//absl:llvm_compiler": ["-fsanitize=leak"], >+ "//conditions:default": [], >+}) >+ >+cc_library( >+ name = "leak_check_api_enabled_for_testing", >+ testonly = 1, >+ srcs = ["leak_check.cc"], >+ hdrs = ["leak_check.h"], >+ copts = select({ >+ "//absl:llvm_compiler": ["-DLEAK_SANITIZER"], >+ "//conditions:default": [], >+ }), >+ visibility = ["//visibility:private"], >+) >+ >+cc_library( >+ name = "leak_check_api_disabled_for_testing", >+ testonly = 1, >+ srcs = ["leak_check.cc"], >+ hdrs = ["leak_check.h"], >+ copts = ["-ULEAK_SANITIZER"], >+ visibility = ["//visibility:private"], >+) >+ >+cc_test( >+ name = "leak_check_test", >+ srcs = ["leak_check_test.cc"], >+ copts = select({ >+ "//absl:llvm_compiler": ["-DABSL_EXPECT_LEAK_SANITIZER"], >+ "//conditions:default": [], >+ }), >+ linkopts = ABSL_LSAN_LINKOPTS, >+ deps = [ >+ ":leak_check_api_enabled_for_testing", >+ "//absl/base", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "leak_check_no_lsan_test", >+ srcs = ["leak_check_test.cc"], >+ copts = ["-UABSL_EXPECT_LEAK_SANITIZER"], >+ deps = [ >+ ":leak_check_api_disabled_for_testing", >+ "//absl/base", # for raw_logging >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+# Test that leak checking is skipped when lsan is enabled but >+# ":leak_check_disable" is linked in. >+# >+# This test should fail in the absence of a dependency on ":leak_check_disable" >+cc_test( >+ name = "disabled_leak_check_test", >+ srcs = ["leak_check_fail_test.cc"], >+ linkopts = ABSL_LSAN_LINKOPTS, >+ deps = [ >+ ":leak_check_api_enabled_for_testing", >+ ":leak_check_disable", >+ "//absl/base", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "stack_consumption", >+ testonly = 1, >+ srcs = ["internal/stack_consumption.cc"], >+ hdrs = ["internal/stack_consumption.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ "//absl/base", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_test( >+ name = "stack_consumption_test", >+ srcs = ["internal/stack_consumption_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":stack_consumption", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.gn >new file mode 100644 >index 00000000000..b50b0a6ddc8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/BUILD.gn >@@ -0,0 +1,245 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+import("//build/config/sanitizers/sanitizers.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("stacktrace") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "stacktrace.cc", >+ ] >+ public = [ >+ "stacktrace.h", >+ ] >+ deps = [ >+ ":debugging_internal", >+ "../base", >+ "../base:core_headers", >+ ] >+} >+ >+source_set("symbolize") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "symbolize.cc", >+ "symbolize_elf.inc", >+ "symbolize_unimplemented.inc", >+ "symbolize_win32.inc", >+ ] >+ public = [ >+ "internal/symbolize.h", >+ "symbolize.h", >+ ] >+ deps = [ >+ ":debugging_internal", >+ ":demangle_internal", >+ "../base", >+ "../base:core_headers", >+ "../base:malloc_internal", >+ ] >+} >+ >+source_set("examine_stack") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/examine_stack.cc", >+ ] >+ public = [ >+ "internal/examine_stack.h", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+ deps = [ >+ ":stacktrace", >+ ":symbolize", >+ "../base", >+ "../base:core_headers", >+ ] >+} >+ >+source_set("failure_signal_handler") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "failure_signal_handler.cc" >+ ] >+ public = [ >+ "failure_signal_handler.h" >+ ] >+ deps = [ >+ ":examine_stack", >+ ":stacktrace", >+ "../base", >+ "../base:config", >+ "../base:core_headers", >+ ] >+} >+ >+source_set("debugging_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/address_is_readable.cc", >+ "internal/elf_mem_image.cc", >+ "internal/vdso_support.cc", >+ ] >+ public = [ >+ "internal/address_is_readable.h", >+ "internal/elf_mem_image.h", >+ "internal/stacktrace_config.h", >+ "internal/vdso_support.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:dynamic_annotations", >+ ] >+} >+ >+source_set("demangle_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/demangle.cc", >+ ] >+ public = [ >+ "internal/demangle.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:core_headers", >+ ] >+} >+ >+source_set("leak_check") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ if (is_ios || is_win) { >+ sources = [] >+ public = [] >+ } else { >+ sources = [ >+ "leak_check.cc", >+ ] >+ public = [ >+ "leak_check.h", >+ ] >+ } >+ deps = [ >+ "../base:core_headers", >+ ] >+} >+ >+source_set("leak_check_disable") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "leak_check_disable.cc", >+ ] >+} >+ >+if (is_lsan) { >+ source_set("leak_check_api_enabled_for_testing") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "leak_check.cc", >+ ] >+ public = [ >+ "leak_check.h", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+ } >+} else { >+ source_set("leak_check_api_disabled_for_testing") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "leak_check.cc", >+ ] >+ public = [ >+ "leak_check.h", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+ } >+} >+ >+source_set("stack_consumption") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/stack_consumption.cc", >+ ] >+ public = [ >+ "internal/stack_consumption.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:core_headers", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/CMakeLists.txt >new file mode 100644 >index 00000000000..4af2ec8a411 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/CMakeLists.txt >@@ -0,0 +1,217 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND DEBUGGING_PUBLIC_HEADERS >+ "failure_signal_handler.h" >+ "leak_check.h" >+ "stacktrace.h" >+ "symbolize.h" >+) >+ >+# TODO(cohenjon) The below is all kinds of wrong. Make this match what we do in >+# Bazel >+list(APPEND DEBUGGING_INTERNAL_HEADERS >+ "internal/address_is_readable.h" >+ "internal/demangle.h" >+ "internal/elf_mem_image.h" >+ "internal/examine_stack.h" >+ "internal/stacktrace_config.h" >+ "internal/symbolize.h" >+ "internal/vdso_support.h" >+) >+ >+list(APPEND DEBUGGING_INTERNAL_SRC >+ "internal/address_is_readable.cc" >+ "internal/elf_mem_image.cc" >+ "internal/vdso_support.cc" >+) >+ >+ >+list(APPEND STACKTRACE_SRC >+ "stacktrace.cc" >+ ${DEBUGGING_INTERNAL_SRC} >+ ${DEBUGGING_PUBLIC_HEADERS} >+ ${DEBUGGING_INTERNAL_HEADERS} >+) >+ >+list(APPEND SYMBOLIZE_SRC >+ "symbolize.cc" >+ "symbolize_elf.inc" >+ "symbolize_unimplemented.inc" >+ "symbolize_win32.inc" >+ "internal/demangle.cc" >+ ${DEBUGGING_PUBLIC_HEADERS} >+ ${DEBUGGING_INTERNAL_HEADERS} >+ ${DEBUGGING_INTERNAL_SRC} >+) >+ >+list(APPEND FAILURE_SIGNAL_HANDLER_SRC >+ "failure_signal_handler.cc" >+ ${DEBUGGING_PUBLIC_HEADERS} >+) >+ >+list(APPEND EXAMINE_STACK_SRC >+ "internal/examine_stack.cc" >+ ${DEBUGGING_PUBLIC_HEADERS} >+ ${DEBUGGING_INTERNAL_HEADERS} >+) >+ >+absl_library( >+ TARGET >+ absl_stacktrace >+ SOURCES >+ ${STACKTRACE_SRC} >+ EXPORT_NAME >+ stacktrace >+) >+ >+absl_library( >+ TARGET >+ absl_symbolize >+ SOURCES >+ ${SYMBOLIZE_SRC} >+ PUBLIC_LIBRARIES >+ absl::base >+ absl_malloc_internal >+ EXPORT_NAME >+ symbolize >+) >+ >+absl_library( >+ TARGET >+ absl_failure_signal_handler >+ SOURCES >+ ${FAILURE_SIGNAL_HANDLER_SRC} >+ PUBLIC_LIBRARIES >+ absl_base absl::examine_stack absl::stacktrace absl_synchronization >+ EXPORT_NAME >+ failure_signal_handler >+) >+ >+# Internal-only. Projects external to Abseil should not depend >+# directly on this library. >+absl_library( >+ TARGET >+ absl_examine_stack >+ SOURCES >+ ${EXAMINE_STACK_SRC} >+ EXPORT_NAME >+ examine_stack >+) >+ >+list(APPEND LEAK_CHECK_SRC >+ "leak_check.cc" >+) >+ >+ >+# leak_check library >+absl_library( >+ TARGET >+ absl_leak_check >+ SOURCES >+ ${LEAK_CHECK_SRC} >+ PUBLIC_LIBRARIES >+ absl_base >+ EXPORT_NAME >+ leak_check >+) >+ >+ >+# component target >+absl_header_library( >+ TARGET >+ absl_debugging >+ PUBLIC_LIBRARIES >+ absl_stacktrace absl_leak_check >+ EXPORT_NAME >+ debugging >+) >+ >+# >+## TESTS >+# >+ >+list(APPEND STACK_CONSUMPTION_SRC >+ "internal/stack_consumption.cc" >+ "internal/stack_consumption.h" >+) >+ >+absl_library( >+ TARGET >+ absl_stack_consumption >+ SOURCES >+ ${STACK_CONSUMPTION_SRC} >+) >+ >+absl_test( >+ TARGET >+ absl_stack_consumption_test >+ SOURCES >+ "internal/stack_consumption_test.cc" >+ PUBLIC_LIBRARIES >+ absl_stack_consumption >+ absl::base >+) >+ >+list(APPEND DEMANGLE_TEST_SRC "internal/demangle_test.cc") >+ >+absl_test( >+ TARGET >+ demangle_test >+ SOURCES >+ ${DEMANGLE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl_symbolize absl_stack_consumption >+) >+ >+list(APPEND SYMBOLIZE_TEST_SRC "symbolize_test.cc") >+ >+absl_test( >+ TARGET >+ symbolize_test >+ SOURCES >+ ${SYMBOLIZE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl::base absl::memory absl_symbolize absl_stack_consumption >+) >+ >+list(APPEND FAILURE_SIGNAL_HANDLER_TEST_SRC "failure_signal_handler_test.cc") >+ >+absl_test( >+ TARGET >+ failure_signal_handler_test >+ SOURCES >+ ${FAILURE_SIGNAL_HANDLER_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl_examine_stack >+ absl_failure_signal_handler >+ absl_stacktrace >+ absl_symbolize >+ absl::base >+ absl::strings >+) >+ >+# test leak_check_test >+list(APPEND LEAK_CHECK_TEST_SRC "leak_check_test.cc") >+ >+absl_test( >+ TARGET >+ leak_check_test >+ SOURCES >+ ${LEAK_CHECK_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl_leak_check >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc >new file mode 100644 >index 00000000000..d4b957bc2e4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.cc >@@ -0,0 +1,355 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#include "absl/debugging/failure_signal_handler.h" >+ >+#include "absl/base/config.h" >+ >+#ifdef _WIN32 >+#include <windows.h> >+#else >+#include <unistd.h> >+#endif >+ >+#ifdef ABSL_HAVE_MMAP >+#include <sys/mman.h> >+#endif >+ >+#include <algorithm> >+#include <atomic> >+#include <cerrno> >+#include <csignal> >+#include <cstdio> >+#include <cstring> >+#include <ctime> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/sysinfo.h" >+#include "absl/debugging/internal/examine_stack.h" >+#include "absl/debugging/stacktrace.h" >+ >+#ifndef _WIN32 >+#define ABSL_HAVE_SIGACTION >+#endif >+ >+namespace absl { >+ >+ABSL_CONST_INIT static FailureSignalHandlerOptions fsh_options; >+ >+// Resets the signal handler for signo to the default action for that >+// signal, then raises the signal. >+static void RaiseToDefaultHandler(int signo) { >+ signal(signo, SIG_DFL); >+ raise(signo); >+} >+ >+struct FailureSignalData { >+ const int signo; >+ const char* const as_string; >+#ifdef ABSL_HAVE_SIGACTION >+ struct sigaction previous_action; >+ // StructSigaction is used to silence -Wmissing-field-initializers. >+ using StructSigaction = struct sigaction; >+ #define FSD_PREVIOUS_INIT FailureSignalData::StructSigaction() >+#else >+ void (*previous_handler)(int); >+ #define FSD_PREVIOUS_INIT SIG_DFL >+#endif >+}; >+ >+ABSL_CONST_INIT static FailureSignalData failure_signal_data[] = { >+ {SIGSEGV, "SIGSEGV", FSD_PREVIOUS_INIT}, >+ {SIGILL, "SIGILL", FSD_PREVIOUS_INIT}, >+ {SIGFPE, "SIGFPE", FSD_PREVIOUS_INIT}, >+ {SIGABRT, "SIGABRT", FSD_PREVIOUS_INIT}, >+ {SIGTERM, "SIGTERM", FSD_PREVIOUS_INIT}, >+#ifndef _WIN32 >+ {SIGBUS, "SIGBUS", FSD_PREVIOUS_INIT}, >+ {SIGTRAP, "SIGTRAP", FSD_PREVIOUS_INIT}, >+#endif >+}; >+ >+#undef FSD_PREVIOUS_INIT >+ >+static void RaiseToPreviousHandler(int signo) { >+ // Search for the previous handler. >+ for (const auto& it : failure_signal_data) { >+ if (it.signo == signo) { >+#ifdef ABSL_HAVE_SIGACTION >+ sigaction(signo, &it.previous_action, nullptr); >+#else >+ signal(signo, it.previous_handler); >+#endif >+ raise(signo); >+ return; >+ } >+ } >+ >+ // Not found, use the default handler. >+ RaiseToDefaultHandler(signo); >+} >+ >+namespace debugging_internal { >+ >+const char* FailureSignalToString(int signo) { >+ for (const auto& it : failure_signal_data) { >+ if (it.signo == signo) { >+ return it.as_string; >+ } >+ } >+ return ""; >+} >+ >+} // namespace debugging_internal >+ >+#ifndef _WIN32 >+ >+static bool SetupAlternateStackOnce() { >+ const size_t page_mask = getpagesize() - 1; >+ size_t stack_size = (std::max(SIGSTKSZ, 65536) + page_mask) & ~page_mask; >+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ >+ defined(THREAD_SANITIZER) >+ // Account for sanitizer instrumentation requiring additional stack space. >+ stack_size *= 5; >+#endif >+ >+ stack_t sigstk; >+ memset(&sigstk, 0, sizeof(sigstk)); >+ sigstk.ss_size = stack_size; >+ >+#ifdef ABSL_HAVE_MMAP >+#ifndef MAP_STACK >+#define MAP_STACK 0 >+#endif >+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) >+#define MAP_ANONYMOUS MAP_ANON >+#endif >+ sigstk.ss_sp = mmap(nullptr, sigstk.ss_size, PROT_READ | PROT_WRITE, >+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); >+ if (sigstk.ss_sp == MAP_FAILED) { >+ ABSL_RAW_LOG(FATAL, "mmap() for alternate signal stack failed"); >+ } >+#else >+ sigstk.ss_sp = malloc(sigstk.ss_size); >+ if (sigstk.ss_sp == nullptr) { >+ ABSL_RAW_LOG(FATAL, "malloc() for alternate signal stack failed"); >+ } >+#endif >+ >+ if (sigaltstack(&sigstk, nullptr) != 0) { >+ ABSL_RAW_LOG(FATAL, "sigaltstack() failed with errno=%d", errno); >+ } >+ return true; >+} >+ >+#endif >+ >+#ifdef ABSL_HAVE_SIGACTION >+ >+// Sets up an alternate stack for signal handlers once. >+// Returns the appropriate flag for sig_action.sa_flags >+// if the system supports using an alternate stack. >+static int MaybeSetupAlternateStack() { >+#ifndef _WIN32 >+ ABSL_ATTRIBUTE_UNUSED static const bool kOnce = SetupAlternateStackOnce(); >+ return SA_ONSTACK; >+#else >+ return 0; >+#endif >+} >+ >+static void InstallOneFailureHandler(FailureSignalData* data, >+ void (*handler)(int, siginfo_t*, void*)) { >+ struct sigaction act; >+ memset(&act, 0, sizeof(act)); >+ sigemptyset(&act.sa_mask); >+ act.sa_flags |= SA_SIGINFO; >+ // SA_NODEFER is required to handle SIGABRT from >+ // ImmediateAbortSignalHandler(). >+ act.sa_flags |= SA_NODEFER; >+ if (fsh_options.use_alternate_stack) { >+ act.sa_flags |= MaybeSetupAlternateStack(); >+ } >+ act.sa_sigaction = handler; >+ ABSL_RAW_CHECK(sigaction(data->signo, &act, &data->previous_action) == 0, >+ "sigaction() failed"); >+} >+ >+#else >+ >+static void InstallOneFailureHandler(FailureSignalData* data, >+ void (*handler)(int)) { >+ data->previous_handler = signal(data->signo, handler); >+ ABSL_RAW_CHECK(data->previous_handler != SIG_ERR, "signal() failed"); >+} >+ >+#endif >+ >+static void WriteToStderr(const char* data) { >+ int old_errno = errno; >+ absl::raw_logging_internal::SafeWriteToStderr(data, strlen(data)); >+ errno = old_errno; >+} >+ >+static void WriteSignalMessage(int signo, void (*writerfn)(const char*)) { >+ char buf[64]; >+ const char* const signal_string = >+ debugging_internal::FailureSignalToString(signo); >+ if (signal_string != nullptr && signal_string[0] != '\0') { >+ snprintf(buf, sizeof(buf), "*** %s received at time=%ld ***\n", >+ signal_string, >+ static_cast<long>(time(nullptr))); // NOLINT(runtime/int) >+ } else { >+ snprintf(buf, sizeof(buf), "*** Signal %d received at time=%ld ***\n", >+ signo, static_cast<long>(time(nullptr))); // NOLINT(runtime/int) >+ } >+ writerfn(buf); >+} >+ >+// `void*` might not be big enough to store `void(*)(const char*)`. >+struct WriterFnStruct { >+ void (*writerfn)(const char*); >+}; >+ >+// Many of the absl::debugging_internal::Dump* functions in >+// examine_stack.h take a writer function pointer that has a void* arg >+// for historical reasons. failure_signal_handler_writer only takes a >+// data pointer. This function converts between these types. >+static void WriterFnWrapper(const char* data, void* arg) { >+ static_cast<WriterFnStruct*>(arg)->writerfn(data); >+} >+ >+// Convenient wrapper around DumpPCAndFrameSizesAndStackTrace() for signal >+// handlers. "noinline" so that GetStackFrames() skips the top-most stack >+// frame for this function. >+ABSL_ATTRIBUTE_NOINLINE static void WriteStackTrace( >+ void* ucontext, bool symbolize_stacktrace, >+ void (*writerfn)(const char*, void*), void* writerfn_arg) { >+ constexpr int kNumStackFrames = 32; >+ void* stack[kNumStackFrames]; >+ int frame_sizes[kNumStackFrames]; >+ int min_dropped_frames; >+ int depth = absl::GetStackFramesWithContext( >+ stack, frame_sizes, kNumStackFrames, >+ 1, // Do not include this function in stack trace. >+ ucontext, &min_dropped_frames); >+ absl::debugging_internal::DumpPCAndFrameSizesAndStackTrace( >+ absl::debugging_internal::GetProgramCounter(ucontext), stack, frame_sizes, >+ depth, min_dropped_frames, symbolize_stacktrace, writerfn, writerfn_arg); >+} >+ >+// Called by AbslFailureSignalHandler() to write the failure info. It is >+// called once with writerfn set to WriteToStderr() and then possibly >+// with writerfn set to the user provided function. >+static void WriteFailureInfo(int signo, void* ucontext, >+ void (*writerfn)(const char*)) { >+ WriterFnStruct writerfn_struct{writerfn}; >+ WriteSignalMessage(signo, writerfn); >+ WriteStackTrace(ucontext, fsh_options.symbolize_stacktrace, WriterFnWrapper, >+ &writerfn_struct); >+} >+ >+// absl::SleepFor() can't be used here since AbslInternalSleepFor() >+// may be overridden to do something that isn't async-signal-safe on >+// some platforms. >+static void PortableSleepForSeconds(int seconds) { >+#ifdef _WIN32 >+ Sleep(seconds * 1000); >+#else >+ struct timespec sleep_time; >+ sleep_time.tv_sec = seconds; >+ sleep_time.tv_nsec = 0; >+ while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {} >+#endif >+} >+ >+#ifdef ABSL_HAVE_ALARM >+// AbslFailureSignalHandler() installs this as a signal handler for >+// SIGALRM, then sets an alarm to be delivered to the program after a >+// set amount of time. If AbslFailureSignalHandler() hangs for more than >+// the alarm timeout, ImmediateAbortSignalHandler() will abort the >+// program. >+static void ImmediateAbortSignalHandler(int) { >+ RaiseToDefaultHandler(SIGABRT); >+} >+#endif >+ >+// absl::base_internal::GetTID() returns pid_t on most platforms, but >+// returns absl::base_internal::pid_t on Windows. >+using GetTidType = decltype(absl::base_internal::GetTID()); >+ABSL_CONST_INIT static std::atomic<GetTidType> failed_tid(0); >+ >+#ifndef ABSL_HAVE_SIGACTION >+static void AbslFailureSignalHandler(int signo) { >+ void* ucontext = nullptr; >+#else >+static void AbslFailureSignalHandler(int signo, siginfo_t*, void* ucontext) { >+#endif >+ >+ const GetTidType this_tid = absl::base_internal::GetTID(); >+ GetTidType previous_failed_tid = 0; >+ if (!failed_tid.compare_exchange_strong( >+ previous_failed_tid, static_cast<intptr_t>(this_tid), >+ std::memory_order_acq_rel, std::memory_order_relaxed)) { >+ ABSL_RAW_LOG( >+ ERROR, >+ "Signal %d raised at PC=%p while already in AbslFailureSignalHandler()", >+ signo, absl::debugging_internal::GetProgramCounter(ucontext)); >+ if (this_tid != previous_failed_tid) { >+ // Another thread is already in AbslFailureSignalHandler(), so wait >+ // a bit for it to finish. If the other thread doesn't kill us, >+ // we do so after sleeping. >+ PortableSleepForSeconds(3); >+ RaiseToDefaultHandler(signo); >+ // The recursively raised signal may be blocked until we return. >+ return; >+ } >+ } >+ >+#ifdef ABSL_HAVE_ALARM >+ // Set an alarm to abort the program in case this code hangs or deadlocks. >+ if (fsh_options.alarm_on_failure_secs > 0) { >+ alarm(0); // Cancel any existing alarms. >+ signal(SIGALRM, ImmediateAbortSignalHandler); >+ alarm(fsh_options.alarm_on_failure_secs); >+ } >+#endif >+ >+ // First write to stderr. >+ WriteFailureInfo(signo, ucontext, WriteToStderr); >+ >+ // Riskier code (because it is less likely to be async-signal-safe) >+ // goes after this point. >+ if (fsh_options.writerfn != nullptr) { >+ WriteFailureInfo(signo, ucontext, fsh_options.writerfn); >+ } >+ >+ if (fsh_options.call_previous_handler) { >+ RaiseToPreviousHandler(signo); >+ } else { >+ RaiseToDefaultHandler(signo); >+ } >+} >+ >+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options) { >+ fsh_options = options; >+ for (auto& it : failure_signal_data) { >+ InstallOneFailureHandler(&it, AbslFailureSignalHandler); >+ } >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h >new file mode 100644 >index 00000000000..c57954e5875 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler.h >@@ -0,0 +1,117 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: failure_signal_handler.h >+// ----------------------------------------------------------------------------- >+// >+// This file configures the Abseil *failure signal handler* to capture and dump >+// useful debugging information (such as a stacktrace) upon program failure. >+// >+// To use the failure signal handler, call `absl::InstallFailureSignalHandler()` >+// very early in your program, usually in the first few lines of main(): >+// >+// int main(int argc, char** argv) { >+// // Initialize the symbolizer to get a human-readable stack trace >+// absl::InitializeSymbolizer(argv[0]); >+// >+// absl::FailureSignalHandlerOptions options; >+// absl::InstallFailureSignalHandler(options); >+// DoSomethingInteresting(); >+// return 0; >+// } >+// >+// Any program that raises a fatal signal (such as `SIGSEGV`, `SIGILL`, >+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP`) will call the >+// installed failure signal handler and provide debugging information to stderr. >+// >+// Note that you should *not* install the Abseil failure signal handler more >+// than once. You may, of course, have another (non-Abseil) failure signal >+// handler installed (which would be triggered if Abseil's failure signal >+// handler sets `call_previous_handler` to `true`). >+ >+#ifndef ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ >+#define ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ >+ >+namespace absl { >+ >+// FailureSignalHandlerOptions >+// >+// Struct for holding `absl::InstallFailureSignalHandler()` configuration >+// options. >+struct FailureSignalHandlerOptions { >+ // If true, try to symbolize the stacktrace emitted on failure, provided that >+ // you have initialized a symbolizer for that purpose. (See symbolize.h for >+ // more information.) >+ bool symbolize_stacktrace = true; >+ >+ // If true, try to run signal handlers on an alternate stack (if supported on >+ // the given platform). An alternate stack is useful for program crashes due >+ // to a stack overflow; by running on a alternate stack, the signal handler >+ // may run even when normal stack space has been exausted. The downside of >+ // using an alternate stack is that extra memory for the alternate stack needs >+ // to be pre-allocated. >+ bool use_alternate_stack = true; >+ >+ // If positive, indicates the number of seconds after which the failure signal >+ // handler is invoked to abort the program. Setting such an alarm is useful in >+ // cases where the failure signal handler itself may become hung or >+ // deadlocked. >+ int alarm_on_failure_secs = 3; >+ >+ // If true, call the previously registered signal handler for the signal that >+ // was received (if one was registered) after the existing signal handler >+ // runs. This mechanism can be used to chain signal handlers together. >+ // >+ // If false, the signal is raised to the default handler for that signal >+ // (which normally terminates the program). >+ // >+ // IMPORTANT: If true, the chained fatal signal handlers must not try to >+ // recover from the fatal signal. Instead, they should terminate the program >+ // via some mechanism, like raising the default handler for the signal, or by >+ // calling `_exit()`. Note that the failure signal handler may put parts of >+ // the Abseil library into a state from which they cannot recover. >+ bool call_previous_handler = false; >+ >+ // If non-null, indicates a pointer to a callback function that will be called >+ // upon failure, with a std::string argument containing failure data. This function >+ // may be used as a hook to write failure data to a secondary location, such >+ // as a log file. This function may also be called with null data, as a hint >+ // to flush any buffered data before the program may be terminated. Consider >+ // flushing any buffered data in all calls to this function. >+ // >+ // Since this function runs within a signal handler, it should be >+ // async-signal-safe if possible. >+ // See http://man7.org/linux/man-pages/man7/signal-safety.7.html >+ void (*writerfn)(const char*) = nullptr; >+}; >+ >+// InstallFailureSignalHandler() >+// >+// Installs a signal handler for the common failure signals `SIGSEGV`, `SIGILL`, >+// `SIGFPE`, `SIGABRT`, `SIGTERM`, `SIGBUG`, and `SIGTRAP` (provided they exist >+// on the given platform). The failure signal handler dumps program failure data >+// useful for debugging in an unspecified format to stderr. This data may >+// include the program counter, a stacktrace, and register information on some >+// systems; do not rely on an exact format for the output, as it is subject to >+// change. >+void InstallFailureSignalHandler(const FailureSignalHandlerOptions& options); >+ >+namespace debugging_internal { >+const char* FailureSignalToString(int signo); >+} // namespace debugging_internal >+ >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_FAILURE_SIGNAL_HANDLER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc >new file mode 100644 >index 00000000000..ba520910f47 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/failure_signal_handler_test.cc >@@ -0,0 +1,155 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#include "absl/debugging/failure_signal_handler.h" >+ >+#include <csignal> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+#include <fstream> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/debugging/stacktrace.h" >+#include "absl/debugging/symbolize.h" >+#include "absl/strings/match.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+#if GTEST_HAS_DEATH_TEST >+ >+// For the parameterized death tests. GetParam() returns the signal number. >+using FailureSignalHandlerDeathTest = ::testing::TestWithParam<int>; >+ >+// This function runs in a fork()ed process on most systems. >+void InstallHandlerAndRaise(int signo) { >+ absl::InstallFailureSignalHandler(absl::FailureSignalHandlerOptions()); >+ raise(signo); >+} >+ >+TEST_P(FailureSignalHandlerDeathTest, AbslFailureSignal) { >+ const int signo = GetParam(); >+ std::string exit_regex = absl::StrCat( >+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo), >+ " received at time="); >+#ifndef _WIN32 >+ EXPECT_EXIT(InstallHandlerAndRaise(signo), testing::KilledBySignal(signo), >+ exit_regex); >+#else >+ // Windows doesn't have testing::KilledBySignal(). >+ EXPECT_DEATH(InstallHandlerAndRaise(signo), exit_regex); >+#endif >+} >+ >+ABSL_CONST_INIT FILE* error_file = nullptr; >+ >+void WriteToErrorFile(const char* msg) { >+ if (msg != nullptr) { >+ ABSL_RAW_CHECK(fwrite(msg, strlen(msg), 1, error_file) == 1, >+ "fwrite() failed"); >+ } >+ ABSL_RAW_CHECK(fflush(error_file) == 0, "fflush() failed"); >+} >+ >+std::string GetTmpDir() { >+ // TEST_TMPDIR is set by Bazel. Try the others when not running under Bazel. >+ static const char* const kTmpEnvVars[] = {"TEST_TMPDIR", "TMPDIR", "TEMP", >+ "TEMPDIR", "TMP"}; >+ for (const char* const var : kTmpEnvVars) { >+ const char* tmp_dir = std::getenv(var); >+ if (tmp_dir != nullptr) { >+ return tmp_dir; >+ } >+ } >+ >+ // Try something reasonable. >+ return "/tmp"; >+} >+ >+// This function runs in a fork()ed process on most systems. >+void InstallHandlerWithWriteToFileAndRaise(const char* file, int signo) { >+ error_file = fopen(file, "w"); >+ ABSL_RAW_CHECK(error_file != nullptr, "Failed create error_file"); >+ absl::FailureSignalHandlerOptions options; >+ options.writerfn = WriteToErrorFile; >+ absl::InstallFailureSignalHandler(options); >+ raise(signo); >+} >+ >+TEST_P(FailureSignalHandlerDeathTest, AbslFatalSignalsWithWriterFn) { >+ const int signo = GetParam(); >+ std::string tmp_dir = GetTmpDir(); >+ std::string file = absl::StrCat(tmp_dir, "/signo_", signo); >+ >+ std::string exit_regex = absl::StrCat( >+ "\\*\\*\\* ", absl::debugging_internal::FailureSignalToString(signo), >+ " received at time="); >+#ifndef _WIN32 >+ EXPECT_EXIT(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), >+ testing::KilledBySignal(signo), exit_regex); >+#else >+ // Windows doesn't have testing::KilledBySignal(). >+ EXPECT_DEATH(InstallHandlerWithWriteToFileAndRaise(file.c_str(), signo), >+ exit_regex); >+#endif >+ >+ // Open the file in this process and check its contents. >+ std::fstream error_output(file); >+ ASSERT_TRUE(error_output.is_open()) << file; >+ std::string error_line; >+ std::getline(error_output, error_line); >+ EXPECT_TRUE(absl::StartsWith( >+ error_line, >+ absl::StrCat("*** ", >+ absl::debugging_internal::FailureSignalToString(signo), >+ " received at "))); >+ >+ if (absl::debugging_internal::StackTraceWorksForTest()) { >+ std::getline(error_output, error_line); >+ EXPECT_TRUE(absl::StartsWith(error_line, "PC: ")); >+ } >+} >+ >+constexpr int kFailureSignals[] = { >+ SIGSEGV, SIGILL, SIGFPE, SIGABRT, SIGTERM, >+#ifndef _WIN32 >+ SIGBUS, SIGTRAP, >+#endif >+}; >+ >+std::string SignalParamToString(const ::testing::TestParamInfo<int>& info) { >+ std::string result = absl::debugging_internal::FailureSignalToString(info.param); >+ if (result.empty()) { >+ result = absl::StrCat(info.param); >+ } >+ return result; >+} >+ >+INSTANTIATE_TEST_CASE_P(AbslDeathTest, FailureSignalHandlerDeathTest, >+ ::testing::ValuesIn(kFailureSignals), >+ SignalParamToString); >+ >+#endif // GTEST_HAS_DEATH_TEST >+ >+} // namespace >+ >+int main(int argc, char** argv) { >+ absl::InitializeSymbolizer(argv[0]); >+ testing::InitGoogleTest(&argc, argv); >+ return RUN_ALL_TESTS(); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc >new file mode 100644 >index 00000000000..7455aa0b416 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc >@@ -0,0 +1,133 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// base::AddressIsReadable() probes an address to see whether it is readable, >+// without faulting. >+ >+#include "absl/debugging/internal/address_is_readable.h" >+ >+#if !defined(__linux__) || defined(__ANDROID__) >+ >+namespace absl { >+namespace debugging_internal { >+ >+// On platforms other than Linux, just return true. >+bool AddressIsReadable(const void* /* addr */) { return true; } >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#else >+ >+#include <fcntl.h> >+#include <sys/syscall.h> >+#include <unistd.h> >+#include <atomic> >+#include <cerrno> >+#include <cstdint> >+ >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Pack a pid and two file descriptors into a 64-bit word, >+// using 16, 24, and 24 bits for each respectively. >+static uint64_t Pack(uint64_t pid, uint64_t read_fd, uint64_t write_fd) { >+ ABSL_RAW_CHECK((read_fd >> 24) == 0 && (write_fd >> 24) == 0, >+ "fd out of range"); >+ return (pid << 48) | ((read_fd & 0xffffff) << 24) | (write_fd & 0xffffff); >+} >+ >+// Unpack x into a pid and two file descriptors, where x was created with >+// Pack(). >+static void Unpack(uint64_t x, int *pid, int *read_fd, int *write_fd) { >+ *pid = x >> 48; >+ *read_fd = (x >> 24) & 0xffffff; >+ *write_fd = x & 0xffffff; >+} >+ >+// Return whether the byte at *addr is readable, without faulting. >+// Save and restores errno. Returns true on systems where >+// unimplemented. >+// This is a namespace-scoped variable for correct zero-initialization. >+static std::atomic<uint64_t> pid_and_fds; // initially 0, an invalid pid. >+bool AddressIsReadable(const void *addr) { >+ int save_errno = errno; >+ // We test whether a byte is readable by using write(). Normally, this would >+ // be done via a cached file descriptor to /dev/null, but linux fails to >+ // check whether the byte is readable when the destination is /dev/null, so >+ // we use a cached pipe. We store the pid of the process that created the >+ // pipe to handle the case where a process forks, and the child closes all >+ // the file descriptors and then calls this routine. This is not perfect: >+ // the child could use the routine, then close all file descriptors and then >+ // use this routine again. But the likely use of this routine is when >+ // crashing, to test the validity of pages when dumping the stack. Beware >+ // that we may leak file descriptors, but we're unlikely to leak many. >+ int bytes_written; >+ int current_pid = getpid() & 0xffff; // we use only the low order 16 bits >+ do { // until we do not get EBADF trying to use file descriptors >+ int pid; >+ int read_fd; >+ int write_fd; >+ uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed); >+ Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); >+ while (current_pid != pid) { >+ int p[2]; >+ // new pipe >+ if (pipe(p) != 0) { >+ ABSL_RAW_LOG(FATAL, "Failed to create pipe, errno=%d", errno); >+ } >+ fcntl(p[0], F_SETFD, FD_CLOEXEC); >+ fcntl(p[1], F_SETFD, FD_CLOEXEC); >+ uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]); >+ if (pid_and_fds.compare_exchange_strong( >+ local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed, >+ std::memory_order_relaxed)) { >+ local_pid_and_fds = new_pid_and_fds; // fds exposed to other threads >+ } else { // fds not exposed to other threads; we can close them. >+ close(p[0]); >+ close(p[1]); >+ local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed); >+ } >+ Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd); >+ } >+ errno = 0; >+ // Use syscall(SYS_write, ...) instead of write() to prevent ASAN >+ // and other checkers from complaining about accesses to arbitrary >+ // memory. >+ do { >+ bytes_written = syscall(SYS_write, write_fd, addr, 1); >+ } while (bytes_written == -1 && errno == EINTR); >+ if (bytes_written == 1) { // remove the byte from the pipe >+ char c; >+ while (read(read_fd, &c, 1) == -1 && errno == EINTR) { >+ } >+ } >+ if (errno == EBADF) { // Descriptors invalid. >+ // If pid_and_fds contains the problematic file descriptors we just used, >+ // this call will forget them, and the loop will try again. >+ pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0, >+ std::memory_order_relaxed, >+ std::memory_order_relaxed); >+ } >+ } while (errno == EBADF); >+ errno = save_errno; >+ return bytes_written == 1; >+} >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.h >new file mode 100644 >index 00000000000..9d48030065c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.h >@@ -0,0 +1,29 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_ >+#define ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_ >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Return whether the byte at *addr is readable, without faulting. >+// Save and restores errno. >+bool AddressIsReadable(const void *addr); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_ADDRESS_IS_READABLE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.cc >new file mode 100644 >index 00000000000..c9ca2f3bdb1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.cc >@@ -0,0 +1,1862 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// For reference check out: >+// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling >+// >+// Note that we only have partial C++11 support yet. >+ >+#include "absl/debugging/internal/demangle.h" >+ >+#include <cstdint> >+#include <cstdio> >+#include <limits> >+ >+namespace absl { >+namespace debugging_internal { >+ >+typedef struct { >+ const char *abbrev; >+ const char *real_name; >+ // Number of arguments in <expression> context, or 0 if disallowed. >+ int arity; >+} AbbrevPair; >+ >+// List of operators from Itanium C++ ABI. >+static const AbbrevPair kOperatorList[] = { >+ // New has special syntax (not currently supported). >+ {"nw", "new", 0}, >+ {"na", "new[]", 0}, >+ >+ // Works except that the 'gs' prefix is not supported. >+ {"dl", "delete", 1}, >+ {"da", "delete[]", 1}, >+ >+ {"ps", "+", 1}, // "positive" >+ {"ng", "-", 1}, // "negative" >+ {"ad", "&", 1}, // "address-of" >+ {"de", "*", 1}, // "dereference" >+ {"co", "~", 1}, >+ >+ {"pl", "+", 2}, >+ {"mi", "-", 2}, >+ {"ml", "*", 2}, >+ {"dv", "/", 2}, >+ {"rm", "%", 2}, >+ {"an", "&", 2}, >+ {"or", "|", 2}, >+ {"eo", "^", 2}, >+ {"aS", "=", 2}, >+ {"pL", "+=", 2}, >+ {"mI", "-=", 2}, >+ {"mL", "*=", 2}, >+ {"dV", "/=", 2}, >+ {"rM", "%=", 2}, >+ {"aN", "&=", 2}, >+ {"oR", "|=", 2}, >+ {"eO", "^=", 2}, >+ {"ls", "<<", 2}, >+ {"rs", ">>", 2}, >+ {"lS", "<<=", 2}, >+ {"rS", ">>=", 2}, >+ {"eq", "==", 2}, >+ {"ne", "!=", 2}, >+ {"lt", "<", 2}, >+ {"gt", ">", 2}, >+ {"le", "<=", 2}, >+ {"ge", ">=", 2}, >+ {"nt", "!", 1}, >+ {"aa", "&&", 2}, >+ {"oo", "||", 2}, >+ {"pp", "++", 1}, >+ {"mm", "--", 1}, >+ {"cm", ",", 2}, >+ {"pm", "->*", 2}, >+ {"pt", "->", 0}, // Special syntax >+ {"cl", "()", 0}, // Special syntax >+ {"ix", "[]", 2}, >+ {"qu", "?", 3}, >+ {"st", "sizeof", 0}, // Special syntax >+ {"sz", "sizeof", 1}, // Not a real operator name, but used in expressions. >+ {nullptr, nullptr, 0}, >+}; >+ >+// List of builtin types from Itanium C++ ABI. >+static const AbbrevPair kBuiltinTypeList[] = { >+ {"v", "void", 0}, >+ {"w", "wchar_t", 0}, >+ {"b", "bool", 0}, >+ {"c", "char", 0}, >+ {"a", "signed char", 0}, >+ {"h", "unsigned char", 0}, >+ {"s", "short", 0}, >+ {"t", "unsigned short", 0}, >+ {"i", "int", 0}, >+ {"j", "unsigned int", 0}, >+ {"l", "long", 0}, >+ {"m", "unsigned long", 0}, >+ {"x", "long long", 0}, >+ {"y", "unsigned long long", 0}, >+ {"n", "__int128", 0}, >+ {"o", "unsigned __int128", 0}, >+ {"f", "float", 0}, >+ {"d", "double", 0}, >+ {"e", "long double", 0}, >+ {"g", "__float128", 0}, >+ {"z", "ellipsis", 0}, >+ {nullptr, nullptr, 0}, >+}; >+ >+// List of substitutions Itanium C++ ABI. >+static const AbbrevPair kSubstitutionList[] = { >+ {"St", "", 0}, >+ {"Sa", "allocator", 0}, >+ {"Sb", "basic_string", 0}, >+ // std::basic_string<char, std::char_traits<char>,std::allocator<char> > >+ {"Ss", "string", 0}, >+ // std::basic_istream<char, std::char_traits<char> > >+ {"Si", "istream", 0}, >+ // std::basic_ostream<char, std::char_traits<char> > >+ {"So", "ostream", 0}, >+ // std::basic_iostream<char, std::char_traits<char> > >+ {"Sd", "iostream", 0}, >+ {nullptr, nullptr, 0}, >+}; >+ >+// State needed for demangling. This struct is copied in almost every stack >+// frame, so every byte counts. >+typedef struct { >+ int mangled_idx; // Cursor of mangled name. >+ int out_cur_idx; // Cursor of output std::string. >+ int prev_name_idx; // For constructors/destructors. >+ signed int prev_name_length : 16; // For constructors/destructors. >+ signed int nest_level : 15; // For nested names. >+ unsigned int append : 1; // Append flag. >+ // Note: for some reason MSVC can't pack "bool append : 1" into the same int >+ // with the above two fields, so we use an int instead. Amusingly it can pack >+ // "signed bool" as expected, but relying on that to continue to be a legal >+ // type seems ill-advised (as it's illegal in at least clang). >+} ParseState; >+ >+static_assert(sizeof(ParseState) == 4 * sizeof(int), >+ "unexpected size of ParseState"); >+ >+// One-off state for demangling that's not subject to backtracking -- either >+// constant data, data that's intentionally immune to backtracking (steps), or >+// data that would never be changed by backtracking anyway (recursion_depth). >+// >+// Only one copy of this exists for each call to Demangle, so the size of this >+// struct is nearly inconsequential. >+typedef struct { >+ const char *mangled_begin; // Beginning of input std::string. >+ char *out; // Beginning of output std::string. >+ int out_end_idx; // One past last allowed output character. >+ int recursion_depth; // For stack exhaustion prevention. >+ int steps; // Cap how much work we'll do, regardless of depth. >+ ParseState parse_state; // Backtrackable state copied for most frames. >+} State; >+ >+namespace { >+// Prevent deep recursion / stack exhaustion. >+// Also prevent unbounded handling of complex inputs. >+class ComplexityGuard { >+ public: >+ explicit ComplexityGuard(State *state) : state_(state) { >+ ++state->recursion_depth; >+ ++state->steps; >+ } >+ ~ComplexityGuard() { --state_->recursion_depth; } >+ >+ // 256 levels of recursion seems like a reasonable upper limit on depth. >+ // 128 is not enough to demagle synthetic tests from demangle_unittest.txt: >+ // "_ZaaZZZZ..." and "_ZaaZcvZcvZ..." >+ static constexpr int kRecursionDepthLimit = 256; >+ >+ // We're trying to pick a charitable upper-limit on how many parse steps are >+ // necessary to handle something that a human could actually make use of. >+ // This is mostly in place as a bound on how much work we'll do if we are >+ // asked to demangle an mangled name from an untrusted source, so it should be >+ // much larger than the largest expected symbol, but much smaller than the >+ // amount of work we can do in, e.g., a second. >+ // >+ // Some real-world symbols from an arbitrary binary started failing between >+ // 2^12 and 2^13, so we multiply the latter by an extra factor of 16 to set >+ // the limit. >+ // >+ // Spending one second on 2^17 parse steps would require each step to take >+ // 7.6us, or ~30000 clock cycles, so it's safe to say this can be done in >+ // under a second. >+ static constexpr int kParseStepsLimit = 1 << 17; >+ >+ bool IsTooComplex() const { >+ return state_->recursion_depth > kRecursionDepthLimit || >+ state_->steps > kParseStepsLimit; >+ } >+ >+ private: >+ State *state_; >+}; >+} // namespace >+ >+// We don't use strlen() in libc since it's not guaranteed to be async >+// signal safe. >+static size_t StrLen(const char *str) { >+ size_t len = 0; >+ while (*str != '\0') { >+ ++str; >+ ++len; >+ } >+ return len; >+} >+ >+// Returns true if "str" has at least "n" characters remaining. >+static bool AtLeastNumCharsRemaining(const char *str, int n) { >+ for (int i = 0; i < n; ++i) { >+ if (str[i] == '\0') { >+ return false; >+ } >+ } >+ return true; >+} >+ >+// Returns true if "str" has "prefix" as a prefix. >+static bool StrPrefix(const char *str, const char *prefix) { >+ size_t i = 0; >+ while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) { >+ ++i; >+ } >+ return prefix[i] == '\0'; // Consumed everything in "prefix". >+} >+ >+static void InitState(State *state, const char *mangled, char *out, >+ int out_size) { >+ state->mangled_begin = mangled; >+ state->out = out; >+ state->out_end_idx = out_size; >+ state->recursion_depth = 0; >+ state->steps = 0; >+ >+ state->parse_state.mangled_idx = 0; >+ state->parse_state.out_cur_idx = 0; >+ state->parse_state.prev_name_idx = 0; >+ state->parse_state.prev_name_length = -1; >+ state->parse_state.nest_level = -1; >+ state->parse_state.append = true; >+} >+ >+static inline const char *RemainingInput(State *state) { >+ return &state->mangled_begin[state->parse_state.mangled_idx]; >+} >+ >+// Returns true and advances "mangled_idx" if we find "one_char_token" >+// at "mangled_idx" position. It is assumed that "one_char_token" does >+// not contain '\0'. >+static bool ParseOneCharToken(State *state, const char one_char_token) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (RemainingInput(state)[0] == one_char_token) { >+ ++state->parse_state.mangled_idx; >+ return true; >+ } >+ return false; >+} >+ >+// Returns true and advances "mangled_cur" if we find "two_char_token" >+// at "mangled_cur" position. It is assumed that "two_char_token" does >+// not contain '\0'. >+static bool ParseTwoCharToken(State *state, const char *two_char_token) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (RemainingInput(state)[0] == two_char_token[0] && >+ RemainingInput(state)[1] == two_char_token[1]) { >+ state->parse_state.mangled_idx += 2; >+ return true; >+ } >+ return false; >+} >+ >+// Returns true and advances "mangled_cur" if we find any character in >+// "char_class" at "mangled_cur" position. >+static bool ParseCharClass(State *state, const char *char_class) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (RemainingInput(state)[0] == '\0') { >+ return false; >+ } >+ const char *p = char_class; >+ for (; *p != '\0'; ++p) { >+ if (RemainingInput(state)[0] == *p) { >+ ++state->parse_state.mangled_idx; >+ return true; >+ } >+ } >+ return false; >+} >+ >+static bool ParseDigit(State *state, int *digit) { >+ char c = RemainingInput(state)[0]; >+ if (ParseCharClass(state, "0123456789")) { >+ if (digit != nullptr) { >+ *digit = c - '0'; >+ } >+ return true; >+ } >+ return false; >+} >+ >+// This function is used for handling an optional non-terminal. >+static bool Optional(bool /*status*/) { return true; } >+ >+// This function is used for handling <non-terminal>+ syntax. >+typedef bool (*ParseFunc)(State *); >+static bool OneOrMore(ParseFunc parse_func, State *state) { >+ if (parse_func(state)) { >+ while (parse_func(state)) { >+ } >+ return true; >+ } >+ return false; >+} >+ >+// This function is used for handling <non-terminal>* syntax. The function >+// always returns true and must be followed by a termination token or a >+// terminating sequence not handled by parse_func (e.g. >+// ParseOneCharToken(state, 'E')). >+static bool ZeroOrMore(ParseFunc parse_func, State *state) { >+ while (parse_func(state)) { >+ } >+ return true; >+} >+ >+// Append "str" at "out_cur_idx". If there is an overflow, out_cur_idx is >+// set to out_end_idx+1. The output std::string is ensured to >+// always terminate with '\0' as long as there is no overflow. >+static void Append(State *state, const char *const str, const int length) { >+ for (int i = 0; i < length; ++i) { >+ if (state->parse_state.out_cur_idx + 1 < >+ state->out_end_idx) { // +1 for '\0' >+ state->out[state->parse_state.out_cur_idx++] = str[i]; >+ } else { >+ // signal overflow >+ state->parse_state.out_cur_idx = state->out_end_idx + 1; >+ break; >+ } >+ } >+ if (state->parse_state.out_cur_idx < state->out_end_idx) { >+ state->out[state->parse_state.out_cur_idx] = >+ '\0'; // Terminate it with '\0' >+ } >+} >+ >+// We don't use equivalents in libc to avoid locale issues. >+static bool IsLower(char c) { return c >= 'a' && c <= 'z'; } >+ >+static bool IsAlpha(char c) { >+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); >+} >+ >+static bool IsDigit(char c) { return c >= '0' && c <= '9'; } >+ >+// Returns true if "str" is a function clone suffix. These suffixes are used >+// by GCC 4.5.x and later versions (and our locally-modified version of GCC >+// 4.4.x) to indicate functions which have been cloned during optimization. >+// We treat any sequence (.<alpha>+.<digit>+)+ as a function clone suffix. >+static bool IsFunctionCloneSuffix(const char *str) { >+ size_t i = 0; >+ while (str[i] != '\0') { >+ // Consume a single .<alpha>+.<digit>+ sequence. >+ if (str[i] != '.' || !IsAlpha(str[i + 1])) { >+ return false; >+ } >+ i += 2; >+ while (IsAlpha(str[i])) { >+ ++i; >+ } >+ if (str[i] != '.' || !IsDigit(str[i + 1])) { >+ return false; >+ } >+ i += 2; >+ while (IsDigit(str[i])) { >+ ++i; >+ } >+ } >+ return true; // Consumed everything in "str". >+} >+ >+static bool EndsWith(State *state, const char chr) { >+ return state->parse_state.out_cur_idx > 0 && >+ chr == state->out[state->parse_state.out_cur_idx - 1]; >+} >+ >+// Append "str" with some tweaks, iff "append" state is true. >+static void MaybeAppendWithLength(State *state, const char *const str, >+ const int length) { >+ if (state->parse_state.append && length > 0) { >+ // Append a space if the output buffer ends with '<' and "str" >+ // starts with '<' to avoid <<<. >+ if (str[0] == '<' && EndsWith(state, '<')) { >+ Append(state, " ", 1); >+ } >+ // Remember the last identifier name for ctors/dtors. >+ if (IsAlpha(str[0]) || str[0] == '_') { >+ state->parse_state.prev_name_idx = state->parse_state.out_cur_idx; >+ state->parse_state.prev_name_length = length; >+ } >+ Append(state, str, length); >+ } >+} >+ >+// Appends a positive decimal number to the output if appending is enabled. >+static bool MaybeAppendDecimal(State *state, unsigned int val) { >+ // Max {32-64}-bit unsigned int is 20 digits. >+ constexpr size_t kMaxLength = 20; >+ char buf[kMaxLength]; >+ >+ // We can't use itoa or sprintf as neither is specified to be >+ // async-signal-safe. >+ if (state->parse_state.append) { >+ // We can't have a one-before-the-beginning pointer, so instead start with >+ // one-past-the-end and manipulate one character before the pointer. >+ char *p = &buf[kMaxLength]; >+ do { // val=0 is the only input that should write a leading zero digit. >+ *--p = (val % 10) + '0'; >+ val /= 10; >+ } while (p > buf && val != 0); >+ >+ // 'p' landed on the last character we set. How convenient. >+ Append(state, p, kMaxLength - (p - buf)); >+ } >+ >+ return true; >+} >+ >+// A convenient wrapper around MaybeAppendWithLength(). >+// Returns true so that it can be placed in "if" conditions. >+static bool MaybeAppend(State *state, const char *const str) { >+ if (state->parse_state.append) { >+ int length = StrLen(str); >+ MaybeAppendWithLength(state, str, length); >+ } >+ return true; >+} >+ >+// This function is used for handling nested names. >+static bool EnterNestedName(State *state) { >+ state->parse_state.nest_level = 0; >+ return true; >+} >+ >+// This function is used for handling nested names. >+static bool LeaveNestedName(State *state, int16_t prev_value) { >+ state->parse_state.nest_level = prev_value; >+ return true; >+} >+ >+// Disable the append mode not to print function parameters, etc. >+static bool DisableAppend(State *state) { >+ state->parse_state.append = false; >+ return true; >+} >+ >+// Restore the append mode to the previous state. >+static bool RestoreAppend(State *state, bool prev_value) { >+ state->parse_state.append = prev_value; >+ return true; >+} >+ >+// Increase the nest level for nested names. >+static void MaybeIncreaseNestLevel(State *state) { >+ if (state->parse_state.nest_level > -1) { >+ ++state->parse_state.nest_level; >+ } >+} >+ >+// Appends :: for nested names if necessary. >+static void MaybeAppendSeparator(State *state) { >+ if (state->parse_state.nest_level >= 1) { >+ MaybeAppend(state, "::"); >+ } >+} >+ >+// Cancel the last separator if necessary. >+static void MaybeCancelLastSeparator(State *state) { >+ if (state->parse_state.nest_level >= 1 && state->parse_state.append && >+ state->parse_state.out_cur_idx >= 2) { >+ state->parse_state.out_cur_idx -= 2; >+ state->out[state->parse_state.out_cur_idx] = '\0'; >+ } >+} >+ >+// Returns true if the identifier of the given length pointed to by >+// "mangled_cur" is anonymous namespace. >+static bool IdentifierIsAnonymousNamespace(State *state, int length) { >+ // Returns true if "anon_prefix" is a proper prefix of "mangled_cur". >+ static const char anon_prefix[] = "_GLOBAL__N_"; >+ return (length > static_cast<int>(sizeof(anon_prefix) - 1) && >+ StrPrefix(RemainingInput(state), anon_prefix)); >+} >+ >+// Forward declarations of our parsing functions. >+static bool ParseMangledName(State *state); >+static bool ParseEncoding(State *state); >+static bool ParseName(State *state); >+static bool ParseUnscopedName(State *state); >+static bool ParseNestedName(State *state); >+static bool ParsePrefix(State *state); >+static bool ParseUnqualifiedName(State *state); >+static bool ParseSourceName(State *state); >+static bool ParseLocalSourceName(State *state); >+static bool ParseUnnamedTypeName(State *state); >+static bool ParseNumber(State *state, int *number_out); >+static bool ParseFloatNumber(State *state); >+static bool ParseSeqId(State *state); >+static bool ParseIdentifier(State *state, int length); >+static bool ParseOperatorName(State *state, int *arity); >+static bool ParseSpecialName(State *state); >+static bool ParseCallOffset(State *state); >+static bool ParseNVOffset(State *state); >+static bool ParseVOffset(State *state); >+static bool ParseCtorDtorName(State *state); >+static bool ParseDecltype(State *state); >+static bool ParseType(State *state); >+static bool ParseCVQualifiers(State *state); >+static bool ParseBuiltinType(State *state); >+static bool ParseFunctionType(State *state); >+static bool ParseBareFunctionType(State *state); >+static bool ParseClassEnumType(State *state); >+static bool ParseArrayType(State *state); >+static bool ParsePointerToMemberType(State *state); >+static bool ParseTemplateParam(State *state); >+static bool ParseTemplateTemplateParam(State *state); >+static bool ParseTemplateArgs(State *state); >+static bool ParseTemplateArg(State *state); >+static bool ParseBaseUnresolvedName(State *state); >+static bool ParseUnresolvedName(State *state); >+static bool ParseExpression(State *state); >+static bool ParseExprPrimary(State *state); >+static bool ParseExprCastValue(State *state); >+static bool ParseLocalName(State *state); >+static bool ParseLocalNameSuffix(State *state); >+static bool ParseDiscriminator(State *state); >+static bool ParseSubstitution(State *state, bool accept_std); >+ >+// Implementation note: the following code is a straightforward >+// translation of the Itanium C++ ABI defined in BNF with a couple of >+// exceptions. >+// >+// - Support GNU extensions not defined in the Itanium C++ ABI >+// - <prefix> and <template-prefix> are combined to avoid infinite loop >+// - Reorder patterns to shorten the code >+// - Reorder patterns to give greedier functions precedence >+// We'll mark "Less greedy than" for these cases in the code >+// >+// Each parsing function changes the parse state and returns true on >+// success, or returns false and doesn't change the parse state (note: >+// the parse-steps counter increases regardless of success or failure). >+// To ensure that the parse state isn't changed in the latter case, we >+// save the original state before we call multiple parsing functions >+// consecutively with &&, and restore it if unsuccessful. See >+// ParseEncoding() as an example of this convention. We follow the >+// convention throughout the code. >+// >+// Originally we tried to do demangling without following the full ABI >+// syntax but it turned out we needed to follow the full syntax to >+// parse complicated cases like nested template arguments. Note that >+// implementing a full-fledged demangler isn't trivial (libiberty's >+// cp-demangle.c has +4300 lines). >+// >+// Note that (foo) in <(foo) ...> is a modifier to be ignored. >+// >+// Reference: >+// - Itanium C++ ABI >+// <https://mentorembedded.github.io/cxx-abi/abi.html#mangling> >+ >+// <mangled-name> ::= _Z <encoding> >+static bool ParseMangledName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ return ParseTwoCharToken(state, "_Z") && ParseEncoding(state); >+} >+ >+// <encoding> ::= <(function) name> <bare-function-type> >+// ::= <(data) name> >+// ::= <special-name> >+static bool ParseEncoding(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ // Implementing the first two productions together as <name> >+ // [<bare-function-type>] avoids exponential blowup of backtracking. >+ // >+ // Since Optional(...) can't fail, there's no need to copy the state for >+ // backtracking. >+ if (ParseName(state) && Optional(ParseBareFunctionType(state))) { >+ return true; >+ } >+ >+ if (ParseSpecialName(state)) { >+ return true; >+ } >+ return false; >+} >+ >+// <name> ::= <nested-name> >+// ::= <unscoped-template-name> <template-args> >+// ::= <unscoped-name> >+// ::= <local-name> >+static bool ParseName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseNestedName(state) || ParseLocalName(state)) { >+ return true; >+ } >+ >+ // We reorganize the productions to avoid re-parsing unscoped names. >+ // - Inline <unscoped-template-name> productions: >+ // <name> ::= <substitution> <template-args> >+ // ::= <unscoped-name> <template-args> >+ // ::= <unscoped-name> >+ // - Merge the two productions that start with unscoped-name: >+ // <name> ::= <unscoped-name> [<template-args>] >+ >+ ParseState copy = state->parse_state; >+ // "std<...>" isn't a valid name. >+ if (ParseSubstitution(state, /*accept_std=*/false) && >+ ParseTemplateArgs(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Note there's no need to restore state after this since only the first >+ // subparser can fail. >+ return ParseUnscopedName(state) && Optional(ParseTemplateArgs(state)); >+} >+ >+// <unscoped-name> ::= <unqualified-name> >+// ::= St <unqualified-name> >+static bool ParseUnscopedName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseUnqualifiedName(state)) { >+ return true; >+ } >+ >+ ParseState copy = state->parse_state; >+ if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") && >+ ParseUnqualifiedName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <ref-qualifer> ::= R // lvalue method reference qualifier >+// ::= O // rvalue method reference qualifier >+static inline bool ParseRefQualifier(State *state) { >+ return ParseCharClass(state, "OR"); >+} >+ >+// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> >+// <unqualified-name> E >+// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> >+// <template-args> E >+static bool ParseNestedName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'N') && EnterNestedName(state) && >+ Optional(ParseCVQualifiers(state)) && >+ Optional(ParseRefQualifier(state)) && ParsePrefix(state) && >+ LeaveNestedName(state, copy.nest_level) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// This part is tricky. If we literally translate them to code, we'll >+// end up infinite loop. Hence we merge them to avoid the case. >+// >+// <prefix> ::= <prefix> <unqualified-name> >+// ::= <template-prefix> <template-args> >+// ::= <template-param> >+// ::= <substitution> >+// ::= # empty >+// <template-prefix> ::= <prefix> <(template) unqualified-name> >+// ::= <template-param> >+// ::= <substitution> >+static bool ParsePrefix(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ bool has_something = false; >+ while (true) { >+ MaybeAppendSeparator(state); >+ if (ParseTemplateParam(state) || >+ ParseSubstitution(state, /*accept_std=*/true) || >+ ParseUnscopedName(state) || >+ (ParseOneCharToken(state, 'M') && ParseUnnamedTypeName(state))) { >+ has_something = true; >+ MaybeIncreaseNestLevel(state); >+ continue; >+ } >+ MaybeCancelLastSeparator(state); >+ if (has_something && ParseTemplateArgs(state)) { >+ return ParsePrefix(state); >+ } else { >+ break; >+ } >+ } >+ return true; >+} >+ >+// <unqualified-name> ::= <operator-name> >+// ::= <ctor-dtor-name> >+// ::= <source-name> >+// ::= <local-source-name> // GCC extension; see below. >+// ::= <unnamed-type-name> >+static bool ParseUnqualifiedName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ return (ParseOperatorName(state, nullptr) || ParseCtorDtorName(state) || >+ ParseSourceName(state) || ParseLocalSourceName(state) || >+ ParseUnnamedTypeName(state)); >+} >+ >+// <source-name> ::= <positive length number> <identifier> >+static bool ParseSourceName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ int length = -1; >+ if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <local-source-name> ::= L <source-name> [<discriminator>] >+// >+// References: >+// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 >+// http://gcc.gnu.org/viewcvs?view=rev&revision=124467 >+static bool ParseLocalSourceName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'L') && ParseSourceName(state) && >+ Optional(ParseDiscriminator(state))) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <unnamed-type-name> ::= Ut [<(nonnegative) number>] _ >+// ::= <closure-type-name> >+// <closure-type-name> ::= Ul <lambda-sig> E [<(nonnegative) number>] _ >+// <lambda-sig> ::= <(parameter) type>+ >+static bool ParseUnnamedTypeName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ // Type's 1-based index n is encoded as { "", n == 1; itoa(n-2), otherwise }. >+ // Optionally parse the encoded value into 'which' and add 2 to get the index. >+ int which = -1; >+ >+ // Unnamed type local to function or class. >+ if (ParseTwoCharToken(state, "Ut") && Optional(ParseNumber(state, &which)) && >+ which <= std::numeric_limits<int>::max() - 2 && // Don't overflow. >+ ParseOneCharToken(state, '_')) { >+ MaybeAppend(state, "{unnamed type#"); >+ MaybeAppendDecimal(state, 2 + which); >+ MaybeAppend(state, "}"); >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Closure type. >+ which = -1; >+ if (ParseTwoCharToken(state, "Ul") && DisableAppend(state) && >+ OneOrMore(ParseType, state) && RestoreAppend(state, copy.append) && >+ ParseOneCharToken(state, 'E') && Optional(ParseNumber(state, &which)) && >+ which <= std::numeric_limits<int>::max() - 2 && // Don't overflow. >+ ParseOneCharToken(state, '_')) { >+ MaybeAppend(state, "{lambda()#"); >+ MaybeAppendDecimal(state, 2 + which); >+ MaybeAppend(state, "}"); >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <number> ::= [n] <non-negative decimal integer> >+// If "number_out" is non-null, then *number_out is set to the value of the >+// parsed number on success. >+static bool ParseNumber(State *state, int *number_out) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ bool negative = false; >+ if (ParseOneCharToken(state, 'n')) { >+ negative = true; >+ } >+ const char *p = RemainingInput(state); >+ uint64_t number = 0; >+ for (; *p != '\0'; ++p) { >+ if (IsDigit(*p)) { >+ number = number * 10 + (*p - '0'); >+ } else { >+ break; >+ } >+ } >+ // Apply the sign with uint64_t arithmetic so overflows aren't UB. Gives >+ // "incorrect" results for out-of-range inputs, but negative values only >+ // appear for literals, which aren't printed. >+ if (negative) { >+ number = ~number + 1; >+ } >+ if (p != RemainingInput(state)) { // Conversion succeeded. >+ state->parse_state.mangled_idx += p - RemainingInput(state); >+ if (number_out != nullptr) { >+ // Note: possibly truncate "number". >+ *number_out = number; >+ } >+ return true; >+ } >+ return false; >+} >+ >+// Floating-point literals are encoded using a fixed-length lowercase >+// hexadecimal std::string. >+static bool ParseFloatNumber(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ const char *p = RemainingInput(state); >+ for (; *p != '\0'; ++p) { >+ if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) { >+ break; >+ } >+ } >+ if (p != RemainingInput(state)) { // Conversion succeeded. >+ state->parse_state.mangled_idx += p - RemainingInput(state); >+ return true; >+ } >+ return false; >+} >+ >+// The <seq-id> is a sequence number in base 36, >+// using digits and upper case letters >+static bool ParseSeqId(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ const char *p = RemainingInput(state); >+ for (; *p != '\0'; ++p) { >+ if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) { >+ break; >+ } >+ } >+ if (p != RemainingInput(state)) { // Conversion succeeded. >+ state->parse_state.mangled_idx += p - RemainingInput(state); >+ return true; >+ } >+ return false; >+} >+ >+// <identifier> ::= <unqualified source code identifier> (of given length) >+static bool ParseIdentifier(State *state, int length) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (length < 0 || !AtLeastNumCharsRemaining(RemainingInput(state), length)) { >+ return false; >+ } >+ if (IdentifierIsAnonymousNamespace(state, length)) { >+ MaybeAppend(state, "(anonymous namespace)"); >+ } else { >+ MaybeAppendWithLength(state, RemainingInput(state), length); >+ } >+ state->parse_state.mangled_idx += length; >+ return true; >+} >+ >+// <operator-name> ::= nw, and other two letters cases >+// ::= cv <type> # (cast) >+// ::= v <digit> <source-name> # vendor extended operator >+static bool ParseOperatorName(State *state, int *arity) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (!AtLeastNumCharsRemaining(RemainingInput(state), 2)) { >+ return false; >+ } >+ // First check with "cv" (cast) case. >+ ParseState copy = state->parse_state; >+ if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") && >+ EnterNestedName(state) && ParseType(state) && >+ LeaveNestedName(state, copy.nest_level)) { >+ if (arity != nullptr) { >+ *arity = 1; >+ } >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Then vendor extended operators. >+ if (ParseOneCharToken(state, 'v') && ParseDigit(state, arity) && >+ ParseSourceName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Other operator names should start with a lower alphabet followed >+ // by a lower/upper alphabet. >+ if (!(IsLower(RemainingInput(state)[0]) && >+ IsAlpha(RemainingInput(state)[1]))) { >+ return false; >+ } >+ // We may want to perform a binary search if we really need speed. >+ const AbbrevPair *p; >+ for (p = kOperatorList; p->abbrev != nullptr; ++p) { >+ if (RemainingInput(state)[0] == p->abbrev[0] && >+ RemainingInput(state)[1] == p->abbrev[1]) { >+ if (arity != nullptr) { >+ *arity = p->arity; >+ } >+ MaybeAppend(state, "operator"); >+ if (IsLower(*p->real_name)) { // new, delete, etc. >+ MaybeAppend(state, " "); >+ } >+ MaybeAppend(state, p->real_name); >+ state->parse_state.mangled_idx += 2; >+ return true; >+ } >+ } >+ return false; >+} >+ >+// <special-name> ::= TV <type> >+// ::= TT <type> >+// ::= TI <type> >+// ::= TS <type> >+// ::= Tc <call-offset> <call-offset> <(base) encoding> >+// ::= GV <(object) name> >+// ::= T <call-offset> <(base) encoding> >+// G++ extensions: >+// ::= TC <type> <(offset) number> _ <(base) type> >+// ::= TF <type> >+// ::= TJ <type> >+// ::= GR <name> >+// ::= GA <encoding> >+// ::= Th <call-offset> <(base) encoding> >+// ::= Tv <call-offset> <(base) encoding> >+// >+// Note: we don't care much about them since they don't appear in >+// stack traces. The are special data. >+static bool ParseSpecialName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && >+ ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) && >+ ParseCallOffset(state) && ParseEncoding(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "GV") && ParseName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) && >+ ParseEncoding(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // G++ extensions >+ if (ParseTwoCharToken(state, "TC") && ParseType(state) && >+ ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') && >+ DisableAppend(state) && ParseType(state)) { >+ RestoreAppend(state, copy.append); >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") && >+ ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "GR") && ParseName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") && >+ ParseCallOffset(state) && ParseEncoding(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <call-offset> ::= h <nv-offset> _ >+// ::= v <v-offset> _ >+static bool ParseCallOffset(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) && >+ ParseOneCharToken(state, '_')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'v') && ParseVOffset(state) && >+ ParseOneCharToken(state, '_')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <nv-offset> ::= <(offset) number> >+static bool ParseNVOffset(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ return ParseNumber(state, nullptr); >+} >+ >+// <v-offset> ::= <(offset) number> _ <(virtual offset) number> >+static bool ParseVOffset(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') && >+ ParseNumber(state, nullptr)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <ctor-dtor-name> ::= C1 | C2 | C3 >+// ::= D0 | D1 | D2 >+// # GCC extensions: "unified" constructor/destructor. See >+// # https://github.com/gcc-mirror/gcc/blob/7ad17b583c3643bd4557f29b8391ca7ef08391f5/gcc/cp/mangle.c#L1847 >+// ::= C4 | D4 >+static bool ParseCtorDtorName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "1234")) { >+ const char *const prev_name = state->out + state->parse_state.prev_name_idx; >+ MaybeAppendWithLength(state, prev_name, >+ state->parse_state.prev_name_length); >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "0124")) { >+ const char *const prev_name = state->out + state->parse_state.prev_name_idx; >+ MaybeAppend(state, "~"); >+ MaybeAppendWithLength(state, prev_name, >+ state->parse_state.prev_name_length); >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <decltype> ::= Dt <expression> E # decltype of an id-expression or class >+// # member access (C++0x) >+// ::= DT <expression> E # decltype of an expression (C++0x) >+static bool ParseDecltype(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") && >+ ParseExpression(state) && ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <type> ::= <CV-qualifiers> <type> >+// ::= P <type> # pointer-to >+// ::= R <type> # reference-to >+// ::= O <type> # rvalue reference-to (C++0x) >+// ::= C <type> # complex pair (C 2000) >+// ::= G <type> # imaginary (C 2000) >+// ::= U <source-name> <type> # vendor extended type qualifier >+// ::= <builtin-type> >+// ::= <function-type> >+// ::= <class-enum-type> # note: just an alias for <name> >+// ::= <array-type> >+// ::= <pointer-to-member-type> >+// ::= <template-template-param> <template-args> >+// ::= <template-param> >+// ::= <decltype> >+// ::= <substitution> >+// ::= Dp <type> # pack expansion of (C++0x) >+// >+static bool ParseType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ >+ // We should check CV-qualifers, and PRGC things first. >+ // >+ // CV-qualifiers overlap with some operator names, but an operator name is not >+ // valid as a type. To avoid an ambiguity that can lead to exponential time >+ // complexity, refuse to backtrack the CV-qualifiers. >+ // >+ // _Z4aoeuIrMvvE >+ // => _Z 4aoeuI rM v v E >+ // aoeu<operator%=, void, void> >+ // => _Z 4aoeuI r Mv v E >+ // aoeu<void void::* restrict> >+ // >+ // By consuming the CV-qualifiers first, the former parse is disabled. >+ if (ParseCVQualifiers(state)) { >+ const bool result = ParseType(state); >+ if (!result) state->parse_state = copy; >+ return result; >+ } >+ state->parse_state = copy; >+ >+ // Similarly, these tag characters can overlap with other <name>s resulting in >+ // two different parse prefixes that land on <template-args> in the same >+ // place, such as "C3r1xI...". So, disable the "ctor-name = C3" parse by >+ // refusing to backtrack the tag characters. >+ if (ParseCharClass(state, "OPRCG")) { >+ const bool result = ParseType(state); >+ if (!result) state->parse_state = copy; >+ return result; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "Dp") && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'U') && ParseSourceName(state) && >+ ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseBuiltinType(state) || ParseFunctionType(state) || >+ ParseClassEnumType(state) || ParseArrayType(state) || >+ ParsePointerToMemberType(state) || ParseDecltype(state) || >+ // "std" on its own isn't a type. >+ ParseSubstitution(state, /*accept_std=*/false)) { >+ return true; >+ } >+ >+ if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Less greedy than <template-template-param> <template-args>. >+ if (ParseTemplateParam(state)) { >+ return true; >+ } >+ >+ return false; >+} >+ >+// <CV-qualifiers> ::= [r] [V] [K] >+// We don't allow empty <CV-qualifiers> to avoid infinite loop in >+// ParseType(). >+static bool ParseCVQualifiers(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ int num_cv_qualifiers = 0; >+ num_cv_qualifiers += ParseOneCharToken(state, 'r'); >+ num_cv_qualifiers += ParseOneCharToken(state, 'V'); >+ num_cv_qualifiers += ParseOneCharToken(state, 'K'); >+ return num_cv_qualifiers > 0; >+} >+ >+// <builtin-type> ::= v, etc. >+// ::= u <source-name> >+static bool ParseBuiltinType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ const AbbrevPair *p; >+ for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) { >+ if (RemainingInput(state)[0] == p->abbrev[0]) { >+ MaybeAppend(state, p->real_name); >+ ++state->parse_state.mangled_idx; >+ return true; >+ } >+ } >+ >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <function-type> ::= F [Y] <bare-function-type> E >+static bool ParseFunctionType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'F') && >+ Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <bare-function-type> ::= <(signature) type>+ >+static bool ParseBareFunctionType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ DisableAppend(state); >+ if (OneOrMore(ParseType, state)) { >+ RestoreAppend(state, copy.append); >+ MaybeAppend(state, "()"); >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <class-enum-type> ::= <name> >+static bool ParseClassEnumType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ return ParseName(state); >+} >+ >+// <array-type> ::= A <(positive dimension) number> _ <(element) type> >+// ::= A [<(dimension) expression>] _ <(element) type> >+static bool ParseArrayType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) && >+ ParseOneCharToken(state, '_') && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) && >+ ParseOneCharToken(state, '_') && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <pointer-to-member-type> ::= M <(class) type> <(member) type> >+static bool ParsePointerToMemberType(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <template-param> ::= T_ >+// ::= T <parameter-2 non-negative number> _ >+static bool ParseTemplateParam(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseTwoCharToken(state, "T_")) { >+ MaybeAppend(state, "?"); // We don't support template substitutions. >+ return true; >+ } >+ >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'T') && ParseNumber(state, nullptr) && >+ ParseOneCharToken(state, '_')) { >+ MaybeAppend(state, "?"); // We don't support template substitutions. >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <template-template-param> ::= <template-param> >+// ::= <substitution> >+static bool ParseTemplateTemplateParam(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ return (ParseTemplateParam(state) || >+ // "std" on its own isn't a template. >+ ParseSubstitution(state, /*accept_std=*/false)); >+} >+ >+// <template-args> ::= I <template-arg>+ E >+static bool ParseTemplateArgs(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ DisableAppend(state); >+ if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) && >+ ParseOneCharToken(state, 'E')) { >+ RestoreAppend(state, copy.append); >+ MaybeAppend(state, "<>"); >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <template-arg> ::= <type> >+// ::= <expr-primary> >+// ::= J <template-arg>* E # argument pack >+// ::= X <expression> E >+static bool ParseTemplateArg(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'J') && ZeroOrMore(ParseTemplateArg, state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // There can be significant overlap between the following leading to >+ // exponential backtracking: >+ // >+ // <expr-primary> ::= L <type> <expr-cast-value> E >+ // e.g. L 2xxIvE 1 E >+ // <type> ==> <local-source-name> <template-args> >+ // e.g. L 2xx IvE >+ // >+ // This means parsing an entire <type> twice, and <type> can contain >+ // <template-arg>, so this can generate exponential backtracking. There is >+ // only overlap when the remaining input starts with "L <source-name>", so >+ // parse all cases that can start this way jointly to share the common prefix. >+ // >+ // We have: >+ // >+ // <template-arg> ::= <type> >+ // ::= <expr-primary> >+ // >+ // First, drop all the productions of <type> that must start with something >+ // other than 'L'. All that's left is <class-enum-type>; inline it. >+ // >+ // <type> ::= <nested-name> # starts with 'N' >+ // ::= <unscoped-name> >+ // ::= <unscoped-template-name> <template-args> >+ // ::= <local-name> # starts with 'Z' >+ // >+ // Drop and inline again: >+ // >+ // <type> ::= <unscoped-name> >+ // ::= <unscoped-name> <template-args> >+ // ::= <substitution> <template-args> # starts with 'S' >+ // >+ // Merge the first two, inline <unscoped-name>, drop last: >+ // >+ // <type> ::= <unqualified-name> [<template-args>] >+ // ::= St <unqualified-name> [<template-args>] # starts with 'S' >+ // >+ // Drop and inline: >+ // >+ // <type> ::= <operator-name> [<template-args>] # starts with lowercase >+ // ::= <ctor-dtor-name> [<template-args>] # starts with 'C' or 'D' >+ // ::= <source-name> [<template-args>] # starts with digit >+ // ::= <local-source-name> [<template-args>] >+ // ::= <unnamed-type-name> [<template-args>] # starts with 'U' >+ // >+ // One more time: >+ // >+ // <type> ::= L <source-name> [<template-args>] >+ // >+ // Likewise with <expr-primary>: >+ // >+ // <expr-primary> ::= L <type> <expr-cast-value> E >+ // ::= LZ <encoding> E # cannot overlap; drop >+ // ::= L <mangled_name> E # cannot overlap; drop >+ // >+ // By similar reasoning as shown above, the only <type>s starting with >+ // <source-name> are "<source-name> [<template-args>]". Inline this. >+ // >+ // <expr-primary> ::= L <source-name> [<template-args>] <expr-cast-value> E >+ // >+ // Now inline both of these into <template-arg>: >+ // >+ // <template-arg> ::= L <source-name> [<template-args>] >+ // ::= L <source-name> [<template-args>] <expr-cast-value> E >+ // >+ // Merge them and we're done: >+ // <template-arg> >+ // ::= L <source-name> [<template-args>] [<expr-cast-value> E] >+ if (ParseLocalSourceName(state) && Optional(ParseTemplateArgs(state))) { >+ copy = state->parse_state; >+ if (ParseExprCastValue(state) && ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ return true; >+ } >+ >+ // Now that the overlapping cases can't reach this code, we can safely call >+ // both of these. >+ if (ParseType(state) || ParseExprPrimary(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'X') && ParseExpression(state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <unresolved-type> ::= <template-param> [<template-args>] >+// ::= <decltype> >+// ::= <substitution> >+static inline bool ParseUnresolvedType(State *state) { >+ // No ComplexityGuard because we don't copy the state in this stack frame. >+ return (ParseTemplateParam(state) && Optional(ParseTemplateArgs(state))) || >+ ParseDecltype(state) || ParseSubstitution(state, /*accept_std=*/false); >+} >+ >+// <simple-id> ::= <source-name> [<template-args>] >+static inline bool ParseSimpleId(State *state) { >+ // No ComplexityGuard because we don't copy the state in this stack frame. >+ >+ // Note: <simple-id> cannot be followed by a parameter pack; see comment in >+ // ParseUnresolvedType. >+ return ParseSourceName(state) && Optional(ParseTemplateArgs(state)); >+} >+ >+// <base-unresolved-name> ::= <source-name> [<template-args>] >+// ::= on <operator-name> [<template-args>] >+// ::= dn <destructor-name> >+static bool ParseBaseUnresolvedName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ >+ if (ParseSimpleId(state)) { >+ return true; >+ } >+ >+ ParseState copy = state->parse_state; >+ if (ParseTwoCharToken(state, "on") && ParseOperatorName(state, nullptr) && >+ Optional(ParseTemplateArgs(state))) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "dn") && >+ (ParseUnresolvedType(state) || ParseSimpleId(state))) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <unresolved-name> ::= [gs] <base-unresolved-name> >+// ::= sr <unresolved-type> <base-unresolved-name> >+// ::= srN <unresolved-type> <unresolved-qualifier-level>+ E >+// <base-unresolved-name> >+// ::= [gs] sr <unresolved-qualifier-level>+ E >+// <base-unresolved-name> >+static bool ParseUnresolvedName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ >+ ParseState copy = state->parse_state; >+ if (Optional(ParseTwoCharToken(state, "gs")) && >+ ParseBaseUnresolvedName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "sr") && ParseUnresolvedType(state) && >+ ParseBaseUnresolvedName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseTwoCharToken(state, "sr") && ParseOneCharToken(state, 'N') && >+ ParseUnresolvedType(state) && >+ OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) && >+ ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (Optional(ParseTwoCharToken(state, "gs")) && >+ ParseTwoCharToken(state, "sr") && >+ OneOrMore(/* <unresolved-qualifier-level> ::= */ ParseSimpleId, state) && >+ ParseOneCharToken(state, 'E') && ParseBaseUnresolvedName(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <expression> ::= <1-ary operator-name> <expression> >+// ::= <2-ary operator-name> <expression> <expression> >+// ::= <3-ary operator-name> <expression> <expression> <expression> >+// ::= cl <expression>+ E >+// ::= cv <type> <expression> # type (expression) >+// ::= cv <type> _ <expression>* E # type (expr-list) >+// ::= st <type> >+// ::= <template-param> >+// ::= <function-param> >+// ::= <expr-primary> >+// ::= dt <expression> <unresolved-name> # expr.name >+// ::= pt <expression> <unresolved-name> # expr->name >+// ::= sp <expression> # argument pack expansion >+// ::= sr <type> <unqualified-name> <template-args> >+// ::= sr <type> <unqualified-name> >+// <function-param> ::= fp <(top-level) CV-qualifiers> _ >+// ::= fp <(top-level) CV-qualifiers> <number> _ >+// ::= fL <number> p <(top-level) CV-qualifiers> _ >+// ::= fL <number> p <(top-level) CV-qualifiers> <number> _ >+static bool ParseExpression(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseTemplateParam(state) || ParseExprPrimary(state)) { >+ return true; >+ } >+ >+ // Object/function call expression. >+ ParseState copy = state->parse_state; >+ if (ParseTwoCharToken(state, "cl") && OneOrMore(ParseExpression, state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Function-param expression (level 0). >+ if (ParseTwoCharToken(state, "fp") && Optional(ParseCVQualifiers(state)) && >+ Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Function-param expression (level 1+). >+ if (ParseTwoCharToken(state, "fL") && Optional(ParseNumber(state, nullptr)) && >+ ParseOneCharToken(state, 'p') && Optional(ParseCVQualifiers(state)) && >+ Optional(ParseNumber(state, nullptr)) && ParseOneCharToken(state, '_')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Parse the conversion expressions jointly to avoid re-parsing the <type> in >+ // their common prefix. Parsed as: >+ // <expression> ::= cv <type> <conversion-args> >+ // <conversion-args> ::= _ <expression>* E >+ // ::= <expression> >+ // >+ // Also don't try ParseOperatorName after seeing "cv", since ParseOperatorName >+ // also needs to accept "cv <type>" in other contexts. >+ if (ParseTwoCharToken(state, "cv")) { >+ if (ParseType(state)) { >+ ParseState copy2 = state->parse_state; >+ if (ParseOneCharToken(state, '_') && ZeroOrMore(ParseExpression, state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy2; >+ if (ParseExpression(state)) { >+ return true; >+ } >+ } >+ } else { >+ // Parse unary, binary, and ternary operator expressions jointly, taking >+ // care not to re-parse subexpressions repeatedly. Parse like: >+ // <expression> ::= <operator-name> <expression> >+ // [<one-to-two-expressions>] >+ // <one-to-two-expressions> ::= <expression> [<expression>] >+ int arity = -1; >+ if (ParseOperatorName(state, &arity) && >+ arity > 0 && // 0 arity => disabled. >+ (arity < 3 || ParseExpression(state)) && >+ (arity < 2 || ParseExpression(state)) && >+ (arity < 1 || ParseExpression(state))) { >+ return true; >+ } >+ } >+ state->parse_state = copy; >+ >+ // sizeof type >+ if (ParseTwoCharToken(state, "st") && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Object and pointer member access expressions. >+ if ((ParseTwoCharToken(state, "dt") || ParseTwoCharToken(state, "pt")) && >+ ParseExpression(state) && ParseType(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Parameter pack expansion >+ if (ParseTwoCharToken(state, "sp") && ParseExpression(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return ParseUnresolvedName(state); >+} >+ >+// <expr-primary> ::= L <type> <(value) number> E >+// ::= L <type> <(value) float> E >+// ::= L <mangled-name> E >+// // A bug in g++'s C++ ABI version 2 (-fabi-version=2). >+// ::= LZ <encoding> E >+// >+// Warning, subtle: the "bug" LZ production above is ambiguous with the first >+// production where <type> starts with <local-name>, which can lead to >+// exponential backtracking in two scenarios: >+// >+// - When whatever follows the E in the <local-name> in the first production is >+// not a name, we backtrack the whole <encoding> and re-parse the whole thing. >+// >+// - When whatever follows the <local-name> in the first production is not a >+// number and this <expr-primary> may be followed by a name, we backtrack the >+// <name> and re-parse it. >+// >+// Moreover this ambiguity isn't always resolved -- for example, the following >+// has two different parses: >+// >+// _ZaaILZ4aoeuE1x1EvE >+// => operator&&<aoeu, x, E, void> >+// => operator&&<(aoeu::x)(1), void> >+// >+// To resolve this, we just do what GCC's demangler does, and refuse to parse >+// casts to <local-name> types. >+static bool ParseExprPrimary(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ >+ // The "LZ" special case: if we see LZ, we commit to accept "LZ <encoding> E" >+ // or fail, no backtracking. >+ if (ParseTwoCharToken(state, "LZ")) { >+ if (ParseEncoding(state) && ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ >+ state->parse_state = copy; >+ return false; >+ } >+ >+ // The merged cast production. >+ if (ParseOneCharToken(state, 'L') && ParseType(state) && >+ ParseExprCastValue(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseOneCharToken(state, 'L') && ParseMangledName(state) && >+ ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <number> or <float>, followed by 'E', as described above ParseExprPrimary. >+static bool ParseExprCastValue(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ // We have to be able to backtrack after accepting a number because we could >+ // have e.g. "7fffE", which will accept "7" as a number but then fail to find >+ // the 'E'. >+ ParseState copy = state->parse_state; >+ if (ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ if (ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) { >+ return true; >+ } >+ state->parse_state = copy; >+ >+ return false; >+} >+ >+// <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>] >+// ::= Z <(function) encoding> E s [<discriminator>] >+// >+// Parsing a common prefix of these two productions together avoids an >+// exponential blowup of backtracking. Parse like: >+// <local-name> := Z <encoding> E <local-name-suffix> >+// <local-name-suffix> ::= s [<discriminator>] >+// ::= <name> [<discriminator>] >+ >+static bool ParseLocalNameSuffix(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ >+ if (MaybeAppend(state, "::") && ParseName(state) && >+ Optional(ParseDiscriminator(state))) { >+ return true; >+ } >+ >+ // Since we're not going to overwrite the above "::" by re-parsing the >+ // <encoding> (whose trailing '\0' byte was in the byte now holding the >+ // first ':'), we have to rollback the "::" if the <name> parse failed. >+ if (state->parse_state.append) { >+ state->out[state->parse_state.out_cur_idx - 2] = '\0'; >+ } >+ >+ return ParseOneCharToken(state, 's') && Optional(ParseDiscriminator(state)); >+} >+ >+static bool ParseLocalName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && >+ ParseOneCharToken(state, 'E') && ParseLocalNameSuffix(state)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <discriminator> := _ <(non-negative) number> >+static bool ParseDiscriminator(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) { >+ return true; >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// <substitution> ::= S_ >+// ::= S <seq-id> _ >+// ::= St, etc. >+// >+// "St" is special in that it's not valid as a standalone name, and it *is* >+// allowed to precede a name without being wrapped in "N...E". This means that >+// if we accept it on its own, we can accept "St1a" and try to parse >+// template-args, then fail and backtrack, accept "St" on its own, then "1a" as >+// an unqualified name and re-parse the same template-args. To block this >+// exponential backtracking, we disable it with 'accept_std=false' in >+// problematic contexts. >+static bool ParseSubstitution(State *state, bool accept_std) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseTwoCharToken(state, "S_")) { >+ MaybeAppend(state, "?"); // We don't support substitutions. >+ return true; >+ } >+ >+ ParseState copy = state->parse_state; >+ if (ParseOneCharToken(state, 'S') && ParseSeqId(state) && >+ ParseOneCharToken(state, '_')) { >+ MaybeAppend(state, "?"); // We don't support substitutions. >+ return true; >+ } >+ state->parse_state = copy; >+ >+ // Expand abbreviations like "St" => "std". >+ if (ParseOneCharToken(state, 'S')) { >+ const AbbrevPair *p; >+ for (p = kSubstitutionList; p->abbrev != nullptr; ++p) { >+ if (RemainingInput(state)[0] == p->abbrev[1] && >+ (accept_std || p->abbrev[1] != 't')) { >+ MaybeAppend(state, "std"); >+ if (p->real_name[0] != '\0') { >+ MaybeAppend(state, "::"); >+ MaybeAppend(state, p->real_name); >+ } >+ ++state->parse_state.mangled_idx; >+ return true; >+ } >+ } >+ } >+ state->parse_state = copy; >+ return false; >+} >+ >+// Parse <mangled-name>, optionally followed by either a function-clone suffix >+// or version suffix. Returns true only if all of "mangled_cur" was consumed. >+static bool ParseTopLevelMangledName(State *state) { >+ ComplexityGuard guard(state); >+ if (guard.IsTooComplex()) return false; >+ if (ParseMangledName(state)) { >+ if (RemainingInput(state)[0] != '\0') { >+ // Drop trailing function clone suffix, if any. >+ if (IsFunctionCloneSuffix(RemainingInput(state))) { >+ return true; >+ } >+ // Append trailing version suffix if any. >+ // ex. _Z3foo@@GLIBCXX_3.4 >+ if (RemainingInput(state)[0] == '@') { >+ MaybeAppend(state, RemainingInput(state)); >+ return true; >+ } >+ return false; // Unconsumed suffix. >+ } >+ return true; >+ } >+ return false; >+} >+ >+static bool Overflowed(const State *state) { >+ return state->parse_state.out_cur_idx >= state->out_end_idx; >+} >+ >+// The demangler entry point. >+bool Demangle(const char *mangled, char *out, int out_size) { >+ State state; >+ InitState(&state, mangled, out, out_size); >+ return ParseTopLevelMangledName(&state) && !Overflowed(&state); >+} >+ >+} // namespace debugging_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.h >new file mode 100644 >index 00000000000..2e75564ed35 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle.h >@@ -0,0 +1,67 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI >+// (aka G++ V3 ABI). >+// >+// The demangler is implemented to be used in async signal handlers to >+// symbolize stack traces. We cannot use libstdc++'s >+// abi::__cxa_demangle() in such signal handlers since it's not async >+// signal safe (it uses malloc() internally). >+// >+// Note that this demangler doesn't support full demangling. More >+// specifically, it doesn't print types of function parameters and >+// types of template arguments. It just skips them. However, it's >+// still very useful to extract basic information such as class, >+// function, constructor, destructor, and operator names. >+// >+// See the implementation note in demangle.cc if you are interested. >+// >+// Example: >+// >+// | Mangled Name | The Demangler | abi::__cxa_demangle() >+// |---------------|---------------|----------------------- >+// | _Z1fv | f() | f() >+// | _Z1fi | f() | f(int) >+// | _Z3foo3bar | foo() | foo(bar) >+// | _Z1fIiEvi | f<>() | void f<int>(int) >+// | _ZN1N1fE | N::f | N::f >+// | _ZN3Foo3BarEv | Foo::Bar() | Foo::Bar() >+// | _Zrm1XS_" | operator%() | operator%(X, X) >+// | _ZN3FooC1Ev | Foo::Foo() | Foo::Foo() >+// | _Z1fSs | f() | f(std::basic_string<char, >+// | | | std::char_traits<char>, >+// | | | std::allocator<char> >) >+// >+// See the unit test for more examples. >+// >+// Note: we might want to write demanglers for ABIs other than Itanium >+// C++ ABI in the future. >+// >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ >+#define ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Demangle `mangled`. On success, return true and write the >+// demangled symbol name to `out`. Otherwise, return false. >+// `out` is modified even if demangling is unsuccessful. >+bool Demangle(const char *mangled, char *out, int out_size); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_DEMANGLE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc >new file mode 100644 >index 00000000000..b9d9008f007 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/demangle_test.cc >@@ -0,0 +1,191 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/debugging/internal/demangle.h" >+ >+#include <cstdlib> >+#include <string> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/debugging/internal/stack_consumption.h" >+#include "absl/memory/memory.h" >+ >+namespace absl { >+namespace debugging_internal { >+namespace { >+ >+// A wrapper function for Demangle() to make the unit test simple. >+static const char *DemangleIt(const char * const mangled) { >+ static char demangled[4096]; >+ if (Demangle(mangled, demangled, sizeof(demangled))) { >+ return demangled; >+ } else { >+ return mangled; >+ } >+} >+ >+// Test corner cases of bounary conditions. >+TEST(Demangle, CornerCases) { >+ char tmp[10]; >+ EXPECT_TRUE(Demangle("_Z6foobarv", tmp, sizeof(tmp))); >+ // sizeof("foobar()") == 9 >+ EXPECT_STREQ("foobar()", tmp); >+ EXPECT_TRUE(Demangle("_Z6foobarv", tmp, 9)); >+ EXPECT_STREQ("foobar()", tmp); >+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 8)); // Not enough. >+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 1)); >+ EXPECT_FALSE(Demangle("_Z6foobarv", tmp, 0)); >+ EXPECT_FALSE(Demangle("_Z6foobarv", nullptr, 0)); // Should not cause SEGV. >+ EXPECT_FALSE(Demangle("_Z1000000", tmp, 9)); >+} >+ >+// Test handling of functions suffixed with .clone.N, which is used >+// by GCC 4.5.x (and our locally-modified version of GCC 4.4.x), and >+// .constprop.N and .isra.N, which are used by GCC 4.6.x. These >+// suffixes are used to indicate functions which have been cloned >+// during optimization. We ignore these suffixes. >+TEST(Demangle, Clones) { >+ char tmp[20]; >+ EXPECT_TRUE(Demangle("_ZL3Foov", tmp, sizeof(tmp))); >+ EXPECT_STREQ("Foo()", tmp); >+ EXPECT_TRUE(Demangle("_ZL3Foov.clone.3", tmp, sizeof(tmp))); >+ EXPECT_STREQ("Foo()", tmp); >+ EXPECT_TRUE(Demangle("_ZL3Foov.constprop.80", tmp, sizeof(tmp))); >+ EXPECT_STREQ("Foo()", tmp); >+ EXPECT_TRUE(Demangle("_ZL3Foov.isra.18", tmp, sizeof(tmp))); >+ EXPECT_STREQ("Foo()", tmp); >+ EXPECT_TRUE(Demangle("_ZL3Foov.isra.2.constprop.18", tmp, sizeof(tmp))); >+ EXPECT_STREQ("Foo()", tmp); >+ // Invalid (truncated), should not demangle. >+ EXPECT_FALSE(Demangle("_ZL3Foov.clo", tmp, sizeof(tmp))); >+ // Invalid (.clone. not followed by number), should not demangle. >+ EXPECT_FALSE(Demangle("_ZL3Foov.clone.", tmp, sizeof(tmp))); >+ // Invalid (.clone. followed by non-number), should not demangle. >+ EXPECT_FALSE(Demangle("_ZL3Foov.clone.foo", tmp, sizeof(tmp))); >+ // Invalid (.constprop. not followed by number), should not demangle. >+ EXPECT_FALSE(Demangle("_ZL3Foov.isra.2.constprop.", tmp, sizeof(tmp))); >+} >+ >+// Tests that verify that Demangle footprint is within some limit. >+// They are not to be run under sanitizers as the sanitizers increase >+// stack consumption by about 4x. >+#if defined(ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION) && \ >+ !ADDRESS_SANITIZER && !MEMORY_SANITIZER && !THREAD_SANITIZER >+ >+static const char *g_mangled; >+static char g_demangle_buffer[4096]; >+static char *g_demangle_result; >+ >+static void DemangleSignalHandler(int signo) { >+ if (Demangle(g_mangled, g_demangle_buffer, sizeof(g_demangle_buffer))) { >+ g_demangle_result = g_demangle_buffer; >+ } else { >+ g_demangle_result = nullptr; >+ } >+} >+ >+// Call Demangle and figure out the stack footprint of this call. >+static const char *DemangleStackConsumption(const char *mangled, >+ int *stack_consumed) { >+ g_mangled = mangled; >+ *stack_consumed = GetSignalHandlerStackConsumption(DemangleSignalHandler); >+ ABSL_RAW_LOG(INFO, "Stack consumption of Demangle: %d", *stack_consumed); >+ return g_demangle_result; >+} >+ >+// Demangle stack consumption should be within 8kB for simple mangled names >+// with some level of nesting. With alternate signal stack we have 64K, >+// but some signal handlers run on thread stack, and could have arbitrarily >+// little space left (so we don't want to make this number too large). >+const int kStackConsumptionUpperLimit = 8192; >+ >+// Returns a mangled name nested to the given depth. >+static std::string NestedMangledName(int depth) { >+ std::string mangled_name = "_Z1a"; >+ if (depth > 0) { >+ mangled_name += "IXL"; >+ mangled_name += NestedMangledName(depth - 1); >+ mangled_name += "EEE"; >+ } >+ return mangled_name; >+} >+ >+TEST(Demangle, DemangleStackConsumption) { >+ // Measure stack consumption of Demangle for nested mangled names of varying >+ // depth. Since Demangle is implemented as a recursive descent parser, >+ // stack consumption will grow as the nesting depth increases. By measuring >+ // the stack consumption for increasing depths, we can see the growing >+ // impact of any stack-saving changes made to the code for Demangle. >+ int stack_consumed = 0; >+ >+ const char *demangled = >+ DemangleStackConsumption("_Z6foobarv", &stack_consumed); >+ EXPECT_STREQ("foobar()", demangled); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); >+ >+ const std::string nested_mangled_name0 = NestedMangledName(0); >+ demangled = DemangleStackConsumption(nested_mangled_name0.c_str(), >+ &stack_consumed); >+ EXPECT_STREQ("a", demangled); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); >+ >+ const std::string nested_mangled_name1 = NestedMangledName(1); >+ demangled = DemangleStackConsumption(nested_mangled_name1.c_str(), >+ &stack_consumed); >+ EXPECT_STREQ("a<>", demangled); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); >+ >+ const std::string nested_mangled_name2 = NestedMangledName(2); >+ demangled = DemangleStackConsumption(nested_mangled_name2.c_str(), >+ &stack_consumed); >+ EXPECT_STREQ("a<>", demangled); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); >+ >+ const std::string nested_mangled_name3 = NestedMangledName(3); >+ demangled = DemangleStackConsumption(nested_mangled_name3.c_str(), >+ &stack_consumed); >+ EXPECT_STREQ("a<>", demangled); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); >+} >+ >+#endif // Stack consumption tests >+ >+static void TestOnInput(const char* input) { >+ static const int kOutSize = 1048576; >+ auto out = absl::make_unique<char[]>(kOutSize); >+ Demangle(input, out.get(), kOutSize); >+} >+ >+TEST(DemangleRegression, NegativeLength) { >+ TestOnInput("_ZZn4"); >+} >+TEST(DemangleRegression, DeeplyNestedArrayType) { >+ const int depth = 100000; >+ std::string data = "_ZStI"; >+ data.reserve(data.size() + 3 * depth + 1); >+ for (int i = 0; i < depth; i++) { >+ data += "A1_"; >+ } >+ TestOnInput(data.c_str()); >+} >+ >+} // namespace >+} // namespace debugging_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc >new file mode 100644 >index 00000000000..3f747e7f958 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.cc >@@ -0,0 +1,380 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Allow dynamic symbol lookup in an in-memory Elf image. >+// >+ >+#include "absl/debugging/internal/elf_mem_image.h" >+ >+#ifdef ABSL_HAVE_ELF_MEM_IMAGE // defined in elf_mem_image.h >+ >+#include <string.h> >+#include <cassert> >+#include <cstddef> >+#include "absl/base/internal/raw_logging.h" >+ >+// From binutils/include/elf/common.h (this doesn't appear to be documented >+// anywhere else). >+// >+// /* This flag appears in a Versym structure. It means that the symbol >+// is hidden, and is only visible with an explicit version number. >+// This is a GNU extension. */ >+// #define VERSYM_HIDDEN 0x8000 >+// >+// /* This is the mask for the rest of the Versym information. */ >+// #define VERSYM_VERSION 0x7fff >+ >+#define VERSYM_VERSION 0x7fff >+ >+namespace absl { >+namespace debugging_internal { >+ >+namespace { >+ >+#if __WORDSIZE == 32 >+const int kElfClass = ELFCLASS32; >+int ElfBind(const ElfW(Sym) *symbol) { return ELF32_ST_BIND(symbol->st_info); } >+int ElfType(const ElfW(Sym) *symbol) { return ELF32_ST_TYPE(symbol->st_info); } >+#elif __WORDSIZE == 64 >+const int kElfClass = ELFCLASS64; >+int ElfBind(const ElfW(Sym) *symbol) { return ELF64_ST_BIND(symbol->st_info); } >+int ElfType(const ElfW(Sym) *symbol) { return ELF64_ST_TYPE(symbol->st_info); } >+#else >+const int kElfClass = -1; >+int ElfBind(const ElfW(Sym) *) { >+ ABSL_RAW_LOG(FATAL, "Unexpected word size"); >+ return 0; >+} >+int ElfType(const ElfW(Sym) *) { >+ ABSL_RAW_LOG(FATAL, "Unexpected word size"); >+ return 0; >+} >+#endif >+ >+// Extract an element from one of the ELF tables, cast it to desired type. >+// This is just a simple arithmetic and a glorified cast. >+// Callers are responsible for bounds checking. >+template <typename T> >+const T *GetTableElement(const ElfW(Ehdr) * ehdr, ElfW(Off) table_offset, >+ ElfW(Word) element_size, size_t index) { >+ return reinterpret_cast<const T*>(reinterpret_cast<const char *>(ehdr) >+ + table_offset >+ + index * element_size); >+} >+ >+} // namespace >+ >+// The value of this variable doesn't matter; it's used only for its >+// unique address. >+const int ElfMemImage::kInvalidBaseSentinel = 0; >+ >+ElfMemImage::ElfMemImage(const void *base) { >+ ABSL_RAW_CHECK(base != kInvalidBase, "bad pointer"); >+ Init(base); >+} >+ >+int ElfMemImage::GetNumSymbols() const { >+ if (!hash_) { >+ return 0; >+ } >+ // See http://www.caldera.com/developers/gabi/latest/ch5.dynamic.html#hash >+ return hash_[1]; >+} >+ >+const ElfW(Sym) *ElfMemImage::GetDynsym(int index) const { >+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range"); >+ return dynsym_ + index; >+} >+ >+const ElfW(Versym) *ElfMemImage::GetVersym(int index) const { >+ ABSL_RAW_CHECK(index < GetNumSymbols(), "index out of range"); >+ return versym_ + index; >+} >+ >+const ElfW(Phdr) *ElfMemImage::GetPhdr(int index) const { >+ ABSL_RAW_CHECK(index < ehdr_->e_phnum, "index out of range"); >+ return GetTableElement<ElfW(Phdr)>(ehdr_, >+ ehdr_->e_phoff, >+ ehdr_->e_phentsize, >+ index); >+} >+ >+const char *ElfMemImage::GetDynstr(ElfW(Word) offset) const { >+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range"); >+ return dynstr_ + offset; >+} >+ >+const void *ElfMemImage::GetSymAddr(const ElfW(Sym) *sym) const { >+ if (sym->st_shndx == SHN_UNDEF || sym->st_shndx >= SHN_LORESERVE) { >+ // Symbol corresponds to "special" (e.g. SHN_ABS) section. >+ return reinterpret_cast<const void *>(sym->st_value); >+ } >+ ABSL_RAW_CHECK(link_base_ < sym->st_value, "symbol out of range"); >+ return GetTableElement<char>(ehdr_, 0, 1, sym->st_value - link_base_); >+} >+ >+const ElfW(Verdef) *ElfMemImage::GetVerdef(int index) const { >+ ABSL_RAW_CHECK(0 <= index && static_cast<size_t>(index) <= verdefnum_, >+ "index out of range"); >+ const ElfW(Verdef) *version_definition = verdef_; >+ while (version_definition->vd_ndx < index && version_definition->vd_next) { >+ const char *const version_definition_as_char = >+ reinterpret_cast<const char *>(version_definition); >+ version_definition = >+ reinterpret_cast<const ElfW(Verdef) *>(version_definition_as_char + >+ version_definition->vd_next); >+ } >+ return version_definition->vd_ndx == index ? version_definition : nullptr; >+} >+ >+const ElfW(Verdaux) *ElfMemImage::GetVerdefAux( >+ const ElfW(Verdef) *verdef) const { >+ return reinterpret_cast<const ElfW(Verdaux) *>(verdef+1); >+} >+ >+const char *ElfMemImage::GetVerstr(ElfW(Word) offset) const { >+ ABSL_RAW_CHECK(offset < strsize_, "offset out of range"); >+ return dynstr_ + offset; >+} >+ >+void ElfMemImage::Init(const void *base) { >+ ehdr_ = nullptr; >+ dynsym_ = nullptr; >+ dynstr_ = nullptr; >+ versym_ = nullptr; >+ verdef_ = nullptr; >+ hash_ = nullptr; >+ strsize_ = 0; >+ verdefnum_ = 0; >+ link_base_ = ~0L; // Sentinel: PT_LOAD .p_vaddr can't possibly be this. >+ if (!base) { >+ return; >+ } >+ const char *const base_as_char = reinterpret_cast<const char *>(base); >+ if (base_as_char[EI_MAG0] != ELFMAG0 || base_as_char[EI_MAG1] != ELFMAG1 || >+ base_as_char[EI_MAG2] != ELFMAG2 || base_as_char[EI_MAG3] != ELFMAG3) { >+ assert(false); >+ return; >+ } >+ int elf_class = base_as_char[EI_CLASS]; >+ if (elf_class != kElfClass) { >+ assert(false); >+ return; >+ } >+ switch (base_as_char[EI_DATA]) { >+ case ELFDATA2LSB: { >+ if (__LITTLE_ENDIAN != __BYTE_ORDER) { >+ assert(false); >+ return; >+ } >+ break; >+ } >+ case ELFDATA2MSB: { >+ if (__BIG_ENDIAN != __BYTE_ORDER) { >+ assert(false); >+ return; >+ } >+ break; >+ } >+ default: { >+ assert(false); >+ return; >+ } >+ } >+ >+ ehdr_ = reinterpret_cast<const ElfW(Ehdr) *>(base); >+ const ElfW(Phdr) *dynamic_program_header = nullptr; >+ for (int i = 0; i < ehdr_->e_phnum; ++i) { >+ const ElfW(Phdr) *const program_header = GetPhdr(i); >+ switch (program_header->p_type) { >+ case PT_LOAD: >+ if (!~link_base_) { >+ link_base_ = program_header->p_vaddr; >+ } >+ break; >+ case PT_DYNAMIC: >+ dynamic_program_header = program_header; >+ break; >+ } >+ } >+ if (!~link_base_ || !dynamic_program_header) { >+ assert(false); >+ // Mark this image as not present. Can not recur infinitely. >+ Init(nullptr); >+ return; >+ } >+ ptrdiff_t relocation = >+ base_as_char - reinterpret_cast<const char *>(link_base_); >+ ElfW(Dyn) *dynamic_entry = >+ reinterpret_cast<ElfW(Dyn) *>(dynamic_program_header->p_vaddr + >+ relocation); >+ for (; dynamic_entry->d_tag != DT_NULL; ++dynamic_entry) { >+ const ElfW(Xword) value = dynamic_entry->d_un.d_val + relocation; >+ switch (dynamic_entry->d_tag) { >+ case DT_HASH: >+ hash_ = reinterpret_cast<ElfW(Word) *>(value); >+ break; >+ case DT_SYMTAB: >+ dynsym_ = reinterpret_cast<ElfW(Sym) *>(value); >+ break; >+ case DT_STRTAB: >+ dynstr_ = reinterpret_cast<const char *>(value); >+ break; >+ case DT_VERSYM: >+ versym_ = reinterpret_cast<ElfW(Versym) *>(value); >+ break; >+ case DT_VERDEF: >+ verdef_ = reinterpret_cast<ElfW(Verdef) *>(value); >+ break; >+ case DT_VERDEFNUM: >+ verdefnum_ = dynamic_entry->d_un.d_val; >+ break; >+ case DT_STRSZ: >+ strsize_ = dynamic_entry->d_un.d_val; >+ break; >+ default: >+ // Unrecognized entries explicitly ignored. >+ break; >+ } >+ } >+ if (!hash_ || !dynsym_ || !dynstr_ || !versym_ || >+ !verdef_ || !verdefnum_ || !strsize_) { >+ assert(false); // invalid VDSO >+ // Mark this image as not present. Can not recur infinitely. >+ Init(nullptr); >+ return; >+ } >+} >+ >+bool ElfMemImage::LookupSymbol(const char *name, >+ const char *version, >+ int type, >+ SymbolInfo *info_out) const { >+ for (const SymbolInfo& info : *this) { >+ if (strcmp(info.name, name) == 0 && strcmp(info.version, version) == 0 && >+ ElfType(info.symbol) == type) { >+ if (info_out) { >+ *info_out = info; >+ } >+ return true; >+ } >+ } >+ return false; >+} >+ >+bool ElfMemImage::LookupSymbolByAddress(const void *address, >+ SymbolInfo *info_out) const { >+ for (const SymbolInfo& info : *this) { >+ const char *const symbol_start = >+ reinterpret_cast<const char *>(info.address); >+ const char *const symbol_end = symbol_start + info.symbol->st_size; >+ if (symbol_start <= address && address < symbol_end) { >+ if (info_out) { >+ // Client wants to know details for that symbol (the usual case). >+ if (ElfBind(info.symbol) == STB_GLOBAL) { >+ // Strong symbol; just return it. >+ *info_out = info; >+ return true; >+ } else { >+ // Weak or local. Record it, but keep looking for a strong one. >+ *info_out = info; >+ } >+ } else { >+ // Client only cares if there is an overlapping symbol. >+ return true; >+ } >+ } >+ } >+ return false; >+} >+ >+ElfMemImage::SymbolIterator::SymbolIterator(const void *const image, int index) >+ : index_(index), image_(image) { >+} >+ >+const ElfMemImage::SymbolInfo *ElfMemImage::SymbolIterator::operator->() const { >+ return &info_; >+} >+ >+const ElfMemImage::SymbolInfo& ElfMemImage::SymbolIterator::operator*() const { >+ return info_; >+} >+ >+bool ElfMemImage::SymbolIterator::operator==(const SymbolIterator &rhs) const { >+ return this->image_ == rhs.image_ && this->index_ == rhs.index_; >+} >+ >+bool ElfMemImage::SymbolIterator::operator!=(const SymbolIterator &rhs) const { >+ return !(*this == rhs); >+} >+ >+ElfMemImage::SymbolIterator &ElfMemImage::SymbolIterator::operator++() { >+ this->Update(1); >+ return *this; >+} >+ >+ElfMemImage::SymbolIterator ElfMemImage::begin() const { >+ SymbolIterator it(this, 0); >+ it.Update(0); >+ return it; >+} >+ >+ElfMemImage::SymbolIterator ElfMemImage::end() const { >+ return SymbolIterator(this, GetNumSymbols()); >+} >+ >+void ElfMemImage::SymbolIterator::Update(int increment) { >+ const ElfMemImage *image = reinterpret_cast<const ElfMemImage *>(image_); >+ ABSL_RAW_CHECK(image->IsPresent() || increment == 0, ""); >+ if (!image->IsPresent()) { >+ return; >+ } >+ index_ += increment; >+ if (index_ >= image->GetNumSymbols()) { >+ index_ = image->GetNumSymbols(); >+ return; >+ } >+ const ElfW(Sym) *symbol = image->GetDynsym(index_); >+ const ElfW(Versym) *version_symbol = image->GetVersym(index_); >+ ABSL_RAW_CHECK(symbol && version_symbol, ""); >+ const char *const symbol_name = image->GetDynstr(symbol->st_name); >+ const ElfW(Versym) version_index = version_symbol[0] & VERSYM_VERSION; >+ const ElfW(Verdef) *version_definition = nullptr; >+ const char *version_name = ""; >+ if (symbol->st_shndx == SHN_UNDEF) { >+ // Undefined symbols reference DT_VERNEED, not DT_VERDEF, and >+ // version_index could well be greater than verdefnum_, so calling >+ // GetVerdef(version_index) may trigger assertion. >+ } else { >+ version_definition = image->GetVerdef(version_index); >+ } >+ if (version_definition) { >+ // I am expecting 1 or 2 auxiliary entries: 1 for the version itself, >+ // optional 2nd if the version has a parent. >+ ABSL_RAW_CHECK( >+ version_definition->vd_cnt == 1 || version_definition->vd_cnt == 2, >+ "wrong number of entries"); >+ const ElfW(Verdaux) *version_aux = image->GetVerdefAux(version_definition); >+ version_name = image->GetVerstr(version_aux->vda_name); >+ } >+ info_.name = symbol_name; >+ info_.version = version_name; >+ info_.address = image->GetSymAddr(symbol); >+ info_.symbol = symbol; >+} >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_ELF_MEM_IMAGE >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h >new file mode 100644 >index 00000000000..3b577268954 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/elf_mem_image.h >@@ -0,0 +1,130 @@ >+/* >+ * Copyright 2017 The Abseil Authors. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+// Allow dynamic symbol lookup for in-memory Elf images. >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_ >+#define ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_ >+ >+// Including this will define the __GLIBC__ macro if glibc is being >+// used. >+#include <climits> >+ >+// Maybe one day we can rewrite this file not to require the elf >+// symbol extensions in glibc, but for right now we need them. >+#ifdef ABSL_HAVE_ELF_MEM_IMAGE >+#error ABSL_HAVE_ELF_MEM_IMAGE cannot be directly set >+#endif >+ >+#if defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ >+ !defined(__asmjs__) && !defined(__wasm__) >+#define ABSL_HAVE_ELF_MEM_IMAGE 1 >+#endif >+ >+#if ABSL_HAVE_ELF_MEM_IMAGE >+ >+#include <link.h> // for ElfW >+ >+namespace absl { >+namespace debugging_internal { >+ >+// An in-memory ELF image (may not exist on disk). >+class ElfMemImage { >+ private: >+ // Sentinel: there could never be an elf image at &kInvalidBaseSentinel. >+ static const int kInvalidBaseSentinel; >+ >+ public: >+ // Sentinel: there could never be an elf image at this address. >+ static constexpr const void *const kInvalidBase = >+ static_cast<const void*>(&kInvalidBaseSentinel); >+ >+ // Information about a single vdso symbol. >+ // All pointers are into .dynsym, .dynstr, or .text of the VDSO. >+ // Do not free() them or modify through them. >+ struct SymbolInfo { >+ const char *name; // E.g. "__vdso_getcpu" >+ const char *version; // E.g. "LINUX_2.6", could be "" >+ // for unversioned symbol. >+ const void *address; // Relocated symbol address. >+ const ElfW(Sym) *symbol; // Symbol in the dynamic symbol table. >+ }; >+ >+ // Supports iteration over all dynamic symbols. >+ class SymbolIterator { >+ public: >+ friend class ElfMemImage; >+ const SymbolInfo *operator->() const; >+ const SymbolInfo &operator*() const; >+ SymbolIterator& operator++(); >+ bool operator!=(const SymbolIterator &rhs) const; >+ bool operator==(const SymbolIterator &rhs) const; >+ private: >+ SymbolIterator(const void *const image, int index); >+ void Update(int incr); >+ SymbolInfo info_; >+ int index_; >+ const void *const image_; >+ }; >+ >+ >+ explicit ElfMemImage(const void *base); >+ void Init(const void *base); >+ bool IsPresent() const { return ehdr_ != nullptr; } >+ const ElfW(Phdr)* GetPhdr(int index) const; >+ const ElfW(Sym)* GetDynsym(int index) const; >+ const ElfW(Versym)* GetVersym(int index) const; >+ const ElfW(Verdef)* GetVerdef(int index) const; >+ const ElfW(Verdaux)* GetVerdefAux(const ElfW(Verdef) *verdef) const; >+ const char* GetDynstr(ElfW(Word) offset) const; >+ const void* GetSymAddr(const ElfW(Sym) *sym) const; >+ const char* GetVerstr(ElfW(Word) offset) const; >+ int GetNumSymbols() const; >+ >+ SymbolIterator begin() const; >+ SymbolIterator end() const; >+ >+ // Look up versioned dynamic symbol in the image. >+ // Returns false if image is not present, or doesn't contain given >+ // symbol/version/type combination. >+ // If info_out is non-null, additional details are filled in. >+ bool LookupSymbol(const char *name, const char *version, >+ int symbol_type, SymbolInfo *info_out) const; >+ >+ // Find info about symbol (if any) which overlaps given address. >+ // Returns true if symbol was found; false if image isn't present >+ // or doesn't have a symbol overlapping given address. >+ // If info_out is non-null, additional details are filled in. >+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const; >+ >+ private: >+ const ElfW(Ehdr) *ehdr_; >+ const ElfW(Sym) *dynsym_; >+ const ElfW(Versym) *versym_; >+ const ElfW(Verdef) *verdef_; >+ const ElfW(Word) *hash_; >+ const char *dynstr_; >+ size_t strsize_; >+ size_t verdefnum_; >+ ElfW(Addr) link_base_; // Link-time base (p_vaddr of first PT_LOAD). >+}; >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_ELF_MEM_IMAGE >+ >+#endif // ABSL_DEBUGGING_INTERNAL_ELF_MEM_IMAGE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc >new file mode 100644 >index 00000000000..faf88836735 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.cc >@@ -0,0 +1,153 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#include "absl/debugging/internal/examine_stack.h" >+ >+#ifndef _WIN32 >+#include <unistd.h> >+#endif >+ >+#include <csignal> >+#include <cstdio> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/macros.h" >+#include "absl/debugging/stacktrace.h" >+#include "absl/debugging/symbolize.h" >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Returns the program counter from signal context, nullptr if >+// unknown. vuc is a ucontext_t*. We use void* to avoid the use of >+// ucontext_t on non-POSIX systems. >+void* GetProgramCounter(void* vuc) { >+#ifdef __linux__ >+ if (vuc != nullptr) { >+ ucontext_t* context = reinterpret_cast<ucontext_t*>(vuc); >+#if defined(__aarch64__) >+ return reinterpret_cast<void*>(context->uc_mcontext.pc); >+#elif defined(__arm__) >+ return reinterpret_cast<void*>(context->uc_mcontext.arm_pc); >+#elif defined(__i386__) >+ if (14 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) >+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[14]); >+#elif defined(__mips__) >+ return reinterpret_cast<void*>(context->uc_mcontext.pc); >+#elif defined(__powerpc64__) >+ return reinterpret_cast<void*>(context->uc_mcontext.gp_regs[32]); >+#elif defined(__powerpc__) >+ return reinterpret_cast<void*>(context->uc_mcontext.regs->nip); >+#elif defined(__s390__) && !defined(__s390x__) >+ return reinterpret_cast<void*>(context->uc_mcontext.psw.addr & 0x7fffffff); >+#elif defined(__s390__) && defined(__s390x__) >+ return reinterpret_cast<void*>(context->uc_mcontext.psw.addr); >+#elif defined(__x86_64__) >+ if (16 < ABSL_ARRAYSIZE(context->uc_mcontext.gregs)) >+ return reinterpret_cast<void*>(context->uc_mcontext.gregs[16]); >+#else >+#error "Undefined Architecture." >+#endif >+ } >+#elif defined(__akaros__) >+ auto* ctx = reinterpret_cast<struct user_context*>(vuc); >+ return reinterpret_cast<void*>(get_user_ctx_pc(ctx)); >+#endif >+ static_cast<void>(vuc); >+ return nullptr; >+} >+ >+// The %p field width for printf() functions is two characters per byte, >+// and two extra for the leading "0x". >+static constexpr int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*); >+ >+// Print a program counter, its stack frame size, and its symbol name. >+// Note that there is a separate symbolize_pc argument. Return addresses may be >+// at the end of the function, and this allows the caller to back up from pc if >+// appropriate. >+static void DumpPCAndFrameSizeAndSymbol(void (*writerfn)(const char*, void*), >+ void* writerfn_arg, void* pc, >+ void* symbolize_pc, int framesize, >+ const char* const prefix) { >+ char tmp[1024]; >+ const char* symbol = "(unknown)"; >+ if (absl::Symbolize(symbolize_pc, tmp, sizeof(tmp))) { >+ symbol = tmp; >+ } >+ char buf[1024]; >+ if (framesize <= 0) { >+ snprintf(buf, sizeof(buf), "%s@ %*p (unknown) %s\n", prefix, >+ kPrintfPointerFieldWidth, pc, symbol); >+ } else { >+ snprintf(buf, sizeof(buf), "%s@ %*p %9d %s\n", prefix, >+ kPrintfPointerFieldWidth, pc, framesize, symbol); >+ } >+ writerfn(buf, writerfn_arg); >+} >+ >+// Print a program counter and the corresponding stack frame size. >+static void DumpPCAndFrameSize(void (*writerfn)(const char*, void*), >+ void* writerfn_arg, void* pc, int framesize, >+ const char* const prefix) { >+ char buf[100]; >+ if (framesize <= 0) { >+ snprintf(buf, sizeof(buf), "%s@ %*p (unknown)\n", prefix, >+ kPrintfPointerFieldWidth, pc); >+ } else { >+ snprintf(buf, sizeof(buf), "%s@ %*p %9d\n", prefix, >+ kPrintfPointerFieldWidth, pc, framesize); >+ } >+ writerfn(buf, writerfn_arg); >+} >+ >+void DumpPCAndFrameSizesAndStackTrace( >+ void* pc, void* const stack[], int frame_sizes[], int depth, >+ int min_dropped_frames, bool symbolize_stacktrace, >+ void (*writerfn)(const char*, void*), void* writerfn_arg) { >+ if (pc != nullptr) { >+ // We don't know the stack frame size for PC, use 0. >+ if (symbolize_stacktrace) { >+ DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, pc, pc, 0, "PC: "); >+ } else { >+ DumpPCAndFrameSize(writerfn, writerfn_arg, pc, 0, "PC: "); >+ } >+ } >+ for (int i = 0; i < depth; i++) { >+ if (symbolize_stacktrace) { >+ // Pass the previous address of pc as the symbol address because pc is a >+ // return address, and an overrun may occur when the function ends with a >+ // call to a function annotated noreturn (e.g. CHECK). Note that we don't >+ // do this for pc above, as the adjustment is only correct for return >+ // addresses. >+ DumpPCAndFrameSizeAndSymbol(writerfn, writerfn_arg, stack[i], >+ reinterpret_cast<char*>(stack[i]) - 1, >+ frame_sizes[i], " "); >+ } else { >+ DumpPCAndFrameSize(writerfn, writerfn_arg, stack[i], frame_sizes[i], >+ " "); >+ } >+ } >+ if (min_dropped_frames > 0) { >+ char buf[100]; >+ snprintf(buf, sizeof(buf), " @ ... and at least %d more frames\n", >+ min_dropped_frames); >+ writerfn(buf, writerfn_arg); >+ } >+} >+ >+} // namespace debugging_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.h >new file mode 100644 >index 00000000000..a16c03b2748 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/examine_stack.h >@@ -0,0 +1,38 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_ >+#define ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_ >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Returns the program counter from signal context, or nullptr if >+// unknown. `vuc` is a ucontext_t*. We use void* to avoid the use of >+// ucontext_t on non-POSIX systems. >+void* GetProgramCounter(void* vuc); >+ >+// Uses `writerfn` to dump the program counter, stack trace, and stack >+// frame sizes. >+void DumpPCAndFrameSizesAndStackTrace( >+ void* pc, void* const stack[], int frame_sizes[], int depth, >+ int min_dropped_frames, bool symbolize_stacktrace, >+ void (*writerfn)(const char*, void*), void* writerfn_arg); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_EXAMINE_STACK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc >new file mode 100644 >index 00000000000..2b3b972ea53 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.cc >@@ -0,0 +1,172 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/debugging/internal/stack_consumption.h" >+ >+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+ >+#include <signal.h> >+#include <sys/mman.h> >+#include <unistd.h> >+ >+#include <string.h> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+namespace debugging_internal { >+namespace { >+ >+// This code requires that we know the direction in which the stack >+// grows. It is commonly believed that this can be detected by putting >+// a variable on the stack and then passing its address to a function >+// that compares the address of this variable to the address of a >+// variable on the function's own stack. However, this is unspecified >+// behavior in C++: If two pointers p and q of the same type point to >+// different objects that are not members of the same object or >+// elements of the same array or to different functions, or if only >+// one of them is null, the results of p<q, p>q, p<=q, and p>=q are >+// unspecified. Therefore, instead we hardcode the direction of the >+// stack on platforms we know about. >+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) >+constexpr bool kStackGrowsDown = true; >+#else >+#error Need to define kStackGrowsDown >+#endif >+ >+// To measure the stack footprint of some code, we create a signal handler >+// (for SIGUSR2 say) that exercises this code on an alternate stack. This >+// alternate stack is initialized to some known pattern (0x55, 0x55, 0x55, >+// ...). We then self-send this signal, and after the signal handler returns, >+// look at the alternate stack buffer to see what portion has been touched. >+// >+// This trick gives us the the stack footprint of the signal handler. But the >+// signal handler, even before the code for it is exercised, consumes some >+// stack already. We however only want the stack usage of the code inside the >+// signal handler. To measure this accurately, we install two signal handlers: >+// one that does nothing and just returns, and the user-provided signal >+// handler. The difference between the stack consumption of these two signals >+// handlers should give us the stack foorprint of interest. >+ >+void EmptySignalHandler(int) {} >+ >+// This is arbitrary value, and could be increase further, at the cost of >+// memset()ting it all to known sentinel value. >+constexpr int kAlternateStackSize = 64 << 10; // 64KiB >+ >+constexpr int kSafetyMargin = 32; >+constexpr char kAlternateStackFillValue = 0x55; >+ >+// These helper functions look at the alternate stack buffer, and figure >+// out what portion of this buffer has been touched - this is the stack >+// consumption of the signal handler running on this alternate stack. >+// This function will return -1 if the alternate stack buffer has not been >+// touched. It will abort the program if the buffer has overflowed or is about >+// to overflow. >+int GetStackConsumption(const void* const altstack) { >+ const char* begin; >+ int increment; >+ if (kStackGrowsDown) { >+ begin = reinterpret_cast<const char*>(altstack); >+ increment = 1; >+ } else { >+ begin = reinterpret_cast<const char*>(altstack) + kAlternateStackSize - 1; >+ increment = -1; >+ } >+ >+ for (int usage_count = kAlternateStackSize; usage_count > 0; --usage_count) { >+ if (*begin != kAlternateStackFillValue) { >+ ABSL_RAW_CHECK(usage_count <= kAlternateStackSize - kSafetyMargin, >+ "Buffer has overflowed or is about to overflow"); >+ return usage_count; >+ } >+ begin += increment; >+ } >+ >+ ABSL_RAW_LOG(FATAL, "Unreachable code"); >+ return -1; >+} >+ >+} // namespace >+ >+int GetSignalHandlerStackConsumption(void (*signal_handler)(int)) { >+ // The alt-signal-stack cannot be heap allocated because there is a >+ // bug in glibc-2.2 where some signal handler setup code looks at the >+ // current stack pointer to figure out what thread is currently running. >+ // Therefore, the alternate stack must be allocated from the main stack >+ // itself. >+ void* altstack = mmap(nullptr, kAlternateStackSize, PROT_READ | PROT_WRITE, >+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); >+ ABSL_RAW_CHECK(altstack != MAP_FAILED, "mmap() failed"); >+ >+ // Set up the alt-signal-stack (and save the older one). >+ stack_t sigstk; >+ memset(&sigstk, 0, sizeof(sigstk)); >+ stack_t old_sigstk; >+ sigstk.ss_sp = altstack; >+ sigstk.ss_size = kAlternateStackSize; >+ sigstk.ss_flags = 0; >+ ABSL_RAW_CHECK(sigaltstack(&sigstk, &old_sigstk) == 0, >+ "sigaltstack() failed"); >+ >+ // Set up SIGUSR1 and SIGUSR2 signal handlers (and save the older ones). >+ struct sigaction sa; >+ memset(&sa, 0, sizeof(sa)); >+ struct sigaction old_sa1, old_sa2; >+ sigemptyset(&sa.sa_mask); >+ sa.sa_flags = SA_ONSTACK; >+ >+ // SIGUSR1 maps to EmptySignalHandler. >+ sa.sa_handler = EmptySignalHandler; >+ ABSL_RAW_CHECK(sigaction(SIGUSR1, &sa, &old_sa1) == 0, "sigaction() failed"); >+ >+ // SIGUSR2 maps to signal_handler. >+ sa.sa_handler = signal_handler; >+ ABSL_RAW_CHECK(sigaction(SIGUSR2, &sa, &old_sa2) == 0, "sigaction() failed"); >+ >+ // Send SIGUSR1 signal and measure the stack consumption of the empty >+ // signal handler. >+ // The first signal might use more stack space. Run once and ignore the >+ // results to get that out of the way. >+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed"); >+ >+ memset(altstack, kAlternateStackFillValue, kAlternateStackSize); >+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR1) == 0, "kill() failed"); >+ int base_stack_consumption = GetStackConsumption(altstack); >+ >+ // Send SIGUSR2 signal and measure the stack consumption of signal_handler. >+ ABSL_RAW_CHECK(kill(getpid(), SIGUSR2) == 0, "kill() failed"); >+ int signal_handler_stack_consumption = GetStackConsumption(altstack); >+ >+ // Now restore the old alt-signal-stack and signal handlers. >+ ABSL_RAW_CHECK(sigaltstack(&old_sigstk, nullptr) == 0, >+ "sigaltstack() failed"); >+ ABSL_RAW_CHECK(sigaction(SIGUSR1, &old_sa1, nullptr) == 0, >+ "sigaction() failed"); >+ ABSL_RAW_CHECK(sigaction(SIGUSR2, &old_sa2, nullptr) == 0, >+ "sigaction() failed"); >+ >+ ABSL_RAW_CHECK(munmap(altstack, kAlternateStackSize) == 0, "munmap() failed"); >+ if (signal_handler_stack_consumption != -1 && base_stack_consumption != -1) { >+ return signal_handler_stack_consumption - base_stack_consumption; >+ } >+ return -1; >+} >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h >new file mode 100644 >index 00000000000..4c5fa0f0d82 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption.h >@@ -0,0 +1,45 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Helper function for measuring stack consumption of signal handlers. >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_ >+ >+// The code in this module is not portable. >+// Use this feature test macro to detect its availability. >+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+#error ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION cannot be set directly >+#elif !defined(__APPLE__) && !defined(_WIN32) && \ >+ (defined(__i386__) || defined(__x86_64__) || defined(__ppc__)) >+#define ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION 1 >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Returns the stack consumption in bytes for the code exercised by >+// signal_handler. To measure stack consumption, signal_handler is registered >+// as a signal handler, so the code that it exercises must be async-signal >+// safe. The argument of signal_handler is an implementation detail of signal >+// handlers and should ignored by the code for signal_handler. Use global >+// variables to pass information between your test code and signal_handler. >+int GetSignalHandlerStackConsumption(void (*signal_handler)(int)); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACK_CONSUMPTION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption_test.cc >new file mode 100644 >index 00000000000..5ce3846ec44 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stack_consumption_test.cc >@@ -0,0 +1,48 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/debugging/internal/stack_consumption.h" >+ >+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+ >+#include <string.h> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+namespace debugging_internal { >+namespace { >+ >+static void SimpleSignalHandler(int signo) { >+ char buf[100]; >+ memset(buf, 'a', sizeof(buf)); >+ >+ // Never true, but prevents compiler from optimizing buf out. >+ if (signo == 0) { >+ ABSL_RAW_LOG(INFO, "%p", static_cast<void*>(buf)); >+ } >+} >+ >+TEST(SignalHandlerStackConsumptionTest, MeasuresStackConsumption) { >+ // Our handler should consume reasonable number of bytes. >+ EXPECT_GE(GetSignalHandlerStackConsumption(SimpleSignalHandler), 100); >+} >+ >+} // namespace >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc >new file mode 100644 >index 00000000000..7ed6b3eb82d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_aarch64-inl.inc >@@ -0,0 +1,190 @@ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_ >+ >+// Generate stack tracer for aarch64 >+ >+#if defined(__linux__) >+#include <sys/mman.h> >+#include <ucontext.h> >+#include <unistd.h> >+#endif >+ >+#include <atomic> >+#include <cassert> >+#include <cstdint> >+#include <iostream> >+ >+#include "absl/base/attributes.h" >+#include "absl/debugging/internal/address_is_readable.h" >+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems >+#include "absl/debugging/stacktrace.h" >+ >+static const uintptr_t kUnknownFrameSize = 0; >+ >+#if defined(__linux__) >+// Returns the address of the VDSO __kernel_rt_sigreturn function, if present. >+static const unsigned char* GetKernelRtSigreturnAddress() { >+ constexpr uintptr_t kImpossibleAddress = 1; >+ ABSL_CONST_INIT static std::atomic<uintptr_t> memoized{kImpossibleAddress}; >+ uintptr_t address = memoized.load(std::memory_order_relaxed); >+ if (address != kImpossibleAddress) { >+ return reinterpret_cast<const unsigned char*>(address); >+ } >+ >+ address = reinterpret_cast<uintptr_t>(nullptr); >+ >+#ifdef ABSL_HAVE_VDSO_SUPPORT >+ absl::debugging_internal::VDSOSupport vdso; >+ if (vdso.IsPresent()) { >+ absl::debugging_internal::VDSOSupport::SymbolInfo symbol_info; >+ if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.6.39", STT_FUNC, >+ &symbol_info) || >+ symbol_info.address == nullptr) { >+ // Unexpected: VDSO is present, yet the expected symbol is missing >+ // or null. >+ assert(false && "VDSO is present, but doesn't have expected symbol"); >+ } else { >+ if (reinterpret_cast<uintptr_t>(symbol_info.address) != >+ kImpossibleAddress) { >+ address = reinterpret_cast<uintptr_t>(symbol_info.address); >+ } else { >+ assert(false && "VDSO returned invalid address"); >+ } >+ } >+ } >+#endif >+ >+ memoized.store(address, std::memory_order_relaxed); >+ return reinterpret_cast<const unsigned char*>(address); >+} >+#endif // __linux__ >+ >+// Compute the size of a stack frame in [low..high). We assume that >+// low < high. Return size of kUnknownFrameSize. >+template<typename T> >+static inline uintptr_t ComputeStackFrameSize(const T* low, >+ const T* high) { >+ const char* low_char_ptr = reinterpret_cast<const char *>(low); >+ const char* high_char_ptr = reinterpret_cast<const char *>(high); >+ return low < high ? high_char_ptr - low_char_ptr : kUnknownFrameSize; >+} >+ >+// Given a pointer to a stack frame, locate and return the calling >+// stackframe, or return null if no stackframe can be found. Perform sanity >+// checks (the strictness of which is controlled by the boolean parameter >+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. >+template<bool STRICT_UNWINDING, bool WITH_CONTEXT> >+static void **NextStackFrame(void **old_frame_pointer, const void *uc) { >+ void **new_frame_pointer = reinterpret_cast<void**>(*old_frame_pointer); >+ bool check_frame_size = true; >+ >+#if defined(__linux__) >+ if (WITH_CONTEXT && uc != nullptr) { >+ // Check to see if next frame's return address is __kernel_rt_sigreturn. >+ if (old_frame_pointer[1] == GetKernelRtSigreturnAddress()) { >+ const ucontext_t *ucv = static_cast<const ucontext_t *>(uc); >+ // old_frame_pointer[0] is not suitable for unwinding, look at >+ // ucontext to discover frame pointer before signal. >+ void **const pre_signal_frame_pointer = >+ reinterpret_cast<void **>(ucv->uc_mcontext.regs[29]); >+ >+ // Check that alleged frame pointer is actually readable. This is to >+ // prevent "double fault" in case we hit the first fault due to e.g. >+ // stack corruption. >+ if (!absl::debugging_internal::AddressIsReadable( >+ pre_signal_frame_pointer)) >+ return nullptr; >+ >+ // Alleged frame pointer is readable, use it for further unwinding. >+ new_frame_pointer = pre_signal_frame_pointer; >+ >+ // Skip frame size check if we return from a signal. We may be using a >+ // an alternate stack for signals. >+ check_frame_size = false; >+ } >+ } >+#endif >+ >+ // aarch64 ABI requires stack pointer to be 16-byte-aligned. >+ if ((reinterpret_cast<uintptr_t>(new_frame_pointer) & 15) != 0) >+ return nullptr; >+ >+ // Check frame size. In strict mode, we assume frames to be under >+ // 100,000 bytes. In non-strict mode, we relax the limit to 1MB. >+ if (check_frame_size) { >+ const uintptr_t max_size = STRICT_UNWINDING ? 100000 : 1000000; >+ const uintptr_t frame_size = >+ ComputeStackFrameSize(old_frame_pointer, new_frame_pointer); >+ if (frame_size == kUnknownFrameSize || frame_size > max_size) >+ return nullptr; >+ } >+ >+ return new_frame_pointer; >+} >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, >+ const void *ucp, int *min_dropped_frames) { >+#ifdef __GNUC__ >+ void **frame_pointer = reinterpret_cast<void**>(__builtin_frame_address(0)); >+#else >+# error reading stack point not yet supported on this platform. >+#endif >+ >+ skip_count++; // Skip the frame for this function. >+ int n = 0; >+ >+ // The frame pointer points to low address of a frame. The first 64-bit >+ // word of a frame points to the next frame up the call chain, which normally >+ // is just after the high address of the current frame. The second word of >+ // a frame contains return adress of to the caller. To find a pc value >+ // associated with the current frame, we need to go down a level in the call >+ // chain. So we remember return the address of the last frame seen. This >+ // does not work for the first stack frame, which belongs to UnwindImp() but >+ // we skip the frame for UnwindImp() anyway. >+ void* prev_return_address = nullptr; >+ >+ while (frame_pointer && n < max_depth) { >+ // The absl::GetStackFrames routine is called when we are in some >+ // informational context (the failure signal handler for example). >+ // Use the non-strict unwinding rules to produce a stack trace >+ // that is as complete as possible (even if it contains a few bogus >+ // entries in some rare cases). >+ void **next_frame_pointer = >+ NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp); >+ >+ if (skip_count > 0) { >+ skip_count--; >+ } else { >+ result[n] = prev_return_address; >+ if (IS_STACK_FRAMES) { >+ sizes[n] = ComputeStackFrameSize(frame_pointer, next_frame_pointer); >+ } >+ n++; >+ } >+ prev_return_address = frame_pointer[1]; >+ frame_pointer = next_frame_pointer; >+ } >+ if (min_dropped_frames != nullptr) { >+ // Implementation detail: we clamp the max of frames we are willing to >+ // count, so as not to spend too much time in the loop below. >+ const int kMaxUnwind = 200; >+ int j = 0; >+ for (; frame_pointer != nullptr && j < kMaxUnwind; j++) { >+ frame_pointer = >+ NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(frame_pointer, ucp); >+ } >+ *min_dropped_frames = j; >+ } >+ return n; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return true; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_AARCH64_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc >new file mode 100644 >index 00000000000..c84083379bb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_arm-inl.inc >@@ -0,0 +1,123 @@ >+// Copyright 2011 and onwards Google Inc. >+// All rights reserved. >+// >+// Author: Doug Kwan >+// This is inspired by Craig Silverstein's PowerPC stacktrace code. >+// >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ >+ >+#include <cstdint> >+ >+#include "absl/debugging/stacktrace.h" >+ >+// WARNING: >+// This only works if all your code is in either ARM or THUMB mode. With >+// interworking, the frame pointer of the caller can either be in r11 (ARM >+// mode) or r7 (THUMB mode). A callee only saves the frame pointer of its >+// mode in a fixed location on its stack frame. If the caller is a different >+// mode, there is no easy way to find the frame pointer. It can either be >+// still in the designated register or saved on stack along with other callee >+// saved registers. >+ >+// Given a pointer to a stack frame, locate and return the calling >+// stackframe, or return nullptr if no stackframe can be found. Perform sanity >+// checks (the strictness of which is controlled by the boolean parameter >+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. >+template<bool STRICT_UNWINDING> >+static void **NextStackFrame(void **old_sp) { >+ void **new_sp = (void**) old_sp[-1]; >+ >+ // Check that the transition from frame pointer old_sp to frame >+ // pointer new_sp isn't clearly bogus >+ if (STRICT_UNWINDING) { >+ // With the stack growing downwards, older stack frame must be >+ // at a greater address that the current one. >+ if (new_sp <= old_sp) return nullptr; >+ // Assume stack frames larger than 100,000 bytes are bogus. >+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr; >+ } else { >+ // In the non-strict mode, allow discontiguous stack frames. >+ // (alternate-signal-stacks for example). >+ if (new_sp == old_sp) return nullptr; >+ // And allow frames upto about 1MB. >+ if ((new_sp > old_sp) >+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr; >+ } >+ if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr; >+ return new_sp; >+} >+ >+// This ensures that absl::GetStackTrace sets up the Link Register properly. >+#ifdef __GNUC__ >+void StacktraceArmDummyFunction() __attribute__((noinline)); >+void StacktraceArmDummyFunction() { __asm__ volatile(""); } >+#else >+# error StacktraceArmDummyFunction() needs to be ported to this platform. >+#endif >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, >+ const void * /* ucp */, int *min_dropped_frames) { >+#ifdef __GNUC__ >+ void **sp = reinterpret_cast<void**>(__builtin_frame_address(0)); >+#else >+# error reading stack point not yet supported on this platform. >+#endif >+ >+ // On ARM, the return address is stored in the link register (r14). >+ // This is not saved on the stack frame of a leaf function. To >+ // simplify code that reads return addresses, we call a dummy >+ // function so that the return address of this function is also >+ // stored in the stack frame. This works at least for gcc. >+ StacktraceArmDummyFunction(); >+ >+ int n = 0; >+ while (sp && n < max_depth) { >+ // The absl::GetStackFrames routine is called when we are in some >+ // informational context (the failure signal handler for example). >+ // Use the non-strict unwinding rules to produce a stack trace >+ // that is as complete as possible (even if it contains a few bogus >+ // entries in some rare cases). >+ void **next_sp = NextStackFrame<!IS_STACK_FRAMES>(sp); >+ >+ if (skip_count > 0) { >+ skip_count--; >+ } else { >+ result[n] = *sp; >+ >+ if (IS_STACK_FRAMES) { >+ if (next_sp > sp) { >+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; >+ } else { >+ // A frame-size of 0 is used to indicate unknown frame size. >+ sizes[n] = 0; >+ } >+ } >+ n++; >+ } >+ sp = next_sp; >+ } >+ if (min_dropped_frames != nullptr) { >+ // Implementation detail: we clamp the max of frames we are willing to >+ // count, so as not to spend too much time in the loop below. >+ const int kMaxUnwind = 200; >+ int j = 0; >+ for (; sp != nullptr && j < kMaxUnwind; j++) { >+ sp = NextStackFrame<!IS_STACK_FRAMES>(sp); >+ } >+ *min_dropped_frames = j; >+ } >+ return n; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return false; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_ARM_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h >new file mode 100644 >index 00000000000..dd713da8c0c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_config.h >@@ -0,0 +1,69 @@ >+/* >+ * Copyright 2017 The Abseil Authors. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ >+ * Defines ABSL_STACKTRACE_INL_HEADER to the *-inl.h containing >+ * actual unwinder implementation. >+ * This header is "private" to stacktrace.cc. >+ * DO NOT include it into any other files. >+*/ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ >+ >+#if defined(ABSL_STACKTRACE_INL_HEADER) >+#error ABSL_STACKTRACE_INL_HEADER cannot be directly set >+ >+#elif defined(_WIN32) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_win32-inl.inc" >+ >+#elif defined(__linux__) && !defined(__ANDROID__) >+ >+#if !defined(NO_FRAME_POINTER) >+# if defined(__i386__) || defined(__x86_64__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_x86-inl.inc" >+# elif defined(__ppc__) || defined(__PPC__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_powerpc-inl.inc" >+# elif defined(__aarch64__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_aarch64-inl.inc" >+# elif defined(__arm__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_arm-inl.inc" >+# else >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc" >+# endif >+#else // defined(NO_FRAME_POINTER) >+# if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_generic-inl.inc" >+# elif defined(__ppc__) || defined(__PPC__) >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_generic-inl.inc" >+# else >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc" >+# endif >+#endif // NO_FRAME_POINTER >+ >+#else >+#define ABSL_STACKTRACE_INL_HEADER \ >+ "absl/debugging/internal/stacktrace_unimplemented-inl.inc" >+ >+#endif >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc >new file mode 100644 >index 00000000000..2c9ca410c60 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_generic-inl.inc >@@ -0,0 +1,59 @@ >+// Copyright 2000 - 2007 Google Inc. >+// All rights reserved. >+// >+// Author: Sanjay Ghemawat >+// >+// Portable implementation - just use glibc >+// >+// Note: The glibc implementation may cause a call to malloc. >+// This can cause a deadlock in HeapProfiler. >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ >+ >+#include <execinfo.h> >+#include <cstring> >+ >+#include "absl/debugging/stacktrace.h" >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, >+ const void *ucp, int *min_dropped_frames) { >+ static const int kStackLength = 64; >+ void * stack[kStackLength]; >+ int size; >+ >+ size = backtrace(stack, kStackLength); >+ skip_count++; // we want to skip the current frame as well >+ int result_count = size - skip_count; >+ if (result_count < 0) >+ result_count = 0; >+ if (result_count > max_depth) >+ result_count = max_depth; >+ for (int i = 0; i < result_count; i++) >+ result[i] = stack[i + skip_count]; >+ >+ if (IS_STACK_FRAMES) { >+ // No implementation for finding out the stack frame sizes yet. >+ memset(sizes, 0, sizeof(*sizes) * result_count); >+ } >+ if (min_dropped_frames != nullptr) { >+ if (size - skip_count - max_depth > 0) { >+ *min_dropped_frames = size - skip_count - max_depth; >+ } else { >+ *min_dropped_frames = 0; >+ } >+ } >+ >+ return result_count; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return true; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_GENERIC_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc >new file mode 100644 >index 00000000000..860ac2b3e58 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_powerpc-inl.inc >@@ -0,0 +1,246 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Produce stack trace. I'm guessing (hoping!) the code is much like >+// for x86. For apple machines, at least, it seems to be; see >+// http://developer.apple.com/documentation/mac/runtimehtml/RTArch-59.html >+// http://www.linux-foundation.org/spec/ELF/ppc64/PPC-elf64abi-1.9.html#STACK >+// Linux has similar code: http://patchwork.ozlabs.org/linuxppc/patch?id=8882 >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_ >+ >+#if defined(__linux__) >+#include <asm/ptrace.h> // for PT_NIP. >+#include <ucontext.h> // for ucontext_t >+#endif >+ >+#include <unistd.h> >+#include <cassert> >+#include <cstdint> >+#include <cstdio> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/optimization.h" >+#include "absl/base/port.h" >+#include "absl/debugging/stacktrace.h" >+#include "absl/debugging/internal/address_is_readable.h" >+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems >+ >+// Given a stack pointer, return the saved link register value. >+// Note that this is the link register for a callee. >+static inline void *StacktracePowerPCGetLR(void **sp) { >+ // PowerPC has 3 main ABIs, which say where in the stack the >+ // Link Register is. For DARWIN and AIX (used by apple and >+ // linux ppc64), it's in sp[2]. For SYSV (used by linux ppc), >+ // it's in sp[1]. >+#if defined(_CALL_AIX) || defined(_CALL_DARWIN) >+ return *(sp+2); >+#elif defined(_CALL_SYSV) >+ return *(sp+1); >+#elif defined(__APPLE__) || defined(__FreeBSD__) || \ >+ (defined(__linux__) && defined(__PPC64__)) >+ // This check is in case the compiler doesn't define _CALL_AIX/etc. >+ return *(sp+2); >+#elif defined(__linux) >+ // This check is in case the compiler doesn't define _CALL_SYSV. >+ return *(sp+1); >+#else >+#error Need to specify the PPC ABI for your archiecture. >+#endif >+} >+ >+// Given a pointer to a stack frame, locate and return the calling >+// stackframe, or return null if no stackframe can be found. Perform sanity >+// checks (the strictness of which is controlled by the boolean parameter >+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. >+template<bool STRICT_UNWINDING, bool IS_WITH_CONTEXT> >+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. >+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. >+static void **NextStackFrame(void **old_sp, const void *uc) { >+ void **new_sp = (void **) *old_sp; >+ enum { kStackAlignment = 16 }; >+ >+ // Check that the transition from frame pointer old_sp to frame >+ // pointer new_sp isn't clearly bogus >+ if (STRICT_UNWINDING) { >+ // With the stack growing downwards, older stack frame must be >+ // at a greater address that the current one. >+ if (new_sp <= old_sp) return nullptr; >+ // Assume stack frames larger than 100,000 bytes are bogus. >+ if ((uintptr_t)new_sp - (uintptr_t)old_sp > 100000) return nullptr; >+ } else { >+ // In the non-strict mode, allow discontiguous stack frames. >+ // (alternate-signal-stacks for example). >+ if (new_sp == old_sp) return nullptr; >+ // And allow frames upto about 1MB. >+ if ((new_sp > old_sp) >+ && ((uintptr_t)new_sp - (uintptr_t)old_sp > 1000000)) return nullptr; >+ } >+ if ((uintptr_t)new_sp % kStackAlignment != 0) return nullptr; >+ >+#if defined(__linux__) >+ enum StackTraceKernelSymbolStatus { >+ kNotInitialized = 0, kAddressValid, kAddressInvalid }; >+ >+ if (IS_WITH_CONTEXT && uc != nullptr) { >+ static StackTraceKernelSymbolStatus kernel_symbol_status = >+ kNotInitialized; // Sentinel: not computed yet. >+ // Initialize with sentinel value: __kernel_rt_sigtramp_rt64 can not >+ // possibly be there. >+ static const unsigned char *kernel_sigtramp_rt64_address = nullptr; >+ if (kernel_symbol_status == kNotInitialized) { >+ absl::debugging_internal::VDSOSupport vdso; >+ if (vdso.IsPresent()) { >+ absl::debugging_internal::VDSOSupport::SymbolInfo >+ sigtramp_rt64_symbol_info; >+ if (!vdso.LookupSymbol( >+ "__kernel_sigtramp_rt64", "LINUX_2.6.15", >+ absl::debugging_internal::VDSOSupport::kVDSOSymbolType, >+ &sigtramp_rt64_symbol_info) || >+ sigtramp_rt64_symbol_info.address == nullptr) { >+ // Unexpected: VDSO is present, yet the expected symbol is missing >+ // or null. >+ assert(false && "VDSO is present, but doesn't have expected symbol"); >+ kernel_symbol_status = kAddressInvalid; >+ } else { >+ kernel_sigtramp_rt64_address = >+ reinterpret_cast<const unsigned char *>( >+ sigtramp_rt64_symbol_info.address); >+ kernel_symbol_status = kAddressValid; >+ } >+ } else { >+ kernel_symbol_status = kAddressInvalid; >+ } >+ } >+ >+ if (new_sp != nullptr && >+ kernel_symbol_status == kAddressValid && >+ StacktracePowerPCGetLR(new_sp) == kernel_sigtramp_rt64_address) { >+ const ucontext_t* signal_context = >+ reinterpret_cast<const ucontext_t*>(uc); >+ void **const sp_before_signal = >+ reinterpret_cast<void**>(signal_context->uc_mcontext.gp_regs[PT_R1]); >+ // Check that alleged sp before signal is nonnull and is reasonably >+ // aligned. >+ if (sp_before_signal != nullptr && >+ ((uintptr_t)sp_before_signal % kStackAlignment) == 0) { >+ // Check that alleged stack pointer is actually readable. This is to >+ // prevent a "double fault" in case we hit the first fault due to e.g. >+ // a stack corruption. >+ if (absl::debugging_internal::AddressIsReadable(sp_before_signal)) { >+ // Alleged stack pointer is readable, use it for further unwinding. >+ new_sp = sp_before_signal; >+ } >+ } >+ } >+ } >+#endif >+ >+ return new_sp; >+} >+ >+// This ensures that absl::GetStackTrace sets up the Link Register properly. >+ABSL_ATTRIBUTE_NOINLINE static void AbslStacktracePowerPCDummyFunction() { >+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); >+} >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. >+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. >+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, >+ const void *ucp, int *min_dropped_frames) { >+ void **sp; >+ // Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther) >+ // and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a >+ // different asm syntax. I don't know quite the best way to discriminate >+ // systems using the old as from the new one; I've gone with __APPLE__. >+#ifdef __APPLE__ >+ __asm__ volatile ("mr %0,r1" : "=r" (sp)); >+#else >+ __asm__ volatile ("mr %0,1" : "=r" (sp)); >+#endif >+ >+ // On PowerPC, the "Link Register" or "Link Record" (LR), is a stack >+ // entry that holds the return address of the subroutine call (what >+ // instruction we run after our function finishes). This is the >+ // same as the stack-pointer of our parent routine, which is what we >+ // want here. While the compiler will always(?) set up LR for >+ // subroutine calls, it may not for leaf functions (such as this one). >+ // This routine forces the compiler (at least gcc) to push it anyway. >+ AbslStacktracePowerPCDummyFunction(); >+ >+ // The LR save area is used by the callee, so the top entry is bogus. >+ skip_count++; >+ >+ int n = 0; >+ >+ // Unlike ABIs of X86 and ARM, PowerPC ABIs say that return address (in >+ // the link register) of a function call is stored in the caller's stack >+ // frame instead of the callee's. When we look for the return address >+ // associated with a stack frame, we need to make sure that there is a >+ // caller frame before it. So we call NextStackFrame before entering the >+ // loop below and check next_sp instead of sp for loop termination. >+ // The outermost frame is set up by runtimes and it does not have a >+ // caller frame, so it is skipped. >+ >+ // The absl::GetStackFrames routine is called when we are in some >+ // informational context (the failure signal handler for example). >+ // Use the non-strict unwinding rules to produce a stack trace >+ // that is as complete as possible (even if it contains a few >+ // bogus entries in some rare cases). >+ void **next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp); >+ >+ while (next_sp && n < max_depth) { >+ if (skip_count > 0) { >+ skip_count--; >+ } else { >+ result[n] = StacktracePowerPCGetLR(sp); >+ if (IS_STACK_FRAMES) { >+ if (next_sp > sp) { >+ sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp; >+ } else { >+ // A frame-size of 0 is used to indicate unknown frame size. >+ sizes[n] = 0; >+ } >+ } >+ n++; >+ } >+ >+ sp = next_sp; >+ next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(sp, ucp); >+ } >+ >+ if (min_dropped_frames != nullptr) { >+ // Implementation detail: we clamp the max of frames we are willing to >+ // count, so as not to spend too much time in the loop below. >+ const int kMaxUnwind = 1000; >+ int j = 0; >+ for (; next_sp != nullptr && j < kMaxUnwind; j++) { >+ next_sp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(next_sp, ucp); >+ } >+ *min_dropped_frames = j; >+ } >+ return n; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return true; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_POWERPC_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_unimplemented-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_unimplemented-inl.inc >new file mode 100644 >index 00000000000..e256fdd4ae7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_unimplemented-inl.inc >@@ -0,0 +1,22 @@ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_ >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+static int UnwindImpl(void** /* result */, int* /* sizes */, >+ int /* max_depth */, int /* skip_count */, >+ const void* /* ucp */, int *min_dropped_frames) { >+ if (min_dropped_frames != nullptr) { >+ *min_dropped_frames = 0; >+ } >+ return 0; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return false; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_UNIMPLEMENTED_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc >new file mode 100644 >index 00000000000..a8f8a56afb3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_win32-inl.inc >@@ -0,0 +1,83 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Produces a stack trace for Windows. Normally, one could use >+// stacktrace_x86-inl.h or stacktrace_x86_64-inl.h -- and indeed, that >+// should work for binaries compiled using MSVC in "debug" mode. >+// However, in "release" mode, Windows uses frame-pointer >+// optimization, which makes getting a stack trace very difficult. >+// >+// There are several approaches one can take. One is to use Windows >+// intrinsics like StackWalk64. These can work, but have restrictions >+// on how successful they can be. Another attempt is to write a >+// version of stacktrace_x86-inl.h that has heuristic support for >+// dealing with FPO, similar to what WinDbg does (see >+// http://www.nynaeve.net/?p=97). There are (non-working) examples of >+// these approaches, complete with TODOs, in stacktrace_win32-inl.h#1 >+// >+// The solution we've ended up doing is to call the undocumented >+// windows function RtlCaptureStackBackTrace, which probably doesn't >+// work with FPO but at least is fast, and doesn't require a symbol >+// server. >+// >+// This code is inspired by a patch from David Vitek: >+// http://code.google.com/p/google-perftools/issues/detail?id=83 >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_ >+ >+#include <windows.h> // for GetProcAddress and GetModuleHandle >+#include <cassert> >+ >+typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( >+ IN ULONG frames_to_skip, >+ IN ULONG frames_to_capture, >+ OUT PVOID *backtrace, >+ OUT PULONG backtrace_hash); >+ >+// Load the function we need at static init time, where we don't have >+// to worry about someone else holding the loader's lock. >+static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = >+ (RtlCaptureStackBackTrace_Function*) >+ GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count, >+ const void *ucp, int *min_dropped_frames) { >+ int n = 0; >+ if (!RtlCaptureStackBackTrace_fn) { >+ // can't find a stacktrace with no function to call >+ } else { >+ n = (int)RtlCaptureStackBackTrace_fn(skip_count + 2, max_depth, result, 0); >+ } >+ if (IS_STACK_FRAMES) { >+ // No implementation for finding out the stack frame sizes yet. >+ memset(sizes, 0, sizeof(*sizes) * n); >+ } >+ if (min_dropped_frames != nullptr) { >+ // Not implemented. >+ *min_dropped_frames = 0; >+ } >+ return n; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return false; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_WIN32_INL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc >new file mode 100644 >index 00000000000..ac85b920332 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/stacktrace_x86-inl.inc >@@ -0,0 +1,337 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Produce stack trace >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_ >+#define ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_ >+ >+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) >+#include <ucontext.h> // for ucontext_t >+#endif >+ >+#if !defined(_WIN32) >+#include <unistd.h> >+#endif >+ >+#include <cassert> >+#include <cstdint> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/debugging/internal/address_is_readable.h" >+#include "absl/debugging/internal/vdso_support.h" // a no-op on non-elf or non-glibc systems >+#include "absl/debugging/stacktrace.h" >+#include "absl/base/internal/raw_logging.h" >+ >+#if defined(__linux__) && defined(__i386__) >+// Count "push %reg" instructions in VDSO __kernel_vsyscall(), >+// preceeding "syscall" or "sysenter". >+// If __kernel_vsyscall uses frame pointer, answer 0. >+// >+// kMaxBytes tells how many instruction bytes of __kernel_vsyscall >+// to analyze before giving up. Up to kMaxBytes+1 bytes of >+// instructions could be accessed. >+// >+// Here are known __kernel_vsyscall instruction sequences: >+// >+// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S). >+// Used on Intel. >+// 0xffffe400 <__kernel_vsyscall+0>: push %ecx >+// 0xffffe401 <__kernel_vsyscall+1>: push %edx >+// 0xffffe402 <__kernel_vsyscall+2>: push %ebp >+// 0xffffe403 <__kernel_vsyscall+3>: mov %esp,%ebp >+// 0xffffe405 <__kernel_vsyscall+5>: sysenter >+// >+// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S). >+// Used on AMD. >+// 0xffffe400 <__kernel_vsyscall+0>: push %ebp >+// 0xffffe401 <__kernel_vsyscall+1>: mov %ecx,%ebp >+// 0xffffe403 <__kernel_vsyscall+3>: syscall >+// >+ >+// The sequence below isn't actually expected in Google fleet, >+// here only for completeness. Remove this comment from OSS release. >+ >+// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S) >+// 0xffffe400 <__kernel_vsyscall+0>: int $0x80 >+// 0xffffe401 <__kernel_vsyscall+1>: ret >+// >+static const int kMaxBytes = 10; >+ >+// We use assert()s instead of DCHECK()s -- this is too low level >+// for DCHECK(). >+ >+static int CountPushInstructions(const unsigned char *const addr) { >+ int result = 0; >+ for (int i = 0; i < kMaxBytes; ++i) { >+ if (addr[i] == 0x89) { >+ // "mov reg,reg" >+ if (addr[i + 1] == 0xE5) { >+ // Found "mov %esp,%ebp". >+ return 0; >+ } >+ ++i; // Skip register encoding byte. >+ } else if (addr[i] == 0x0F && >+ (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) { >+ // Found "sysenter" or "syscall". >+ return result; >+ } else if ((addr[i] & 0xF0) == 0x50) { >+ // Found "push %reg". >+ ++result; >+ } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) { >+ // Found "int $0x80" >+ assert(result == 0); >+ return 0; >+ } else { >+ // Unexpected instruction. >+ assert(false && "unexpected instruction in __kernel_vsyscall"); >+ return 0; >+ } >+ } >+ // Unexpected: didn't find SYSENTER or SYSCALL in >+ // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval. >+ assert(false && "did not find SYSENTER or SYSCALL in __kernel_vsyscall"); >+ return 0; >+} >+#endif >+ >+// Assume stack frames larger than 100,000 bytes are bogus. >+static const int kMaxFrameBytes = 100000; >+ >+// Returns the stack frame pointer from signal context, 0 if unknown. >+// vuc is a ucontext_t *. We use void* to avoid the use >+// of ucontext_t on non-POSIX systems. >+static uintptr_t GetFP(const void *vuc) { >+#if !defined(__linux__) >+ static_cast<void>(vuc); // Avoid an unused argument compiler warning. >+#else >+ if (vuc != nullptr) { >+ auto *uc = reinterpret_cast<const ucontext_t *>(vuc); >+#if defined(__i386__) >+ const auto bp = uc->uc_mcontext.gregs[REG_EBP]; >+ const auto sp = uc->uc_mcontext.gregs[REG_ESP]; >+#elif defined(__x86_64__) >+ const auto bp = uc->uc_mcontext.gregs[REG_RBP]; >+ const auto sp = uc->uc_mcontext.gregs[REG_RSP]; >+#else >+ const uintptr_t bp = 0; >+ const uintptr_t sp = 0; >+#endif >+ // Sanity-check that the base pointer is valid. It should be as long as >+ // SHRINK_WRAP_FRAME_POINTER is not set, but it's possible that some code in >+ // the process is compiled with --copt=-fomit-frame-pointer or >+ // --copt=-momit-leaf-frame-pointer. >+ // >+ // TODO(bcmills): -momit-leaf-frame-pointer is currently the default >+ // behavior when building with clang. Talk to the C++ toolchain team about >+ // fixing that. >+ if (bp >= sp && bp - sp <= kMaxFrameBytes) return bp; >+ >+ // If bp isn't a plausible frame pointer, return the stack pointer instead. >+ // If we're lucky, it points to the start of a stack frame; otherwise, we'll >+ // get one frame of garbage in the stack trace and fail the sanity check on >+ // the next iteration. >+ return sp; >+ } >+#endif >+ return 0; >+} >+ >+// Given a pointer to a stack frame, locate and return the calling >+// stackframe, or return null if no stackframe can be found. Perform sanity >+// checks (the strictness of which is controlled by the boolean parameter >+// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned. >+template <bool STRICT_UNWINDING, bool WITH_CONTEXT> >+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. >+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. >+static void **NextStackFrame(void **old_fp, const void *uc) { >+ void **new_fp = (void **)*old_fp; >+ >+#if defined(__linux__) && defined(__i386__) >+ if (WITH_CONTEXT && uc != nullptr) { >+ // How many "push %reg" instructions are there at __kernel_vsyscall? >+ // This is constant for a given kernel and processor, so compute >+ // it only once. >+ static int num_push_instructions = -1; // Sentinel: not computed yet. >+ // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly >+ // be there. >+ static const unsigned char *kernel_rt_sigreturn_address = nullptr; >+ static const unsigned char *kernel_vsyscall_address = nullptr; >+ if (num_push_instructions == -1) { >+ absl::debugging_internal::VDSOSupport vdso; >+ if (vdso.IsPresent()) { >+ absl::debugging_internal::VDSOSupport::SymbolInfo >+ rt_sigreturn_symbol_info; >+ absl::debugging_internal::VDSOSupport::SymbolInfo vsyscall_symbol_info; >+ if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5", STT_FUNC, >+ &rt_sigreturn_symbol_info) || >+ !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5", STT_FUNC, >+ &vsyscall_symbol_info) || >+ rt_sigreturn_symbol_info.address == nullptr || >+ vsyscall_symbol_info.address == nullptr) { >+ // Unexpected: 32-bit VDSO is present, yet one of the expected >+ // symbols is missing or null. >+ assert(false && "VDSO is present, but doesn't have expected symbols"); >+ num_push_instructions = 0; >+ } else { >+ kernel_rt_sigreturn_address = >+ reinterpret_cast<const unsigned char *>( >+ rt_sigreturn_symbol_info.address); >+ kernel_vsyscall_address = >+ reinterpret_cast<const unsigned char *>( >+ vsyscall_symbol_info.address); >+ num_push_instructions = >+ CountPushInstructions(kernel_vsyscall_address); >+ } >+ } else { >+ num_push_instructions = 0; >+ } >+ } >+ if (num_push_instructions != 0 && kernel_rt_sigreturn_address != nullptr && >+ old_fp[1] == kernel_rt_sigreturn_address) { >+ const ucontext_t *ucv = static_cast<const ucontext_t *>(uc); >+ // This kernel does not use frame pointer in its VDSO code, >+ // and so %ebp is not suitable for unwinding. >+ void **const reg_ebp = >+ reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_EBP]); >+ const unsigned char *const reg_eip = >+ reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]); >+ if (new_fp == reg_ebp && kernel_vsyscall_address <= reg_eip && >+ reg_eip - kernel_vsyscall_address < kMaxBytes) { >+ // We "stepped up" to __kernel_vsyscall, but %ebp is not usable. >+ // Restore from 'ucv' instead. >+ void **const reg_esp = >+ reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]); >+ // Check that alleged %esp is not null and is reasonably aligned. >+ if (reg_esp && >+ ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) { >+ // Check that alleged %esp is actually readable. This is to prevent >+ // "double fault" in case we hit the first fault due to e.g. stack >+ // corruption. >+ void *const reg_esp2 = reg_esp[num_push_instructions - 1]; >+ if (absl::debugging_internal::AddressIsReadable(reg_esp2)) { >+ // Alleged %esp is readable, use it for further unwinding. >+ new_fp = reinterpret_cast<void **>(reg_esp2); >+ } >+ } >+ } >+ } >+ } >+#endif >+ >+ const uintptr_t old_fp_u = reinterpret_cast<uintptr_t>(old_fp); >+ const uintptr_t new_fp_u = reinterpret_cast<uintptr_t>(new_fp); >+ >+ // Check that the transition from frame pointer old_fp to frame >+ // pointer new_fp isn't clearly bogus. Skip the checks if new_fp >+ // matches the signal context, so that we don't skip out early when >+ // using an alternate signal stack. >+ // >+ // TODO(bcmills): The GetFP call should be completely unnecessary when >+ // SHRINK_WRAP_FRAME_POINTER is set (because we should be back in the thread's >+ // stack by this point), but it is empirically still needed (e.g. when the >+ // stack includes a call to abort). unw_get_reg returns UNW_EBADREG for some >+ // frames. Figure out why GetValidFrameAddr and/or libunwind isn't doing what >+ // it's supposed to. >+ if (STRICT_UNWINDING && >+ (!WITH_CONTEXT || uc == nullptr || new_fp_u != GetFP(uc))) { >+ // With the stack growing downwards, older stack frame must be >+ // at a greater address that the current one. >+ if (new_fp_u <= old_fp_u) return nullptr; >+ if (new_fp_u - old_fp_u > kMaxFrameBytes) return nullptr; >+ } else { >+ if (new_fp == nullptr) return nullptr; // skip AddressIsReadable() below >+ // In the non-strict mode, allow discontiguous stack frames. >+ // (alternate-signal-stacks for example). >+ if (new_fp == old_fp) return nullptr; >+ } >+ >+ if (new_fp_u & (sizeof(void *) - 1)) return nullptr; >+#ifdef __i386__ >+ // On 32-bit machines, the stack pointer can be very close to >+ // 0xffffffff, so we explicitly check for a pointer into the >+ // last two pages in the address space >+ if (new_fp_u >= 0xffffe000) return nullptr; >+#endif >+#if !defined(_WIN32) >+ if (!STRICT_UNWINDING) { >+ // Lax sanity checks cause a crash in 32-bit tcmalloc/crash_reason_test >+ // on AMD-based machines with VDSO-enabled kernels. >+ // Make an extra sanity check to insure new_fp is readable. >+ // Note: NextStackFrame<false>() is only called while the program >+ // is already on its last leg, so it's ok to be slow here. >+ >+ if (!absl::debugging_internal::AddressIsReadable(new_fp)) { >+ return nullptr; >+ } >+ } >+#endif >+ return new_fp; >+} >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS // May read random elements from stack. >+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY // May read random elements from stack. >+ABSL_ATTRIBUTE_NOINLINE >+static int UnwindImpl(void **result, int *sizes, int max_depth, int skip_count, >+ const void *ucp, int *min_dropped_frames) { >+ int n = 0; >+ void **fp = reinterpret_cast<void **>(__builtin_frame_address(0)); >+ >+ while (fp && n < max_depth) { >+ if (*(fp + 1) == reinterpret_cast<void *>(0)) { >+ // In 64-bit code, we often see a frame that >+ // points to itself and has a return address of 0. >+ break; >+ } >+ void **next_fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp); >+ if (skip_count > 0) { >+ skip_count--; >+ } else { >+ result[n] = *(fp + 1); >+ if (IS_STACK_FRAMES) { >+ if (next_fp > fp) { >+ sizes[n] = (uintptr_t)next_fp - (uintptr_t)fp; >+ } else { >+ // A frame-size of 0 is used to indicate unknown frame size. >+ sizes[n] = 0; >+ } >+ } >+ n++; >+ } >+ fp = next_fp; >+ } >+ if (min_dropped_frames != nullptr) { >+ // Implementation detail: we clamp the max of frames we are willing to >+ // count, so as not to spend too much time in the loop below. >+ const int kMaxUnwind = 1000; >+ int j = 0; >+ for (; fp != nullptr && j < kMaxUnwind; j++) { >+ fp = NextStackFrame<!IS_STACK_FRAMES, IS_WITH_CONTEXT>(fp, ucp); >+ } >+ *min_dropped_frames = j; >+ } >+ return n; >+} >+ >+namespace absl { >+namespace debugging_internal { >+bool StackTraceWorksForTest() { >+ return true; >+} >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_STACKTRACE_X86_INL_INC_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/symbolize.h >new file mode 100644 >index 00000000000..8d926fec48a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/symbolize.h >@@ -0,0 +1,123 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains internal parts of the Abseil symbolizer. >+// Do not depend on the anything in this file, it may change at anytime. >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ >+#define ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ >+ >+#include <cstddef> >+#include <cstdint> >+#include "absl/base/port.h" // Needed for string vs std::string >+ >+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE >+#error ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE cannot be directly set >+#elif defined(__ELF__) && defined(__GLIBC__) && !defined(__native_client__) && \ >+ !defined(__asmjs__) && !defined(__wasm__) >+#define ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE 1 >+ >+#include <elf.h> >+#include <link.h> // For ElfW() macro. >+#include <functional> >+#include <string> >+ >+namespace absl { >+namespace debugging_internal { >+ >+// Iterates over all sections, invoking callback on each with the section name >+// and the section header. >+// >+// Returns true on success; otherwise returns false in case of errors. >+// >+// This is not async-signal-safe. >+bool ForEachSection( >+ int fd, const std::function<bool(const std::string& name, const ElfW(Shdr) &)>& >+ callback); >+ >+// Gets the section header for the given name, if it exists. Returns true on >+// success. Otherwise, returns false. >+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len, >+ ElfW(Shdr) *out); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE >+ >+namespace absl { >+namespace debugging_internal { >+ >+struct SymbolDecoratorArgs { >+ // The program counter we are getting symbolic name for. >+ const void *pc; >+ // 0 for main executable, load address for shared libraries. >+ ptrdiff_t relocation; >+ // Read-only file descriptor for ELF image covering "pc", >+ // or -1 if no such ELF image exists in /proc/self/maps. >+ int fd; >+ // Output buffer, size. >+ // Note: the buffer may not be empty -- default symbolizer may have already >+ // produced some output, and earlier decorators may have adorned it in >+ // some way. You are free to replace or augment the contents (within the >+ // symbol_buf_size limit). >+ char *const symbol_buf; >+ size_t symbol_buf_size; >+ // Temporary scratch space, size. >+ // Use that space in preference to allocating your own stack buffer to >+ // conserve stack. >+ char *const tmp_buf; >+ size_t tmp_buf_size; >+ // User-provided argument >+ void* arg; >+}; >+using SymbolDecorator = void (*)(const SymbolDecoratorArgs *); >+ >+// Installs a function-pointer as a decorator. Returns a value less than zero >+// if the system cannot install the decorator. Otherwise, returns a unique >+// identifier corresponding to the decorator. This identifier can be used to >+// uninstall the decorator - See RemoveSymbolDecorator() below. >+int InstallSymbolDecorator(SymbolDecorator decorator, void* arg); >+ >+// Removes a previously installed function-pointer decorator. Parameter "ticket" >+// is the return-value from calling InstallSymbolDecorator(). >+bool RemoveSymbolDecorator(int ticket); >+ >+// Remove all installed decorators. Returns true if successful, false if >+// symbolization is currently in progress. >+bool RemoveAllSymbolDecorators(void); >+ >+// Registers an address range to a file mapping. >+// >+// Preconditions: >+// start <= end >+// filename != nullptr >+// >+// Returns true if the file was successfully registered. >+bool RegisterFileMappingHint( >+ const void* start, const void* end, uint64_t offset, const char* filename); >+ >+// Looks up the file mapping registered by RegisterFileMappingHint for an >+// address range. If there is one, the file name is stored in *filename and >+// *start and *end are modified to reflect the registered mapping. Returns >+// whether any hint was found. >+bool GetFileMappingHint(const void** start, >+ const void** end, >+ uint64_t * offset, >+ const char** filename); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_INTERNAL_SYMBOLIZE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc >new file mode 100644 >index 00000000000..e8129e87dca >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.cc >@@ -0,0 +1,192 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Allow dynamic symbol lookup in the kernel VDSO page. >+// >+// VDSOSupport -- a class representing kernel VDSO (if present). >+ >+#include "absl/debugging/internal/vdso_support.h" >+ >+#ifdef ABSL_HAVE_VDSO_SUPPORT // defined in vdso_support.h >+ >+#include <errno.h> >+#include <fcntl.h> >+#include <sys/syscall.h> >+#include <unistd.h> >+ >+#if __GLIBC_PREREQ(2, 16) // GLIBC-2.16 implements getauxval. >+#include <sys/auxv.h> >+#endif >+ >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/port.h" >+ >+#ifndef AT_SYSINFO_EHDR >+#define AT_SYSINFO_EHDR 33 // for crosstoolv10 >+#endif >+ >+namespace absl { >+namespace debugging_internal { >+ >+ABSL_CONST_INIT >+std::atomic<const void *> VDSOSupport::vdso_base_( >+ debugging_internal::ElfMemImage::kInvalidBase); >+ >+std::atomic<VDSOSupport::GetCpuFn> VDSOSupport::getcpu_fn_(&InitAndGetCPU); >+VDSOSupport::VDSOSupport() >+ // If vdso_base_ is still set to kInvalidBase, we got here >+ // before VDSOSupport::Init has been called. Call it now. >+ : image_(vdso_base_.load(std::memory_order_relaxed) == >+ debugging_internal::ElfMemImage::kInvalidBase >+ ? Init() >+ : vdso_base_.load(std::memory_order_relaxed)) {} >+ >+// NOTE: we can't use GoogleOnceInit() below, because we can be >+// called by tcmalloc, and none of the *once* stuff may be functional yet. >+// >+// In addition, we hope that the VDSOSupportHelper constructor >+// causes this code to run before there are any threads, and before >+// InitGoogle() has executed any chroot or setuid calls. >+// >+// Finally, even if there is a race here, it is harmless, because >+// the operation should be idempotent. >+const void *VDSOSupport::Init() { >+ const auto kInvalidBase = debugging_internal::ElfMemImage::kInvalidBase; >+#if __GLIBC_PREREQ(2, 16) >+ if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { >+ errno = 0; >+ const void *const sysinfo_ehdr = >+ reinterpret_cast<const void *>(getauxval(AT_SYSINFO_EHDR)); >+ if (errno == 0) { >+ vdso_base_.store(sysinfo_ehdr, std::memory_order_relaxed); >+ } >+ } >+#endif // __GLIBC_PREREQ(2, 16) >+ if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { >+ // Valgrind zaps AT_SYSINFO_EHDR and friends from the auxv[] >+ // on stack, and so glibc works as if VDSO was not present. >+ // But going directly to kernel via /proc/self/auxv below bypasses >+ // Valgrind zapping. So we check for Valgrind separately. >+ if (AbslRunningOnValgrind()) { >+ vdso_base_.store(nullptr, std::memory_order_relaxed); >+ getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); >+ return nullptr; >+ } >+ int fd = open("/proc/self/auxv", O_RDONLY); >+ if (fd == -1) { >+ // Kernel too old to have a VDSO. >+ vdso_base_.store(nullptr, std::memory_order_relaxed); >+ getcpu_fn_.store(&GetCPUViaSyscall, std::memory_order_relaxed); >+ return nullptr; >+ } >+ ElfW(auxv_t) aux; >+ while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) { >+ if (aux.a_type == AT_SYSINFO_EHDR) { >+ vdso_base_.store(reinterpret_cast<void *>(aux.a_un.a_val), >+ std::memory_order_relaxed); >+ break; >+ } >+ } >+ close(fd); >+ if (vdso_base_.load(std::memory_order_relaxed) == kInvalidBase) { >+ // Didn't find AT_SYSINFO_EHDR in auxv[]. >+ vdso_base_.store(nullptr, std::memory_order_relaxed); >+ } >+ } >+ GetCpuFn fn = &GetCPUViaSyscall; // default if VDSO not present. >+ if (vdso_base_.load(std::memory_order_relaxed)) { >+ VDSOSupport vdso; >+ SymbolInfo info; >+ if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { >+ fn = reinterpret_cast<GetCpuFn>(const_cast<void *>(info.address)); >+ } >+ } >+ // Subtle: this code runs outside of any locks; prevent compiler >+ // from assigning to getcpu_fn_ more than once. >+ getcpu_fn_.store(fn, std::memory_order_relaxed); >+ return vdso_base_.load(std::memory_order_relaxed); >+} >+ >+const void *VDSOSupport::SetBase(const void *base) { >+ ABSL_RAW_CHECK(base != debugging_internal::ElfMemImage::kInvalidBase, >+ "internal error"); >+ const void *old_base = vdso_base_.load(std::memory_order_relaxed); >+ vdso_base_.store(base, std::memory_order_relaxed); >+ image_.Init(base); >+ // Also reset getcpu_fn_, so GetCPU could be tested with simulated VDSO. >+ getcpu_fn_.store(&InitAndGetCPU, std::memory_order_relaxed); >+ return old_base; >+} >+ >+bool VDSOSupport::LookupSymbol(const char *name, >+ const char *version, >+ int type, >+ SymbolInfo *info) const { >+ return image_.LookupSymbol(name, version, type, info); >+} >+ >+bool VDSOSupport::LookupSymbolByAddress(const void *address, >+ SymbolInfo *info_out) const { >+ return image_.LookupSymbolByAddress(address, info_out); >+} >+ >+// NOLINT on 'long' because this routine mimics kernel api. >+long VDSOSupport::GetCPUViaSyscall(unsigned *cpu, // NOLINT(runtime/int) >+ void *, void *) { >+#ifdef SYS_getcpu >+ return syscall(SYS_getcpu, cpu, nullptr, nullptr); >+#else >+ // x86_64 never implemented sys_getcpu(), except as a VDSO call. >+ static_cast<void>(cpu); // Avoid an unused argument compiler warning. >+ errno = ENOSYS; >+ return -1; >+#endif >+} >+ >+// Use fast __vdso_getcpu if available. >+long VDSOSupport::InitAndGetCPU(unsigned *cpu, // NOLINT(runtime/int) >+ void *x, void *y) { >+ Init(); >+ GetCpuFn fn = getcpu_fn_.load(std::memory_order_relaxed); >+ ABSL_RAW_CHECK(fn != &InitAndGetCPU, "Init() did not set getcpu_fn_"); >+ return (*fn)(cpu, x, y); >+} >+ >+// This function must be very fast, and may be called from very >+// low level (e.g. tcmalloc). Hence I avoid things like >+// GoogleOnceInit() and ::operator new. >+ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY >+int GetCPU() { >+ unsigned cpu; >+ int ret_code = (*VDSOSupport::getcpu_fn_)(&cpu, nullptr, nullptr); >+ return ret_code == 0 ? cpu : ret_code; >+} >+ >+// We need to make sure VDSOSupport::Init() is called before >+// InitGoogle() does any setuid or chroot calls. If VDSOSupport >+// is used in any global constructor, this will happen, since >+// VDSOSupport's constructor calls Init. But if not, we need to >+// ensure it here, with a global constructor of our own. This >+// is an allowed exception to the normal rule against non-trivial >+// global constructors. >+static class VDSOInitHelper { >+ public: >+ VDSOInitHelper() { VDSOSupport::Init(); } >+} vdso_init_helper; >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_VDSO_SUPPORT >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h >new file mode 100644 >index 00000000000..8002c7405fa >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/internal/vdso_support.h >@@ -0,0 +1,156 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// Allow dynamic symbol lookup in the kernel VDSO page. >+// >+// VDSO stands for "Virtual Dynamic Shared Object" -- a page of >+// executable code, which looks like a shared library, but doesn't >+// necessarily exist anywhere on disk, and which gets mmap()ed into >+// every process by kernels which support VDSO, such as 2.6.x for 32-bit >+// executables, and 2.6.24 and above for 64-bit executables. >+// >+// More details could be found here: >+// http://www.trilithium.com/johan/2005/08/linux-gate/ >+// >+// VDSOSupport -- a class representing kernel VDSO (if present). >+// >+// Example usage: >+// VDSOSupport vdso; >+// VDSOSupport::SymbolInfo info; >+// typedef (*FN)(unsigned *, void *, void *); >+// FN fn = nullptr; >+// if (vdso.LookupSymbol("__vdso_getcpu", "LINUX_2.6", STT_FUNC, &info)) { >+// fn = reinterpret_cast<FN>(info.address); >+// } >+ >+#ifndef ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_ >+#define ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_ >+ >+#include <atomic> >+ >+#include "absl/base/attributes.h" >+#include "absl/debugging/internal/elf_mem_image.h" >+ >+#ifdef ABSL_HAVE_ELF_MEM_IMAGE >+ >+#ifdef ABSL_HAVE_VDSO_SUPPORT >+#error ABSL_HAVE_VDSO_SUPPORT cannot be directly set >+#else >+#define ABSL_HAVE_VDSO_SUPPORT 1 >+#endif >+ >+namespace absl { >+namespace debugging_internal { >+ >+// NOTE: this class may be used from within tcmalloc, and can not >+// use any memory allocation routines. >+class VDSOSupport { >+ public: >+ VDSOSupport(); >+ >+ typedef ElfMemImage::SymbolInfo SymbolInfo; >+ typedef ElfMemImage::SymbolIterator SymbolIterator; >+ >+ // On PowerPC64 VDSO symbols can either be of type STT_FUNC or STT_NOTYPE >+ // depending on how the kernel is built. The kernel is normally built with >+ // STT_NOTYPE type VDSO symbols. Let's make things simpler first by using a >+ // compile-time constant. >+#ifdef __powerpc64__ >+ enum { kVDSOSymbolType = STT_NOTYPE }; >+#else >+ enum { kVDSOSymbolType = STT_FUNC }; >+#endif >+ >+ // Answers whether we have a vdso at all. >+ bool IsPresent() const { return image_.IsPresent(); } >+ >+ // Allow to iterate over all VDSO symbols. >+ SymbolIterator begin() const { return image_.begin(); } >+ SymbolIterator end() const { return image_.end(); } >+ >+ // Look up versioned dynamic symbol in the kernel VDSO. >+ // Returns false if VDSO is not present, or doesn't contain given >+ // symbol/version/type combination. >+ // If info_out != nullptr, additional details are filled in. >+ bool LookupSymbol(const char *name, const char *version, >+ int symbol_type, SymbolInfo *info_out) const; >+ >+ // Find info about symbol (if any) which overlaps given address. >+ // Returns true if symbol was found; false if VDSO isn't present >+ // or doesn't have a symbol overlapping given address. >+ // If info_out != nullptr, additional details are filled in. >+ bool LookupSymbolByAddress(const void *address, SymbolInfo *info_out) const; >+ >+ // Used only for testing. Replace real VDSO base with a mock. >+ // Returns previous value of vdso_base_. After you are done testing, >+ // you are expected to call SetBase() with previous value, in order to >+ // reset state to the way it was. >+ const void *SetBase(const void *s); >+ >+ // Computes vdso_base_ and returns it. Should be called as early as >+ // possible; before any thread creation, chroot or setuid. >+ static const void *Init(); >+ >+ private: >+ // image_ represents VDSO ELF image in memory. >+ // image_.ehdr_ == nullptr implies there is no VDSO. >+ ElfMemImage image_; >+ >+ // Cached value of auxv AT_SYSINFO_EHDR, computed once. >+ // This is a tri-state: >+ // kInvalidBase => value hasn't been determined yet. >+ // 0 => there is no VDSO. >+ // else => vma of VDSO Elf{32,64}_Ehdr. >+ // >+ // When testing with mock VDSO, low bit is set. >+ // The low bit is always available because vdso_base_ is >+ // page-aligned. >+ static std::atomic<const void *> vdso_base_; >+ >+ // NOLINT on 'long' because these routines mimic kernel api. >+ // The 'cache' parameter may be used by some versions of the kernel, >+ // and should be nullptr or point to a static buffer containing at >+ // least two 'long's. >+ static long InitAndGetCPU(unsigned *cpu, void *cache, // NOLINT 'long'. >+ void *unused); >+ static long GetCPUViaSyscall(unsigned *cpu, void *cache, // NOLINT 'long'. >+ void *unused); >+ typedef long (*GetCpuFn)(unsigned *cpu, void *cache, // NOLINT 'long'. >+ void *unused); >+ >+ // This function pointer may point to InitAndGetCPU, >+ // GetCPUViaSyscall, or __vdso_getcpu at different stages of initialization. >+ ABSL_CONST_INIT static std::atomic<GetCpuFn> getcpu_fn_; >+ >+ friend int GetCPU(void); // Needs access to getcpu_fn_. >+ >+ VDSOSupport(const VDSOSupport&) = delete; >+ VDSOSupport& operator=(const VDSOSupport&) = delete; >+}; >+ >+// Same as sched_getcpu() on later glibc versions. >+// Return current CPU, using (fast) __vdso_getcpu@LINUX_2.6 if present, >+// otherwise use syscall(SYS_getcpu,...). >+// May return -1 with errno == ENOSYS if the kernel doesn't >+// support SYS_getcpu. >+int GetCPU(); >+ >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_ELF_MEM_IMAGE >+ >+#endif // ABSL_DEBUGGING_INTERNAL_VDSO_SUPPORT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.cc >new file mode 100644 >index 00000000000..e01e5f8c937 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.cc >@@ -0,0 +1,48 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// Wrappers around lsan_interface functions. >+// When lsan is not linked in, these functions are not available, >+// therefore Abseil code which depends on these functions is conditioned on the >+// definition of LEAK_SANITIZER. >+#include "absl/debugging/leak_check.h" >+ >+#ifndef LEAK_SANITIZER >+ >+namespace absl { >+bool HaveLeakSanitizer() { return false; } >+void DoIgnoreLeak(const void*) { } >+void RegisterLivePointers(const void*, size_t) { } >+void UnRegisterLivePointers(const void*, size_t) { } >+LeakCheckDisabler::LeakCheckDisabler() { } >+LeakCheckDisabler::~LeakCheckDisabler() { } >+} // namespace absl >+ >+#else >+ >+#include <sanitizer/lsan_interface.h> >+ >+namespace absl { >+bool HaveLeakSanitizer() { return true; } >+void DoIgnoreLeak(const void* ptr) { __lsan_ignore_object(ptr); } >+void RegisterLivePointers(const void* ptr, size_t size) { >+ __lsan_register_root_region(ptr, size); >+} >+void UnRegisterLivePointers(const void* ptr, size_t size) { >+ __lsan_unregister_root_region(ptr, size); >+} >+LeakCheckDisabler::LeakCheckDisabler() { __lsan_disable(); } >+LeakCheckDisabler::~LeakCheckDisabler() { __lsan_enable(); } >+} // namespace absl >+ >+#endif // LEAK_SANITIZER >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.h >new file mode 100644 >index 00000000000..c930684e959 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check.h >@@ -0,0 +1,109 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: leak_check.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains functions that affect leak checking behavior within >+// targets built with the LeakSanitizer (LSan), a memory leak detector that is >+// integrated within the AddressSanitizer (ASan) as an additional component, or >+// which can be used standalone. LSan and ASan are included (or can be provided) >+// as additional components for most compilers such as Clang, gcc and MSVC. >+// Note: this leak checking API is not yet supported in MSVC. >+// Leak checking is enabled by default in all ASan builds. >+// >+// See https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer >+// >+// ----------------------------------------------------------------------------- >+#ifndef ABSL_DEBUGGING_LEAK_CHECK_H_ >+#define ABSL_DEBUGGING_LEAK_CHECK_H_ >+ >+#include <cstddef> >+ >+namespace absl { >+ >+// HaveLeakSanitizer() >+// >+// Returns true if a leak-checking sanitizer (either ASan or standalone LSan) is >+// currently built into this target. >+bool HaveLeakSanitizer(); >+ >+// DoIgnoreLeak() >+// >+// Implements `IgnoreLeak()` below. This function should usually >+// not be called directly; calling `IgnoreLeak()` is preferred. >+void DoIgnoreLeak(const void* ptr); >+ >+// IgnoreLeak() >+// >+// Instruct the leak sanitizer to ignore leak warnings on the object referenced >+// by the passed pointer, as well as all heap objects transitively referenced >+// by it. The passed object pointer can point to either the beginning of the >+// object or anywhere within it. >+// >+// Example: >+// >+// static T* obj = IgnoreLeak(new T(...)); >+// >+// If the passed `ptr` does not point to an actively allocated object at the >+// time `IgnoreLeak()` is called, the call is a no-op; if it is actively >+// allocated, the object must not get deallocated later. >+// >+template <typename T> >+T* IgnoreLeak(T* ptr) { >+ DoIgnoreLeak(ptr); >+ return ptr; >+} >+ >+// LeakCheckDisabler >+// >+// This helper class indicates that any heap allocations done in the code block >+// covered by the scoped object, which should be allocated on the stack, will >+// not be reported as leaks. Leak check disabling will occur within the code >+// block and any nested function calls within the code block. >+// >+// Example: >+// >+// void Foo() { >+// LeakCheckDisabler disabler; >+// ... code that allocates objects whose leaks should be ignored ... >+// } >+// >+// REQUIRES: Destructor runs in same thread as constructor >+class LeakCheckDisabler { >+ public: >+ LeakCheckDisabler(); >+ LeakCheckDisabler(const LeakCheckDisabler&) = delete; >+ LeakCheckDisabler& operator=(const LeakCheckDisabler&) = delete; >+ ~LeakCheckDisabler(); >+}; >+ >+// RegisterLivePointers() >+// >+// Registers `ptr[0,size-1]` as pointers to memory that is still actively being >+// referenced and for which leak checking should be ignored. This function is >+// useful if you store pointers in mapped memory, for memory ranges that we know >+// are correct but for which normal analysis would flag as leaked code. >+void RegisterLivePointers(const void* ptr, size_t size); >+ >+// UnRegisterLivePointers() >+// >+// Deregisters the pointers previously marked as active in >+// `RegisterLivePointers()`, enabling leak checking of those pointers. >+void UnRegisterLivePointers(const void* ptr, size_t size); >+ >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_LEAK_CHECK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_disable.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_disable.cc >new file mode 100644 >index 00000000000..df22c1cae91 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_disable.cc >@@ -0,0 +1,20 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Disable LeakSanitizer when this file is linked in. >+// This function overrides __lsan_is_turned_off from sanitizer/lsan_interface.h >+extern "C" int __lsan_is_turned_off(); >+extern "C" int __lsan_is_turned_off() { >+ return 1; >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_fail_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_fail_test.cc >new file mode 100644 >index 00000000000..bf541fe8415 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_fail_test.cc >@@ -0,0 +1,41 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <memory> >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/debugging/leak_check.h" >+ >+namespace { >+ >+TEST(LeakCheckTest, LeakMemory) { >+ // This test is expected to cause lsan failures on program exit. Therefore the >+ // test will be run only by leak_check_test.sh, which will verify a >+ // failed exit code. >+ >+ char* foo = strdup("lsan should complain about this leaked string"); >+ ABSL_RAW_LOG(INFO, "Should detect leaked std::string %s", foo); >+} >+ >+TEST(LeakCheckTest, LeakMemoryAfterDisablerScope) { >+ // This test is expected to cause lsan failures on program exit. Therefore the >+ // test will be run only by external_leak_check_test.sh, which will verify a >+ // failed exit code. >+ { absl::LeakCheckDisabler disabler; } >+ char* foo = strdup("lsan should also complain about this leaked string"); >+ ABSL_RAW_LOG(INFO, "Re-enabled leak detection.Should detect leaked std::string %s", >+ foo); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_test.cc >new file mode 100644 >index 00000000000..febd1ee4f92 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/leak_check_test.cc >@@ -0,0 +1,42 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <string> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/debugging/leak_check.h" >+ >+namespace { >+ >+TEST(LeakCheckTest, DetectLeakSanitizer) { >+#ifdef ABSL_EXPECT_LEAK_SANITIZER >+ EXPECT_TRUE(absl::HaveLeakSanitizer()); >+#else >+ EXPECT_FALSE(absl::HaveLeakSanitizer()); >+#endif >+} >+ >+TEST(LeakCheckTest, IgnoreLeakSuppressesLeakedMemoryErrors) { >+ auto foo = absl::IgnoreLeak(new std::string("some ignored leaked string")); >+ ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str()); >+} >+ >+TEST(LeakCheckTest, LeakCheckDisablerIgnoresLeak) { >+ absl::LeakCheckDisabler disabler; >+ auto foo = new std::string("some std::string leaked while checks are disabled"); >+ ABSL_RAW_LOG(INFO, "Ignoring leaked std::string %s", foo->c_str()); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.cc >new file mode 100644 >index 00000000000..61fee6190f5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.cc >@@ -0,0 +1,133 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Produce stack trace. >+// >+// There are three different ways we can try to get the stack trace: >+// >+// 1) Our hand-coded stack-unwinder. This depends on a certain stack >+// layout, which is used by gcc (and those systems using a >+// gcc-compatible ABI) on x86 systems, at least since gcc 2.95. >+// It uses the frame pointer to do its work. >+// >+// 2) The libunwind library. This is still in development, and as a >+// separate library adds a new dependency, but doesn't need a frame >+// pointer. It also doesn't call malloc. >+// >+// 3) The gdb unwinder -- also the one used by the c++ exception code. >+// It's obviously well-tested, but has a fatal flaw: it can call >+// malloc() from the unwinder. This is a problem because we're >+// trying to use the unwinder to instrument malloc(). >+// >+// Note: if you add a new implementation here, make sure it works >+// correctly when absl::GetStackTrace() is called with max_depth == 0. >+// Some code may do that. >+ >+#include "absl/debugging/stacktrace.h" >+ >+#include <atomic> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/port.h" >+#include "absl/debugging/internal/stacktrace_config.h" >+ >+#if defined(ABSL_STACKTRACE_INL_HEADER) >+#include ABSL_STACKTRACE_INL_HEADER >+#else >+# error Cannot calculate stack trace: will need to write for your environment >+# include "absl/debugging/internal/stacktrace_aarch64-inl.inc" >+# include "absl/debugging/internal/stacktrace_arm-inl.inc" >+# include "absl/debugging/internal/stacktrace_generic-inl.inc" >+# include "absl/debugging/internal/stacktrace_powerpc-inl.inc" >+# include "absl/debugging/internal/stacktrace_unimplemented-inl.inc" >+# include "absl/debugging/internal/stacktrace_win32-inl.inc" >+# include "absl/debugging/internal/stacktrace_x86-inl.inc" >+#endif >+ >+namespace absl { >+namespace { >+ >+typedef int (*Unwinder)(void**, int*, int, int, const void*, int*); >+std::atomic<Unwinder> custom; >+ >+template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT> >+ABSL_ATTRIBUTE_ALWAYS_INLINE inline int Unwind(void** result, int* sizes, >+ int max_depth, int skip_count, >+ const void* uc, >+ int* min_dropped_frames) { >+ Unwinder f = &UnwindImpl<IS_STACK_FRAMES, IS_WITH_CONTEXT>; >+ Unwinder g = custom.load(std::memory_order_acquire); >+ if (g != nullptr) f = g; >+ >+ // Add 1 to skip count for the unwinder function itself >+ int size = (*f)(result, sizes, max_depth, skip_count + 1, uc, >+ min_dropped_frames); >+ // To disable tail call to (*f)(...) >+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); >+ return size; >+} >+ >+} // anonymous namespace >+ >+int GetStackFrames(void** result, int* sizes, int max_depth, int skip_count) { >+ return Unwind<true, false>(result, sizes, max_depth, skip_count, nullptr, >+ nullptr); >+} >+ >+int GetStackFramesWithContext(void** result, int* sizes, int max_depth, >+ int skip_count, const void* uc, >+ int* min_dropped_frames) { >+ return Unwind<true, true>(result, sizes, max_depth, skip_count, uc, >+ min_dropped_frames); >+} >+ >+int GetStackTrace(void** result, int max_depth, int skip_count) { >+ return Unwind<false, false>(result, nullptr, max_depth, skip_count, nullptr, >+ nullptr); >+} >+ >+int GetStackTraceWithContext(void** result, int max_depth, int skip_count, >+ const void* uc, int* min_dropped_frames) { >+ return Unwind<false, true>(result, nullptr, max_depth, skip_count, uc, >+ min_dropped_frames); >+} >+ >+void SetStackUnwinder(Unwinder w) { >+ custom.store(w, std::memory_order_release); >+} >+ >+int DefaultStackUnwinder(void** pcs, int* sizes, int depth, int skip, >+ const void* uc, int* min_dropped_frames) { >+ skip++; // For this function >+ Unwinder f = nullptr; >+ if (sizes == nullptr) { >+ if (uc == nullptr) { >+ f = &UnwindImpl<false, false>; >+ } else { >+ f = &UnwindImpl<false, true>; >+ } >+ } else { >+ if (uc == nullptr) { >+ f = &UnwindImpl<true, false>; >+ } else { >+ f = &UnwindImpl<true, true>; >+ } >+ } >+ volatile int x = 0; >+ int n = (*f)(pcs, sizes, depth, skip, uc, min_dropped_frames); >+ x = 1; (void) x; // To disable tail call to (*f)(...) >+ return n; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.h >new file mode 100644 >index 00000000000..8b831e26815 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/stacktrace.h >@@ -0,0 +1,225 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: stacktrace.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains routines to extract the current stack trace and associated >+// stack frames. These functions are thread-safe and async-signal-safe. >+// >+// Note that stack trace functionality is platform dependent and requires >+// additional support from the compiler/build system in most cases. (That is, >+// this functionality generally only works on platforms/builds that have been >+// specifically configured to support it.) >+// >+// Note: stack traces in Abseil that do not utilize a symbolizer will result in >+// frames consisting of function addresses rather than human-readable function >+// names. (See symbolize.h for information on symbolizing these values.) >+ >+#ifndef ABSL_DEBUGGING_STACKTRACE_H_ >+#define ABSL_DEBUGGING_STACKTRACE_H_ >+ >+namespace absl { >+ >+// GetStackFrames() >+// >+// Records program counter values for up to `max_depth` frames, skipping the >+// most recent `skip_count` stack frames, and stores their corresponding values >+// and sizes in `results` and `sizes` buffers. (Note that the frame generated >+// for the `absl::GetStackFrames()` routine itself is also skipped.) >+// routine itself. >+// >+// Example: >+// >+// main() { foo(); } >+// foo() { bar(); } >+// bar() { >+// void* result[10]; >+// int sizes[10]; >+// int depth = absl::GetStackFrames(result, sizes, 10, 1); >+// } >+// >+// The current stack frame would consist of three function calls: `bar()`, >+// `foo()`, and then `main()`; however, since the `GetStackFrames()` call sets >+// `skip_count` to `1`, it will skip the frame for `bar()`, the most recently >+// invoked function call. It will therefore return two program counters and will >+// produce values that map to the following function calls: >+// >+// result[0] foo() >+// result[1] main() >+// >+// (Note: in practice, a few more entries after `main()` may be added to account >+// for startup processes.) >+// >+// Corresponding stack frame sizes will also be recorded: >+// >+// sizes[0] 16 >+// sizes[1] 16 >+// >+// (Stack frame sizes of `16` above are just for illustration purposes.) >+// >+// Stack frame sizes of 0 or less indicate that those frame sizes couldn't >+// be identified. >+// >+// This routine may return fewer stack frame entries than are >+// available. Also note that `result` and `sizes` must both be non-null. >+extern int GetStackFrames(void** result, int* sizes, int max_depth, >+ int skip_count); >+ >+// GetStackFramesWithContext() >+// >+// Records program counter values obtained from a signal handler. Records >+// program counter values for up to `max_depth` frames, skipping the most recent >+// `skip_count` stack frames, and stores their corresponding values and sizes in >+// `results` and `sizes` buffers. (Note that the frame generated for the >+// `absl::GetStackFramesWithContext()` routine itself is also skipped.) >+// >+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value >+// passed to a signal handler registered via the `sa_sigaction` field of a >+// `sigaction` struct. (See >+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may >+// help a stack unwinder to provide a better stack trace under certain >+// conditions. `uc` may safely be null. >+// >+// The `min_dropped_frames` output parameter, if non-null, points to the >+// location to note any dropped stack frames, if any, due to buffer limitations >+// or other reasons. (This value will be set to `0` if no frames were dropped.) >+// The number of total stack frames is guaranteed to be >= skip_count + >+// max_depth + *min_dropped_frames. >+extern int GetStackFramesWithContext(void** result, int* sizes, int max_depth, >+ int skip_count, const void* uc, >+ int* min_dropped_frames); >+ >+// GetStackTrace() >+// >+// Records program counter values for up to `max_depth` frames, skipping the >+// most recent `skip_count` stack frames, and stores their corresponding values >+// in `results`. Note that this function is similar to `absl::GetStackFrames()` >+// except that it returns the stack trace only, and not stack frame sizes. >+// >+// Example: >+// >+// main() { foo(); } >+// foo() { bar(); } >+// bar() { >+// void* result[10]; >+// int depth = absl::GetStackTrace(result, 10, 1); >+// } >+// >+// This produces: >+// >+// result[0] foo >+// result[1] main >+// .... ... >+// >+// `result` must not be null. >+extern int GetStackTrace(void** result, int max_depth, int skip_count); >+ >+// GetStackTraceWithContext() >+// >+// Records program counter values obtained from a signal handler. Records >+// program counter values for up to `max_depth` frames, skipping the most recent >+// `skip_count` stack frames, and stores their corresponding values in >+// `results`. (Note that the frame generated for the >+// `absl::GetStackFramesWithContext()` routine itself is also skipped.) >+// >+// The `uc` parameter, if non-null, should be a pointer to a `ucontext_t` value >+// passed to a signal handler registered via the `sa_sigaction` field of a >+// `sigaction` struct. (See >+// http://man7.org/linux/man-pages/man2/sigaction.2.html.) The `uc` value may >+// help a stack unwinder to provide a better stack trace under certain >+// conditions. `uc` may safely be null. >+// >+// The `min_dropped_frames` output parameter, if non-null, points to the >+// location to note any dropped stack frames, if any, due to buffer limitations >+// or other reasons. (This value will be set to `0` if no frames were dropped.) >+// The number of total stack frames is guaranteed to be >= skip_count + >+// max_depth + *min_dropped_frames. >+extern int GetStackTraceWithContext(void** result, int max_depth, >+ int skip_count, const void* uc, >+ int* min_dropped_frames); >+ >+// SetStackUnwinder() >+// >+// Provides a custom function for unwinding stack frames that will be used in >+// place of the default stack unwinder when invoking the static >+// GetStack{Frames,Trace}{,WithContext}() functions above. >+// >+// The arguments passed to the unwinder function will match the >+// arguments passed to `absl::GetStackFramesWithContext()` except that sizes >+// will be non-null iff the caller is interested in frame sizes. >+// >+// If unwinder is set to null, we revert to the default stack-tracing behavior. >+// >+// ***************************************************************************** >+// WARNING >+// ***************************************************************************** >+// >+// absl::SetStackUnwinder is not suitable for general purpose use. It is >+// provided for custom runtimes. >+// Some things to watch out for when calling `absl::SetStackUnwinder()`: >+// >+// (a) The unwinder may be called from within signal handlers and >+// therefore must be async-signal-safe. >+// >+// (b) Even after a custom stack unwinder has been unregistered, other >+// threads may still be in the process of using that unwinder. >+// Therefore do not clean up any state that may be needed by an old >+// unwinder. >+// ***************************************************************************** >+extern void SetStackUnwinder(int (*unwinder)(void** pcs, int* sizes, >+ int max_depth, int skip_count, >+ const void* uc, >+ int* min_dropped_frames)); >+ >+// DefaultStackUnwinder() >+// >+// Records program counter values of up to `max_depth` frames, skipping the most >+// recent `skip_count` stack frames, and stores their corresponding values in >+// `pcs`. (Note that the frame generated for this call itself is also skipped.) >+// This function acts as a generic stack-unwinder; prefer usage of the more >+// specific `GetStack{Trace,Frames}{,WithContext}()` functions above. >+// >+// If you have set your own stack unwinder (with the `SetStackUnwinder()` >+// function above, you can still get the default stack unwinder by calling >+// `DefaultStackUnwinder()`, which will ignore any previously set stack unwinder >+// and use the default one instead. >+// >+// Because this function is generic, only `pcs` is guaranteed to be non-null >+// upon return. It is legal for `sizes`, `uc`, and `min_dropped_frames` to all >+// be null when called. >+// >+// The semantics are the same as the corresponding `GetStack*()` function in the >+// case where `absl::SetStackUnwinder()` was never called. Equivalents are: >+// >+// null sizes | non-nullptr sizes >+// |==========================================================| >+// null uc | GetStackTrace() | GetStackFrames() | >+// non-null uc | GetStackTraceWithContext() | GetStackFramesWithContext() | >+// |==========================================================| >+extern int DefaultStackUnwinder(void** pcs, int* sizes, int max_depth, >+ int skip_count, const void* uc, >+ int* min_dropped_frames); >+ >+namespace debugging_internal { >+// Returns true for platforms which are expected to have functioning stack trace >+// implementations. Intended to be used for tests which want to exclude >+// verification of logic known to be broken because stack traces are not >+// working. >+extern bool StackTraceWorksForTest(); >+} // namespace debugging_internal >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_STACKTRACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.cc >new file mode 100644 >index 00000000000..a35e24cc29a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.cc >@@ -0,0 +1,28 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/debugging/symbolize.h" >+ >+#if defined(ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE) >+#include "absl/debugging/symbolize_elf.inc" >+#elif defined(_WIN32) && defined(_DEBUG) >+// The Windows Symbolizer only works in debug mode. Note that _DEBUG >+// is the macro that defines whether or not MS C-Runtime debug info is >+// available. Note that the PDB files containing the debug info must >+// also be available to the program at runtime for the symbolizer to >+// work. >+#include "absl/debugging/symbolize_win32.inc" >+#else >+#include "absl/debugging/symbolize_unimplemented.inc" >+#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.h >new file mode 100644 >index 00000000000..24e6e6471c6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize.h >@@ -0,0 +1,97 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: symbolize.h >+// ----------------------------------------------------------------------------- >+// >+// This file configures the Abseil symbolizer for use in converting instruction >+// pointer addresses (program counters) into human-readable names (function >+// calls, etc.) within Abseil code. >+// >+// The symbolizer may be invoked from several sources: >+// >+// * Implicitly, through the installation of an Abseil failure signal handler. >+// (See failure_signal_handler.h for more information.) >+// * By calling `Symbolize()` directly on a program counter you obtain through >+// `absl::GetStackTrace()` or `absl::GetStackFrames()`. (See stacktrace.h >+// for more information. >+// * By calling `Symbolize()` directly on a program counter you obtain through >+// other means (which would be platform-dependent). >+// >+// In all of the above cases, the symbolizer must first be initialized before >+// any program counter values can be symbolized. If you are installing a failure >+// signal handler, initialize the symbolizer before you do so. >+// >+// Example: >+// >+// int main(int argc, char** argv) { >+// // Initialize the Symbolizer before installing the failure signal handler >+// absl::InitializeSymbolizer(argv[0]); >+// >+// // Now you may install the failure signal handler >+// absl::FailureSignalHandlerOptions options; >+// absl::InstallFailureSignalHandler(options); >+// >+// // Start running your main program >+// ... >+// return 0; >+// } >+// >+#ifndef ABSL_DEBUGGING_SYMBOLIZE_H_ >+#define ABSL_DEBUGGING_SYMBOLIZE_H_ >+ >+#include "absl/debugging/internal/symbolize.h" >+ >+namespace absl { >+ >+// InitializeSymbolizer() >+// >+// Initializes the program counter symbolizer, given the path of the program >+// (typically obtained through `main()`s `argv[0]`). The Abseil symbolizer >+// allows you to read program counters (instruction pointer values) using their >+// human-readable names within output such as stack traces. >+// >+// Example: >+// >+// int main(int argc, char *argv[]) { >+// absl::InitializeSymbolizer(argv[0]); >+// // Now you can use the symbolizer >+// } >+void InitializeSymbolizer(const char* argv0); >+ >+// Symbolize() >+// >+// Symbolizes a program counter (instruction pointer value) `pc` and, on >+// success, writes the name to `out`. The symbol name is demangled, if possible. >+// Note that the symbolized name may be truncated and will be NUL-terminated. >+// Demangling is supported for symbols generated by GCC 3.x or newer). Returns >+// `false` on failure. >+// >+// Example: >+// >+// // Print a program counter and its symbol name. >+// static void DumpPCAndSymbol(void *pc) { >+// char tmp[1024]; >+// const char *symbol = "(unknown)"; >+// if (absl::Symbolize(pc, tmp, sizeof(tmp))) { >+// symbol = tmp; >+// } >+// absl::PrintF("%*p %s\n", pc, symbol); >+// } >+bool Symbolize(const void *pc, char *out, int out_size); >+ >+} // namespace absl >+ >+#endif // ABSL_DEBUGGING_SYMBOLIZE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc >new file mode 100644 >index 00000000000..b16a42a62c9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_elf.inc >@@ -0,0 +1,1473 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This library provides Symbolize() function that symbolizes program >+// counters to their corresponding symbol names on linux platforms. >+// This library has a minimal implementation of an ELF symbol table >+// reader (i.e. it doesn't depend on libelf, etc.). >+// >+// The algorithm used in Symbolize() is as follows. >+// >+// 1. Go through a list of maps in /proc/self/maps and find the map >+// containing the program counter. >+// >+// 2. Open the mapped file and find a regular symbol table inside. >+// Iterate over symbols in the symbol table and look for the symbol >+// containing the program counter. If such a symbol is found, >+// obtain the symbol name, and demangle the symbol if possible. >+// If the symbol isn't found in the regular symbol table (binary is >+// stripped), try the same thing with a dynamic symbol table. >+// >+// Note that Symbolize() is originally implemented to be used in >+// signal handlers, hence it doesn't use malloc() and other unsafe >+// operations. It should be both thread-safe and async-signal-safe. >+// >+// Implementation note: >+// >+// We don't use heaps but only use stacks. We want to reduce the >+// stack consumption so that the symbolizer can run on small stacks. >+// >+// Here are some numbers collected with GCC 4.1.0 on x86: >+// - sizeof(Elf32_Sym) = 16 >+// - sizeof(Elf32_Shdr) = 40 >+// - sizeof(Elf64_Sym) = 24 >+// - sizeof(Elf64_Shdr) = 64 >+// >+// This implementation is intended to be async-signal-safe but uses some >+// functions which are not guaranteed to be so, such as memchr() and >+// memmove(). We assume they are async-signal-safe. >+ >+#include <dlfcn.h> >+#include <elf.h> >+#include <fcntl.h> >+#include <link.h> // For ElfW() macro. >+#include <sys/stat.h> >+#include <sys/types.h> >+#include <unistd.h> >+ >+#include <algorithm> >+#include <atomic> >+#include <cerrno> >+#include <cinttypes> >+#include <climits> >+#include <cstdint> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+ >+#include "absl/base/casts.h" >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/low_level_alloc.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/port.h" >+#include "absl/debugging/internal/demangle.h" >+#include "absl/debugging/internal/vdso_support.h" >+ >+namespace absl { >+ >+// Value of argv[0]. Used by MaybeInitializeObjFile(). >+static char *argv0_value = nullptr; >+ >+void InitializeSymbolizer(const char *argv0) { >+ if (argv0_value != nullptr) { >+ free(argv0_value); >+ argv0_value = nullptr; >+ } >+ if (argv0 != nullptr && argv0[0] != '\0') { >+ argv0_value = strdup(argv0); >+ } >+} >+ >+namespace debugging_internal { >+namespace { >+ >+// Re-runs fn until it doesn't cause EINTR. >+#define NO_INTR(fn) \ >+ do { \ >+ } while ((fn) < 0 && errno == EINTR) >+ >+// On Linux, ELF_ST_* are defined in <linux/elf.h>. To make this portable >+// we define our own ELF_ST_BIND and ELF_ST_TYPE if not available. >+#ifndef ELF_ST_BIND >+#define ELF_ST_BIND(info) (((unsigned char)(info)) >> 4) >+#endif >+ >+#ifndef ELF_ST_TYPE >+#define ELF_ST_TYPE(info) (((unsigned char)(info)) & 0xF) >+#endif >+ >+// Some platforms use a special .opd section to store function pointers. >+const char kOpdSectionName[] = ".opd"; >+ >+#if (defined(__powerpc__) && !(_CALL_ELF > 1)) || defined(__ia64) >+// Use opd section for function descriptors on these platforms, the function >+// address is the first word of the descriptor. >+enum { kPlatformUsesOPDSections = 1 }; >+#else // not PPC or IA64 >+enum { kPlatformUsesOPDSections = 0 }; >+#endif >+ >+// This works for PowerPC & IA64 only. A function descriptor consist of two >+// pointers and the first one is the function's entry. >+const size_t kFunctionDescriptorSize = sizeof(void *) * 2; >+ >+const int kMaxDecorators = 10; // Seems like a reasonable upper limit. >+ >+struct InstalledSymbolDecorator { >+ SymbolDecorator fn; >+ void *arg; >+ int ticket; >+}; >+ >+int g_num_decorators; >+InstalledSymbolDecorator g_decorators[kMaxDecorators]; >+ >+struct FileMappingHint { >+ const void *start; >+ const void *end; >+ uint64_t offset; >+ const char *filename; >+}; >+ >+// Protects g_decorators. >+// We are using SpinLock and not a Mutex here, because we may be called >+// from inside Mutex::Lock itself, and it prohibits recursive calls. >+// This happens in e.g. base/stacktrace_syscall_unittest. >+// Moreover, we are using only TryLock(), if the decorator list >+// is being modified (is busy), we skip all decorators, and possibly >+// loose some info. Sorry, that's the best we could do. >+base_internal::SpinLock g_decorators_mu(base_internal::kLinkerInitialized); >+ >+const int kMaxFileMappingHints = 8; >+int g_num_file_mapping_hints; >+FileMappingHint g_file_mapping_hints[kMaxFileMappingHints]; >+// Protects g_file_mapping_hints. >+base_internal::SpinLock g_file_mapping_mu(base_internal::kLinkerInitialized); >+ >+// Async-signal-safe function to zero a buffer. >+// memset() is not guaranteed to be async-signal-safe. >+static void SafeMemZero(void* p, size_t size) { >+ unsigned char *c = static_cast<unsigned char *>(p); >+ while (size--) { >+ *c++ = 0; >+ } >+} >+ >+struct ObjFile { >+ ObjFile() >+ : filename(nullptr), >+ start_addr(nullptr), >+ end_addr(nullptr), >+ offset(0), >+ fd(-1), >+ elf_type(-1) { >+ SafeMemZero(&elf_header, sizeof(elf_header)); >+ } >+ >+ char *filename; >+ const void *start_addr; >+ const void *end_addr; >+ uint64_t offset; >+ >+ // The following fields are initialized on the first access to the >+ // object file. >+ int fd; >+ int elf_type; >+ ElfW(Ehdr) elf_header; >+}; >+ >+// Build 4-way associative cache for symbols. Within each cache line, symbols >+// are replaced in LRU order. >+enum { >+ ASSOCIATIVITY = 4, >+}; >+struct SymbolCacheLine { >+ const void *pc[ASSOCIATIVITY]; >+ char *name[ASSOCIATIVITY]; >+ >+ // age[i] is incremented when a line is accessed. it's reset to zero if the >+ // i'th entry is read. >+ uint32_t age[ASSOCIATIVITY]; >+}; >+ >+// --------------------------------------------------------------- >+// An async-signal-safe arena for LowLevelAlloc >+static std::atomic<base_internal::LowLevelAlloc::Arena *> g_sig_safe_arena; >+ >+static base_internal::LowLevelAlloc::Arena *SigSafeArena() { >+ return g_sig_safe_arena.load(std::memory_order_acquire); >+} >+ >+static void InitSigSafeArena() { >+ if (SigSafeArena() == nullptr) { >+ base_internal::LowLevelAlloc::Arena *new_arena = >+ base_internal::LowLevelAlloc::NewArena( >+ base_internal::LowLevelAlloc::kAsyncSignalSafe); >+ base_internal::LowLevelAlloc::Arena *old_value = nullptr; >+ if (!g_sig_safe_arena.compare_exchange_strong(old_value, new_arena, >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ // We lost a race to allocate an arena; deallocate. >+ base_internal::LowLevelAlloc::DeleteArena(new_arena); >+ } >+ } >+} >+ >+// --------------------------------------------------------------- >+// An AddrMap is a vector of ObjFile, using SigSafeArena() for allocation. >+ >+class AddrMap { >+ public: >+ AddrMap() : size_(0), allocated_(0), obj_(nullptr) {} >+ ~AddrMap() { base_internal::LowLevelAlloc::Free(obj_); } >+ int Size() const { return size_; } >+ ObjFile *At(int i) { return &obj_[i]; } >+ ObjFile *Add(); >+ void Clear(); >+ >+ private: >+ int size_; // count of valid elements (<= allocated_) >+ int allocated_; // count of allocated elements >+ ObjFile *obj_; // array of allocated_ elements >+ AddrMap(const AddrMap &) = delete; >+ AddrMap &operator=(const AddrMap &) = delete; >+}; >+ >+void AddrMap::Clear() { >+ for (int i = 0; i != size_; i++) { >+ At(i)->~ObjFile(); >+ } >+ size_ = 0; >+} >+ >+ObjFile *AddrMap::Add() { >+ if (size_ == allocated_) { >+ int new_allocated = allocated_ * 2 + 50; >+ ObjFile *new_obj_ = >+ static_cast<ObjFile *>(base_internal::LowLevelAlloc::AllocWithArena( >+ new_allocated * sizeof(*new_obj_), SigSafeArena())); >+ if (obj_) { >+ memcpy(new_obj_, obj_, allocated_ * sizeof(*new_obj_)); >+ base_internal::LowLevelAlloc::Free(obj_); >+ } >+ obj_ = new_obj_; >+ allocated_ = new_allocated; >+ } >+ return new (&obj_[size_++]) ObjFile; >+} >+ >+// --------------------------------------------------------------- >+ >+enum FindSymbolResult { SYMBOL_NOT_FOUND = 1, SYMBOL_TRUNCATED, SYMBOL_FOUND }; >+ >+class Symbolizer { >+ public: >+ Symbolizer(); >+ ~Symbolizer(); >+ const char *GetSymbol(const void *const pc); >+ >+ private: >+ char *CopyString(const char *s) { >+ int len = strlen(s); >+ char *dst = static_cast<char *>( >+ base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena())); >+ ABSL_RAW_CHECK(dst != nullptr, "out of memory"); >+ memcpy(dst, s, len + 1); >+ return dst; >+ } >+ ObjFile *FindObjFile(const void *const start, >+ size_t size) ABSL_ATTRIBUTE_NOINLINE; >+ static bool RegisterObjFile(const char *filename, >+ const void *const start_addr, >+ const void *const end_addr, uint64_t offset, >+ void *arg); >+ SymbolCacheLine *GetCacheLine(const void *const pc); >+ const char *FindSymbolInCache(const void *const pc); >+ const char *InsertSymbolInCache(const void *const pc, const char *name); >+ void AgeSymbols(SymbolCacheLine *line); >+ void ClearAddrMap(); >+ FindSymbolResult GetSymbolFromObjectFile(const ObjFile &obj, >+ const void *const pc, >+ const ptrdiff_t relocation, >+ char *out, int out_size, >+ char *tmp_buf, int tmp_buf_size); >+ >+ enum { >+ SYMBOL_BUF_SIZE = 2048, >+ TMP_BUF_SIZE = 1024, >+ SYMBOL_CACHE_LINES = 128, >+ }; >+ >+ AddrMap addr_map_; >+ >+ bool ok_; >+ bool addr_map_read_; >+ >+ char symbol_buf_[SYMBOL_BUF_SIZE]; >+ >+ // tmp_buf_ will be used to store arrays of ElfW(Shdr) and ElfW(Sym) >+ // so we ensure that tmp_buf_ is properly aligned to store either. >+ alignas(16) char tmp_buf_[TMP_BUF_SIZE]; >+ static_assert(alignof(ElfW(Shdr)) <= 16, >+ "alignment of tmp buf too small for Shdr"); >+ static_assert(alignof(ElfW(Sym)) <= 16, >+ "alignment of tmp buf too small for Sym"); >+ >+ SymbolCacheLine symbol_cache_[SYMBOL_CACHE_LINES]; >+}; >+ >+static std::atomic<Symbolizer *> g_cached_symbolizer; >+ >+} // namespace >+ >+static int SymbolizerSize() { >+ int pagesize = getpagesize(); >+ return ((sizeof(Symbolizer) - 1) / pagesize + 1) * pagesize; >+} >+ >+// Return (and set null) g_cached_symbolized_state if it is not null. >+// Otherwise return a new symbolizer. >+static Symbolizer *AllocateSymbolizer() { >+ InitSigSafeArena(); >+ Symbolizer *symbolizer = >+ g_cached_symbolizer.exchange(nullptr, std::memory_order_acquire); >+ if (symbolizer != nullptr) { >+ return symbolizer; >+ } >+ return new (base_internal::LowLevelAlloc::AllocWithArena( >+ SymbolizerSize(), SigSafeArena())) Symbolizer(); >+} >+ >+// Set g_cached_symbolize_state to s if it is null, otherwise >+// delete s. >+static void FreeSymbolizer(Symbolizer *s) { >+ Symbolizer *old_cached_symbolizer = nullptr; >+ if (!g_cached_symbolizer.compare_exchange_strong(old_cached_symbolizer, s, >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ s->~Symbolizer(); >+ base_internal::LowLevelAlloc::Free(s); >+ } >+} >+ >+Symbolizer::Symbolizer() : ok_(true), addr_map_read_(false) { >+ for (SymbolCacheLine &symbol_cache_line : symbol_cache_) { >+ for (size_t j = 0; j < ABSL_ARRAYSIZE(symbol_cache_line.name); ++j) { >+ symbol_cache_line.pc[j] = nullptr; >+ symbol_cache_line.name[j] = nullptr; >+ symbol_cache_line.age[j] = 0; >+ } >+ } >+} >+ >+Symbolizer::~Symbolizer() { >+ for (SymbolCacheLine &symbol_cache_line : symbol_cache_) { >+ for (char *s : symbol_cache_line.name) { >+ base_internal::LowLevelAlloc::Free(s); >+ } >+ } >+ ClearAddrMap(); >+} >+ >+// We don't use assert() since it's not guaranteed to be >+// async-signal-safe. Instead we define a minimal assertion >+// macro. So far, we don't need pretty printing for __FILE__, etc. >+#define SAFE_ASSERT(expr) ((expr) ? static_cast<void>(0) : abort()) >+ >+// Read up to "count" bytes from file descriptor "fd" into the buffer >+// starting at "buf" while handling short reads and EINTR. On >+// success, return the number of bytes read. Otherwise, return -1. >+static ssize_t ReadPersistent(int fd, void *buf, size_t count) { >+ SAFE_ASSERT(fd >= 0); >+ SAFE_ASSERT(count <= SSIZE_MAX); >+ char *buf0 = reinterpret_cast<char *>(buf); >+ size_t num_bytes = 0; >+ while (num_bytes < count) { >+ ssize_t len; >+ NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes)); >+ if (len < 0) { // There was an error other than EINTR. >+ ABSL_RAW_LOG(WARNING, "read failed: errno=%d", errno); >+ return -1; >+ } >+ if (len == 0) { // Reached EOF. >+ break; >+ } >+ num_bytes += len; >+ } >+ SAFE_ASSERT(num_bytes <= count); >+ return static_cast<ssize_t>(num_bytes); >+} >+ >+// Read up to "count" bytes from "offset" in the file pointed by file >+// descriptor "fd" into the buffer starting at "buf". On success, >+// return the number of bytes read. Otherwise, return -1. >+static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count, >+ const off_t offset) { >+ off_t off = lseek(fd, offset, SEEK_SET); >+ if (off == (off_t)-1) { >+ ABSL_RAW_LOG(WARNING, "lseek(%d, %ju, SEEK_SET) failed: errno=%d", fd, >+ static_cast<uintmax_t>(offset), errno); >+ return -1; >+ } >+ return ReadPersistent(fd, buf, count); >+} >+ >+// Try reading exactly "count" bytes from "offset" bytes in a file >+// pointed by "fd" into the buffer starting at "buf" while handling >+// short reads and EINTR. On success, return true. Otherwise, return >+// false. >+static bool ReadFromOffsetExact(const int fd, void *buf, const size_t count, >+ const off_t offset) { >+ ssize_t len = ReadFromOffset(fd, buf, count, offset); >+ return len >= 0 && static_cast<size_t>(len) == count; >+} >+ >+// Returns elf_header.e_type if the file pointed by fd is an ELF binary. >+static int FileGetElfType(const int fd) { >+ ElfW(Ehdr) elf_header; >+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { >+ return -1; >+ } >+ if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) { >+ return -1; >+ } >+ return elf_header.e_type; >+} >+ >+// Read the section headers in the given ELF binary, and if a section >+// of the specified type is found, set the output to this section header >+// and return true. Otherwise, return false. >+// To keep stack consumption low, we would like this function to not get >+// inlined. >+static ABSL_ATTRIBUTE_NOINLINE bool GetSectionHeaderByType( >+ const int fd, ElfW(Half) sh_num, const off_t sh_offset, ElfW(Word) type, >+ ElfW(Shdr) * out, char *tmp_buf, int tmp_buf_size) { >+ ElfW(Shdr) *buf = reinterpret_cast<ElfW(Shdr) *>(tmp_buf); >+ const int buf_entries = tmp_buf_size / sizeof(buf[0]); >+ const int buf_bytes = buf_entries * sizeof(buf[0]); >+ >+ for (int i = 0; i < sh_num;) { >+ const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]); >+ const ssize_t num_bytes_to_read = >+ (buf_bytes > num_bytes_left) ? num_bytes_left : buf_bytes; >+ const off_t offset = sh_offset + i * sizeof(buf[0]); >+ const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, offset); >+ if (len % sizeof(buf[0]) != 0) { >+ ABSL_RAW_LOG( >+ WARNING, >+ "Reading %zd bytes from offset %ju returned %zd which is not a " >+ "multiple of %zu.", >+ num_bytes_to_read, static_cast<uintmax_t>(offset), len, >+ sizeof(buf[0])); >+ return false; >+ } >+ const ssize_t num_headers_in_buf = len / sizeof(buf[0]); >+ SAFE_ASSERT(num_headers_in_buf <= buf_entries); >+ for (int j = 0; j < num_headers_in_buf; ++j) { >+ if (buf[j].sh_type == type) { >+ *out = buf[j]; >+ return true; >+ } >+ } >+ i += num_headers_in_buf; >+ } >+ return false; >+} >+ >+// There is no particular reason to limit section name to 63 characters, >+// but there has (as yet) been no need for anything longer either. >+const int kMaxSectionNameLen = 64; >+ >+bool ForEachSection(int fd, >+ const std::function<bool(const std::string &name, >+ const ElfW(Shdr) &)> &callback) { >+ ElfW(Ehdr) elf_header; >+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { >+ return false; >+ } >+ >+ ElfW(Shdr) shstrtab; >+ off_t shstrtab_offset = >+ (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx); >+ if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) { >+ return false; >+ } >+ >+ for (int i = 0; i < elf_header.e_shnum; ++i) { >+ ElfW(Shdr) out; >+ off_t section_header_offset = >+ (elf_header.e_shoff + elf_header.e_shentsize * i); >+ if (!ReadFromOffsetExact(fd, &out, sizeof(out), section_header_offset)) { >+ return false; >+ } >+ off_t name_offset = shstrtab.sh_offset + out.sh_name; >+ char header_name[kMaxSectionNameLen + 1]; >+ ssize_t n_read = >+ ReadFromOffset(fd, &header_name, kMaxSectionNameLen, name_offset); >+ if (n_read == -1) { >+ return false; >+ } else if (n_read > kMaxSectionNameLen) { >+ // Long read? >+ return false; >+ } >+ header_name[n_read] = '\0'; >+ >+ std::string name(header_name); >+ if (!callback(name, out)) { >+ break; >+ } >+ } >+ return true; >+} >+ >+// name_len should include terminating '\0'. >+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len, >+ ElfW(Shdr) * out) { >+ char header_name[kMaxSectionNameLen]; >+ if (sizeof(header_name) < name_len) { >+ ABSL_RAW_LOG(WARNING, >+ "Section name '%s' is too long (%zu); " >+ "section will not be found (even if present).", >+ name, name_len); >+ // No point in even trying. >+ return false; >+ } >+ >+ ElfW(Ehdr) elf_header; >+ if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { >+ return false; >+ } >+ >+ ElfW(Shdr) shstrtab; >+ off_t shstrtab_offset = >+ (elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx); >+ if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) { >+ return false; >+ } >+ >+ for (int i = 0; i < elf_header.e_shnum; ++i) { >+ off_t section_header_offset = >+ (elf_header.e_shoff + elf_header.e_shentsize * i); >+ if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) { >+ return false; >+ } >+ off_t name_offset = shstrtab.sh_offset + out->sh_name; >+ ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset); >+ if (n_read < 0) { >+ return false; >+ } else if (static_cast<size_t>(n_read) != name_len) { >+ // Short read -- name could be at end of file. >+ continue; >+ } >+ if (memcmp(header_name, name, name_len) == 0) { >+ return true; >+ } >+ } >+ return false; >+} >+ >+// Compare symbols at in the same address. >+// Return true if we should pick symbol1. >+static bool ShouldPickFirstSymbol(const ElfW(Sym) & symbol1, >+ const ElfW(Sym) & symbol2) { >+ // If one of the symbols is weak and the other is not, pick the one >+ // this is not a weak symbol. >+ char bind1 = ELF_ST_BIND(symbol1.st_info); >+ char bind2 = ELF_ST_BIND(symbol1.st_info); >+ if (bind1 == STB_WEAK && bind2 != STB_WEAK) return false; >+ if (bind2 == STB_WEAK && bind1 != STB_WEAK) return true; >+ >+ // If one of the symbols has zero size and the other is not, pick the >+ // one that has non-zero size. >+ if (symbol1.st_size != 0 && symbol2.st_size == 0) { >+ return true; >+ } >+ if (symbol1.st_size == 0 && symbol2.st_size != 0) { >+ return false; >+ } >+ >+ // If one of the symbols has no type and the other is not, pick the >+ // one that has a type. >+ char type1 = ELF_ST_TYPE(symbol1.st_info); >+ char type2 = ELF_ST_TYPE(symbol1.st_info); >+ if (type1 != STT_NOTYPE && type2 == STT_NOTYPE) { >+ return true; >+ } >+ if (type1 == STT_NOTYPE && type2 != STT_NOTYPE) { >+ return false; >+ } >+ >+ // Pick the first one, if we still cannot decide. >+ return true; >+} >+ >+// Return true if an address is inside a section. >+static bool InSection(const void *address, const ElfW(Shdr) * section) { >+ const char *start = reinterpret_cast<const char *>(section->sh_addr); >+ size_t size = static_cast<size_t>(section->sh_size); >+ return start <= address && address < (start + size); >+} >+ >+// Read a symbol table and look for the symbol containing the >+// pc. Iterate over symbols in a symbol table and look for the symbol >+// containing "pc". If the symbol is found, and its name fits in >+// out_size, the name is written into out and SYMBOL_FOUND is returned. >+// If the name does not fit, truncated name is written into out, >+// and SYMBOL_TRUNCATED is returned. Out is NUL-terminated. >+// If the symbol is not found, SYMBOL_NOT_FOUND is returned; >+// To keep stack consumption low, we would like this function to not get >+// inlined. >+static ABSL_ATTRIBUTE_NOINLINE FindSymbolResult FindSymbol( >+ const void *const pc, const int fd, char *out, int out_size, >+ ptrdiff_t relocation, const ElfW(Shdr) * strtab, const ElfW(Shdr) * symtab, >+ const ElfW(Shdr) * opd, char *tmp_buf, int tmp_buf_size) { >+ if (symtab == nullptr) { >+ return SYMBOL_NOT_FOUND; >+ } >+ >+ // Read multiple symbols at once to save read() calls. >+ ElfW(Sym) *buf = reinterpret_cast<ElfW(Sym) *>(tmp_buf); >+ const int buf_entries = tmp_buf_size / sizeof(buf[0]); >+ >+ const int num_symbols = symtab->sh_size / symtab->sh_entsize; >+ >+ // On platforms using an .opd section (PowerPC & IA64), a function symbol >+ // has the address of a function descriptor, which contains the real >+ // starting address. However, we do not always want to use the real >+ // starting address because we sometimes want to symbolize a function >+ // pointer into the .opd section, e.g. FindSymbol(&foo,...). >+ const bool pc_in_opd = >+ kPlatformUsesOPDSections && opd != nullptr && InSection(pc, opd); >+ const bool deref_function_descriptor_pointer = >+ kPlatformUsesOPDSections && opd != nullptr && !pc_in_opd; >+ >+ ElfW(Sym) best_match; >+ SafeMemZero(&best_match, sizeof(best_match)); >+ bool found_match = false; >+ for (int i = 0; i < num_symbols;) { >+ off_t offset = symtab->sh_offset + i * symtab->sh_entsize; >+ const int num_remaining_symbols = num_symbols - i; >+ const int entries_in_chunk = std::min(num_remaining_symbols, buf_entries); >+ const int bytes_in_chunk = entries_in_chunk * sizeof(buf[0]); >+ const ssize_t len = ReadFromOffset(fd, buf, bytes_in_chunk, offset); >+ SAFE_ASSERT(len % sizeof(buf[0]) == 0); >+ const ssize_t num_symbols_in_buf = len / sizeof(buf[0]); >+ SAFE_ASSERT(num_symbols_in_buf <= entries_in_chunk); >+ for (int j = 0; j < num_symbols_in_buf; ++j) { >+ const ElfW(Sym) &symbol = buf[j]; >+ >+ // For a DSO, a symbol address is relocated by the loading address. >+ // We keep the original address for opd redirection below. >+ const char *const original_start_address = >+ reinterpret_cast<const char *>(symbol.st_value); >+ const char *start_address = original_start_address + relocation; >+ >+ if (deref_function_descriptor_pointer && >+ InSection(original_start_address, opd)) { >+ // The opd section is mapped into memory. Just dereference >+ // start_address to get the first double word, which points to the >+ // function entry. >+ start_address = *reinterpret_cast<const char *const *>(start_address); >+ } >+ >+ // If pc is inside the .opd section, it points to a function descriptor. >+ const size_t size = pc_in_opd ? kFunctionDescriptorSize : symbol.st_size; >+ const void *const end_address = >+ reinterpret_cast<const char *>(start_address) + size; >+ if (symbol.st_value != 0 && // Skip null value symbols. >+ symbol.st_shndx != 0 && // Skip undefined symbols. >+#ifdef STT_TLS >+ ELF_ST_TYPE(symbol.st_info) != STT_TLS && // Skip thread-local data. >+#endif // STT_TLS >+ ((start_address <= pc && pc < end_address) || >+ (start_address == pc && pc == end_address))) { >+ if (!found_match || ShouldPickFirstSymbol(symbol, best_match)) { >+ found_match = true; >+ best_match = symbol; >+ } >+ } >+ } >+ i += num_symbols_in_buf; >+ } >+ >+ if (found_match) { >+ const size_t off = strtab->sh_offset + best_match.st_name; >+ const ssize_t n_read = ReadFromOffset(fd, out, out_size, off); >+ if (n_read <= 0) { >+ // This should never happen. >+ ABSL_RAW_LOG(WARNING, >+ "Unable to read from fd %d at offset %zu: n_read = %zd", fd, >+ off, n_read); >+ return SYMBOL_NOT_FOUND; >+ } >+ ABSL_RAW_CHECK(n_read <= out_size, "ReadFromOffset read too much data."); >+ >+ // strtab->sh_offset points into .strtab-like section that contains >+ // NUL-terminated strings: '\0foo\0barbaz\0...". >+ // >+ // sh_offset+st_name points to the start of symbol name, but we don't know >+ // how long the symbol is, so we try to read as much as we have space for, >+ // and usually over-read (i.e. there is a NUL somewhere before n_read). >+ if (memchr(out, '\0', n_read) == nullptr) { >+ // Either out_size was too small (n_read == out_size and no NUL), or >+ // we tried to read past the EOF (n_read < out_size) and .strtab is >+ // corrupt (missing terminating NUL; should never happen for valid ELF). >+ out[n_read - 1] = '\0'; >+ return SYMBOL_TRUNCATED; >+ } >+ return SYMBOL_FOUND; >+ } >+ >+ return SYMBOL_NOT_FOUND; >+} >+ >+// Get the symbol name of "pc" from the file pointed by "fd". Process >+// both regular and dynamic symbol tables if necessary. >+// See FindSymbol() comment for description of return value. >+FindSymbolResult Symbolizer::GetSymbolFromObjectFile( >+ const ObjFile &obj, const void *const pc, const ptrdiff_t relocation, >+ char *out, int out_size, char *tmp_buf, int tmp_buf_size) { >+ ElfW(Shdr) symtab; >+ ElfW(Shdr) strtab; >+ ElfW(Shdr) opd; >+ ElfW(Shdr) *opd_ptr = nullptr; >+ >+ // On platforms using an .opd sections for function descriptor, read >+ // the section header. The .opd section is in data segment and should be >+ // loaded but we check that it is mapped just to be extra careful. >+ if (kPlatformUsesOPDSections) { >+ if (GetSectionHeaderByName(obj.fd, kOpdSectionName, >+ sizeof(kOpdSectionName) - 1, &opd) && >+ FindObjFile(reinterpret_cast<const char *>(opd.sh_addr) + relocation, >+ opd.sh_size) != nullptr) { >+ opd_ptr = &opd; >+ } else { >+ return SYMBOL_NOT_FOUND; >+ } >+ } >+ >+ // Consult a regular symbol table first. >+ if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum, >+ obj.elf_header.e_shoff, SHT_SYMTAB, &symtab, >+ tmp_buf, tmp_buf_size)) { >+ return SYMBOL_NOT_FOUND; >+ } >+ if (!ReadFromOffsetExact( >+ obj.fd, &strtab, sizeof(strtab), >+ obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) { >+ return SYMBOL_NOT_FOUND; >+ } >+ const FindSymbolResult rc = >+ FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab, >+ opd_ptr, tmp_buf, tmp_buf_size); >+ if (rc != SYMBOL_NOT_FOUND) { >+ return rc; // Found the symbol in a regular symbol table. >+ } >+ >+ // If the symbol is not found, then consult a dynamic symbol table. >+ if (!GetSectionHeaderByType(obj.fd, obj.elf_header.e_shnum, >+ obj.elf_header.e_shoff, SHT_DYNSYM, &symtab, >+ tmp_buf, tmp_buf_size)) { >+ return SYMBOL_NOT_FOUND; >+ } >+ if (!ReadFromOffsetExact( >+ obj.fd, &strtab, sizeof(strtab), >+ obj.elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) { >+ return SYMBOL_NOT_FOUND; >+ } >+ return FindSymbol(pc, obj.fd, out, out_size, relocation, &strtab, &symtab, >+ opd_ptr, tmp_buf, tmp_buf_size); >+} >+ >+namespace { >+// Thin wrapper around a file descriptor so that the file descriptor >+// gets closed for sure. >+class FileDescriptor { >+ public: >+ explicit FileDescriptor(int fd) : fd_(fd) {} >+ FileDescriptor(const FileDescriptor &) = delete; >+ FileDescriptor &operator=(const FileDescriptor &) = delete; >+ >+ ~FileDescriptor() { >+ if (fd_ >= 0) { >+ NO_INTR(close(fd_)); >+ } >+ } >+ >+ int get() const { return fd_; } >+ >+ private: >+ const int fd_; >+}; >+ >+// Helper class for reading lines from file. >+// >+// Note: we don't use ProcMapsIterator since the object is big (it has >+// a 5k array member) and uses async-unsafe functions such as sscanf() >+// and snprintf(). >+class LineReader { >+ public: >+ explicit LineReader(int fd, char *buf, int buf_len) >+ : fd_(fd), >+ buf_len_(buf_len), >+ buf_(buf), >+ bol_(buf), >+ eol_(buf), >+ eod_(buf) {} >+ >+ LineReader(const LineReader &) = delete; >+ LineReader &operator=(const LineReader &) = delete; >+ >+ // Read '\n'-terminated line from file. On success, modify "bol" >+ // and "eol", then return true. Otherwise, return false. >+ // >+ // Note: if the last line doesn't end with '\n', the line will be >+ // dropped. It's an intentional behavior to make the code simple. >+ bool ReadLine(const char **bol, const char **eol) { >+ if (BufferIsEmpty()) { // First time. >+ const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_); >+ if (num_bytes <= 0) { // EOF or error. >+ return false; >+ } >+ eod_ = buf_ + num_bytes; >+ bol_ = buf_; >+ } else { >+ bol_ = eol_ + 1; // Advance to the next line in the buffer. >+ SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_". >+ if (!HasCompleteLine()) { >+ const int incomplete_line_length = eod_ - bol_; >+ // Move the trailing incomplete line to the beginning. >+ memmove(buf_, bol_, incomplete_line_length); >+ // Read text from file and append it. >+ char *const append_pos = buf_ + incomplete_line_length; >+ const int capacity_left = buf_len_ - incomplete_line_length; >+ const ssize_t num_bytes = >+ ReadPersistent(fd_, append_pos, capacity_left); >+ if (num_bytes <= 0) { // EOF or error. >+ return false; >+ } >+ eod_ = append_pos + num_bytes; >+ bol_ = buf_; >+ } >+ } >+ eol_ = FindLineFeed(); >+ if (eol_ == nullptr) { // '\n' not found. Malformed line. >+ return false; >+ } >+ *eol_ = '\0'; // Replace '\n' with '\0'. >+ >+ *bol = bol_; >+ *eol = eol_; >+ return true; >+ } >+ >+ private: >+ char *FindLineFeed() const { >+ return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_)); >+ } >+ >+ bool BufferIsEmpty() const { return buf_ == eod_; } >+ >+ bool HasCompleteLine() const { >+ return !BufferIsEmpty() && FindLineFeed() != nullptr; >+ } >+ >+ const int fd_; >+ const int buf_len_; >+ char *const buf_; >+ char *bol_; >+ char *eol_; >+ const char *eod_; // End of data in "buf_". >+}; >+} // namespace >+ >+// Place the hex number read from "start" into "*hex". The pointer to >+// the first non-hex character or "end" is returned. >+static const char *GetHex(const char *start, const char *end, >+ uint64_t *const value) { >+ uint64_t hex = 0; >+ const char *p; >+ for (p = start; p < end; ++p) { >+ int ch = *p; >+ if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || >+ (ch >= 'a' && ch <= 'f')) { >+ hex = (hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9); >+ } else { // Encountered the first non-hex character. >+ break; >+ } >+ } >+ SAFE_ASSERT(p <= end); >+ *value = hex; >+ return p; >+} >+ >+static const char *GetHex(const char *start, const char *end, >+ const void **const addr) { >+ uint64_t hex = 0; >+ const char *p = GetHex(start, end, &hex); >+ *addr = reinterpret_cast<void *>(hex); >+ return p; >+} >+ >+// Read /proc/self/maps and run "callback" for each mmapped file found. If >+// "callback" returns false, stop scanning and return true. Else continue >+// scanning /proc/self/maps. Return true if no parse error is found. >+static ABSL_ATTRIBUTE_NOINLINE bool ReadAddrMap( >+ bool (*callback)(const char *filename, const void *const start_addr, >+ const void *const end_addr, uint64_t offset, void *arg), >+ void *arg, void *tmp_buf, int tmp_buf_size) { >+ // Use /proc/self/task/<pid>/maps instead of /proc/self/maps. The latter >+ // requires kernel to stop all threads, and is significantly slower when there >+ // are 1000s of threads. >+ char maps_path[80]; >+ snprintf(maps_path, sizeof(maps_path), "/proc/self/task/%d/maps", getpid()); >+ >+ int maps_fd; >+ NO_INTR(maps_fd = open(maps_path, O_RDONLY)); >+ FileDescriptor wrapped_maps_fd(maps_fd); >+ if (wrapped_maps_fd.get() < 0) { >+ ABSL_RAW_LOG(WARNING, "%s: errno=%d", maps_path, errno); >+ return false; >+ } >+ >+ // Iterate over maps and look for the map containing the pc. Then >+ // look into the symbol tables inside. >+ LineReader reader(wrapped_maps_fd.get(), static_cast<char *>(tmp_buf), >+ tmp_buf_size); >+ while (true) { >+ const char *cursor; >+ const char *eol; >+ if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line. >+ break; >+ } >+ >+ const char *line = cursor; >+ const void *start_address; >+ // Start parsing line in /proc/self/maps. Here is an example: >+ // >+ // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat >+ // >+ // We want start address (08048000), end address (0804c000), flags >+ // (r-xp) and file name (/bin/cat). >+ >+ // Read start address. >+ cursor = GetHex(cursor, eol, &start_address); >+ if (cursor == eol || *cursor != '-') { >+ ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line); >+ return false; >+ } >+ ++cursor; // Skip '-'. >+ >+ // Read end address. >+ const void *end_address; >+ cursor = GetHex(cursor, eol, &end_address); >+ if (cursor == eol || *cursor != ' ') { >+ ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps line: %s", line); >+ return false; >+ } >+ ++cursor; // Skip ' '. >+ >+ // Read flags. Skip flags until we encounter a space or eol. >+ const char *const flags_start = cursor; >+ while (cursor < eol && *cursor != ' ') { >+ ++cursor; >+ } >+ // We expect at least four letters for flags (ex. "r-xp"). >+ if (cursor == eol || cursor < flags_start + 4) { >+ ABSL_RAW_LOG(WARNING, "Corrupt /proc/self/maps: %s", line); >+ return false; >+ } >+ >+ // Check flags. Normally we are only interested in "r-x" maps. On >+ // the PowerPC, function pointers point to descriptors in the .opd >+ // section. The descriptors themselves are not executable code. So >+ // we need to relax the check below to "r**". >+ if (memcmp(flags_start, "r-x", 3) != 0 && // Not a "r-x" map. >+ !(kPlatformUsesOPDSections && flags_start[0] == 'r')) { >+ continue; // We skip this map. >+ } >+ ++cursor; // Skip ' '. >+ >+ // Read file offset. >+ uint64_t offset; >+ cursor = GetHex(cursor, eol, &offset); >+ ++cursor; // Skip ' '. >+ >+ // Skip to file name. "cursor" now points to dev. We need to skip at least >+ // two spaces for dev and inode. >+ int num_spaces = 0; >+ while (cursor < eol) { >+ if (*cursor == ' ') { >+ ++num_spaces; >+ } else if (num_spaces >= 2) { >+ // The first non-space character after skipping two spaces >+ // is the beginning of the file name. >+ break; >+ } >+ ++cursor; >+ } >+ >+ // Check whether this entry corresponds to our hint table for the true >+ // filename. >+ bool hinted = >+ GetFileMappingHint(&start_address, &end_address, &offset, &cursor); >+ if (!hinted && (cursor == eol || cursor[0] == '[')) { >+ // not an object file, typically [vdso] or [vsyscall] >+ continue; >+ } >+ if (!callback(cursor, start_address, end_address, offset, arg)) break; >+ } >+ return true; >+} >+ >+// Find the objfile mapped in address region containing [addr, addr + len). >+ObjFile *Symbolizer::FindObjFile(const void *const addr, size_t len) { >+ for (int i = 0; i < 2; ++i) { >+ if (!ok_) return nullptr; >+ >+ // Read /proc/self/maps if necessary >+ if (!addr_map_read_) { >+ addr_map_read_ = true; >+ if (!ReadAddrMap(RegisterObjFile, this, tmp_buf_, TMP_BUF_SIZE)) { >+ ok_ = false; >+ return nullptr; >+ } >+ } >+ >+ int lo = 0; >+ int hi = addr_map_.Size(); >+ while (lo < hi) { >+ int mid = (lo + hi) / 2; >+ if (addr < addr_map_.At(mid)->end_addr) { >+ hi = mid; >+ } else { >+ lo = mid + 1; >+ } >+ } >+ if (lo != addr_map_.Size()) { >+ ObjFile *obj = addr_map_.At(lo); >+ SAFE_ASSERT(obj->end_addr > addr); >+ if (addr >= obj->start_addr && >+ reinterpret_cast<const char *>(addr) + len <= obj->end_addr) >+ return obj; >+ } >+ >+ // The address mapping may have changed since it was last read. Retry. >+ ClearAddrMap(); >+ } >+ return nullptr; >+} >+ >+void Symbolizer::ClearAddrMap() { >+ for (int i = 0; i != addr_map_.Size(); i++) { >+ ObjFile *o = addr_map_.At(i); >+ base_internal::LowLevelAlloc::Free(o->filename); >+ if (o->fd >= 0) { >+ NO_INTR(close(o->fd)); >+ } >+ } >+ addr_map_.Clear(); >+ addr_map_read_ = false; >+} >+ >+// Callback for ReadAddrMap to register objfiles in an in-memory table. >+bool Symbolizer::RegisterObjFile(const char *filename, >+ const void *const start_addr, >+ const void *const end_addr, uint64_t offset, >+ void *arg) { >+ Symbolizer *impl = static_cast<Symbolizer *>(arg); >+ >+ // Files are supposed to be added in the increasing address order. Make >+ // sure that's the case. >+ int addr_map_size = impl->addr_map_.Size(); >+ if (addr_map_size != 0) { >+ ObjFile *old = impl->addr_map_.At(addr_map_size - 1); >+ if (old->end_addr > end_addr) { >+ ABSL_RAW_LOG(ERROR, >+ "Unsorted addr map entry: 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR >+ ": %s", >+ reinterpret_cast<uintptr_t>(end_addr), filename, >+ reinterpret_cast<uintptr_t>(old->end_addr), old->filename); >+ return true; >+ } else if (old->end_addr == end_addr) { >+ // The same entry appears twice. This sometimes happens for [vdso]. >+ if (old->start_addr != start_addr || >+ strcmp(old->filename, filename) != 0) { >+ ABSL_RAW_LOG(ERROR, >+ "Duplicate addr 0x%" PRIxPTR ": %s <-> 0x%" PRIxPTR ": %s", >+ reinterpret_cast<uintptr_t>(end_addr), filename, >+ reinterpret_cast<uintptr_t>(old->end_addr), old->filename); >+ } >+ return true; >+ } >+ } >+ ObjFile *obj = impl->addr_map_.Add(); >+ obj->filename = impl->CopyString(filename); >+ obj->start_addr = start_addr; >+ obj->end_addr = end_addr; >+ obj->offset = offset; >+ obj->elf_type = -1; // filled on demand >+ obj->fd = -1; // opened on demand >+ return true; >+} >+ >+// This function wraps the Demangle function to provide an interface >+// where the input symbol is demangled in-place. >+// To keep stack consumption low, we would like this function to not >+// get inlined. >+static ABSL_ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size, >+ char *tmp_buf, >+ int tmp_buf_size) { >+ if (Demangle(out, tmp_buf, tmp_buf_size)) { >+ // Demangling succeeded. Copy to out if the space allows. >+ int len = strlen(tmp_buf); >+ if (len + 1 <= out_size) { // +1 for '\0'. >+ SAFE_ASSERT(len < tmp_buf_size); >+ memmove(out, tmp_buf, len + 1); >+ } >+ } >+} >+ >+SymbolCacheLine *Symbolizer::GetCacheLine(const void *const pc) { >+ uintptr_t pc0 = reinterpret_cast<uintptr_t>(pc); >+ pc0 >>= 3; // drop the low 3 bits >+ >+ // Shuffle bits. >+ pc0 ^= (pc0 >> 6) ^ (pc0 >> 12) ^ (pc0 >> 18); >+ return &symbol_cache_[pc0 % SYMBOL_CACHE_LINES]; >+} >+ >+void Symbolizer::AgeSymbols(SymbolCacheLine *line) { >+ for (uint32_t &age : line->age) { >+ ++age; >+ } >+} >+ >+const char *Symbolizer::FindSymbolInCache(const void *const pc) { >+ if (pc == nullptr) return nullptr; >+ >+ SymbolCacheLine *line = GetCacheLine(pc); >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) { >+ if (line->pc[i] == pc) { >+ AgeSymbols(line); >+ line->age[i] = 0; >+ return line->name[i]; >+ } >+ } >+ return nullptr; >+} >+ >+const char *Symbolizer::InsertSymbolInCache(const void *const pc, >+ const char *name) { >+ SAFE_ASSERT(pc != nullptr); >+ >+ SymbolCacheLine *line = GetCacheLine(pc); >+ uint32_t max_age = 0; >+ int oldest_index = -1; >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(line->pc); ++i) { >+ if (line->pc[i] == nullptr) { >+ AgeSymbols(line); >+ line->pc[i] = pc; >+ line->name[i] = CopyString(name); >+ line->age[i] = 0; >+ return line->name[i]; >+ } >+ if (line->age[i] >= max_age) { >+ max_age = line->age[i]; >+ oldest_index = i; >+ } >+ } >+ >+ AgeSymbols(line); >+ ABSL_RAW_CHECK(oldest_index >= 0, "Corrupt cache"); >+ base_internal::LowLevelAlloc::Free(line->name[oldest_index]); >+ line->pc[oldest_index] = pc; >+ line->name[oldest_index] = CopyString(name); >+ line->age[oldest_index] = 0; >+ return line->name[oldest_index]; >+} >+ >+static void MaybeOpenFdFromSelfExe(ObjFile *obj) { >+ if (memcmp(obj->start_addr, ELFMAG, SELFMAG) != 0) { >+ return; >+ } >+ int fd = open("/proc/self/exe", O_RDONLY); >+ if (fd == -1) { >+ return; >+ } >+ // Verify that contents of /proc/self/exe matches in-memory image of >+ // the binary. This can fail if the "deleted" binary is in fact not >+ // the main executable, or for binaries that have the first PT_LOAD >+ // segment smaller than 4K. We do it in four steps so that the >+ // buffer is smaller and we don't consume too much stack space. >+ const char *mem = reinterpret_cast<const char *>(obj->start_addr); >+ for (int i = 0; i < 4; ++i) { >+ char buf[1024]; >+ ssize_t n = read(fd, buf, sizeof(buf)); >+ if (n != sizeof(buf) || memcmp(buf, mem, sizeof(buf)) != 0) { >+ close(fd); >+ return; >+ } >+ mem += sizeof(buf); >+ } >+ obj->fd = fd; >+} >+ >+static bool MaybeInitializeObjFile(ObjFile *obj) { >+ if (obj->fd < 0) { >+ obj->fd = open(obj->filename, O_RDONLY); >+ >+ if (obj->fd < 0) { >+ // Getting /proc/self/exe here means that we were hinted. >+ if (strcmp(obj->filename, "/proc/self/exe") == 0) { >+ // /proc/self/exe may be inaccessible (due to setuid, etc.), so try >+ // accessing the binary via argv0. >+ if (argv0_value != nullptr) { >+ obj->fd = open(argv0_value, O_RDONLY); >+ } >+ } else { >+ MaybeOpenFdFromSelfExe(obj); >+ } >+ } >+ >+ if (obj->fd < 0) { >+ ABSL_RAW_LOG(WARNING, "%s: open failed: errno=%d", obj->filename, errno); >+ return false; >+ } >+ obj->elf_type = FileGetElfType(obj->fd); >+ if (obj->elf_type < 0) { >+ ABSL_RAW_LOG(WARNING, "%s: wrong elf type: %d", obj->filename, >+ obj->elf_type); >+ return false; >+ } >+ >+ if (!ReadFromOffsetExact(obj->fd, &obj->elf_header, sizeof(obj->elf_header), >+ 0)) { >+ ABSL_RAW_LOG(WARNING, "%s: failed to read elf header", obj->filename); >+ return false; >+ } >+ } >+ return true; >+} >+ >+// The implementation of our symbolization routine. If it >+// successfully finds the symbol containing "pc" and obtains the >+// symbol name, returns pointer to that symbol. Otherwise, returns nullptr. >+// If any symbol decorators have been installed via InstallSymbolDecorator(), >+// they are called here as well. >+// To keep stack consumption low, we would like this function to not >+// get inlined. >+const char *Symbolizer::GetSymbol(const void *const pc) { >+ const char *entry = FindSymbolInCache(pc); >+ if (entry != nullptr) { >+ return entry; >+ } >+ symbol_buf_[0] = '\0'; >+ >+ ObjFile *const obj = FindObjFile(pc, 1); >+ ptrdiff_t relocation = 0; >+ int fd = -1; >+ if (obj != nullptr) { >+ if (MaybeInitializeObjFile(obj)) { >+ if (obj->elf_type == ET_DYN && >+ reinterpret_cast<uint64_t>(obj->start_addr) >= obj->offset) { >+ // This object was relocated. >+ // >+ // For obj->offset > 0, adjust the relocation since a mapping at offset >+ // X in the file will have a start address of [true relocation]+X. >+ relocation = reinterpret_cast<ptrdiff_t>(obj->start_addr) - obj->offset; >+ } >+ >+ fd = obj->fd; >+ } >+ if (GetSymbolFromObjectFile(*obj, pc, relocation, symbol_buf_, >+ sizeof(symbol_buf_), tmp_buf_, >+ sizeof(tmp_buf_)) == SYMBOL_FOUND) { >+ // Only try to demangle the symbol name if it fit into symbol_buf_. >+ DemangleInplace(symbol_buf_, sizeof(symbol_buf_), tmp_buf_, >+ sizeof(tmp_buf_)); >+ } >+ } else { >+#if ABSL_HAVE_VDSO_SUPPORT >+ VDSOSupport vdso; >+ if (vdso.IsPresent()) { >+ VDSOSupport::SymbolInfo symbol_info; >+ if (vdso.LookupSymbolByAddress(pc, &symbol_info)) { >+ // All VDSO symbols are known to be short. >+ size_t len = strlen(symbol_info.name); >+ ABSL_RAW_CHECK(len + 1 < sizeof(symbol_buf_), >+ "VDSO symbol unexpectedly long"); >+ memcpy(symbol_buf_, symbol_info.name, len + 1); >+ } >+ } >+#endif >+ } >+ >+ if (g_decorators_mu.TryLock()) { >+ if (g_num_decorators > 0) { >+ SymbolDecoratorArgs decorator_args = { >+ pc, relocation, fd, symbol_buf_, sizeof(symbol_buf_), >+ tmp_buf_, sizeof(tmp_buf_), nullptr}; >+ for (int i = 0; i < g_num_decorators; ++i) { >+ decorator_args.arg = g_decorators[i].arg; >+ g_decorators[i].fn(&decorator_args); >+ } >+ } >+ g_decorators_mu.Unlock(); >+ } >+ if (symbol_buf_[0] == '\0') { >+ return nullptr; >+ } >+ symbol_buf_[sizeof(symbol_buf_) - 1] = '\0'; // Paranoia. >+ return InsertSymbolInCache(pc, symbol_buf_); >+} >+ >+bool RemoveAllSymbolDecorators(void) { >+ if (!g_decorators_mu.TryLock()) { >+ // Someone else is using decorators. Get out. >+ return false; >+ } >+ g_num_decorators = 0; >+ g_decorators_mu.Unlock(); >+ return true; >+} >+ >+bool RemoveSymbolDecorator(int ticket) { >+ if (!g_decorators_mu.TryLock()) { >+ // Someone else is using decorators. Get out. >+ return false; >+ } >+ for (int i = 0; i < g_num_decorators; ++i) { >+ if (g_decorators[i].ticket == ticket) { >+ while (i < g_num_decorators - 1) { >+ g_decorators[i] = g_decorators[i + 1]; >+ ++i; >+ } >+ g_num_decorators = i; >+ break; >+ } >+ } >+ g_decorators_mu.Unlock(); >+ return true; // Decorator is known to be removed. >+} >+ >+int InstallSymbolDecorator(SymbolDecorator decorator, void *arg) { >+ static int ticket = 0; >+ >+ if (!g_decorators_mu.TryLock()) { >+ // Someone else is using decorators. Get out. >+ return false; >+ } >+ int ret = ticket; >+ if (g_num_decorators >= kMaxDecorators) { >+ ret = -1; >+ } else { >+ g_decorators[g_num_decorators] = {decorator, arg, ticket++}; >+ ++g_num_decorators; >+ } >+ g_decorators_mu.Unlock(); >+ return ret; >+} >+ >+bool RegisterFileMappingHint(const void *start, const void *end, uint64_t offset, >+ const char *filename) { >+ SAFE_ASSERT(start <= end); >+ SAFE_ASSERT(filename != nullptr); >+ >+ InitSigSafeArena(); >+ >+ if (!g_file_mapping_mu.TryLock()) { >+ return false; >+ } >+ >+ bool ret = true; >+ if (g_num_file_mapping_hints >= kMaxFileMappingHints) { >+ ret = false; >+ } else { >+ // TODO(ckennelly): Move this into a std::string copy routine. >+ int len = strlen(filename); >+ char *dst = static_cast<char *>( >+ base_internal::LowLevelAlloc::AllocWithArena(len + 1, SigSafeArena())); >+ ABSL_RAW_CHECK(dst != nullptr, "out of memory"); >+ memcpy(dst, filename, len + 1); >+ >+ auto &hint = g_file_mapping_hints[g_num_file_mapping_hints++]; >+ hint.start = start; >+ hint.end = end; >+ hint.offset = offset; >+ hint.filename = dst; >+ } >+ >+ g_file_mapping_mu.Unlock(); >+ return ret; >+} >+ >+bool GetFileMappingHint(const void **start, const void **end, uint64_t *offset, >+ const char **filename) { >+ if (!g_file_mapping_mu.TryLock()) { >+ return false; >+ } >+ bool found = false; >+ for (int i = 0; i < g_num_file_mapping_hints; i++) { >+ if (g_file_mapping_hints[i].start <= *start && >+ *end <= g_file_mapping_hints[i].end) { >+ // We assume that the start_address for the mapping is the base >+ // address of the ELF section, but when [start_address,end_address) is >+ // not strictly equal to [hint.start, hint.end), that assumption is >+ // invalid. >+ // >+ // This uses the hint's start address (even though hint.start is not >+ // necessarily equal to start_address) to ensure the correct >+ // relocation is computed later. >+ *start = g_file_mapping_hints[i].start; >+ *end = g_file_mapping_hints[i].end; >+ *offset = g_file_mapping_hints[i].offset; >+ *filename = g_file_mapping_hints[i].filename; >+ found = true; >+ break; >+ } >+ } >+ g_file_mapping_mu.Unlock(); >+ return found; >+} >+ >+} // namespace debugging_internal >+ >+bool Symbolize(const void *pc, char *out, int out_size) { >+ // Symbolization is very slow under tsan. >+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); >+ SAFE_ASSERT(out_size >= 0); >+ debugging_internal::Symbolizer *s = debugging_internal::AllocateSymbolizer(); >+ const char *name = s->GetSymbol(pc); >+ bool ok = false; >+ if (name != nullptr && out_size > 0) { >+ strncpy(out, name, out_size); >+ ok = true; >+ if (out[out_size - 1] != '\0') { >+ // strncpy() does not '\0' terminate when it truncates. Do so, with >+ // trailing ellipsis. >+ static constexpr char kEllipsis[] = "..."; >+ int ellipsis_size = >+ std::min(implicit_cast<int>(strlen(kEllipsis)), out_size - 1); >+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); >+ out[out_size - 1] = '\0'; >+ } >+ } >+ debugging_internal::FreeSymbolizer(s); >+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END(); >+ return ok; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_test.cc >new file mode 100644 >index 00000000000..5f2af47ee45 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_test.cc >@@ -0,0 +1,517 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/debugging/symbolize.h" >+ >+#ifndef _WIN32 >+#include <fcntl.h> >+#include <sys/mman.h> >+#endif >+ >+#include <cstring> >+#include <iostream> >+#include <memory> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/casts.h" >+#include "absl/base/internal/per_thread_tls.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/optimization.h" >+#include "absl/debugging/internal/stack_consumption.h" >+#include "absl/memory/memory.h" >+ >+using testing::Contains; >+ >+// Functions to symbolize. Use C linkage to avoid mangled names. >+extern "C" { >+void nonstatic_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } >+static void static_func() { ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); } >+} // extern "C" >+ >+struct Foo { >+ static void func(int x); >+}; >+ >+// A C++ method that should have a mangled name. >+void ABSL_ATTRIBUTE_NOINLINE Foo::func(int) { >+ ABSL_BLOCK_TAIL_CALL_OPTIMIZATION(); >+} >+ >+// Create functions that will remain in different text sections in the >+// final binary when linker option "-z,keep-text-section-prefix" is used. >+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.unlikely) unlikely_func() { >+ return 0; >+} >+ >+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.hot) hot_func() { >+ return 0; >+} >+ >+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.startup) startup_func() { >+ return 0; >+} >+ >+int ABSL_ATTRIBUTE_SECTION_VARIABLE(.text.exit) exit_func() { >+ return 0; >+} >+ >+int /*ABSL_ATTRIBUTE_SECTION_VARIABLE(.text)*/ regular_func() { >+ return 0; >+} >+ >+// Thread-local data may confuse the symbolizer, ensure that it does not. >+// Variable sizes and order are important. >+#if ABSL_PER_THREAD_TLS >+static ABSL_PER_THREAD_TLS_KEYWORD char symbolize_test_thread_small[1]; >+static ABSL_PER_THREAD_TLS_KEYWORD char >+ symbolize_test_thread_big[2 * 1024 * 1024]; >+#endif >+ >+// Used below to hopefully inhibit some compiler/linker optimizations >+// that may remove kHpageTextPadding, kPadding0, and kPadding1 from >+// the binary. >+static volatile bool volatile_bool = false; >+ >+// Force the binary to be large enough that a THP .text remap will succeed. >+static constexpr size_t kHpageSize = 1 << 21; >+const char kHpageTextPadding[kHpageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE( >+ .text) = ""; >+ >+static char try_symbolize_buffer[4096]; >+ >+// A wrapper function for absl::Symbolize() to make the unit test simple. The >+// limit must be < sizeof(try_symbolize_buffer). Returns null if >+// absl::Symbolize() returns false, otherwise returns try_symbolize_buffer with >+// the result of absl::Symbolize(). >+static const char *TrySymbolizeWithLimit(void *pc, int limit) { >+ ABSL_RAW_CHECK(limit <= sizeof(try_symbolize_buffer), >+ "try_symbolize_buffer is too small"); >+ >+ // Use the heap to facilitate heap and buffer sanitizer tools. >+ auto heap_buffer = absl::make_unique<char[]>(sizeof(try_symbolize_buffer)); >+ bool found = absl::Symbolize(pc, heap_buffer.get(), limit); >+ if (found) { >+ ABSL_RAW_CHECK(strnlen(heap_buffer.get(), limit) < limit, >+ "absl::Symbolize() did not properly terminate the string"); >+ strncpy(try_symbolize_buffer, heap_buffer.get(), >+ sizeof(try_symbolize_buffer)); >+ } >+ >+ return found ? try_symbolize_buffer : nullptr; >+} >+ >+// A wrapper for TrySymbolizeWithLimit(), with a large limit. >+static const char *TrySymbolize(void *pc) { >+ return TrySymbolizeWithLimit(pc, sizeof(try_symbolize_buffer)); >+} >+ >+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE >+ >+TEST(Symbolize, Cached) { >+ // Compilers should give us pointers to them. >+ EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); >+ >+ // The name of an internal linkage symbol is not specified; allow either a >+ // mangled or an unmangled name here. >+ const char *static_func_symbol = TrySymbolize((void *)(&static_func)); >+ EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 || >+ strcmp("static_func()", static_func_symbol) == 0); >+ >+ EXPECT_TRUE(nullptr == TrySymbolize(nullptr)); >+} >+ >+TEST(Symbolize, Truncation) { >+ constexpr char kNonStaticFunc[] = "nonstatic_func"; >+ EXPECT_STREQ("nonstatic_func", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) + 1)); >+ EXPECT_STREQ("nonstatic_...", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) + 0)); >+ EXPECT_STREQ("nonstatic...", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) - 1)); >+ EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5)); >+ EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4)); >+ EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3)); >+ EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2)); >+ EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1)); >+ EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0)); >+} >+ >+TEST(Symbolize, SymbolizeWithDemangling) { >+ Foo::func(100); >+ EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func))); >+} >+ >+TEST(Symbolize, SymbolizeSplitTextSections) { >+ EXPECT_STREQ("unlikely_func()", TrySymbolize((void *)(&unlikely_func))); >+ EXPECT_STREQ("hot_func()", TrySymbolize((void *)(&hot_func))); >+ EXPECT_STREQ("startup_func()", TrySymbolize((void *)(&startup_func))); >+ EXPECT_STREQ("exit_func()", TrySymbolize((void *)(&exit_func))); >+ EXPECT_STREQ("regular_func()", TrySymbolize((void *)(®ular_func))); >+} >+ >+// Tests that verify that Symbolize stack footprint is within some limit. >+#ifdef ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+ >+static void *g_pc_to_symbolize; >+static char g_symbolize_buffer[4096]; >+static char *g_symbolize_result; >+ >+static void SymbolizeSignalHandler(int signo) { >+ if (absl::Symbolize(g_pc_to_symbolize, g_symbolize_buffer, >+ sizeof(g_symbolize_buffer))) { >+ g_symbolize_result = g_symbolize_buffer; >+ } else { >+ g_symbolize_result = nullptr; >+ } >+} >+ >+// Call Symbolize and figure out the stack footprint of this call. >+static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) { >+ g_pc_to_symbolize = pc; >+ *stack_consumed = absl::debugging_internal::GetSignalHandlerStackConsumption( >+ SymbolizeSignalHandler); >+ return g_symbolize_result; >+} >+ >+static int GetStackConsumptionUpperLimit() { >+ // Symbolize stack consumption should be within 2kB. >+ int stack_consumption_upper_limit = 2048; >+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ >+ defined(THREAD_SANITIZER) >+ // Account for sanitizer instrumentation requiring additional stack space. >+ stack_consumption_upper_limit *= 5; >+#endif >+ return stack_consumption_upper_limit; >+} >+ >+TEST(Symbolize, SymbolizeStackConsumption) { >+ int stack_consumed = 0; >+ >+ const char *symbol = >+ SymbolizeStackConsumption((void *)(&nonstatic_func), &stack_consumed); >+ EXPECT_STREQ("nonstatic_func", symbol); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit()); >+ >+ // The name of an internal linkage symbol is not specified; allow either a >+ // mangled or an unmangled name here. >+ symbol = SymbolizeStackConsumption((void *)(&static_func), &stack_consumed); >+ EXPECT_TRUE(strcmp("static_func", symbol) == 0 || >+ strcmp("static_func()", symbol) == 0); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit()); >+} >+ >+TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { >+ Foo::func(100); >+ int stack_consumed = 0; >+ >+ const char *symbol = >+ SymbolizeStackConsumption((void *)(&Foo::func), &stack_consumed); >+ >+ EXPECT_STREQ("Foo::func()", symbol); >+ EXPECT_GT(stack_consumed, 0); >+ EXPECT_LT(stack_consumed, GetStackConsumptionUpperLimit()); >+} >+ >+#endif // ABSL_INTERNAL_HAVE_DEBUGGING_STACK_CONSUMPTION >+ >+// Use a 64K page size for PPC. >+const size_t kPageSize = 64 << 10; >+// We place a read-only symbols into the .text section and verify that we can >+// symbolize them and other symbols after remapping them. >+const char kPadding0[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = >+ ""; >+const char kPadding1[kPageSize * 4] ABSL_ATTRIBUTE_SECTION_VARIABLE(.text) = >+ ""; >+ >+static int FilterElfHeader(struct dl_phdr_info *info, size_t size, void *data) { >+ for (int i = 0; i < info->dlpi_phnum; i++) { >+ if (info->dlpi_phdr[i].p_type == PT_LOAD && >+ info->dlpi_phdr[i].p_flags == (PF_R | PF_X)) { >+ const void *const vaddr = >+ absl::bit_cast<void *>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); >+ const auto segsize = info->dlpi_phdr[i].p_memsz; >+ >+ const char *self_exe; >+ if (info->dlpi_name != nullptr && info->dlpi_name[0] != '\0') { >+ self_exe = info->dlpi_name; >+ } else { >+ self_exe = "/proc/self/exe"; >+ } >+ >+ absl::debugging_internal::RegisterFileMappingHint( >+ vaddr, reinterpret_cast<const char *>(vaddr) + segsize, >+ info->dlpi_phdr[i].p_offset, self_exe); >+ >+ return 1; >+ } >+ } >+ >+ return 1; >+} >+ >+TEST(Symbolize, SymbolizeWithMultipleMaps) { >+ // Force kPadding0 and kPadding1 to be linked in. >+ if (volatile_bool) { >+ ABSL_RAW_LOG(INFO, "%s", kPadding0); >+ ABSL_RAW_LOG(INFO, "%s", kPadding1); >+ } >+ >+ // Verify we can symbolize everything. >+ char buf[512]; >+ memset(buf, 0, sizeof(buf)); >+ absl::Symbolize(kPadding0, buf, sizeof(buf)); >+ EXPECT_STREQ("kPadding0", buf); >+ >+ memset(buf, 0, sizeof(buf)); >+ absl::Symbolize(kPadding1, buf, sizeof(buf)); >+ EXPECT_STREQ("kPadding1", buf); >+ >+ // Specify a hint for the executable segment. >+ dl_iterate_phdr(FilterElfHeader, nullptr); >+ >+ // Reload at least one page out of kPadding0, kPadding1 >+ const char *ptrs[] = {kPadding0, kPadding1}; >+ >+ for (const char *ptr : ptrs) { >+ const int kMapFlags = MAP_ANONYMOUS | MAP_PRIVATE; >+ void *addr = mmap(nullptr, kPageSize, PROT_READ, kMapFlags, 0, 0); >+ ASSERT_NE(addr, MAP_FAILED); >+ >+ // kPadding[0-1] is full of zeroes, so we can remap anywhere within it, but >+ // we ensure there is at least a full page of padding. >+ void *remapped = reinterpret_cast<void *>( >+ reinterpret_cast<uintptr_t>(ptr + kPageSize) & ~(kPageSize - 1ULL)); >+ >+ const int kMremapFlags = (MREMAP_MAYMOVE | MREMAP_FIXED); >+ void *ret = mremap(addr, kPageSize, kPageSize, kMremapFlags, remapped); >+ ASSERT_NE(ret, MAP_FAILED); >+ } >+ >+ // Invalidate the symbolization cache so we are forced to rely on the hint. >+ absl::Symbolize(nullptr, buf, sizeof(buf)); >+ >+ // Verify we can still symbolize. >+ const char *expected[] = {"kPadding0", "kPadding1"}; >+ const size_t offsets[] = {0, kPageSize, 2 * kPageSize, 3 * kPageSize}; >+ >+ for (int i = 0; i < 2; i++) { >+ for (size_t offset : offsets) { >+ memset(buf, 0, sizeof(buf)); >+ absl::Symbolize(ptrs[i] + offset, buf, sizeof(buf)); >+ EXPECT_STREQ(expected[i], buf); >+ } >+ } >+} >+ >+// Appends std::string(*args->arg) to args->symbol_buf. >+static void DummySymbolDecorator( >+ const absl::debugging_internal::SymbolDecoratorArgs *args) { >+ std::string *message = static_cast<std::string *>(args->arg); >+ strncat(args->symbol_buf, message->c_str(), >+ args->symbol_buf_size - strlen(args->symbol_buf) - 1); >+} >+ >+TEST(Symbolize, InstallAndRemoveSymbolDecorators) { >+ int ticket_a; >+ std::string a_message("a"); >+ EXPECT_GE(ticket_a = absl::debugging_internal::InstallSymbolDecorator( >+ DummySymbolDecorator, &a_message), >+ 0); >+ >+ int ticket_b; >+ std::string b_message("b"); >+ EXPECT_GE(ticket_b = absl::debugging_internal::InstallSymbolDecorator( >+ DummySymbolDecorator, &b_message), >+ 0); >+ >+ int ticket_c; >+ std::string c_message("c"); >+ EXPECT_GE(ticket_c = absl::debugging_internal::InstallSymbolDecorator( >+ DummySymbolDecorator, &c_message), >+ 0); >+ >+ char *address = reinterpret_cast<char *>(1); >+ EXPECT_STREQ("abc", TrySymbolize(address++)); >+ >+ EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_b)); >+ >+ EXPECT_STREQ("ac", TrySymbolize(address++)); >+ >+ // Cleanup: remove all remaining decorators so other stack traces don't >+ // get mystery "ac" decoration. >+ EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_a)); >+ EXPECT_TRUE(absl::debugging_internal::RemoveSymbolDecorator(ticket_c)); >+} >+ >+// Some versions of Clang with optimizations enabled seem to be able >+// to optimize away the .data section if no variables live in the >+// section. This variable should get placed in the .data section, and >+// the test below checks for the existence of a .data section. >+static int in_data_section = 1; >+ >+TEST(Symbolize, ForEachSection) { >+ int fd = TEMP_FAILURE_RETRY(open("/proc/self/exe", O_RDONLY)); >+ ASSERT_NE(fd, -1); >+ >+ std::vector<std::string> sections; >+ ASSERT_TRUE(absl::debugging_internal::ForEachSection( >+ fd, [§ions](const std::string &name, const ElfW(Shdr) &) { >+ sections.push_back(name); >+ return true; >+ })); >+ >+ // Check for the presence of common section names. >+ EXPECT_THAT(sections, Contains(".text")); >+ EXPECT_THAT(sections, Contains(".rodata")); >+ EXPECT_THAT(sections, Contains(".bss")); >+ ++in_data_section; >+ EXPECT_THAT(sections, Contains(".data")); >+ >+ close(fd); >+} >+ >+// x86 specific tests. Uses some inline assembler. >+extern "C" { >+inline void *ABSL_ATTRIBUTE_ALWAYS_INLINE inline_func() { >+ void *pc = nullptr; >+#if defined(__i386__) || defined(__x86_64__) >+ __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); >+#endif >+ return pc; >+} >+ >+void *ABSL_ATTRIBUTE_NOINLINE non_inline_func() { >+ void *pc = nullptr; >+#if defined(__i386__) || defined(__x86_64__) >+ __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc)); >+#endif >+ return pc; >+} >+ >+void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { >+#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) && \ >+ (defined(__i386__) || defined(__x86_64__)) >+ void *pc = non_inline_func(); >+ const char *symbol = TrySymbolize(pc); >+ ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideNonInlineFunction failed"); >+ ABSL_RAW_CHECK(strcmp(symbol, "non_inline_func") == 0, >+ "TestWithPCInsideNonInlineFunction failed"); >+ std::cout << "TestWithPCInsideNonInlineFunction passed" << std::endl; >+#endif >+} >+ >+void ABSL_ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { >+#if defined(ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE) && \ >+ (defined(__i386__) || defined(__x86_64__)) >+ void *pc = inline_func(); // Must be inlined. >+ const char *symbol = TrySymbolize(pc); >+ ABSL_RAW_CHECK(symbol != nullptr, "TestWithPCInsideInlineFunction failed"); >+ ABSL_RAW_CHECK(strcmp(symbol, __FUNCTION__) == 0, >+ "TestWithPCInsideInlineFunction failed"); >+ std::cout << "TestWithPCInsideInlineFunction passed" << std::endl; >+#endif >+} >+} >+ >+// Test with a return address. >+void ABSL_ATTRIBUTE_NOINLINE TestWithReturnAddress() { >+#if defined(ABSL_HAVE_ATTRIBUTE_NOINLINE) >+ void *return_address = __builtin_return_address(0); >+ const char *symbol = TrySymbolize(return_address); >+ ABSL_RAW_CHECK(symbol != nullptr, "TestWithReturnAddress failed"); >+ ABSL_RAW_CHECK(strcmp(symbol, "main") == 0, "TestWithReturnAddress failed"); >+ std::cout << "TestWithReturnAddress passed" << std::endl; >+#endif >+} >+ >+#elif defined(_WIN32) && defined(_DEBUG) >+ >+TEST(Symbolize, Basics) { >+ EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func))); >+ >+ // The name of an internal linkage symbol is not specified; allow either a >+ // mangled or an unmangled name here. >+ const char* static_func_symbol = TrySymbolize((void *)(&static_func)); >+ ASSERT_TRUE(static_func_symbol != nullptr); >+ EXPECT_TRUE(strstr(static_func_symbol, "static_func") != nullptr); >+ >+ EXPECT_TRUE(nullptr == TrySymbolize(nullptr)); >+} >+ >+TEST(Symbolize, Truncation) { >+ constexpr char kNonStaticFunc[] = "nonstatic_func"; >+ EXPECT_STREQ("nonstatic_func", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) + 1)); >+ EXPECT_STREQ("nonstatic_...", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) + 0)); >+ EXPECT_STREQ("nonstatic...", >+ TrySymbolizeWithLimit((void *)(&nonstatic_func), >+ strlen(kNonStaticFunc) - 1)); >+ EXPECT_STREQ("n...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 5)); >+ EXPECT_STREQ("...", TrySymbolizeWithLimit((void *)(&nonstatic_func), 4)); >+ EXPECT_STREQ("..", TrySymbolizeWithLimit((void *)(&nonstatic_func), 3)); >+ EXPECT_STREQ(".", TrySymbolizeWithLimit((void *)(&nonstatic_func), 2)); >+ EXPECT_STREQ("", TrySymbolizeWithLimit((void *)(&nonstatic_func), 1)); >+ EXPECT_EQ(nullptr, TrySymbolizeWithLimit((void *)(&nonstatic_func), 0)); >+} >+ >+TEST(Symbolize, SymbolizeWithDemangling) { >+ const char* result = TrySymbolize((void *)(&Foo::func)); >+ ASSERT_TRUE(result != nullptr); >+ EXPECT_TRUE(strstr(result, "Foo::func") != nullptr) << result; >+} >+ >+#else // Symbolizer unimplemented >+ >+TEST(Symbolize, Unimplemented) { >+ char buf[64]; >+ EXPECT_FALSE(absl::Symbolize((void *)(&nonstatic_func), buf, sizeof(buf))); >+ EXPECT_FALSE(absl::Symbolize((void *)(&static_func), buf, sizeof(buf))); >+ EXPECT_FALSE(absl::Symbolize((void *)(&Foo::func), buf, sizeof(buf))); >+} >+ >+#endif >+ >+int main(int argc, char **argv) { >+ // Make sure kHpageTextPadding is linked into the binary. >+ if (volatile_bool) { >+ ABSL_RAW_LOG(INFO, "%s", kHpageTextPadding); >+ } >+ >+#if ABSL_PER_THREAD_TLS >+ // Touch the per-thread variables. >+ symbolize_test_thread_small[0] = 0; >+ symbolize_test_thread_big[0] = 0; >+#endif >+ >+ absl::InitializeSymbolizer(argv[0]); >+ testing::InitGoogleTest(&argc, argv); >+ >+#ifdef ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE >+ TestWithPCInsideInlineFunction(); >+ TestWithPCInsideNonInlineFunction(); >+ TestWithReturnAddress(); >+#endif >+ >+ return RUN_ALL_TESTS(); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_unimplemented.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_unimplemented.inc >new file mode 100644 >index 00000000000..2a3f4acb0e1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_unimplemented.inc >@@ -0,0 +1,35 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstdint> >+ >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+namespace debugging_internal { >+ >+int InstallSymbolDecorator(SymbolDecorator, void*) { return -1; } >+bool RemoveSymbolDecorator(int) { return false; } >+bool RemoveAllSymbolDecorators(void) { return false; } >+bool RegisterFileMappingHint(const void *, const void *, uint64_t, const char *) { >+ return false; >+} >+ >+} // namespace debugging_internal >+ >+void InitializeSymbolizer(const char*) {} >+bool Symbolize(const void *, char *, int) { return false; } >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc >new file mode 100644 >index 00000000000..e3fff74d493 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/debugging/symbolize_win32.inc >@@ -0,0 +1,74 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// See "Retrieving Symbol Information by Address": >+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx >+ >+#include <windows.h> >+#include <DbgHelp.h> >+#pragma comment(lib, "DbgHelp") >+ >+#include <algorithm> >+#include <cstring> >+ >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+static HANDLE process = NULL; >+ >+void InitializeSymbolizer(const char *argv0) { >+ if (process != nullptr) { >+ return; >+ } >+ process = GetCurrentProcess(); >+ >+ // Symbols are not loaded until a reference is made requiring the >+ // symbols be loaded. This is the fastest, most efficient way to use >+ // the symbol handler. >+ SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME); >+ if (!SymInitialize(process, nullptr, true)) { >+ // GetLastError() returns a Win32 DWORD, but we assign to >+ // unsigned long long to simplify the ABSL_RAW_LOG case below. The uniform >+ // initialization guarantees this is not a narrowing conversion. >+ const unsigned long long error{GetLastError()}; // NOLINT(runtime/int) >+ ABSL_RAW_LOG(FATAL, "SymInitialize() failed: %llu", error); >+ } >+} >+ >+bool Symbolize(const void *pc, char *out, int out_size) { >+ if (out_size <= 0) { >+ return false; >+ } >+ std::aligned_storage<sizeof(SYMBOL_INFO) + MAX_SYM_NAME, >+ alignof(SYMBOL_INFO)>::type buf; >+ SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(&buf); >+ symbol->SizeOfStruct = sizeof(SYMBOL_INFO); >+ symbol->MaxNameLen = MAX_SYM_NAME; >+ if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) { >+ return false; >+ } >+ strncpy(out, symbol->Name, out_size); >+ if (out[out_size - 1] != '\0') { >+ // strncpy() does not '\0' terminate when it truncates. >+ static constexpr char kEllipsis[] = "..."; >+ int ellipsis_size = >+ std::min<int>(sizeof(kEllipsis) - 1, out_size - 1); >+ memcpy(out + out_size - ellipsis_size - 1, kEllipsis, ellipsis_size); >+ out[out_size - 1] = '\0'; >+ } >+ return true; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.bazel >new file mode 100644 >index 00000000000..46f47b12bb2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.bazel >@@ -0,0 +1,61 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+ "ABSL_EXCEPTIONS_FLAG", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "memory", >+ hdrs = ["memory.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ ], >+) >+ >+cc_test( >+ name = "memory_test", >+ srcs = ["memory_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":memory", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "memory_exception_safety_test", >+ srcs = [ >+ "memory_exception_safety_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":memory", >+ "//absl/base:exception_safety_testing", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.gn >new file mode 100644 >index 00000000000..30224c6a112 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/BUILD.gn >@@ -0,0 +1,31 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("memory") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "memory.h", >+ ] >+ deps = [ >+ "../base:core_headers", >+ "../meta:type_traits", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/CMakeLists.txt >new file mode 100644 >index 00000000000..5958f5c52bf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/CMakeLists.txt >@@ -0,0 +1,71 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND MEMORY_PUBLIC_HEADERS >+ "memory.h" >+) >+ >+ >+absl_header_library( >+ TARGET >+ absl_memory >+ EXPORT_NAME >+ memory >+) >+ >+# >+## TESTS >+# >+ >+# test memory_test >+list(APPEND MEMORY_TEST_SRC >+ "memory_test.cc" >+ ${MEMORY_PUBLIC_HEADERS} >+) >+set(MEMORY_TEST_PUBLIC_LIBRARIES absl::base absl::memory) >+ >+ >+ >+absl_test( >+ TARGET >+ memory_test >+ SOURCES >+ ${MEMORY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${MEMORY_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test memory_exception_safety_test >+set(MEMORY_EXCEPTION_SAFETY_TEST_SRC "memory_exception_safety_test.cc") >+set(MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES >+ absl::memory >+ absl_base_internal_exception_safety_testing >+) >+ >+absl_test( >+ TARGET >+ memory_exception_safety_test >+ SOURCES >+ ${MEMORY_EXCEPTION_SAFETY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${MEMORY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory.h >new file mode 100644 >index 00000000000..4d9cc0075df >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory.h >@@ -0,0 +1,697 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: memory.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains utility functions for managing the creation and >+// conversion of smart pointers. This file is an extension to the C++ >+// standard <memory> library header file. >+ >+#ifndef ABSL_MEMORY_MEMORY_H_ >+#define ABSL_MEMORY_MEMORY_H_ >+ >+#include <cstddef> >+#include <limits> >+#include <memory> >+#include <new> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/base/macros.h" >+#include "absl/meta/type_traits.h" >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// Function Template: WrapUnique() >+// ----------------------------------------------------------------------------- >+// >+// Adopts ownership from a raw pointer and transfers it to the returned >+// `std::unique_ptr`, whose type is deduced. DO NOT specify the template type T >+// when calling WrapUnique. >+// >+// Example: >+// X* NewX(int, int); >+// auto x = WrapUnique(NewX(1, 2)); // 'x' is std::unique_ptr<X>. >+// >+// `absl::WrapUnique` is useful for capturing the output of a raw pointer >+// factory. However, prefer 'absl::make_unique<T>(args...) over >+// 'absl::WrapUnique(new T(args...))'. >+// >+// auto x = WrapUnique(new X(1, 2)); // works, but nonideal. >+// auto x = make_unique<X>(1, 2); // safer, standard, avoids raw 'new'. >+// >+// Note that `absl::WrapUnique(p)` is valid only if `delete p` is a valid >+// expression. In particular, `absl::WrapUnique()` cannot wrap pointers to >+// arrays, functions or void, and it must not be used to capture pointers >+// obtained from array-new expressions (even though that would compile!). >+template <typename T> >+std::unique_ptr<T> WrapUnique(T* ptr) { >+ static_assert(!std::is_array<T>::value, "array types are unsupported"); >+ static_assert(std::is_object<T>::value, "non-object types are unsupported"); >+ return std::unique_ptr<T>(ptr); >+} >+ >+namespace memory_internal { >+ >+// Traits to select proper overload and return type for `absl::make_unique<>`. >+template <typename T> >+struct MakeUniqueResult { >+ using scalar = std::unique_ptr<T>; >+}; >+template <typename T> >+struct MakeUniqueResult<T[]> { >+ using array = std::unique_ptr<T[]>; >+}; >+template <typename T, size_t N> >+struct MakeUniqueResult<T[N]> { >+ using invalid = void; >+}; >+ >+} // namespace memory_internal >+ >+// gcc 4.8 has __cplusplus at 201301 but doesn't define make_unique. Other >+// supported compilers either just define __cplusplus as 201103 but have >+// make_unique (msvc), or have make_unique whenever __cplusplus > 201103 (clang) >+#if (__cplusplus > 201103L || defined(_MSC_VER)) && \ >+ !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8) >+using std::make_unique; >+#else >+// ----------------------------------------------------------------------------- >+// Function Template: make_unique<T>() >+// ----------------------------------------------------------------------------- >+// >+// Creates a `std::unique_ptr<>`, while avoiding issues creating temporaries >+// during the construction process. `absl::make_unique<>` also avoids redundant >+// type declarations, by avoiding the need to explicitly use the `new` operator. >+// >+// This implementation of `absl::make_unique<>` is designed for C++11 code and >+// will be replaced in C++14 by the equivalent `std::make_unique<>` abstraction. >+// `absl::make_unique<>` is designed to be 100% compatible with >+// `std::make_unique<>` so that the eventual migration will involve a simple >+// rename operation. >+// >+// For more background on why `std::unique_ptr<T>(new T(a,b))` is problematic, >+// see Herb Sutter's explanation on >+// (Exception-Safe Function Calls)[http://herbsutter.com/gotw/_102/]. >+// (In general, reviewers should treat `new T(a,b)` with scrutiny.) >+// >+// Example usage: >+// >+// auto p = make_unique<X>(args...); // 'p' is a std::unique_ptr<X> >+// auto pa = make_unique<X[]>(5); // 'pa' is a std::unique_ptr<X[]> >+// >+// Three overloads of `absl::make_unique` are required: >+// >+// - For non-array T: >+// >+// Allocates a T with `new T(std::forward<Args> args...)`, >+// forwarding all `args` to T's constructor. >+// Returns a `std::unique_ptr<T>` owning that object. >+// >+// - For an array of unknown bounds T[]: >+// >+// `absl::make_unique<>` will allocate an array T of type U[] with >+// `new U[n]()` and return a `std::unique_ptr<U[]>` owning that array. >+// >+// Note that 'U[n]()' is different from 'U[n]', and elements will be >+// value-initialized. Note as well that `std::unique_ptr` will perform its >+// own destruction of the array elements upon leaving scope, even though >+// the array [] does not have a default destructor. >+// >+// NOTE: an array of unknown bounds T[] may still be (and often will be) >+// initialized to have a size, and will still use this overload. E.g: >+// >+// auto my_array = absl::make_unique<int[]>(10); >+// >+// - For an array of known bounds T[N]: >+// >+// `absl::make_unique<>` is deleted (like with `std::make_unique<>`) as >+// this overload is not useful. >+// >+// NOTE: an array of known bounds T[N] is not considered a useful >+// construction, and may cause undefined behavior in templates. E.g: >+// >+// auto my_array = absl::make_unique<int[10]>(); >+// >+// In those cases, of course, you can still use the overload above and >+// simply initialize it to its desired size: >+// >+// auto my_array = absl::make_unique<int[]>(10); >+ >+// `absl::make_unique` overload for non-array types. >+template <typename T, typename... Args> >+typename memory_internal::MakeUniqueResult<T>::scalar make_unique( >+ Args&&... args) { >+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); >+} >+ >+// `absl::make_unique` overload for an array T[] of unknown bounds. >+// The array allocation needs to use the `new T[size]` form and cannot take >+// element constructor arguments. The `std::unique_ptr` will manage destructing >+// these array elements. >+template <typename T> >+typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) { >+ return std::unique_ptr<T>(new typename absl::remove_extent_t<T>[n]()); >+} >+ >+// `absl::make_unique` overload for an array T[N] of known bounds. >+// This construction will be rejected. >+template <typename T, typename... Args> >+typename memory_internal::MakeUniqueResult<T>::invalid make_unique( >+ Args&&... /* args */) = delete; >+#endif >+ >+// ----------------------------------------------------------------------------- >+// Function Template: RawPtr() >+// ----------------------------------------------------------------------------- >+// >+// Extracts the raw pointer from a pointer-like value `ptr`. `absl::RawPtr` is >+// useful within templates that need to handle a complement of raw pointers, >+// `std::nullptr_t`, and smart pointers. >+template <typename T> >+auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr)) { >+ // ptr is a forwarding reference to support Ts with non-const operators. >+ return (ptr != nullptr) ? std::addressof(*ptr) : nullptr; >+} >+inline std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; } >+ >+// ----------------------------------------------------------------------------- >+// Function Template: ShareUniquePtr() >+// ----------------------------------------------------------------------------- >+// >+// Adopts a `std::unique_ptr` rvalue and returns a `std::shared_ptr` of deduced >+// type. Ownership (if any) of the held value is transferred to the returned >+// shared pointer. >+// >+// Example: >+// >+// auto up = absl::make_unique<int>(10); >+// auto sp = absl::ShareUniquePtr(std::move(up)); // shared_ptr<int> >+// CHECK_EQ(*sp, 10); >+// CHECK(up == nullptr); >+// >+// Note that this conversion is correct even when T is an array type, and more >+// generally it works for *any* deleter of the `unique_ptr` (single-object >+// deleter, array deleter, or any custom deleter), since the deleter is adopted >+// by the shared pointer as well. The deleter is copied (unless it is a >+// reference). >+// >+// Implements the resolution of [LWG 2415](http://wg21.link/lwg2415), by which a >+// null shared pointer does not attempt to call the deleter. >+template <typename T, typename D> >+std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) { >+ return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>(); >+} >+ >+// ----------------------------------------------------------------------------- >+// Function Template: WeakenPtr() >+// ----------------------------------------------------------------------------- >+// >+// Creates a weak pointer associated with a given shared pointer. The returned >+// value is a `std::weak_ptr` of deduced type. >+// >+// Example: >+// >+// auto sp = std::make_shared<int>(10); >+// auto wp = absl::WeakenPtr(sp); >+// CHECK_EQ(sp.get(), wp.lock().get()); >+// sp.reset(); >+// CHECK(wp.lock() == nullptr); >+// >+template <typename T> >+std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) { >+ return std::weak_ptr<T>(ptr); >+} >+ >+namespace memory_internal { >+ >+// ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D. >+template <template <typename> class Extract, typename Obj, typename Default, >+ typename> >+struct ExtractOr { >+ using type = Default; >+}; >+ >+template <template <typename> class Extract, typename Obj, typename Default> >+struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> { >+ using type = Extract<Obj>; >+}; >+ >+template <template <typename> class Extract, typename Obj, typename Default> >+using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type; >+ >+// Extractors for the features of allocators. >+template <typename T> >+using GetPointer = typename T::pointer; >+ >+template <typename T> >+using GetConstPointer = typename T::const_pointer; >+ >+template <typename T> >+using GetVoidPointer = typename T::void_pointer; >+ >+template <typename T> >+using GetConstVoidPointer = typename T::const_void_pointer; >+ >+template <typename T> >+using GetDifferenceType = typename T::difference_type; >+ >+template <typename T> >+using GetSizeType = typename T::size_type; >+ >+template <typename T> >+using GetPropagateOnContainerCopyAssignment = >+ typename T::propagate_on_container_copy_assignment; >+ >+template <typename T> >+using GetPropagateOnContainerMoveAssignment = >+ typename T::propagate_on_container_move_assignment; >+ >+template <typename T> >+using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap; >+ >+template <typename T> >+using GetIsAlwaysEqual = typename T::is_always_equal; >+ >+template <typename T> >+struct GetFirstArg; >+ >+template <template <typename...> class Class, typename T, typename... Args> >+struct GetFirstArg<Class<T, Args...>> { >+ using type = T; >+}; >+ >+template <typename Ptr, typename = void> >+struct ElementType { >+ using type = typename GetFirstArg<Ptr>::type; >+}; >+ >+template <typename T> >+struct ElementType<T, void_t<typename T::element_type>> { >+ using type = typename T::element_type; >+}; >+ >+template <typename T, typename U> >+struct RebindFirstArg; >+ >+template <template <typename...> class Class, typename T, typename... Args, >+ typename U> >+struct RebindFirstArg<Class<T, Args...>, U> { >+ using type = Class<U, Args...>; >+}; >+ >+template <typename T, typename U, typename = void> >+struct RebindPtr { >+ using type = typename RebindFirstArg<T, U>::type; >+}; >+ >+template <typename T, typename U> >+struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> { >+ using type = typename T::template rebind<U>; >+}; >+ >+template <typename T, typename U> >+constexpr bool HasRebindAlloc(...) { >+ return false; >+} >+ >+template <typename T, typename U> >+constexpr bool HasRebindAlloc(typename T::template rebind<U>::other*) { >+ return true; >+} >+ >+template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)> >+struct RebindAlloc { >+ using type = typename RebindFirstArg<T, U>::type; >+}; >+ >+template <typename T, typename U> >+struct RebindAlloc<T, U, true> { >+ using type = typename T::template rebind<U>::other; >+}; >+ >+} // namespace memory_internal >+ >+// ----------------------------------------------------------------------------- >+// Class Template: pointer_traits >+// ----------------------------------------------------------------------------- >+// >+// An implementation of C++11's std::pointer_traits. >+// >+// Provided for portability on toolchains that have a working C++11 compiler, >+// but the standard library is lacking in C++11 support. For example, some >+// version of the Android NDK. >+// >+ >+template <typename Ptr> >+struct pointer_traits { >+ using pointer = Ptr; >+ >+ // element_type: >+ // Ptr::element_type if present. Otherwise T if Ptr is a template >+ // instantiation Template<T, Args...> >+ using element_type = typename memory_internal::ElementType<Ptr>::type; >+ >+ // difference_type: >+ // Ptr::difference_type if present, otherwise std::ptrdiff_t >+ using difference_type = >+ memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr, >+ std::ptrdiff_t>; >+ >+ // rebind: >+ // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a >+ // template instantiation Template<T, Args...> >+ template <typename U> >+ using rebind = typename memory_internal::RebindPtr<Ptr, U>::type; >+ >+ // pointer_to: >+ // Calls Ptr::pointer_to(r) >+ static pointer pointer_to(element_type& r) { // NOLINT(runtime/references) >+ return Ptr::pointer_to(r); >+ } >+}; >+ >+// Specialization for T*. >+template <typename T> >+struct pointer_traits<T*> { >+ using pointer = T*; >+ using element_type = T; >+ using difference_type = std::ptrdiff_t; >+ >+ template <typename U> >+ using rebind = U*; >+ >+ // pointer_to: >+ // Calls std::addressof(r) >+ static pointer pointer_to( >+ element_type& r) noexcept { // NOLINT(runtime/references) >+ return std::addressof(r); >+ } >+}; >+ >+// ----------------------------------------------------------------------------- >+// Class Template: allocator_traits >+// ----------------------------------------------------------------------------- >+// >+// A C++11 compatible implementation of C++17's std::allocator_traits. >+// >+template <typename Alloc> >+struct allocator_traits { >+ using allocator_type = Alloc; >+ >+ // value_type: >+ // Alloc::value_type >+ using value_type = typename Alloc::value_type; >+ >+ // pointer: >+ // Alloc::pointer if present, otherwise value_type* >+ using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer, >+ Alloc, value_type*>; >+ >+ // const_pointer: >+ // Alloc::const_pointer if present, otherwise >+ // absl::pointer_traits<pointer>::rebind<const value_type> >+ using const_pointer = >+ memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc, >+ typename absl::pointer_traits<pointer>:: >+ template rebind<const value_type>>; >+ >+ // void_pointer: >+ // Alloc::void_pointer if present, otherwise >+ // absl::pointer_traits<pointer>::rebind<void> >+ using void_pointer = memory_internal::ExtractOrT< >+ memory_internal::GetVoidPointer, Alloc, >+ typename absl::pointer_traits<pointer>::template rebind<void>>; >+ >+ // const_void_pointer: >+ // Alloc::const_void_pointer if present, otherwise >+ // absl::pointer_traits<pointer>::rebind<const void> >+ using const_void_pointer = memory_internal::ExtractOrT< >+ memory_internal::GetConstVoidPointer, Alloc, >+ typename absl::pointer_traits<pointer>::template rebind<const void>>; >+ >+ // difference_type: >+ // Alloc::difference_type if present, otherwise >+ // absl::pointer_traits<pointer>::difference_type >+ using difference_type = memory_internal::ExtractOrT< >+ memory_internal::GetDifferenceType, Alloc, >+ typename absl::pointer_traits<pointer>::difference_type>; >+ >+ // size_type: >+ // Alloc::size_type if present, otherwise >+ // std::make_unsigned<difference_type>::type >+ using size_type = memory_internal::ExtractOrT< >+ memory_internal::GetSizeType, Alloc, >+ typename std::make_unsigned<difference_type>::type>; >+ >+ // propagate_on_container_copy_assignment: >+ // Alloc::propagate_on_container_copy_assignment if present, otherwise >+ // std::false_type >+ using propagate_on_container_copy_assignment = memory_internal::ExtractOrT< >+ memory_internal::GetPropagateOnContainerCopyAssignment, Alloc, >+ std::false_type>; >+ >+ // propagate_on_container_move_assignment: >+ // Alloc::propagate_on_container_move_assignment if present, otherwise >+ // std::false_type >+ using propagate_on_container_move_assignment = memory_internal::ExtractOrT< >+ memory_internal::GetPropagateOnContainerMoveAssignment, Alloc, >+ std::false_type>; >+ >+ // propagate_on_container_swap: >+ // Alloc::propagate_on_container_swap if present, otherwise std::false_type >+ using propagate_on_container_swap = >+ memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap, >+ Alloc, std::false_type>; >+ >+ // is_always_equal: >+ // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type >+ using is_always_equal = >+ memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc, >+ typename std::is_empty<Alloc>::type>; >+ >+ // rebind_alloc: >+ // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc >+ // is Alloc<U, Args> >+ template <typename T> >+ using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type; >+ >+ // rebind_traits: >+ // absl::allocator_traits<rebind_alloc<T>> >+ template <typename T> >+ using rebind_traits = absl::allocator_traits<rebind_alloc<T>>; >+ >+ // allocate(Alloc& a, size_type n): >+ // Calls a.allocate(n) >+ static pointer allocate(Alloc& a, // NOLINT(runtime/references) >+ size_type n) { >+ return a.allocate(n); >+ } >+ >+ // allocate(Alloc& a, size_type n, const_void_pointer hint): >+ // Calls a.allocate(n, hint) if possible. >+ // If not possible, calls a.allocate(n) >+ static pointer allocate(Alloc& a, size_type n, // NOLINT(runtime/references) >+ const_void_pointer hint) { >+ return allocate_impl(0, a, n, hint); >+ } >+ >+ // deallocate(Alloc& a, pointer p, size_type n): >+ // Calls a.deallocate(p, n) >+ static void deallocate(Alloc& a, pointer p, // NOLINT(runtime/references) >+ size_type n) { >+ a.deallocate(p, n); >+ } >+ >+ // construct(Alloc& a, T* p, Args&&... args): >+ // Calls a.construct(p, std::forward<Args>(args)...) if possible. >+ // If not possible, calls >+ // ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...) >+ template <typename T, typename... Args> >+ static void construct(Alloc& a, T* p, // NOLINT(runtime/references) >+ Args&&... args) { >+ construct_impl(0, a, p, std::forward<Args>(args)...); >+ } >+ >+ // destroy(Alloc& a, T* p): >+ // Calls a.destroy(p) if possible. If not possible, calls p->~T(). >+ template <typename T> >+ static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references) >+ destroy_impl(0, a, p); >+ } >+ >+ // max_size(const Alloc& a): >+ // Returns a.max_size() if possible. If not possible, returns >+ // std::numeric_limits<size_type>::max() / sizeof(value_type) >+ static size_type max_size(const Alloc& a) { return max_size_impl(0, a); } >+ >+ // select_on_container_copy_construction(const Alloc& a): >+ // Returns a.select_on_container_copy_construction() if possible. >+ // If not possible, returns a. >+ static Alloc select_on_container_copy_construction(const Alloc& a) { >+ return select_on_container_copy_construction_impl(0, a); >+ } >+ >+ private: >+ template <typename A> >+ static auto allocate_impl(int, A& a, // NOLINT(runtime/references) >+ size_type n, const_void_pointer hint) >+ -> decltype(a.allocate(n, hint)) { >+ return a.allocate(n, hint); >+ } >+ static pointer allocate_impl(char, Alloc& a, // NOLINT(runtime/references) >+ size_type n, const_void_pointer) { >+ return a.allocate(n); >+ } >+ >+ template <typename A, typename... Args> >+ static auto construct_impl(int, A& a, // NOLINT(runtime/references) >+ Args&&... args) >+ -> decltype(a.construct(std::forward<Args>(args)...)) { >+ a.construct(std::forward<Args>(args)...); >+ } >+ >+ template <typename T, typename... Args> >+ static void construct_impl(char, Alloc&, T* p, Args&&... args) { >+ ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...); >+ } >+ >+ template <typename A, typename T> >+ static auto destroy_impl(int, A& a, // NOLINT(runtime/references) >+ T* p) -> decltype(a.destroy(p)) { >+ a.destroy(p); >+ } >+ template <typename T> >+ static void destroy_impl(char, Alloc&, T* p) { >+ p->~T(); >+ } >+ >+ template <typename A> >+ static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) { >+ return a.max_size(); >+ } >+ static size_type max_size_impl(char, const Alloc&) { >+ return std::numeric_limits<size_type>::max() / sizeof(value_type); >+ } >+ >+ template <typename A> >+ static auto select_on_container_copy_construction_impl(int, const A& a) >+ -> decltype(a.select_on_container_copy_construction()) { >+ return a.select_on_container_copy_construction(); >+ } >+ static Alloc select_on_container_copy_construction_impl(char, >+ const Alloc& a) { >+ return a; >+ } >+}; >+ >+namespace memory_internal { >+ >+// This template alias transforms Alloc::is_nothrow into a metafunction with >+// Alloc as a parameter so it can be used with ExtractOrT<>. >+template <typename Alloc> >+using GetIsNothrow = typename Alloc::is_nothrow; >+ >+} // namespace memory_internal >+ >+// ABSL_ALLOCATOR_NOTHROW is a build time configuration macro for user to >+// specify whether the default allocation function can throw or never throws. >+// If the allocation function never throws, user should define it to a non-zero >+// value (e.g. via `-DABSL_ALLOCATOR_NOTHROW`). >+// If the allocation function can throw, user should leave it undefined or >+// define it to zero. >+// >+// allocator_is_nothrow<Alloc> is a traits class that derives from >+// Alloc::is_nothrow if present, otherwise std::false_type. It's specialized >+// for Alloc = std::allocator<T> for any type T according to the state of >+// ABSL_ALLOCATOR_NOTHROW. >+// >+// default_allocator_is_nothrow is a class that derives from std::true_type >+// when the default allocator (global operator new) never throws, and >+// std::false_type when it can throw. It is a convenience shorthand for writing >+// allocator_is_nothrow<std::allocator<T>> (T can be any type). >+// NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from >+// the same type for all T, because users should specialize neither >+// allocator_is_nothrow nor std::allocator. >+template <typename Alloc> >+struct allocator_is_nothrow >+ : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc, >+ std::false_type> {}; >+ >+// FIXME: Define ABSL_ALLOCATOR_NOTHROW >+#if 1 >+template <typename T> >+struct allocator_is_nothrow<std::allocator<T>> : std::true_type {}; >+struct default_allocator_is_nothrow : std::true_type {}; >+#else >+struct default_allocator_is_nothrow : std::false_type {}; >+#endif >+ >+namespace memory_internal { >+#ifdef ABSL_HAVE_EXCEPTIONS >+template <typename Allocator, typename StorageElement, typename... Args> >+void ConstructStorage(Allocator* alloc, StorageElement* first, >+ StorageElement* last, const Args&... args) { >+ for (StorageElement* cur = first; cur != last; ++cur) { >+ try { >+ std::allocator_traits<Allocator>::construct(*alloc, cur, args...); >+ } catch (...) { >+ while (cur != first) { >+ --cur; >+ std::allocator_traits<Allocator>::destroy(*alloc, cur); >+ } >+ throw; >+ } >+ } >+} >+template <typename Allocator, typename StorageElement, typename Iterator> >+void CopyToStorageFromRange(Allocator* alloc, StorageElement* destination, >+ Iterator first, Iterator last) { >+ for (StorageElement* cur = destination; first != last; >+ static_cast<void>(++cur), static_cast<void>(++first)) { >+ try { >+ std::allocator_traits<Allocator>::construct(*alloc, cur, *first); >+ } catch (...) { >+ while (cur != destination) { >+ --cur; >+ std::allocator_traits<Allocator>::destroy(*alloc, cur); >+ } >+ throw; >+ } >+ } >+} >+#else // ABSL_HAVE_EXCEPTIONS >+template <typename Allocator, typename StorageElement, typename... Args> >+void ConstructStorage(Allocator* alloc, StorageElement* first, >+ StorageElement* last, const Args&... args) { >+ for (; first != last; ++first) { >+ std::allocator_traits<Allocator>::construct(*alloc, first, args...); >+ } >+} >+template <typename Allocator, typename StorageElement, typename Iterator> >+void CopyToStorageFromRange(Allocator* alloc, StorageElement* destination, >+ Iterator first, Iterator last) { >+ for (; first != last; >+ static_cast<void>(++destination), static_cast<void>(++first)) { >+ std::allocator_traits<Allocator>::construct(*alloc, destination, *first); >+ } >+} >+#endif // ABSL_HAVE_EXCEPTIONS >+} // namespace memory_internal >+} // namespace absl >+ >+#endif // ABSL_MEMORY_MEMORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc >new file mode 100644 >index 00000000000..d1f6e84f10f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_exception_safety_test.cc >@@ -0,0 +1,52 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/memory/memory.h" >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_safety_testing.h" >+ >+namespace absl { >+namespace { >+ >+constexpr int kLength = 50; >+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; >+using ThrowerStorage = >+ absl::aligned_storage_t<sizeof(Thrower), alignof(Thrower)>; >+using ThrowerList = std::array<ThrowerStorage, kLength>; >+ >+TEST(MakeUnique, CheckForLeaks) { >+ constexpr int kValue = 321; >+ auto tester = testing::MakeExceptionSafetyTester() >+ .WithInitialValue(Thrower(kValue)) >+ // Ensures make_unique does not modify the input. The real >+ // test, though, is ConstructorTracker checking for leaks. >+ .WithInvariants(testing::strong_guarantee); >+ >+ EXPECT_TRUE(tester.Test([](Thrower* thrower) { >+ static_cast<void>(absl::make_unique<Thrower>(*thrower)); >+ })); >+ >+ EXPECT_TRUE(tester.Test([](Thrower* thrower) { >+ static_cast<void>(absl::make_unique<Thrower>(std::move(*thrower))); >+ })); >+ >+ // Test T[n] overload >+ EXPECT_TRUE(tester.Test([&](Thrower*) { >+ static_cast<void>(absl::make_unique<Thrower[]>(kLength)); >+ })); >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_test.cc >new file mode 100644 >index 00000000000..dee9b486a30 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/memory/memory_test.cc >@@ -0,0 +1,614 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Tests for pointer utilities. >+ >+#include "absl/memory/memory.h" >+ >+#include <sys/types.h> >+#include <cstddef> >+#include <memory> >+#include <string> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace { >+ >+using ::testing::ElementsAre; >+using ::testing::Return; >+ >+// This class creates observable behavior to verify that a destructor has >+// been called, via the instance_count variable. >+class DestructorVerifier { >+ public: >+ DestructorVerifier() { ++instance_count_; } >+ DestructorVerifier(const DestructorVerifier&) = delete; >+ DestructorVerifier& operator=(const DestructorVerifier&) = delete; >+ ~DestructorVerifier() { --instance_count_; } >+ >+ // The number of instances of this class currently active. >+ static int instance_count() { return instance_count_; } >+ >+ private: >+ // The number of instances of this class currently active. >+ static int instance_count_; >+}; >+ >+int DestructorVerifier::instance_count_ = 0; >+ >+TEST(WrapUniqueTest, WrapUnique) { >+ // Test that the unique_ptr is constructed properly by verifying that the >+ // destructor for its payload gets called at the proper time. >+ { >+ auto dv = new DestructorVerifier; >+ EXPECT_EQ(1, DestructorVerifier::instance_count()); >+ std::unique_ptr<DestructorVerifier> ptr = absl::WrapUnique(dv); >+ EXPECT_EQ(1, DestructorVerifier::instance_count()); >+ } >+ EXPECT_EQ(0, DestructorVerifier::instance_count()); >+} >+TEST(MakeUniqueTest, Basic) { >+ std::unique_ptr<std::string> p = absl::make_unique<std::string>(); >+ EXPECT_EQ("", *p); >+ p = absl::make_unique<std::string>("hi"); >+ EXPECT_EQ("hi", *p); >+} >+ >+struct MoveOnly { >+ MoveOnly() = default; >+ explicit MoveOnly(int i1) : ip1{new int{i1}} {} >+ MoveOnly(int i1, int i2) : ip1{new int{i1}}, ip2{new int{i2}} {} >+ std::unique_ptr<int> ip1; >+ std::unique_ptr<int> ip2; >+}; >+ >+struct AcceptMoveOnly { >+ explicit AcceptMoveOnly(MoveOnly m) : m_(std::move(m)) {} >+ MoveOnly m_; >+}; >+ >+TEST(MakeUniqueTest, MoveOnlyTypeAndValue) { >+ using ExpectedType = std::unique_ptr<MoveOnly>; >+ { >+ auto p = absl::make_unique<MoveOnly>(); >+ static_assert(std::is_same<decltype(p), ExpectedType>::value, >+ "unexpected return type"); >+ EXPECT_TRUE(!p->ip1); >+ EXPECT_TRUE(!p->ip2); >+ } >+ { >+ auto p = absl::make_unique<MoveOnly>(1); >+ static_assert(std::is_same<decltype(p), ExpectedType>::value, >+ "unexpected return type"); >+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1); >+ EXPECT_TRUE(!p->ip2); >+ } >+ { >+ auto p = absl::make_unique<MoveOnly>(1, 2); >+ static_assert(std::is_same<decltype(p), ExpectedType>::value, >+ "unexpected return type"); >+ EXPECT_TRUE(p->ip1 && *p->ip1 == 1); >+ EXPECT_TRUE(p->ip2 && *p->ip2 == 2); >+ } >+} >+ >+TEST(MakeUniqueTest, AcceptMoveOnly) { >+ auto p = absl::make_unique<AcceptMoveOnly>(MoveOnly()); >+ p = std::unique_ptr<AcceptMoveOnly>(new AcceptMoveOnly(MoveOnly())); >+} >+ >+struct ArrayWatch { >+ void* operator new[](size_t n) { >+ allocs().push_back(n); >+ return ::operator new[](n); >+ } >+ void operator delete[](void* p) { >+ return ::operator delete[](p); >+ } >+ static std::vector<size_t>& allocs() { >+ static auto& v = *new std::vector<size_t>; >+ return v; >+ } >+}; >+ >+TEST(Make_UniqueTest, Array) { >+ // Ensure state is clean before we start so that these tests >+ // are order-agnostic. >+ ArrayWatch::allocs().clear(); >+ >+ auto p = absl::make_unique<ArrayWatch[]>(5); >+ static_assert(std::is_same<decltype(p), >+ std::unique_ptr<ArrayWatch[]>>::value, >+ "unexpected return type"); >+ EXPECT_THAT(ArrayWatch::allocs(), ElementsAre(5 * sizeof(ArrayWatch))); >+} >+ >+TEST(Make_UniqueTest, NotAmbiguousWithStdMakeUnique) { >+ // Ensure that absl::make_unique is not ambiguous with std::make_unique. >+ // In C++14 mode, the below call to make_unique has both types as candidates. >+ struct TakesStdType { >+ explicit TakesStdType(const std::vector<int> &vec) {} >+ }; >+ using absl::make_unique; >+ make_unique<TakesStdType>(std::vector<int>()); >+} >+ >+#if 0 >+// TODO(billydonahue): Make a proper NC test. >+// These tests shouldn't compile. >+TEST(MakeUniqueTestNC, AcceptMoveOnlyLvalue) { >+ auto m = MoveOnly(); >+ auto p = absl::make_unique<AcceptMoveOnly>(m); >+} >+TEST(MakeUniqueTestNC, KnownBoundArray) { >+ auto p = absl::make_unique<ArrayWatch[5]>(); >+} >+#endif >+ >+TEST(RawPtrTest, RawPointer) { >+ int i = 5; >+ EXPECT_EQ(&i, absl::RawPtr(&i)); >+} >+ >+TEST(RawPtrTest, SmartPointer) { >+ int* o = new int(5); >+ std::unique_ptr<int> p(o); >+ EXPECT_EQ(o, absl::RawPtr(p)); >+} >+ >+class IntPointerNonConstDeref { >+ public: >+ explicit IntPointerNonConstDeref(int* p) : p_(p) {} >+ friend bool operator!=(const IntPointerNonConstDeref& a, std::nullptr_t) { >+ return a.p_ != nullptr; >+ } >+ int& operator*() { return *p_; } >+ >+ private: >+ std::unique_ptr<int> p_; >+}; >+ >+TEST(RawPtrTest, SmartPointerNonConstDereference) { >+ int* o = new int(5); >+ IntPointerNonConstDeref p(o); >+ EXPECT_EQ(o, absl::RawPtr(p)); >+} >+ >+TEST(RawPtrTest, NullValuedRawPointer) { >+ int* p = nullptr; >+ EXPECT_EQ(nullptr, absl::RawPtr(p)); >+} >+ >+TEST(RawPtrTest, NullValuedSmartPointer) { >+ std::unique_ptr<int> p; >+ EXPECT_EQ(nullptr, absl::RawPtr(p)); >+} >+ >+TEST(RawPtrTest, Nullptr) { >+ auto p = absl::RawPtr(nullptr); >+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value)); >+ EXPECT_EQ(nullptr, p); >+} >+ >+TEST(RawPtrTest, Null) { >+ auto p = absl::RawPtr(nullptr); >+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value)); >+ EXPECT_EQ(nullptr, p); >+} >+ >+TEST(RawPtrTest, Zero) { >+ auto p = absl::RawPtr(nullptr); >+ EXPECT_TRUE((std::is_same<std::nullptr_t, decltype(p)>::value)); >+ EXPECT_EQ(nullptr, p); >+} >+ >+TEST(ShareUniquePtrTest, Share) { >+ auto up = absl::make_unique<int>(); >+ int* rp = up.get(); >+ auto sp = absl::ShareUniquePtr(std::move(up)); >+ EXPECT_EQ(sp.get(), rp); >+} >+ >+TEST(ShareUniquePtrTest, ShareNull) { >+ struct NeverDie { >+ using pointer = void*; >+ void operator()(pointer) { >+ ASSERT_TRUE(false) << "Deleter should not have been called."; >+ } >+ }; >+ >+ std::unique_ptr<void, NeverDie> up; >+ auto sp = absl::ShareUniquePtr(std::move(up)); >+} >+ >+TEST(WeakenPtrTest, Weak) { >+ auto sp = std::make_shared<int>(); >+ auto wp = absl::WeakenPtr(sp); >+ EXPECT_EQ(sp.get(), wp.lock().get()); >+ sp.reset(); >+ EXPECT_TRUE(wp.expired()); >+} >+ >+// Should not compile. >+/* >+TEST(RawPtrTest, NotAPointer) { >+ absl::RawPtr(1.5); >+} >+*/ >+ >+template <typename T> >+struct SmartPointer { >+ using difference_type = char; >+}; >+ >+struct PointerWith { >+ using element_type = int32_t; >+ using difference_type = int16_t; >+ template <typename U> >+ using rebind = SmartPointer<U>; >+ >+ static PointerWith pointer_to( >+ element_type& r) { // NOLINT(runtime/references) >+ return PointerWith{&r}; >+ } >+ >+ element_type* ptr; >+}; >+ >+template <typename... Args> >+struct PointerWithout {}; >+ >+TEST(PointerTraits, Types) { >+ using TraitsWith = absl::pointer_traits<PointerWith>; >+ EXPECT_TRUE((std::is_same<TraitsWith::pointer, PointerWith>::value)); >+ EXPECT_TRUE((std::is_same<TraitsWith::element_type, int32_t>::value)); >+ EXPECT_TRUE((std::is_same<TraitsWith::difference_type, int16_t>::value)); >+ EXPECT_TRUE(( >+ std::is_same<TraitsWith::rebind<int64_t>, SmartPointer<int64_t>>::value)); >+ >+ using TraitsWithout = absl::pointer_traits<PointerWithout<double, int>>; >+ EXPECT_TRUE((std::is_same<TraitsWithout::pointer, >+ PointerWithout<double, int>>::value)); >+ EXPECT_TRUE((std::is_same<TraitsWithout::element_type, double>::value)); >+ EXPECT_TRUE( >+ (std::is_same<TraitsWithout ::difference_type, std::ptrdiff_t>::value)); >+ EXPECT_TRUE((std::is_same<TraitsWithout::rebind<int64_t>, >+ PointerWithout<int64_t, int>>::value)); >+ >+ using TraitsRawPtr = absl::pointer_traits<char*>; >+ EXPECT_TRUE((std::is_same<TraitsRawPtr::pointer, char*>::value)); >+ EXPECT_TRUE((std::is_same<TraitsRawPtr::element_type, char>::value)); >+ EXPECT_TRUE( >+ (std::is_same<TraitsRawPtr::difference_type, std::ptrdiff_t>::value)); >+ EXPECT_TRUE((std::is_same<TraitsRawPtr::rebind<int64_t>, int64_t*>::value)); >+} >+ >+TEST(PointerTraits, Functions) { >+ int i; >+ EXPECT_EQ(&i, absl::pointer_traits<PointerWith>::pointer_to(i).ptr); >+ EXPECT_EQ(&i, absl::pointer_traits<int*>::pointer_to(i)); >+} >+ >+TEST(AllocatorTraits, Typedefs) { >+ struct A { >+ struct value_type {}; >+ }; >+ EXPECT_TRUE(( >+ std::is_same<A, >+ typename absl::allocator_traits<A>::allocator_type>::value)); >+ EXPECT_TRUE( >+ (std::is_same<A::value_type, >+ typename absl::allocator_traits<A>::value_type>::value)); >+ >+ struct X {}; >+ struct HasPointer { >+ using value_type = X; >+ using pointer = SmartPointer<X>; >+ }; >+ EXPECT_TRUE((std::is_same<SmartPointer<X>, typename absl::allocator_traits< >+ HasPointer>::pointer>::value)); >+ EXPECT_TRUE( >+ (std::is_same<A::value_type*, >+ typename absl::allocator_traits<A>::pointer>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_same< >+ SmartPointer<const X>, >+ typename absl::allocator_traits<HasPointer>::const_pointer>::value)); >+ EXPECT_TRUE( >+ (std::is_same<const A::value_type*, >+ typename absl::allocator_traits<A>::const_pointer>::value)); >+ >+ struct HasVoidPointer { >+ using value_type = X; >+ struct void_pointer {}; >+ }; >+ >+ EXPECT_TRUE((std::is_same<HasVoidPointer::void_pointer, >+ typename absl::allocator_traits< >+ HasVoidPointer>::void_pointer>::value)); >+ EXPECT_TRUE( >+ (std::is_same<SmartPointer<void>, typename absl::allocator_traits< >+ HasPointer>::void_pointer>::value)); >+ >+ struct HasConstVoidPointer { >+ using value_type = X; >+ struct const_void_pointer {}; >+ }; >+ >+ EXPECT_TRUE( >+ (std::is_same<HasConstVoidPointer::const_void_pointer, >+ typename absl::allocator_traits< >+ HasConstVoidPointer>::const_void_pointer>::value)); >+ EXPECT_TRUE((std::is_same<SmartPointer<const void>, >+ typename absl::allocator_traits< >+ HasPointer>::const_void_pointer>::value)); >+ >+ struct HasDifferenceType { >+ using value_type = X; >+ using difference_type = int; >+ }; >+ EXPECT_TRUE( >+ (std::is_same<int, typename absl::allocator_traits< >+ HasDifferenceType>::difference_type>::value)); >+ EXPECT_TRUE((std::is_same<char, typename absl::allocator_traits< >+ HasPointer>::difference_type>::value)); >+ >+ struct HasSizeType { >+ using value_type = X; >+ using size_type = unsigned int; >+ }; >+ EXPECT_TRUE((std::is_same<unsigned int, typename absl::allocator_traits< >+ HasSizeType>::size_type>::value)); >+ EXPECT_TRUE((std::is_same<unsigned char, typename absl::allocator_traits< >+ HasPointer>::size_type>::value)); >+ >+ struct HasPropagateOnCopy { >+ using value_type = X; >+ struct propagate_on_container_copy_assignment {}; >+ }; >+ >+ EXPECT_TRUE( >+ (std::is_same<HasPropagateOnCopy::propagate_on_container_copy_assignment, >+ typename absl::allocator_traits<HasPropagateOnCopy>:: >+ propagate_on_container_copy_assignment>::value)); >+ EXPECT_TRUE( >+ (std::is_same<std::false_type, >+ typename absl::allocator_traits< >+ A>::propagate_on_container_copy_assignment>::value)); >+ >+ struct HasPropagateOnMove { >+ using value_type = X; >+ struct propagate_on_container_move_assignment {}; >+ }; >+ >+ EXPECT_TRUE( >+ (std::is_same<HasPropagateOnMove::propagate_on_container_move_assignment, >+ typename absl::allocator_traits<HasPropagateOnMove>:: >+ propagate_on_container_move_assignment>::value)); >+ EXPECT_TRUE( >+ (std::is_same<std::false_type, >+ typename absl::allocator_traits< >+ A>::propagate_on_container_move_assignment>::value)); >+ >+ struct HasPropagateOnSwap { >+ using value_type = X; >+ struct propagate_on_container_swap {}; >+ }; >+ >+ EXPECT_TRUE( >+ (std::is_same<HasPropagateOnSwap::propagate_on_container_swap, >+ typename absl::allocator_traits<HasPropagateOnSwap>:: >+ propagate_on_container_swap>::value)); >+ EXPECT_TRUE( >+ (std::is_same<std::false_type, typename absl::allocator_traits<A>:: >+ propagate_on_container_swap>::value)); >+ >+ struct HasIsAlwaysEqual { >+ using value_type = X; >+ struct is_always_equal {}; >+ }; >+ >+ EXPECT_TRUE((std::is_same<HasIsAlwaysEqual::is_always_equal, >+ typename absl::allocator_traits< >+ HasIsAlwaysEqual>::is_always_equal>::value)); >+ EXPECT_TRUE((std::is_same<std::true_type, typename absl::allocator_traits< >+ A>::is_always_equal>::value)); >+ struct NonEmpty { >+ using value_type = X; >+ int i; >+ }; >+ EXPECT_TRUE( >+ (std::is_same<std::false_type, >+ absl::allocator_traits<NonEmpty>::is_always_equal>::value)); >+} >+ >+template <typename T> >+struct AllocWithPrivateInheritance : private std::allocator<T> { >+ using value_type = T; >+}; >+ >+TEST(AllocatorTraits, RebindWithPrivateInheritance) { >+ // Regression test for some versions of gcc that do not like the sfinae we >+ // used in combination with private inheritance. >+ EXPECT_TRUE( >+ (std::is_same<AllocWithPrivateInheritance<int>, >+ absl::allocator_traits<AllocWithPrivateInheritance<char>>:: >+ rebind_alloc<int>>::value)); >+} >+ >+template <typename T> >+struct Rebound {}; >+ >+struct AllocWithRebind { >+ using value_type = int; >+ template <typename T> >+ struct rebind { >+ using other = Rebound<T>; >+ }; >+}; >+ >+template <typename T, typename U> >+struct AllocWithoutRebind { >+ using value_type = int; >+}; >+ >+TEST(AllocatorTraits, Rebind) { >+ EXPECT_TRUE( >+ (std::is_same<Rebound<int>, >+ typename absl::allocator_traits< >+ AllocWithRebind>::template rebind_alloc<int>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<absl::allocator_traits<Rebound<int>>, >+ typename absl::allocator_traits< >+ AllocWithRebind>::template rebind_traits<int>>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_same<AllocWithoutRebind<double, char>, >+ typename absl::allocator_traits<AllocWithoutRebind< >+ int, char>>::template rebind_alloc<double>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<absl::allocator_traits<AllocWithoutRebind<double, char>>, >+ typename absl::allocator_traits<AllocWithoutRebind< >+ int, char>>::template rebind_traits<double>>::value)); >+} >+ >+struct TestValue { >+ TestValue() {} >+ explicit TestValue(int* trace) : trace(trace) { ++*trace; } >+ ~TestValue() { >+ if (trace) --*trace; >+ } >+ int* trace = nullptr; >+}; >+ >+struct MinimalMockAllocator { >+ MinimalMockAllocator() : value(0) {} >+ explicit MinimalMockAllocator(int value) : value(value) {} >+ MinimalMockAllocator(const MinimalMockAllocator& other) >+ : value(other.value) {} >+ using value_type = TestValue; >+ MOCK_METHOD1(allocate, value_type*(size_t)); >+ MOCK_METHOD2(deallocate, void(value_type*, size_t)); >+ >+ int value; >+}; >+ >+TEST(AllocatorTraits, FunctionsMinimal) { >+ int trace = 0; >+ int hint; >+ TestValue x(&trace); >+ MinimalMockAllocator mock; >+ using Traits = absl::allocator_traits<MinimalMockAllocator>; >+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x)); >+ EXPECT_CALL(mock, deallocate(&x, 7)); >+ >+ EXPECT_EQ(&x, Traits::allocate(mock, 7)); >+ Traits::allocate(mock, 7, static_cast<const void*>(&hint)); >+ EXPECT_EQ(&x, Traits::allocate(mock, 7, static_cast<const void*>(&hint))); >+ Traits::deallocate(mock, &x, 7); >+ >+ EXPECT_EQ(1, trace); >+ Traits::construct(mock, &x, &trace); >+ EXPECT_EQ(2, trace); >+ Traits::destroy(mock, &x); >+ EXPECT_EQ(1, trace); >+ >+ EXPECT_EQ(std::numeric_limits<size_t>::max() / sizeof(TestValue), >+ Traits::max_size(mock)); >+ >+ EXPECT_EQ(0, mock.value); >+ EXPECT_EQ(0, Traits::select_on_container_copy_construction(mock).value); >+} >+ >+struct FullMockAllocator { >+ FullMockAllocator() : value(0) {} >+ explicit FullMockAllocator(int value) : value(value) {} >+ FullMockAllocator(const FullMockAllocator& other) : value(other.value) {} >+ using value_type = TestValue; >+ MOCK_METHOD1(allocate, value_type*(size_t)); >+ MOCK_METHOD2(allocate, value_type*(size_t, const void*)); >+ MOCK_METHOD2(construct, void(value_type*, int*)); >+ MOCK_METHOD1(destroy, void(value_type*)); >+ MOCK_CONST_METHOD0(max_size, size_t()); >+ MOCK_CONST_METHOD0(select_on_container_copy_construction, >+ FullMockAllocator()); >+ >+ int value; >+}; >+ >+TEST(AllocatorTraits, FunctionsFull) { >+ int trace = 0; >+ int hint; >+ TestValue x(&trace), y; >+ FullMockAllocator mock; >+ using Traits = absl::allocator_traits<FullMockAllocator>; >+ EXPECT_CALL(mock, allocate(7)).WillRepeatedly(Return(&x)); >+ EXPECT_CALL(mock, allocate(13, &hint)).WillRepeatedly(Return(&y)); >+ EXPECT_CALL(mock, construct(&x, &trace)); >+ EXPECT_CALL(mock, destroy(&x)); >+ EXPECT_CALL(mock, max_size()).WillRepeatedly(Return(17)); >+ EXPECT_CALL(mock, select_on_container_copy_construction()) >+ .WillRepeatedly(Return(FullMockAllocator(23))); >+ >+ EXPECT_EQ(&x, Traits::allocate(mock, 7)); >+ EXPECT_EQ(&y, Traits::allocate(mock, 13, static_cast<const void*>(&hint))); >+ >+ EXPECT_EQ(1, trace); >+ Traits::construct(mock, &x, &trace); >+ EXPECT_EQ(1, trace); >+ Traits::destroy(mock, &x); >+ EXPECT_EQ(1, trace); >+ >+ EXPECT_EQ(17, Traits::max_size(mock)); >+ >+ EXPECT_EQ(0, mock.value); >+ EXPECT_EQ(23, Traits::select_on_container_copy_construction(mock).value); >+} >+ >+TEST(AllocatorNoThrowTest, DefaultAllocator) { >+#if ABSL_ALLOCATOR_NOTHROW >+ EXPECT_TRUE(absl::default_allocator_is_nothrow::value); >+#else >+ EXPECT_FALSE(absl::default_allocator_is_nothrow::value); >+#endif >+} >+ >+TEST(AllocatorNoThrowTest, StdAllocator) { >+#if ABSL_ALLOCATOR_NOTHROW >+ EXPECT_TRUE(absl::allocator_is_nothrow<std::allocator<int>>::value); >+#else >+ EXPECT_FALSE(absl::allocator_is_nothrow<std::allocator<int>>::value); >+#endif >+} >+ >+TEST(AllocatorNoThrowTest, CustomAllocator) { >+ struct NoThrowAllocator { >+ using is_nothrow = std::true_type; >+ }; >+ struct CanThrowAllocator { >+ using is_nothrow = std::false_type; >+ }; >+ struct UnspecifiedAllocator { >+ }; >+ EXPECT_TRUE(absl::allocator_is_nothrow<NoThrowAllocator>::value); >+ EXPECT_FALSE(absl::allocator_is_nothrow<CanThrowAllocator>::value); >+ EXPECT_FALSE(absl::allocator_is_nothrow<UnspecifiedAllocator>::value); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.bazel >new file mode 100644 >index 00000000000..dbc9717ddd3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.bazel >@@ -0,0 +1,29 @@ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "type_traits", >+ hdrs = ["type_traits.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base:config", >+ ], >+) >+ >+cc_test( >+ name = "type_traits_test", >+ srcs = ["type_traits_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":type_traits", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.gn >new file mode 100644 >index 00000000000..6757219c273 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/BUILD.gn >@@ -0,0 +1,30 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("type_traits") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "type_traits.h", >+ ] >+ deps = [ >+ "../base:config", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/CMakeLists.txt >new file mode 100644 >index 00000000000..adb0ceb754d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/CMakeLists.txt >@@ -0,0 +1,52 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND META_PUBLIC_HEADERS >+ "type_traits.h" >+) >+ >+ >+# >+## TESTS >+# >+ >+# test type_traits_test >+list(APPEND TYPE_TRAITS_TEST_SRC >+ "type_traits_test.cc" >+ ${META_PUBLIC_HEADERS} >+) >+ >+absl_header_library( >+ TARGET >+ absl_meta >+ PUBLIC_LIBRARIES >+ absl::base >+ EXPORT_NAME >+ meta >+ ) >+ >+absl_test( >+ TARGET >+ type_traits_test >+ SOURCES >+ ${TYPE_TRAITS_TEST_SRC} >+ PUBLIC_LIBRARIES >+ absl::base >+ absl::meta >+) >+ >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits.h >new file mode 100644 >index 00000000000..457b890841a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits.h >@@ -0,0 +1,419 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// type_traits.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains C++11-compatible versions of standard <type_traits> API >+// functions for determining the characteristics of types. Such traits can >+// support type inference, classification, and transformation, as well as >+// make it easier to write templates based on generic type behavior. >+// >+// See http://en.cppreference.com/w/cpp/header/type_traits >+// >+// WARNING: use of many of the constructs in this header will count as "complex >+// template metaprogramming", so before proceeding, please carefully consider >+// https://google.github.io/styleguide/cppguide.html#Template_metaprogramming >+// >+// WARNING: using template metaprogramming to detect or depend on API >+// features is brittle and not guaranteed. Neither the standard library nor >+// Abseil provides any guarantee that APIs are stable in the face of template >+// metaprogramming. Use with caution. >+#ifndef ABSL_META_TYPE_TRAITS_H_ >+#define ABSL_META_TYPE_TRAITS_H_ >+ >+#include <stddef.h> >+#include <functional> >+#include <type_traits> >+ >+#include "absl/base/config.h" >+ >+namespace absl { >+ >+namespace type_traits_internal { >+ >+template <typename... Ts> >+struct VoidTImpl { >+ using type = void; >+}; >+ >+// This trick to retrieve a default alignment is necessary for our >+// implementation of aligned_storage_t to be consistent with any implementation >+// of std::aligned_storage. >+template <size_t Len, typename T = std::aligned_storage<Len>> >+struct default_alignment_of_aligned_storage; >+ >+template <size_t Len, size_t Align> >+struct default_alignment_of_aligned_storage<Len, >+ std::aligned_storage<Len, Align>> { >+ static constexpr size_t value = Align; >+}; >+ >+//////////////////////////////// >+// Library Fundamentals V2 TS // >+//////////////////////////////// >+ >+// NOTE: The `is_detected` family of templates here differ from the library >+// fundamentals specification in that for library fundamentals, `Op<Args...>` is >+// evaluated as soon as the type `is_detected<Op, Args...>` undergoes >+// substitution, regardless of whether or not the `::value` is accessed. That >+// is inconsistent with all other standard traits and prevents lazy evaluation >+// in larger contexts (such as if the `is_detected` check is a trailing argument >+// of a `conjunction`. This implementation opts to instead be lazy in the same >+// way that the standard traits are (this "defect" of the detection idiom >+// specifications has been reported). >+ >+template <class Enabler, template <class...> class Op, class... Args> >+struct is_detected_impl { >+ using type = std::false_type; >+}; >+ >+template <template <class...> class Op, class... Args> >+struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> { >+ using type = std::true_type; >+}; >+ >+template <template <class...> class Op, class... Args> >+struct is_detected : is_detected_impl<void, Op, Args...>::type {}; >+ >+template <class Enabler, class To, template <class...> class Op, class... Args> >+struct is_detected_convertible_impl { >+ using type = std::false_type; >+}; >+ >+template <class To, template <class...> class Op, class... Args> >+struct is_detected_convertible_impl< >+ typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type, >+ To, Op, Args...> { >+ using type = std::true_type; >+}; >+ >+template <class To, template <class...> class Op, class... Args> >+struct is_detected_convertible >+ : is_detected_convertible_impl<void, To, Op, Args...>::type {}; >+ >+} // namespace type_traits_internal >+ >+// void_t() >+// >+// Ignores the type of any its arguments and returns `void`. In general, this >+// metafunction allows you to create a general case that maps to `void` while >+// allowing specializations that map to specific types. >+// >+// This metafunction is designed to be a drop-in replacement for the C++17 >+// `std::void_t` metafunction. >+// >+// NOTE: `absl::void_t` does not use the standard-specified implementation so >+// that it can remain compatible with gcc < 5.1. This can introduce slightly >+// different behavior, such as when ordering partial specializations. >+template <typename... Ts> >+using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type; >+ >+// conjunction >+// >+// Performs a compile-time logical AND operation on the passed types (which >+// must have `::value` members convertible to `bool`. Short-circuits if it >+// encounters any `false` members (and does not compare the `::value` members >+// of any remaining arguments). >+// >+// This metafunction is designed to be a drop-in replacement for the C++17 >+// `std::conjunction` metafunction. >+template <typename... Ts> >+struct conjunction; >+ >+template <typename T, typename... Ts> >+struct conjunction<T, Ts...> >+ : std::conditional<T::value, conjunction<Ts...>, T>::type {}; >+ >+template <typename T> >+struct conjunction<T> : T {}; >+ >+template <> >+struct conjunction<> : std::true_type {}; >+ >+// disjunction >+// >+// Performs a compile-time logical OR operation on the passed types (which >+// must have `::value` members convertible to `bool`. Short-circuits if it >+// encounters any `true` members (and does not compare the `::value` members >+// of any remaining arguments). >+// >+// This metafunction is designed to be a drop-in replacement for the C++17 >+// `std::disjunction` metafunction. >+template <typename... Ts> >+struct disjunction; >+ >+template <typename T, typename... Ts> >+struct disjunction<T, Ts...> : >+ std::conditional<T::value, T, disjunction<Ts...>>::type {}; >+ >+template <typename T> >+struct disjunction<T> : T {}; >+ >+template <> >+struct disjunction<> : std::false_type {}; >+ >+// negation >+// >+// Performs a compile-time logical NOT operation on the passed type (which >+// must have `::value` members convertible to `bool`. >+// >+// This metafunction is designed to be a drop-in replacement for the C++17 >+// `std::negation` metafunction. >+template <typename T> >+struct negation : std::integral_constant<bool, !T::value> {}; >+ >+// is_trivially_destructible() >+// >+// Determines whether the passed type `T` is trivially destructable. >+// >+// This metafunction is designed to be a drop-in replacement for the C++11 >+// `std::is_trivially_destructible()` metafunction for platforms that have >+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do >+// fully support C++11, we check whether this yields the same result as the std >+// implementation. >+// >+// NOTE: the extensions (__has_trivial_xxx) are implemented in gcc (version >= >+// 4.3) and clang. Since we are supporting libstdc++ > 4.7, they should always >+// be present. These extensions are documented at >+// https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html#Type-Traits. >+template <typename T> >+struct is_trivially_destructible >+ : std::integral_constant<bool, __has_trivial_destructor(T) && >+ std::is_destructible<T>::value> { >+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE >+ private: >+ static constexpr bool compliant = std::is_trivially_destructible<T>::value == >+ is_trivially_destructible::value; >+ static_assert(compliant || std::is_trivially_destructible<T>::value, >+ "Not compliant with std::is_trivially_destructible; " >+ "Standard: false, Implementation: true"); >+ static_assert(compliant || !std::is_trivially_destructible<T>::value, >+ "Not compliant with std::is_trivially_destructible; " >+ "Standard: true, Implementation: false"); >+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE >+}; >+ >+// is_trivially_default_constructible() >+// >+// Determines whether the passed type `T` is trivially default constructible. >+// >+// This metafunction is designed to be a drop-in replacement for the C++11 >+// `std::is_trivially_default_constructible()` metafunction for platforms that >+// have incomplete C++11 support (such as libstdc++ 4.x). On any platforms that >+// do fully support C++11, we check whether this yields the same result as the >+// std implementation. >+// >+// NOTE: according to the C++ standard, Section: 20.15.4.3 [meta.unary.prop] >+// "The predicate condition for a template specialization is_constructible<T, >+// Args...> shall be satisfied if and only if the following variable >+// definition would be well-formed for some invented variable t: >+// >+// T t(declval<Args>()...); >+// >+// is_trivially_constructible<T, Args...> additionally requires that the >+// variable definition does not call any operation that is not trivial. >+// For the purposes of this check, the call to std::declval is considered >+// trivial." >+// >+// Notes from http://en.cppreference.com/w/cpp/types/is_constructible: >+// In many implementations, is_nothrow_constructible also checks if the >+// destructor throws because it is effectively noexcept(T(arg)). Same >+// applies to is_trivially_constructible, which, in these implementations, also >+// requires that the destructor is trivial. >+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 >+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116. >+// >+// "T obj();" need to be well-formed and not call any nontrivial operation. >+// Nontrivially destructible types will cause the expression to be nontrivial. >+template <typename T> >+struct is_trivially_default_constructible >+ : std::integral_constant<bool, __has_trivial_constructor(T) && >+ std::is_default_constructible<T>::value && >+ is_trivially_destructible<T>::value> { >+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE >+ private: >+ static constexpr bool compliant = >+ std::is_trivially_default_constructible<T>::value == >+ is_trivially_default_constructible::value; >+ static_assert(compliant || std::is_trivially_default_constructible<T>::value, >+ "Not compliant with std::is_trivially_default_constructible; " >+ "Standard: false, Implementation: true"); >+ static_assert(compliant || !std::is_trivially_default_constructible<T>::value, >+ "Not compliant with std::is_trivially_default_constructible; " >+ "Standard: true, Implementation: false"); >+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE >+}; >+ >+// is_trivially_copy_constructible() >+// >+// Determines whether the passed type `T` is trivially copy constructible. >+// >+// This metafunction is designed to be a drop-in replacement for the C++11 >+// `std::is_trivially_copy_constructible()` metafunction for platforms that have >+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do >+// fully support C++11, we check whether this yields the same result as the std >+// implementation. >+// >+// NOTE: `T obj(declval<const T&>());` needs to be well-formed and not call any >+// nontrivial operation. Nontrivially destructible types will cause the >+// expression to be nontrivial. >+template <typename T> >+struct is_trivially_copy_constructible >+ : std::integral_constant<bool, __has_trivial_copy(T) && >+ std::is_copy_constructible<T>::value && >+ is_trivially_destructible<T>::value> { >+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE >+ private: >+ static constexpr bool compliant = >+ std::is_trivially_copy_constructible<T>::value == >+ is_trivially_copy_constructible::value; >+ static_assert(compliant || std::is_trivially_copy_constructible<T>::value, >+ "Not compliant with std::is_trivially_copy_constructible; " >+ "Standard: false, Implementation: true"); >+ static_assert(compliant || !std::is_trivially_copy_constructible<T>::value, >+ "Not compliant with std::is_trivially_copy_constructible; " >+ "Standard: true, Implementation: false"); >+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE >+}; >+ >+// is_trivially_copy_assignable() >+// >+// Determines whether the passed type `T` is trivially copy assignable. >+// >+// This metafunction is designed to be a drop-in replacement for the C++11 >+// `std::is_trivially_copy_assignable()` metafunction for platforms that have >+// incomplete C++11 support (such as libstdc++ 4.x). On any platforms that do >+// fully support C++11, we check whether this yields the same result as the std >+// implementation. >+// >+// NOTE: `is_assignable<T, U>::value` is `true` if the expression >+// `declval<T>() = declval<U>()` is well-formed when treated as an unevaluated >+// operand. `is_trivially_assignable<T, U>` requires the assignment to call no >+// operation that is not trivial. `is_trivially_copy_assignable<T>` is simply >+// `is_trivially_assignable<T&, const T&>`. >+template <typename T> >+struct is_trivially_copy_assignable >+ : std::integral_constant< >+ bool, __has_trivial_assign(typename std::remove_reference<T>::type) && >+ std::is_copy_assignable<T>::value> { >+#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE >+ private: >+ static constexpr bool compliant = >+ std::is_trivially_copy_assignable<T>::value == >+ is_trivially_copy_assignable::value; >+ static_assert(compliant || std::is_trivially_copy_assignable<T>::value, >+ "Not compliant with std::is_trivially_copy_assignable; " >+ "Standard: false, Implementation: true"); >+ static_assert(compliant || !std::is_trivially_copy_assignable<T>::value, >+ "Not compliant with std::is_trivially_copy_assignable; " >+ "Standard: true, Implementation: false"); >+#endif // ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE >+}; >+ >+// ----------------------------------------------------------------------------- >+// C++14 "_t" trait aliases >+// ----------------------------------------------------------------------------- >+ >+template <typename T> >+using remove_cv_t = typename std::remove_cv<T>::type; >+ >+template <typename T> >+using remove_const_t = typename std::remove_const<T>::type; >+ >+template <typename T> >+using remove_volatile_t = typename std::remove_volatile<T>::type; >+ >+template <typename T> >+using add_cv_t = typename std::add_cv<T>::type; >+ >+template <typename T> >+using add_const_t = typename std::add_const<T>::type; >+ >+template <typename T> >+using add_volatile_t = typename std::add_volatile<T>::type; >+ >+template <typename T> >+using remove_reference_t = typename std::remove_reference<T>::type; >+ >+template <typename T> >+using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type; >+ >+template <typename T> >+using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type; >+ >+template <typename T> >+using remove_pointer_t = typename std::remove_pointer<T>::type; >+ >+template <typename T> >+using add_pointer_t = typename std::add_pointer<T>::type; >+ >+template <typename T> >+using make_signed_t = typename std::make_signed<T>::type; >+ >+template <typename T> >+using make_unsigned_t = typename std::make_unsigned<T>::type; >+ >+template <typename T> >+using remove_extent_t = typename std::remove_extent<T>::type; >+ >+template <typename T> >+using remove_all_extents_t = typename std::remove_all_extents<T>::type; >+ >+template <size_t Len, size_t Align = type_traits_internal:: >+ default_alignment_of_aligned_storage<Len>::value> >+using aligned_storage_t = typename std::aligned_storage<Len, Align>::type; >+ >+template <typename T> >+using decay_t = typename std::decay<T>::type; >+ >+template <bool B, typename T = void> >+using enable_if_t = typename std::enable_if<B, T>::type; >+ >+template <bool B, typename T, typename F> >+using conditional_t = typename std::conditional<B, T, F>::type; >+ >+template <typename... T> >+using common_type_t = typename std::common_type<T...>::type; >+ >+template <typename T> >+using underlying_type_t = typename std::underlying_type<T>::type; >+ >+template <typename T> >+using result_of_t = typename std::result_of<T>::type; >+ >+namespace type_traits_internal { >+template <typename Key, typename = size_t> >+struct IsHashable : std::false_type {}; >+ >+template <typename Key> >+struct IsHashable<Key, >+ decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))> >+ : std::true_type {}; >+ >+template <typename Key> >+struct IsHashEnabled >+ : absl::conjunction<std::is_default_constructible<std::hash<Key>>, >+ std::is_copy_constructible<std::hash<Key>>, >+ std::is_destructible<std::hash<Key>>, >+ std::is_copy_assignable<std::hash<Key>>, >+ IsHashable<Key>> {}; >+} // namespace type_traits_internal >+ >+} // namespace absl >+ >+ >+#endif // ABSL_META_TYPE_TRAITS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits_test.cc >new file mode 100644 >index 00000000000..81b4bd32397 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/meta/type_traits_test.cc >@@ -0,0 +1,880 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/meta/type_traits.h" >+ >+#include <cstdint> >+#include <string> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+using ::testing::StaticAssertTypeEq; >+ >+template <class T, class U> >+struct simple_pair { >+ T first; >+ U second; >+}; >+ >+struct Dummy {}; >+ >+struct ReturnType {}; >+struct ConvertibleToReturnType { >+ operator ReturnType() const; // NOLINT >+}; >+ >+// Unique types used as parameter types for testing the detection idiom. >+struct StructA {}; >+struct StructB {}; >+struct StructC {}; >+ >+struct TypeWithBarFunction { >+ template <class T, >+ absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0> >+ ReturnType bar(T&&, const StructB&, StructC&&) &&; // NOLINT >+}; >+ >+struct TypeWithBarFunctionAndConvertibleReturnType { >+ template <class T, >+ absl::enable_if_t<std::is_same<T&&, StructA&>::value, int> = 0> >+ ConvertibleToReturnType bar(T&&, const StructB&, StructC&&) &&; // NOLINT >+}; >+ >+template <class Class, class... Ts> >+using BarIsCallableImpl = >+ decltype(std::declval<Class>().bar(std::declval<Ts>()...)); >+ >+template <class Class, class... T> >+using BarIsCallable = >+ absl::type_traits_internal::is_detected<BarIsCallableImpl, Class, T...>; >+ >+template <class Class, class... T> >+using BarIsCallableConv = absl::type_traits_internal::is_detected_convertible< >+ ReturnType, BarIsCallableImpl, Class, T...>; >+ >+// NOTE: Test of detail type_traits_internal::is_detected. >+TEST(IsDetectedTest, BasicUsage) { >+ EXPECT_TRUE((BarIsCallable<TypeWithBarFunction, StructA&, const StructB&, >+ StructC>::value)); >+ EXPECT_TRUE( >+ (BarIsCallable<TypeWithBarFunction, StructA&, StructB&, StructC>::value)); >+ EXPECT_TRUE( >+ (BarIsCallable<TypeWithBarFunction, StructA&, StructB, StructC>::value)); >+ >+ EXPECT_FALSE((BarIsCallable<int, StructA&, const StructB&, StructC>::value)); >+ EXPECT_FALSE((BarIsCallable<TypeWithBarFunction&, StructA&, const StructB&, >+ StructC>::value)); >+ EXPECT_FALSE((BarIsCallable<TypeWithBarFunction, StructA, const StructB&, >+ StructC>::value)); >+} >+ >+// NOTE: Test of detail type_traits_internal::is_detected_convertible. >+TEST(IsDetectedConvertibleTest, BasicUsage) { >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, const StructB&, >+ StructC>::value)); >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB&, >+ StructC>::value)); >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunction, StructA&, StructB, >+ StructC>::value)); >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType, >+ StructA&, const StructB&, StructC>::value)); >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType, >+ StructA&, StructB&, StructC>::value)); >+ EXPECT_TRUE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType, >+ StructA&, StructB, StructC>::value)); >+ >+ EXPECT_FALSE( >+ (BarIsCallableConv<int, StructA&, const StructB&, StructC>::value)); >+ EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction&, StructA&, >+ const StructB&, StructC>::value)); >+ EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunction, StructA, const StructB&, >+ StructC>::value)); >+ EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType&, >+ StructA&, const StructB&, StructC>::value)); >+ EXPECT_FALSE((BarIsCallableConv<TypeWithBarFunctionAndConvertibleReturnType, >+ StructA, const StructB&, StructC>::value)); >+} >+ >+TEST(VoidTTest, BasicUsage) { >+ StaticAssertTypeEq<void, absl::void_t<Dummy>>(); >+ StaticAssertTypeEq<void, absl::void_t<Dummy, Dummy, Dummy>>(); >+} >+ >+TEST(ConjunctionTest, BasicBooleanLogic) { >+ EXPECT_TRUE(absl::conjunction<>::value); >+ EXPECT_TRUE(absl::conjunction<std::true_type>::value); >+ EXPECT_TRUE((absl::conjunction<std::true_type, std::true_type>::value)); >+ EXPECT_FALSE((absl::conjunction<std::true_type, std::false_type>::value)); >+ EXPECT_FALSE((absl::conjunction<std::false_type, std::true_type>::value)); >+ EXPECT_FALSE((absl::conjunction<std::false_type, std::false_type>::value)); >+} >+ >+struct MyTrueType { >+ static constexpr bool value = true; >+}; >+ >+struct MyFalseType { >+ static constexpr bool value = false; >+}; >+ >+TEST(ConjunctionTest, ShortCircuiting) { >+ EXPECT_FALSE( >+ (absl::conjunction<std::true_type, std::false_type, Dummy>::value)); >+ EXPECT_TRUE((std::is_base_of<MyFalseType, >+ absl::conjunction<std::true_type, MyFalseType, >+ std::false_type>>::value)); >+ EXPECT_TRUE( >+ (std::is_base_of<MyTrueType, >+ absl::conjunction<std::true_type, MyTrueType>>::value)); >+} >+ >+TEST(DisjunctionTest, BasicBooleanLogic) { >+ EXPECT_FALSE(absl::disjunction<>::value); >+ EXPECT_FALSE(absl::disjunction<std::false_type>::value); >+ EXPECT_TRUE((absl::disjunction<std::true_type, std::true_type>::value)); >+ EXPECT_TRUE((absl::disjunction<std::true_type, std::false_type>::value)); >+ EXPECT_TRUE((absl::disjunction<std::false_type, std::true_type>::value)); >+ EXPECT_FALSE((absl::disjunction<std::false_type, std::false_type>::value)); >+} >+ >+TEST(DisjunctionTest, ShortCircuiting) { >+ EXPECT_TRUE( >+ (absl::disjunction<std::false_type, std::true_type, Dummy>::value)); >+ EXPECT_TRUE(( >+ std::is_base_of<MyTrueType, absl::disjunction<std::false_type, MyTrueType, >+ std::true_type>>::value)); >+ EXPECT_TRUE(( >+ std::is_base_of<MyFalseType, >+ absl::disjunction<std::false_type, MyFalseType>>::value)); >+} >+ >+TEST(NegationTest, BasicBooleanLogic) { >+ EXPECT_FALSE(absl::negation<std::true_type>::value); >+ EXPECT_FALSE(absl::negation<MyTrueType>::value); >+ EXPECT_TRUE(absl::negation<std::false_type>::value); >+ EXPECT_TRUE(absl::negation<MyFalseType>::value); >+} >+ >+// all member functions are trivial >+class Trivial { >+ int n_; >+}; >+ >+struct TrivialDestructor { >+ ~TrivialDestructor() = default; >+}; >+ >+struct NontrivialDestructor { >+ ~NontrivialDestructor() {} >+}; >+ >+struct DeletedDestructor { >+ ~DeletedDestructor() = delete; >+}; >+ >+class TrivialDefaultCtor { >+ public: >+ TrivialDefaultCtor() = default; >+ explicit TrivialDefaultCtor(int n) : n_(n) {} >+ >+ private: >+ int n_; >+}; >+ >+class NontrivialDefaultCtor { >+ public: >+ NontrivialDefaultCtor() : n_(1) {} >+ >+ private: >+ int n_; >+}; >+ >+class DeletedDefaultCtor { >+ public: >+ DeletedDefaultCtor() = delete; >+ explicit DeletedDefaultCtor(int n) : n_(n) {} >+ >+ private: >+ int n_; >+}; >+ >+class TrivialCopyCtor { >+ public: >+ explicit TrivialCopyCtor(int n) : n_(n) {} >+ TrivialCopyCtor(const TrivialCopyCtor&) = default; >+ TrivialCopyCtor& operator=(const TrivialCopyCtor& t) { >+ n_ = t.n_; >+ return *this; >+ } >+ >+ private: >+ int n_; >+}; >+ >+class NontrivialCopyCtor { >+ public: >+ explicit NontrivialCopyCtor(int n) : n_(n) {} >+ NontrivialCopyCtor(const NontrivialCopyCtor& t) : n_(t.n_) {} >+ NontrivialCopyCtor& operator=(const NontrivialCopyCtor&) = default; >+ >+ private: >+ int n_; >+}; >+ >+class DeletedCopyCtor { >+ public: >+ explicit DeletedCopyCtor(int n) : n_(n) {} >+ DeletedCopyCtor(const DeletedCopyCtor&) = delete; >+ DeletedCopyCtor& operator=(const DeletedCopyCtor&) = default; >+ >+ private: >+ int n_; >+}; >+ >+class TrivialCopyAssign { >+ public: >+ explicit TrivialCopyAssign(int n) : n_(n) {} >+ TrivialCopyAssign(const TrivialCopyAssign& t) : n_(t.n_) {} >+ TrivialCopyAssign& operator=(const TrivialCopyAssign& t) = default; >+ ~TrivialCopyAssign() {} // can have nontrivial destructor >+ private: >+ int n_; >+}; >+ >+class NontrivialCopyAssign { >+ public: >+ explicit NontrivialCopyAssign(int n) : n_(n) {} >+ NontrivialCopyAssign(const NontrivialCopyAssign&) = default; >+ NontrivialCopyAssign& operator=(const NontrivialCopyAssign& t) { >+ n_ = t.n_; >+ return *this; >+ } >+ >+ private: >+ int n_; >+}; >+ >+class DeletedCopyAssign { >+ public: >+ explicit DeletedCopyAssign(int n) : n_(n) {} >+ DeletedCopyAssign(const DeletedCopyAssign&) = default; >+ DeletedCopyAssign& operator=(const DeletedCopyAssign&) = delete; >+ >+ private: >+ int n_; >+}; >+ >+struct NonCopyable { >+ NonCopyable() = default; >+ NonCopyable(const NonCopyable&) = delete; >+ NonCopyable& operator=(const NonCopyable&) = delete; >+}; >+ >+class Base { >+ public: >+ virtual ~Base() {} >+}; >+ >+// In GCC/Clang, std::is_trivially_constructible requires that the destructor is >+// trivial. However, MSVC doesn't require that. This results in different >+// behavior when checking is_trivially_constructible on any type with >+// nontrivial destructor. Since absl::is_trivially_default_constructible and >+// absl::is_trivially_copy_constructible both follows Clang/GCC's interpretation >+// and check is_trivially_destructible, it results in inconsistency with >+// std::is_trivially_xxx_constructible on MSVC. This macro is used to work >+// around this issue in test. In practice, a trivially constructible type >+// should also be trivially destructible. >+// GCC bug 51452: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 >+// LWG issue 2116: http://cplusplus.github.io/LWG/lwg-active.html#2116 >+#ifndef _MSC_VER >+#define ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE 1 >+#endif >+ >+// Old versions of libc++, around Clang 3.5 to 3.6, consider deleted destructors >+// as also being trivial. With the resolution of CWG 1928 and CWG 1734, this >+// is no longer considered true and has thus been amended. >+// Compiler Explorer: https://godbolt.org/g/zT59ZL >+// CWG issue 1734: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1734 >+// CWG issue 1928: http://open-std.org/JTC1/SC22/WG21/docs/cwg_closed.html#1928 >+#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 3700 >+#define ABSL_TRIVIALLY_DESTRUCTIBLE_CONSIDER_DELETED_DESTRUCTOR_NOT_TRIVIAL 1 >+#endif >+ >+// As of the moment, GCC versions >5.1 have a problem compiling for >+// std::is_trivially_default_constructible<NontrivialDestructor[10]>, where >+// NontrivialDestructor is a struct with a custom nontrivial destructor. Note >+// that this problem only occurs for arrays of a known size, so something like >+// std::is_trivially_default_constructible<NontrivialDestructor[]> does not >+// have any problems. >+// Compiler Explorer: https://godbolt.org/g/dXRbdK >+// GCC bug 83689: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83689 >+#if defined(__clang__) || defined(_MSC_VER) || \ >+ (defined(__GNUC__) && __GNUC__ < 5) >+#define ABSL_GCC_BUG_TRIVIALLY_CONSTRUCTIBLE_ON_ARRAY_OF_NONTRIVIAL 1 >+#endif >+ >+TEST(TypeTraitsTest, TestTrivialDestructor) { >+ // Verify that arithmetic types and pointers have trivial destructors. >+ EXPECT_TRUE(absl::is_trivially_destructible<bool>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<char>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<unsigned char>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<signed char>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<wchar_t>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<int>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<unsigned int>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<int16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<uint16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<int64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<uint64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<float>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<double>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<long double>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<const std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<const Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<std::string**>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial**>::value); >+ >+ // classes with destructors >+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor>::value); >+ >+ // Verify that types with a nontrivial or deleted destructor >+ // are marked as such. >+ EXPECT_FALSE(absl::is_trivially_destructible<NontrivialDestructor>::value); >+#ifdef ABSL_TRIVIALLY_DESTRUCTIBLE_CONSIDER_DELETED_DESTRUCTOR_NOT_TRIVIAL >+ EXPECT_FALSE(absl::is_trivially_destructible<DeletedDestructor>::value); >+#endif >+ >+ // simple_pair of such types is trivial >+ EXPECT_TRUE((absl::is_trivially_destructible<simple_pair<int, int>>::value)); >+ EXPECT_TRUE((absl::is_trivially_destructible< >+ simple_pair<Trivial, TrivialDestructor>>::value)); >+ >+ // Verify that types without trivial destructors are correctly marked as such. >+ EXPECT_FALSE(absl::is_trivially_destructible<std::string>::value); >+ EXPECT_FALSE(absl::is_trivially_destructible<std::vector<int>>::value); >+ >+ // Verify that simple_pairs of types without trivial destructors >+ // are not marked as trivial. >+ EXPECT_FALSE((absl::is_trivially_destructible< >+ simple_pair<int, std::string>>::value)); >+ EXPECT_FALSE((absl::is_trivially_destructible< >+ simple_pair<std::string, int>>::value)); >+ >+ // array of such types is trivial >+ using int10 = int[10]; >+ EXPECT_TRUE(absl::is_trivially_destructible<int10>::value); >+ using Trivial10 = Trivial[10]; >+ EXPECT_TRUE(absl::is_trivially_destructible<Trivial10>::value); >+ using TrivialDestructor10 = TrivialDestructor[10]; >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivialDestructor10>::value); >+ >+ // Conversely, the opposite also holds. >+ using NontrivialDestructor10 = NontrivialDestructor[10]; >+ EXPECT_FALSE(absl::is_trivially_destructible<NontrivialDestructor10>::value); >+} >+ >+TEST(TypeTraitsTest, TestTrivialDefaultCtor) { >+ // arithmetic types and pointers have trivial default constructors. >+ EXPECT_TRUE(absl::is_trivially_default_constructible<bool>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<char>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned char>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<signed char>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<wchar_t>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<int>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<unsigned int>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<int16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<uint16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<int64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<uint64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<float>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<double>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<long double>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial*>::value); >+ EXPECT_TRUE( >+ absl::is_trivially_default_constructible<const std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<const Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<std::string**>::value); >+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial**>::value); >+ >+ // types with compiler generated default ctors >+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial>::value); >+ EXPECT_TRUE( >+ absl::is_trivially_default_constructible<TrivialDefaultCtor>::value); >+ >+ // Verify that types without them are not. >+ EXPECT_FALSE( >+ absl::is_trivially_default_constructible<NontrivialDefaultCtor>::value); >+ EXPECT_FALSE( >+ absl::is_trivially_default_constructible<DeletedDefaultCtor>::value); >+ >+#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE >+ // types with nontrivial destructor are nontrivial >+ EXPECT_FALSE( >+ absl::is_trivially_default_constructible<NontrivialDestructor>::value); >+#endif >+ >+ // types with vtables >+ EXPECT_FALSE(absl::is_trivially_default_constructible<Base>::value); >+ >+ // Verify that simple_pair has trivial constructors where applicable. >+ EXPECT_TRUE((absl::is_trivially_default_constructible< >+ simple_pair<int, char*>>::value)); >+ EXPECT_TRUE((absl::is_trivially_default_constructible< >+ simple_pair<int, Trivial>>::value)); >+ EXPECT_TRUE((absl::is_trivially_default_constructible< >+ simple_pair<int, TrivialDefaultCtor>>::value)); >+ >+ // Verify that types without trivial constructors are >+ // correctly marked as such. >+ EXPECT_FALSE(absl::is_trivially_default_constructible<std::string>::value); >+ EXPECT_FALSE( >+ absl::is_trivially_default_constructible<std::vector<int>>::value); >+ >+ // Verify that simple_pairs of types without trivial constructors >+ // are not marked as trivial. >+ EXPECT_FALSE((absl::is_trivially_default_constructible< >+ simple_pair<int, std::string>>::value)); >+ EXPECT_FALSE((absl::is_trivially_default_constructible< >+ simple_pair<std::string, int>>::value)); >+ >+ // Verify that arrays of such types are trivially default constructible >+ using int10 = int[10]; >+ EXPECT_TRUE(absl::is_trivially_default_constructible<int10>::value); >+ using Trivial10 = Trivial[10]; >+ EXPECT_TRUE(absl::is_trivially_default_constructible<Trivial10>::value); >+ using TrivialDefaultCtor10 = TrivialDefaultCtor[10]; >+ EXPECT_TRUE( >+ absl::is_trivially_default_constructible<TrivialDefaultCtor10>::value); >+ >+ // Conversely, the opposite also holds. >+#ifdef ABSL_GCC_BUG_TRIVIALLY_CONSTRUCTIBLE_ON_ARRAY_OF_NONTRIVIAL >+ using NontrivialDefaultCtor10 = NontrivialDefaultCtor[10]; >+ EXPECT_FALSE( >+ absl::is_trivially_default_constructible<NontrivialDefaultCtor10>::value); >+#endif >+} >+ >+TEST(TypeTraitsTest, TestTrivialCopyCtor) { >+ // Verify that arithmetic types and pointers have trivial copy >+ // constructors. >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<bool>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<signed char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<wchar_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<unsigned int>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<uint16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<int64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<uint64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<float>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<double>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<long double>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<const std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<const Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<std::string**>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial**>::value); >+ >+ // types with compiler generated copy ctors >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<Trivial>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivialCopyCtor>::value); >+ >+ // Verify that types without them (i.e. nontrivial or deleted) are not. >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<NontrivialCopyCtor>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<DeletedCopyCtor>::value); >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<NonCopyable>::value); >+ >+#ifdef ABSL_TRIVIALLY_CONSTRUCTIBLE_VERIFY_TRIVIALLY_DESTRUCTIBLE >+ // type with nontrivial destructor are nontrivial copy construbtible >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<NontrivialDestructor>::value); >+#endif >+ >+ // types with vtables >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<Base>::value); >+ >+ // Verify that simple_pair of such types is trivially copy constructible >+ EXPECT_TRUE( >+ (absl::is_trivially_copy_constructible<simple_pair<int, char*>>::value)); >+ EXPECT_TRUE(( >+ absl::is_trivially_copy_constructible<simple_pair<int, Trivial>>::value)); >+ EXPECT_TRUE((absl::is_trivially_copy_constructible< >+ simple_pair<int, TrivialCopyCtor>>::value)); >+ >+ // Verify that types without trivial copy constructors are >+ // correctly marked as such. >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<std::string>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<std::vector<int>>::value); >+ >+ // Verify that simple_pairs of types without trivial copy constructors >+ // are not marked as trivial. >+ EXPECT_FALSE((absl::is_trivially_copy_constructible< >+ simple_pair<int, std::string>>::value)); >+ EXPECT_FALSE((absl::is_trivially_copy_constructible< >+ simple_pair<std::string, int>>::value)); >+ >+ // Verify that arrays are not >+ using int10 = int[10]; >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<int10>::value); >+} >+ >+TEST(TypeTraitsTest, TestTrivialCopyAssign) { >+ // Verify that arithmetic types and pointers have trivial copy >+ // assignment operators. >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<bool>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<signed char>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<wchar_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<unsigned int>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<uint16_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<uint64_t>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<float>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<double>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<long double>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<const std::string*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<const Trivial*>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<std::string**>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial**>::value); >+ >+ // const qualified types are not assignable >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<const int>::value); >+ >+ // types with compiler generated copy assignment >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivialCopyAssign>::value); >+ >+ // Verify that types without them (i.e. nontrivial or deleted) are not. >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NontrivialCopyAssign>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<DeletedCopyAssign>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NonCopyable>::value); >+ >+ // types with vtables >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<Base>::value); >+ >+ // Verify that simple_pair is trivially assignable >+ EXPECT_TRUE( >+ (absl::is_trivially_copy_assignable<simple_pair<int, char*>>::value)); >+ EXPECT_TRUE( >+ (absl::is_trivially_copy_assignable<simple_pair<int, Trivial>>::value)); >+ EXPECT_TRUE((absl::is_trivially_copy_assignable< >+ simple_pair<int, TrivialCopyAssign>>::value)); >+ >+ // Verify that types not trivially copy assignable are >+ // correctly marked as such. >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<std::string>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<std::vector<int>>::value); >+ >+ // Verify that simple_pairs of types not trivially copy assignable >+ // are not marked as trivial. >+ EXPECT_FALSE((absl::is_trivially_copy_assignable< >+ simple_pair<int, std::string>>::value)); >+ EXPECT_FALSE((absl::is_trivially_copy_assignable< >+ simple_pair<std::string, int>>::value)); >+ >+ // Verify that arrays are not trivially copy assignable >+ using int10 = int[10]; >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<int10>::value); >+ >+ // Verify that references are handled correctly >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&&>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial&>::value); >+} >+ >+#define ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(trait_name, ...) \ >+ EXPECT_TRUE((std::is_same<typename std::trait_name<__VA_ARGS__>::type, \ >+ absl::trait_name##_t<__VA_ARGS__>>::value)) >+ >+TEST(TypeTraitsTest, TestRemoveCVAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_cv, const volatile int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_const, const volatile int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_volatile, const volatile int); >+} >+ >+TEST(TypeTraitsTest, TestAddCVAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_cv, const volatile int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_const, const volatile int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_volatile, const volatile int); >+} >+ >+TEST(TypeTraitsTest, TestReferenceAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, int&&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_reference, volatile int&&); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, int&&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_lvalue_reference, volatile int&&); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, int&&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_rvalue_reference, volatile int&&); >+} >+ >+TEST(TypeTraitsTest, TestPointerAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, int*); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_pointer, volatile int*); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(add_pointer, volatile int); >+} >+ >+TEST(TypeTraitsTest, TestSignednessAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, unsigned); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_signed, volatile unsigned); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, unsigned); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(make_unsigned, volatile unsigned); >+} >+ >+TEST(TypeTraitsTest, TestExtentAliases) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[1][1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_extent, int[][1]); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[1][1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(remove_all_extents, int[][1]); >+} >+ >+TEST(TypeTraitsTest, TestAlignedStorageAlias) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 1, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 2, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 3, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 4, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 5, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 6, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 7, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 8, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 9, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 10, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 11, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 12, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 13, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 14, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 15, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 16, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 17, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 18, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 19, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 20, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 21, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 22, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 23, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 24, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 25, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 26, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 27, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 28, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 29, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 30, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 31, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 32, 128); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(aligned_storage, 33, 128); >+} >+ >+TEST(TypeTraitsTest, TestDecay) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, volatile int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, const volatile int&); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[1][1]); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int[][1]); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int()); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(float)); // NOLINT >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(decay, int(char, ...)); // NOLINT >+} >+ >+struct TypeA {}; >+struct TypeB {}; >+struct TypeC {}; >+struct TypeD {}; >+ >+template <typename T> >+struct Wrap {}; >+ >+enum class TypeEnum { A, B, C, D }; >+ >+struct GetTypeT { >+ template <typename T, >+ absl::enable_if_t<std::is_same<T, TypeA>::value, int> = 0> >+ TypeEnum operator()(Wrap<T>) const { >+ return TypeEnum::A; >+ } >+ >+ template <typename T, >+ absl::enable_if_t<std::is_same<T, TypeB>::value, int> = 0> >+ TypeEnum operator()(Wrap<T>) const { >+ return TypeEnum::B; >+ } >+ >+ template <typename T, >+ absl::enable_if_t<std::is_same<T, TypeC>::value, int> = 0> >+ TypeEnum operator()(Wrap<T>) const { >+ return TypeEnum::C; >+ } >+ >+ // NOTE: TypeD is intentionally not handled >+} constexpr GetType = {}; >+ >+TEST(TypeTraitsTest, TestEnableIf) { >+ EXPECT_EQ(TypeEnum::A, GetType(Wrap<TypeA>())); >+ EXPECT_EQ(TypeEnum::B, GetType(Wrap<TypeB>())); >+ EXPECT_EQ(TypeEnum::C, GetType(Wrap<TypeC>())); >+} >+ >+TEST(TypeTraitsTest, TestConditional) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, true, int, char); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(conditional, false, int, char); >+} >+ >+// TODO(calabrese) Check with specialized std::common_type >+TEST(TypeTraitsTest, TestCommonType) { >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int); >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char&); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(common_type, int, char, int&); >+} >+ >+TEST(TypeTraitsTest, TestUnderlyingType) { >+ enum class enum_char : char {}; >+ enum class enum_long_long : long long {}; // NOLINT(runtime/int) >+ >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_char); >+ ABSL_INTERNAL_EXPECT_ALIAS_EQUIVALENCE(underlying_type, enum_long_long); >+} >+ >+struct GetTypeExtT { >+ template <typename T> >+ absl::result_of_t<const GetTypeT&(T)> operator()(T&& arg) const { >+ return GetType(std::forward<T>(arg)); >+ } >+ >+ TypeEnum operator()(Wrap<TypeD>) const { return TypeEnum::D; } >+} constexpr GetTypeExt = {}; >+ >+TEST(TypeTraitsTest, TestResultOf) { >+ EXPECT_EQ(TypeEnum::A, GetTypeExt(Wrap<TypeA>())); >+ EXPECT_EQ(TypeEnum::B, GetTypeExt(Wrap<TypeB>())); >+ EXPECT_EQ(TypeEnum::C, GetTypeExt(Wrap<TypeC>())); >+ EXPECT_EQ(TypeEnum::D, GetTypeExt(Wrap<TypeD>())); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.bazel >new file mode 100644 >index 00000000000..f49571ebb3e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.bazel >@@ -0,0 +1,67 @@ >+# Copyright 2018 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "int128", >+ srcs = [ >+ "int128.cc", >+ "int128_have_intrinsic.inc", >+ "int128_no_intrinsic.inc", >+ ], >+ hdrs = ["int128.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_test( >+ name = "int128_test", >+ size = "small", >+ srcs = [ >+ "int128_stream_test.cc", >+ "int128_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":int128", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "int128_benchmark", >+ srcs = ["int128_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ deps = [ >+ ":int128", >+ "//absl/base:config", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.gn >new file mode 100644 >index 00000000000..fdfa2e271ff >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/BUILD.gn >@@ -0,0 +1,36 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("int128") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "int128.cc", >+ "int128_have_intrinsic.inc", >+ "int128_no_intrinsic.inc", >+ ] >+ public = [ >+ "int128.h", >+ ] >+ deps = [ >+ "../base:config", >+ "../base:core_headers", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/CMakeLists.txt >new file mode 100644 >index 00000000000..3360b2ee726 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/CMakeLists.txt >@@ -0,0 +1,62 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND NUMERIC_PUBLIC_HEADERS >+ "int128.h" >+) >+ >+ >+# library 128 >+list(APPEND INT128_SRC >+ "int128.cc" >+ ${NUMERIC_PUBLIC_HEADERS} >+) >+absl_library( >+ TARGET >+ absl_int128 >+ SOURCES >+ ${INT128_SRC} >+ PUBLIC_LIBRARIES >+ ${INT128_PUBLIC_LIBRARIES} >+ EXPORT_NAME >+ int128 >+) >+ >+ >+absl_header_library( >+ TARGET >+ absl_numeric >+ PUBLIC_LIBRARIES >+ absl::int128 >+ EXPORT_NAME >+ numeric >+) >+ >+# test int128_test >+set(INT128_TEST_SRC "int128_test.cc") >+set(INT128_TEST_PUBLIC_LIBRARIES absl::numeric absl::base) >+ >+absl_test( >+ TARGET >+ int128_test >+ SOURCES >+ ${INT128_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${INT128_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.cc >new file mode 100644 >index 00000000000..cd79534f3bf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.cc >@@ -0,0 +1,251 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/numeric/int128.h" >+ >+#include <stddef.h> >+#include <cassert> >+#include <iomanip> >+#include <iostream> // NOLINT(readability/streams) >+#include <sstream> >+#include <string> >+#include <type_traits> >+ >+namespace absl { >+ >+const uint128 kuint128max = MakeUint128(std::numeric_limits<uint64_t>::max(), >+ std::numeric_limits<uint64_t>::max()); >+ >+namespace { >+ >+// Returns the 0-based position of the last set bit (i.e., most significant bit) >+// in the given uint64_t. The argument may not be 0. >+// >+// For example: >+// Given: 5 (decimal) == 101 (binary) >+// Returns: 2 >+#define STEP(T, n, pos, sh) \ >+ do { \ >+ if ((n) >= (static_cast<T>(1) << (sh))) { \ >+ (n) = (n) >> (sh); \ >+ (pos) |= (sh); \ >+ } \ >+ } while (0) >+static inline int Fls64(uint64_t n) { >+ assert(n != 0); >+ int pos = 0; >+ STEP(uint64_t, n, pos, 0x20); >+ uint32_t n32 = static_cast<uint32_t>(n); >+ STEP(uint32_t, n32, pos, 0x10); >+ STEP(uint32_t, n32, pos, 0x08); >+ STEP(uint32_t, n32, pos, 0x04); >+ return pos + ((uint64_t{0x3333333322221100} >> (n32 << 2)) & 0x3); >+} >+#undef STEP >+ >+// Like Fls64() above, but returns the 0-based position of the last set bit >+// (i.e., most significant bit) in the given uint128. The argument may not be 0. >+static inline int Fls128(uint128 n) { >+ if (uint64_t hi = Uint128High64(n)) { >+ return Fls64(hi) + 64; >+ } >+ return Fls64(Uint128Low64(n)); >+} >+ >+// Long division/modulo for uint128 implemented using the shift-subtract >+// division algorithm adapted from: >+// http://stackoverflow.com/questions/5386377/division-without-using >+void DivModImpl(uint128 dividend, uint128 divisor, uint128* quotient_ret, >+ uint128* remainder_ret) { >+ assert(divisor != 0); >+ >+ if (divisor > dividend) { >+ *quotient_ret = 0; >+ *remainder_ret = dividend; >+ return; >+ } >+ >+ if (divisor == dividend) { >+ *quotient_ret = 1; >+ *remainder_ret = 0; >+ return; >+ } >+ >+ uint128 denominator = divisor; >+ uint128 quotient = 0; >+ >+ // Left aligns the MSB of the denominator and the dividend. >+ const int shift = Fls128(dividend) - Fls128(denominator); >+ denominator <<= shift; >+ >+ // Uses shift-subtract algorithm to divide dividend by denominator. The >+ // remainder will be left in dividend. >+ for (int i = 0; i <= shift; ++i) { >+ quotient <<= 1; >+ if (dividend >= denominator) { >+ dividend -= denominator; >+ quotient |= 1; >+ } >+ denominator >>= 1; >+ } >+ >+ *quotient_ret = quotient; >+ *remainder_ret = dividend; >+} >+ >+template <typename T> >+uint128 MakeUint128FromFloat(T v) { >+ static_assert(std::is_floating_point<T>::value, ""); >+ >+ // Rounding behavior is towards zero, same as for built-in types. >+ >+ // Undefined behavior if v is NaN or cannot fit into uint128. >+ assert(std::isfinite(v) && v > -1 && >+ (std::numeric_limits<T>::max_exponent <= 128 || >+ v < std::ldexp(static_cast<T>(1), 128))); >+ >+ if (v >= std::ldexp(static_cast<T>(1), 64)) { >+ uint64_t hi = static_cast<uint64_t>(std::ldexp(v, -64)); >+ uint64_t lo = static_cast<uint64_t>(v - std::ldexp(static_cast<T>(hi), 64)); >+ return MakeUint128(hi, lo); >+ } >+ >+ return MakeUint128(0, static_cast<uint64_t>(v)); >+} >+} // namespace >+ >+uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {} >+uint128::uint128(double v) : uint128(MakeUint128FromFloat(v)) {} >+uint128::uint128(long double v) : uint128(MakeUint128FromFloat(v)) {} >+ >+uint128 operator/(uint128 lhs, uint128 rhs) { >+#if defined(ABSL_HAVE_INTRINSIC_INT128) >+ return static_cast<unsigned __int128>(lhs) / >+ static_cast<unsigned __int128>(rhs); >+#else // ABSL_HAVE_INTRINSIC_INT128 >+ uint128 quotient = 0; >+ uint128 remainder = 0; >+ DivModImpl(lhs, rhs, "ient, &remainder); >+ return quotient; >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+} >+uint128 operator%(uint128 lhs, uint128 rhs) { >+#if defined(ABSL_HAVE_INTRINSIC_INT128) >+ return static_cast<unsigned __int128>(lhs) % >+ static_cast<unsigned __int128>(rhs); >+#else // ABSL_HAVE_INTRINSIC_INT128 >+ uint128 quotient = 0; >+ uint128 remainder = 0; >+ DivModImpl(lhs, rhs, "ient, &remainder); >+ return remainder; >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+} >+ >+namespace { >+ >+std::string Uint128ToFormattedString(uint128 v, std::ios_base::fmtflags flags) { >+ // Select a divisor which is the largest power of the base < 2^64. >+ uint128 div; >+ int div_base_log; >+ switch (flags & std::ios::basefield) { >+ case std::ios::hex: >+ div = 0x1000000000000000; // 16^15 >+ div_base_log = 15; >+ break; >+ case std::ios::oct: >+ div = 01000000000000000000000; // 8^21 >+ div_base_log = 21; >+ break; >+ default: // std::ios::dec >+ div = 10000000000000000000u; // 10^19 >+ div_base_log = 19; >+ break; >+ } >+ >+ // Now piece together the uint128 representation from three chunks of the >+ // original value, each less than "div" and therefore representable as a >+ // uint64_t. >+ std::ostringstream os; >+ std::ios_base::fmtflags copy_mask = >+ std::ios::basefield | std::ios::showbase | std::ios::uppercase; >+ os.setf(flags & copy_mask, copy_mask); >+ uint128 high = v; >+ uint128 low; >+ DivModImpl(high, div, &high, &low); >+ uint128 mid; >+ DivModImpl(high, div, &high, &mid); >+ if (Uint128Low64(high) != 0) { >+ os << Uint128Low64(high); >+ os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); >+ os << Uint128Low64(mid); >+ os << std::setw(div_base_log); >+ } else if (Uint128Low64(mid) != 0) { >+ os << Uint128Low64(mid); >+ os << std::noshowbase << std::setfill('0') << std::setw(div_base_log); >+ } >+ os << Uint128Low64(low); >+ return os.str(); >+} >+ >+} // namespace >+ >+std::ostream& operator<<(std::ostream& os, uint128 v) { >+ std::ios_base::fmtflags flags = os.flags(); >+ std::string rep = Uint128ToFormattedString(v, flags); >+ >+ // Add the requisite padding. >+ std::streamsize width = os.width(0); >+ if (static_cast<size_t>(width) > rep.size()) { >+ std::ios::fmtflags adjustfield = flags & std::ios::adjustfield; >+ if (adjustfield == std::ios::left) { >+ rep.append(width - rep.size(), os.fill()); >+ } else if (adjustfield == std::ios::internal && >+ (flags & std::ios::showbase) && >+ (flags & std::ios::basefield) == std::ios::hex && v != 0) { >+ rep.insert(2, width - rep.size(), os.fill()); >+ } else { >+ rep.insert(0, width - rep.size(), os.fill()); >+ } >+ } >+ >+ return os << rep; >+} >+ >+} // namespace absl >+ >+namespace std { >+constexpr bool numeric_limits<absl::uint128>::is_specialized; >+constexpr bool numeric_limits<absl::uint128>::is_signed; >+constexpr bool numeric_limits<absl::uint128>::is_integer; >+constexpr bool numeric_limits<absl::uint128>::is_exact; >+constexpr bool numeric_limits<absl::uint128>::has_infinity; >+constexpr bool numeric_limits<absl::uint128>::has_quiet_NaN; >+constexpr bool numeric_limits<absl::uint128>::has_signaling_NaN; >+constexpr float_denorm_style numeric_limits<absl::uint128>::has_denorm; >+constexpr bool numeric_limits<absl::uint128>::has_denorm_loss; >+constexpr float_round_style numeric_limits<absl::uint128>::round_style; >+constexpr bool numeric_limits<absl::uint128>::is_iec559; >+constexpr bool numeric_limits<absl::uint128>::is_bounded; >+constexpr bool numeric_limits<absl::uint128>::is_modulo; >+constexpr int numeric_limits<absl::uint128>::digits; >+constexpr int numeric_limits<absl::uint128>::digits10; >+constexpr int numeric_limits<absl::uint128>::max_digits10; >+constexpr int numeric_limits<absl::uint128>::radix; >+constexpr int numeric_limits<absl::uint128>::min_exponent; >+constexpr int numeric_limits<absl::uint128>::min_exponent10; >+constexpr int numeric_limits<absl::uint128>::max_exponent; >+constexpr int numeric_limits<absl::uint128>::max_exponent10; >+constexpr bool numeric_limits<absl::uint128>::traps; >+constexpr bool numeric_limits<absl::uint128>::tinyness_before; >+} // namespace std >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.h >new file mode 100644 >index 00000000000..2d131b8bda1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128.h >@@ -0,0 +1,705 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: int128.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines 128-bit integer types. >+// >+// Currently, this file defines `uint128`, an unsigned 128-bit integer; a signed >+// 128-bit integer is forthcoming. >+ >+#ifndef ABSL_NUMERIC_INT128_H_ >+#define ABSL_NUMERIC_INT128_H_ >+ >+#include <cassert> >+#include <cmath> >+#include <cstdint> >+#include <cstring> >+#include <iosfwd> >+#include <limits> >+#include <utility> >+ >+#include "absl/base/config.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+ >+ >+// uint128 >+// >+// An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type >+// as closely as is practical, including exhibiting undefined behavior in >+// analogous cases (e.g. division by zero). This type is intended to be a >+// drop-in replacement once C++ supports an intrinsic `uint128_t` type; when >+// that occurs, existing well-behaved uses of `uint128` will continue to work >+// using that new type. >+// >+// Note: code written with this type will continue to compile once `uint128_t` >+// is introduced, provided the replacement helper functions >+// `Uint128(Low|High)64()` and `MakeUint128()` are made. >+// >+// A `uint128` supports the following: >+// >+// * Implicit construction from integral types >+// * Explicit conversion to integral types >+// >+// Additionally, if your compiler supports `__int128`, `uint128` is >+// interoperable with that type. (Abseil checks for this compatibility through >+// the `ABSL_HAVE_INTRINSIC_INT128` macro.) >+// >+// However, a `uint128` differs from intrinsic integral types in the following >+// ways: >+// >+// * Errors on implicit conversions that do not preserve value (such as >+// loss of precision when converting to float values). >+// * Requires explicit construction from and conversion to floating point >+// types. >+// * Conversion to integral types requires an explicit static_cast() to >+// mimic use of the `-Wnarrowing` compiler flag. >+// * The alignment requirement of `uint128` may differ from that of an >+// intrinsic 128-bit integer type depending on platform and build >+// configuration. >+// >+// Example: >+// >+// float y = absl::Uint128Max(); // Error. uint128 cannot be implicitly >+// // converted to float. >+// >+// absl::uint128 v; >+// uint64_t i = v; // Error >+// uint64_t i = static_cast<uint64_t>(v); // OK >+// >+class >+#if defined(ABSL_HAVE_INTRINSIC_INT128) >+ alignas(unsigned __int128) >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ uint128 { >+ public: >+ uint128() = default; >+ >+ // Constructors from arithmetic types >+ constexpr uint128(int v); // NOLINT(runtime/explicit) >+ constexpr uint128(unsigned int v); // NOLINT(runtime/explicit) >+ constexpr uint128(long v); // NOLINT(runtime/int) >+ constexpr uint128(unsigned long v); // NOLINT(runtime/int) >+ constexpr uint128(long long v); // NOLINT(runtime/int) >+ constexpr uint128(unsigned long long v); // NOLINT(runtime/int) >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ constexpr uint128(__int128 v); // NOLINT(runtime/explicit) >+ constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit) >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ explicit uint128(float v); >+ explicit uint128(double v); >+ explicit uint128(long double v); >+ >+ // Assignment operators from arithmetic types >+ uint128& operator=(int v); >+ uint128& operator=(unsigned int v); >+ uint128& operator=(long v); // NOLINT(runtime/int) >+ uint128& operator=(unsigned long v); // NOLINT(runtime/int) >+ uint128& operator=(long long v); // NOLINT(runtime/int) >+ uint128& operator=(unsigned long long v); // NOLINT(runtime/int) >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ uint128& operator=(__int128 v); >+ uint128& operator=(unsigned __int128 v); >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+ // Conversion operators to other arithmetic types >+ constexpr explicit operator bool() const; >+ constexpr explicit operator char() const; >+ constexpr explicit operator signed char() const; >+ constexpr explicit operator unsigned char() const; >+ constexpr explicit operator char16_t() const; >+ constexpr explicit operator char32_t() const; >+ constexpr explicit operator wchar_t() const; >+ constexpr explicit operator short() const; // NOLINT(runtime/int) >+ // NOLINTNEXTLINE(runtime/int) >+ constexpr explicit operator unsigned short() const; >+ constexpr explicit operator int() const; >+ constexpr explicit operator unsigned int() const; >+ constexpr explicit operator long() const; // NOLINT(runtime/int) >+ // NOLINTNEXTLINE(runtime/int) >+ constexpr explicit operator unsigned long() const; >+ // NOLINTNEXTLINE(runtime/int) >+ constexpr explicit operator long long() const; >+ // NOLINTNEXTLINE(runtime/int) >+ constexpr explicit operator unsigned long long() const; >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ constexpr explicit operator __int128() const; >+ constexpr explicit operator unsigned __int128() const; >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ explicit operator float() const; >+ explicit operator double() const; >+ explicit operator long double() const; >+ >+ // Trivial copy constructor, assignment operator and destructor. >+ >+ // Arithmetic operators. >+ uint128& operator+=(uint128 other); >+ uint128& operator-=(uint128 other); >+ uint128& operator*=(uint128 other); >+ // Long division/modulo for uint128. >+ uint128& operator/=(uint128 other); >+ uint128& operator%=(uint128 other); >+ uint128 operator++(int); >+ uint128 operator--(int); >+ uint128& operator<<=(int); >+ uint128& operator>>=(int); >+ uint128& operator&=(uint128 other); >+ uint128& operator|=(uint128 other); >+ uint128& operator^=(uint128 other); >+ uint128& operator++(); >+ uint128& operator--(); >+ >+ // Uint128Low64() >+ // >+ // Returns the lower 64-bit value of a `uint128` value. >+ friend constexpr uint64_t Uint128Low64(uint128 v); >+ >+ // Uint128High64() >+ // >+ // Returns the higher 64-bit value of a `uint128` value. >+ friend constexpr uint64_t Uint128High64(uint128 v); >+ >+ // MakeUInt128() >+ // >+ // Constructs a `uint128` numeric value from two 64-bit unsigned integers. >+ // Note that this factory function is the only way to construct a `uint128` >+ // from integer values greater than 2^64. >+ // >+ // Example: >+ // >+ // absl::uint128 big = absl::MakeUint128(1, 0); >+ friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low); >+ >+ // Uint128Max() >+ // >+ // Returns the highest value for a 128-bit unsigned integer. >+ friend constexpr uint128 Uint128Max(); >+ >+ private: >+ constexpr uint128(uint64_t high, uint64_t low); >+ >+ // TODO(strel) Update implementation to use __int128 once all users of >+ // uint128 are fixed to not depend on alignof(uint128) == 8. Also add >+ // alignas(16) to class definition to keep alignment consistent across >+ // platforms. >+#if defined(ABSL_IS_LITTLE_ENDIAN) >+ uint64_t lo_; >+ uint64_t hi_; >+#elif defined(ABSL_IS_BIG_ENDIAN) >+ uint64_t hi_; >+ uint64_t lo_; >+#else // byte order >+#error "Unsupported byte order: must be little-endian or big-endian." >+#endif // byte order >+}; >+ >+// Prefer to use the constexpr `Uint128Max()`. >+// >+// TODO(absl-team) deprecate kuint128max once migration tool is released. >+extern const uint128 kuint128max; >+ >+// allow uint128 to be logged >+std::ostream& operator<<(std::ostream& os, uint128 v); >+ >+// TODO(strel) add operator>>(std::istream&, uint128) >+ >+constexpr uint128 Uint128Max() { >+ return uint128(std::numeric_limits<uint64_t>::max(), >+ std::numeric_limits<uint64_t>::max()); >+} >+ >+} // namespace absl >+ >+// Specialized numeric_limits for uint128. >+namespace std { >+template <> >+class numeric_limits<absl::uint128> { >+ public: >+ static constexpr bool is_specialized = true; >+ static constexpr bool is_signed = false; >+ static constexpr bool is_integer = true; >+ static constexpr bool is_exact = true; >+ static constexpr bool has_infinity = false; >+ static constexpr bool has_quiet_NaN = false; >+ static constexpr bool has_signaling_NaN = false; >+ static constexpr float_denorm_style has_denorm = denorm_absent; >+ static constexpr bool has_denorm_loss = false; >+ static constexpr float_round_style round_style = round_toward_zero; >+ static constexpr bool is_iec559 = false; >+ static constexpr bool is_bounded = true; >+ static constexpr bool is_modulo = true; >+ static constexpr int digits = 128; >+ static constexpr int digits10 = 38; >+ static constexpr int max_digits10 = 0; >+ static constexpr int radix = 2; >+ static constexpr int min_exponent = 0; >+ static constexpr int min_exponent10 = 0; >+ static constexpr int max_exponent = 0; >+ static constexpr int max_exponent10 = 0; >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ static constexpr bool traps = numeric_limits<unsigned __int128>::traps; >+#else // ABSL_HAVE_INTRINSIC_INT128 >+ static constexpr bool traps = numeric_limits<uint64_t>::traps; >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ static constexpr bool tinyness_before = false; >+ >+ static constexpr absl::uint128 min() { return 0; } >+ static constexpr absl::uint128 lowest() { return 0; } >+ static constexpr absl::uint128 max() { return absl::Uint128Max(); } >+ static constexpr absl::uint128 epsilon() { return 0; } >+ static constexpr absl::uint128 round_error() { return 0; } >+ static constexpr absl::uint128 infinity() { return 0; } >+ static constexpr absl::uint128 quiet_NaN() { return 0; } >+ static constexpr absl::uint128 signaling_NaN() { return 0; } >+ static constexpr absl::uint128 denorm_min() { return 0; } >+}; >+} // namespace std >+ >+// TODO(absl-team): Implement signed 128-bit type >+ >+// -------------------------------------------------------------------------- >+// Implementation details follow >+// -------------------------------------------------------------------------- >+namespace absl { >+ >+constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { >+ return uint128(high, low); >+} >+ >+// Assignment from integer types. >+ >+inline uint128& uint128::operator=(int v) { return *this = uint128(v); } >+ >+inline uint128& uint128::operator=(unsigned int v) { >+ return *this = uint128(v); >+} >+ >+inline uint128& uint128::operator=(long v) { // NOLINT(runtime/int) >+ return *this = uint128(v); >+} >+ >+// NOLINTNEXTLINE(runtime/int) >+inline uint128& uint128::operator=(unsigned long v) { >+ return *this = uint128(v); >+} >+ >+// NOLINTNEXTLINE(runtime/int) >+inline uint128& uint128::operator=(long long v) { >+ return *this = uint128(v); >+} >+ >+// NOLINTNEXTLINE(runtime/int) >+inline uint128& uint128::operator=(unsigned long long v) { >+ return *this = uint128(v); >+} >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+inline uint128& uint128::operator=(__int128 v) { >+ return *this = uint128(v); >+} >+ >+inline uint128& uint128::operator=(unsigned __int128 v) { >+ return *this = uint128(v); >+} >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+// Arithmetic operators. >+ >+uint128 operator<<(uint128 lhs, int amount); >+uint128 operator>>(uint128 lhs, int amount); >+uint128 operator+(uint128 lhs, uint128 rhs); >+uint128 operator-(uint128 lhs, uint128 rhs); >+uint128 operator*(uint128 lhs, uint128 rhs); >+uint128 operator/(uint128 lhs, uint128 rhs); >+uint128 operator%(uint128 lhs, uint128 rhs); >+ >+inline uint128& uint128::operator<<=(int amount) { >+ *this = *this << amount; >+ return *this; >+} >+ >+inline uint128& uint128::operator>>=(int amount) { >+ *this = *this >> amount; >+ return *this; >+} >+ >+inline uint128& uint128::operator+=(uint128 other) { >+ *this = *this + other; >+ return *this; >+} >+ >+inline uint128& uint128::operator-=(uint128 other) { >+ *this = *this - other; >+ return *this; >+} >+ >+inline uint128& uint128::operator*=(uint128 other) { >+ *this = *this * other; >+ return *this; >+} >+ >+inline uint128& uint128::operator/=(uint128 other) { >+ *this = *this / other; >+ return *this; >+} >+ >+inline uint128& uint128::operator%=(uint128 other) { >+ *this = *this % other; >+ return *this; >+} >+ >+constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } >+ >+constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } >+ >+// Constructors from integer types. >+ >+#if defined(ABSL_IS_LITTLE_ENDIAN) >+ >+constexpr uint128::uint128(uint64_t high, uint64_t low) >+ : lo_{low}, hi_{high} {} >+ >+constexpr uint128::uint128(int v) >+ : lo_{static_cast<uint64_t>(v)}, >+ hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} >+constexpr uint128::uint128(long v) // NOLINT(runtime/int) >+ : lo_{static_cast<uint64_t>(v)}, >+ hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} >+constexpr uint128::uint128(long long v) // NOLINT(runtime/int) >+ : lo_{static_cast<uint64_t>(v)}, >+ hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0} {} >+ >+constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {} >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {} >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {} >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+constexpr uint128::uint128(__int128 v) >+ : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, >+ hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)} {} >+constexpr uint128::uint128(unsigned __int128 v) >+ : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, >+ hi_{static_cast<uint64_t>(v >> 64)} {} >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+#elif defined(ABSL_IS_BIG_ENDIAN) >+ >+constexpr uint128::uint128(uint64_t high, uint64_t low) >+ : hi_{high}, lo_{low} {} >+ >+constexpr uint128::uint128(int v) >+ : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, >+ lo_{static_cast<uint64_t>(v)} {} >+constexpr uint128::uint128(long v) // NOLINT(runtime/int) >+ : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, >+ lo_{static_cast<uint64_t>(v)} {} >+constexpr uint128::uint128(long long v) // NOLINT(runtime/int) >+ : hi_{v < 0 ? std::numeric_limits<uint64_t>::max() : 0}, >+ lo_{static_cast<uint64_t>(v)} {} >+ >+constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {} >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {} >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {} >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+constexpr uint128::uint128(__int128 v) >+ : hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)}, >+ lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} >+constexpr uint128::uint128(unsigned __int128 v) >+ : hi_{static_cast<uint64_t>(v >> 64)}, >+ lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+#else // byte order >+#error "Unsupported byte order: must be little-endian or big-endian." >+#endif // byte order >+ >+// Conversion operators to integer types. >+ >+constexpr uint128::operator bool() const { return lo_ || hi_; } >+ >+constexpr uint128::operator char() const { return static_cast<char>(lo_); } >+ >+constexpr uint128::operator signed char() const { >+ return static_cast<signed char>(lo_); >+} >+ >+constexpr uint128::operator unsigned char() const { >+ return static_cast<unsigned char>(lo_); >+} >+ >+constexpr uint128::operator char16_t() const { >+ return static_cast<char16_t>(lo_); >+} >+ >+constexpr uint128::operator char32_t() const { >+ return static_cast<char32_t>(lo_); >+} >+ >+constexpr uint128::operator wchar_t() const { >+ return static_cast<wchar_t>(lo_); >+} >+ >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::operator short() const { return static_cast<short>(lo_); } >+ >+constexpr uint128::operator unsigned short() const { // NOLINT(runtime/int) >+ return static_cast<unsigned short>(lo_); // NOLINT(runtime/int) >+} >+ >+constexpr uint128::operator int() const { return static_cast<int>(lo_); } >+ >+constexpr uint128::operator unsigned int() const { >+ return static_cast<unsigned int>(lo_); >+} >+ >+// NOLINTNEXTLINE(runtime/int) >+constexpr uint128::operator long() const { return static_cast<long>(lo_); } >+ >+constexpr uint128::operator unsigned long() const { // NOLINT(runtime/int) >+ return static_cast<unsigned long>(lo_); // NOLINT(runtime/int) >+} >+ >+constexpr uint128::operator long long() const { // NOLINT(runtime/int) >+ return static_cast<long long>(lo_); // NOLINT(runtime/int) >+} >+ >+constexpr uint128::operator unsigned long long() const { // NOLINT(runtime/int) >+ return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) >+} >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+constexpr uint128::operator __int128() const { >+ return (static_cast<__int128>(hi_) << 64) + lo_; >+} >+ >+constexpr uint128::operator unsigned __int128() const { >+ return (static_cast<unsigned __int128>(hi_) << 64) + lo_; >+} >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+// Conversion operators to floating point types. >+ >+inline uint128::operator float() const { >+ return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64); >+} >+ >+inline uint128::operator double() const { >+ return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64); >+} >+ >+inline uint128::operator long double() const { >+ return static_cast<long double>(lo_) + >+ std::ldexp(static_cast<long double>(hi_), 64); >+} >+ >+// Comparison operators. >+ >+inline bool operator==(uint128 lhs, uint128 rhs) { >+ return (Uint128Low64(lhs) == Uint128Low64(rhs) && >+ Uint128High64(lhs) == Uint128High64(rhs)); >+} >+ >+inline bool operator!=(uint128 lhs, uint128 rhs) { >+ return !(lhs == rhs); >+} >+ >+inline bool operator<(uint128 lhs, uint128 rhs) { >+ return (Uint128High64(lhs) == Uint128High64(rhs)) >+ ? (Uint128Low64(lhs) < Uint128Low64(rhs)) >+ : (Uint128High64(lhs) < Uint128High64(rhs)); >+} >+ >+inline bool operator>(uint128 lhs, uint128 rhs) { >+ return (Uint128High64(lhs) == Uint128High64(rhs)) >+ ? (Uint128Low64(lhs) > Uint128Low64(rhs)) >+ : (Uint128High64(lhs) > Uint128High64(rhs)); >+} >+ >+inline bool operator<=(uint128 lhs, uint128 rhs) { >+ return (Uint128High64(lhs) == Uint128High64(rhs)) >+ ? (Uint128Low64(lhs) <= Uint128Low64(rhs)) >+ : (Uint128High64(lhs) <= Uint128High64(rhs)); >+} >+ >+inline bool operator>=(uint128 lhs, uint128 rhs) { >+ return (Uint128High64(lhs) == Uint128High64(rhs)) >+ ? (Uint128Low64(lhs) >= Uint128Low64(rhs)) >+ : (Uint128High64(lhs) >= Uint128High64(rhs)); >+} >+ >+// Unary operators. >+ >+inline uint128 operator-(uint128 val) { >+ uint64_t hi = ~Uint128High64(val); >+ uint64_t lo = ~Uint128Low64(val) + 1; >+ if (lo == 0) ++hi; // carry >+ return MakeUint128(hi, lo); >+} >+ >+inline bool operator!(uint128 val) { >+ return !Uint128High64(val) && !Uint128Low64(val); >+} >+ >+// Logical operators. >+ >+inline uint128 operator~(uint128 val) { >+ return MakeUint128(~Uint128High64(val), ~Uint128Low64(val)); >+} >+ >+inline uint128 operator|(uint128 lhs, uint128 rhs) { >+ return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs), >+ Uint128Low64(lhs) | Uint128Low64(rhs)); >+} >+ >+inline uint128 operator&(uint128 lhs, uint128 rhs) { >+ return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs), >+ Uint128Low64(lhs) & Uint128Low64(rhs)); >+} >+ >+inline uint128 operator^(uint128 lhs, uint128 rhs) { >+ return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs), >+ Uint128Low64(lhs) ^ Uint128Low64(rhs)); >+} >+ >+inline uint128& uint128::operator|=(uint128 other) { >+ hi_ |= other.hi_; >+ lo_ |= other.lo_; >+ return *this; >+} >+ >+inline uint128& uint128::operator&=(uint128 other) { >+ hi_ &= other.hi_; >+ lo_ &= other.lo_; >+ return *this; >+} >+ >+inline uint128& uint128::operator^=(uint128 other) { >+ hi_ ^= other.hi_; >+ lo_ ^= other.lo_; >+ return *this; >+} >+ >+// Arithmetic operators. >+ >+inline uint128 operator<<(uint128 lhs, int amount) { >+ // uint64_t shifts of >= 64 are undefined, so we will need some >+ // special-casing. >+ if (amount < 64) { >+ if (amount != 0) { >+ return MakeUint128( >+ (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), >+ Uint128Low64(lhs) << amount); >+ } >+ return lhs; >+ } >+ return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0); >+} >+ >+inline uint128 operator>>(uint128 lhs, int amount) { >+ // uint64_t shifts of >= 64 are undefined, so we will need some >+ // special-casing. >+ if (amount < 64) { >+ if (amount != 0) { >+ return MakeUint128(Uint128High64(lhs) >> amount, >+ (Uint128Low64(lhs) >> amount) | >+ (Uint128High64(lhs) << (64 - amount))); >+ } >+ return lhs; >+ } >+ return MakeUint128(0, Uint128High64(lhs) >> (amount - 64)); >+} >+ >+inline uint128 operator+(uint128 lhs, uint128 rhs) { >+ uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), >+ Uint128Low64(lhs) + Uint128Low64(rhs)); >+ if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry >+ return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)); >+ } >+ return result; >+} >+ >+inline uint128 operator-(uint128 lhs, uint128 rhs) { >+ uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), >+ Uint128Low64(lhs) - Uint128Low64(rhs)); >+ if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry >+ return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)); >+ } >+ return result; >+} >+ >+inline uint128 operator*(uint128 lhs, uint128 rhs) { >+#if defined(ABSL_HAVE_INTRINSIC_INT128) >+ // TODO(strel) Remove once alignment issues are resolved and unsigned __int128 >+ // can be used for uint128 storage. >+ return static_cast<unsigned __int128>(lhs) * >+ static_cast<unsigned __int128>(rhs); >+#else // ABSL_HAVE_INTRINSIC128 >+ uint64_t a32 = Uint128Low64(lhs) >> 32; >+ uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; >+ uint64_t b32 = Uint128Low64(rhs) >> 32; >+ uint64_t b00 = Uint128Low64(rhs) & 0xffffffff; >+ uint128 result = >+ MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) + >+ Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32, >+ a00 * b00); >+ result += uint128(a32 * b00) << 32; >+ result += uint128(a00 * b32) << 32; >+ return result; >+#endif // ABSL_HAVE_INTRINSIC128 >+} >+ >+// Increment/decrement operators. >+ >+inline uint128 uint128::operator++(int) { >+ uint128 tmp(*this); >+ *this += 1; >+ return tmp; >+} >+ >+inline uint128 uint128::operator--(int) { >+ uint128 tmp(*this); >+ *this -= 1; >+ return tmp; >+} >+ >+inline uint128& uint128::operator++() { >+ *this += 1; >+ return *this; >+} >+ >+inline uint128& uint128::operator--() { >+ *this -= 1; >+ return *this; >+} >+ >+#if defined(ABSL_HAVE_INTRINSIC_INT128) >+#include "absl/numeric/int128_have_intrinsic.inc" >+#else // ABSL_HAVE_INTRINSIC_INT128 >+#include "absl/numeric/int128_no_intrinsic.inc" >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+} // namespace absl >+ >+#endif // ABSL_NUMERIC_INT128_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_benchmark.cc >new file mode 100644 >index 00000000000..1cb7d0ed87e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_benchmark.cc >@@ -0,0 +1,221 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/numeric/int128.h" >+ >+#include <algorithm> >+#include <cstdint> >+#include <random> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/config.h" >+ >+namespace { >+ >+constexpr size_t kSampleSize = 1000000; >+ >+std::mt19937 MakeRandomEngine() { >+ std::random_device r; >+ std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()}); >+ return std::mt19937(seed); >+} >+ >+std::vector<std::pair<absl::uint128, absl::uint128>> >+GetRandomClass128SampleUniformDivisor() { >+ std::vector<std::pair<absl::uint128, absl::uint128>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ std::uniform_int_distribution<uint64_t> uniform_uint64; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ absl::uint128 a = >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)); >+ absl::uint128 b = >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)); >+ values.emplace_back(std::max(a, b), >+ std::max(absl::uint128(2), std::min(a, b))); >+ } >+ return values; >+} >+ >+void BM_DivideClass128UniformDivisor(benchmark::State& state) { >+ auto values = GetRandomClass128SampleUniformDivisor(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first / pair.second); >+ } >+ } >+} >+BENCHMARK(BM_DivideClass128UniformDivisor); >+ >+std::vector<std::pair<absl::uint128, uint64_t>> >+GetRandomClass128SampleSmallDivisor() { >+ std::vector<std::pair<absl::uint128, uint64_t>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ std::uniform_int_distribution<uint64_t> uniform_uint64; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ absl::uint128 a = >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)); >+ uint64_t b = std::max(uint64_t{2}, uniform_uint64(random)); >+ values.emplace_back(std::max(a, absl::uint128(b)), b); >+ } >+ return values; >+} >+ >+void BM_DivideClass128SmallDivisor(benchmark::State& state) { >+ auto values = GetRandomClass128SampleSmallDivisor(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first / pair.second); >+ } >+ } >+} >+BENCHMARK(BM_DivideClass128SmallDivisor); >+ >+std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() { >+ std::vector<std::pair<absl::uint128, absl::uint128>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ std::uniform_int_distribution<uint64_t> uniform_uint64; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ values.emplace_back( >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)), >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random))); >+ } >+ return values; >+} >+ >+void BM_MultiplyClass128(benchmark::State& state) { >+ auto values = GetRandomClass128Sample(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first * pair.second); >+ } >+ } >+} >+BENCHMARK(BM_MultiplyClass128); >+ >+void BM_AddClass128(benchmark::State& state) { >+ auto values = GetRandomClass128Sample(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first + pair.second); >+ } >+ } >+} >+BENCHMARK(BM_AddClass128); >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ >+// Some implementations of <random> do not support __int128 when it is >+// available, so we make our own uniform_int_distribution-like type. >+class UniformIntDistribution128 { >+ public: >+ // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API >+ unsigned __int128 operator()(std::mt19937& generator) { >+ return (static_cast<unsigned __int128>(dist64_(generator)) << 64) | >+ dist64_(generator); >+ } >+ >+ private: >+ std::uniform_int_distribution<uint64_t> dist64_; >+}; >+ >+std::vector<std::pair<unsigned __int128, unsigned __int128>> >+GetRandomIntrinsic128SampleUniformDivisor() { >+ std::vector<std::pair<unsigned __int128, unsigned __int128>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ UniformIntDistribution128 uniform_uint128; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ unsigned __int128 a = uniform_uint128(random); >+ unsigned __int128 b = uniform_uint128(random); >+ values.emplace_back( >+ std::max(a, b), >+ std::max(static_cast<unsigned __int128>(2), std::min(a, b))); >+ } >+ return values; >+} >+ >+void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) { >+ auto values = GetRandomIntrinsic128SampleUniformDivisor(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first / pair.second); >+ } >+ } >+} >+BENCHMARK(BM_DivideIntrinsic128UniformDivisor); >+ >+std::vector<std::pair<unsigned __int128, uint64_t>> >+GetRandomIntrinsic128SampleSmallDivisor() { >+ std::vector<std::pair<unsigned __int128, uint64_t>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ UniformIntDistribution128 uniform_uint128; >+ std::uniform_int_distribution<uint64_t> uniform_uint64; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ unsigned __int128 a = uniform_uint128(random); >+ uint64_t b = std::max(uint64_t{2}, uniform_uint64(random)); >+ values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b); >+ } >+ return values; >+} >+ >+void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) { >+ auto values = GetRandomIntrinsic128SampleSmallDivisor(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first / pair.second); >+ } >+ } >+} >+BENCHMARK(BM_DivideIntrinsic128SmallDivisor); >+ >+std::vector<std::pair<unsigned __int128, unsigned __int128>> >+ GetRandomIntrinsic128Sample() { >+ std::vector<std::pair<unsigned __int128, unsigned __int128>> values; >+ std::mt19937 random = MakeRandomEngine(); >+ UniformIntDistribution128 uniform_uint128; >+ values.reserve(kSampleSize); >+ for (size_t i = 0; i < kSampleSize; ++i) { >+ values.emplace_back(uniform_uint128(random), uniform_uint128(random)); >+ } >+ return values; >+} >+ >+void BM_MultiplyIntrinsic128(benchmark::State& state) { >+ auto values = GetRandomIntrinsic128Sample(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first * pair.second); >+ } >+ } >+} >+BENCHMARK(BM_MultiplyIntrinsic128); >+ >+void BM_AddIntrinsic128(benchmark::State& state) { >+ auto values = GetRandomIntrinsic128Sample(); >+ while (state.KeepRunningBatch(values.size())) { >+ for (const auto& pair : values) { >+ benchmark::DoNotOptimize(pair.first + pair.second); >+ } >+ } >+} >+BENCHMARK(BM_AddIntrinsic128); >+ >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc >new file mode 100644 >index 00000000000..ee2a093018d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_have_intrinsic.inc >@@ -0,0 +1,18 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains :int128 implementation details that depend on internal >+// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is >+// included by int128.h. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc >new file mode 100644 >index 00000000000..0d0b3cfdeb1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_no_intrinsic.inc >@@ -0,0 +1,18 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains :int128 implementation details that depend on internal >+// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file >+// is included by int128.h. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_stream_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_stream_test.cc >new file mode 100644 >index 00000000000..09efaad4e7f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_stream_test.cc >@@ -0,0 +1,666 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/numeric/int128.h" >+ >+#include <sstream> >+#include <string> >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+struct Uint128TestCase { >+ absl::uint128 value; >+ std::ios_base::fmtflags flags; >+ std::streamsize width; >+ const char* expected; >+}; >+ >+constexpr char kFill = '_'; >+ >+std::string StreamFormatToString(std::ios_base::fmtflags flags, >+ std::streamsize width) { >+ std::vector<const char*> flagstr; >+ switch (flags & std::ios::basefield) { >+ case std::ios::dec: >+ flagstr.push_back("std::ios::dec"); >+ break; >+ case std::ios::oct: >+ flagstr.push_back("std::ios::oct"); >+ break; >+ case std::ios::hex: >+ flagstr.push_back("std::ios::hex"); >+ break; >+ default: // basefield not specified >+ break; >+ } >+ switch (flags & std::ios::adjustfield) { >+ case std::ios::left: >+ flagstr.push_back("std::ios::left"); >+ break; >+ case std::ios::internal: >+ flagstr.push_back("std::ios::internal"); >+ break; >+ case std::ios::right: >+ flagstr.push_back("std::ios::right"); >+ break; >+ default: // adjustfield not specified >+ break; >+ } >+ if (flags & std::ios::uppercase) flagstr.push_back("std::ios::uppercase"); >+ if (flags & std::ios::showbase) flagstr.push_back("std::ios::showbase"); >+ if (flags & std::ios::showpos) flagstr.push_back("std::ios::showpos"); >+ >+ std::ostringstream msg; >+ msg << "\n StreamFormatToString(test_case.flags, test_case.width)\n " >+ "flags: "; >+ if (!flagstr.empty()) { >+ for (size_t i = 0; i < flagstr.size() - 1; ++i) msg << flagstr[i] << " | "; >+ msg << flagstr.back(); >+ } else { >+ msg << "(default)"; >+ } >+ msg << "\n width: " << width << "\n fill: '" << kFill << "'"; >+ return msg.str(); >+} >+ >+void CheckUint128Case(const Uint128TestCase& test_case) { >+ std::ostringstream os; >+ os.flags(test_case.flags); >+ os.width(test_case.width); >+ os.fill(kFill); >+ os << test_case.value; >+ SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width)); >+ EXPECT_EQ(test_case.expected, os.str()); >+} >+ >+constexpr std::ios::fmtflags kDec = std::ios::dec; >+constexpr std::ios::fmtflags kOct = std::ios::oct; >+constexpr std::ios::fmtflags kHex = std::ios::hex; >+constexpr std::ios::fmtflags kLeft = std::ios::left; >+constexpr std::ios::fmtflags kInt = std::ios::internal; >+constexpr std::ios::fmtflags kRight = std::ios::right; >+constexpr std::ios::fmtflags kUpper = std::ios::uppercase; >+constexpr std::ios::fmtflags kBase = std::ios::showbase; >+constexpr std::ios::fmtflags kPos = std::ios::showpos; >+ >+TEST(Uint128, OStreamValueTest) { >+ CheckUint128Case({1, kDec, /*width = */ 0, "1"}); >+ CheckUint128Case({1, kOct, /*width = */ 0, "1"}); >+ CheckUint128Case({1, kHex, /*width = */ 0, "1"}); >+ CheckUint128Case({9, kDec, /*width = */ 0, "9"}); >+ CheckUint128Case({9, kOct, /*width = */ 0, "11"}); >+ CheckUint128Case({9, kHex, /*width = */ 0, "9"}); >+ CheckUint128Case({12345, kDec, /*width = */ 0, "12345"}); >+ CheckUint128Case({12345, kOct, /*width = */ 0, "30071"}); >+ CheckUint128Case({12345, kHex, /*width = */ 0, "3039"}); >+ CheckUint128Case( >+ {0x8000000000000000, kDec, /*width = */ 0, "9223372036854775808"}); >+ CheckUint128Case( >+ {0x8000000000000000, kOct, /*width = */ 0, "1000000000000000000000"}); >+ CheckUint128Case( >+ {0x8000000000000000, kHex, /*width = */ 0, "8000000000000000"}); >+ CheckUint128Case({std::numeric_limits<uint64_t>::max(), kDec, >+ /*width = */ 0, "18446744073709551615"}); >+ CheckUint128Case({std::numeric_limits<uint64_t>::max(), kOct, >+ /*width = */ 0, "1777777777777777777777"}); >+ CheckUint128Case({std::numeric_limits<uint64_t>::max(), kHex, >+ /*width = */ 0, "ffffffffffffffff"}); >+ CheckUint128Case( >+ {absl::MakeUint128(1, 0), kDec, /*width = */ 0, "18446744073709551616"}); >+ CheckUint128Case({absl::MakeUint128(1, 0), kOct, /*width = */ 0, >+ "2000000000000000000000"}); >+ CheckUint128Case( >+ {absl::MakeUint128(1, 0), kHex, /*width = */ 0, "10000000000000000"}); >+ CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kDec, >+ /*width = */ 0, "170141183460469231731687303715884105728"}); >+ CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kOct, >+ /*width = */ 0, >+ "2000000000000000000000000000000000000000000"}); >+ CheckUint128Case({absl::MakeUint128(0x8000000000000000, 0), kHex, >+ /*width = */ 0, "80000000000000000000000000000000"}); >+ CheckUint128Case({absl::kuint128max, kDec, /*width = */ 0, >+ "340282366920938463463374607431768211455"}); >+ CheckUint128Case({absl::kuint128max, kOct, /*width = */ 0, >+ "3777777777777777777777777777777777777777777"}); >+ CheckUint128Case({absl::kuint128max, kHex, /*width = */ 0, >+ "ffffffffffffffffffffffffffffffff"}); >+} >+ >+std::vector<Uint128TestCase> GetUint128FormatCases(); >+ >+TEST(Uint128, OStreamFormatTest) { >+ for (const Uint128TestCase& test_case : GetUint128FormatCases()) { >+ CheckUint128Case(test_case); >+ } >+} >+ >+std::vector<Uint128TestCase> GetUint128FormatCases() { >+ return { >+ {0, std::ios_base::fmtflags(), /*width = */ 0, "0"}, >+ {0, std::ios_base::fmtflags(), /*width = */ 6, "_____0"}, >+ {0, kPos, /*width = */ 0, "0"}, >+ {0, kPos, /*width = */ 6, "_____0"}, >+ {0, kBase, /*width = */ 0, "0"}, >+ {0, kBase, /*width = */ 6, "_____0"}, >+ {0, kBase | kPos, /*width = */ 0, "0"}, >+ {0, kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kUpper, /*width = */ 0, "0"}, >+ {0, kUpper, /*width = */ 6, "_____0"}, >+ {0, kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kLeft, /*width = */ 0, "0"}, >+ {0, kLeft, /*width = */ 6, "0_____"}, >+ {0, kLeft | kPos, /*width = */ 0, "0"}, >+ {0, kLeft | kPos, /*width = */ 6, "0_____"}, >+ {0, kLeft | kBase, /*width = */ 0, "0"}, >+ {0, kLeft | kBase, /*width = */ 6, "0_____"}, >+ {0, kLeft | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kLeft | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kLeft | kUpper, /*width = */ 0, "0"}, >+ {0, kLeft | kUpper, /*width = */ 6, "0_____"}, >+ {0, kLeft | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kLeft | kUpper | kPos, /*width = */ 6, "0_____"}, >+ {0, kLeft | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kLeft | kUpper | kBase, /*width = */ 6, "0_____"}, >+ {0, kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kInt, /*width = */ 0, "0"}, >+ {0, kInt, /*width = */ 6, "_____0"}, >+ {0, kInt | kPos, /*width = */ 0, "0"}, >+ {0, kInt | kPos, /*width = */ 6, "_____0"}, >+ {0, kInt | kBase, /*width = */ 0, "0"}, >+ {0, kInt | kBase, /*width = */ 6, "_____0"}, >+ {0, kInt | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kInt | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kInt | kUpper, /*width = */ 0, "0"}, >+ {0, kInt | kUpper, /*width = */ 6, "_____0"}, >+ {0, kInt | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kInt | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kInt | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kInt | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kInt | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kRight, /*width = */ 0, "0"}, >+ {0, kRight, /*width = */ 6, "_____0"}, >+ {0, kRight | kPos, /*width = */ 0, "0"}, >+ {0, kRight | kPos, /*width = */ 6, "_____0"}, >+ {0, kRight | kBase, /*width = */ 0, "0"}, >+ {0, kRight | kBase, /*width = */ 6, "_____0"}, >+ {0, kRight | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kRight | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kRight | kUpper, /*width = */ 0, "0"}, >+ {0, kRight | kUpper, /*width = */ 6, "_____0"}, >+ {0, kRight | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kRight | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kRight | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kRight | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kRight | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec, /*width = */ 0, "0"}, >+ {0, kDec, /*width = */ 6, "_____0"}, >+ {0, kDec | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kUpper, /*width = */ 0, "0"}, >+ {0, kDec | kUpper, /*width = */ 6, "_____0"}, >+ {0, kDec | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kLeft, /*width = */ 0, "0"}, >+ {0, kDec | kLeft, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kPos, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kBase, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kUpper, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kUpper, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kUpper | kPos, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kUpper | kBase, /*width = */ 6, "0_____"}, >+ {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kDec | kInt, /*width = */ 0, "0"}, >+ {0, kDec | kInt, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kUpper, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kUpper, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight, /*width = */ 0, "0"}, >+ {0, kDec | kRight, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kUpper, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kUpper, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct, /*width = */ 0, "0"}, >+ {0, kOct, /*width = */ 6, "_____0"}, >+ {0, kOct | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kUpper, /*width = */ 0, "0"}, >+ {0, kOct | kUpper, /*width = */ 6, "_____0"}, >+ {0, kOct | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kLeft, /*width = */ 0, "0"}, >+ {0, kOct | kLeft, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kPos, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kBase, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kUpper, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kUpper, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kUpper | kPos, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kUpper | kBase, /*width = */ 6, "0_____"}, >+ {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kOct | kInt, /*width = */ 0, "0"}, >+ {0, kOct | kInt, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kUpper, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kUpper, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight, /*width = */ 0, "0"}, >+ {0, kOct | kRight, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kUpper, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kUpper, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex, /*width = */ 0, "0"}, >+ {0, kHex, /*width = */ 6, "_____0"}, >+ {0, kHex | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kUpper, /*width = */ 0, "0"}, >+ {0, kHex | kUpper, /*width = */ 6, "_____0"}, >+ {0, kHex | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kLeft, /*width = */ 0, "0"}, >+ {0, kHex | kLeft, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kPos, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kBase, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kUpper, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kUpper, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kUpper | kPos, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0_____"}, >+ {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0_____"}, >+ {0, kHex | kInt, /*width = */ 0, "0"}, >+ {0, kHex | kInt, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kUpper, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kUpper, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight, /*width = */ 0, "0"}, >+ {0, kHex | kRight, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kBase | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kUpper, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kUpper, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kUpper | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kUpper | kPos, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kUpper | kBase, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kUpper | kBase, /*width = */ 6, "_____0"}, >+ {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0"}, >+ {0, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "_____0"}, >+ {37, std::ios_base::fmtflags(), /*width = */ 0, "37"}, >+ {37, std::ios_base::fmtflags(), /*width = */ 6, "____37"}, >+ {37, kPos, /*width = */ 0, "37"}, >+ {37, kPos, /*width = */ 6, "____37"}, >+ {37, kBase, /*width = */ 0, "37"}, >+ {37, kBase, /*width = */ 6, "____37"}, >+ {37, kBase | kPos, /*width = */ 0, "37"}, >+ {37, kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kUpper, /*width = */ 0, "37"}, >+ {37, kUpper, /*width = */ 6, "____37"}, >+ {37, kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kLeft, /*width = */ 0, "37"}, >+ {37, kLeft, /*width = */ 6, "37____"}, >+ {37, kLeft | kPos, /*width = */ 0, "37"}, >+ {37, kLeft | kPos, /*width = */ 6, "37____"}, >+ {37, kLeft | kBase, /*width = */ 0, "37"}, >+ {37, kLeft | kBase, /*width = */ 6, "37____"}, >+ {37, kLeft | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kLeft | kBase | kPos, /*width = */ 6, "37____"}, >+ {37, kLeft | kUpper, /*width = */ 0, "37"}, >+ {37, kLeft | kUpper, /*width = */ 6, "37____"}, >+ {37, kLeft | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kLeft | kUpper | kPos, /*width = */ 6, "37____"}, >+ {37, kLeft | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kLeft | kUpper | kBase, /*width = */ 6, "37____"}, >+ {37, kLeft | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kLeft | kUpper | kBase | kPos, /*width = */ 6, "37____"}, >+ {37, kInt, /*width = */ 0, "37"}, >+ {37, kInt, /*width = */ 6, "____37"}, >+ {37, kInt | kPos, /*width = */ 0, "37"}, >+ {37, kInt | kPos, /*width = */ 6, "____37"}, >+ {37, kInt | kBase, /*width = */ 0, "37"}, >+ {37, kInt | kBase, /*width = */ 6, "____37"}, >+ {37, kInt | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kInt | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kInt | kUpper, /*width = */ 0, "37"}, >+ {37, kInt | kUpper, /*width = */ 6, "____37"}, >+ {37, kInt | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kInt | kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kInt | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kInt | kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kInt | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kInt | kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kRight, /*width = */ 0, "37"}, >+ {37, kRight, /*width = */ 6, "____37"}, >+ {37, kRight | kPos, /*width = */ 0, "37"}, >+ {37, kRight | kPos, /*width = */ 6, "____37"}, >+ {37, kRight | kBase, /*width = */ 0, "37"}, >+ {37, kRight | kBase, /*width = */ 6, "____37"}, >+ {37, kRight | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kRight | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kRight | kUpper, /*width = */ 0, "37"}, >+ {37, kRight | kUpper, /*width = */ 6, "____37"}, >+ {37, kRight | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kRight | kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kRight | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kRight | kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kRight | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kRight | kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec, /*width = */ 0, "37"}, >+ {37, kDec, /*width = */ 6, "____37"}, >+ {37, kDec | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kUpper, /*width = */ 0, "37"}, >+ {37, kDec | kUpper, /*width = */ 6, "____37"}, >+ {37, kDec | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kLeft, /*width = */ 0, "37"}, >+ {37, kDec | kLeft, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kPos, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kBase, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kBase | kPos, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kUpper, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kUpper, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kUpper | kPos, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kUpper | kBase, /*width = */ 6, "37____"}, >+ {37, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kLeft | kUpper | kBase | kPos, /*width = */ 6, "37____"}, >+ {37, kDec | kInt, /*width = */ 0, "37"}, >+ {37, kDec | kInt, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kUpper, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kUpper, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kInt | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kInt | kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kRight, /*width = */ 0, "37"}, >+ {37, kDec | kRight, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kUpper, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kUpper, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kUpper | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kUpper | kPos, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kUpper | kBase, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kUpper | kBase, /*width = */ 6, "____37"}, >+ {37, kDec | kRight | kUpper | kBase | kPos, /*width = */ 0, "37"}, >+ {37, kDec | kRight | kUpper | kBase | kPos, /*width = */ 6, "____37"}, >+ {37, kOct, /*width = */ 0, "45"}, >+ {37, kOct, /*width = */ 6, "____45"}, >+ {37, kOct | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kOct | kUpper, /*width = */ 0, "45"}, >+ {37, kOct | kUpper, /*width = */ 6, "____45"}, >+ {37, kOct | kUpper | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kUpper | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kUpper | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kUpper | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kUpper | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kUpper | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kOct | kLeft, /*width = */ 0, "45"}, >+ {37, kOct | kLeft, /*width = */ 6, "45____"}, >+ {37, kOct | kLeft | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kLeft | kPos, /*width = */ 6, "45____"}, >+ {37, kOct | kLeft | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kLeft | kBase, /*width = */ 6, "045___"}, >+ {37, kOct | kLeft | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kLeft | kBase | kPos, /*width = */ 6, "045___"}, >+ {37, kOct | kLeft | kUpper, /*width = */ 0, "45"}, >+ {37, kOct | kLeft | kUpper, /*width = */ 6, "45____"}, >+ {37, kOct | kLeft | kUpper | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kLeft | kUpper | kPos, /*width = */ 6, "45____"}, >+ {37, kOct | kLeft | kUpper | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kLeft | kUpper | kBase, /*width = */ 6, "045___"}, >+ {37, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kLeft | kUpper | kBase | kPos, /*width = */ 6, "045___"}, >+ {37, kOct | kInt, /*width = */ 0, "45"}, >+ {37, kOct | kInt, /*width = */ 6, "____45"}, >+ {37, kOct | kInt | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kInt | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kInt | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kInt | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kInt | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kInt | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kOct | kInt | kUpper, /*width = */ 0, "45"}, >+ {37, kOct | kInt | kUpper, /*width = */ 6, "____45"}, >+ {37, kOct | kInt | kUpper | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kInt | kUpper | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kInt | kUpper | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kInt | kUpper | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kInt | kUpper | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kInt | kUpper | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kOct | kRight, /*width = */ 0, "45"}, >+ {37, kOct | kRight, /*width = */ 6, "____45"}, >+ {37, kOct | kRight | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kRight | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kRight | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kRight | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kRight | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kRight | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kOct | kRight | kUpper, /*width = */ 0, "45"}, >+ {37, kOct | kRight | kUpper, /*width = */ 6, "____45"}, >+ {37, kOct | kRight | kUpper | kPos, /*width = */ 0, "45"}, >+ {37, kOct | kRight | kUpper | kPos, /*width = */ 6, "____45"}, >+ {37, kOct | kRight | kUpper | kBase, /*width = */ 0, "045"}, >+ {37, kOct | kRight | kUpper | kBase, /*width = */ 6, "___045"}, >+ {37, kOct | kRight | kUpper | kBase | kPos, /*width = */ 0, "045"}, >+ {37, kOct | kRight | kUpper | kBase | kPos, /*width = */ 6, "___045"}, >+ {37, kHex, /*width = */ 0, "25"}, >+ {37, kHex, /*width = */ 6, "____25"}, >+ {37, kHex | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kBase, /*width = */ 0, "0x25"}, >+ {37, kHex | kBase, /*width = */ 6, "__0x25"}, >+ {37, kHex | kBase | kPos, /*width = */ 0, "0x25"}, >+ {37, kHex | kBase | kPos, /*width = */ 6, "__0x25"}, >+ {37, kHex | kUpper, /*width = */ 0, "25"}, >+ {37, kHex | kUpper, /*width = */ 6, "____25"}, >+ {37, kHex | kUpper | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kUpper | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kUpper | kBase, /*width = */ 0, "0X25"}, >+ {37, kHex | kUpper | kBase, /*width = */ 6, "__0X25"}, >+ {37, kHex | kUpper | kBase | kPos, /*width = */ 0, "0X25"}, >+ {37, kHex | kUpper | kBase | kPos, /*width = */ 6, "__0X25"}, >+ {37, kHex | kLeft, /*width = */ 0, "25"}, >+ {37, kHex | kLeft, /*width = */ 6, "25____"}, >+ {37, kHex | kLeft | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kLeft | kPos, /*width = */ 6, "25____"}, >+ {37, kHex | kLeft | kBase, /*width = */ 0, "0x25"}, >+ {37, kHex | kLeft | kBase, /*width = */ 6, "0x25__"}, >+ {37, kHex | kLeft | kBase | kPos, /*width = */ 0, "0x25"}, >+ {37, kHex | kLeft | kBase | kPos, /*width = */ 6, "0x25__"}, >+ {37, kHex | kLeft | kUpper, /*width = */ 0, "25"}, >+ {37, kHex | kLeft | kUpper, /*width = */ 6, "25____"}, >+ {37, kHex | kLeft | kUpper | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kLeft | kUpper | kPos, /*width = */ 6, "25____"}, >+ {37, kHex | kLeft | kUpper | kBase, /*width = */ 0, "0X25"}, >+ {37, kHex | kLeft | kUpper | kBase, /*width = */ 6, "0X25__"}, >+ {37, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 0, "0X25"}, >+ {37, kHex | kLeft | kUpper | kBase | kPos, /*width = */ 6, "0X25__"}, >+ {37, kHex | kInt, /*width = */ 0, "25"}, >+ {37, kHex | kInt, /*width = */ 6, "____25"}, >+ {37, kHex | kInt | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kInt | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kInt | kBase, /*width = */ 0, "0x25"}, >+ {37, kHex | kInt | kBase, /*width = */ 6, "0x__25"}, >+ {37, kHex | kInt | kBase | kPos, /*width = */ 0, "0x25"}, >+ {37, kHex | kInt | kBase | kPos, /*width = */ 6, "0x__25"}, >+ {37, kHex | kInt | kUpper, /*width = */ 0, "25"}, >+ {37, kHex | kInt | kUpper, /*width = */ 6, "____25"}, >+ {37, kHex | kInt | kUpper | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kInt | kUpper | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kInt | kUpper | kBase, /*width = */ 0, "0X25"}, >+ {37, kHex | kInt | kUpper | kBase, /*width = */ 6, "0X__25"}, >+ {37, kHex | kInt | kUpper | kBase | kPos, /*width = */ 0, "0X25"}, >+ {37, kHex | kInt | kUpper | kBase | kPos, /*width = */ 6, "0X__25"}, >+ {37, kHex | kRight, /*width = */ 0, "25"}, >+ {37, kHex | kRight, /*width = */ 6, "____25"}, >+ {37, kHex | kRight | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kRight | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kRight | kBase, /*width = */ 0, "0x25"}, >+ {37, kHex | kRight | kBase, /*width = */ 6, "__0x25"}, >+ {37, kHex | kRight | kBase | kPos, /*width = */ 0, "0x25"}, >+ {37, kHex | kRight | kBase | kPos, /*width = */ 6, "__0x25"}, >+ {37, kHex | kRight | kUpper, /*width = */ 0, "25"}, >+ {37, kHex | kRight | kUpper, /*width = */ 6, "____25"}, >+ {37, kHex | kRight | kUpper | kPos, /*width = */ 0, "25"}, >+ {37, kHex | kRight | kUpper | kPos, /*width = */ 6, "____25"}, >+ {37, kHex | kRight | kUpper | kBase, /*width = */ 0, "0X25"}, >+ {37, kHex | kRight | kUpper | kBase, /*width = */ 6, "__0X25"}, >+ {37, kHex | kRight | kUpper | kBase | kPos, /*width = */ 0, "0X25"}, >+ {37, kHex | kRight | kUpper | kBase | kPos, /*width = */ 6, "__0X25"}}; >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_test.cc >new file mode 100644 >index 00000000000..1eb3e0ec896 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/numeric/int128_test.cc >@@ -0,0 +1,442 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/numeric/int128.h" >+ >+#include <algorithm> >+#include <limits> >+#include <random> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/cycleclock.h" >+#include "absl/meta/type_traits.h" >+ >+#if defined(_MSC_VER) && _MSC_VER == 1900 >+// Disable "unary minus operator applied to unsigned type" warnings in Microsoft >+// Visual C++ 14 (2015). >+#pragma warning(disable:4146) >+#endif >+ >+namespace { >+ >+template <typename T> >+class Uint128IntegerTraitsTest : public ::testing::Test {}; >+typedef ::testing::Types<bool, char, signed char, unsigned char, char16_t, >+ char32_t, wchar_t, >+ short, // NOLINT(runtime/int) >+ unsigned short, // NOLINT(runtime/int) >+ int, unsigned int, >+ long, // NOLINT(runtime/int) >+ unsigned long, // NOLINT(runtime/int) >+ long long, // NOLINT(runtime/int) >+ unsigned long long> // NOLINT(runtime/int) >+ IntegerTypes; >+ >+template <typename T> >+class Uint128FloatTraitsTest : public ::testing::Test {}; >+typedef ::testing::Types<float, double, long double> FloatingPointTypes; >+ >+TYPED_TEST_CASE(Uint128IntegerTraitsTest, IntegerTypes); >+ >+TYPED_TEST(Uint128IntegerTraitsTest, ConstructAssignTest) { >+ static_assert(std::is_constructible<absl::uint128, TypeParam>::value, >+ "absl::uint128 must be constructible from TypeParam"); >+ static_assert(std::is_assignable<absl::uint128&, TypeParam>::value, >+ "absl::uint128 must be assignable from TypeParam"); >+ static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value, >+ "TypeParam must not be assignable from absl::uint128"); >+} >+ >+TYPED_TEST_CASE(Uint128FloatTraitsTest, FloatingPointTypes); >+ >+TYPED_TEST(Uint128FloatTraitsTest, ConstructAssignTest) { >+ static_assert(std::is_constructible<absl::uint128, TypeParam>::value, >+ "absl::uint128 must be constructible from TypeParam"); >+ static_assert(!std::is_assignable<absl::uint128&, TypeParam>::value, >+ "absl::uint128 must not be assignable from TypeParam"); >+ static_assert(!std::is_assignable<TypeParam&, absl::uint128>::value, >+ "TypeParam must not be assignable from absl::uint128"); >+} >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+// These type traits done separately as TYPED_TEST requires typeinfo, and not >+// all platforms have this for __int128 even though they define the type. >+TEST(Uint128, IntrinsicTypeTraitsTest) { >+ static_assert(std::is_constructible<absl::uint128, __int128>::value, >+ "absl::uint128 must be constructible from __int128"); >+ static_assert(std::is_assignable<absl::uint128&, __int128>::value, >+ "absl::uint128 must be assignable from __int128"); >+ static_assert(!std::is_assignable<__int128&, absl::uint128>::value, >+ "__int128 must not be assignable from absl::uint128"); >+ >+ static_assert(std::is_constructible<absl::uint128, unsigned __int128>::value, >+ "absl::uint128 must be constructible from unsigned __int128"); >+ static_assert(std::is_assignable<absl::uint128&, unsigned __int128>::value, >+ "absl::uint128 must be assignable from unsigned __int128"); >+ static_assert(!std::is_assignable<unsigned __int128&, absl::uint128>::value, >+ "unsigned __int128 must not be assignable from absl::uint128"); >+} >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+TEST(Uint128, TrivialTraitsTest) { >+ static_assert(absl::is_trivially_default_constructible<absl::uint128>::value, >+ ""); >+ static_assert(absl::is_trivially_copy_constructible<absl::uint128>::value, >+ ""); >+ static_assert(absl::is_trivially_copy_assignable<absl::uint128>::value, ""); >+ static_assert(std::is_trivially_destructible<absl::uint128>::value, ""); >+} >+ >+TEST(Uint128, AllTests) { >+ absl::uint128 zero = 0; >+ absl::uint128 one = 1; >+ absl::uint128 one_2arg = absl::MakeUint128(0, 1); >+ absl::uint128 two = 2; >+ absl::uint128 three = 3; >+ absl::uint128 big = absl::MakeUint128(2000, 2); >+ absl::uint128 big_minus_one = absl::MakeUint128(2000, 1); >+ absl::uint128 bigger = absl::MakeUint128(2001, 1); >+ absl::uint128 biggest = absl::Uint128Max(); >+ absl::uint128 high_low = absl::MakeUint128(1, 0); >+ absl::uint128 low_high = >+ absl::MakeUint128(0, std::numeric_limits<uint64_t>::max()); >+ EXPECT_LT(one, two); >+ EXPECT_GT(two, one); >+ EXPECT_LT(one, big); >+ EXPECT_LT(one, big); >+ EXPECT_EQ(one, one_2arg); >+ EXPECT_NE(one, two); >+ EXPECT_GT(big, one); >+ EXPECT_GE(big, two); >+ EXPECT_GE(big, big_minus_one); >+ EXPECT_GT(big, big_minus_one); >+ EXPECT_LT(big_minus_one, big); >+ EXPECT_LE(big_minus_one, big); >+ EXPECT_NE(big_minus_one, big); >+ EXPECT_LT(big, biggest); >+ EXPECT_LE(big, biggest); >+ EXPECT_GT(biggest, big); >+ EXPECT_GE(biggest, big); >+ EXPECT_EQ(big, ~~big); >+ EXPECT_EQ(one, one | one); >+ EXPECT_EQ(big, big | big); >+ EXPECT_EQ(one, one | zero); >+ EXPECT_EQ(one, one & one); >+ EXPECT_EQ(big, big & big); >+ EXPECT_EQ(zero, one & zero); >+ EXPECT_EQ(zero, big & ~big); >+ EXPECT_EQ(zero, one ^ one); >+ EXPECT_EQ(zero, big ^ big); >+ EXPECT_EQ(one, one ^ zero); >+ >+ // Shift operators. >+ EXPECT_EQ(big, big << 0); >+ EXPECT_EQ(big, big >> 0); >+ EXPECT_GT(big << 1, big); >+ EXPECT_LT(big >> 1, big); >+ EXPECT_EQ(big, (big << 10) >> 10); >+ EXPECT_EQ(big, (big >> 1) << 1); >+ EXPECT_EQ(one, (one << 80) >> 80); >+ EXPECT_EQ(zero, (one >> 80) << 80); >+ >+ // Shift assignments. >+ absl::uint128 big_copy = big; >+ EXPECT_EQ(big << 0, big_copy <<= 0); >+ big_copy = big; >+ EXPECT_EQ(big >> 0, big_copy >>= 0); >+ big_copy = big; >+ EXPECT_EQ(big << 1, big_copy <<= 1); >+ big_copy = big; >+ EXPECT_EQ(big >> 1, big_copy >>= 1); >+ big_copy = big; >+ EXPECT_EQ(big << 10, big_copy <<= 10); >+ big_copy = big; >+ EXPECT_EQ(big >> 10, big_copy >>= 10); >+ big_copy = big; >+ EXPECT_EQ(big << 64, big_copy <<= 64); >+ big_copy = big; >+ EXPECT_EQ(big >> 64, big_copy >>= 64); >+ big_copy = big; >+ EXPECT_EQ(big << 73, big_copy <<= 73); >+ big_copy = big; >+ EXPECT_EQ(big >> 73, big_copy >>= 73); >+ >+ EXPECT_EQ(absl::Uint128High64(biggest), std::numeric_limits<uint64_t>::max()); >+ EXPECT_EQ(absl::Uint128Low64(biggest), std::numeric_limits<uint64_t>::max()); >+ EXPECT_EQ(zero + one, one); >+ EXPECT_EQ(one + one, two); >+ EXPECT_EQ(big_minus_one + one, big); >+ EXPECT_EQ(one - one, zero); >+ EXPECT_EQ(one - zero, one); >+ EXPECT_EQ(zero - one, biggest); >+ EXPECT_EQ(big - big, zero); >+ EXPECT_EQ(big - one, big_minus_one); >+ EXPECT_EQ(big + std::numeric_limits<uint64_t>::max(), bigger); >+ EXPECT_EQ(biggest + 1, zero); >+ EXPECT_EQ(zero - 1, biggest); >+ EXPECT_EQ(high_low - one, low_high); >+ EXPECT_EQ(low_high + one, high_low); >+ EXPECT_EQ(absl::Uint128High64((absl::uint128(1) << 64) - 1), 0); >+ EXPECT_EQ(absl::Uint128Low64((absl::uint128(1) << 64) - 1), >+ std::numeric_limits<uint64_t>::max()); >+ EXPECT_TRUE(!!one); >+ EXPECT_TRUE(!!high_low); >+ EXPECT_FALSE(!!zero); >+ EXPECT_FALSE(!one); >+ EXPECT_FALSE(!high_low); >+ EXPECT_TRUE(!zero); >+ EXPECT_TRUE(zero == 0); // NOLINT(readability/check) >+ EXPECT_FALSE(zero != 0); // NOLINT(readability/check) >+ EXPECT_FALSE(one == 0); // NOLINT(readability/check) >+ EXPECT_TRUE(one != 0); // NOLINT(readability/check) >+ EXPECT_FALSE(high_low == 0); // NOLINT(readability/check) >+ EXPECT_TRUE(high_low != 0); // NOLINT(readability/check) >+ >+ absl::uint128 test = zero; >+ EXPECT_EQ(++test, one); >+ EXPECT_EQ(test, one); >+ EXPECT_EQ(test++, one); >+ EXPECT_EQ(test, two); >+ EXPECT_EQ(test -= 2, zero); >+ EXPECT_EQ(test, zero); >+ EXPECT_EQ(test += 2, two); >+ EXPECT_EQ(test, two); >+ EXPECT_EQ(--test, one); >+ EXPECT_EQ(test, one); >+ EXPECT_EQ(test--, one); >+ EXPECT_EQ(test, zero); >+ EXPECT_EQ(test |= three, three); >+ EXPECT_EQ(test &= one, one); >+ EXPECT_EQ(test ^= three, two); >+ EXPECT_EQ(test >>= 1, one); >+ EXPECT_EQ(test <<= 1, two); >+ >+ EXPECT_EQ(big, -(-big)); >+ EXPECT_EQ(two, -((-one) - 1)); >+ EXPECT_EQ(absl::Uint128Max(), -one); >+ EXPECT_EQ(zero, -zero); >+ >+ EXPECT_EQ(absl::Uint128Max(), absl::kuint128max); >+} >+ >+TEST(Uint128, ConversionTests) { >+ EXPECT_TRUE(absl::MakeUint128(1, 0)); >+ >+#ifdef ABSL_HAVE_INTRINSIC_INT128 >+ unsigned __int128 intrinsic = >+ (static_cast<unsigned __int128>(0x3a5b76c209de76f6) << 64) + >+ 0x1f25e1d63a2b46c5; >+ absl::uint128 custom = >+ absl::MakeUint128(0x3a5b76c209de76f6, 0x1f25e1d63a2b46c5); >+ >+ EXPECT_EQ(custom, absl::uint128(intrinsic)); >+ EXPECT_EQ(custom, absl::uint128(static_cast<__int128>(intrinsic))); >+ EXPECT_EQ(intrinsic, static_cast<unsigned __int128>(custom)); >+ EXPECT_EQ(intrinsic, static_cast<__int128>(custom)); >+#endif // ABSL_HAVE_INTRINSIC_INT128 >+ >+ // verify that an integer greater than 2**64 that can be stored precisely >+ // inside a double is converted to a absl::uint128 without loss of >+ // information. >+ double precise_double = 0x530e * std::pow(2.0, 64.0) + 0xda74000000000000; >+ absl::uint128 from_precise_double(precise_double); >+ absl::uint128 from_precise_ints = >+ absl::MakeUint128(0x530e, 0xda74000000000000); >+ EXPECT_EQ(from_precise_double, from_precise_ints); >+ EXPECT_DOUBLE_EQ(static_cast<double>(from_precise_ints), precise_double); >+ >+ double approx_double = 0xffffeeeeddddcccc * std::pow(2.0, 64.0) + >+ 0xbbbbaaaa99998888; >+ absl::uint128 from_approx_double(approx_double); >+ EXPECT_DOUBLE_EQ(static_cast<double>(from_approx_double), approx_double); >+ >+ double round_to_zero = 0.7; >+ double round_to_five = 5.8; >+ double round_to_nine = 9.3; >+ EXPECT_EQ(static_cast<absl::uint128>(round_to_zero), 0); >+ EXPECT_EQ(static_cast<absl::uint128>(round_to_five), 5); >+ EXPECT_EQ(static_cast<absl::uint128>(round_to_nine), 9); >+} >+ >+TEST(Uint128, OperatorAssignReturnRef) { >+ absl::uint128 v(1); >+ (v += 4) -= 3; >+ EXPECT_EQ(2, v); >+} >+ >+TEST(Uint128, Multiply) { >+ absl::uint128 a, b, c; >+ >+ // Zero test. >+ a = 0; >+ b = 0; >+ c = a * b; >+ EXPECT_EQ(0, c); >+ >+ // Max carries. >+ a = absl::uint128(0) - 1; >+ b = absl::uint128(0) - 1; >+ c = a * b; >+ EXPECT_EQ(1, c); >+ >+ // Self-operation with max carries. >+ c = absl::uint128(0) - 1; >+ c *= c; >+ EXPECT_EQ(1, c); >+ >+ // 1-bit x 1-bit. >+ for (int i = 0; i < 64; ++i) { >+ for (int j = 0; j < 64; ++j) { >+ a = absl::uint128(1) << i; >+ b = absl::uint128(1) << j; >+ c = a * b; >+ EXPECT_EQ(absl::uint128(1) << (i + j), c); >+ } >+ } >+ >+ // Verified with dc. >+ a = absl::MakeUint128(0xffffeeeeddddcccc, 0xbbbbaaaa99998888); >+ b = absl::MakeUint128(0x7777666655554444, 0x3333222211110000); >+ c = a * b; >+ EXPECT_EQ(absl::MakeUint128(0x530EDA741C71D4C3, 0xBF25975319080000), c); >+ EXPECT_EQ(0, c - b * a); >+ EXPECT_EQ(a*a - b*b, (a+b) * (a-b)); >+ >+ // Verified with dc. >+ a = absl::MakeUint128(0x0123456789abcdef, 0xfedcba9876543210); >+ b = absl::MakeUint128(0x02468ace13579bdf, 0xfdb97531eca86420); >+ c = a * b; >+ EXPECT_EQ(absl::MakeUint128(0x97a87f4f261ba3f2, 0x342d0bbf48948200), c); >+ EXPECT_EQ(0, c - b * a); >+ EXPECT_EQ(a*a - b*b, (a+b) * (a-b)); >+} >+ >+TEST(Uint128, AliasTests) { >+ absl::uint128 x1 = absl::MakeUint128(1, 2); >+ absl::uint128 x2 = absl::MakeUint128(2, 4); >+ x1 += x1; >+ EXPECT_EQ(x2, x1); >+ >+ absl::uint128 x3 = absl::MakeUint128(1, static_cast<uint64_t>(1) << 63); >+ absl::uint128 x4 = absl::MakeUint128(3, 0); >+ x3 += x3; >+ EXPECT_EQ(x4, x3); >+} >+ >+TEST(Uint128, DivideAndMod) { >+ using std::swap; >+ >+ // a := q * b + r >+ absl::uint128 a, b, q, r; >+ >+ // Zero test. >+ a = 0; >+ b = 123; >+ q = a / b; >+ r = a % b; >+ EXPECT_EQ(0, q); >+ EXPECT_EQ(0, r); >+ >+ a = absl::MakeUint128(0x530eda741c71d4c3, 0xbf25975319080000); >+ q = absl::MakeUint128(0x4de2cab081, 0x14c34ab4676e4bab); >+ b = absl::uint128(0x1110001); >+ r = absl::uint128(0x3eb455); >+ ASSERT_EQ(a, q * b + r); // Sanity-check. >+ >+ absl::uint128 result_q, result_r; >+ result_q = a / b; >+ result_r = a % b; >+ EXPECT_EQ(q, result_q); >+ EXPECT_EQ(r, result_r); >+ >+ // Try the other way around. >+ swap(q, b); >+ result_q = a / b; >+ result_r = a % b; >+ EXPECT_EQ(q, result_q); >+ EXPECT_EQ(r, result_r); >+ // Restore. >+ swap(b, q); >+ >+ // Dividend < divisor; result should be q:0 r:<dividend>. >+ swap(a, b); >+ result_q = a / b; >+ result_r = a % b; >+ EXPECT_EQ(0, result_q); >+ EXPECT_EQ(a, result_r); >+ // Try the other way around. >+ swap(a, q); >+ result_q = a / b; >+ result_r = a % b; >+ EXPECT_EQ(0, result_q); >+ EXPECT_EQ(a, result_r); >+ // Restore. >+ swap(q, a); >+ swap(b, a); >+ >+ // Try a large remainder. >+ b = a / 2 + 1; >+ absl::uint128 expected_r = >+ absl::MakeUint128(0x29876d3a0e38ea61, 0xdf92cba98c83ffff); >+ // Sanity checks. >+ ASSERT_EQ(a / 2 - 1, expected_r); >+ ASSERT_EQ(a, b + expected_r); >+ result_q = a / b; >+ result_r = a % b; >+ EXPECT_EQ(1, result_q); >+ EXPECT_EQ(expected_r, result_r); >+} >+ >+TEST(Uint128, DivideAndModRandomInputs) { >+ const int kNumIters = 1 << 18; >+ std::minstd_rand random(testing::UnitTest::GetInstance()->random_seed()); >+ std::uniform_int_distribution<uint64_t> uniform_uint64; >+ for (int i = 0; i < kNumIters; ++i) { >+ const absl::uint128 a = >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)); >+ const absl::uint128 b = >+ absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)); >+ if (b == 0) { >+ continue; // Avoid a div-by-zero. >+ } >+ const absl::uint128 q = a / b; >+ const absl::uint128 r = a % b; >+ ASSERT_EQ(a, b * q + r); >+ } >+} >+ >+TEST(Uint128, ConstexprTest) { >+ constexpr absl::uint128 zero = absl::uint128(); >+ constexpr absl::uint128 one = 1; >+ constexpr absl::uint128 minus_two = -2; >+ EXPECT_EQ(zero, absl::uint128(0)); >+ EXPECT_EQ(one, absl::uint128(1)); >+ EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2)); >+} >+ >+TEST(Uint128, NumericLimitsTest) { >+ static_assert(std::numeric_limits<absl::uint128>::is_specialized, ""); >+ static_assert(!std::numeric_limits<absl::uint128>::is_signed, ""); >+ static_assert(std::numeric_limits<absl::uint128>::is_integer, ""); >+ EXPECT_EQ(static_cast<int>(128 * std::log10(2)), >+ std::numeric_limits<absl::uint128>::digits10); >+ EXPECT_EQ(0, std::numeric_limits<absl::uint128>::min()); >+ EXPECT_EQ(0, std::numeric_limits<absl::uint128>::lowest()); >+ EXPECT_EQ(absl::Uint128Max(), std::numeric_limits<absl::uint128>::max()); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.bazel >new file mode 100644 >index 00000000000..3a5f1332cda >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.bazel >@@ -0,0 +1,661 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+ "ABSL_EXCEPTIONS_FLAG", >+) >+ >+package( >+ default_visibility = ["//visibility:public"], >+ features = ["parse_headers"], >+) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "strings", >+ srcs = [ >+ "ascii.cc", >+ "charconv.cc", >+ "escaping.cc", >+ "internal/charconv_bigint.cc", >+ "internal/charconv_bigint.h", >+ "internal/charconv_parse.cc", >+ "internal/charconv_parse.h", >+ "internal/memutil.cc", >+ "internal/memutil.h", >+ "internal/stl_type_traits.h", >+ "internal/str_join_internal.h", >+ "internal/str_split_internal.h", >+ "match.cc", >+ "numbers.cc", >+ "str_cat.cc", >+ "str_replace.cc", >+ "str_split.cc", >+ "string_view.cc", >+ "substitute.cc", >+ ], >+ hdrs = [ >+ "ascii.h", >+ "charconv.h", >+ "escaping.h", >+ "match.h", >+ "numbers.h", >+ "str_cat.h", >+ "str_join.h", >+ "str_replace.h", >+ "str_split.h", >+ "string_view.h", >+ "strip.h", >+ "substitute.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":internal", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/base:endian", >+ "//absl/base:throw_delegate", >+ "//absl/memory", >+ "//absl/meta:type_traits", >+ "//absl/numeric:int128", >+ ], >+) >+ >+cc_library( >+ name = "internal", >+ srcs = [ >+ "internal/ostringstream.cc", >+ "internal/utf8.cc", >+ ], >+ hdrs = [ >+ "internal/bits.h", >+ "internal/char_map.h", >+ "internal/ostringstream.h", >+ "internal/resize_uninitialized.h", >+ "internal/utf8.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base:core_headers", >+ "//absl/base:endian", >+ "//absl/meta:type_traits", >+ ], >+) >+ >+cc_test( >+ name = "match_test", >+ size = "small", >+ srcs = ["match_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "escaping_test", >+ size = "small", >+ srcs = [ >+ "escaping_test.cc", >+ "internal/escaping_test_common.h", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "//absl/container:fixed_array", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "escaping_benchmark", >+ srcs = [ >+ "escaping_benchmark.cc", >+ "internal/escaping_test_common.h", >+ ], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "ascii_test", >+ size = "small", >+ srcs = ["ascii_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "ascii_benchmark", >+ srcs = ["ascii_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "memutil_benchmark", >+ srcs = [ >+ "internal/memutil.h", >+ "internal/memutil_benchmark.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "memutil_test", >+ size = "small", >+ srcs = [ >+ "internal/memutil.h", >+ "internal/memutil_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "utf8_test", >+ size = "small", >+ srcs = [ >+ "internal/utf8_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":internal", >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "string_view_benchmark", >+ srcs = ["string_view_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "string_view_test", >+ size = "small", >+ srcs = ["string_view_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/base:dynamic_annotations", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "substitute_test", >+ size = "small", >+ srcs = ["substitute_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_replace_benchmark", >+ srcs = ["str_replace_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "str_replace_test", >+ size = "small", >+ srcs = ["str_replace_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_split_test", >+ srcs = ["str_split_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "//absl/base:dynamic_annotations", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_split_benchmark", >+ srcs = ["str_split_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "ostringstream_test", >+ size = "small", >+ srcs = ["internal/ostringstream_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "ostringstream_benchmark", >+ srcs = ["internal/ostringstream_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":internal", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "resize_uninitialized_test", >+ size = "small", >+ srcs = [ >+ "internal/resize_uninitialized.h", >+ "internal/resize_uninitialized_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_join_test", >+ size = "small", >+ srcs = ["str_join_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_join_benchmark", >+ srcs = ["str_join_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/memory", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "str_cat_test", >+ size = "small", >+ srcs = ["str_cat_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_cat_benchmark", >+ srcs = ["str_cat_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "numbers_test", >+ size = "small", >+ srcs = [ >+ "internal/numbers_test_common.h", >+ "numbers_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "numbers_benchmark", >+ srcs = ["numbers_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "strip_test", >+ size = "small", >+ srcs = ["strip_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "char_map_test", >+ srcs = ["internal/char_map_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "char_map_benchmark", >+ srcs = ["internal/char_map_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ deps = [ >+ ":internal", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "charconv_test", >+ srcs = ["charconv_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "charconv_parse_test", >+ srcs = [ >+ "internal/charconv_parse.h", >+ "internal/charconv_parse_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "charconv_bigint_test", >+ srcs = [ >+ "internal/charconv_bigint.h", >+ "internal/charconv_bigint_test.cc", >+ "internal/charconv_parse.h", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "charconv_benchmark", >+ srcs = [ >+ "charconv_benchmark.cc", >+ ], >+ tags = [ >+ "benchmark", >+ ], >+ deps = [ >+ ":strings", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_library( >+ name = "str_format", >+ hdrs = [ >+ "str_format.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":str_format_internal", >+ ], >+) >+ >+cc_library( >+ name = "str_format_internal", >+ srcs = [ >+ "internal/str_format/arg.cc", >+ "internal/str_format/bind.cc", >+ "internal/str_format/extension.cc", >+ "internal/str_format/float_conversion.cc", >+ "internal/str_format/output.cc", >+ "internal/str_format/parser.cc", >+ ], >+ hdrs = [ >+ "internal/str_format/arg.h", >+ "internal/str_format/bind.h", >+ "internal/str_format/checker.h", >+ "internal/str_format/extension.h", >+ "internal/str_format/float_conversion.h", >+ "internal/str_format/output.h", >+ "internal/str_format/parser.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":strings", >+ "//absl/base:core_headers", >+ "//absl/container:inlined_vector", >+ "//absl/meta:type_traits", >+ "//absl/numeric:int128", >+ "//absl/types:span", >+ ], >+) >+ >+cc_test( >+ name = "str_format_test", >+ srcs = ["str_format_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format", >+ ":strings", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_extension_test", >+ srcs = [ >+ "internal/str_format/extension_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format", >+ ":str_format_internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_arg_test", >+ srcs = ["internal/str_format/arg_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format", >+ ":str_format_internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_bind_test", >+ srcs = ["internal/str_format/bind_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format_internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_checker_test", >+ srcs = ["internal/str_format/checker_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_convert_test", >+ size = "small", >+ srcs = ["internal/str_format/convert_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format_internal", >+ "//absl/numeric:int128", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_output_test", >+ srcs = ["internal/str_format/output_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format_internal", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "str_format_parser_test", >+ srcs = ["internal/str_format/parser_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":str_format_internal", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.gn >new file mode 100644 >index 00000000000..9a8a10d0e71 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/BUILD.gn >@@ -0,0 +1,146 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("strings") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "ascii.cc", >+ "charconv.cc", >+ "escaping.cc", >+ "internal/charconv_bigint.cc", >+ "internal/charconv_bigint.h", >+ "internal/charconv_parse.cc", >+ "internal/charconv_parse.h", >+ "internal/memutil.cc", >+ "internal/memutil.h", >+ "internal/stl_type_traits.h", >+ "internal/str_join_internal.h", >+ "internal/str_split_internal.h", >+ "match.cc", >+ "numbers.cc", >+ "str_cat.cc", >+ "str_replace.cc", >+ "str_split.cc", >+ "string_view.cc", >+ "substitute.cc", >+ ] >+ public = [ >+ "ascii.h", >+ "charconv.h", >+ "escaping.h", >+ "match.h", >+ "numbers.h", >+ "str_cat.h", >+ "str_join.h", >+ "str_replace.h", >+ "str_split.h", >+ "string_view.h", >+ "strip.h", >+ "substitute.h", >+ ] >+ deps = [ >+ ":internal", >+ "../base", >+ "../base:config", >+ "../base:core_headers", >+ "../base:endian", >+ "../base:throw_delegate", >+ "../memory", >+ "../meta:type_traits", >+ "../numeric:int128", >+ ] >+} >+ >+source_set("internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/ostringstream.cc", >+ "internal/utf8.cc", >+ ] >+ public = [ >+ "internal/bits.h", >+ "internal/char_map.h", >+ "internal/ostringstream.h", >+ "internal/resize_uninitialized.h", >+ "internal/utf8.h", >+ ] >+ deps = [ >+ "../base:core_headers", >+ "../base:endian", >+ "../meta:type_traits", >+ ] >+} >+ >+source_set("str_format") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "str_format.h", >+ ] >+ deps = [ >+ ":str_format_internal", >+ ] >+} >+ >+source_set("str_format_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/str_format/arg.cc", >+ "internal/str_format/bind.cc", >+ "internal/str_format/extension.cc", >+ "internal/str_format/float_conversion.cc", >+ "internal/str_format/output.cc", >+ "internal/str_format/parser.cc", >+ ] >+ public = [ >+ "internal/str_format/arg.h", >+ "internal/str_format/bind.h", >+ "internal/str_format/checker.h", >+ "internal/str_format/extension.h", >+ "internal/str_format/float_conversion.h", >+ "internal/str_format/output.h", >+ "internal/str_format/parser.h", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+ deps = [ >+ ":strings", >+ "../base:core_headers", >+ "../container:inlined_vector", >+ "../meta:type_traits", >+ "../numeric:int128", >+ "../types:span", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/CMakeLists.txt >new file mode 100644 >index 00000000000..cd122134729 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/CMakeLists.txt >@@ -0,0 +1,464 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+ >+list(APPEND STRINGS_PUBLIC_HEADERS >+ "ascii.h" >+ "charconv.h" >+ "escaping.h" >+ "match.h" >+ "numbers.h" >+ "str_cat.h" >+ "string_view.h" >+ "strip.h" >+ "str_join.h" >+ "str_replace.h" >+ "str_split.h" >+ "substitute.h" >+) >+ >+ >+list(APPEND STRINGS_INTERNAL_HEADERS >+ "internal/bits.h" >+ "internal/char_map.h" >+ "internal/charconv_bigint.h" >+ "internal/charconv_parse.h" >+ "internal/memutil.h" >+ "internal/ostringstream.h" >+ "internal/resize_uninitialized.h" >+ "internal/stl_type_traits.h" >+ "internal/str_join_internal.h" >+ "internal/str_split_internal.h" >+ "internal/utf8.h" >+) >+ >+ >+ >+# add string library >+list(APPEND STRINGS_SRC >+ "ascii.cc" >+ "charconv.cc" >+ "escaping.cc" >+ "internal/charconv_bigint.cc" >+ "internal/charconv_parse.cc" >+ "internal/memutil.cc" >+ "internal/memutil.h" >+ "internal/utf8.cc" >+ "internal/ostringstream.cc" >+ "match.cc" >+ "numbers.cc" >+ "str_cat.cc" >+ "str_replace.cc" >+ "str_split.cc" >+ "string_view.cc" >+ "substitute.cc" >+ ${STRINGS_PUBLIC_HEADERS} >+ ${STRINGS_INTERNAL_HEADERS} >+) >+set(STRINGS_PUBLIC_LIBRARIES absl::base absl_throw_delegate) >+ >+absl_library( >+ TARGET >+ absl_strings >+ SOURCES >+ ${STRINGS_SRC} >+ PUBLIC_LIBRARIES >+ ${STRINGS_PUBLIC_LIBRARIES} >+ EXPORT_NAME >+ strings >+) >+ >+# add str_format library >+absl_header_library( >+ TARGET >+ absl_str_format >+ PUBLIC_LIBRARIES >+ str_format_internal >+ EXPORT_NAME >+ str_format >+) >+ >+# str_format_internal >+absl_library( >+ TARGET >+ str_format_internal >+ SOURCES >+ "internal/str_format/arg.cc" >+ "internal/str_format/bind.cc" >+ "internal/str_format/extension.cc" >+ "internal/str_format/float_conversion.cc" >+ "internal/str_format/output.cc" >+ "internal/str_format/parser.cc" >+ "internal/str_format/arg.h" >+ "internal/str_format/bind.h" >+ "internal/str_format/checker.h" >+ "internal/str_format/extension.h" >+ "internal/str_format/float_conversion.h" >+ "internal/str_format/output.h" >+ "internal/str_format/parser.h" >+ PUBLIC_LIBRARIES >+ str_format_extension_internal >+ absl::strings >+ absl::base >+ absl::numeric >+ absl::container >+ absl::span >+) >+ >+# str_format_extension_internal >+absl_library( >+ TARGET >+ str_format_extension_internal >+ SOURCES >+ "internal/str_format/extension.cc" >+ "internal/str_format/extension.h" >+ "internal/str_format/output.cc" >+ "internal/str_format/output.h" >+ PUBLIC_LIBRARIES >+ absl::base >+ absl::strings >+) >+ >+# >+## TESTS >+# >+ >+# test match_test >+set(MATCH_TEST_SRC "match_test.cc") >+set(MATCH_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ match_test >+ SOURCES >+ ${MATCH_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${MATCH_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test escaping_test >+set(ESCAPING_TEST_SRC "escaping_test.cc") >+set(ESCAPING_TEST_PUBLIC_LIBRARIES absl::strings absl::base) >+ >+absl_test( >+ TARGET >+ escaping_test >+ SOURCES >+ ${ESCAPING_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ESCAPING_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test ascii_test >+set(ASCII_TEST_SRC "ascii_test.cc") >+set(ASCII_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ ascii_test >+ SOURCES >+ ${ASCII_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ASCII_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test memutil_test >+set(MEMUTIL_TEST_SRC "internal/memutil_test.cc") >+set(MEMUTIL_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ memutil_test >+ SOURCES >+ ${MEMUTIL_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${MEMUTIL_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test utf8_test >+set(UTF8_TEST_SRC "internal/utf8_test.cc") >+set(UTF8_TEST_PUBLIC_LIBRARIES absl::strings absl::base) >+ >+absl_test( >+ TARGET >+ utf8_test >+ SOURCES >+ ${UTF8_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${UTF8_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test string_view_test >+set(STRING_VIEW_TEST_SRC "string_view_test.cc") >+set(STRING_VIEW_TEST_PUBLIC_LIBRARIES absl::strings absl_throw_delegate absl::base) >+ >+absl_test( >+ TARGET >+ string_view_test >+ SOURCES >+ ${STRING_VIEW_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STRING_VIEW_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test substitute_test >+set(SUBSTITUTE_TEST_SRC "substitute_test.cc") >+set(SUBSTITUTE_TEST_PUBLIC_LIBRARIES absl::strings absl::base) >+ >+absl_test( >+ TARGET >+ substitute_test >+ SOURCES >+ ${SUBSTITUTE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${SUBSTITUTE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test str_replace_test >+set(STR_REPLACE_TEST_SRC "str_replace_test.cc") >+set(STR_REPLACE_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate) >+ >+absl_test( >+ TARGET >+ str_replace_test >+ SOURCES >+ ${STR_REPLACE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STR_REPLACE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test str_split_test >+set(STR_SPLIT_TEST_SRC "str_split_test.cc") >+set(STR_SPLIT_TEST_PUBLIC_LIBRARIES absl::strings absl::base absl_throw_delegate) >+ >+absl_test( >+ TARGET >+ str_split_test >+ SOURCES >+ ${STR_SPLIT_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STR_SPLIT_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test ostringstream_test >+set(OSTRINGSTREAM_TEST_SRC "internal/ostringstream_test.cc") >+set(OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ ostringstream_test >+ SOURCES >+ ${OSTRINGSTREAM_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${OSTRINGSTREAM_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test resize_uninitialized_test >+set(RESIZE_UNINITIALIZED_TEST_SRC "internal/resize_uninitialized_test.cc") >+ >+absl_test( >+ TARGET >+ resize_uninitialized_test >+ SOURCES >+ ${RESIZE_UNINITIALIZED_TEST_SRC} >+) >+ >+ >+# test str_join_test >+set(STR_JOIN_TEST_SRC "str_join_test.cc") >+set(STR_JOIN_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ str_join_test >+ SOURCES >+ ${STR_JOIN_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STR_JOIN_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test str_cat_test >+set(STR_CAT_TEST_SRC "str_cat_test.cc") >+set(STR_CAT_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ str_cat_test >+ SOURCES >+ ${STR_CAT_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STR_CAT_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test numbers_test >+set(NUMBERS_TEST_SRC "numbers_test.cc") >+set(NUMBERS_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ numbers_test >+ SOURCES >+ ${NUMBERS_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${NUMBERS_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test strip_test >+set(STRIP_TEST_SRC "strip_test.cc") >+set(STRIP_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ strip_test >+ SOURCES >+ ${STRIP_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${STRIP_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test char_map_test >+set(CHAR_MAP_TEST_SRC "internal/char_map_test.cc") >+set(CHAR_MAP_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ char_map_test >+ SOURCES >+ ${CHAR_MAP_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CHAR_MAP_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test charconv_test >+set(CHARCONV_TEST_SRC "charconv_test.cc") >+set(CHARCONV_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ charconv_test >+ SOURCES >+ ${CHARCONV_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CHARCONV_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test charconv_parse_test >+set(CHARCONV_PARSE_TEST_SRC "internal/charconv_parse_test.cc") >+set(CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ charconv_parse_test >+ SOURCES >+ ${CHARCONV_PARSE_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CHARCONV_PARSE_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test charconv_bigint_test >+set(CHARCONV_BIGINT_TEST_SRC "internal/charconv_bigint_test.cc") >+set(CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES absl::strings) >+ >+absl_test( >+ TARGET >+ charconv_bigint_test >+ SOURCES >+ ${CHARCONV_BIGINT_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${CHARCONV_BIGINT_TEST_PUBLIC_LIBRARIES} >+) >+# test str_format_test >+absl_test( >+ TARGET >+ str_format_test >+ SOURCES >+ "str_format_test.cc" >+ PUBLIC_LIBRARIES >+ absl::base >+ absl::str_format >+ absl::strings >+) >+ >+# test str_format_bind_test >+absl_test( >+ TARGET >+ str_format_bind_test >+ SOURCES >+ "internal/str_format/bind_test.cc" >+ PUBLIC_LIBRARIES >+ str_format_internal >+) >+ >+# test str_format_checker_test >+absl_test( >+ TARGET >+ str_format_checker_test >+ SOURCES >+ "internal/str_format/checker_test.cc" >+ PUBLIC_LIBRARIES >+ absl::str_format >+) >+ >+# test str_format_convert_test >+absl_test( >+ TARGET >+ str_format_convert_test >+ SOURCES >+ "internal/str_format/convert_test.cc" >+ PUBLIC_LIBRARIES >+ str_format_internal >+ absl::numeric >+) >+ >+# test str_format_output_test >+absl_test( >+ TARGET >+ str_format_output_test >+ SOURCES >+ "internal/str_format/output_test.cc" >+ PUBLIC_LIBRARIES >+ str_format_extension_internal >+) >+ >+# test str_format_parser_test >+absl_test( >+ TARGET >+ str_format_parser_test >+ SOURCES >+ "internal/str_format/parser_test.cc" >+ PUBLIC_LIBRARIES >+ str_format_internal >+ absl::base >+) >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.cc >new file mode 100644 >index 00000000000..c9481e88654 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.cc >@@ -0,0 +1,198 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/ascii.h" >+ >+namespace absl { >+namespace ascii_internal { >+ >+// # Table generated by this Python code (bit 0x02 is currently unused): >+// TODO(mbar) Move Python code for generation of table to BUILD and link here. >+ >+// NOTE: The kAsciiPropertyBits table used within this code was generated by >+// Python code of the following form. (Bit 0x02 is currently unused and >+// available.) >+// >+// def Hex2(n): >+// return '0x' + hex(n/16)[2:] + hex(n%16)[2:] >+// def IsPunct(ch): >+// return (ord(ch) >= 32 and ord(ch) < 127 and >+// not ch.isspace() and not ch.isalnum()) >+// def IsBlank(ch): >+// return ch in ' \t' >+// def IsCntrl(ch): >+// return ord(ch) < 32 or ord(ch) == 127 >+// def IsXDigit(ch): >+// return ch.isdigit() or ch.lower() in 'abcdef' >+// for i in range(128): >+// ch = chr(i) >+// mask = ((ch.isalpha() and 0x01 or 0) | >+// (ch.isalnum() and 0x04 or 0) | >+// (ch.isspace() and 0x08 or 0) | >+// (IsPunct(ch) and 0x10 or 0) | >+// (IsBlank(ch) and 0x20 or 0) | >+// (IsCntrl(ch) and 0x40 or 0) | >+// (IsXDigit(ch) and 0x80 or 0)) >+// print Hex2(mask) + ',', >+// if i % 16 == 7: >+// print ' //', Hex2(i & 0x78) >+// elif i % 16 == 15: >+// print >+ >+// clang-format off >+// Array of bitfields holding character information. Each bit value corresponds >+// to a particular character feature. For readability, and because the value >+// of these bits is tightly coupled to this implementation, the individual bits >+// are not named. Note that bitfields for all characters above ASCII 127 are >+// zero-initialized. >+const unsigned char kPropertyBits[256] = { >+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x00 >+ 0x40, 0x68, 0x48, 0x48, 0x48, 0x48, 0x40, 0x40, >+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0x10 >+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, >+ 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // 0x20 >+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, >+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, // 0x30 >+ 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, >+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x40 >+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, >+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x50 >+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x10, >+ 0x10, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x05, // 0x60 >+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, >+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, // 0x70 >+ 0x05, 0x05, 0x05, 0x10, 0x10, 0x10, 0x10, 0x40, >+}; >+ >+// Array of characters for the ascii_tolower() function. For values 'A' >+// through 'Z', return the lower-case character; otherwise, return the >+// identity of the passed character. >+const char kToLower[256] = { >+ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', >+ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', >+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', >+ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', >+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', >+ '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', >+ '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', >+ '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', >+ '\x40', 'a', 'b', 'c', 'd', 'e', 'f', 'g', >+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', >+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', >+ 'x', 'y', 'z', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', >+ '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', >+ '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', >+ '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', >+ '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', >+ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', >+ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', >+ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', >+ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', >+ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', >+ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', >+ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', >+ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', >+ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', >+ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', >+ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', >+ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', >+ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', >+ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', >+ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', >+ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', >+}; >+ >+// Array of characters for the ascii_toupper() function. For values 'a' >+// through 'z', return the upper-case character; otherwise, return the >+// identity of the passed character. >+const char kToUpper[256] = { >+ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', >+ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', >+ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', >+ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', >+ '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', >+ '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f', >+ '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37', >+ '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', >+ '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', >+ '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', >+ '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', >+ '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', >+ '\x60', 'A', 'B', 'C', 'D', 'E', 'F', 'G', >+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', >+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', >+ 'X', 'Y', 'Z', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f', >+ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', >+ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', >+ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', >+ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', >+ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', >+ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf', >+ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7', >+ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf', >+ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7', >+ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', >+ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', >+ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', >+ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', >+ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef', >+ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7', >+ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff', >+}; >+// clang-format on >+ >+} // namespace ascii_internal >+ >+void AsciiStrToLower(std::string* s) { >+ for (auto& ch : *s) { >+ ch = absl::ascii_tolower(ch); >+ } >+} >+ >+void AsciiStrToUpper(std::string* s) { >+ for (auto& ch : *s) { >+ ch = absl::ascii_toupper(ch); >+ } >+} >+ >+void RemoveExtraAsciiWhitespace(std::string* str) { >+ auto stripped = StripAsciiWhitespace(*str); >+ >+ if (stripped.empty()) { >+ str->clear(); >+ return; >+ } >+ >+ auto input_it = stripped.begin(); >+ auto input_end = stripped.end(); >+ auto output_it = &(*str)[0]; >+ bool is_ws = false; >+ >+ for (; input_it < input_end; ++input_it) { >+ if (is_ws) { >+ // Consecutive whitespace? Keep only the last. >+ is_ws = absl::ascii_isspace(*input_it); >+ if (is_ws) --output_it; >+ } else { >+ is_ws = absl::ascii_isspace(*input_it); >+ } >+ >+ *output_it = *input_it; >+ ++output_it; >+ } >+ >+ str->erase(output_it - &(*str)[0]); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.h >new file mode 100644 >index 00000000000..96a64541c32 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii.h >@@ -0,0 +1,239 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: ascii.h >+// ----------------------------------------------------------------------------- >+// >+// This package contains functions operating on characters and strings >+// restricted to standard ASCII. These include character classification >+// functions analogous to those found in the ANSI C Standard Library <ctype.h> >+// header file. >+// >+// C++ implementations provide <ctype.h> functionality based on their >+// C environment locale. In general, reliance on such a locale is not ideal, as >+// the locale standard is problematic (and may not return invariant information >+// for the same character set, for example). These `ascii_*()` functions are >+// hard-wired for standard ASCII, much faster, and guaranteed to behave >+// consistently. They will never be overloaded, nor will their function >+// signature change. >+// >+// `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`, >+// `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`, >+// `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`, >+// `ascii_isxdigit()` >+// Analogous to the <ctype.h> functions with similar names, these >+// functions take an unsigned char and return a bool, based on whether the >+// character matches the condition specified. >+// >+// If the input character has a numerical value greater than 127, these >+// functions return `false`. >+// >+// `ascii_tolower()`, `ascii_toupper()` >+// Analogous to the <ctype.h> functions with similar names, these functions >+// take an unsigned char and return a char. >+// >+// If the input character is not an ASCII {lower,upper}-case letter (including >+// numerical values greater than 127) then the functions return the same value >+// as the input character. >+ >+#ifndef ABSL_STRINGS_ASCII_H_ >+#define ABSL_STRINGS_ASCII_H_ >+ >+#include <algorithm> >+#include <string> >+ >+#include "absl/base/attributes.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace ascii_internal { >+ >+// Declaration for an array of bitfields holding character information. >+extern const unsigned char kPropertyBits[256]; >+ >+// Declaration for the array of characters to upper-case characters. >+extern const char kToUpper[256]; >+ >+// Declaration for the array of characters to lower-case characters. >+extern const char kToLower[256]; >+ >+} // namespace ascii_internal >+ >+// ascii_isalpha() >+// >+// Determines whether the given character is an alphabetic character. >+inline bool ascii_isalpha(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x01) != 0; >+} >+ >+// ascii_isalnum() >+// >+// Determines whether the given character is an alphanumeric character. >+inline bool ascii_isalnum(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x04) != 0; >+} >+ >+// ascii_isspace() >+// >+// Determines whether the given character is a whitespace character (space, >+// tab, vertical tab, formfeed, linefeed, or carriage return). >+inline bool ascii_isspace(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x08) != 0; >+} >+ >+// ascii_ispunct() >+// >+// Determines whether the given character is a punctuation character. >+inline bool ascii_ispunct(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x10) != 0; >+} >+ >+// ascii_isblank() >+// >+// Determines whether the given character is a blank character (tab or space). >+inline bool ascii_isblank(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x20) != 0; >+} >+ >+// ascii_iscntrl() >+// >+// Determines whether the given character is a control character. >+inline bool ascii_iscntrl(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x40) != 0; >+} >+ >+// ascii_isxdigit() >+// >+// Determines whether the given character can be represented as a hexadecimal >+// digit character (i.e. {0-9} or {A-F}). >+inline bool ascii_isxdigit(unsigned char c) { >+ return (ascii_internal::kPropertyBits[c] & 0x80) != 0; >+} >+ >+// ascii_isdigit() >+// >+// Determines whether the given character can be represented as a decimal >+// digit character (i.e. {0-9}). >+inline bool ascii_isdigit(unsigned char c) { return c >= '0' && c <= '9'; } >+ >+// ascii_isprint() >+// >+// Determines whether the given character is printable, including whitespace. >+inline bool ascii_isprint(unsigned char c) { return c >= 32 && c < 127; } >+ >+// ascii_isgraph() >+// >+// Determines whether the given character has a graphical representation. >+inline bool ascii_isgraph(unsigned char c) { return c > 32 && c < 127; } >+ >+// ascii_isupper() >+// >+// Determines whether the given character is uppercase. >+inline bool ascii_isupper(unsigned char c) { return c >= 'A' && c <= 'Z'; } >+ >+// ascii_islower() >+// >+// Determines whether the given character is lowercase. >+inline bool ascii_islower(unsigned char c) { return c >= 'a' && c <= 'z'; } >+ >+// ascii_isascii() >+// >+// Determines whether the given character is ASCII. >+inline bool ascii_isascii(unsigned char c) { return c < 128; } >+ >+// ascii_tolower() >+// >+// Returns an ASCII character, converting to lowercase if uppercase is >+// passed. Note that character values > 127 are simply returned. >+inline char ascii_tolower(unsigned char c) { >+ return ascii_internal::kToLower[c]; >+} >+ >+// Converts the characters in `s` to lowercase, changing the contents of `s`. >+void AsciiStrToLower(std::string* s); >+ >+// Creates a lowercase std::string from a given absl::string_view. >+ABSL_MUST_USE_RESULT inline std::string AsciiStrToLower(absl::string_view s) { >+ std::string result(s); >+ absl::AsciiStrToLower(&result); >+ return result; >+} >+ >+// ascii_toupper() >+// >+// Returns the ASCII character, converting to upper-case if lower-case is >+// passed. Note that characters values > 127 are simply returned. >+inline char ascii_toupper(unsigned char c) { >+ return ascii_internal::kToUpper[c]; >+} >+ >+// Converts the characters in `s` to uppercase, changing the contents of `s`. >+void AsciiStrToUpper(std::string* s); >+ >+// Creates an uppercase std::string from a given absl::string_view. >+ABSL_MUST_USE_RESULT inline std::string AsciiStrToUpper(absl::string_view s) { >+ std::string result(s); >+ absl::AsciiStrToUpper(&result); >+ return result; >+} >+ >+// Returns absl::string_view with whitespace stripped from the beginning of the >+// given string_view. >+ABSL_MUST_USE_RESULT inline absl::string_view StripLeadingAsciiWhitespace( >+ absl::string_view str) { >+ auto it = std::find_if_not(str.begin(), str.end(), absl::ascii_isspace); >+ return absl::string_view(it, str.end() - it); >+} >+ >+// Strips in place whitespace from the beginning of the given std::string. >+inline void StripLeadingAsciiWhitespace(std::string* str) { >+ auto it = std::find_if_not(str->begin(), str->end(), absl::ascii_isspace); >+ str->erase(str->begin(), it); >+} >+ >+// Returns absl::string_view with whitespace stripped from the end of the given >+// string_view. >+ABSL_MUST_USE_RESULT inline absl::string_view StripTrailingAsciiWhitespace( >+ absl::string_view str) { >+ auto it = std::find_if_not(str.rbegin(), str.rend(), absl::ascii_isspace); >+ return absl::string_view(str.begin(), str.rend() - it); >+} >+ >+// Strips in place whitespace from the end of the given std::string >+inline void StripTrailingAsciiWhitespace(std::string* str) { >+ auto it = std::find_if_not(str->rbegin(), str->rend(), absl::ascii_isspace); >+ str->erase(str->rend() - it); >+} >+ >+// Returns absl::string_view with whitespace stripped from both ends of the >+// given string_view. >+ABSL_MUST_USE_RESULT inline absl::string_view StripAsciiWhitespace( >+ absl::string_view str) { >+ return StripTrailingAsciiWhitespace(StripLeadingAsciiWhitespace(str)); >+} >+ >+// Strips in place whitespace from both ends of the given std::string >+inline void StripAsciiWhitespace(std::string* str) { >+ StripTrailingAsciiWhitespace(str); >+ StripLeadingAsciiWhitespace(str); >+} >+ >+// Removes leading, trailing, and consecutive internal whitespace. >+void RemoveExtraAsciiWhitespace(std::string*); >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_ASCII_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc >new file mode 100644 >index 00000000000..8dea4b8cfbf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_benchmark.cc >@@ -0,0 +1,120 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/ascii.h" >+ >+#include <cctype> >+#include <string> >+#include <array> >+#include <random> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+std::array<unsigned char, 256> MakeShuffledBytes() { >+ std::array<unsigned char, 256> bytes; >+ for (size_t i = 0; i < 256; ++i) bytes[i] = static_cast<unsigned char>(i); >+ std::random_device rd; >+ std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}); >+ std::mt19937 g(seed); >+ std::shuffle(bytes.begin(), bytes.end(), g); >+ return bytes; >+} >+ >+template <typename Function> >+void AsciiBenchmark(benchmark::State& state, Function f) { >+ std::array<unsigned char, 256> bytes = MakeShuffledBytes(); >+ size_t sum = 0; >+ for (auto _ : state) { >+ for (unsigned char b : bytes) sum += f(b) ? 1 : 0; >+ } >+ // Make a copy of `sum` before calling `DoNotOptimize` to make sure that `sum` >+ // can be put in a CPU register and not degrade performance in the loop above. >+ size_t sum2 = sum; >+ benchmark::DoNotOptimize(sum2); >+ state.SetBytesProcessed(state.iterations() * bytes.size()); >+} >+ >+using StdAsciiFunction = int (*)(int); >+template <StdAsciiFunction f> >+void BM_Ascii(benchmark::State& state) { >+ AsciiBenchmark(state, f); >+} >+ >+using AbslAsciiIsFunction = bool (*)(unsigned char); >+template <AbslAsciiIsFunction f> >+void BM_Ascii(benchmark::State& state) { >+ AsciiBenchmark(state, f); >+} >+ >+using AbslAsciiToFunction = char (*)(unsigned char); >+template <AbslAsciiToFunction f> >+void BM_Ascii(benchmark::State& state) { >+ AsciiBenchmark(state, f); >+} >+ >+inline char Noop(unsigned char b) { return static_cast<char>(b); } >+ >+BENCHMARK_TEMPLATE(BM_Ascii, Noop); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isalpha); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isalpha); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isdigit); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isdigit); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isalnum); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isalnum); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isspace); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isspace); >+BENCHMARK_TEMPLATE(BM_Ascii, std::ispunct); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_ispunct); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isblank); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isblank); >+BENCHMARK_TEMPLATE(BM_Ascii, std::iscntrl); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_iscntrl); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isxdigit); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isxdigit); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isprint); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isprint); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isgraph); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isgraph); >+BENCHMARK_TEMPLATE(BM_Ascii, std::isupper); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isupper); >+BENCHMARK_TEMPLATE(BM_Ascii, std::islower); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_islower); >+BENCHMARK_TEMPLATE(BM_Ascii, isascii); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_isascii); >+BENCHMARK_TEMPLATE(BM_Ascii, std::tolower); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_tolower); >+BENCHMARK_TEMPLATE(BM_Ascii, std::toupper); >+BENCHMARK_TEMPLATE(BM_Ascii, absl::ascii_toupper); >+ >+static void BM_StrToLower(benchmark::State& state) { >+ const int size = state.range(0); >+ std::string s(size, 'X'); >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::AsciiStrToLower(s)); >+ } >+} >+BENCHMARK(BM_StrToLower)->Range(1, 1 << 20); >+ >+static void BM_StrToUpper(benchmark::State& state) { >+ const int size = state.range(0); >+ std::string s(size, 'x'); >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::AsciiStrToUpper(s)); >+ } >+} >+BENCHMARK(BM_StrToUpper)->Range(1, 1 << 20); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_test.cc >new file mode 100644 >index 00000000000..9903b0496b7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/ascii_test.cc >@@ -0,0 +1,361 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/ascii.h" >+ >+#include <cctype> >+#include <clocale> >+#include <cstring> >+#include <string> >+ >+#include "gtest/gtest.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+namespace { >+ >+TEST(AsciiIsFoo, All) { >+ for (int i = 0; i < 256; i++) { >+ if ((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z')) >+ EXPECT_TRUE(absl::ascii_isalpha(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isalpha(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if ((i >= '0' && i <= '9')) >+ EXPECT_TRUE(absl::ascii_isdigit(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isdigit(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (absl::ascii_isalpha(i) || absl::ascii_isdigit(i)) >+ EXPECT_TRUE(absl::ascii_isalnum(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isalnum(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i != '\0' && strchr(" \r\n\t\v\f", i)) >+ EXPECT_TRUE(absl::ascii_isspace(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isspace(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i >= 32 && i < 127) >+ EXPECT_TRUE(absl::ascii_isprint(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isprint(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (absl::ascii_isprint(i) && !absl::ascii_isspace(i) && >+ !absl::ascii_isalnum(i)) >+ EXPECT_TRUE(absl::ascii_ispunct(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_ispunct(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i == ' ' || i == '\t') >+ EXPECT_TRUE(absl::ascii_isblank(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isblank(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i < 32 || i == 127) >+ EXPECT_TRUE(absl::ascii_iscntrl(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_iscntrl(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (absl::ascii_isdigit(i) || (i >= 'A' && i <= 'F') || >+ (i >= 'a' && i <= 'f')) >+ EXPECT_TRUE(absl::ascii_isxdigit(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isxdigit(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i > 32 && i < 127) >+ EXPECT_TRUE(absl::ascii_isgraph(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isgraph(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i >= 'A' && i <= 'Z') >+ EXPECT_TRUE(absl::ascii_isupper(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_isupper(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 256; i++) { >+ if (i >= 'a' && i <= 'z') >+ EXPECT_TRUE(absl::ascii_islower(i)) << ": failed on " << i; >+ else >+ EXPECT_TRUE(!absl::ascii_islower(i)) << ": failed on " << i; >+ } >+ for (int i = 0; i < 128; i++) { >+ EXPECT_TRUE(absl::ascii_isascii(i)) << ": failed on " << i; >+ } >+ for (int i = 128; i < 256; i++) { >+ EXPECT_TRUE(!absl::ascii_isascii(i)) << ": failed on " << i; >+ } >+ >+ // The official is* functions don't accept negative signed chars, but >+ // our absl::ascii_is* functions do. >+ for (int i = 0; i < 256; i++) { >+ signed char sc = static_cast<signed char>(static_cast<unsigned char>(i)); >+ EXPECT_EQ(absl::ascii_isalpha(i), absl::ascii_isalpha(sc)) << i; >+ EXPECT_EQ(absl::ascii_isdigit(i), absl::ascii_isdigit(sc)) << i; >+ EXPECT_EQ(absl::ascii_isalnum(i), absl::ascii_isalnum(sc)) << i; >+ EXPECT_EQ(absl::ascii_isspace(i), absl::ascii_isspace(sc)) << i; >+ EXPECT_EQ(absl::ascii_ispunct(i), absl::ascii_ispunct(sc)) << i; >+ EXPECT_EQ(absl::ascii_isblank(i), absl::ascii_isblank(sc)) << i; >+ EXPECT_EQ(absl::ascii_iscntrl(i), absl::ascii_iscntrl(sc)) << i; >+ EXPECT_EQ(absl::ascii_isxdigit(i), absl::ascii_isxdigit(sc)) << i; >+ EXPECT_EQ(absl::ascii_isprint(i), absl::ascii_isprint(sc)) << i; >+ EXPECT_EQ(absl::ascii_isgraph(i), absl::ascii_isgraph(sc)) << i; >+ EXPECT_EQ(absl::ascii_isupper(i), absl::ascii_isupper(sc)) << i; >+ EXPECT_EQ(absl::ascii_islower(i), absl::ascii_islower(sc)) << i; >+ EXPECT_EQ(absl::ascii_isascii(i), absl::ascii_isascii(sc)) << i; >+ } >+} >+ >+// Checks that absl::ascii_isfoo returns the same value as isfoo in the C >+// locale. >+TEST(AsciiIsFoo, SameAsIsFoo) { >+#ifndef __ANDROID__ >+ // temporarily change locale to C. It should already be C, but just for safety >+ const char* old_locale = setlocale(LC_CTYPE, "C"); >+ ASSERT_TRUE(old_locale != nullptr); >+#endif >+ >+ for (int i = 0; i < 256; i++) { >+ EXPECT_EQ(isalpha(i) != 0, absl::ascii_isalpha(i)) << i; >+ EXPECT_EQ(isdigit(i) != 0, absl::ascii_isdigit(i)) << i; >+ EXPECT_EQ(isalnum(i) != 0, absl::ascii_isalnum(i)) << i; >+ EXPECT_EQ(isspace(i) != 0, absl::ascii_isspace(i)) << i; >+ EXPECT_EQ(ispunct(i) != 0, absl::ascii_ispunct(i)) << i; >+ EXPECT_EQ(isblank(i) != 0, absl::ascii_isblank(i)) << i; >+ EXPECT_EQ(iscntrl(i) != 0, absl::ascii_iscntrl(i)) << i; >+ EXPECT_EQ(isxdigit(i) != 0, absl::ascii_isxdigit(i)) << i; >+ EXPECT_EQ(isprint(i) != 0, absl::ascii_isprint(i)) << i; >+ EXPECT_EQ(isgraph(i) != 0, absl::ascii_isgraph(i)) << i; >+ EXPECT_EQ(isupper(i) != 0, absl::ascii_isupper(i)) << i; >+ EXPECT_EQ(islower(i) != 0, absl::ascii_islower(i)) << i; >+ EXPECT_EQ(isascii(i) != 0, absl::ascii_isascii(i)) << i; >+ } >+ >+#ifndef __ANDROID__ >+ // restore the old locale. >+ ASSERT_TRUE(setlocale(LC_CTYPE, old_locale)); >+#endif >+} >+ >+TEST(AsciiToFoo, All) { >+#ifndef __ANDROID__ >+ // temporarily change locale to C. It should already be C, but just for safety >+ const char* old_locale = setlocale(LC_CTYPE, "C"); >+ ASSERT_TRUE(old_locale != nullptr); >+#endif >+ >+ for (int i = 0; i < 256; i++) { >+ if (absl::ascii_islower(i)) >+ EXPECT_EQ(absl::ascii_toupper(i), 'A' + (i - 'a')) << i; >+ else >+ EXPECT_EQ(absl::ascii_toupper(i), static_cast<char>(i)) << i; >+ >+ if (absl::ascii_isupper(i)) >+ EXPECT_EQ(absl::ascii_tolower(i), 'a' + (i - 'A')) << i; >+ else >+ EXPECT_EQ(absl::ascii_tolower(i), static_cast<char>(i)) << i; >+ >+ // These CHECKs only hold in a C locale. >+ EXPECT_EQ(static_cast<char>(tolower(i)), absl::ascii_tolower(i)) << i; >+ EXPECT_EQ(static_cast<char>(toupper(i)), absl::ascii_toupper(i)) << i; >+ >+ // The official to* functions don't accept negative signed chars, but >+ // our absl::ascii_to* functions do. >+ signed char sc = static_cast<signed char>(static_cast<unsigned char>(i)); >+ EXPECT_EQ(absl::ascii_tolower(i), absl::ascii_tolower(sc)) << i; >+ EXPECT_EQ(absl::ascii_toupper(i), absl::ascii_toupper(sc)) << i; >+ } >+#ifndef __ANDROID__ >+ // restore the old locale. >+ ASSERT_TRUE(setlocale(LC_CTYPE, old_locale)); >+#endif >+} >+ >+TEST(AsciiStrTo, Lower) { >+ const char buf[] = "ABCDEF"; >+ const std::string str("GHIJKL"); >+ const std::string str2("MNOPQR"); >+ const absl::string_view sp(str2); >+ >+ EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf)); >+ EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str)); >+ EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp)); >+ >+ char mutable_buf[] = "Mutable"; >+ std::transform(mutable_buf, mutable_buf + strlen(mutable_buf), >+ mutable_buf, absl::ascii_tolower); >+ EXPECT_STREQ("mutable", mutable_buf); >+} >+ >+TEST(AsciiStrTo, Upper) { >+ const char buf[] = "abcdef"; >+ const std::string str("ghijkl"); >+ const std::string str2("mnopqr"); >+ const absl::string_view sp(str2); >+ >+ EXPECT_EQ("ABCDEF", absl::AsciiStrToUpper(buf)); >+ EXPECT_EQ("GHIJKL", absl::AsciiStrToUpper(str)); >+ EXPECT_EQ("MNOPQR", absl::AsciiStrToUpper(sp)); >+ >+ char mutable_buf[] = "Mutable"; >+ std::transform(mutable_buf, mutable_buf + strlen(mutable_buf), >+ mutable_buf, absl::ascii_toupper); >+ EXPECT_STREQ("MUTABLE", mutable_buf); >+} >+ >+TEST(StripLeadingAsciiWhitespace, FromStringView) { >+ EXPECT_EQ(absl::string_view{}, >+ absl::StripLeadingAsciiWhitespace(absl::string_view{})); >+ EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"foo"})); >+ EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo"})); >+ EXPECT_EQ("foo foo\n ", >+ absl::StripLeadingAsciiWhitespace({"\t \n\f\r\n\vfoo foo\n "})); >+ EXPECT_EQ(absl::string_view{}, absl::StripLeadingAsciiWhitespace( >+ {"\t \n\f\r\v\n\t \n\f\r\v\n"})); >+} >+ >+TEST(StripLeadingAsciiWhitespace, InPlace) { >+ std::string str; >+ >+ absl::StripLeadingAsciiWhitespace(&str); >+ EXPECT_EQ("", str); >+ >+ str = "foo"; >+ absl::StripLeadingAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = "\t \n\f\r\n\vfoo"; >+ absl::StripLeadingAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = "\t \n\f\r\n\vfoo foo\n "; >+ absl::StripLeadingAsciiWhitespace(&str); >+ EXPECT_EQ("foo foo\n ", str); >+ >+ str = "\t \n\f\r\v\n\t \n\f\r\v\n"; >+ absl::StripLeadingAsciiWhitespace(&str); >+ EXPECT_EQ(absl::string_view{}, str); >+} >+ >+TEST(StripTrailingAsciiWhitespace, FromStringView) { >+ EXPECT_EQ(absl::string_view{}, >+ absl::StripTrailingAsciiWhitespace(absl::string_view{})); >+ EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo"})); >+ EXPECT_EQ("foo", absl::StripTrailingAsciiWhitespace({"foo\t \n\f\r\n\v"})); >+ EXPECT_EQ(" \nfoo foo", >+ absl::StripTrailingAsciiWhitespace({" \nfoo foo\t \n\f\r\n\v"})); >+ EXPECT_EQ(absl::string_view{}, absl::StripTrailingAsciiWhitespace( >+ {"\t \n\f\r\v\n\t \n\f\r\v\n"})); >+} >+ >+TEST(StripTrailingAsciiWhitespace, InPlace) { >+ std::string str; >+ >+ absl::StripTrailingAsciiWhitespace(&str); >+ EXPECT_EQ("", str); >+ >+ str = "foo"; >+ absl::StripTrailingAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = "foo\t \n\f\r\n\v"; >+ absl::StripTrailingAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = " \nfoo foo\t \n\f\r\n\v"; >+ absl::StripTrailingAsciiWhitespace(&str); >+ EXPECT_EQ(" \nfoo foo", str); >+ >+ str = "\t \n\f\r\v\n\t \n\f\r\v\n"; >+ absl::StripTrailingAsciiWhitespace(&str); >+ EXPECT_EQ(absl::string_view{}, str); >+} >+ >+TEST(StripAsciiWhitespace, FromStringView) { >+ EXPECT_EQ(absl::string_view{}, >+ absl::StripAsciiWhitespace(absl::string_view{})); >+ EXPECT_EQ("foo", absl::StripAsciiWhitespace({"foo"})); >+ EXPECT_EQ("foo", >+ absl::StripAsciiWhitespace({"\t \n\f\r\n\vfoo\t \n\f\r\n\v"})); >+ EXPECT_EQ("foo foo", absl::StripAsciiWhitespace( >+ {"\t \n\f\r\n\vfoo foo\t \n\f\r\n\v"})); >+ EXPECT_EQ(absl::string_view{}, >+ absl::StripAsciiWhitespace({"\t \n\f\r\v\n\t \n\f\r\v\n"})); >+} >+ >+TEST(StripAsciiWhitespace, InPlace) { >+ std::string str; >+ >+ absl::StripAsciiWhitespace(&str); >+ EXPECT_EQ("", str); >+ >+ str = "foo"; >+ absl::StripAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = "\t \n\f\r\n\vfoo\t \n\f\r\n\v"; >+ absl::StripAsciiWhitespace(&str); >+ EXPECT_EQ("foo", str); >+ >+ str = "\t \n\f\r\n\vfoo foo\t \n\f\r\n\v"; >+ absl::StripAsciiWhitespace(&str); >+ EXPECT_EQ("foo foo", str); >+ >+ str = "\t \n\f\r\v\n\t \n\f\r\v\n"; >+ absl::StripAsciiWhitespace(&str); >+ EXPECT_EQ(absl::string_view{}, str); >+} >+ >+TEST(RemoveExtraAsciiWhitespace, InPlace) { >+ const char* inputs[] = {"No extra space", >+ " Leading whitespace", >+ "Trailing whitespace ", >+ " Leading and trailing ", >+ " Whitespace \t in\v middle ", >+ "'Eeeeep! \n Newlines!\n", >+ "nospaces", >+ "", >+ "\n\t a\t\n\nb \t\n"}; >+ >+ const char* outputs[] = { >+ "No extra space", >+ "Leading whitespace", >+ "Trailing whitespace", >+ "Leading and trailing", >+ "Whitespace in middle", >+ "'Eeeeep! Newlines!", >+ "nospaces", >+ "", >+ "a\nb", >+ }; >+ const int NUM_TESTS = ABSL_ARRAYSIZE(inputs); >+ >+ for (int i = 0; i < NUM_TESTS; i++) { >+ std::string s(inputs[i]); >+ absl::RemoveExtraAsciiWhitespace(&s); >+ EXPECT_EQ(outputs[i], s); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.cc >new file mode 100644 >index 00000000000..08c3947eccd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.cc >@@ -0,0 +1,982 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/charconv.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <cmath> >+#include <cstring> >+ >+#include "absl/base/casts.h" >+#include "absl/numeric/int128.h" >+#include "absl/strings/internal/bits.h" >+#include "absl/strings/internal/charconv_bigint.h" >+#include "absl/strings/internal/charconv_parse.h" >+ >+// The macro ABSL_BIT_PACK_FLOATS is defined on x86-64, where IEEE floating >+// point numbers have the same endianness in memory as a bitfield struct >+// containing the corresponding parts. >+// >+// When set, we replace calls to ldexp() with manual bit packing, which is >+// faster and is unaffected by floating point environment. >+#ifdef ABSL_BIT_PACK_FLOATS >+#error ABSL_BIT_PACK_FLOATS cannot be directly set >+#elif defined(__x86_64__) || defined(_M_X64) >+#define ABSL_BIT_PACK_FLOATS 1 >+#endif >+ >+// A note about subnormals: >+// >+// The code below talks about "normals" and "subnormals". A normal IEEE float >+// has a fixed-width mantissa and power of two exponent. For example, a normal >+// `double` has a 53-bit mantissa. Because the high bit is always 1, it is not >+// stored in the representation. The implicit bit buys an extra bit of >+// resolution in the datatype. >+// >+// The downside of this scheme is that there is a large gap between DBL_MIN and >+// zero. (Large, at least, relative to the different between DBL_MIN and the >+// next representable number). This gap is softened by the "subnormal" numbers, >+// which have the same power-of-two exponent as DBL_MIN, but no implicit 53rd >+// bit. An all-bits-zero exponent in the encoding represents subnormals. (Zero >+// is represented as a subnormal with an all-bits-zero mantissa.) >+// >+// The code below, in calculations, represents the mantissa as a uint64_t. The >+// end result normally has the 53rd bit set. It represents subnormals by using >+// narrower mantissas. >+ >+namespace absl { >+namespace { >+ >+template <typename FloatType> >+struct FloatTraits; >+ >+template <> >+struct FloatTraits<double> { >+ // The number of mantissa bits in the given float type. This includes the >+ // implied high bit. >+ static constexpr int kTargetMantissaBits = 53; >+ >+ // The largest supported IEEE exponent, in our integral mantissa >+ // representation. >+ // >+ // If `m` is the largest possible int kTargetMantissaBits bits wide, then >+ // m * 2**kMaxExponent is exactly equal to DBL_MAX. >+ static constexpr int kMaxExponent = 971; >+ >+ // The smallest supported IEEE normal exponent, in our integral mantissa >+ // representation. >+ // >+ // If `m` is the smallest possible int kTargetMantissaBits bits wide, then >+ // m * 2**kMinNormalExponent is exactly equal to DBL_MIN. >+ static constexpr int kMinNormalExponent = -1074; >+ >+ static double MakeNan(const char* tagp) { >+ // Support nan no matter which namespace it's in. Some platforms >+ // incorrectly don't put it in namespace std. >+ using namespace std; // NOLINT >+ return nan(tagp); >+ } >+ >+ // Builds a nonzero floating point number out of the provided parts. >+ // >+ // This is intended to do the same operation as ldexp(mantissa, exponent), >+ // but using purely integer math, to avoid -ffastmath and floating >+ // point environment issues. Using type punning is also faster. We fall back >+ // to ldexp on a per-platform basis for portability. >+ // >+ // `exponent` must be between kMinNormalExponent and kMaxExponent. >+ // >+ // `mantissa` must either be exactly kTargetMantissaBits wide, in which case >+ // a normal value is made, or it must be less narrow than that, in which case >+ // `exponent` must be exactly kMinNormalExponent, and a subnormal value is >+ // made. >+ static double Make(uint64_t mantissa, int exponent, bool sign) { >+#ifndef ABSL_BIT_PACK_FLOATS >+ // Support ldexp no matter which namespace it's in. Some platforms >+ // incorrectly don't put it in namespace std. >+ using namespace std; // NOLINT >+ return sign ? -ldexp(mantissa, exponent) : ldexp(mantissa, exponent); >+#else >+ constexpr uint64_t kMantissaMask = >+ (uint64_t(1) << (kTargetMantissaBits - 1)) - 1; >+ uint64_t dbl = static_cast<uint64_t>(sign) << 63; >+ if (mantissa > kMantissaMask) { >+ // Normal value. >+ // Adjust by 1023 for the exponent representation bias, and an additional >+ // 52 due to the implied decimal point in the IEEE mantissa represenation. >+ dbl += uint64_t{exponent + 1023u + kTargetMantissaBits - 1} << 52; >+ mantissa &= kMantissaMask; >+ } else { >+ // subnormal value >+ assert(exponent == kMinNormalExponent); >+ } >+ dbl += mantissa; >+ return absl::bit_cast<double>(dbl); >+#endif // ABSL_BIT_PACK_FLOATS >+ } >+}; >+ >+// Specialization of floating point traits for the `float` type. See the >+// FloatTraits<double> specialization above for meaning of each of the following >+// members and methods. >+template <> >+struct FloatTraits<float> { >+ static constexpr int kTargetMantissaBits = 24; >+ static constexpr int kMaxExponent = 104; >+ static constexpr int kMinNormalExponent = -149; >+ static float MakeNan(const char* tagp) { >+ // Support nanf no matter which namespace it's in. Some platforms >+ // incorrectly don't put it in namespace std. >+ using namespace std; // NOLINT >+ return nanf(tagp); >+ } >+ static float Make(uint32_t mantissa, int exponent, bool sign) { >+#ifndef ABSL_BIT_PACK_FLOATS >+ // Support ldexpf no matter which namespace it's in. Some platforms >+ // incorrectly don't put it in namespace std. >+ using namespace std; // NOLINT >+ return sign ? -ldexpf(mantissa, exponent) : ldexpf(mantissa, exponent); >+#else >+ constexpr uint32_t kMantissaMask = >+ (uint32_t(1) << (kTargetMantissaBits - 1)) - 1; >+ uint32_t flt = static_cast<uint32_t>(sign) << 31; >+ if (mantissa > kMantissaMask) { >+ // Normal value. >+ // Adjust by 127 for the exponent representation bias, and an additional >+ // 23 due to the implied decimal point in the IEEE mantissa represenation. >+ flt += uint32_t{exponent + 127u + kTargetMantissaBits - 1} << 23; >+ mantissa &= kMantissaMask; >+ } else { >+ // subnormal value >+ assert(exponent == kMinNormalExponent); >+ } >+ flt += mantissa; >+ return absl::bit_cast<float>(flt); >+#endif // ABSL_BIT_PACK_FLOATS >+ } >+}; >+ >+// Decimal-to-binary conversions require coercing powers of 10 into a mantissa >+// and a power of 2. The two helper functions Power10Mantissa(n) and >+// Power10Exponent(n) perform this task. Together, these represent a hand- >+// rolled floating point value which is equal to or just less than 10**n. >+// >+// The return values satisfy two range guarantees: >+// >+// Power10Mantissa(n) * 2**Power10Exponent(n) <= 10**n >+// < (Power10Mantissa(n) + 1) * 2**Power10Exponent(n) >+// >+// 2**63 <= Power10Mantissa(n) < 2**64. >+// >+// Lookups into the power-of-10 table must first check the Power10Overflow() and >+// Power10Underflow() functions, to avoid out-of-bounds table access. >+// >+// Indexes into these tables are biased by -kPower10TableMin, and the table has >+// values in the range [kPower10TableMin, kPower10TableMax]. >+extern const uint64_t kPower10MantissaTable[]; >+extern const int16_t kPower10ExponentTable[]; >+ >+// The smallest allowed value for use with the Power10Mantissa() and >+// Power10Exponent() functions below. (If a smaller exponent is needed in >+// calculations, the end result is guaranteed to underflow.) >+constexpr int kPower10TableMin = -342; >+ >+// The largest allowed value for use with the Power10Mantissa() and >+// Power10Exponent() functions below. (If a smaller exponent is needed in >+// calculations, the end result is guaranteed to overflow.) >+constexpr int kPower10TableMax = 308; >+ >+uint64_t Power10Mantissa(int n) { >+ return kPower10MantissaTable[n - kPower10TableMin]; >+} >+ >+int Power10Exponent(int n) { >+ return kPower10ExponentTable[n - kPower10TableMin]; >+} >+ >+// Returns true if n is large enough that 10**n always results in an IEEE >+// overflow. >+bool Power10Overflow(int n) { return n > kPower10TableMax; } >+ >+// Returns true if n is small enough that 10**n times a ParsedFloat mantissa >+// always results in an IEEE underflow. >+bool Power10Underflow(int n) { return n < kPower10TableMin; } >+ >+// Returns true if Power10Mantissa(n) * 2**Power10Exponent(n) is exactly equal >+// to 10**n numerically. Put another way, this returns true if there is no >+// truncation error in Power10Mantissa(n). >+bool Power10Exact(int n) { return n >= 0 && n <= 27; } >+ >+// Sentinel exponent values for representing numbers too large or too close to >+// zero to represent in a double. >+constexpr int kOverflow = 99999; >+constexpr int kUnderflow = -99999; >+ >+// Struct representing the calculated conversion result of a positive (nonzero) >+// floating point number. >+// >+// The calculated number is mantissa * 2**exponent (mantissa is treated as an >+// integer.) `mantissa` is chosen to be the correct width for the IEEE float >+// representation being calculated. (`mantissa` will always have the same bit >+// width for normal values, and narrower bit widths for subnormals.) >+// >+// If the result of conversion was an underflow or overflow, exponent is set >+// to kUnderflow or kOverflow. >+struct CalculatedFloat { >+ uint64_t mantissa = 0; >+ int exponent = 0; >+}; >+ >+// Returns the bit width of the given uint128. (Equivalently, returns 128 >+// minus the number of leading zero bits.) >+int BitWidth(uint128 value) { >+ if (Uint128High64(value) == 0) { >+ return 64 - strings_internal::CountLeadingZeros64(Uint128Low64(value)); >+ } >+ return 128 - strings_internal::CountLeadingZeros64(Uint128High64(value)); >+} >+ >+// Calculates how far to the right a mantissa needs to be shifted to create a >+// properly adjusted mantissa for an IEEE floating point number. >+// >+// `mantissa_width` is the bit width of the mantissa to be shifted, and >+// `binary_exponent` is the exponent of the number before the shift. >+// >+// This accounts for subnormal values, and will return a larger-than-normal >+// shift if binary_exponent would otherwise be too low. >+template <typename FloatType> >+int NormalizedShiftSize(int mantissa_width, int binary_exponent) { >+ const int normal_shift = >+ mantissa_width - FloatTraits<FloatType>::kTargetMantissaBits; >+ const int minimum_shift = >+ FloatTraits<FloatType>::kMinNormalExponent - binary_exponent; >+ return std::max(normal_shift, minimum_shift); >+} >+ >+// Right shifts a uint128 so that it has the requested bit width. (The >+// resulting value will have 128 - bit_width leading zeroes.) The initial >+// `value` must be wider than the requested bit width. >+// >+// Returns the number of bits shifted. >+int TruncateToBitWidth(int bit_width, uint128* value) { >+ const int current_bit_width = BitWidth(*value); >+ const int shift = current_bit_width - bit_width; >+ *value >>= shift; >+ return shift; >+} >+ >+// Checks if the given ParsedFloat represents one of the edge cases that are >+// not dependent on number base: zero, infinity, or NaN. If so, sets *value >+// the appropriate double, and returns true. >+template <typename FloatType> >+bool HandleEdgeCase(const strings_internal::ParsedFloat& input, bool negative, >+ FloatType* value) { >+ if (input.type == strings_internal::FloatType::kNan) { >+ // A bug in both clang and gcc would cause the compiler to optimize away the >+ // buffer we are building below. Declaring the buffer volatile avoids the >+ // issue, and has no measurable performance impact in microbenchmarks. >+ // >+ // https://bugs.llvm.org/show_bug.cgi?id=37778 >+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86113 >+ constexpr ptrdiff_t kNanBufferSize = 128; >+ volatile char n_char_sequence[kNanBufferSize]; >+ if (input.subrange_begin == nullptr) { >+ n_char_sequence[0] = '\0'; >+ } else { >+ ptrdiff_t nan_size = input.subrange_end - input.subrange_begin; >+ nan_size = std::min(nan_size, kNanBufferSize - 1); >+ std::copy_n(input.subrange_begin, nan_size, n_char_sequence); >+ n_char_sequence[nan_size] = '\0'; >+ } >+ char* nan_argument = const_cast<char*>(n_char_sequence); >+ *value = negative ? -FloatTraits<FloatType>::MakeNan(nan_argument) >+ : FloatTraits<FloatType>::MakeNan(nan_argument); >+ return true; >+ } >+ if (input.type == strings_internal::FloatType::kInfinity) { >+ *value = negative ? -std::numeric_limits<FloatType>::infinity() >+ : std::numeric_limits<FloatType>::infinity(); >+ return true; >+ } >+ if (input.mantissa == 0) { >+ *value = negative ? -0.0 : 0.0; >+ return true; >+ } >+ return false; >+} >+ >+// Given a CalculatedFloat result of a from_chars conversion, generate the >+// correct output values. >+// >+// CalculatedFloat can represent an underflow or overflow, in which case the >+// error code in *result is set. Otherwise, the calculated floating point >+// number is stored in *value. >+template <typename FloatType> >+void EncodeResult(const CalculatedFloat& calculated, bool negative, >+ absl::from_chars_result* result, FloatType* value) { >+ if (calculated.exponent == kOverflow) { >+ result->ec = std::errc::result_out_of_range; >+ *value = negative ? -std::numeric_limits<FloatType>::max() >+ : std::numeric_limits<FloatType>::max(); >+ return; >+ } else if (calculated.mantissa == 0 || calculated.exponent == kUnderflow) { >+ result->ec = std::errc::result_out_of_range; >+ *value = negative ? -0.0 : 0.0; >+ return; >+ } >+ *value = FloatTraits<FloatType>::Make(calculated.mantissa, >+ calculated.exponent, negative); >+} >+ >+// Returns the given uint128 shifted to the right by `shift` bits, and rounds >+// the remaining bits using round_to_nearest logic. The value is returned as a >+// uint64_t, since this is the type used by this library for storing calculated >+// floating point mantissas. >+// >+// It is expected that the width of the input value shifted by `shift` will >+// be the correct bit-width for the target mantissa, which is strictly narrower >+// than a uint64_t. >+// >+// If `input_exact` is false, then a nonzero error epsilon is assumed. For >+// rounding purposes, the true value being rounded is strictly greater than the >+// input value. The error may represent a single lost carry bit. >+// >+// When input_exact, shifted bits of the form 1000000... represent a tie, which >+// is broken by rounding to even -- the rounding direction is chosen so the low >+// bit of the returned value is 0. >+// >+// When !input_exact, shifted bits of the form 10000000... represent a value >+// strictly greater than one half (due to the error epsilon), and so ties are >+// always broken by rounding up. >+// >+// When !input_exact, shifted bits of the form 01111111... are uncertain; >+// the true value may or may not be greater than 10000000..., due to the >+// possible lost carry bit. The correct rounding direction is unknown. In this >+// case, the result is rounded down, and `output_exact` is set to false. >+// >+// Zero and negative values of `shift` are accepted, in which case the word is >+// shifted left, as necessary. >+uint64_t ShiftRightAndRound(uint128 value, int shift, bool input_exact, >+ bool* output_exact) { >+ if (shift <= 0) { >+ *output_exact = input_exact; >+ return static_cast<uint64_t>(value << -shift); >+ } >+ if (shift >= 128) { >+ // Exponent is so small that we are shifting away all significant bits. >+ // Answer will not be representable, even as a subnormal, so return a zero >+ // mantissa (which represents underflow). >+ *output_exact = true; >+ return 0; >+ } >+ >+ *output_exact = true; >+ const uint128 shift_mask = (uint128(1) << shift) - 1; >+ const uint128 halfway_point = uint128(1) << (shift - 1); >+ >+ const uint128 shifted_bits = value & shift_mask; >+ value >>= shift; >+ if (shifted_bits > halfway_point) { >+ // Shifted bits greater than 10000... require rounding up. >+ return static_cast<uint64_t>(value + 1); >+ } >+ if (shifted_bits == halfway_point) { >+ // In exact mode, shifted bits of 10000... mean we're exactly halfway >+ // between two numbers, and we must round to even. So only round up if >+ // the low bit of `value` is set. >+ // >+ // In inexact mode, the nonzero error means the actual value is greater >+ // than the halfway point and we must alway round up. >+ if ((value & 1) == 1 || !input_exact) { >+ ++value; >+ } >+ return static_cast<uint64_t>(value); >+ } >+ if (!input_exact && shifted_bits == halfway_point - 1) { >+ // Rounding direction is unclear, due to error. >+ *output_exact = false; >+ } >+ // Otherwise, round down. >+ return static_cast<uint64_t>(value); >+} >+ >+// Checks if a floating point guess needs to be rounded up, using high precision >+// math. >+// >+// `guess_mantissa` and `guess_exponent` represent a candidate guess for the >+// number represented by `parsed_decimal`. >+// >+// The exact number represented by `parsed_decimal` must lie between the two >+// numbers: >+// A = `guess_mantissa * 2**guess_exponent` >+// B = `(guess_mantissa + 1) * 2**guess_exponent` >+// >+// This function returns false if `A` is the better guess, and true if `B` is >+// the better guess, with rounding ties broken by rounding to even. >+bool MustRoundUp(uint64_t guess_mantissa, int guess_exponent, >+ const strings_internal::ParsedFloat& parsed_decimal) { >+ // 768 is the number of digits needed in the worst case. We could determine a >+ // better limit dynamically based on the value of parsed_decimal.exponent. >+ // This would optimize pathological input cases only. (Sane inputs won't have >+ // hundreds of digits of mantissa.) >+ absl::strings_internal::BigUnsigned<84> exact_mantissa; >+ int exact_exponent = exact_mantissa.ReadFloatMantissa(parsed_decimal, 768); >+ >+ // Adjust the `guess` arguments to be halfway between A and B. >+ guess_mantissa = guess_mantissa * 2 + 1; >+ guess_exponent -= 1; >+ >+ // In our comparison: >+ // lhs = exact = exact_mantissa * 10**exact_exponent >+ // = exact_mantissa * 5**exact_exponent * 2**exact_exponent >+ // rhs = guess = guess_mantissa * 2**guess_exponent >+ // >+ // Because we are doing integer math, we can't directly deal with negative >+ // exponents. We instead move these to the other side of the inequality. >+ absl::strings_internal::BigUnsigned<84>& lhs = exact_mantissa; >+ int comparison; >+ if (exact_exponent >= 0) { >+ lhs.MultiplyByFiveToTheNth(exact_exponent); >+ absl::strings_internal::BigUnsigned<84> rhs(guess_mantissa); >+ // There are powers of 2 on both sides of the inequality; reduce this to >+ // a single bit-shift. >+ if (exact_exponent > guess_exponent) { >+ lhs.ShiftLeft(exact_exponent - guess_exponent); >+ } else { >+ rhs.ShiftLeft(guess_exponent - exact_exponent); >+ } >+ comparison = Compare(lhs, rhs); >+ } else { >+ // Move the power of 5 to the other side of the equation, giving us: >+ // lhs = exact_mantissa * 2**exact_exponent >+ // rhs = guess_mantissa * 5**(-exact_exponent) * 2**guess_exponent >+ absl::strings_internal::BigUnsigned<84> rhs = >+ absl::strings_internal::BigUnsigned<84>::FiveToTheNth(-exact_exponent); >+ rhs.MultiplyBy(guess_mantissa); >+ if (exact_exponent > guess_exponent) { >+ lhs.ShiftLeft(exact_exponent - guess_exponent); >+ } else { >+ rhs.ShiftLeft(guess_exponent - exact_exponent); >+ } >+ comparison = Compare(lhs, rhs); >+ } >+ if (comparison < 0) { >+ return false; >+ } else if (comparison > 0) { >+ return true; >+ } else { >+ // When lhs == rhs, the decimal input is exactly between A and B. >+ // Round towards even -- round up only if the low bit of the initial >+ // `guess_mantissa` was a 1. We shifted guess_mantissa left 1 bit at >+ // the beginning of this function, so test the 2nd bit here. >+ return (guess_mantissa & 2) == 2; >+ } >+} >+ >+// Constructs a CalculatedFloat from a given mantissa and exponent, but >+// with the following normalizations applied: >+// >+// If rounding has caused mantissa to increase just past the allowed bit >+// width, shift and adjust exponent. >+// >+// If exponent is too high, sets kOverflow. >+// >+// If mantissa is zero (representing a non-zero value not representable, even >+// as a subnormal), sets kUnderflow. >+template <typename FloatType> >+CalculatedFloat CalculatedFloatFromRawValues(uint64_t mantissa, int exponent) { >+ CalculatedFloat result; >+ if (mantissa == uint64_t(1) << FloatTraits<FloatType>::kTargetMantissaBits) { >+ mantissa >>= 1; >+ exponent += 1; >+ } >+ if (exponent > FloatTraits<FloatType>::kMaxExponent) { >+ result.exponent = kOverflow; >+ } else if (mantissa == 0) { >+ result.exponent = kUnderflow; >+ } else { >+ result.exponent = exponent; >+ result.mantissa = mantissa; >+ } >+ return result; >+} >+ >+template <typename FloatType> >+CalculatedFloat CalculateFromParsedHexadecimal( >+ const strings_internal::ParsedFloat& parsed_hex) { >+ uint64_t mantissa = parsed_hex.mantissa; >+ int exponent = parsed_hex.exponent; >+ int mantissa_width = 64 - strings_internal::CountLeadingZeros64(mantissa); >+ const int shift = NormalizedShiftSize<FloatType>(mantissa_width, exponent); >+ bool result_exact; >+ exponent += shift; >+ mantissa = ShiftRightAndRound(mantissa, shift, >+ /* input exact= */ true, &result_exact); >+ // ParseFloat handles rounding in the hexadecimal case, so we don't have to >+ // check `result_exact` here. >+ return CalculatedFloatFromRawValues<FloatType>(mantissa, exponent); >+} >+ >+template <typename FloatType> >+CalculatedFloat CalculateFromParsedDecimal( >+ const strings_internal::ParsedFloat& parsed_decimal) { >+ CalculatedFloat result; >+ >+ // Large or small enough decimal exponents will always result in overflow >+ // or underflow. >+ if (Power10Underflow(parsed_decimal.exponent)) { >+ result.exponent = kUnderflow; >+ return result; >+ } else if (Power10Overflow(parsed_decimal.exponent)) { >+ result.exponent = kOverflow; >+ return result; >+ } >+ >+ // Otherwise convert our power of 10 into a power of 2 times an integer >+ // mantissa, and multiply this by our parsed decimal mantissa. >+ uint128 wide_binary_mantissa = parsed_decimal.mantissa; >+ wide_binary_mantissa *= Power10Mantissa(parsed_decimal.exponent); >+ int binary_exponent = Power10Exponent(parsed_decimal.exponent); >+ >+ // Discard bits that are inaccurate due to truncation error. The magic >+ // `mantissa_width` constants below are justified in charconv_algorithm.md. >+ // They represent the number of bits in `wide_binary_mantissa` that are >+ // guaranteed to be unaffected by error propagation. >+ bool mantissa_exact; >+ int mantissa_width; >+ if (parsed_decimal.subrange_begin) { >+ // Truncated mantissa >+ mantissa_width = 58; >+ mantissa_exact = false; >+ binary_exponent += >+ TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); >+ } else if (!Power10Exact(parsed_decimal.exponent)) { >+ // Exact mantissa, truncated power of ten >+ mantissa_width = 63; >+ mantissa_exact = false; >+ binary_exponent += >+ TruncateToBitWidth(mantissa_width, &wide_binary_mantissa); >+ } else { >+ // Product is exact >+ mantissa_width = BitWidth(wide_binary_mantissa); >+ mantissa_exact = true; >+ } >+ >+ // Shift into an FloatType-sized mantissa, and round to nearest. >+ const int shift = >+ NormalizedShiftSize<FloatType>(mantissa_width, binary_exponent); >+ bool result_exact; >+ binary_exponent += shift; >+ uint64_t binary_mantissa = ShiftRightAndRound(wide_binary_mantissa, shift, >+ mantissa_exact, &result_exact); >+ if (!result_exact) { >+ // We could not determine the rounding direction using int128 math. Use >+ // full resolution math instead. >+ if (MustRoundUp(binary_mantissa, binary_exponent, parsed_decimal)) { >+ binary_mantissa += 1; >+ } >+ } >+ >+ return CalculatedFloatFromRawValues<FloatType>(binary_mantissa, >+ binary_exponent); >+} >+ >+template <typename FloatType> >+from_chars_result FromCharsImpl(const char* first, const char* last, >+ FloatType& value, chars_format fmt_flags) { >+ from_chars_result result; >+ result.ptr = first; // overwritten on successful parse >+ result.ec = std::errc(); >+ >+ bool negative = false; >+ if (first != last && *first == '-') { >+ ++first; >+ negative = true; >+ } >+ // If the `hex` flag is *not* set, then we will accept a 0x prefix and try >+ // to parse a hexadecimal float. >+ if ((fmt_flags & chars_format::hex) == chars_format{} && last - first >= 2 && >+ *first == '0' && (first[1] == 'x' || first[1] == 'X')) { >+ const char* hex_first = first + 2; >+ strings_internal::ParsedFloat hex_parse = >+ strings_internal::ParseFloat<16>(hex_first, last, fmt_flags); >+ if (hex_parse.end == nullptr || >+ hex_parse.type != strings_internal::FloatType::kNumber) { >+ // Either we failed to parse a hex float after the "0x", or we read >+ // "0xinf" or "0xnan" which we don't want to match. >+ // >+ // However, a std::string that begins with "0x" also begins with "0", which >+ // is normally a valid match for the number zero. So we want these >+ // strings to match zero unless fmt_flags is `scientific`. (This flag >+ // means an exponent is required, which the std::string "0" does not have.) >+ if (fmt_flags == chars_format::scientific) { >+ result.ec = std::errc::invalid_argument; >+ } else { >+ result.ptr = first + 1; >+ value = negative ? -0.0 : 0.0; >+ } >+ return result; >+ } >+ // We matched a value. >+ result.ptr = hex_parse.end; >+ if (HandleEdgeCase(hex_parse, negative, &value)) { >+ return result; >+ } >+ CalculatedFloat calculated = >+ CalculateFromParsedHexadecimal<FloatType>(hex_parse); >+ EncodeResult(calculated, negative, &result, &value); >+ return result; >+ } >+ // Otherwise, we choose the number base based on the flags. >+ if ((fmt_flags & chars_format::hex) == chars_format::hex) { >+ strings_internal::ParsedFloat hex_parse = >+ strings_internal::ParseFloat<16>(first, last, fmt_flags); >+ if (hex_parse.end == nullptr) { >+ result.ec = std::errc::invalid_argument; >+ return result; >+ } >+ result.ptr = hex_parse.end; >+ if (HandleEdgeCase(hex_parse, negative, &value)) { >+ return result; >+ } >+ CalculatedFloat calculated = >+ CalculateFromParsedHexadecimal<FloatType>(hex_parse); >+ EncodeResult(calculated, negative, &result, &value); >+ return result; >+ } else { >+ strings_internal::ParsedFloat decimal_parse = >+ strings_internal::ParseFloat<10>(first, last, fmt_flags); >+ if (decimal_parse.end == nullptr) { >+ result.ec = std::errc::invalid_argument; >+ return result; >+ } >+ result.ptr = decimal_parse.end; >+ if (HandleEdgeCase(decimal_parse, negative, &value)) { >+ return result; >+ } >+ CalculatedFloat calculated = >+ CalculateFromParsedDecimal<FloatType>(decimal_parse); >+ EncodeResult(calculated, negative, &result, &value); >+ return result; >+ } >+ return result; >+} >+} // namespace >+ >+from_chars_result from_chars(const char* first, const char* last, double& value, >+ chars_format fmt) { >+ return FromCharsImpl(first, last, value, fmt); >+} >+ >+from_chars_result from_chars(const char* first, const char* last, float& value, >+ chars_format fmt) { >+ return FromCharsImpl(first, last, value, fmt); >+} >+ >+namespace { >+ >+// Table of powers of 10, from kPower10TableMin to kPower10TableMax. >+// >+// kPower10MantissaTable[i - kPower10TableMin] stores the 64-bit mantissa (high >+// bit always on), and kPower10ExponentTable[i - kPower10TableMin] stores the >+// power-of-two exponent. For a given number i, this gives the unique mantissa >+// and exponent such that mantissa * 2**exponent <= 10**i < (mantissa + 1) * >+// 2**exponent. >+ >+const uint64_t kPower10MantissaTable[] = { >+ 0xeef453d6923bd65aU, 0x9558b4661b6565f8U, 0xbaaee17fa23ebf76U, >+ 0xe95a99df8ace6f53U, 0x91d8a02bb6c10594U, 0xb64ec836a47146f9U, >+ 0xe3e27a444d8d98b7U, 0x8e6d8c6ab0787f72U, 0xb208ef855c969f4fU, >+ 0xde8b2b66b3bc4723U, 0x8b16fb203055ac76U, 0xaddcb9e83c6b1793U, >+ 0xd953e8624b85dd78U, 0x87d4713d6f33aa6bU, 0xa9c98d8ccb009506U, >+ 0xd43bf0effdc0ba48U, 0x84a57695fe98746dU, 0xa5ced43b7e3e9188U, >+ 0xcf42894a5dce35eaU, 0x818995ce7aa0e1b2U, 0xa1ebfb4219491a1fU, >+ 0xca66fa129f9b60a6U, 0xfd00b897478238d0U, 0x9e20735e8cb16382U, >+ 0xc5a890362fddbc62U, 0xf712b443bbd52b7bU, 0x9a6bb0aa55653b2dU, >+ 0xc1069cd4eabe89f8U, 0xf148440a256e2c76U, 0x96cd2a865764dbcaU, >+ 0xbc807527ed3e12bcU, 0xeba09271e88d976bU, 0x93445b8731587ea3U, >+ 0xb8157268fdae9e4cU, 0xe61acf033d1a45dfU, 0x8fd0c16206306babU, >+ 0xb3c4f1ba87bc8696U, 0xe0b62e2929aba83cU, 0x8c71dcd9ba0b4925U, >+ 0xaf8e5410288e1b6fU, 0xdb71e91432b1a24aU, 0x892731ac9faf056eU, >+ 0xab70fe17c79ac6caU, 0xd64d3d9db981787dU, 0x85f0468293f0eb4eU, >+ 0xa76c582338ed2621U, 0xd1476e2c07286faaU, 0x82cca4db847945caU, >+ 0xa37fce126597973cU, 0xcc5fc196fefd7d0cU, 0xff77b1fcbebcdc4fU, >+ 0x9faacf3df73609b1U, 0xc795830d75038c1dU, 0xf97ae3d0d2446f25U, >+ 0x9becce62836ac577U, 0xc2e801fb244576d5U, 0xf3a20279ed56d48aU, >+ 0x9845418c345644d6U, 0xbe5691ef416bd60cU, 0xedec366b11c6cb8fU, >+ 0x94b3a202eb1c3f39U, 0xb9e08a83a5e34f07U, 0xe858ad248f5c22c9U, >+ 0x91376c36d99995beU, 0xb58547448ffffb2dU, 0xe2e69915b3fff9f9U, >+ 0x8dd01fad907ffc3bU, 0xb1442798f49ffb4aU, 0xdd95317f31c7fa1dU, >+ 0x8a7d3eef7f1cfc52U, 0xad1c8eab5ee43b66U, 0xd863b256369d4a40U, >+ 0x873e4f75e2224e68U, 0xa90de3535aaae202U, 0xd3515c2831559a83U, >+ 0x8412d9991ed58091U, 0xa5178fff668ae0b6U, 0xce5d73ff402d98e3U, >+ 0x80fa687f881c7f8eU, 0xa139029f6a239f72U, 0xc987434744ac874eU, >+ 0xfbe9141915d7a922U, 0x9d71ac8fada6c9b5U, 0xc4ce17b399107c22U, >+ 0xf6019da07f549b2bU, 0x99c102844f94e0fbU, 0xc0314325637a1939U, >+ 0xf03d93eebc589f88U, 0x96267c7535b763b5U, 0xbbb01b9283253ca2U, >+ 0xea9c227723ee8bcbU, 0x92a1958a7675175fU, 0xb749faed14125d36U, >+ 0xe51c79a85916f484U, 0x8f31cc0937ae58d2U, 0xb2fe3f0b8599ef07U, >+ 0xdfbdcece67006ac9U, 0x8bd6a141006042bdU, 0xaecc49914078536dU, >+ 0xda7f5bf590966848U, 0x888f99797a5e012dU, 0xaab37fd7d8f58178U, >+ 0xd5605fcdcf32e1d6U, 0x855c3be0a17fcd26U, 0xa6b34ad8c9dfc06fU, >+ 0xd0601d8efc57b08bU, 0x823c12795db6ce57U, 0xa2cb1717b52481edU, >+ 0xcb7ddcdda26da268U, 0xfe5d54150b090b02U, 0x9efa548d26e5a6e1U, >+ 0xc6b8e9b0709f109aU, 0xf867241c8cc6d4c0U, 0x9b407691d7fc44f8U, >+ 0xc21094364dfb5636U, 0xf294b943e17a2bc4U, 0x979cf3ca6cec5b5aU, >+ 0xbd8430bd08277231U, 0xece53cec4a314ebdU, 0x940f4613ae5ed136U, >+ 0xb913179899f68584U, 0xe757dd7ec07426e5U, 0x9096ea6f3848984fU, >+ 0xb4bca50b065abe63U, 0xe1ebce4dc7f16dfbU, 0x8d3360f09cf6e4bdU, >+ 0xb080392cc4349decU, 0xdca04777f541c567U, 0x89e42caaf9491b60U, >+ 0xac5d37d5b79b6239U, 0xd77485cb25823ac7U, 0x86a8d39ef77164bcU, >+ 0xa8530886b54dbdebU, 0xd267caa862a12d66U, 0x8380dea93da4bc60U, >+ 0xa46116538d0deb78U, 0xcd795be870516656U, 0x806bd9714632dff6U, >+ 0xa086cfcd97bf97f3U, 0xc8a883c0fdaf7df0U, 0xfad2a4b13d1b5d6cU, >+ 0x9cc3a6eec6311a63U, 0xc3f490aa77bd60fcU, 0xf4f1b4d515acb93bU, >+ 0x991711052d8bf3c5U, 0xbf5cd54678eef0b6U, 0xef340a98172aace4U, >+ 0x9580869f0e7aac0eU, 0xbae0a846d2195712U, 0xe998d258869facd7U, >+ 0x91ff83775423cc06U, 0xb67f6455292cbf08U, 0xe41f3d6a7377eecaU, >+ 0x8e938662882af53eU, 0xb23867fb2a35b28dU, 0xdec681f9f4c31f31U, >+ 0x8b3c113c38f9f37eU, 0xae0b158b4738705eU, 0xd98ddaee19068c76U, >+ 0x87f8a8d4cfa417c9U, 0xa9f6d30a038d1dbcU, 0xd47487cc8470652bU, >+ 0x84c8d4dfd2c63f3bU, 0xa5fb0a17c777cf09U, 0xcf79cc9db955c2ccU, >+ 0x81ac1fe293d599bfU, 0xa21727db38cb002fU, 0xca9cf1d206fdc03bU, >+ 0xfd442e4688bd304aU, 0x9e4a9cec15763e2eU, 0xc5dd44271ad3cdbaU, >+ 0xf7549530e188c128U, 0x9a94dd3e8cf578b9U, 0xc13a148e3032d6e7U, >+ 0xf18899b1bc3f8ca1U, 0x96f5600f15a7b7e5U, 0xbcb2b812db11a5deU, >+ 0xebdf661791d60f56U, 0x936b9fcebb25c995U, 0xb84687c269ef3bfbU, >+ 0xe65829b3046b0afaU, 0x8ff71a0fe2c2e6dcU, 0xb3f4e093db73a093U, >+ 0xe0f218b8d25088b8U, 0x8c974f7383725573U, 0xafbd2350644eeacfU, >+ 0xdbac6c247d62a583U, 0x894bc396ce5da772U, 0xab9eb47c81f5114fU, >+ 0xd686619ba27255a2U, 0x8613fd0145877585U, 0xa798fc4196e952e7U, >+ 0xd17f3b51fca3a7a0U, 0x82ef85133de648c4U, 0xa3ab66580d5fdaf5U, >+ 0xcc963fee10b7d1b3U, 0xffbbcfe994e5c61fU, 0x9fd561f1fd0f9bd3U, >+ 0xc7caba6e7c5382c8U, 0xf9bd690a1b68637bU, 0x9c1661a651213e2dU, >+ 0xc31bfa0fe5698db8U, 0xf3e2f893dec3f126U, 0x986ddb5c6b3a76b7U, >+ 0xbe89523386091465U, 0xee2ba6c0678b597fU, 0x94db483840b717efU, >+ 0xba121a4650e4ddebU, 0xe896a0d7e51e1566U, 0x915e2486ef32cd60U, >+ 0xb5b5ada8aaff80b8U, 0xe3231912d5bf60e6U, 0x8df5efabc5979c8fU, >+ 0xb1736b96b6fd83b3U, 0xddd0467c64bce4a0U, 0x8aa22c0dbef60ee4U, >+ 0xad4ab7112eb3929dU, 0xd89d64d57a607744U, 0x87625f056c7c4a8bU, >+ 0xa93af6c6c79b5d2dU, 0xd389b47879823479U, 0x843610cb4bf160cbU, >+ 0xa54394fe1eedb8feU, 0xce947a3da6a9273eU, 0x811ccc668829b887U, >+ 0xa163ff802a3426a8U, 0xc9bcff6034c13052U, 0xfc2c3f3841f17c67U, >+ 0x9d9ba7832936edc0U, 0xc5029163f384a931U, 0xf64335bcf065d37dU, >+ 0x99ea0196163fa42eU, 0xc06481fb9bcf8d39U, 0xf07da27a82c37088U, >+ 0x964e858c91ba2655U, 0xbbe226efb628afeaU, 0xeadab0aba3b2dbe5U, >+ 0x92c8ae6b464fc96fU, 0xb77ada0617e3bbcbU, 0xe55990879ddcaabdU, >+ 0x8f57fa54c2a9eab6U, 0xb32df8e9f3546564U, 0xdff9772470297ebdU, >+ 0x8bfbea76c619ef36U, 0xaefae51477a06b03U, 0xdab99e59958885c4U, >+ 0x88b402f7fd75539bU, 0xaae103b5fcd2a881U, 0xd59944a37c0752a2U, >+ 0x857fcae62d8493a5U, 0xa6dfbd9fb8e5b88eU, 0xd097ad07a71f26b2U, >+ 0x825ecc24c873782fU, 0xa2f67f2dfa90563bU, 0xcbb41ef979346bcaU, >+ 0xfea126b7d78186bcU, 0x9f24b832e6b0f436U, 0xc6ede63fa05d3143U, >+ 0xf8a95fcf88747d94U, 0x9b69dbe1b548ce7cU, 0xc24452da229b021bU, >+ 0xf2d56790ab41c2a2U, 0x97c560ba6b0919a5U, 0xbdb6b8e905cb600fU, >+ 0xed246723473e3813U, 0x9436c0760c86e30bU, 0xb94470938fa89bceU, >+ 0xe7958cb87392c2c2U, 0x90bd77f3483bb9b9U, 0xb4ecd5f01a4aa828U, >+ 0xe2280b6c20dd5232U, 0x8d590723948a535fU, 0xb0af48ec79ace837U, >+ 0xdcdb1b2798182244U, 0x8a08f0f8bf0f156bU, 0xac8b2d36eed2dac5U, >+ 0xd7adf884aa879177U, 0x86ccbb52ea94baeaU, 0xa87fea27a539e9a5U, >+ 0xd29fe4b18e88640eU, 0x83a3eeeef9153e89U, 0xa48ceaaab75a8e2bU, >+ 0xcdb02555653131b6U, 0x808e17555f3ebf11U, 0xa0b19d2ab70e6ed6U, >+ 0xc8de047564d20a8bU, 0xfb158592be068d2eU, 0x9ced737bb6c4183dU, >+ 0xc428d05aa4751e4cU, 0xf53304714d9265dfU, 0x993fe2c6d07b7fabU, >+ 0xbf8fdb78849a5f96U, 0xef73d256a5c0f77cU, 0x95a8637627989aadU, >+ 0xbb127c53b17ec159U, 0xe9d71b689dde71afU, 0x9226712162ab070dU, >+ 0xb6b00d69bb55c8d1U, 0xe45c10c42a2b3b05U, 0x8eb98a7a9a5b04e3U, >+ 0xb267ed1940f1c61cU, 0xdf01e85f912e37a3U, 0x8b61313bbabce2c6U, >+ 0xae397d8aa96c1b77U, 0xd9c7dced53c72255U, 0x881cea14545c7575U, >+ 0xaa242499697392d2U, 0xd4ad2dbfc3d07787U, 0x84ec3c97da624ab4U, >+ 0xa6274bbdd0fadd61U, 0xcfb11ead453994baU, 0x81ceb32c4b43fcf4U, >+ 0xa2425ff75e14fc31U, 0xcad2f7f5359a3b3eU, 0xfd87b5f28300ca0dU, >+ 0x9e74d1b791e07e48U, 0xc612062576589ddaU, 0xf79687aed3eec551U, >+ 0x9abe14cd44753b52U, 0xc16d9a0095928a27U, 0xf1c90080baf72cb1U, >+ 0x971da05074da7beeU, 0xbce5086492111aeaU, 0xec1e4a7db69561a5U, >+ 0x9392ee8e921d5d07U, 0xb877aa3236a4b449U, 0xe69594bec44de15bU, >+ 0x901d7cf73ab0acd9U, 0xb424dc35095cd80fU, 0xe12e13424bb40e13U, >+ 0x8cbccc096f5088cbU, 0xafebff0bcb24aafeU, 0xdbe6fecebdedd5beU, >+ 0x89705f4136b4a597U, 0xabcc77118461cefcU, 0xd6bf94d5e57a42bcU, >+ 0x8637bd05af6c69b5U, 0xa7c5ac471b478423U, 0xd1b71758e219652bU, >+ 0x83126e978d4fdf3bU, 0xa3d70a3d70a3d70aU, 0xccccccccccccccccU, >+ 0x8000000000000000U, 0xa000000000000000U, 0xc800000000000000U, >+ 0xfa00000000000000U, 0x9c40000000000000U, 0xc350000000000000U, >+ 0xf424000000000000U, 0x9896800000000000U, 0xbebc200000000000U, >+ 0xee6b280000000000U, 0x9502f90000000000U, 0xba43b74000000000U, >+ 0xe8d4a51000000000U, 0x9184e72a00000000U, 0xb5e620f480000000U, >+ 0xe35fa931a0000000U, 0x8e1bc9bf04000000U, 0xb1a2bc2ec5000000U, >+ 0xde0b6b3a76400000U, 0x8ac7230489e80000U, 0xad78ebc5ac620000U, >+ 0xd8d726b7177a8000U, 0x878678326eac9000U, 0xa968163f0a57b400U, >+ 0xd3c21bcecceda100U, 0x84595161401484a0U, 0xa56fa5b99019a5c8U, >+ 0xcecb8f27f4200f3aU, 0x813f3978f8940984U, 0xa18f07d736b90be5U, >+ 0xc9f2c9cd04674edeU, 0xfc6f7c4045812296U, 0x9dc5ada82b70b59dU, >+ 0xc5371912364ce305U, 0xf684df56c3e01bc6U, 0x9a130b963a6c115cU, >+ 0xc097ce7bc90715b3U, 0xf0bdc21abb48db20U, 0x96769950b50d88f4U, >+ 0xbc143fa4e250eb31U, 0xeb194f8e1ae525fdU, 0x92efd1b8d0cf37beU, >+ 0xb7abc627050305adU, 0xe596b7b0c643c719U, 0x8f7e32ce7bea5c6fU, >+ 0xb35dbf821ae4f38bU, 0xe0352f62a19e306eU, 0x8c213d9da502de45U, >+ 0xaf298d050e4395d6U, 0xdaf3f04651d47b4cU, 0x88d8762bf324cd0fU, >+ 0xab0e93b6efee0053U, 0xd5d238a4abe98068U, 0x85a36366eb71f041U, >+ 0xa70c3c40a64e6c51U, 0xd0cf4b50cfe20765U, 0x82818f1281ed449fU, >+ 0xa321f2d7226895c7U, 0xcbea6f8ceb02bb39U, 0xfee50b7025c36a08U, >+ 0x9f4f2726179a2245U, 0xc722f0ef9d80aad6U, 0xf8ebad2b84e0d58bU, >+ 0x9b934c3b330c8577U, 0xc2781f49ffcfa6d5U, 0xf316271c7fc3908aU, >+ 0x97edd871cfda3a56U, 0xbde94e8e43d0c8ecU, 0xed63a231d4c4fb27U, >+ 0x945e455f24fb1cf8U, 0xb975d6b6ee39e436U, 0xe7d34c64a9c85d44U, >+ 0x90e40fbeea1d3a4aU, 0xb51d13aea4a488ddU, 0xe264589a4dcdab14U, >+ 0x8d7eb76070a08aecU, 0xb0de65388cc8ada8U, 0xdd15fe86affad912U, >+ 0x8a2dbf142dfcc7abU, 0xacb92ed9397bf996U, 0xd7e77a8f87daf7fbU, >+ 0x86f0ac99b4e8dafdU, 0xa8acd7c0222311bcU, 0xd2d80db02aabd62bU, >+ 0x83c7088e1aab65dbU, 0xa4b8cab1a1563f52U, 0xcde6fd5e09abcf26U, >+ 0x80b05e5ac60b6178U, 0xa0dc75f1778e39d6U, 0xc913936dd571c84cU, >+ 0xfb5878494ace3a5fU, 0x9d174b2dcec0e47bU, 0xc45d1df942711d9aU, >+ 0xf5746577930d6500U, 0x9968bf6abbe85f20U, 0xbfc2ef456ae276e8U, >+ 0xefb3ab16c59b14a2U, 0x95d04aee3b80ece5U, 0xbb445da9ca61281fU, >+ 0xea1575143cf97226U, 0x924d692ca61be758U, 0xb6e0c377cfa2e12eU, >+ 0xe498f455c38b997aU, 0x8edf98b59a373fecU, 0xb2977ee300c50fe7U, >+ 0xdf3d5e9bc0f653e1U, 0x8b865b215899f46cU, 0xae67f1e9aec07187U, >+ 0xda01ee641a708de9U, 0x884134fe908658b2U, 0xaa51823e34a7eedeU, >+ 0xd4e5e2cdc1d1ea96U, 0x850fadc09923329eU, 0xa6539930bf6bff45U, >+ 0xcfe87f7cef46ff16U, 0x81f14fae158c5f6eU, 0xa26da3999aef7749U, >+ 0xcb090c8001ab551cU, 0xfdcb4fa002162a63U, 0x9e9f11c4014dda7eU, >+ 0xc646d63501a1511dU, 0xf7d88bc24209a565U, 0x9ae757596946075fU, >+ 0xc1a12d2fc3978937U, 0xf209787bb47d6b84U, 0x9745eb4d50ce6332U, >+ 0xbd176620a501fbffU, 0xec5d3fa8ce427affU, 0x93ba47c980e98cdfU, >+ 0xb8a8d9bbe123f017U, 0xe6d3102ad96cec1dU, 0x9043ea1ac7e41392U, >+ 0xb454e4a179dd1877U, 0xe16a1dc9d8545e94U, 0x8ce2529e2734bb1dU, >+ 0xb01ae745b101e9e4U, 0xdc21a1171d42645dU, 0x899504ae72497ebaU, >+ 0xabfa45da0edbde69U, 0xd6f8d7509292d603U, 0x865b86925b9bc5c2U, >+ 0xa7f26836f282b732U, 0xd1ef0244af2364ffU, 0x8335616aed761f1fU, >+ 0xa402b9c5a8d3a6e7U, 0xcd036837130890a1U, 0x802221226be55a64U, >+ 0xa02aa96b06deb0fdU, 0xc83553c5c8965d3dU, 0xfa42a8b73abbf48cU, >+ 0x9c69a97284b578d7U, 0xc38413cf25e2d70dU, 0xf46518c2ef5b8cd1U, >+ 0x98bf2f79d5993802U, 0xbeeefb584aff8603U, 0xeeaaba2e5dbf6784U, >+ 0x952ab45cfa97a0b2U, 0xba756174393d88dfU, 0xe912b9d1478ceb17U, >+ 0x91abb422ccb812eeU, 0xb616a12b7fe617aaU, 0xe39c49765fdf9d94U, >+ 0x8e41ade9fbebc27dU, 0xb1d219647ae6b31cU, 0xde469fbd99a05fe3U, >+ 0x8aec23d680043beeU, 0xada72ccc20054ae9U, 0xd910f7ff28069da4U, >+ 0x87aa9aff79042286U, 0xa99541bf57452b28U, 0xd3fa922f2d1675f2U, >+ 0x847c9b5d7c2e09b7U, 0xa59bc234db398c25U, 0xcf02b2c21207ef2eU, >+ 0x8161afb94b44f57dU, 0xa1ba1ba79e1632dcU, 0xca28a291859bbf93U, >+ 0xfcb2cb35e702af78U, 0x9defbf01b061adabU, 0xc56baec21c7a1916U, >+ 0xf6c69a72a3989f5bU, 0x9a3c2087a63f6399U, 0xc0cb28a98fcf3c7fU, >+ 0xf0fdf2d3f3c30b9fU, 0x969eb7c47859e743U, 0xbc4665b596706114U, >+ 0xeb57ff22fc0c7959U, 0x9316ff75dd87cbd8U, 0xb7dcbf5354e9beceU, >+ 0xe5d3ef282a242e81U, 0x8fa475791a569d10U, 0xb38d92d760ec4455U, >+ 0xe070f78d3927556aU, 0x8c469ab843b89562U, 0xaf58416654a6babbU, >+ 0xdb2e51bfe9d0696aU, 0x88fcf317f22241e2U, 0xab3c2fddeeaad25aU, >+ 0xd60b3bd56a5586f1U, 0x85c7056562757456U, 0xa738c6bebb12d16cU, >+ 0xd106f86e69d785c7U, 0x82a45b450226b39cU, 0xa34d721642b06084U, >+ 0xcc20ce9bd35c78a5U, 0xff290242c83396ceU, 0x9f79a169bd203e41U, >+ 0xc75809c42c684dd1U, 0xf92e0c3537826145U, 0x9bbcc7a142b17ccbU, >+ 0xc2abf989935ddbfeU, 0xf356f7ebf83552feU, 0x98165af37b2153deU, >+ 0xbe1bf1b059e9a8d6U, 0xeda2ee1c7064130cU, 0x9485d4d1c63e8be7U, >+ 0xb9a74a0637ce2ee1U, 0xe8111c87c5c1ba99U, 0x910ab1d4db9914a0U, >+ 0xb54d5e4a127f59c8U, 0xe2a0b5dc971f303aU, 0x8da471a9de737e24U, >+ 0xb10d8e1456105dadU, 0xdd50f1996b947518U, 0x8a5296ffe33cc92fU, >+ 0xace73cbfdc0bfb7bU, 0xd8210befd30efa5aU, 0x8714a775e3e95c78U, >+ 0xa8d9d1535ce3b396U, 0xd31045a8341ca07cU, 0x83ea2b892091e44dU, >+ 0xa4e4b66b68b65d60U, 0xce1de40642e3f4b9U, 0x80d2ae83e9ce78f3U, >+ 0xa1075a24e4421730U, 0xc94930ae1d529cfcU, 0xfb9b7cd9a4a7443cU, >+ 0x9d412e0806e88aa5U, 0xc491798a08a2ad4eU, 0xf5b5d7ec8acb58a2U, >+ 0x9991a6f3d6bf1765U, 0xbff610b0cc6edd3fU, 0xeff394dcff8a948eU, >+ 0x95f83d0a1fb69cd9U, 0xbb764c4ca7a4440fU, 0xea53df5fd18d5513U, >+ 0x92746b9be2f8552cU, 0xb7118682dbb66a77U, 0xe4d5e82392a40515U, >+ 0x8f05b1163ba6832dU, 0xb2c71d5bca9023f8U, 0xdf78e4b2bd342cf6U, >+ 0x8bab8eefb6409c1aU, 0xae9672aba3d0c320U, 0xda3c0f568cc4f3e8U, >+ 0x8865899617fb1871U, 0xaa7eebfb9df9de8dU, 0xd51ea6fa85785631U, >+ 0x8533285c936b35deU, 0xa67ff273b8460356U, 0xd01fef10a657842cU, >+ 0x8213f56a67f6b29bU, 0xa298f2c501f45f42U, 0xcb3f2f7642717713U, >+ 0xfe0efb53d30dd4d7U, 0x9ec95d1463e8a506U, 0xc67bb4597ce2ce48U, >+ 0xf81aa16fdc1b81daU, 0x9b10a4e5e9913128U, 0xc1d4ce1f63f57d72U, >+ 0xf24a01a73cf2dccfU, 0x976e41088617ca01U, 0xbd49d14aa79dbc82U, >+ 0xec9c459d51852ba2U, 0x93e1ab8252f33b45U, 0xb8da1662e7b00a17U, >+ 0xe7109bfba19c0c9dU, 0x906a617d450187e2U, 0xb484f9dc9641e9daU, >+ 0xe1a63853bbd26451U, 0x8d07e33455637eb2U, 0xb049dc016abc5e5fU, >+ 0xdc5c5301c56b75f7U, 0x89b9b3e11b6329baU, 0xac2820d9623bf429U, >+ 0xd732290fbacaf133U, 0x867f59a9d4bed6c0U, 0xa81f301449ee8c70U, >+ 0xd226fc195c6a2f8cU, 0x83585d8fd9c25db7U, 0xa42e74f3d032f525U, >+ 0xcd3a1230c43fb26fU, 0x80444b5e7aa7cf85U, 0xa0555e361951c366U, >+ 0xc86ab5c39fa63440U, 0xfa856334878fc150U, 0x9c935e00d4b9d8d2U, >+ 0xc3b8358109e84f07U, 0xf4a642e14c6262c8U, 0x98e7e9cccfbd7dbdU, >+ 0xbf21e44003acdd2cU, 0xeeea5d5004981478U, 0x95527a5202df0ccbU, >+ 0xbaa718e68396cffdU, 0xe950df20247c83fdU, 0x91d28b7416cdd27eU, >+ 0xb6472e511c81471dU, 0xe3d8f9e563a198e5U, 0x8e679c2f5e44ff8fU, >+}; >+ >+const int16_t kPower10ExponentTable[] = { >+ -1200, -1196, -1193, -1190, -1186, -1183, -1180, -1176, -1173, -1170, -1166, >+ -1163, -1160, -1156, -1153, -1150, -1146, -1143, -1140, -1136, -1133, -1130, >+ -1127, -1123, -1120, -1117, -1113, -1110, -1107, -1103, -1100, -1097, -1093, >+ -1090, -1087, -1083, -1080, -1077, -1073, -1070, -1067, -1063, -1060, -1057, >+ -1053, -1050, -1047, -1043, -1040, -1037, -1034, -1030, -1027, -1024, -1020, >+ -1017, -1014, -1010, -1007, -1004, -1000, -997, -994, -990, -987, -984, >+ -980, -977, -974, -970, -967, -964, -960, -957, -954, -950, -947, >+ -944, -940, -937, -934, -931, -927, -924, -921, -917, -914, -911, >+ -907, -904, -901, -897, -894, -891, -887, -884, -881, -877, -874, >+ -871, -867, -864, -861, -857, -854, -851, -847, -844, -841, -838, >+ -834, -831, -828, -824, -821, -818, -814, -811, -808, -804, -801, >+ -798, -794, -791, -788, -784, -781, -778, -774, -771, -768, -764, >+ -761, -758, -754, -751, -748, -744, -741, -738, -735, -731, -728, >+ -725, -721, -718, -715, -711, -708, -705, -701, -698, -695, -691, >+ -688, -685, -681, -678, -675, -671, -668, -665, -661, -658, -655, >+ -651, -648, -645, -642, -638, -635, -632, -628, -625, -622, -618, >+ -615, -612, -608, -605, -602, -598, -595, -592, -588, -585, -582, >+ -578, -575, -572, -568, -565, -562, -558, -555, -552, -549, -545, >+ -542, -539, -535, -532, -529, -525, -522, -519, -515, -512, -509, >+ -505, -502, -499, -495, -492, -489, -485, -482, -479, -475, -472, >+ -469, -465, -462, -459, -455, -452, -449, -446, -442, -439, -436, >+ -432, -429, -426, -422, -419, -416, -412, -409, -406, -402, -399, >+ -396, -392, -389, -386, -382, -379, -376, -372, -369, -366, -362, >+ -359, -356, -353, -349, -346, -343, -339, -336, -333, -329, -326, >+ -323, -319, -316, -313, -309, -306, -303, -299, -296, -293, -289, >+ -286, -283, -279, -276, -273, -269, -266, -263, -259, -256, -253, >+ -250, -246, -243, -240, -236, -233, -230, -226, -223, -220, -216, >+ -213, -210, -206, -203, -200, -196, -193, -190, -186, -183, -180, >+ -176, -173, -170, -166, -163, -160, -157, -153, -150, -147, -143, >+ -140, -137, -133, -130, -127, -123, -120, -117, -113, -110, -107, >+ -103, -100, -97, -93, -90, -87, -83, -80, -77, -73, -70, >+ -67, -63, -60, -57, -54, -50, -47, -44, -40, -37, -34, >+ -30, -27, -24, -20, -17, -14, -10, -7, -4, 0, 3, >+ 6, 10, 13, 16, 20, 23, 26, 30, 33, 36, 39, >+ 43, 46, 49, 53, 56, 59, 63, 66, 69, 73, 76, >+ 79, 83, 86, 89, 93, 96, 99, 103, 106, 109, 113, >+ 116, 119, 123, 126, 129, 132, 136, 139, 142, 146, 149, >+ 152, 156, 159, 162, 166, 169, 172, 176, 179, 182, 186, >+ 189, 192, 196, 199, 202, 206, 209, 212, 216, 219, 222, >+ 226, 229, 232, 235, 239, 242, 245, 249, 252, 255, 259, >+ 262, 265, 269, 272, 275, 279, 282, 285, 289, 292, 295, >+ 299, 302, 305, 309, 312, 315, 319, 322, 325, 328, 332, >+ 335, 338, 342, 345, 348, 352, 355, 358, 362, 365, 368, >+ 372, 375, 378, 382, 385, 388, 392, 395, 398, 402, 405, >+ 408, 412, 415, 418, 422, 425, 428, 431, 435, 438, 441, >+ 445, 448, 451, 455, 458, 461, 465, 468, 471, 475, 478, >+ 481, 485, 488, 491, 495, 498, 501, 505, 508, 511, 515, >+ 518, 521, 524, 528, 531, 534, 538, 541, 544, 548, 551, >+ 554, 558, 561, 564, 568, 571, 574, 578, 581, 584, 588, >+ 591, 594, 598, 601, 604, 608, 611, 614, 617, 621, 624, >+ 627, 631, 634, 637, 641, 644, 647, 651, 654, 657, 661, >+ 664, 667, 671, 674, 677, 681, 684, 687, 691, 694, 697, >+ 701, 704, 707, 711, 714, 717, 720, 724, 727, 730, 734, >+ 737, 740, 744, 747, 750, 754, 757, 760, 764, 767, 770, >+ 774, 777, 780, 784, 787, 790, 794, 797, 800, 804, 807, >+ 810, 813, 817, 820, 823, 827, 830, 833, 837, 840, 843, >+ 847, 850, 853, 857, 860, 863, 867, 870, 873, 877, 880, >+ 883, 887, 890, 893, 897, 900, 903, 907, 910, 913, 916, >+ 920, 923, 926, 930, 933, 936, 940, 943, 946, 950, 953, >+ 956, 960, >+}; >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.h >new file mode 100644 >index 00000000000..3e313679c96 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv.h >@@ -0,0 +1,115 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_STRINGS_CHARCONV_H_ >+#define ABSL_STRINGS_CHARCONV_H_ >+ >+#include <system_error> // NOLINT(build/c++11) >+ >+namespace absl { >+ >+// Workalike compatibilty version of std::chars_format from C++17. >+// >+// This is an bitfield enumerator which can be passed to absl::from_chars to >+// configure the std::string-to-float conversion. >+enum class chars_format { >+ scientific = 1, >+ fixed = 2, >+ hex = 4, >+ general = fixed | scientific, >+}; >+ >+// The return result of a std::string-to-number conversion. >+// >+// `ec` will be set to `invalid_argument` if a well-formed number was not found >+// at the start of the input range, `result_out_of_range` if a well-formed >+// number was found, but it was out of the representable range of the requested >+// type, or to std::errc() otherwise. >+// >+// If a well-formed number was found, `ptr` is set to one past the sequence of >+// characters that were successfully parsed. If none was found, `ptr` is set >+// to the `first` argument to from_chars. >+struct from_chars_result { >+ const char* ptr; >+ std::errc ec; >+}; >+ >+// Workalike compatibilty version of std::from_chars from C++17. Currently >+// this only supports the `double` and `float` types. >+// >+// This interface incorporates the proposed resolutions for library issues >+// DR 3800 and DR 3801. If these are adopted with different wording, >+// Abseil's behavior will change to match the standard. (The behavior most >+// likely to change is for DR 3801, which says what `value` will be set to in >+// the case of overflow and underflow. Code that wants to avoid possible >+// breaking changes in this area should not depend on `value` when the returned >+// from_chars_result indicates a range error.) >+// >+// Searches the range [first, last) for the longest matching pattern beginning >+// at `first` that represents a floating point number. If one is found, store >+// the result in `value`. >+// >+// The matching pattern format is almost the same as that of strtod(), except >+// that C locale is not respected, and an initial '+' character in the input >+// range will never be matched. >+// >+// If `fmt` is set, it must be one of the enumerator values of the chars_format. >+// (This is despite the fact that chars_format is a bitmask type.) If set to >+// `scientific`, a matching number must contain an exponent. If set to `fixed`, >+// then an exponent will never match. (For example, the std::string "1e5" will be >+// parsed as "1".) If set to `hex`, then a hexadecimal float is parsed in the >+// format that strtod() accepts, except that a "0x" prefix is NOT matched. >+// (In particular, in `hex` mode, the input "0xff" results in the largest >+// matching pattern "0".) >+absl::from_chars_result from_chars(const char* first, const char* last, >+ double& value, // NOLINT >+ chars_format fmt = chars_format::general); >+ >+absl::from_chars_result from_chars(const char* first, const char* last, >+ float& value, // NOLINT >+ chars_format fmt = chars_format::general); >+ >+// std::chars_format is specified as a bitmask type, which means the following >+// operations must be provided: >+inline constexpr chars_format operator&(chars_format lhs, chars_format rhs) { >+ return static_cast<chars_format>(static_cast<int>(lhs) & >+ static_cast<int>(rhs)); >+} >+inline constexpr chars_format operator|(chars_format lhs, chars_format rhs) { >+ return static_cast<chars_format>(static_cast<int>(lhs) | >+ static_cast<int>(rhs)); >+} >+inline constexpr chars_format operator^(chars_format lhs, chars_format rhs) { >+ return static_cast<chars_format>(static_cast<int>(lhs) ^ >+ static_cast<int>(rhs)); >+} >+inline constexpr chars_format operator~(chars_format arg) { >+ return static_cast<chars_format>(~static_cast<int>(arg)); >+} >+inline chars_format& operator&=(chars_format& lhs, chars_format rhs) { >+ lhs = lhs & rhs; >+ return lhs; >+} >+inline chars_format& operator|=(chars_format& lhs, chars_format rhs) { >+ lhs = lhs | rhs; >+ return lhs; >+} >+inline chars_format& operator^=(chars_format& lhs, chars_format rhs) { >+ lhs = lhs ^ rhs; >+ return lhs; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_CHARCONV_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_benchmark.cc >new file mode 100644 >index 00000000000..fd83f44e3d0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_benchmark.cc >@@ -0,0 +1,204 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/charconv.h" >+ >+#include <cstdlib> >+#include <cstring> >+#include <string> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+void BM_Strtod_Pi(benchmark::State& state) { >+ const char* pi = "3.14159"; >+ for (auto s : state) { >+ benchmark::DoNotOptimize(pi); >+ benchmark::DoNotOptimize(strtod(pi, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_Pi); >+ >+void BM_Absl_Pi(benchmark::State& state) { >+ const char* pi = "3.14159"; >+ const char* pi_end = pi + strlen(pi); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(pi); >+ double v; >+ absl::from_chars(pi, pi_end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_Pi); >+ >+void BM_Strtod_Pi_float(benchmark::State& state) { >+ const char* pi = "3.14159"; >+ for (auto s : state) { >+ benchmark::DoNotOptimize(pi); >+ benchmark::DoNotOptimize(strtof(pi, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_Pi_float); >+ >+void BM_Absl_Pi_float(benchmark::State& state) { >+ const char* pi = "3.14159"; >+ const char* pi_end = pi + strlen(pi); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(pi); >+ float v; >+ absl::from_chars(pi, pi_end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_Pi_float); >+ >+void BM_Strtod_HardLarge(benchmark::State& state) { >+ const char* num = "272104041512242479.e200"; >+ for (auto s : state) { >+ benchmark::DoNotOptimize(num); >+ benchmark::DoNotOptimize(strtod(num, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_HardLarge); >+ >+void BM_Absl_HardLarge(benchmark::State& state) { >+ const char* numstr = "272104041512242479.e200"; >+ const char* numstr_end = numstr + strlen(numstr); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(numstr); >+ double v; >+ absl::from_chars(numstr, numstr_end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_HardLarge); >+ >+void BM_Strtod_HardSmall(benchmark::State& state) { >+ const char* num = "94080055902682397.e-242"; >+ for (auto s : state) { >+ benchmark::DoNotOptimize(num); >+ benchmark::DoNotOptimize(strtod(num, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_HardSmall); >+ >+void BM_Absl_HardSmall(benchmark::State& state) { >+ const char* numstr = "94080055902682397.e-242"; >+ const char* numstr_end = numstr + strlen(numstr); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(numstr); >+ double v; >+ absl::from_chars(numstr, numstr_end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_HardSmall); >+ >+void BM_Strtod_HugeMantissa(benchmark::State& state) { >+ std::string huge(200, '3'); >+ const char* num = huge.c_str(); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(num); >+ benchmark::DoNotOptimize(strtod(num, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_HugeMantissa); >+ >+void BM_Absl_HugeMantissa(benchmark::State& state) { >+ std::string huge(200, '3'); >+ const char* num = huge.c_str(); >+ const char* num_end = num + 200; >+ for (auto s : state) { >+ benchmark::DoNotOptimize(num); >+ double v; >+ absl::from_chars(num, num_end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_HugeMantissa); >+ >+std::string MakeHardCase(int length) { >+ // The number 1.1521...e-297 is exactly halfway between 12345 * 2**-1000 and >+ // the next larger representable number. The digits of this number are in >+ // the std::string below. >+ const std::string digits = >+ "1." >+ "152113937042223790993097181572444900347587985074226836242307364987727724" >+ "831384300183638649152607195040591791364113930628852279348613864894524591" >+ "272746490313676832900762939595690019745859128071117417798540258114233761" >+ "012939937017879509401007964861774960297319002612457273148497158989073482" >+ "171377406078223015359818300988676687994537274548940612510414856761641652" >+ "513434981938564294004070500716200446656421722229202383105446378511678258" >+ "370570631774499359748259931676320916632111681001853983492795053244971606" >+ "922718923011680846577744433974087653954904214152517799883551075537146316" >+ "168973685866425605046988661997658648354773076621610279716804960009043764" >+ "038392994055171112475093876476783502487512538082706095923790634572014823" >+ "78877699375152587890625" + >+ std::string(5000, '0'); >+ // generate the hard cases on either side for the given length. >+ // Lengths between 3 and 1000 are reasonable. >+ return digits.substr(0, length) + "1e-297"; >+} >+ >+void BM_Strtod_Big_And_Difficult(benchmark::State& state) { >+ std::string testcase = MakeHardCase(state.range(0)); >+ const char* begin = testcase.c_str(); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(begin); >+ benchmark::DoNotOptimize(strtod(begin, nullptr)); >+ } >+} >+BENCHMARK(BM_Strtod_Big_And_Difficult)->Range(3, 5000); >+ >+void BM_Absl_Big_And_Difficult(benchmark::State& state) { >+ std::string testcase = MakeHardCase(state.range(0)); >+ const char* begin = testcase.c_str(); >+ const char* end = begin + testcase.size(); >+ for (auto s : state) { >+ benchmark::DoNotOptimize(begin); >+ double v; >+ absl::from_chars(begin, end, v); >+ benchmark::DoNotOptimize(v); >+ } >+} >+BENCHMARK(BM_Absl_Big_And_Difficult)->Range(3, 5000); >+ >+} // namespace >+ >+// ------------------------------------------------------------------------ >+// Benchmark Time CPU Iterations >+// ------------------------------------------------------------------------ >+// BM_Strtod_Pi 96 ns 96 ns 6337454 >+// BM_Absl_Pi 35 ns 35 ns 20031996 >+// BM_Strtod_Pi_float 91 ns 91 ns 7745851 >+// BM_Absl_Pi_float 35 ns 35 ns 20430298 >+// BM_Strtod_HardLarge 133 ns 133 ns 5288341 >+// BM_Absl_HardLarge 181 ns 181 ns 3855615 >+// BM_Strtod_HardSmall 279 ns 279 ns 2517243 >+// BM_Absl_HardSmall 287 ns 287 ns 2458744 >+// BM_Strtod_HugeMantissa 433 ns 433 ns 1604293 >+// BM_Absl_HugeMantissa 160 ns 160 ns 4403671 >+// BM_Strtod_Big_And_Difficult/3 236 ns 236 ns 2942496 >+// BM_Strtod_Big_And_Difficult/8 232 ns 232 ns 2983796 >+// BM_Strtod_Big_And_Difficult/64 437 ns 437 ns 1591951 >+// BM_Strtod_Big_And_Difficult/512 1738 ns 1738 ns 402519 >+// BM_Strtod_Big_And_Difficult/4096 3943 ns 3943 ns 176128 >+// BM_Strtod_Big_And_Difficult/5000 4397 ns 4397 ns 157878 >+// BM_Absl_Big_And_Difficult/3 39 ns 39 ns 17799583 >+// BM_Absl_Big_And_Difficult/8 43 ns 43 ns 16096859 >+// BM_Absl_Big_And_Difficult/64 550 ns 550 ns 1259717 >+// BM_Absl_Big_And_Difficult/512 4167 ns 4167 ns 171414 >+// BM_Absl_Big_And_Difficult/4096 9160 ns 9159 ns 76297 >+// BM_Absl_Big_And_Difficult/5000 9738 ns 9738 ns 70140 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_test.cc >new file mode 100644 >index 00000000000..f8d71cc6c44 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/charconv_test.cc >@@ -0,0 +1,766 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/charconv.h" >+ >+#include <cstdlib> >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/strings/str_cat.h" >+ >+#ifdef _MSC_FULL_VER >+#define ABSL_COMPILER_DOES_EXACT_ROUNDING 0 >+#define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 0 >+#else >+#define ABSL_COMPILER_DOES_EXACT_ROUNDING 1 >+#define ABSL_STRTOD_HANDLES_NAN_CORRECTLY 1 >+#endif >+ >+namespace { >+ >+#if ABSL_COMPILER_DOES_EXACT_ROUNDING >+ >+// Tests that the given std::string is accepted by absl::from_chars, and that it >+// converts exactly equal to the given number. >+void TestDoubleParse(absl::string_view str, double expected_number) { >+ SCOPED_TRACE(str); >+ double actual_number = 0.0; >+ absl::from_chars_result result = >+ absl::from_chars(str.data(), str.data() + str.length(), actual_number); >+ EXPECT_EQ(result.ec, std::errc()); >+ EXPECT_EQ(result.ptr, str.data() + str.length()); >+ EXPECT_EQ(actual_number, expected_number); >+} >+ >+void TestFloatParse(absl::string_view str, float expected_number) { >+ SCOPED_TRACE(str); >+ float actual_number = 0.0; >+ absl::from_chars_result result = >+ absl::from_chars(str.data(), str.data() + str.length(), actual_number); >+ EXPECT_EQ(result.ec, std::errc()); >+ EXPECT_EQ(result.ptr, str.data() + str.length()); >+ EXPECT_EQ(actual_number, expected_number); >+} >+ >+// Tests that the given double or single precision floating point literal is >+// parsed correctly by absl::from_chars. >+// >+// These convenience macros assume that the C++ compiler being used also does >+// fully correct decimal-to-binary conversions. >+#define FROM_CHARS_TEST_DOUBLE(number) \ >+ { \ >+ TestDoubleParse(#number, number); \ >+ TestDoubleParse("-" #number, -number); \ >+ } >+ >+#define FROM_CHARS_TEST_FLOAT(number) \ >+ { \ >+ TestFloatParse(#number, number##f); \ >+ TestFloatParse("-" #number, -number##f); \ >+ } >+ >+TEST(FromChars, NearRoundingCases) { >+ // Cases from "A Program for Testing IEEE Decimal-Binary Conversion" >+ // by Vern Paxson. >+ >+ // Forms that should round towards zero. (These are the hardest cases for >+ // each decimal mantissa size.) >+ FROM_CHARS_TEST_DOUBLE(5.e125); >+ FROM_CHARS_TEST_DOUBLE(69.e267); >+ FROM_CHARS_TEST_DOUBLE(999.e-026); >+ FROM_CHARS_TEST_DOUBLE(7861.e-034); >+ FROM_CHARS_TEST_DOUBLE(75569.e-254); >+ FROM_CHARS_TEST_DOUBLE(928609.e-261); >+ FROM_CHARS_TEST_DOUBLE(9210917.e080); >+ FROM_CHARS_TEST_DOUBLE(84863171.e114); >+ FROM_CHARS_TEST_DOUBLE(653777767.e273); >+ FROM_CHARS_TEST_DOUBLE(5232604057.e-298); >+ FROM_CHARS_TEST_DOUBLE(27235667517.e-109); >+ FROM_CHARS_TEST_DOUBLE(653532977297.e-123); >+ FROM_CHARS_TEST_DOUBLE(3142213164987.e-294); >+ FROM_CHARS_TEST_DOUBLE(46202199371337.e-072); >+ FROM_CHARS_TEST_DOUBLE(231010996856685.e-073); >+ FROM_CHARS_TEST_DOUBLE(9324754620109615.e212); >+ FROM_CHARS_TEST_DOUBLE(78459735791271921.e049); >+ FROM_CHARS_TEST_DOUBLE(272104041512242479.e200); >+ FROM_CHARS_TEST_DOUBLE(6802601037806061975.e198); >+ FROM_CHARS_TEST_DOUBLE(20505426358836677347.e-221); >+ FROM_CHARS_TEST_DOUBLE(836168422905420598437.e-234); >+ FROM_CHARS_TEST_DOUBLE(4891559871276714924261.e222); >+ FROM_CHARS_TEST_FLOAT(5.e-20); >+ FROM_CHARS_TEST_FLOAT(67.e14); >+ FROM_CHARS_TEST_FLOAT(985.e15); >+ FROM_CHARS_TEST_FLOAT(7693.e-42); >+ FROM_CHARS_TEST_FLOAT(55895.e-16); >+ FROM_CHARS_TEST_FLOAT(996622.e-44); >+ FROM_CHARS_TEST_FLOAT(7038531.e-32); >+ FROM_CHARS_TEST_FLOAT(60419369.e-46); >+ FROM_CHARS_TEST_FLOAT(702990899.e-20); >+ FROM_CHARS_TEST_FLOAT(6930161142.e-48); >+ FROM_CHARS_TEST_FLOAT(25933168707.e-13); >+ FROM_CHARS_TEST_FLOAT(596428896559.e20); >+ >+ // Similarly, forms that should round away from zero. >+ FROM_CHARS_TEST_DOUBLE(9.e-265); >+ FROM_CHARS_TEST_DOUBLE(85.e-037); >+ FROM_CHARS_TEST_DOUBLE(623.e100); >+ FROM_CHARS_TEST_DOUBLE(3571.e263); >+ FROM_CHARS_TEST_DOUBLE(81661.e153); >+ FROM_CHARS_TEST_DOUBLE(920657.e-023); >+ FROM_CHARS_TEST_DOUBLE(4603285.e-024); >+ FROM_CHARS_TEST_DOUBLE(87575437.e-309); >+ FROM_CHARS_TEST_DOUBLE(245540327.e122); >+ FROM_CHARS_TEST_DOUBLE(6138508175.e120); >+ FROM_CHARS_TEST_DOUBLE(83356057653.e193); >+ FROM_CHARS_TEST_DOUBLE(619534293513.e124); >+ FROM_CHARS_TEST_DOUBLE(2335141086879.e218); >+ FROM_CHARS_TEST_DOUBLE(36167929443327.e-159); >+ FROM_CHARS_TEST_DOUBLE(609610927149051.e-255); >+ FROM_CHARS_TEST_DOUBLE(3743626360493413.e-165); >+ FROM_CHARS_TEST_DOUBLE(94080055902682397.e-242); >+ FROM_CHARS_TEST_DOUBLE(899810892172646163.e283); >+ FROM_CHARS_TEST_DOUBLE(7120190517612959703.e120); >+ FROM_CHARS_TEST_DOUBLE(25188282901709339043.e-252); >+ FROM_CHARS_TEST_DOUBLE(308984926168550152811.e-052); >+ FROM_CHARS_TEST_DOUBLE(6372891218502368041059.e064); >+ FROM_CHARS_TEST_FLOAT(3.e-23); >+ FROM_CHARS_TEST_FLOAT(57.e18); >+ FROM_CHARS_TEST_FLOAT(789.e-35); >+ FROM_CHARS_TEST_FLOAT(2539.e-18); >+ FROM_CHARS_TEST_FLOAT(76173.e28); >+ FROM_CHARS_TEST_FLOAT(887745.e-11); >+ FROM_CHARS_TEST_FLOAT(5382571.e-37); >+ FROM_CHARS_TEST_FLOAT(82381273.e-35); >+ FROM_CHARS_TEST_FLOAT(750486563.e-38); >+ FROM_CHARS_TEST_FLOAT(3752432815.e-39); >+ FROM_CHARS_TEST_FLOAT(75224575729.e-45); >+ FROM_CHARS_TEST_FLOAT(459926601011.e15); >+} >+ >+#undef FROM_CHARS_TEST_DOUBLE >+#undef FROM_CHARS_TEST_FLOAT >+#endif >+ >+float ToFloat(absl::string_view s) { >+ float f; >+ absl::from_chars(s.data(), s.data() + s.size(), f); >+ return f; >+} >+ >+double ToDouble(absl::string_view s) { >+ double d; >+ absl::from_chars(s.data(), s.data() + s.size(), d); >+ return d; >+} >+ >+// A duplication of the test cases in "NearRoundingCases" above, but with >+// expected values expressed with integers, using ldexp/ldexpf. These test >+// cases will work even on compilers that do not accurately round floating point >+// literals. >+TEST(FromChars, NearRoundingCasesExplicit) { >+ EXPECT_EQ(ToDouble("5.e125"), ldexp(6653062250012735, 365)); >+ EXPECT_EQ(ToDouble("69.e267"), ldexp(4705683757438170, 841)); >+ EXPECT_EQ(ToDouble("999.e-026"), ldexp(6798841691080350, -129)); >+ EXPECT_EQ(ToDouble("7861.e-034"), ldexp(8975675289889240, -153)); >+ EXPECT_EQ(ToDouble("75569.e-254"), ldexp(6091718967192243, -880)); >+ EXPECT_EQ(ToDouble("928609.e-261"), ldexp(7849264900213743, -900)); >+ EXPECT_EQ(ToDouble("9210917.e080"), ldexp(8341110837370930, 236)); >+ EXPECT_EQ(ToDouble("84863171.e114"), ldexp(4625202867375927, 353)); >+ EXPECT_EQ(ToDouble("653777767.e273"), ldexp(5068902999763073, 884)); >+ EXPECT_EQ(ToDouble("5232604057.e-298"), ldexp(5741343011915040, -1010)); >+ EXPECT_EQ(ToDouble("27235667517.e-109"), ldexp(6707124626673586, -380)); >+ EXPECT_EQ(ToDouble("653532977297.e-123"), ldexp(7078246407265384, -422)); >+ EXPECT_EQ(ToDouble("3142213164987.e-294"), ldexp(8219991337640559, -988)); >+ EXPECT_EQ(ToDouble("46202199371337.e-072"), ldexp(5224462102115359, -246)); >+ EXPECT_EQ(ToDouble("231010996856685.e-073"), ldexp(5224462102115359, -247)); >+ EXPECT_EQ(ToDouble("9324754620109615.e212"), ldexp(5539753864394442, 705)); >+ EXPECT_EQ(ToDouble("78459735791271921.e049"), ldexp(8388176519442766, 166)); >+ EXPECT_EQ(ToDouble("272104041512242479.e200"), ldexp(5554409530847367, 670)); >+ EXPECT_EQ(ToDouble("6802601037806061975.e198"), ldexp(5554409530847367, 668)); >+ EXPECT_EQ(ToDouble("20505426358836677347.e-221"), >+ ldexp(4524032052079546, -722)); >+ EXPECT_EQ(ToDouble("836168422905420598437.e-234"), >+ ldexp(5070963299887562, -760)); >+ EXPECT_EQ(ToDouble("4891559871276714924261.e222"), >+ ldexp(6452687840519111, 757)); >+ EXPECT_EQ(ToFloat("5.e-20"), ldexpf(15474250, -88)); >+ EXPECT_EQ(ToFloat("67.e14"), ldexpf(12479722, 29)); >+ EXPECT_EQ(ToFloat("985.e15"), ldexpf(14333636, 36)); >+ EXPECT_EQ(ToFloat("7693.e-42"), ldexpf(10979816, -150)); >+ EXPECT_EQ(ToFloat("55895.e-16"), ldexpf(12888509, -61)); >+ EXPECT_EQ(ToFloat("996622.e-44"), ldexpf(14224264, -150)); >+ EXPECT_EQ(ToFloat("7038531.e-32"), ldexpf(11420669, -107)); >+ EXPECT_EQ(ToFloat("60419369.e-46"), ldexpf(8623340, -150)); >+ EXPECT_EQ(ToFloat("702990899.e-20"), ldexpf(16209866, -61)); >+ EXPECT_EQ(ToFloat("6930161142.e-48"), ldexpf(9891056, -150)); >+ EXPECT_EQ(ToFloat("25933168707.e-13"), ldexpf(11138211, -32)); >+ EXPECT_EQ(ToFloat("596428896559.e20"), ldexpf(12333860, 82)); >+ >+ >+ EXPECT_EQ(ToDouble("9.e-265"), ldexp(8168427841980010, -930)); >+ EXPECT_EQ(ToDouble("85.e-037"), ldexp(6360455125664090, -169)); >+ EXPECT_EQ(ToDouble("623.e100"), ldexp(6263531988747231, 289)); >+ EXPECT_EQ(ToDouble("3571.e263"), ldexp(6234526311072170, 833)); >+ EXPECT_EQ(ToDouble("81661.e153"), ldexp(6696636728760206, 472)); >+ EXPECT_EQ(ToDouble("920657.e-023"), ldexp(5975405561110124, -109)); >+ EXPECT_EQ(ToDouble("4603285.e-024"), ldexp(5975405561110124, -110)); >+ EXPECT_EQ(ToDouble("87575437.e-309"), ldexp(8452160731874668, -1053)); >+ EXPECT_EQ(ToDouble("245540327.e122"), ldexp(4985336549131723, 381)); >+ EXPECT_EQ(ToDouble("6138508175.e120"), ldexp(4985336549131723, 379)); >+ EXPECT_EQ(ToDouble("83356057653.e193"), ldexp(5986732817132056, 625)); >+ EXPECT_EQ(ToDouble("619534293513.e124"), ldexp(4798406992060657, 399)); >+ EXPECT_EQ(ToDouble("2335141086879.e218"), ldexp(5419088166961646, 713)); >+ EXPECT_EQ(ToDouble("36167929443327.e-159"), ldexp(8135819834632444, -536)); >+ EXPECT_EQ(ToDouble("609610927149051.e-255"), ldexp(4576664294594737, -850)); >+ EXPECT_EQ(ToDouble("3743626360493413.e-165"), ldexp(6898586531774201, -549)); >+ EXPECT_EQ(ToDouble("94080055902682397.e-242"), ldexp(6273271706052298, -800)); >+ EXPECT_EQ(ToDouble("899810892172646163.e283"), ldexp(7563892574477827, 947)); >+ EXPECT_EQ(ToDouble("7120190517612959703.e120"), ldexp(5385467232557565, 409)); >+ EXPECT_EQ(ToDouble("25188282901709339043.e-252"), >+ ldexp(5635662608542340, -825)); >+ EXPECT_EQ(ToDouble("308984926168550152811.e-052"), >+ ldexp(5644774693823803, -157)); >+ EXPECT_EQ(ToDouble("6372891218502368041059.e064"), >+ ldexp(4616868614322430, 233)); >+ >+ EXPECT_EQ(ToFloat("3.e-23"), ldexpf(9507380, -98)); >+ EXPECT_EQ(ToFloat("57.e18"), ldexpf(12960300, 42)); >+ EXPECT_EQ(ToFloat("789.e-35"), ldexpf(10739312, -130)); >+ EXPECT_EQ(ToFloat("2539.e-18"), ldexpf(11990089, -72)); >+ EXPECT_EQ(ToFloat("76173.e28"), ldexpf(9845130, 86)); >+ EXPECT_EQ(ToFloat("887745.e-11"), ldexpf(9760860, -40)); >+ EXPECT_EQ(ToFloat("5382571.e-37"), ldexpf(11447463, -124)); >+ EXPECT_EQ(ToFloat("82381273.e-35"), ldexpf(8554961, -113)); >+ EXPECT_EQ(ToFloat("750486563.e-38"), ldexpf(9975678, -120)); >+ EXPECT_EQ(ToFloat("3752432815.e-39"), ldexpf(9975678, -121)); >+ EXPECT_EQ(ToFloat("75224575729.e-45"), ldexpf(13105970, -137)); >+ EXPECT_EQ(ToFloat("459926601011.e15"), ldexpf(12466336, 65)); >+} >+ >+// Common test logic for converting a std::string which lies exactly halfway between >+// two target floats. >+// >+// mantissa and exponent represent the precise value between two floating point >+// numbers, `expected_low` and `expected_high`. The floating point >+// representation to parse in `StrCat(mantissa, "e", exponent)`. >+// >+// This function checks that an input just slightly less than the exact value >+// is rounded down to `expected_low`, and an input just slightly greater than >+// the exact value is rounded up to `expected_high`. >+// >+// The exact value should round to `expected_half`, which must be either >+// `expected_low` or `expected_high`. >+template <typename FloatType> >+void TestHalfwayValue(const std::string& mantissa, int exponent, >+ FloatType expected_low, FloatType expected_high, >+ FloatType expected_half) { >+ std::string low_rep = mantissa; >+ low_rep[low_rep.size() - 1] -= 1; >+ absl::StrAppend(&low_rep, std::string(1000, '9'), "e", exponent); >+ >+ FloatType actual_low = 0; >+ absl::from_chars(low_rep.data(), low_rep.data() + low_rep.size(), actual_low); >+ EXPECT_EQ(expected_low, actual_low); >+ >+ std::string high_rep = absl::StrCat(mantissa, std::string(1000, '0'), "1e", exponent); >+ FloatType actual_high = 0; >+ absl::from_chars(high_rep.data(), high_rep.data() + high_rep.size(), >+ actual_high); >+ EXPECT_EQ(expected_high, actual_high); >+ >+ std::string halfway_rep = absl::StrCat(mantissa, "e", exponent); >+ FloatType actual_half = 0; >+ absl::from_chars(halfway_rep.data(), halfway_rep.data() + halfway_rep.size(), >+ actual_half); >+ EXPECT_EQ(expected_half, actual_half); >+} >+ >+TEST(FromChars, DoubleRounding) { >+ const double zero = 0.0; >+ const double first_subnormal = nextafter(zero, 1.0); >+ const double second_subnormal = nextafter(first_subnormal, 1.0); >+ >+ const double first_normal = DBL_MIN; >+ const double last_subnormal = nextafter(first_normal, 0.0); >+ const double second_normal = nextafter(first_normal, 1.0); >+ >+ const double last_normal = DBL_MAX; >+ const double penultimate_normal = nextafter(last_normal, 0.0); >+ >+ // Various test cases for numbers between two representable floats. Each >+ // call to TestHalfwayValue tests a number just below and just above the >+ // halfway point, as well as the number exactly between them. >+ >+ // Test between zero and first_subnormal. Round-to-even tie rounds down. >+ TestHalfwayValue( >+ "2." >+ "470328229206232720882843964341106861825299013071623822127928412503377536" >+ "351043759326499181808179961898982823477228588654633283551779698981993873" >+ "980053909390631503565951557022639229085839244910518443593180284993653615" >+ "250031937045767824921936562366986365848075700158576926990370631192827955" >+ "855133292783433840935197801553124659726357957462276646527282722005637400" >+ "648549997709659947045402082816622623785739345073633900796776193057750674" >+ "017632467360096895134053553745851666113422376667860416215968046191446729" >+ "184030053005753084904876539171138659164623952491262365388187963623937328" >+ "042389101867234849766823508986338858792562830275599565752445550725518931" >+ "369083625477918694866799496832404970582102851318545139621383772282614543" >+ "7693412532098591327667236328125", >+ -324, zero, first_subnormal, zero); >+ >+ // first_subnormal and second_subnormal. Round-to-even tie rounds up. >+ TestHalfwayValue( >+ "7." >+ "410984687618698162648531893023320585475897039214871466383785237510132609" >+ "053131277979497545424539885696948470431685765963899850655339096945981621" >+ "940161728171894510697854671067917687257517734731555330779540854980960845" >+ "750095811137303474765809687100959097544227100475730780971111893578483867" >+ "565399878350301522805593404659373979179073872386829939581848166016912201" >+ "945649993128979841136206248449867871357218035220901702390328579173252022" >+ "052897402080290685402160661237554998340267130003581248647904138574340187" >+ "552090159017259254714629617513415977493871857473787096164563890871811984" >+ "127167305601704549300470526959016576377688490826798697257336652176556794" >+ "107250876433756084600398490497214911746308553955635418864151316847843631" >+ "3080237596295773983001708984375", >+ -324, first_subnormal, second_subnormal, second_subnormal); >+ >+ // last_subnormal and first_normal. Round-to-even tie rounds up. >+ TestHalfwayValue( >+ "2." >+ "225073858507201136057409796709131975934819546351645648023426109724822222" >+ "021076945516529523908135087914149158913039621106870086438694594645527657" >+ "207407820621743379988141063267329253552286881372149012981122451451889849" >+ "057222307285255133155755015914397476397983411801999323962548289017107081" >+ "850690630666655994938275772572015763062690663332647565300009245888316433" >+ "037779791869612049497390377829704905051080609940730262937128958950003583" >+ "799967207254304360284078895771796150945516748243471030702609144621572289" >+ "880258182545180325707018860872113128079512233426288368622321503775666622" >+ "503982534335974568884423900265498198385487948292206894721689831099698365" >+ "846814022854243330660339850886445804001034933970427567186443383770486037" >+ "86162277173854562306587467901408672332763671875", >+ -308, last_subnormal, first_normal, first_normal); >+ >+ // first_normal and second_normal. Round-to-even tie rounds down. >+ TestHalfwayValue( >+ "2." >+ "225073858507201630123055637955676152503612414573018013083228724049586647" >+ "606759446192036794116886953213985520549032000903434781884412325572184367" >+ "563347617020518175998922941393629966742598285899994830148971433555578567" >+ "693279306015978183162142425067962460785295885199272493577688320732492479" >+ "924816869232247165964934329258783950102250973957579510571600738343645738" >+ "494324192997092179207389919761694314131497173265255020084997973676783743" >+ "155205818804439163810572367791175177756227497413804253387084478193655533" >+ "073867420834526162513029462022730109054820067654020201547112002028139700" >+ "141575259123440177362244273712468151750189745559978653234255886219611516" >+ "335924167958029604477064946470184777360934300451421683607013647479513962" >+ "13837722826145437693412532098591327667236328125", >+ -308, first_normal, second_normal, first_normal); >+ >+ // penultimate_normal and last_normal. Round-to-even rounds down. >+ TestHalfwayValue( >+ "1." >+ "797693134862315608353258760581052985162070023416521662616611746258695532" >+ "672923265745300992879465492467506314903358770175220871059269879629062776" >+ "047355692132901909191523941804762171253349609463563872612866401980290377" >+ "995141836029815117562837277714038305214839639239356331336428021390916694" >+ "57927874464075218944", >+ 308, penultimate_normal, last_normal, penultimate_normal); >+} >+ >+// Same test cases as DoubleRounding, now with new and improved Much Smaller >+// Precision! >+TEST(FromChars, FloatRounding) { >+ const float zero = 0.0; >+ const float first_subnormal = nextafterf(zero, 1.0); >+ const float second_subnormal = nextafterf(first_subnormal, 1.0); >+ >+ const float first_normal = FLT_MIN; >+ const float last_subnormal = nextafterf(first_normal, 0.0); >+ const float second_normal = nextafterf(first_normal, 1.0); >+ >+ const float last_normal = FLT_MAX; >+ const float penultimate_normal = nextafterf(last_normal, 0.0); >+ >+ // Test between zero and first_subnormal. Round-to-even tie rounds down. >+ TestHalfwayValue( >+ "7." >+ "006492321624085354618647916449580656401309709382578858785341419448955413" >+ "42930300743319094181060791015625", >+ -46, zero, first_subnormal, zero); >+ >+ // first_subnormal and second_subnormal. Round-to-even tie rounds up. >+ TestHalfwayValue( >+ "2." >+ "101947696487225606385594374934874196920392912814773657635602425834686624" >+ "028790902229957282543182373046875", >+ -45, first_subnormal, second_subnormal, second_subnormal); >+ >+ // last_subnormal and first_normal. Round-to-even tie rounds up. >+ TestHalfwayValue( >+ "1." >+ "175494280757364291727882991035766513322858992758990427682963118425003064" >+ "9651730385585324256680905818939208984375", >+ -38, last_subnormal, first_normal, first_normal); >+ >+ // first_normal and second_normal. Round-to-even tie rounds down. >+ TestHalfwayValue( >+ "1." >+ "175494420887210724209590083408724842314472120785184615334540294131831453" >+ "9442813071445925743319094181060791015625", >+ -38, first_normal, second_normal, first_normal); >+ >+ // penultimate_normal and last_normal. Round-to-even rounds down. >+ TestHalfwayValue("3.40282336497324057985868971510891282432", 38, >+ penultimate_normal, last_normal, penultimate_normal); >+} >+ >+TEST(FromChars, Underflow) { >+ // Check that underflow is handled correctly, according to the specification >+ // in DR 3081. >+ double d; >+ float f; >+ absl::from_chars_result result; >+ >+ std::string negative_underflow = "-1e-1000"; >+ const char* begin = negative_underflow.data(); >+ const char* end = begin + negative_underflow.size(); >+ d = 100.0; >+ result = absl::from_chars(begin, end, d); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_TRUE(std::signbit(d)); // negative >+ EXPECT_GE(d, -std::numeric_limits<double>::min()); >+ f = 100.0; >+ result = absl::from_chars(begin, end, f); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_TRUE(std::signbit(f)); // negative >+ EXPECT_GE(f, -std::numeric_limits<float>::min()); >+ >+ std::string positive_underflow = "1e-1000"; >+ begin = positive_underflow.data(); >+ end = begin + positive_underflow.size(); >+ d = -100.0; >+ result = absl::from_chars(begin, end, d); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_FALSE(std::signbit(d)); // positive >+ EXPECT_LE(d, std::numeric_limits<double>::min()); >+ f = -100.0; >+ result = absl::from_chars(begin, end, f); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_FALSE(std::signbit(f)); // positive >+ EXPECT_LE(f, std::numeric_limits<float>::min()); >+} >+ >+TEST(FromChars, Overflow) { >+ // Check that overflow is handled correctly, according to the specification >+ // in DR 3081. >+ double d; >+ float f; >+ absl::from_chars_result result; >+ >+ std::string negative_overflow = "-1e1000"; >+ const char* begin = negative_overflow.data(); >+ const char* end = begin + negative_overflow.size(); >+ d = 100.0; >+ result = absl::from_chars(begin, end, d); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_TRUE(std::signbit(d)); // negative >+ EXPECT_EQ(d, -std::numeric_limits<double>::max()); >+ f = 100.0; >+ result = absl::from_chars(begin, end, f); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_TRUE(std::signbit(f)); // negative >+ EXPECT_EQ(f, -std::numeric_limits<float>::max()); >+ >+ std::string positive_overflow = "1e1000"; >+ begin = positive_overflow.data(); >+ end = begin + positive_overflow.size(); >+ d = -100.0; >+ result = absl::from_chars(begin, end, d); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_FALSE(std::signbit(d)); // positive >+ EXPECT_EQ(d, std::numeric_limits<double>::max()); >+ f = -100.0; >+ result = absl::from_chars(begin, end, f); >+ EXPECT_EQ(result.ptr, end); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_FALSE(std::signbit(f)); // positive >+ EXPECT_EQ(f, std::numeric_limits<float>::max()); >+} >+ >+TEST(FromChars, ReturnValuePtr) { >+ // Check that `ptr` points one past the number scanned, even if that number >+ // is not representable. >+ double d; >+ absl::from_chars_result result; >+ >+ std::string normal = "3.14@#$%@#$%"; >+ result = absl::from_chars(normal.data(), normal.data() + normal.size(), d); >+ EXPECT_EQ(result.ec, std::errc()); >+ EXPECT_EQ(result.ptr - normal.data(), 4); >+ >+ std::string overflow = "1e1000@#$%@#$%"; >+ result = absl::from_chars(overflow.data(), >+ overflow.data() + overflow.size(), d); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_EQ(result.ptr - overflow.data(), 6); >+ >+ std::string garbage = "#$%@#$%"; >+ result = absl::from_chars(garbage.data(), >+ garbage.data() + garbage.size(), d); >+ EXPECT_EQ(result.ec, std::errc::invalid_argument); >+ EXPECT_EQ(result.ptr - garbage.data(), 0); >+} >+ >+// Check for a wide range of inputs that strtod() and absl::from_chars() exactly >+// agree on the conversion amount. >+// >+// This test assumes the platform's strtod() uses perfect round_to_nearest >+// rounding. >+TEST(FromChars, TestVersusStrtod) { >+ for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) { >+ for (int exponent = -300; exponent < 300; ++exponent) { >+ std::string candidate = absl::StrCat(mantissa, "e", exponent); >+ double strtod_value = strtod(candidate.c_str(), nullptr); >+ double absl_value = 0; >+ absl::from_chars(candidate.data(), candidate.data() + candidate.size(), >+ absl_value); >+ ASSERT_EQ(strtod_value, absl_value) << candidate; >+ } >+ } >+} >+ >+// Check for a wide range of inputs that strtof() and absl::from_chars() exactly >+// agree on the conversion amount. >+// >+// This test assumes the platform's strtof() uses perfect round_to_nearest >+// rounding. >+TEST(FromChars, TestVersusStrtof) { >+ for (int mantissa = 1000000; mantissa <= 9999999; mantissa += 501) { >+ for (int exponent = -43; exponent < 32; ++exponent) { >+ std::string candidate = absl::StrCat(mantissa, "e", exponent); >+ float strtod_value = strtof(candidate.c_str(), nullptr); >+ float absl_value = 0; >+ absl::from_chars(candidate.data(), candidate.data() + candidate.size(), >+ absl_value); >+ ASSERT_EQ(strtod_value, absl_value) << candidate; >+ } >+ } >+} >+ >+// Tests if two floating point values have identical bit layouts. (EXPECT_EQ >+// is not suitable for NaN testing, since NaNs are never equal.) >+template <typename Float> >+bool Identical(Float a, Float b) { >+ return 0 == memcmp(&a, &b, sizeof(Float)); >+} >+ >+// Check that NaNs are parsed correctly. The spec requires that >+// std::from_chars on "NaN(123abc)" return the same value as std::nan("123abc"). >+// How such an n-char-sequence affects the generated NaN is unspecified, so we >+// just test for symmetry with std::nan and strtod here. >+// >+// (In Linux, this parses the value as a number and stuffs that number into the >+// free bits of a quiet NaN.) >+TEST(FromChars, NaNDoubles) { >+ for (std::string n_char_sequence : >+ {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000", >+ "8000000000000", "abc123", "legal_but_unexpected", >+ "99999999999999999999999", "_"}) { >+ std::string input = absl::StrCat("nan(", n_char_sequence, ")"); >+ SCOPED_TRACE(input); >+ double from_chars_double; >+ absl::from_chars(input.data(), input.data() + input.size(), >+ from_chars_double); >+ double std_nan_double = std::nan(n_char_sequence.c_str()); >+ EXPECT_TRUE(Identical(from_chars_double, std_nan_double)); >+ >+ // Also check that we match strtod()'s behavior. This test assumes that the >+ // platform has a compliant strtod(). >+#if ABSL_STRTOD_HANDLES_NAN_CORRECTLY >+ double strtod_double = strtod(input.c_str(), nullptr); >+ EXPECT_TRUE(Identical(from_chars_double, strtod_double)); >+#endif // ABSL_STRTOD_HANDLES_NAN_CORRECTLY >+ >+ // Check that we can parse a negative NaN >+ std::string negative_input = "-" + input; >+ double negative_from_chars_double; >+ absl::from_chars(negative_input.data(), >+ negative_input.data() + negative_input.size(), >+ negative_from_chars_double); >+ EXPECT_TRUE(std::signbit(negative_from_chars_double)); >+ EXPECT_FALSE(Identical(negative_from_chars_double, from_chars_double)); >+ from_chars_double = std::copysign(from_chars_double, -1.0); >+ EXPECT_TRUE(Identical(negative_from_chars_double, from_chars_double)); >+ } >+} >+ >+TEST(FromChars, NaNFloats) { >+ for (std::string n_char_sequence : >+ {"", "1", "2", "3", "fff", "FFF", "200000", "400000", "4000000000000", >+ "8000000000000", "abc123", "legal_but_unexpected", >+ "99999999999999999999999", "_"}) { >+ std::string input = absl::StrCat("nan(", n_char_sequence, ")"); >+ SCOPED_TRACE(input); >+ float from_chars_float; >+ absl::from_chars(input.data(), input.data() + input.size(), >+ from_chars_float); >+ float std_nan_float = std::nanf(n_char_sequence.c_str()); >+ EXPECT_TRUE(Identical(from_chars_float, std_nan_float)); >+ >+ // Also check that we match strtof()'s behavior. This test assumes that the >+ // platform has a compliant strtof(). >+#if ABSL_STRTOD_HANDLES_NAN_CORRECTLY >+ float strtof_float = strtof(input.c_str(), nullptr); >+ EXPECT_TRUE(Identical(from_chars_float, strtof_float)); >+#endif // ABSL_STRTOD_HANDLES_NAN_CORRECTLY >+ >+ // Check that we can parse a negative NaN >+ std::string negative_input = "-" + input; >+ float negative_from_chars_float; >+ absl::from_chars(negative_input.data(), >+ negative_input.data() + negative_input.size(), >+ negative_from_chars_float); >+ EXPECT_TRUE(std::signbit(negative_from_chars_float)); >+ EXPECT_FALSE(Identical(negative_from_chars_float, from_chars_float)); >+ from_chars_float = std::copysign(from_chars_float, -1.0); >+ EXPECT_TRUE(Identical(negative_from_chars_float, from_chars_float)); >+ } >+} >+ >+// Returns an integer larger than step. The values grow exponentially. >+int NextStep(int step) { >+ return step + (step >> 2) + 1; >+} >+ >+// Test a conversion on a family of input strings, checking that the calculation >+// is correct for in-bounds values, and that overflow and underflow are done >+// correctly for out-of-bounds values. >+// >+// input_generator maps from an integer index to a std::string to test. >+// expected_generator maps from an integer index to an expected Float value. >+// from_chars conversion of input_generator(i) should result in >+// expected_generator(i). >+// >+// lower_bound and upper_bound denote the smallest and largest values for which >+// the conversion is expected to succeed. >+template <typename Float> >+void TestOverflowAndUnderflow( >+ const std::function<std::string(int)>& input_generator, >+ const std::function<Float(int)>& expected_generator, int lower_bound, >+ int upper_bound) { >+ // test legal values near lower_bound >+ int index, step; >+ for (index = lower_bound, step = 1; index < upper_bound; >+ index += step, step = NextStep(step)) { >+ std::string input = input_generator(index); >+ SCOPED_TRACE(input); >+ Float expected = expected_generator(index); >+ Float actual; >+ auto result = >+ absl::from_chars(input.data(), input.data() + input.size(), actual); >+ EXPECT_EQ(result.ec, std::errc()); >+ EXPECT_EQ(expected, actual); >+ } >+ // test legal values near upper_bound >+ for (index = upper_bound, step = 1; index > lower_bound; >+ index -= step, step = NextStep(step)) { >+ std::string input = input_generator(index); >+ SCOPED_TRACE(input); >+ Float expected = expected_generator(index); >+ Float actual; >+ auto result = >+ absl::from_chars(input.data(), input.data() + input.size(), actual); >+ EXPECT_EQ(result.ec, std::errc()); >+ EXPECT_EQ(expected, actual); >+ } >+ // Test underflow values below lower_bound >+ for (index = lower_bound - 1, step = 1; index > -1000000; >+ index -= step, step = NextStep(step)) { >+ std::string input = input_generator(index); >+ SCOPED_TRACE(input); >+ Float actual; >+ auto result = >+ absl::from_chars(input.data(), input.data() + input.size(), actual); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_LT(actual, 1.0); // check for underflow >+ } >+ // Test overflow values above upper_bound >+ for (index = upper_bound + 1, step = 1; index < 1000000; >+ index += step, step = NextStep(step)) { >+ std::string input = input_generator(index); >+ SCOPED_TRACE(input); >+ Float actual; >+ auto result = >+ absl::from_chars(input.data(), input.data() + input.size(), actual); >+ EXPECT_EQ(result.ec, std::errc::result_out_of_range); >+ EXPECT_GT(actual, 1.0); // check for overflow >+ } >+} >+ >+// Check that overflow and underflow are caught correctly for hex doubles. >+// >+// The largest representable double is 0x1.fffffffffffffp+1023, and the >+// smallest representable subnormal is 0x0.0000000000001p-1022, which equals >+// 0x1p-1074. Therefore 1023 and -1074 are the limits of acceptable exponents >+// in this test. >+TEST(FromChars, HexdecimalDoubleLimits) { >+ auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); }; >+ auto expected_gen = [](int index) { return std::ldexp(1.0, index); }; >+ TestOverflowAndUnderflow<double>(input_gen, expected_gen, -1074, 1023); >+} >+ >+// Check that overflow and underflow are caught correctly for hex floats. >+// >+// The largest representable float is 0x1.fffffep+127, and the smallest >+// representable subnormal is 0x0.000002p-126, which equals 0x1p-149. >+// Therefore 127 and -149 are the limits of acceptable exponents in this test. >+TEST(FromChars, HexdecimalFloatLimits) { >+ auto input_gen = [](int index) { return absl::StrCat("0x1.0p", index); }; >+ auto expected_gen = [](int index) { return std::ldexp(1.0f, index); }; >+ TestOverflowAndUnderflow<float>(input_gen, expected_gen, -149, 127); >+} >+ >+// Check that overflow and underflow are caught correctly for decimal doubles. >+// >+// The largest representable double is about 1.8e308, and the smallest >+// representable subnormal is about 5e-324. '1e-324' therefore rounds away from >+// the smallest representable positive value. -323 and 308 are the limits of >+// acceptable exponents in this test. >+TEST(FromChars, DecimalDoubleLimits) { >+ auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; >+ auto expected_gen = [](int index) { return std::pow(10.0, index); }; >+ TestOverflowAndUnderflow<double>(input_gen, expected_gen, -323, 308); >+} >+ >+// Check that overflow and underflow are caught correctly for decimal floats. >+// >+// The largest representable float is about 3.4e38, and the smallest >+// representable subnormal is about 1.45e-45. '1e-45' therefore rounds towards >+// the smallest representable positive value. -45 and 38 are the limits of >+// acceptable exponents in this test. >+TEST(FromChars, DecimalFloatLimits) { >+ auto input_gen = [](int index) { return absl::StrCat("1.0e", index); }; >+ auto expected_gen = [](int index) { return std::pow(10.0, index); }; >+ TestOverflowAndUnderflow<float>(input_gen, expected_gen, -45, 38); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.cc >new file mode 100644 >index 00000000000..fbc9f756315 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.cc >@@ -0,0 +1,1109 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/escaping.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <cstdint> >+#include <cstring> >+#include <iterator> >+#include <limits> >+#include <string> >+ >+#include "absl/base/internal/endian.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/unaligned_access.h" >+#include "absl/strings/internal/char_map.h" >+#include "absl/strings/internal/resize_uninitialized.h" >+#include "absl/strings/internal/utf8.h" >+#include "absl/strings/str_cat.h" >+#include "absl/strings/str_join.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace { >+ >+// Digit conversion. >+constexpr char kHexChar[] = "0123456789abcdef"; >+ >+constexpr char kHexTable[513] = >+ "000102030405060708090a0b0c0d0e0f" >+ "101112131415161718191a1b1c1d1e1f" >+ "202122232425262728292a2b2c2d2e2f" >+ "303132333435363738393a3b3c3d3e3f" >+ "404142434445464748494a4b4c4d4e4f" >+ "505152535455565758595a5b5c5d5e5f" >+ "606162636465666768696a6b6c6d6e6f" >+ "707172737475767778797a7b7c7d7e7f" >+ "808182838485868788898a8b8c8d8e8f" >+ "909192939495969798999a9b9c9d9e9f" >+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" >+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" >+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" >+ "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" >+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" >+ "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; >+ >+// These are used for the leave_nulls_escaped argument to CUnescapeInternal(). >+constexpr bool kUnescapeNulls = false; >+ >+inline bool is_octal_digit(char c) { return ('0' <= c) && (c <= '7'); } >+ >+inline int hex_digit_to_int(char c) { >+ static_assert('0' == 0x30 && 'A' == 0x41 && 'a' == 0x61, >+ "Character set must be ASCII."); >+ assert(absl::ascii_isxdigit(c)); >+ int x = static_cast<unsigned char>(c); >+ if (x > '9') { >+ x += 9; >+ } >+ return x & 0xf; >+} >+ >+inline bool IsSurrogate(char32_t c, absl::string_view src, std::string* error) { >+ if (c >= 0xD800 && c <= 0xDFFF) { >+ if (error) { >+ *error = absl::StrCat("invalid surrogate character (0xD800-DFFF): \\", >+ src); >+ } >+ return true; >+ } >+ return false; >+} >+ >+// ---------------------------------------------------------------------- >+// CUnescapeInternal() >+// Implements both CUnescape() and CUnescapeForNullTerminatedString(). >+// >+// Unescapes C escape sequences and is the reverse of CEscape(). >+// >+// If 'source' is valid, stores the unescaped std::string and its size in >+// 'dest' and 'dest_len' respectively, and returns true. Otherwise >+// returns false and optionally stores the error description in >+// 'error'. Set 'error' to nullptr to disable error reporting. >+// >+// 'dest' should point to a buffer that is at least as big as 'source'. >+// 'source' and 'dest' may be the same. >+// >+// NOTE: any changes to this function must also be reflected in the older >+// UnescapeCEscapeSequences(). >+// ---------------------------------------------------------------------- >+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, >+ char* dest, ptrdiff_t* dest_len, std::string* error) { >+ char* d = dest; >+ const char* p = source.data(); >+ const char* end = source.end(); >+ const char* last_byte = end - 1; >+ >+ // Small optimization for case where source = dest and there's no escaping >+ while (p == d && p < end && *p != '\\') p++, d++; >+ >+ while (p < end) { >+ if (*p != '\\') { >+ *d++ = *p++; >+ } else { >+ if (++p > last_byte) { // skip past the '\\' >+ if (error) *error = "String cannot end with \\"; >+ return false; >+ } >+ switch (*p) { >+ case 'a': *d++ = '\a'; break; >+ case 'b': *d++ = '\b'; break; >+ case 'f': *d++ = '\f'; break; >+ case 'n': *d++ = '\n'; break; >+ case 'r': *d++ = '\r'; break; >+ case 't': *d++ = '\t'; break; >+ case 'v': *d++ = '\v'; break; >+ case '\\': *d++ = '\\'; break; >+ case '?': *d++ = '\?'; break; // \? Who knew? >+ case '\'': *d++ = '\''; break; >+ case '"': *d++ = '\"'; break; >+ case '0': >+ case '1': >+ case '2': >+ case '3': >+ case '4': >+ case '5': >+ case '6': >+ case '7': { >+ // octal digit: 1 to 3 digits >+ const char* octal_start = p; >+ unsigned int ch = *p - '0'; >+ if (p < last_byte && is_octal_digit(p[1])) ch = ch * 8 + *++p - '0'; >+ if (p < last_byte && is_octal_digit(p[1])) >+ ch = ch * 8 + *++p - '0'; // now points at last digit >+ if (ch > 0xff) { >+ if (error) { >+ *error = "Value of \\" + >+ std::string(octal_start, p + 1 - octal_start) + >+ " exceeds 0xff"; >+ } >+ return false; >+ } >+ if ((ch == 0) && leave_nulls_escaped) { >+ // Copy the escape sequence for the null character >+ const ptrdiff_t octal_size = p + 1 - octal_start; >+ *d++ = '\\'; >+ memcpy(d, octal_start, octal_size); >+ d += octal_size; >+ break; >+ } >+ *d++ = ch; >+ break; >+ } >+ case 'x': >+ case 'X': { >+ if (p >= last_byte) { >+ if (error) *error = "String cannot end with \\x"; >+ return false; >+ } else if (!absl::ascii_isxdigit(p[1])) { >+ if (error) *error = "\\x cannot be followed by a non-hex digit"; >+ return false; >+ } >+ unsigned int ch = 0; >+ const char* hex_start = p; >+ while (p < last_byte && absl::ascii_isxdigit(p[1])) >+ // Arbitrarily many hex digits >+ ch = (ch << 4) + hex_digit_to_int(*++p); >+ if (ch > 0xFF) { >+ if (error) { >+ *error = "Value of \\" + std::string(hex_start, p + 1 - hex_start) + >+ " exceeds 0xff"; >+ } >+ return false; >+ } >+ if ((ch == 0) && leave_nulls_escaped) { >+ // Copy the escape sequence for the null character >+ const ptrdiff_t hex_size = p + 1 - hex_start; >+ *d++ = '\\'; >+ memcpy(d, hex_start, hex_size); >+ d += hex_size; >+ break; >+ } >+ *d++ = ch; >+ break; >+ } >+ case 'u': { >+ // \uhhhh => convert 4 hex digits to UTF-8 >+ char32_t rune = 0; >+ const char* hex_start = p; >+ if (p + 4 >= end) { >+ if (error) { >+ *error = "\\u must be followed by 4 hex digits: \\" + >+ std::string(hex_start, p + 1 - hex_start); >+ } >+ return false; >+ } >+ for (int i = 0; i < 4; ++i) { >+ // Look one char ahead. >+ if (absl::ascii_isxdigit(p[1])) { >+ rune = (rune << 4) + hex_digit_to_int(*++p); // Advance p. >+ } else { >+ if (error) { >+ *error = "\\u must be followed by 4 hex digits: \\" + >+ std::string(hex_start, p + 1 - hex_start); >+ } >+ return false; >+ } >+ } >+ if ((rune == 0) && leave_nulls_escaped) { >+ // Copy the escape sequence for the null character >+ *d++ = '\\'; >+ memcpy(d, hex_start, 5); // u0000 >+ d += 5; >+ break; >+ } >+ if (IsSurrogate(rune, absl::string_view(hex_start, 5), error)) { >+ return false; >+ } >+ d += strings_internal::EncodeUTF8Char(d, rune); >+ break; >+ } >+ case 'U': { >+ // \Uhhhhhhhh => convert 8 hex digits to UTF-8 >+ char32_t rune = 0; >+ const char* hex_start = p; >+ if (p + 8 >= end) { >+ if (error) { >+ *error = "\\U must be followed by 8 hex digits: \\" + >+ std::string(hex_start, p + 1 - hex_start); >+ } >+ return false; >+ } >+ for (int i = 0; i < 8; ++i) { >+ // Look one char ahead. >+ if (absl::ascii_isxdigit(p[1])) { >+ // Don't change rune until we're sure this >+ // is within the Unicode limit, but do advance p. >+ uint32_t newrune = (rune << 4) + hex_digit_to_int(*++p); >+ if (newrune > 0x10FFFF) { >+ if (error) { >+ *error = "Value of \\" + >+ std::string(hex_start, p + 1 - hex_start) + >+ " exceeds Unicode limit (0x10FFFF)"; >+ } >+ return false; >+ } else { >+ rune = newrune; >+ } >+ } else { >+ if (error) { >+ *error = "\\U must be followed by 8 hex digits: \\" + >+ std::string(hex_start, p + 1 - hex_start); >+ } >+ return false; >+ } >+ } >+ if ((rune == 0) && leave_nulls_escaped) { >+ // Copy the escape sequence for the null character >+ *d++ = '\\'; >+ memcpy(d, hex_start, 9); // U00000000 >+ d += 9; >+ break; >+ } >+ if (IsSurrogate(rune, absl::string_view(hex_start, 9), error)) { >+ return false; >+ } >+ d += strings_internal::EncodeUTF8Char(d, rune); >+ break; >+ } >+ default: { >+ if (error) *error = std::string("Unknown escape sequence: \\") + *p; >+ return false; >+ } >+ } >+ p++; // read past letter we escaped >+ } >+ } >+ *dest_len = d - dest; >+ return true; >+} >+ >+// ---------------------------------------------------------------------- >+// CUnescapeInternal() >+// >+// Same as above but uses a C++ std::string for output. 'source' and 'dest' >+// may be the same. >+// ---------------------------------------------------------------------- >+bool CUnescapeInternal(absl::string_view source, bool leave_nulls_escaped, >+ std::string* dest, std::string* error) { >+ strings_internal::STLStringResizeUninitialized(dest, source.size()); >+ >+ ptrdiff_t dest_size; >+ if (!CUnescapeInternal(source, >+ leave_nulls_escaped, >+ const_cast<char*>(dest->data()), >+ &dest_size, >+ error)) { >+ return false; >+ } >+ dest->erase(dest_size); >+ return true; >+} >+ >+// ---------------------------------------------------------------------- >+// CEscape() >+// CHexEscape() >+// Utf8SafeCEscape() >+// Utf8SafeCHexEscape() >+// Escapes 'src' using C-style escape sequences. This is useful for >+// preparing query flags. The 'Hex' version uses hexadecimal rather than >+// octal sequences. The 'Utf8Safe' version does not touch UTF-8 bytes. >+// >+// Escaped chars: \n, \r, \t, ", ', \, and !absl::ascii_isprint(). >+// ---------------------------------------------------------------------- >+std::string CEscapeInternal(absl::string_view src, bool use_hex, bool utf8_safe) { >+ std::string dest; >+ bool last_hex_escape = false; // true if last output char was \xNN. >+ >+ for (unsigned char c : src) { >+ bool is_hex_escape = false; >+ switch (c) { >+ case '\n': dest.append("\\" "n"); break; >+ case '\r': dest.append("\\" "r"); break; >+ case '\t': dest.append("\\" "t"); break; >+ case '\"': dest.append("\\" "\""); break; >+ case '\'': dest.append("\\" "'"); break; >+ case '\\': dest.append("\\" "\\"); break; >+ default: >+ // Note that if we emit \xNN and the src character after that is a hex >+ // digit then that digit must be escaped too to prevent it being >+ // interpreted as part of the character code by C. >+ if ((!utf8_safe || c < 0x80) && >+ (!absl::ascii_isprint(c) || >+ (last_hex_escape && absl::ascii_isxdigit(c)))) { >+ if (use_hex) { >+ dest.append("\\" "x"); >+ dest.push_back(kHexChar[c / 16]); >+ dest.push_back(kHexChar[c % 16]); >+ is_hex_escape = true; >+ } else { >+ dest.append("\\"); >+ dest.push_back(kHexChar[c / 64]); >+ dest.push_back(kHexChar[(c % 64) / 8]); >+ dest.push_back(kHexChar[c % 8]); >+ } >+ } else { >+ dest.push_back(c); >+ break; >+ } >+ } >+ last_hex_escape = is_hex_escape; >+ } >+ >+ return dest; >+} >+ >+/* clang-format off */ >+constexpr char c_escaped_len[256] = { >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", ' >+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' >+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O' >+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\' >+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o' >+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, >+}; >+/* clang-format on */ >+ >+// Calculates the length of the C-style escaped version of 'src'. >+// Assumes that non-printable characters are escaped using octal sequences, and >+// that UTF-8 bytes are not handled specially. >+inline size_t CEscapedLength(absl::string_view src) { >+ size_t escaped_len = 0; >+ for (unsigned char c : src) escaped_len += c_escaped_len[c]; >+ return escaped_len; >+} >+ >+void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) { >+ size_t escaped_len = CEscapedLength(src); >+ if (escaped_len == src.size()) { >+ dest->append(src.data(), src.size()); >+ return; >+ } >+ >+ size_t cur_dest_len = dest->size(); >+ strings_internal::STLStringResizeUninitialized(dest, >+ cur_dest_len + escaped_len); >+ char* append_ptr = &(*dest)[cur_dest_len]; >+ >+ for (unsigned char c : src) { >+ int char_len = c_escaped_len[c]; >+ if (char_len == 1) { >+ *append_ptr++ = c; >+ } else if (char_len == 2) { >+ switch (c) { >+ case '\n': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = 'n'; >+ break; >+ case '\r': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = 'r'; >+ break; >+ case '\t': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = 't'; >+ break; >+ case '\"': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = '\"'; >+ break; >+ case '\'': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = '\''; >+ break; >+ case '\\': >+ *append_ptr++ = '\\'; >+ *append_ptr++ = '\\'; >+ break; >+ } >+ } else { >+ *append_ptr++ = '\\'; >+ *append_ptr++ = '0' + c / 64; >+ *append_ptr++ = '0' + (c % 64) / 8; >+ *append_ptr++ = '0' + c % 8; >+ } >+ } >+} >+ >+bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest, >+ size_t szdest, const signed char* unbase64, >+ size_t* len) { >+ static const char kPad64Equals = '='; >+ static const char kPad64Dot = '.'; >+ >+ size_t destidx = 0; >+ int decode = 0; >+ int state = 0; >+ unsigned int ch = 0; >+ unsigned int temp = 0; >+ >+ // If "char" is signed by default, using *src as an array index results in >+ // accessing negative array elements. Treat the input as a pointer to >+ // unsigned char to avoid this. >+ const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param); >+ >+ // The GET_INPUT macro gets the next input character, skipping >+ // over any whitespace, and stopping when we reach the end of the >+ // std::string or when we read any non-data character. The arguments are >+ // an arbitrary identifier (used as a label for goto) and the number >+ // of data bytes that must remain in the input to avoid aborting the >+ // loop. >+#define GET_INPUT(label, remain) \ >+ label: \ >+ --szsrc; \ >+ ch = *src++; \ >+ decode = unbase64[ch]; \ >+ if (decode < 0) { \ >+ if (absl::ascii_isspace(ch) && szsrc >= remain) goto label; \ >+ state = 4 - remain; \ >+ break; \ >+ } >+ >+ // if dest is null, we're just checking to see if it's legal input >+ // rather than producing output. (I suspect this could just be done >+ // with a regexp...). We duplicate the loop so this test can be >+ // outside it instead of in every iteration. >+ >+ if (dest) { >+ // This loop consumes 4 input bytes and produces 3 output bytes >+ // per iteration. We can't know at the start that there is enough >+ // data left in the std::string for a full iteration, so the loop may >+ // break out in the middle; if so 'state' will be set to the >+ // number of input bytes read. >+ >+ while (szsrc >= 4) { >+ // We'll start by optimistically assuming that the next four >+ // bytes of the std::string (src[0..3]) are four good data bytes >+ // (that is, no nulls, whitespace, padding chars, or illegal >+ // chars). We need to test src[0..2] for nulls individually >+ // before constructing temp to preserve the property that we >+ // never read past a null in the std::string (no matter how long >+ // szsrc claims the std::string is). >+ >+ if (!src[0] || !src[1] || !src[2] || >+ ((temp = ((unsigned(unbase64[src[0]]) << 18) | >+ (unsigned(unbase64[src[1]]) << 12) | >+ (unsigned(unbase64[src[2]]) << 6) | >+ (unsigned(unbase64[src[3]])))) & >+ 0x80000000)) { >+ // Iff any of those four characters was bad (null, illegal, >+ // whitespace, padding), then temp's high bit will be set >+ // (because unbase64[] is -1 for all bad characters). >+ // >+ // We'll back up and resort to the slower decoder, which knows >+ // how to handle those cases. >+ >+ GET_INPUT(first, 4); >+ temp = decode; >+ GET_INPUT(second, 3); >+ temp = (temp << 6) | decode; >+ GET_INPUT(third, 2); >+ temp = (temp << 6) | decode; >+ GET_INPUT(fourth, 1); >+ temp = (temp << 6) | decode; >+ } else { >+ // We really did have four good data bytes, so advance four >+ // characters in the std::string. >+ >+ szsrc -= 4; >+ src += 4; >+ } >+ >+ // temp has 24 bits of input, so write that out as three bytes. >+ >+ if (destidx + 3 > szdest) return false; >+ dest[destidx + 2] = temp; >+ temp >>= 8; >+ dest[destidx + 1] = temp; >+ temp >>= 8; >+ dest[destidx] = temp; >+ destidx += 3; >+ } >+ } else { >+ while (szsrc >= 4) { >+ if (!src[0] || !src[1] || !src[2] || >+ ((temp = ((unsigned(unbase64[src[0]]) << 18) | >+ (unsigned(unbase64[src[1]]) << 12) | >+ (unsigned(unbase64[src[2]]) << 6) | >+ (unsigned(unbase64[src[3]])))) & >+ 0x80000000)) { >+ GET_INPUT(first_no_dest, 4); >+ GET_INPUT(second_no_dest, 3); >+ GET_INPUT(third_no_dest, 2); >+ GET_INPUT(fourth_no_dest, 1); >+ } else { >+ szsrc -= 4; >+ src += 4; >+ } >+ destidx += 3; >+ } >+ } >+ >+#undef GET_INPUT >+ >+ // if the loop terminated because we read a bad character, return >+ // now. >+ if (decode < 0 && ch != kPad64Equals && ch != kPad64Dot && >+ !absl::ascii_isspace(ch)) >+ return false; >+ >+ if (ch == kPad64Equals || ch == kPad64Dot) { >+ // if we stopped by hitting an '=' or '.', un-read that character -- we'll >+ // look at it again when we count to check for the proper number of >+ // equals signs at the end. >+ ++szsrc; >+ --src; >+ } else { >+ // This loop consumes 1 input byte per iteration. It's used to >+ // clean up the 0-3 input bytes remaining when the first, faster >+ // loop finishes. 'temp' contains the data from 'state' input >+ // characters read by the first loop. >+ while (szsrc > 0) { >+ --szsrc; >+ ch = *src++; >+ decode = unbase64[ch]; >+ if (decode < 0) { >+ if (absl::ascii_isspace(ch)) { >+ continue; >+ } else if (ch == kPad64Equals || ch == kPad64Dot) { >+ // back up one character; we'll read it again when we check >+ // for the correct number of pad characters at the end. >+ ++szsrc; >+ --src; >+ break; >+ } else { >+ return false; >+ } >+ } >+ >+ // Each input character gives us six bits of output. >+ temp = (temp << 6) | decode; >+ ++state; >+ if (state == 4) { >+ // If we've accumulated 24 bits of output, write that out as >+ // three bytes. >+ if (dest) { >+ if (destidx + 3 > szdest) return false; >+ dest[destidx + 2] = temp; >+ temp >>= 8; >+ dest[destidx + 1] = temp; >+ temp >>= 8; >+ dest[destidx] = temp; >+ } >+ destidx += 3; >+ state = 0; >+ temp = 0; >+ } >+ } >+ } >+ >+ // Process the leftover data contained in 'temp' at the end of the input. >+ int expected_equals = 0; >+ switch (state) { >+ case 0: >+ // Nothing left over; output is a multiple of 3 bytes. >+ break; >+ >+ case 1: >+ // Bad input; we have 6 bits left over. >+ return false; >+ >+ case 2: >+ // Produce one more output byte from the 12 input bits we have left. >+ if (dest) { >+ if (destidx + 1 > szdest) return false; >+ temp >>= 4; >+ dest[destidx] = temp; >+ } >+ ++destidx; >+ expected_equals = 2; >+ break; >+ >+ case 3: >+ // Produce two more output bytes from the 18 input bits we have left. >+ if (dest) { >+ if (destidx + 2 > szdest) return false; >+ temp >>= 2; >+ dest[destidx + 1] = temp; >+ temp >>= 8; >+ dest[destidx] = temp; >+ } >+ destidx += 2; >+ expected_equals = 1; >+ break; >+ >+ default: >+ // state should have no other values at this point. >+ ABSL_RAW_LOG(FATAL, "This can't happen; base64 decoder state = %d", >+ state); >+ } >+ >+ // The remainder of the std::string should be all whitespace, mixed with >+ // exactly 0 equals signs, or exactly 'expected_equals' equals >+ // signs. (Always accepting 0 equals signs is an Abseil extension >+ // not covered in the RFC, as is accepting dot as the pad character.) >+ >+ int equals = 0; >+ while (szsrc > 0) { >+ if (*src == kPad64Equals || *src == kPad64Dot) >+ ++equals; >+ else if (!absl::ascii_isspace(*src)) >+ return false; >+ --szsrc; >+ ++src; >+ } >+ >+ const bool ok = (equals == 0 || equals == expected_equals); >+ if (ok) *len = destidx; >+ return ok; >+} >+ >+// The arrays below were generated by the following code >+// #include <sys/time.h> >+// #include <stdlib.h> >+// #include <std::string.h> >+// main() >+// { >+// static const char Base64[] = >+// "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; >+// char* pos; >+// int idx, i, j; >+// printf(" "); >+// for (i = 0; i < 255; i += 8) { >+// for (j = i; j < i + 8; j++) { >+// pos = strchr(Base64, j); >+// if ((pos == nullptr) || (j == 0)) >+// idx = -1; >+// else >+// idx = pos - Base64; >+// if (idx == -1) >+// printf(" %2d, ", idx); >+// else >+// printf(" %2d/*%c*/,", idx, j); >+// } >+// printf("\n "); >+// } >+// } >+// >+// where the value of "Base64[]" was replaced by one of the base-64 conversion >+// tables from the functions below. >+/* clang-format off */ >+constexpr signed char kUnBase64[] = { >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, >+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, >+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, >+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, >+ 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, >+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, >+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, >+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, >+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, >+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, >+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1 >+}; >+ >+constexpr signed char kUnWebSafeBase64[] = { >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, 62/*-*/, -1, -1, >+ 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, >+ 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, >+ -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, >+ 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, >+ 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, >+ 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, 63/*_*/, >+ -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, >+ 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, >+ 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, >+ 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1 >+}; >+/* clang-format on */ >+ >+size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { >+ // Base64 encodes three bytes of input at a time. If the input is not >+ // divisible by three, we pad as appropriate. >+ // >+ // (from http://tools.ietf.org/html/rfc3548) >+ // Special processing is performed if fewer than 24 bits are available >+ // at the end of the data being encoded. A full encoding quantum is >+ // always completed at the end of a quantity. When fewer than 24 input >+ // bits are available in an input group, zero bits are added (on the >+ // right) to form an integral number of 6-bit groups. Padding at the >+ // end of the data is performed using the '=' character. Since all base >+ // 64 input is an integral number of octets, only the following cases >+ // can arise: >+ >+ // Base64 encodes each three bytes of input into four bytes of output. >+ size_t len = (input_len / 3) * 4; >+ >+ if (input_len % 3 == 0) { >+ // (from http://tools.ietf.org/html/rfc3548) >+ // (1) the final quantum of encoding input is an integral multiple of 24 >+ // bits; here, the final unit of encoded output will be an integral >+ // multiple of 4 characters with no "=" padding, >+ } else if (input_len % 3 == 1) { >+ // (from http://tools.ietf.org/html/rfc3548) >+ // (2) the final quantum of encoding input is exactly 8 bits; here, the >+ // final unit of encoded output will be two characters followed by two >+ // "=" padding characters, or >+ len += 2; >+ if (do_padding) { >+ len += 2; >+ } >+ } else { // (input_len % 3 == 2) >+ // (from http://tools.ietf.org/html/rfc3548) >+ // (3) the final quantum of encoding input is exactly 16 bits; here, the >+ // final unit of encoded output will be three characters followed by one >+ // "=" padding character. >+ len += 3; >+ if (do_padding) { >+ len += 1; >+ } >+ } >+ >+ assert(len >= input_len); // make sure we didn't overflow >+ return len; >+} >+ >+size_t Base64EscapeInternal(const unsigned char* src, size_t szsrc, char* dest, >+ size_t szdest, const char* base64, >+ bool do_padding) { >+ static const char kPad64 = '='; >+ >+ if (szsrc * 4 > szdest * 3) return 0; >+ >+ char* cur_dest = dest; >+ const unsigned char* cur_src = src; >+ >+ char* const limit_dest = dest + szdest; >+ const unsigned char* const limit_src = src + szsrc; >+ >+ // Three bytes of data encodes to four characters of cyphertext. >+ // So we can pump through three-byte chunks atomically. >+ if (szsrc >= 3) { // "limit_src - 3" is UB if szsrc < 3 >+ while (cur_src < limit_src - 3) { // as long as we have >= 32 bits >+ uint32_t in = absl::big_endian::Load32(cur_src) >> 8; >+ >+ cur_dest[0] = base64[in >> 18]; >+ in &= 0x3FFFF; >+ cur_dest[1] = base64[in >> 12]; >+ in &= 0xFFF; >+ cur_dest[2] = base64[in >> 6]; >+ in &= 0x3F; >+ cur_dest[3] = base64[in]; >+ >+ cur_dest += 4; >+ cur_src += 3; >+ } >+ } >+ // To save time, we didn't update szdest or szsrc in the loop. So do it now. >+ szdest = limit_dest - cur_dest; >+ szsrc = limit_src - cur_src; >+ >+ /* now deal with the tail (<=3 bytes) */ >+ switch (szsrc) { >+ case 0: >+ // Nothing left; nothing more to do. >+ break; >+ case 1: { >+ // One byte left: this encodes to two characters, and (optionally) >+ // two pad characters to round out the four-character cypherblock. >+ if (szdest < 2) return 0; >+ uint32_t in = cur_src[0]; >+ cur_dest[0] = base64[in >> 2]; >+ in &= 0x3; >+ cur_dest[1] = base64[in << 4]; >+ cur_dest += 2; >+ szdest -= 2; >+ if (do_padding) { >+ if (szdest < 2) return 0; >+ cur_dest[0] = kPad64; >+ cur_dest[1] = kPad64; >+ cur_dest += 2; >+ szdest -= 2; >+ } >+ break; >+ } >+ case 2: { >+ // Two bytes left: this encodes to three characters, and (optionally) >+ // one pad character to round out the four-character cypherblock. >+ if (szdest < 3) return 0; >+ uint32_t in = absl::big_endian::Load16(cur_src); >+ cur_dest[0] = base64[in >> 10]; >+ in &= 0x3FF; >+ cur_dest[1] = base64[in >> 4]; >+ in &= 0x00F; >+ cur_dest[2] = base64[in << 2]; >+ cur_dest += 3; >+ szdest -= 3; >+ if (do_padding) { >+ if (szdest < 1) return 0; >+ cur_dest[0] = kPad64; >+ cur_dest += 1; >+ szdest -= 1; >+ } >+ break; >+ } >+ case 3: { >+ // Three bytes left: same as in the big loop above. We can't do this in >+ // the loop because the loop above always reads 4 bytes, and the fourth >+ // byte is past the end of the input. >+ if (szdest < 4) return 0; >+ uint32_t in = (cur_src[0] << 16) + absl::big_endian::Load16(cur_src + 1); >+ cur_dest[0] = base64[in >> 18]; >+ in &= 0x3FFFF; >+ cur_dest[1] = base64[in >> 12]; >+ in &= 0xFFF; >+ cur_dest[2] = base64[in >> 6]; >+ in &= 0x3F; >+ cur_dest[3] = base64[in]; >+ cur_dest += 4; >+ szdest -= 4; >+ break; >+ } >+ default: >+ // Should not be reached: blocks of 4 bytes are handled >+ // in the while loop before this switch statement. >+ ABSL_RAW_LOG(FATAL, "Logic problem? szsrc = %zu", szsrc); >+ break; >+ } >+ return (cur_dest - dest); >+} >+ >+constexpr char kBase64Chars[] = >+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; >+ >+constexpr char kWebSafeBase64Chars[] = >+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; >+ >+void Base64EscapeInternal(const unsigned char* src, size_t szsrc, std::string* dest, >+ bool do_padding, const char* base64_chars) { >+ const size_t calc_escaped_size = >+ CalculateBase64EscapedLenInternal(szsrc, do_padding); >+ strings_internal::STLStringResizeUninitialized(dest, calc_escaped_size); >+ >+ const size_t escaped_len = Base64EscapeInternal( >+ src, szsrc, &(*dest)[0], dest->size(), base64_chars, do_padding); >+ assert(calc_escaped_size == escaped_len); >+ dest->erase(escaped_len); >+} >+ >+bool Base64UnescapeInternal(const char* src, size_t slen, std::string* dest, >+ const signed char* unbase64) { >+ // Determine the size of the output std::string. Base64 encodes every 3 bytes into >+ // 4 characters. any leftover chars are added directly for good measure. >+ // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548 >+ const size_t dest_len = 3 * (slen / 4) + (slen % 4); >+ >+ strings_internal::STLStringResizeUninitialized(dest, dest_len); >+ >+ // We are getting the destination buffer by getting the beginning of the >+ // std::string and converting it into a char *. >+ size_t len; >+ const bool ok = >+ Base64UnescapeInternal(src, slen, &(*dest)[0], dest_len, unbase64, &len); >+ if (!ok) { >+ dest->clear(); >+ return false; >+ } >+ >+ // could be shorter if there was padding >+ assert(len <= dest_len); >+ dest->erase(len); >+ >+ return true; >+} >+ >+/* clang-format off */ >+constexpr char kHexValue[256] = { >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, // '0'..'9' >+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'A'..'F' >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 'a'..'f' >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, >+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >+}; >+/* clang-format on */ >+ >+// This is a templated function so that T can be either a char* >+// or a std::string. This works because we use the [] operator to access >+// individual characters at a time. >+template <typename T> >+void HexStringToBytesInternal(const char* from, T to, ptrdiff_t num) { >+ for (int i = 0; i < num; i++) { >+ to[i] = (kHexValue[from[i * 2] & 0xFF] << 4) + >+ (kHexValue[from[i * 2 + 1] & 0xFF]); >+ } >+} >+ >+// This is a templated function so that T can be either a char* or a std::string. >+template <typename T> >+void BytesToHexStringInternal(const unsigned char* src, T dest, ptrdiff_t num) { >+ auto dest_ptr = &dest[0]; >+ for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) { >+ const char* hex_p = &kHexTable[*src_ptr * 2]; >+ std::copy(hex_p, hex_p + 2, dest_ptr); >+ } >+} >+ >+} // namespace >+ >+// ---------------------------------------------------------------------- >+// CUnescape() >+// >+// See CUnescapeInternal() for implementation details. >+// ---------------------------------------------------------------------- >+bool CUnescape(absl::string_view source, std::string* dest, std::string* error) { >+ return CUnescapeInternal(source, kUnescapeNulls, dest, error); >+} >+ >+std::string CEscape(absl::string_view src) { >+ std::string dest; >+ CEscapeAndAppendInternal(src, &dest); >+ return dest; >+} >+ >+std::string CHexEscape(absl::string_view src) { >+ return CEscapeInternal(src, true, false); >+} >+ >+std::string Utf8SafeCEscape(absl::string_view src) { >+ return CEscapeInternal(src, false, true); >+} >+ >+std::string Utf8SafeCHexEscape(absl::string_view src) { >+ return CEscapeInternal(src, true, true); >+} >+ >+// ---------------------------------------------------------------------- >+// ptrdiff_t Base64Unescape() - base64 decoder >+// ptrdiff_t Base64Escape() - base64 encoder >+// ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder >+// ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder >+// >+// Check out >+// http://tools.ietf.org/html/rfc2045 for formal description, but what we >+// care about is that... >+// Take the encoded stuff in groups of 4 characters and turn each >+// character into a code 0 to 63 thus: >+// A-Z map to 0 to 25 >+// a-z map to 26 to 51 >+// 0-9 map to 52 to 61 >+// +(- for WebSafe) maps to 62 >+// /(_ for WebSafe) maps to 63 >+// There will be four numbers, all less than 64 which can be represented >+// by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively). >+// Arrange the 6 digit binary numbers into three bytes as such: >+// aaaaaabb bbbbcccc ccdddddd >+// Equals signs (one or two) are used at the end of the encoded block to >+// indicate that the text was not an integer multiple of three bytes long. >+// ---------------------------------------------------------------------- >+ >+bool Base64Unescape(absl::string_view src, std::string* dest) { >+ return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64); >+} >+ >+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest) { >+ return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64); >+} >+ >+void Base64Escape(absl::string_view src, std::string* dest) { >+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), >+ src.size(), dest, true, kBase64Chars); >+} >+ >+void WebSafeBase64Escape(absl::string_view src, std::string* dest) { >+ Base64EscapeInternal(reinterpret_cast<const unsigned char*>(src.data()), >+ src.size(), dest, false, kWebSafeBase64Chars); >+} >+ >+std::string HexStringToBytes(absl::string_view from) { >+ std::string result; >+ const auto num = from.size() / 2; >+ strings_internal::STLStringResizeUninitialized(&result, num); >+ absl::HexStringToBytesInternal<std::string&>(from.data(), result, num); >+ return result; >+} >+ >+std::string BytesToHexString(absl::string_view from) { >+ std::string result; >+ strings_internal::STLStringResizeUninitialized(&result, 2 * from.size()); >+ absl::BytesToHexStringInternal<std::string&>( >+ reinterpret_cast<const unsigned char*>(from.data()), result, from.size()); >+ return result; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.h >new file mode 100644 >index 00000000000..7f1ab96d8ff >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping.h >@@ -0,0 +1,161 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: escaping.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains std::string utilities involved in escaping and >+// unescaping strings in various ways. >+// >+ >+#ifndef ABSL_STRINGS_ESCAPING_H_ >+#define ABSL_STRINGS_ESCAPING_H_ >+ >+#include <cstddef> >+#include <string> >+#include <vector> >+ >+#include "absl/base/macros.h" >+#include "absl/strings/ascii.h" >+#include "absl/strings/str_join.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// CUnescape() >+// >+// Unescapes a `source` std::string and copies it into `dest`, rewriting C-style >+// escape sequences (http://en.cppreference.com/w/cpp/language/escape) into >+// their proper code point equivalents, returning `true` if successful. >+// >+// The following unescape sequences can be handled: >+// >+// * ASCII escape sequences ('\n','\r','\\', etc.) to their ASCII equivalents >+// * Octal escape sequences ('\nnn') to byte nnn. The unescaped value must >+// resolve to a single byte or an error will occur. E.g. values greater than >+// 0xff will produce an error. >+// * Hexadecimal escape sequences ('\xnn') to byte nn. While an arbitrary >+// number of following digits are allowed, the unescaped value must resolve >+// to a single byte or an error will occur. E.g. '\x0045' is equivalent to >+// '\x45', but '\x1234' will produce an error. >+// * Unicode escape sequences ('\unnnn' for exactly four hex digits or >+// '\Unnnnnnnn' for exactly eight hex digits, which will be encoded in >+// UTF-8. (E.g., `\u2019` unescapes to the three bytes 0xE2, 0x80, and >+// 0x99). >+// >+// >+// If any errors are encountered, this function returns `false` and stores the >+// first encountered error in `error`. To disable error reporting, set `error` >+// to `nullptr` or use the overload with no error reporting below. >+// >+// Example: >+// >+// std::string s = "foo\\rbar\\nbaz\\t"; >+// std::string unescaped_s; >+// if (!absl::CUnescape(s, &unescaped_s) { >+// ... >+// } >+// EXPECT_EQ(unescaped_s, "foo\rbar\nbaz\t"); >+bool CUnescape(absl::string_view source, std::string* dest, std::string* error); >+ >+// Overload of `CUnescape()` with no error reporting. >+inline bool CUnescape(absl::string_view source, std::string* dest) { >+ return CUnescape(source, dest, nullptr); >+} >+ >+// CEscape() >+// >+// Escapes a 'src' std::string using C-style escapes sequences >+// (http://en.cppreference.com/w/cpp/language/escape), escaping other >+// non-printable/non-whitespace bytes as octal sequences (e.g. "\377"). >+// >+// Example: >+// >+// std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n"; >+// std::string escaped_s = absl::CEscape(s); >+// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\010\\t\\n\\013\\014\\r\\n"); >+std::string CEscape(absl::string_view src); >+ >+// CHexEscape() >+// >+// Escapes a 'src' std::string using C-style escape sequences, escaping >+// other non-printable/non-whitespace bytes as hexadecimal sequences (e.g. >+// "\xFF"). >+// >+// Example: >+// >+// std::string s = "foo\rbar\tbaz\010\011\012\013\014\x0d\n"; >+// std::string escaped_s = absl::CHexEscape(s); >+// EXPECT_EQ(escaped_s, "foo\\rbar\\tbaz\\x08\\t\\n\\x0b\\x0c\\r\\n"); >+std::string CHexEscape(absl::string_view src); >+ >+// Utf8SafeCEscape() >+// >+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as >+// octal sequences, and passing through UTF-8 characters without conversion. >+// I.e., when encountering any bytes with their high bit set, this function >+// will not escape those values, whether or not they are valid UTF-8. >+std::string Utf8SafeCEscape(absl::string_view src); >+ >+// Utf8SafeCHexEscape() >+// >+// Escapes a 'src' std::string using C-style escape sequences, escaping bytes as >+// hexadecimal sequences, and passing through UTF-8 characters without >+// conversion. >+std::string Utf8SafeCHexEscape(absl::string_view src); >+ >+// Base64Unescape() >+// >+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing >+// it to a `dest` buffer, returning `true` on success. If `src` contains invalid >+// characters, `dest` is cleared and returns `false`. >+bool Base64Unescape(absl::string_view src, std::string* dest); >+ >+// WebSafeBase64Unescape(absl::string_view, std::string*) >+// >+// Converts a `src` std::string encoded in Base64 to its binary equivalent, writing >+// it to a `dest` buffer, but using '-' instead of '+', and '_' instead of '/'. >+// If `src` contains invalid characters, `dest` is cleared and returns `false`. >+bool WebSafeBase64Unescape(absl::string_view src, std::string* dest); >+ >+// Base64Escape() >+// >+// Encodes a `src` std::string into a `dest` buffer using base64 encoding, with >+// padding characters. This function conforms with RFC 4648 section 4 (base64). >+void Base64Escape(absl::string_view src, std::string* dest); >+ >+// WebSafeBase64Escape() >+// >+// Encodes a `src` std::string into a `dest` buffer using '-' instead of '+' and >+// '_' instead of '/', and without padding. This function conforms with RFC 4648 >+// section 5 (base64url). >+void WebSafeBase64Escape(absl::string_view src, std::string* dest); >+ >+// HexStringToBytes() >+// >+// Converts an ASCII hex std::string into bytes, returning binary data of length >+// `from.size()/2`. >+std::string HexStringToBytes(absl::string_view from); >+ >+// BytesToHexString() >+// >+// Converts binary data into an ASCII text std::string, returning a std::string of size >+// `2*from.size()`. >+std::string BytesToHexString(absl::string_view from); >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_ESCAPING_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_benchmark.cc >new file mode 100644 >index 00000000000..0f791f4e875 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_benchmark.cc >@@ -0,0 +1,94 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/escaping.h" >+ >+#include <cstdio> >+#include <cstring> >+#include <random> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/internal/escaping_test_common.h" >+ >+namespace { >+ >+void BM_CUnescapeHexString(benchmark::State& state) { >+ std::string src; >+ for (int i = 0; i < 50; i++) { >+ src += "\\x55"; >+ } >+ std::string dest; >+ for (auto _ : state) { >+ absl::CUnescape(src, &dest); >+ } >+} >+BENCHMARK(BM_CUnescapeHexString); >+ >+void BM_WebSafeBase64Escape_string(benchmark::State& state) { >+ std::string raw; >+ for (int i = 0; i < 10; ++i) { >+ for (const auto& test_set : absl::strings_internal::base64_strings()) { >+ raw += std::string(test_set.plaintext); >+ } >+ } >+ >+ // The actual benchmark loop is tiny... >+ std::string escaped; >+ for (auto _ : state) { >+ absl::WebSafeBase64Escape(raw, &escaped); >+ } >+ >+ // We want to be sure the compiler doesn't throw away the loop above, >+ // and the easiest way to ensure that is to round-trip the results and verify >+ // them. >+ std::string round_trip; >+ absl::WebSafeBase64Unescape(escaped, &round_trip); >+ ABSL_RAW_CHECK(round_trip == raw, ""); >+} >+BENCHMARK(BM_WebSafeBase64Escape_string); >+ >+// Used for the CEscape benchmarks >+const char kStringValueNoEscape[] = "1234567890"; >+const char kStringValueSomeEscaped[] = "123\n56789\xA1"; >+const char kStringValueMostEscaped[] = "\xA1\xA2\ny\xA4\xA5\xA6z\b\r"; >+ >+void CEscapeBenchmarkHelper(benchmark::State& state, const char* string_value, >+ int max_len) { >+ std::string src; >+ while (src.size() < max_len) { >+ absl::StrAppend(&src, string_value); >+ } >+ >+ for (auto _ : state) { >+ absl::CEscape(src); >+ } >+} >+ >+void BM_CEscape_NoEscape(benchmark::State& state) { >+ CEscapeBenchmarkHelper(state, kStringValueNoEscape, state.range(0)); >+} >+BENCHMARK(BM_CEscape_NoEscape)->Range(1, 1 << 14); >+ >+void BM_CEscape_SomeEscaped(benchmark::State& state) { >+ CEscapeBenchmarkHelper(state, kStringValueSomeEscaped, state.range(0)); >+} >+BENCHMARK(BM_CEscape_SomeEscaped)->Range(1, 1 << 14); >+ >+void BM_CEscape_MostEscaped(benchmark::State& state) { >+ CEscapeBenchmarkHelper(state, kStringValueMostEscaped, state.range(0)); >+} >+BENCHMARK(BM_CEscape_MostEscaped)->Range(1, 1 << 14); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_test.cc >new file mode 100644 >index 00000000000..3f65ec107f4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/escaping_test.cc >@@ -0,0 +1,641 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/escaping.h" >+ >+#include <array> >+#include <cstdio> >+#include <cstring> >+#include <memory> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/container/fixed_array.h" >+#include "absl/strings/str_cat.h" >+ >+#include "absl/strings/internal/escaping_test_common.h" >+ >+namespace { >+ >+struct epair { >+ std::string escaped; >+ std::string unescaped; >+}; >+ >+TEST(CEscape, EscapeAndUnescape) { >+ const std::string inputs[] = { >+ std::string("foo\nxx\r\b\0023"), >+ std::string(""), >+ std::string("abc"), >+ std::string("\1chad_rules"), >+ std::string("\1arnar_drools"), >+ std::string("xxxx\r\t'\"\\"), >+ std::string("\0xx\0", 4), >+ std::string("\x01\x31"), >+ std::string("abc\xb\x42\141bc"), >+ std::string("123\1\x31\x32\x33"), >+ std::string("\xc1\xca\x1b\x62\x19o\xcc\x04"), >+ std::string("\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name"), >+ }; >+ // Do this twice, once for octal escapes and once for hex escapes. >+ for (int kind = 0; kind < 4; kind++) { >+ for (const std::string& original : inputs) { >+ std::string escaped; >+ switch (kind) { >+ case 0: >+ escaped = absl::CEscape(original); >+ break; >+ case 1: >+ escaped = absl::CHexEscape(original); >+ break; >+ case 2: >+ escaped = absl::Utf8SafeCEscape(original); >+ break; >+ case 3: >+ escaped = absl::Utf8SafeCHexEscape(original); >+ break; >+ } >+ std::string unescaped_str; >+ EXPECT_TRUE(absl::CUnescape(escaped, &unescaped_str)); >+ EXPECT_EQ(unescaped_str, original); >+ >+ // Check in-place unescaping >+ std::string s = escaped; >+ EXPECT_TRUE(absl::CUnescape(s, &s)); >+ ASSERT_EQ(s, original); >+ } >+ } >+ // Check that all possible two character strings can be escaped then >+ // unescaped successfully. >+ for (int char0 = 0; char0 < 256; char0++) { >+ for (int char1 = 0; char1 < 256; char1++) { >+ char chars[2]; >+ chars[0] = char0; >+ chars[1] = char1; >+ std::string s(chars, 2); >+ std::string escaped = absl::CHexEscape(s); >+ std::string unescaped; >+ EXPECT_TRUE(absl::CUnescape(escaped, &unescaped)); >+ EXPECT_EQ(s, unescaped); >+ } >+ } >+} >+ >+TEST(CEscape, BasicEscaping) { >+ epair oct_values[] = { >+ {"foo\\rbar\\nbaz\\t", "foo\rbar\nbaz\t"}, >+ {"\\'full of \\\"sound\\\" and \\\"fury\\\"\\'", >+ "'full of \"sound\" and \"fury\"'"}, >+ {"signi\\\\fying\\\\ nothing\\\\", "signi\\fying\\ nothing\\"}, >+ {"\\010\\t\\n\\013\\014\\r", "\010\011\012\013\014\015"} >+ }; >+ epair hex_values[] = { >+ {"ubik\\rubik\\nubik\\t", "ubik\rubik\nubik\t"}, >+ {"I\\\'ve just seen a \\\"face\\\"", >+ "I've just seen a \"face\""}, >+ {"hel\\\\ter\\\\skel\\\\ter\\\\", "hel\\ter\\skel\\ter\\"}, >+ {"\\x08\\t\\n\\x0b\\x0c\\r", "\010\011\012\013\014\015"} >+ }; >+ epair utf8_oct_values[] = { >+ {"\xe8\xb0\xb7\xe6\xad\x8c\\r\xe8\xb0\xb7\xe6\xad\x8c\\nbaz\\t", >+ "\xe8\xb0\xb7\xe6\xad\x8c\r\xe8\xb0\xb7\xe6\xad\x8c\nbaz\t"}, >+ {"\\\"\xe8\xb0\xb7\xe6\xad\x8c\\\" is Google\\\'s Chinese name", >+ "\"\xe8\xb0\xb7\xe6\xad\x8c\" is Google\'s Chinese name"}, >+ {"\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\\\are\\\\Japanese\\\\chars\\\\", >+ "\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\\are\\Japanese\\chars\\"}, >+ {"\xed\x81\xac\xeb\xa1\xac\\010\\t\\n\\013\\014\\r", >+ "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"} >+ }; >+ epair utf8_hex_values[] = { >+ {"\x20\xe4\xbd\xa0\\t\xe5\xa5\xbd,\\r!\\n", >+ "\x20\xe4\xbd\xa0\t\xe5\xa5\xbd,\r!\n"}, >+ {"\xe8\xa9\xa6\xe9\xa8\x93\\\' means \\\"test\\\"", >+ "\xe8\xa9\xa6\xe9\xa8\x93\' means \"test\""}, >+ {"\\\\\xe6\x88\x91\\\\:\\\\\xe6\x9d\xa8\xe6\xac\xa2\\\\", >+ "\\\xe6\x88\x91\\:\\\xe6\x9d\xa8\xe6\xac\xa2\\"}, >+ {"\xed\x81\xac\xeb\xa1\xac\\x08\\t\\n\\x0b\\x0c\\r", >+ "\xed\x81\xac\xeb\xa1\xac\010\011\012\013\014\015"} >+ }; >+ >+ for (const epair& val : oct_values) { >+ std::string escaped = absl::CEscape(val.unescaped); >+ EXPECT_EQ(escaped, val.escaped); >+ } >+ for (const epair& val : hex_values) { >+ std::string escaped = absl::CHexEscape(val.unescaped); >+ EXPECT_EQ(escaped, val.escaped); >+ } >+ for (const epair& val : utf8_oct_values) { >+ std::string escaped = absl::Utf8SafeCEscape(val.unescaped); >+ EXPECT_EQ(escaped, val.escaped); >+ } >+ for (const epair& val : utf8_hex_values) { >+ std::string escaped = absl::Utf8SafeCHexEscape(val.unescaped); >+ EXPECT_EQ(escaped, val.escaped); >+ } >+} >+ >+TEST(Unescape, BasicFunction) { >+ epair tests[] = >+ {{"\\u0030", "0"}, >+ {"\\u00A3", "\xC2\xA3"}, >+ {"\\u22FD", "\xE2\x8B\xBD"}, >+ {"\\U00010000", "\xF0\x90\x80\x80"}, >+ {"\\U0010FFFD", "\xF4\x8F\xBF\xBD"}}; >+ for (const epair& val : tests) { >+ std::string out; >+ EXPECT_TRUE(absl::CUnescape(val.escaped, &out)); >+ EXPECT_EQ(out, val.unescaped); >+ } >+ std::string bad[] = >+ {"\\u1", // too short >+ "\\U1", // too short >+ "\\Uffffff", // exceeds 0x10ffff (largest Unicode) >+ "\\U00110000", // exceeds 0x10ffff (largest Unicode) >+ "\\uD835", // surrogate character (D800-DFFF) >+ "\\U0000DD04", // surrogate character (D800-DFFF) >+ "\\777", // exceeds 0xff >+ "\\xABCD"}; // exceeds 0xff >+ for (const std::string& e : bad) { >+ std::string error; >+ std::string out; >+ EXPECT_FALSE(absl::CUnescape(e, &out, &error)); >+ EXPECT_FALSE(error.empty()); >+ } >+} >+ >+class CUnescapeTest : public testing::Test { >+ protected: >+ static const char kStringWithMultipleOctalNulls[]; >+ static const char kStringWithMultipleHexNulls[]; >+ static const char kStringWithMultipleUnicodeNulls[]; >+ >+ std::string result_string_; >+}; >+ >+const char CUnescapeTest::kStringWithMultipleOctalNulls[] = >+ "\\0\\n" // null escape \0 plus newline >+ "0\\n" // just a number 0 (not a null escape) plus newline >+ "\\00\\12" // null escape \00 plus octal newline code >+ "\\000"; // null escape \000 >+ >+// This has the same ingredients as kStringWithMultipleOctalNulls >+// but with \x hex escapes instead of octal escapes. >+const char CUnescapeTest::kStringWithMultipleHexNulls[] = >+ "\\x0\\n" >+ "0\\n" >+ "\\x00\\xa" >+ "\\x000"; >+ >+const char CUnescapeTest::kStringWithMultipleUnicodeNulls[] = >+ "\\u0000\\n" // short-form (4-digit) null escape plus newline >+ "0\\n" // just a number 0 (not a null escape) plus newline >+ "\\U00000000"; // long-form (8-digit) null escape >+ >+TEST_F(CUnescapeTest, Unescapes1CharOctalNull) { >+ std::string original_string = "\\0"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes2CharOctalNull) { >+ std::string original_string = "\\00"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes3CharOctalNull) { >+ std::string original_string = "\\000"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes1CharHexNull) { >+ std::string original_string = "\\x0"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes2CharHexNull) { >+ std::string original_string = "\\x00"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes3CharHexNull) { >+ std::string original_string = "\\x000"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes4CharUnicodeNull) { >+ std::string original_string = "\\u0000"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, Unescapes8CharUnicodeNull) { >+ std::string original_string = "\\U00000000"; >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0", 1), result_string_); >+} >+ >+TEST_F(CUnescapeTest, UnescapesMultipleOctalNulls) { >+ std::string original_string(kStringWithMultipleOctalNulls); >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ // All escapes, including newlines and null escapes, should have been >+ // converted to the equivalent characters. >+ EXPECT_EQ(std::string("\0\n" >+ "0\n" >+ "\0\n" >+ "\0", 7), result_string_); >+} >+ >+ >+TEST_F(CUnescapeTest, UnescapesMultipleHexNulls) { >+ std::string original_string(kStringWithMultipleHexNulls); >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0\n" >+ "0\n" >+ "\0\n" >+ "\0", 7), result_string_); >+} >+ >+TEST_F(CUnescapeTest, UnescapesMultipleUnicodeNulls) { >+ std::string original_string(kStringWithMultipleUnicodeNulls); >+ EXPECT_TRUE(absl::CUnescape(original_string, &result_string_)); >+ EXPECT_EQ(std::string("\0\n" >+ "0\n" >+ "\0", 5), result_string_); >+} >+ >+static struct { >+ absl::string_view plaintext; >+ absl::string_view cyphertext; >+} const base64_tests[] = { >+ // Empty std::string. >+ {{"", 0}, {"", 0}}, >+ {{nullptr, 0}, >+ {"", 0}}, // if length is zero, plaintext ptr must be ignored! >+ >+ // Basic bit patterns; >+ // values obtained with "echo -n '...' | uuencode -m test" >+ >+ {{"\000", 1}, "AA=="}, >+ {{"\001", 1}, "AQ=="}, >+ {{"\002", 1}, "Ag=="}, >+ {{"\004", 1}, "BA=="}, >+ {{"\010", 1}, "CA=="}, >+ {{"\020", 1}, "EA=="}, >+ {{"\040", 1}, "IA=="}, >+ {{"\100", 1}, "QA=="}, >+ {{"\200", 1}, "gA=="}, >+ >+ {{"\377", 1}, "/w=="}, >+ {{"\376", 1}, "/g=="}, >+ {{"\375", 1}, "/Q=="}, >+ {{"\373", 1}, "+w=="}, >+ {{"\367", 1}, "9w=="}, >+ {{"\357", 1}, "7w=="}, >+ {{"\337", 1}, "3w=="}, >+ {{"\277", 1}, "vw=="}, >+ {{"\177", 1}, "fw=="}, >+ {{"\000\000", 2}, "AAA="}, >+ {{"\000\001", 2}, "AAE="}, >+ {{"\000\002", 2}, "AAI="}, >+ {{"\000\004", 2}, "AAQ="}, >+ {{"\000\010", 2}, "AAg="}, >+ {{"\000\020", 2}, "ABA="}, >+ {{"\000\040", 2}, "ACA="}, >+ {{"\000\100", 2}, "AEA="}, >+ {{"\000\200", 2}, "AIA="}, >+ {{"\001\000", 2}, "AQA="}, >+ {{"\002\000", 2}, "AgA="}, >+ {{"\004\000", 2}, "BAA="}, >+ {{"\010\000", 2}, "CAA="}, >+ {{"\020\000", 2}, "EAA="}, >+ {{"\040\000", 2}, "IAA="}, >+ {{"\100\000", 2}, "QAA="}, >+ {{"\200\000", 2}, "gAA="}, >+ >+ {{"\377\377", 2}, "//8="}, >+ {{"\377\376", 2}, "//4="}, >+ {{"\377\375", 2}, "//0="}, >+ {{"\377\373", 2}, "//s="}, >+ {{"\377\367", 2}, "//c="}, >+ {{"\377\357", 2}, "/+8="}, >+ {{"\377\337", 2}, "/98="}, >+ {{"\377\277", 2}, "/78="}, >+ {{"\377\177", 2}, "/38="}, >+ {{"\376\377", 2}, "/v8="}, >+ {{"\375\377", 2}, "/f8="}, >+ {{"\373\377", 2}, "+/8="}, >+ {{"\367\377", 2}, "9/8="}, >+ {{"\357\377", 2}, "7/8="}, >+ {{"\337\377", 2}, "3/8="}, >+ {{"\277\377", 2}, "v/8="}, >+ {{"\177\377", 2}, "f/8="}, >+ >+ {{"\000\000\000", 3}, "AAAA"}, >+ {{"\000\000\001", 3}, "AAAB"}, >+ {{"\000\000\002", 3}, "AAAC"}, >+ {{"\000\000\004", 3}, "AAAE"}, >+ {{"\000\000\010", 3}, "AAAI"}, >+ {{"\000\000\020", 3}, "AAAQ"}, >+ {{"\000\000\040", 3}, "AAAg"}, >+ {{"\000\000\100", 3}, "AABA"}, >+ {{"\000\000\200", 3}, "AACA"}, >+ {{"\000\001\000", 3}, "AAEA"}, >+ {{"\000\002\000", 3}, "AAIA"}, >+ {{"\000\004\000", 3}, "AAQA"}, >+ {{"\000\010\000", 3}, "AAgA"}, >+ {{"\000\020\000", 3}, "ABAA"}, >+ {{"\000\040\000", 3}, "ACAA"}, >+ {{"\000\100\000", 3}, "AEAA"}, >+ {{"\000\200\000", 3}, "AIAA"}, >+ {{"\001\000\000", 3}, "AQAA"}, >+ {{"\002\000\000", 3}, "AgAA"}, >+ {{"\004\000\000", 3}, "BAAA"}, >+ {{"\010\000\000", 3}, "CAAA"}, >+ {{"\020\000\000", 3}, "EAAA"}, >+ {{"\040\000\000", 3}, "IAAA"}, >+ {{"\100\000\000", 3}, "QAAA"}, >+ {{"\200\000\000", 3}, "gAAA"}, >+ >+ {{"\377\377\377", 3}, "////"}, >+ {{"\377\377\376", 3}, "///+"}, >+ {{"\377\377\375", 3}, "///9"}, >+ {{"\377\377\373", 3}, "///7"}, >+ {{"\377\377\367", 3}, "///3"}, >+ {{"\377\377\357", 3}, "///v"}, >+ {{"\377\377\337", 3}, "///f"}, >+ {{"\377\377\277", 3}, "//+/"}, >+ {{"\377\377\177", 3}, "//9/"}, >+ {{"\377\376\377", 3}, "//7/"}, >+ {{"\377\375\377", 3}, "//3/"}, >+ {{"\377\373\377", 3}, "//v/"}, >+ {{"\377\367\377", 3}, "//f/"}, >+ {{"\377\357\377", 3}, "/+//"}, >+ {{"\377\337\377", 3}, "/9//"}, >+ {{"\377\277\377", 3}, "/7//"}, >+ {{"\377\177\377", 3}, "/3//"}, >+ {{"\376\377\377", 3}, "/v//"}, >+ {{"\375\377\377", 3}, "/f//"}, >+ {{"\373\377\377", 3}, "+///"}, >+ {{"\367\377\377", 3}, "9///"}, >+ {{"\357\377\377", 3}, "7///"}, >+ {{"\337\377\377", 3}, "3///"}, >+ {{"\277\377\377", 3}, "v///"}, >+ {{"\177\377\377", 3}, "f///"}, >+ >+ // Random numbers: values obtained with >+ // >+ // #! /bin/bash >+ // dd bs=$1 count=1 if=/dev/random of=/tmp/bar.random >+ // od -N $1 -t o1 /tmp/bar.random >+ // uuencode -m test < /tmp/bar.random >+ // >+ // where $1 is the number of bytes (2, 3) >+ >+ {{"\243\361", 2}, "o/E="}, >+ {{"\024\167", 2}, "FHc="}, >+ {{"\313\252", 2}, "y6o="}, >+ {{"\046\041", 2}, "JiE="}, >+ {{"\145\236", 2}, "ZZ4="}, >+ {{"\254\325", 2}, "rNU="}, >+ {{"\061\330", 2}, "Mdg="}, >+ {{"\245\032", 2}, "pRo="}, >+ {{"\006\000", 2}, "BgA="}, >+ {{"\375\131", 2}, "/Vk="}, >+ {{"\303\210", 2}, "w4g="}, >+ {{"\040\037", 2}, "IB8="}, >+ {{"\261\372", 2}, "sfo="}, >+ {{"\335\014", 2}, "3Qw="}, >+ {{"\233\217", 2}, "m48="}, >+ {{"\373\056", 2}, "+y4="}, >+ {{"\247\232", 2}, "p5o="}, >+ {{"\107\053", 2}, "Rys="}, >+ {{"\204\077", 2}, "hD8="}, >+ {{"\276\211", 2}, "vok="}, >+ {{"\313\110", 2}, "y0g="}, >+ {{"\363\376", 2}, "8/4="}, >+ {{"\251\234", 2}, "qZw="}, >+ {{"\103\262", 2}, "Q7I="}, >+ {{"\142\312", 2}, "Yso="}, >+ {{"\067\211", 2}, "N4k="}, >+ {{"\220\001", 2}, "kAE="}, >+ {{"\152\240", 2}, "aqA="}, >+ {{"\367\061", 2}, "9zE="}, >+ {{"\133\255", 2}, "W60="}, >+ {{"\176\035", 2}, "fh0="}, >+ {{"\032\231", 2}, "Gpk="}, >+ >+ {{"\013\007\144", 3}, "Cwdk"}, >+ {{"\030\112\106", 3}, "GEpG"}, >+ {{"\047\325\046", 3}, "J9Um"}, >+ {{"\310\160\022", 3}, "yHAS"}, >+ {{"\131\100\237", 3}, "WUCf"}, >+ {{"\064\342\134", 3}, "NOJc"}, >+ {{"\010\177\004", 3}, "CH8E"}, >+ {{"\345\147\205", 3}, "5WeF"}, >+ {{"\300\343\360", 3}, "wOPw"}, >+ {{"\061\240\201", 3}, "MaCB"}, >+ {{"\225\333\044", 3}, "ldsk"}, >+ {{"\215\137\352", 3}, "jV/q"}, >+ {{"\371\147\160", 3}, "+Wdw"}, >+ {{"\030\320\051", 3}, "GNAp"}, >+ {{"\044\174\241", 3}, "JHyh"}, >+ {{"\260\127\037", 3}, "sFcf"}, >+ {{"\111\045\033", 3}, "SSUb"}, >+ {{"\202\114\107", 3}, "gkxH"}, >+ {{"\057\371\042", 3}, "L/ki"}, >+ {{"\223\247\244", 3}, "k6ek"}, >+ {{"\047\216\144", 3}, "J45k"}, >+ {{"\203\070\327", 3}, "gzjX"}, >+ {{"\247\140\072", 3}, "p2A6"}, >+ {{"\124\115\116", 3}, "VE1O"}, >+ {{"\157\162\050", 3}, "b3Io"}, >+ {{"\357\223\004", 3}, "75ME"}, >+ {{"\052\117\156", 3}, "Kk9u"}, >+ {{"\347\154\000", 3}, "52wA"}, >+ {{"\303\012\142", 3}, "wwpi"}, >+ {{"\060\035\362", 3}, "MB3y"}, >+ {{"\130\226\361", 3}, "WJbx"}, >+ {{"\173\013\071", 3}, "ews5"}, >+ {{"\336\004\027", 3}, "3gQX"}, >+ {{"\357\366\234", 3}, "7/ac"}, >+ {{"\353\304\111", 3}, "68RJ"}, >+ {{"\024\264\131", 3}, "FLRZ"}, >+ {{"\075\114\251", 3}, "PUyp"}, >+ {{"\315\031\225", 3}, "zRmV"}, >+ {{"\154\201\276", 3}, "bIG+"}, >+ {{"\200\066\072", 3}, "gDY6"}, >+ {{"\142\350\267", 3}, "Yui3"}, >+ {{"\033\000\166", 3}, "GwB2"}, >+ {{"\210\055\077", 3}, "iC0/"}, >+ {{"\341\037\124", 3}, "4R9U"}, >+ {{"\161\103\152", 3}, "cUNq"}, >+ {{"\270\142\131", 3}, "uGJZ"}, >+ {{"\337\076\074", 3}, "3z48"}, >+ {{"\375\106\362", 3}, "/Uby"}, >+ {{"\227\301\127", 3}, "l8FX"}, >+ {{"\340\002\234", 3}, "4AKc"}, >+ {{"\121\064\033", 3}, "UTQb"}, >+ {{"\157\134\143", 3}, "b1xj"}, >+ {{"\247\055\327", 3}, "py3X"}, >+ {{"\340\142\005", 3}, "4GIF"}, >+ {{"\060\260\143", 3}, "MLBj"}, >+ {{"\075\203\170", 3}, "PYN4"}, >+ {{"\143\160\016", 3}, "Y3AO"}, >+ {{"\313\013\063", 3}, "ywsz"}, >+ {{"\174\236\135", 3}, "fJ5d"}, >+ {{"\103\047\026", 3}, "QycW"}, >+ {{"\365\005\343", 3}, "9QXj"}, >+ {{"\271\160\223", 3}, "uXCT"}, >+ {{"\362\255\172", 3}, "8q16"}, >+ {{"\113\012\015", 3}, "SwoN"}, >+ >+ // various lengths, generated by this python script: >+ // >+ // from std::string import lowercase as lc >+ // for i in range(27): >+ // print '{ %2d, "%s",%s "%s" },' % (i, lc[:i], ' ' * (26-i), >+ // lc[:i].encode('base64').strip()) >+ >+ {{"", 0}, {"", 0}}, >+ {"a", "YQ=="}, >+ {"ab", "YWI="}, >+ {"abc", "YWJj"}, >+ {"abcd", "YWJjZA=="}, >+ {"abcde", "YWJjZGU="}, >+ {"abcdef", "YWJjZGVm"}, >+ {"abcdefg", "YWJjZGVmZw=="}, >+ {"abcdefgh", "YWJjZGVmZ2g="}, >+ {"abcdefghi", "YWJjZGVmZ2hp"}, >+ {"abcdefghij", "YWJjZGVmZ2hpag=="}, >+ {"abcdefghijk", "YWJjZGVmZ2hpams="}, >+ {"abcdefghijkl", "YWJjZGVmZ2hpamts"}, >+ {"abcdefghijklm", "YWJjZGVmZ2hpamtsbQ=="}, >+ {"abcdefghijklmn", "YWJjZGVmZ2hpamtsbW4="}, >+ {"abcdefghijklmno", "YWJjZGVmZ2hpamtsbW5v"}, >+ {"abcdefghijklmnop", "YWJjZGVmZ2hpamtsbW5vcA=="}, >+ {"abcdefghijklmnopq", "YWJjZGVmZ2hpamtsbW5vcHE="}, >+ {"abcdefghijklmnopqr", "YWJjZGVmZ2hpamtsbW5vcHFy"}, >+ {"abcdefghijklmnopqrs", "YWJjZGVmZ2hpamtsbW5vcHFycw=="}, >+ {"abcdefghijklmnopqrst", "YWJjZGVmZ2hpamtsbW5vcHFyc3Q="}, >+ {"abcdefghijklmnopqrstu", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1"}, >+ {"abcdefghijklmnopqrstuv", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dg=="}, >+ {"abcdefghijklmnopqrstuvw", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnc="}, >+ {"abcdefghijklmnopqrstuvwx", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4"}, >+ {"abcdefghijklmnopqrstuvwxy", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eQ=="}, >+ {"abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="}, >+}; >+ >+TEST(Base64, EscapeAndUnescape) { >+ // Check the short strings; this tests the math (and boundaries) >+ for (const auto& tc : base64_tests) { >+ std::string encoded("this junk should be ignored"); >+ absl::Base64Escape(tc.plaintext, &encoded); >+ EXPECT_EQ(encoded, tc.cyphertext); >+ >+ std::string decoded("this junk should be ignored"); >+ EXPECT_TRUE(absl::Base64Unescape(encoded, &decoded)); >+ EXPECT_EQ(decoded, tc.plaintext); >+ >+ std::string websafe(tc.cyphertext); >+ for (int c = 0; c < websafe.size(); ++c) { >+ if ('+' == websafe[c]) websafe[c] = '-'; >+ if ('/' == websafe[c]) websafe[c] = '_'; >+ if ('=' == websafe[c]) { >+ websafe.resize(c); >+ break; >+ } >+ } >+ >+ encoded = "this junk should be ignored"; >+ absl::WebSafeBase64Escape(tc.plaintext, &encoded); >+ EXPECT_EQ(encoded, websafe); >+ >+ // Let's try the std::string version of the decoder >+ decoded = "this junk should be ignored"; >+ EXPECT_TRUE(absl::WebSafeBase64Unescape(websafe, &decoded)); >+ EXPECT_EQ(decoded, tc.plaintext); >+ } >+ >+ // Now try the long strings, this tests the streaming >+ for (const auto& tc : absl::strings_internal::base64_strings()) { >+ std::string buffer; >+ absl::WebSafeBase64Escape(tc.plaintext, &buffer); >+ EXPECT_EQ(tc.cyphertext, buffer); >+ } >+ >+ // Verify the behavior when decoding bad data >+ { >+ absl::string_view data_set[] = {"ab-/", absl::string_view("\0bcd", 4), >+ absl::string_view("abc.\0", 5)}; >+ for (absl::string_view bad_data : data_set) { >+ std::string buf; >+ EXPECT_FALSE(absl::Base64Unescape(bad_data, &buf)); >+ EXPECT_FALSE(absl::WebSafeBase64Unescape(bad_data, &buf)); >+ EXPECT_TRUE(buf.empty()); >+ } >+ } >+} >+ >+TEST(Base64, DISABLED_HugeData) { >+ const size_t kSize = size_t(3) * 1000 * 1000 * 1000; >+ static_assert(kSize % 3 == 0, "kSize must be divisible by 3"); >+ const std::string huge(kSize, 'x'); >+ >+ std::string escaped; >+ absl::Base64Escape(huge, &escaped); >+ >+ // Generates the std::string that should match a base64 encoded "xxx..." std::string. >+ // "xxx" in base64 is "eHh4". >+ std::string expected_encoding; >+ expected_encoding.reserve(kSize / 3 * 4); >+ for (size_t i = 0; i < kSize / 3; ++i) { >+ expected_encoding.append("eHh4"); >+ } >+ EXPECT_EQ(expected_encoding, escaped); >+ >+ std::string unescaped; >+ EXPECT_TRUE(absl::Base64Unescape(escaped, &unescaped)); >+ EXPECT_EQ(huge, unescaped); >+} >+ >+TEST(HexAndBack, HexStringToBytes_and_BytesToHexString) { >+ std::string hex_mixed = "0123456789abcdefABCDEF"; >+ std::string bytes_expected = "\x01\x23\x45\x67\x89\xab\xcd\xef\xAB\xCD\xEF"; >+ std::string hex_only_lower = "0123456789abcdefabcdef"; >+ >+ std::string bytes_result = absl::HexStringToBytes(hex_mixed); >+ EXPECT_EQ(bytes_expected, bytes_result); >+ >+ std::string prefix_valid = hex_mixed + "?"; >+ std::string prefix_valid_result = absl::HexStringToBytes( >+ absl::string_view(prefix_valid.data(), prefix_valid.size() - 1)); >+ EXPECT_EQ(bytes_expected, prefix_valid_result); >+ >+ std::string infix_valid = "?" + hex_mixed + "???"; >+ std::string infix_valid_result = absl::HexStringToBytes( >+ absl::string_view(infix_valid.data() + 1, hex_mixed.size())); >+ EXPECT_EQ(bytes_expected, infix_valid_result); >+ >+ std::string hex_result = absl::BytesToHexString(bytes_expected); >+ EXPECT_EQ(hex_only_lower, hex_result); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/bits.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/bits.h >new file mode 100644 >index 00000000000..901082ccddf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/bits.h >@@ -0,0 +1,53 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_STRINGS_INTERNAL_BITS_H_ >+#define ABSL_STRINGS_INTERNAL_BITS_H_ >+ >+#include <cstdint> >+ >+#if defined(_MSC_VER) && defined(_M_X64) >+#include <intrin.h> >+#pragma intrinsic(_BitScanReverse64) >+#endif >+ >+namespace absl { >+namespace strings_internal { >+ >+// Returns the number of leading 0 bits in a 64-bit value. >+inline int CountLeadingZeros64(uint64_t n) { >+#if defined(__GNUC__) >+ static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int) >+ "__builtin_clzll does not take 64bit arg"); >+ return n == 0 ? 64 : __builtin_clzll(n); >+#elif defined(_MSC_VER) && defined(_M_X64) >+ unsigned long result; // NOLINT(runtime/int) >+ if (_BitScanReverse64(&result, n)) { >+ return 63 - result; >+ } >+ return 64; >+#else >+ int zeroes = 60; >+ if (n >> 32) zeroes -= 32, n >>= 32; >+ if (n >> 16) zeroes -= 16, n >>= 16; >+ if (n >> 8) zeroes -= 8, n >>= 8; >+ if (n >> 4) zeroes -= 4, n >>= 4; >+ return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0\0"[n] + zeroes; >+#endif >+} >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_BITS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map.h >new file mode 100644 >index 00000000000..8d92963a4de >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map.h >@@ -0,0 +1,154 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Character Map Class >+// >+// A fast, bit-vector map for 8-bit unsigned characters. >+// This class is useful for non-character purposes as well. >+ >+#ifndef ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ >+#define ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ >+ >+#include <cstddef> >+#include <cstdint> >+#include <cstring> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+class Charmap { >+ public: >+ constexpr Charmap() : m_() {} >+ >+ // Initializes with a given char*. Note that NUL is not treated as >+ // a terminator, but rather a char to be flicked. >+ Charmap(const char* str, int len) : m_() { >+ while (len--) SetChar(*str++); >+ } >+ >+ // Initializes with a given char*. NUL is treated as a terminator >+ // and will not be in the charmap. >+ explicit Charmap(const char* str) : m_() { >+ while (*str) SetChar(*str++); >+ } >+ >+ constexpr bool contains(unsigned char c) const { >+ return (m_[c / 64] >> (c % 64)) & 0x1; >+ } >+ >+ // Returns true if and only if a character exists in both maps. >+ bool IntersectsWith(const Charmap& c) const { >+ for (size_t i = 0; i < ABSL_ARRAYSIZE(m_); ++i) { >+ if ((m_[i] & c.m_[i]) != 0) return true; >+ } >+ return false; >+ } >+ >+ bool IsZero() const { >+ for (uint64_t c : m_) { >+ if (c != 0) return false; >+ } >+ return true; >+ } >+ >+ // Containing only a single specified char. >+ static constexpr Charmap Char(char x) { >+ return Charmap(CharMaskForWord(x, 0), CharMaskForWord(x, 1), >+ CharMaskForWord(x, 2), CharMaskForWord(x, 3)); >+ } >+ >+ // Containing all the chars in the C-std::string 's'. >+ // Note that this is expensively recursive because of the C++11 constexpr >+ // formulation. Use only in constexpr initializers. >+ static constexpr Charmap FromString(const char* s) { >+ return *s == 0 ? Charmap() : (Char(*s) | FromString(s + 1)); >+ } >+ >+ // Containing all the chars in the closed interval [lo,hi]. >+ static constexpr Charmap Range(char lo, char hi) { >+ return Charmap(RangeForWord(lo, hi, 0), RangeForWord(lo, hi, 1), >+ RangeForWord(lo, hi, 2), RangeForWord(lo, hi, 3)); >+ } >+ >+ friend constexpr Charmap operator&(const Charmap& a, const Charmap& b) { >+ return Charmap(a.m_[0] & b.m_[0], a.m_[1] & b.m_[1], a.m_[2] & b.m_[2], >+ a.m_[3] & b.m_[3]); >+ } >+ >+ friend constexpr Charmap operator|(const Charmap& a, const Charmap& b) { >+ return Charmap(a.m_[0] | b.m_[0], a.m_[1] | b.m_[1], a.m_[2] | b.m_[2], >+ a.m_[3] | b.m_[3]); >+ } >+ >+ friend constexpr Charmap operator~(const Charmap& a) { >+ return Charmap(~a.m_[0], ~a.m_[1], ~a.m_[2], ~a.m_[3]); >+ } >+ >+ private: >+ constexpr Charmap(uint64_t b0, uint64_t b1, uint64_t b2, uint64_t b3) >+ : m_{b0, b1, b2, b3} {} >+ >+ static constexpr uint64_t RangeForWord(unsigned char lo, unsigned char hi, >+ uint64_t word) { >+ return OpenRangeFromZeroForWord(hi + 1, word) & >+ ~OpenRangeFromZeroForWord(lo, word); >+ } >+ >+ // All the chars in the specified word of the range [0, upper). >+ static constexpr uint64_t OpenRangeFromZeroForWord(uint64_t upper, >+ uint64_t word) { >+ return (upper <= 64 * word) >+ ? 0 >+ : (upper >= 64 * (word + 1)) >+ ? ~static_cast<uint64_t>(0) >+ : (~static_cast<uint64_t>(0) >> (64 - upper % 64)); >+ } >+ >+ static constexpr uint64_t CharMaskForWord(unsigned char x, uint64_t word) { >+ return (x / 64 == word) ? (static_cast<uint64_t>(1) << (x % 64)) : 0; >+ } >+ >+ private: >+ void SetChar(unsigned char c) { >+ m_[c / 64] |= static_cast<uint64_t>(1) << (c % 64); >+ } >+ >+ uint64_t m_[4]; >+}; >+ >+// Mirror the char-classifying predicates in <cctype> >+constexpr Charmap UpperCharmap() { return Charmap::Range('A', 'Z'); } >+constexpr Charmap LowerCharmap() { return Charmap::Range('a', 'z'); } >+constexpr Charmap DigitCharmap() { return Charmap::Range('0', '9'); } >+constexpr Charmap AlphaCharmap() { return LowerCharmap() | UpperCharmap(); } >+constexpr Charmap AlnumCharmap() { return DigitCharmap() | AlphaCharmap(); } >+constexpr Charmap XDigitCharmap() { >+ return DigitCharmap() | Charmap::Range('A', 'F') | Charmap::Range('a', 'f'); >+} >+constexpr Charmap PrintCharmap() { return Charmap::Range(0x20, 0x7e); } >+constexpr Charmap SpaceCharmap() { return Charmap::FromString("\t\n\v\f\r "); } >+constexpr Charmap CntrlCharmap() { >+ return Charmap::Range(0, 0x7f) & ~PrintCharmap(); >+} >+constexpr Charmap BlankCharmap() { return Charmap::FromString("\t "); } >+constexpr Charmap GraphCharmap() { return PrintCharmap() & ~SpaceCharmap(); } >+constexpr Charmap PunctCharmap() { return GraphCharmap() & ~AlnumCharmap(); } >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_CHAR_MAP_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_benchmark.cc >new file mode 100644 >index 00000000000..c45f3157c29 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_benchmark.cc >@@ -0,0 +1,61 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/char_map.h" >+ >+#include <cstdint> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+absl::strings_internal::Charmap MakeBenchmarkMap() { >+ absl::strings_internal::Charmap m; >+ uint32_t x[] = {0x0, 0x1, 0x2, 0x3, 0xf, 0xe, 0xd, 0xc}; >+ for (uint32_t& t : x) t *= static_cast<uint32_t>(0x11111111UL); >+ for (uint32_t i = 0; i < 256; ++i) { >+ if ((x[i / 32] >> (i % 32)) & 1) >+ m = m | absl::strings_internal::Charmap::Char(i); >+ } >+ return m; >+} >+ >+// Micro-benchmark for Charmap::contains. >+void BM_Contains(benchmark::State& state) { >+ // Loop-body replicated 10 times to increase time per iteration. >+ // Argument continuously changed to avoid generating common subexpressions. >+ const absl::strings_internal::Charmap benchmark_map = MakeBenchmarkMap(); >+ unsigned char c = 0; >+ int ops = 0; >+ for (auto _ : state) { >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ ops += benchmark_map.contains(c++); >+ } >+ benchmark::DoNotOptimize(ops); >+} >+BENCHMARK(BM_Contains); >+ >+// We don't bother benchmarking Charmap::IsZero or Charmap::IntersectsWith; >+// their running time is data-dependent and it is not worth characterizing >+// "typical" data. >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_test.cc >new file mode 100644 >index 00000000000..c3601e101e2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/char_map_test.cc >@@ -0,0 +1,172 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/char_map.h" >+ >+#include <cctype> >+#include <string> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace { >+ >+constexpr absl::strings_internal::Charmap everything_map = >+ ~absl::strings_internal::Charmap(); >+constexpr absl::strings_internal::Charmap nothing_map{}; >+ >+TEST(Charmap, AllTests) { >+ const absl::strings_internal::Charmap also_nothing_map("", 0); >+ ASSERT_TRUE(everything_map.contains('\0')); >+ ASSERT_TRUE(!nothing_map.contains('\0')); >+ ASSERT_TRUE(!also_nothing_map.contains('\0')); >+ for (unsigned char ch = 1; ch != 0; ++ch) { >+ ASSERT_TRUE(everything_map.contains(ch)); >+ ASSERT_TRUE(!nothing_map.contains(ch)); >+ ASSERT_TRUE(!also_nothing_map.contains(ch)); >+ } >+ >+ const absl::strings_internal::Charmap symbols("&@#@^!@?", 5); >+ ASSERT_TRUE(symbols.contains('&')); >+ ASSERT_TRUE(symbols.contains('@')); >+ ASSERT_TRUE(symbols.contains('#')); >+ ASSERT_TRUE(symbols.contains('^')); >+ ASSERT_TRUE(!symbols.contains('!')); >+ ASSERT_TRUE(!symbols.contains('?')); >+ int cnt = 0; >+ for (unsigned char ch = 1; ch != 0; ++ch) >+ cnt += symbols.contains(ch); >+ ASSERT_EQ(cnt, 4); >+ >+ const absl::strings_internal::Charmap lets("^abcde", 3); >+ const absl::strings_internal::Charmap lets2("fghij\0klmnop", 10); >+ const absl::strings_internal::Charmap lets3("fghij\0klmnop"); >+ ASSERT_TRUE(lets2.contains('k')); >+ ASSERT_TRUE(!lets3.contains('k')); >+ >+ ASSERT_TRUE(symbols.IntersectsWith(lets)); >+ ASSERT_TRUE(!lets2.IntersectsWith(lets)); >+ ASSERT_TRUE(lets.IntersectsWith(symbols)); >+ ASSERT_TRUE(!lets.IntersectsWith(lets2)); >+ >+ ASSERT_TRUE(nothing_map.IsZero()); >+ ASSERT_TRUE(!lets.IsZero()); >+} >+ >+namespace { >+std::string Members(const absl::strings_internal::Charmap& m) { >+ std::string r; >+ for (size_t i = 0; i < 256; ++i) >+ if (m.contains(i)) r.push_back(i); >+ return r; >+} >+ >+std::string ClosedRangeString(unsigned char lo, unsigned char hi) { >+ // Don't depend on lo<hi. Just increment until lo==hi. >+ std::string s; >+ while (true) { >+ s.push_back(lo); >+ if (lo == hi) break; >+ ++lo; >+ } >+ return s; >+} >+ >+} // namespace >+ >+TEST(Charmap, Constexpr) { >+ constexpr absl::strings_internal::Charmap kEmpty = nothing_map; >+ EXPECT_THAT(Members(kEmpty), ""); >+ constexpr absl::strings_internal::Charmap kA = >+ absl::strings_internal::Charmap::Char('A'); >+ EXPECT_THAT(Members(kA), "A"); >+ constexpr absl::strings_internal::Charmap kAZ = >+ absl::strings_internal::Charmap::Range('A', 'Z'); >+ EXPECT_THAT(Members(kAZ), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); >+ constexpr absl::strings_internal::Charmap kIdentifier = >+ absl::strings_internal::Charmap::Range('0', '9') | >+ absl::strings_internal::Charmap::Range('A', 'Z') | >+ absl::strings_internal::Charmap::Range('a', 'z') | >+ absl::strings_internal::Charmap::Char('_'); >+ EXPECT_THAT(Members(kIdentifier), >+ "0123456789" >+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" >+ "_" >+ "abcdefghijklmnopqrstuvwxyz"); >+ constexpr absl::strings_internal::Charmap kAll = everything_map; >+ for (size_t i = 0; i < 256; ++i) { >+ EXPECT_TRUE(kAll.contains(i)) << i; >+ } >+ constexpr absl::strings_internal::Charmap kHello = >+ absl::strings_internal::Charmap::FromString("Hello, world!"); >+ EXPECT_THAT(Members(kHello), " !,Hdelorw"); >+ >+ // test negation and intersection >+ constexpr absl::strings_internal::Charmap kABC = >+ absl::strings_internal::Charmap::Range('A', 'Z') & >+ ~absl::strings_internal::Charmap::Range('D', 'Z'); >+ EXPECT_THAT(Members(kABC), "ABC"); >+} >+ >+TEST(Charmap, Range) { >+ // Exhaustive testing takes too long, so test some of the boundaries that >+ // are perhaps going to cause trouble. >+ std::vector<size_t> poi = {0, 1, 2, 3, 4, 7, 8, 9, 15, >+ 16, 17, 30, 31, 32, 33, 63, 64, 65, >+ 127, 128, 129, 223, 224, 225, 254, 255}; >+ for (auto lo = poi.begin(); lo != poi.end(); ++lo) { >+ SCOPED_TRACE(*lo); >+ for (auto hi = lo; hi != poi.end(); ++hi) { >+ SCOPED_TRACE(*hi); >+ EXPECT_THAT(Members(absl::strings_internal::Charmap::Range(*lo, *hi)), >+ ClosedRangeString(*lo, *hi)); >+ } >+ } >+} >+ >+bool AsBool(int x) { return static_cast<bool>(x); } >+ >+TEST(CharmapCtype, Match) { >+ for (int c = 0; c < 256; ++c) { >+ SCOPED_TRACE(c); >+ SCOPED_TRACE(static_cast<char>(c)); >+ EXPECT_EQ(AsBool(std::isupper(c)), >+ absl::strings_internal::UpperCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::islower(c)), >+ absl::strings_internal::LowerCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isdigit(c)), >+ absl::strings_internal::DigitCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isalpha(c)), >+ absl::strings_internal::AlphaCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isalnum(c)), >+ absl::strings_internal::AlnumCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isxdigit(c)), >+ absl::strings_internal::XDigitCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isprint(c)), >+ absl::strings_internal::PrintCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isspace(c)), >+ absl::strings_internal::SpaceCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::iscntrl(c)), >+ absl::strings_internal::CntrlCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isblank(c)), >+ absl::strings_internal::BlankCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::isgraph(c)), >+ absl::strings_internal::GraphCharmap().contains(c)); >+ EXPECT_EQ(AsBool(std::ispunct(c)), >+ absl::strings_internal::PunctCharmap().contains(c)); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc >new file mode 100644 >index 00000000000..3e7296e7068 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.cc >@@ -0,0 +1,357 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/charconv_bigint.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <string> >+ >+namespace absl { >+namespace strings_internal { >+ >+namespace { >+ >+// Table containing some large powers of 5, for fast computation. >+ >+// Constant step size for entries in the kLargePowersOfFive table. Each entry >+// is larger than the previous entry by a factor of 5**kLargePowerOfFiveStep >+// (or 5**27). >+// >+// In other words, the Nth entry in the table is 5**(27*N). >+// >+// 5**27 is the largest power of 5 that fits in 64 bits. >+constexpr int kLargePowerOfFiveStep = 27; >+ >+// The largest legal index into the kLargePowersOfFive table. >+// >+// In other words, the largest precomputed power of 5 is 5**(27*20). >+constexpr int kLargestPowerOfFiveIndex = 20; >+ >+// Table of powers of (5**27), up to (5**27)**20 == 5**540. >+// >+// Used to generate large powers of 5 while limiting the number of repeated >+// multiplications required. >+// >+// clang-format off >+const uint32_t kLargePowersOfFive[] = { >+// 5**27 (i=1), start=0, end=2 >+ 0xfa10079dU, 0x6765c793U, >+// 5**54 (i=2), start=2, end=6 >+ 0x97d9f649U, 0x6664242dU, 0x29939b14U, 0x29c30f10U, >+// 5**81 (i=3), start=6, end=12 >+ 0xc4f809c5U, 0x7bf3f22aU, 0x67bdae34U, 0xad340517U, 0x369d1b5fU, 0x10de1593U, >+// 5**108 (i=4), start=12, end=20 >+ 0x92b260d1U, 0x9efff7c7U, 0x81de0ec6U, 0xaeba5d56U, 0x410664a4U, 0x4f40737aU, >+ 0x20d3846fU, 0x06d00f73U, >+// 5**135 (i=5), start=20, end=30 >+ 0xff1b172dU, 0x13a1d71cU, 0xefa07617U, 0x7f682d3dU, 0xff8c90c0U, 0x3f0131e7U, >+ 0x3fdcb9feU, 0x917b0177U, 0x16c407a7U, 0x02c06b9dU, >+// 5**162 (i=6), start=30, end=42 >+ 0x960f7199U, 0x056667ecU, 0xe07aefd8U, 0x80f2b9ccU, 0x8273f5e3U, 0xeb9a214aU, >+ 0x40b38005U, 0x0e477ad4U, 0x277d08e6U, 0xfa28b11eU, 0xd3f7d784U, 0x011c835bU, >+// 5**189 (i=7), start=42, end=56 >+ 0xf723d9d5U, 0x3282d3f3U, 0xe00857d1U, 0x69659d25U, 0x2cf117cfU, 0x24da6d07U, >+ 0x954d1417U, 0x3e5d8cedU, 0x7a8bb766U, 0xfd785ae6U, 0x645436d2U, 0x40c78b34U, >+ 0x94151217U, 0x0072e9f7U, >+// 5**216 (i=8), start=56, end=72 >+ 0x2b416aa1U, 0x7893c5a7U, 0xe37dc6d4U, 0x2bad2beaU, 0xf0fc846cU, 0x7575ae4bU, >+ 0x62587b14U, 0x83b67a34U, 0x02110cdbU, 0xf7992f55U, 0x00deb022U, 0xa4a23becU, >+ 0x8af5c5cdU, 0xb85b654fU, 0x818df38bU, 0x002e69d2U, >+// 5**243 (i=9), start=72, end=90 >+ 0x3518cbbdU, 0x20b0c15fU, 0x38756c2fU, 0xfb5dc3ddU, 0x22ad2d94U, 0xbf35a952U, >+ 0xa699192aU, 0x9a613326U, 0xad2a9cedU, 0xd7f48968U, 0xe87dfb54U, 0xc8f05db6U, >+ 0x5ef67531U, 0x31c1ab49U, 0xe202ac9fU, 0x9b2957b5U, 0xa143f6d3U, 0x0012bf07U, >+// 5**270 (i=10), start=90, end=110 >+ 0x8b971de9U, 0x21aba2e1U, 0x63944362U, 0x57172336U, 0xd9544225U, 0xfb534166U, >+ 0x08c563eeU, 0x14640ee2U, 0x24e40d31U, 0x02b06537U, 0x03887f14U, 0x0285e533U, >+ 0xb744ef26U, 0x8be3a6c4U, 0x266979b4U, 0x6761ece2U, 0xd9cb39e4U, 0xe67de319U, >+ 0x0d39e796U, 0x00079250U, >+// 5**297 (i=11), start=110, end=132 >+ 0x260eb6e5U, 0xf414a796U, 0xee1a7491U, 0xdb9368ebU, 0xf50c105bU, 0x59157750U, >+ 0x9ed2fb5cU, 0xf6e56d8bU, 0xeaee8d23U, 0x0f319f75U, 0x2aa134d6U, 0xac2908e9U, >+ 0xd4413298U, 0x02f02a55U, 0x989d5a7aU, 0x70dde184U, 0xba8040a7U, 0x03200981U, >+ 0xbe03b11cU, 0x3c1c2a18U, 0xd60427a1U, 0x00030ee0U, >+// 5**324 (i=12), start=132, end=156 >+ 0xce566d71U, 0xf1c4aa25U, 0x4e93ca53U, 0xa72283d0U, 0x551a73eaU, 0x3d0538e2U, >+ 0x8da4303fU, 0x6a58de60U, 0x0e660221U, 0x49cf61a6U, 0x8d058fc1U, 0xb9d1a14cU, >+ 0x4bab157dU, 0xc85c6932U, 0x518c8b9eU, 0x9b92b8d0U, 0x0d8a0e21U, 0xbd855df9U, >+ 0xb3ea59a1U, 0x8da29289U, 0x4584d506U, 0x3752d80fU, 0xb72569c6U, 0x00013c33U, >+// 5**351 (i=13), start=156, end=182 >+ 0x190f354dU, 0x83695cfeU, 0xe5a4d0c7U, 0xb60fb7e8U, 0xee5bbcc4U, 0xb922054cU, >+ 0xbb4f0d85U, 0x48394028U, 0x1d8957dbU, 0x0d7edb14U, 0x4ecc7587U, 0x505e9e02U, >+ 0x4c87f36bU, 0x99e66bd6U, 0x44b9ed35U, 0x753037d4U, 0xe5fe5f27U, 0x2742c203U, >+ 0x13b2ed2bU, 0xdc525d2cU, 0xe6fde59aU, 0x77ffb18fU, 0x13c5752cU, 0x08a84bccU, >+ 0x859a4940U, 0x00007fb6U, >+// 5**378 (i=14), start=182, end=210 >+ 0x4f98cb39U, 0xa60edbbcU, 0x83b5872eU, 0xa501acffU, 0x9cc76f78U, 0xbadd4c73U, >+ 0x43e989faU, 0xca7acf80U, 0x2e0c824fU, 0xb19f4ffcU, 0x092fd81cU, 0xe4eb645bU, >+ 0xa1ff84c2U, 0x8a5a83baU, 0xa8a1fae9U, 0x1db43609U, 0xb0fed50bU, 0x0dd7d2bdU, >+ 0x7d7accd8U, 0x91fa640fU, 0x37dcc6c5U, 0x1c417fd5U, 0xe4d462adU, 0xe8a43399U, >+ 0x131bf9a5U, 0x8df54d29U, 0x36547dc1U, 0x00003395U, >+// 5**405 (i=15), start=210, end=240 >+ 0x5bd330f5U, 0x77d21967U, 0x1ac481b7U, 0x6be2f7ceU, 0x7f4792a9U, 0xe84c2c52U, >+ 0x84592228U, 0x9dcaf829U, 0xdab44ce1U, 0x3d0c311bU, 0x532e297dU, 0x4704e8b4U, >+ 0x9cdc32beU, 0x41e64d9dU, 0x7717bea1U, 0xa824c00dU, 0x08f50b27U, 0x0f198d77U, >+ 0x49bbfdf0U, 0x025c6c69U, 0xd4e55cd3U, 0xf083602bU, 0xb9f0fecdU, 0xc0864aeaU, >+ 0x9cb98681U, 0xaaf620e9U, 0xacb6df30U, 0x4faafe66U, 0x8af13c3bU, 0x000014d5U, >+// 5**432 (i=16), start=240, end=272 >+ 0x682bb941U, 0x89a9f297U, 0xcba75d7bU, 0x404217b1U, 0xb4e519e9U, 0xa1bc162bU, >+ 0xf7f5910aU, 0x98715af5U, 0x2ff53e57U, 0xe3ef118cU, 0x490c4543U, 0xbc9b1734U, >+ 0x2affbe4dU, 0x4cedcb4cU, 0xfb14e99eU, 0x35e34212U, 0xece39c24U, 0x07673ab3U, >+ 0xe73115ddU, 0xd15d38e7U, 0x093eed3bU, 0xf8e7eac5U, 0x78a8cc80U, 0x25227aacU, >+ 0x3f590551U, 0x413da1cbU, 0xdf643a55U, 0xab65ad44U, 0xd70b23d7U, 0xc672cd76U, >+ 0x3364ea62U, 0x0000086aU, >+// 5**459 (i=17), start=272, end=306 >+ 0x22f163ddU, 0x23cf07acU, 0xbe2af6c2U, 0xf412f6f6U, 0xc3ff541eU, 0x6eeaf7deU, >+ 0xa47047e0U, 0x408cda92U, 0x0f0eeb08U, 0x56deba9dU, 0xcfc6b090U, 0x8bbbdf04U, >+ 0x3933cdb3U, 0x9e7bb67dU, 0x9f297035U, 0x38946244U, 0xee1d37bbU, 0xde898174U, >+ 0x63f3559dU, 0x705b72fbU, 0x138d27d9U, 0xf8603a78U, 0x735eec44U, 0xe30987d5U, >+ 0xc6d38070U, 0x9cfe548eU, 0x9ff01422U, 0x7c564aa8U, 0x91cc60baU, 0xcbc3565dU, >+ 0x7550a50bU, 0x6909aeadU, 0x13234c45U, 0x00000366U, >+// 5**486 (i=18), start=306, end=342 >+ 0x17954989U, 0x3a7d7709U, 0x98042de5U, 0xa9011443U, 0x45e723c2U, 0x269ffd6fU, >+ 0x58852a46U, 0xaaa1042aU, 0x2eee8153U, 0xb2b6c39eU, 0xaf845b65U, 0xf6c365d7U, >+ 0xe4cffb2bU, 0xc840e90cU, 0xabea8abbU, 0x5c58f8d2U, 0x5c19fa3aU, 0x4670910aU, >+ 0x4449f21cU, 0xefa645b3U, 0xcc427decU, 0x083c3d73U, 0x467cb413U, 0x6fe10ae4U, >+ 0x3caffc72U, 0x9f8da55eU, 0x5e5c8ea7U, 0x490594bbU, 0xf0871b0bU, 0xdd89816cU, >+ 0x8e931df8U, 0xe85ce1c9U, 0xcca090a5U, 0x575fa16bU, 0x6b9f106cU, 0x0000015fU, >+// 5**513 (i=19), start=342, end=380 >+ 0xee20d805U, 0x57bc3c07U, 0xcdea624eU, 0xd3f0f52dU, 0x9924b4f4U, 0xcf968640U, >+ 0x61d41962U, 0xe87fb464U, 0xeaaf51c7U, 0x564c8b60U, 0xccda4028U, 0x529428bbU, >+ 0x313a1fa8U, 0x96bd0f94U, 0x7a82ebaaU, 0xad99e7e9U, 0xf2668cd4U, 0xbe33a45eU, >+ 0xfd0db669U, 0x87ee369fU, 0xd3ec20edU, 0x9c4d7db7U, 0xdedcf0d8U, 0x7cd2ca64U, >+ 0xe25a6577U, 0x61003fd4U, 0xe56f54ccU, 0x10b7c748U, 0x40526e5eU, 0x7300ae87U, >+ 0x5c439261U, 0x2c0ff469U, 0xbf723f12U, 0xb2379b61U, 0xbf59b4f5U, 0xc91b1c3fU, >+ 0xf0046d27U, 0x0000008dU, >+// 5**540 (i=20), start=380, end=420 >+ 0x525c9e11U, 0xf4e0eb41U, 0xebb2895dU, 0x5da512f9U, 0x7d9b29d4U, 0x452f4edcU, >+ 0x0b90bc37U, 0x341777cbU, 0x63d269afU, 0x1da77929U, 0x0a5c1826U, 0x77991898U, >+ 0x5aeddf86U, 0xf853a877U, 0x538c31ccU, 0xe84896daU, 0xb7a0010bU, 0x17ef4de5U, >+ 0xa52a2adeU, 0x029fd81cU, 0x987ce701U, 0x27fefd77U, 0xdb46c66fU, 0x5d301900U, >+ 0x496998c0U, 0xbb6598b9U, 0x5eebb607U, 0xe547354aU, 0xdf4a2f7eU, 0xf06c4955U, >+ 0x96242ffaU, 0x1775fb27U, 0xbecc58ceU, 0xebf2a53bU, 0x3eaad82aU, 0xf41137baU, >+ 0x573e6fbaU, 0xfb4866b8U, 0x54002148U, 0x00000039U, >+}; >+// clang-format on >+ >+// Returns a pointer to the big integer data for (5**27)**i. i must be >+// between 1 and 20, inclusive. >+const uint32_t* LargePowerOfFiveData(int i) { >+ return kLargePowersOfFive + i * (i - 1); >+} >+ >+// Returns the size of the big integer data for (5**27)**i, in words. i must be >+// between 1 and 20, inclusive. >+int LargePowerOfFiveSize(int i) { return 2 * i; } >+} // namespace >+ >+const uint32_t kFiveToNth[14] = { >+ 1, 5, 25, 125, 625, 3125, 15625, >+ 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, >+}; >+ >+const uint32_t kTenToNth[10] = { >+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, >+}; >+ >+template <int max_words> >+int BigUnsigned<max_words>::ReadFloatMantissa(const ParsedFloat& fp, >+ int significant_digits) { >+ SetToZero(); >+ assert(fp.type == FloatType::kNumber); >+ >+ if (fp.subrange_begin == nullptr) { >+ // We already exactly parsed the mantissa, so no more work is necessary. >+ words_[0] = fp.mantissa & 0xffffffffu; >+ words_[1] = fp.mantissa >> 32; >+ if (words_[1]) { >+ size_ = 2; >+ } else if (words_[0]) { >+ size_ = 1; >+ } >+ return fp.exponent; >+ } >+ int exponent_adjust = >+ ReadDigits(fp.subrange_begin, fp.subrange_end, significant_digits); >+ return fp.literal_exponent + exponent_adjust; >+} >+ >+template <int max_words> >+int BigUnsigned<max_words>::ReadDigits(const char* begin, const char* end, >+ int significant_digits) { >+ assert(significant_digits <= Digits10() + 1); >+ SetToZero(); >+ >+ bool after_decimal_point = false; >+ // Discard any leading zeroes before the decimal point >+ while (begin < end && *begin == '0') { >+ ++begin; >+ } >+ int dropped_digits = 0; >+ // Discard any trailing zeroes. These may or may not be after the decimal >+ // point. >+ while (begin < end && *std::prev(end) == '0') { >+ --end; >+ ++dropped_digits; >+ } >+ if (begin < end && *std::prev(end) == '.') { >+ // If the std::string ends in '.', either before or after dropping zeroes, then >+ // drop the decimal point and look for more digits to drop. >+ dropped_digits = 0; >+ --end; >+ while (begin < end && *std::prev(end) == '0') { >+ --end; >+ ++dropped_digits; >+ } >+ } else if (dropped_digits) { >+ // We dropped digits, and aren't sure if they're before or after the decimal >+ // point. Figure that out now. >+ const char* dp = std::find(begin, end, '.'); >+ if (dp != end) { >+ // The dropped trailing digits were after the decimal point, so don't >+ // count them. >+ dropped_digits = 0; >+ } >+ } >+ // Any non-fraction digits we dropped need to be accounted for in our exponent >+ // adjustment. >+ int exponent_adjust = dropped_digits; >+ >+ uint32_t queued = 0; >+ int digits_queued = 0; >+ for (; begin != end && significant_digits > 0; ++begin) { >+ if (*begin == '.') { >+ after_decimal_point = true; >+ continue; >+ } >+ if (after_decimal_point) { >+ // For each fractional digit we emit in our parsed integer, adjust our >+ // decimal exponent to compensate. >+ --exponent_adjust; >+ } >+ int digit = (*begin - '0'); >+ --significant_digits; >+ if (significant_digits == 0 && std::next(begin) != end && >+ (digit == 0 || digit == 5)) { >+ // If this is the very last significant digit, but insignificant digits >+ // remain, we know that the last of those remaining significant digits is >+ // nonzero. (If it wasn't, we would have stripped it before we got here.) >+ // So if this final digit is a 0 or 5, adjust it upward by 1. >+ // >+ // This adjustment is what allows incredibly large mantissas ending in >+ // 500000...000000000001 to correctly round up, rather than to nearest. >+ ++digit; >+ } >+ queued = 10 * queued + digit; >+ ++digits_queued; >+ if (digits_queued == kMaxSmallPowerOfTen) { >+ MultiplyBy(kTenToNth[kMaxSmallPowerOfTen]); >+ AddWithCarry(0, queued); >+ queued = digits_queued = 0; >+ } >+ } >+ // Encode any remaining digits. >+ if (digits_queued) { >+ MultiplyBy(kTenToNth[digits_queued]); >+ AddWithCarry(0, queued); >+ } >+ >+ // If any insignificant digits remain, we will drop them. But if we have not >+ // yet read the decimal point, then we have to adjust the exponent to account >+ // for the dropped digits. >+ if (begin < end && !after_decimal_point) { >+ // This call to std::find will result in a pointer either to the decimal >+ // point, or to the end of our buffer if there was none. >+ // >+ // Either way, [begin, decimal_point) will contain the set of dropped digits >+ // that require an exponent adjustment. >+ const char* decimal_point = std::find(begin, end, '.'); >+ exponent_adjust += (decimal_point - begin); >+ } >+ return exponent_adjust; >+} >+ >+template <int max_words> >+/* static */ BigUnsigned<max_words> BigUnsigned<max_words>::FiveToTheNth( >+ int n) { >+ BigUnsigned answer(1u); >+ >+ // Seed from the table of large powers, if possible. >+ bool first_pass = true; >+ while (n >= kLargePowerOfFiveStep) { >+ int big_power = >+ std::min(n / kLargePowerOfFiveStep, kLargestPowerOfFiveIndex); >+ if (first_pass) { >+ // just copy, rather than multiplying by 1 >+ std::copy( >+ LargePowerOfFiveData(big_power), >+ LargePowerOfFiveData(big_power) + LargePowerOfFiveSize(big_power), >+ answer.words_); >+ answer.size_ = LargePowerOfFiveSize(big_power); >+ first_pass = false; >+ } else { >+ answer.MultiplyBy(LargePowerOfFiveSize(big_power), >+ LargePowerOfFiveData(big_power)); >+ } >+ n -= kLargePowerOfFiveStep * big_power; >+ } >+ answer.MultiplyByFiveToTheNth(n); >+ return answer; >+} >+ >+template <int max_words> >+void BigUnsigned<max_words>::MultiplyStep(int original_size, >+ const uint32_t* other_words, >+ int other_size, int step) { >+ int this_i = std::min(original_size - 1, step); >+ int other_i = step - this_i; >+ >+ uint64_t this_word = 0; >+ uint64_t carry = 0; >+ for (; this_i >= 0 && other_i < other_size; --this_i, ++other_i) { >+ uint64_t product = words_[this_i]; >+ product *= other_words[other_i]; >+ this_word += product; >+ carry += (this_word >> 32); >+ this_word &= 0xffffffff; >+ } >+ AddWithCarry(step + 1, carry); >+ words_[step] = this_word & 0xffffffff; >+ if (this_word > 0 && size_ <= step) { >+ size_ = step + 1; >+ } >+} >+ >+template <int max_words> >+std::string BigUnsigned<max_words>::ToString() const { >+ BigUnsigned<max_words> copy = *this; >+ std::string result; >+ // Build result in reverse order >+ while (copy.size() > 0) { >+ int next_digit = copy.DivMod<10>(); >+ result.push_back('0' + next_digit); >+ } >+ if (result.empty()) { >+ result.push_back('0'); >+ } >+ std::reverse(result.begin(), result.end()); >+ return result; >+} >+ >+template class BigUnsigned<4>; >+template class BigUnsigned<84>; >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h >new file mode 100644 >index 00000000000..aa70af2c289 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint.h >@@ -0,0 +1,426 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ >+#define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ >+ >+#include <algorithm> >+#include <cstdint> >+#include <iostream> >+#include <string> >+ >+#include "absl/strings/ascii.h" >+#include "absl/strings/internal/charconv_parse.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+// The largest power that 5 that can be raised to, and still fit in a uint32_t. >+constexpr int kMaxSmallPowerOfFive = 13; >+// The largest power that 10 that can be raised to, and still fit in a uint32_t. >+constexpr int kMaxSmallPowerOfTen = 9; >+ >+extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1]; >+extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; >+ >+// Large, fixed-width unsigned integer. >+// >+// Exact rounding for decimal-to-binary floating point conversion requires very >+// large integer math, but a design goal of absl::from_chars is to avoid >+// allocating memory. The integer precision needed for decimal-to-binary >+// conversions is large but bounded, so a huge fixed-width integer class >+// suffices. >+// >+// This is an intentionally limited big integer class. Only needed operations >+// are implemented. All storage lives in an array data member, and all >+// arithmetic is done in-place, to avoid requiring separate storage for operand >+// and result. >+// >+// This is an internal class. Some methods live in the .cc file, and are >+// instantiated only for the values of max_words we need. >+template <int max_words> >+class BigUnsigned { >+ public: >+ static_assert(max_words == 4 || max_words == 84, >+ "unsupported max_words value"); >+ >+ BigUnsigned() : size_(0), words_{} {} >+ explicit BigUnsigned(uint32_t v) : size_(v > 0 ? 1 : 0), words_{v} {} >+ explicit BigUnsigned(uint64_t v) >+ : size_(0), >+ words_{static_cast<uint32_t>(v & 0xffffffff), >+ static_cast<uint32_t>(v >> 32)} { >+ if (words_[1]) { >+ size_ = 2; >+ } else if (words_[0]) { >+ size_ = 1; >+ } >+ } >+ >+ // Constructs a BigUnsigned from the given string_view containing a decimal >+ // value. If the input std::string is not a decimal integer, constructs a 0 >+ // instead. >+ explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} { >+ // Check for valid input, returning a 0 otherwise. This is reasonable >+ // behavior only because this constructor is for unit tests. >+ if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() || >+ sv.empty()) { >+ return; >+ } >+ int exponent_adjust = >+ ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1); >+ if (exponent_adjust > 0) { >+ MultiplyByTenToTheNth(exponent_adjust); >+ } >+ } >+ >+ // Loads the mantissa value of a previously-parsed float. >+ // >+ // Returns the associated decimal exponent. The value of the parsed float is >+ // exactly *this * 10**exponent. >+ int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits); >+ >+ // Returns the number of decimal digits of precision this type provides. All >+ // numbers with this many decimal digits or fewer are representable by this >+ // type. >+ // >+ // Analagous to std::numeric_limits<BigUnsigned>::digits10. >+ static constexpr int Digits10() { >+ // 9975007/1035508 is very slightly less than log10(2**32). >+ return static_cast<uint64_t>(max_words) * 9975007 / 1035508; >+ } >+ >+ // Shifts left by the given number of bits. >+ void ShiftLeft(int count) { >+ if (count > 0) { >+ const int word_shift = count / 32; >+ if (word_shift >= max_words) { >+ SetToZero(); >+ return; >+ } >+ size_ = std::min(size_ + word_shift, max_words); >+ count %= 32; >+ if (count == 0) { >+ std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_); >+ } else { >+ for (int i = std::min(size_, max_words - 1); i > word_shift; --i) { >+ words_[i] = (words_[i - word_shift] << count) | >+ (words_[i - word_shift - 1] >> (32 - count)); >+ } >+ words_[word_shift] = words_[0] << count; >+ // Grow size_ if necessary. >+ if (size_ < max_words && words_[size_]) { >+ ++size_; >+ } >+ } >+ std::fill(words_, words_ + word_shift, 0u); >+ } >+ } >+ >+ >+ // Multiplies by v in-place. >+ void MultiplyBy(uint32_t v) { >+ if (size_ == 0 || v == 1) { >+ return; >+ } >+ if (v == 0) { >+ SetToZero(); >+ return; >+ } >+ const uint64_t factor = v; >+ uint64_t window = 0; >+ for (int i = 0; i < size_; ++i) { >+ window += factor * words_[i]; >+ words_[i] = window & 0xffffffff; >+ window >>= 32; >+ } >+ // If carry bits remain and there's space for them, grow size_. >+ if (window && size_ < max_words) { >+ words_[size_] = window & 0xffffffff; >+ ++size_; >+ } >+ } >+ >+ void MultiplyBy(uint64_t v) { >+ uint32_t words[2]; >+ words[0] = static_cast<uint32_t>(v); >+ words[1] = static_cast<uint32_t>(v >> 32); >+ if (words[1] == 0) { >+ MultiplyBy(words[0]); >+ } else { >+ MultiplyBy(2, words); >+ } >+ } >+ >+ // Multiplies in place by 5 to the power of n. n must be non-negative. >+ void MultiplyByFiveToTheNth(int n) { >+ while (n >= kMaxSmallPowerOfFive) { >+ MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]); >+ n -= kMaxSmallPowerOfFive; >+ } >+ if (n > 0) { >+ MultiplyBy(kFiveToNth[n]); >+ } >+ } >+ >+ // Multiplies in place by 10 to the power of n. n must be non-negative. >+ void MultiplyByTenToTheNth(int n) { >+ if (n > kMaxSmallPowerOfTen) { >+ // For large n, raise to a power of 5, then shift left by the same amount. >+ // (10**n == 5**n * 2**n.) This requires fewer multiplications overall. >+ MultiplyByFiveToTheNth(n); >+ ShiftLeft(n); >+ } else if (n > 0) { >+ // We can do this more quickly for very small N by using a single >+ // multiplication. >+ MultiplyBy(kTenToNth[n]); >+ } >+ } >+ >+ // Returns the value of 5**n, for non-negative n. This implementation uses >+ // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling >+ // MultiplyByFiveToTheNth(). >+ static BigUnsigned FiveToTheNth(int n); >+ >+ // Multiplies by another BigUnsigned, in-place. >+ template <int M> >+ void MultiplyBy(const BigUnsigned<M>& other) { >+ MultiplyBy(other.size(), other.words()); >+ } >+ >+ void SetToZero() { >+ std::fill(words_, words_ + size_, 0u); >+ size_ = 0; >+ } >+ >+ // Returns the value of the nth word of this BigUnsigned. This is >+ // range-checked, and returns 0 on out-of-bounds accesses. >+ uint32_t GetWord(int index) const { >+ if (index < 0 || index >= size_) { >+ return 0; >+ } >+ return words_[index]; >+ } >+ >+ // Returns this integer as a decimal std::string. This is not used in the decimal- >+ // to-binary conversion; it is intended to aid in testing. >+ std::string ToString() const; >+ >+ int size() const { return size_; } >+ const uint32_t* words() const { return words_; } >+ >+ private: >+ // Reads the number between [begin, end), possibly containing a decimal point, >+ // into this BigUnsigned. >+ // >+ // Callers are required to ensure [begin, end) contains a valid number, with >+ // one or more decimal digits and at most one decimal point. This routine >+ // will behave unpredictably if these preconditions are not met. >+ // >+ // Only the first `significant_digits` digits are read. Digits beyond this >+ // limit are "sticky": If the final significant digit is 0 or 5, and if any >+ // dropped digit is nonzero, then that final significant digit is adjusted up >+ // to 1 or 6. This adjustment allows for precise rounding. >+ // >+ // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to >+ // account for the decimal point and for dropped significant digits. After >+ // this function returns, >+ // actual_value_of_parsed_string ~= *this * 10**exponent_adjustment. >+ int ReadDigits(const char* begin, const char* end, int significant_digits); >+ >+ // Performs a step of big integer multiplication. This computes the full >+ // (64-bit-wide) values that should be added at the given index (step), and >+ // adds to that location in-place. >+ // >+ // Because our math all occurs in place, we must multiply starting from the >+ // highest word working downward. (This is a bit more expensive due to the >+ // extra carries involved.) >+ // >+ // This must be called in steps, for each word to be calculated, starting from >+ // the high end and working down to 0. The first value of `step` should be >+ // `std::min(original_size + other.size_ - 2, max_words - 1)`. >+ // The reason for this expression is that multiplying the i'th word from one >+ // multiplicand and the j'th word of another multiplicand creates a >+ // two-word-wide value to be stored at the (i+j)'th element. The highest >+ // word indices we will access are `original_size - 1` from this object, and >+ // `other.size_ - 1` from our operand. Therefore, >+ // `original_size + other.size_ - 2` is the first step we should calculate, >+ // but limited on an upper bound by max_words. >+ >+ // Working from high-to-low ensures that we do not overwrite the portions of >+ // the initial value of *this which are still needed for later steps. >+ // >+ // Once called with step == 0, *this contains the result of the >+ // multiplication. >+ // >+ // `original_size` is the size_ of *this before the first call to >+ // MultiplyStep(). `other_words` and `other_size` are the contents of our >+ // operand. `step` is the step to perform, as described above. >+ void MultiplyStep(int original_size, const uint32_t* other_words, >+ int other_size, int step); >+ >+ void MultiplyBy(int other_size, const uint32_t* other_words) { >+ const int original_size = size_; >+ const int first_step = >+ std::min(original_size + other_size - 2, max_words - 1); >+ for (int step = first_step; step >= 0; --step) { >+ MultiplyStep(original_size, other_words, other_size, step); >+ } >+ } >+ >+ // Adds a 32-bit value to the index'th word, with carry. >+ void AddWithCarry(int index, uint32_t value) { >+ if (value) { >+ while (index < max_words && value > 0) { >+ words_[index] += value; >+ // carry if we overflowed in this word: >+ if (value > words_[index]) { >+ value = 1; >+ ++index; >+ } else { >+ value = 0; >+ } >+ } >+ size_ = std::min(max_words, std::max(index + 1, size_)); >+ } >+ } >+ >+ void AddWithCarry(int index, uint64_t value) { >+ if (value && index < max_words) { >+ uint32_t high = value >> 32; >+ uint32_t low = value & 0xffffffff; >+ words_[index] += low; >+ if (words_[index] < low) { >+ ++high; >+ if (high == 0) { >+ // Carry from the low word caused our high word to overflow. >+ // Short circuit here to do the right thing. >+ AddWithCarry(index + 2, static_cast<uint32_t>(1)); >+ return; >+ } >+ } >+ if (high > 0) { >+ AddWithCarry(index + 1, high); >+ } else { >+ // Normally 32-bit AddWithCarry() sets size_, but since we don't call >+ // it when `high` is 0, do it ourselves here. >+ size_ = std::min(max_words, std::max(index + 1, size_)); >+ } >+ } >+ } >+ >+ // Divide this in place by a constant divisor. Returns the remainder of the >+ // division. >+ template <uint32_t divisor> >+ uint32_t DivMod() { >+ uint64_t accumulator = 0; >+ for (int i = size_ - 1; i >= 0; --i) { >+ accumulator <<= 32; >+ accumulator += words_[i]; >+ // accumulator / divisor will never overflow an int32_t in this loop >+ words_[i] = static_cast<uint32_t>(accumulator / divisor); >+ accumulator = accumulator % divisor; >+ } >+ while (size_ > 0 && words_[size_ - 1] == 0) { >+ --size_; >+ } >+ return static_cast<uint32_t>(accumulator); >+ } >+ >+ // The number of elements in words_ that may carry significant values. >+ // All elements beyond this point are 0. >+ // >+ // When size_ is 0, this BigUnsigned stores the value 0. >+ // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is >+ // nonzero. This can occur due to overflow truncation. >+ // In particular, x.size_ != y.size_ does *not* imply x != y. >+ int size_; >+ uint32_t words_[max_words]; >+}; >+ >+// Compares two big integer instances. >+// >+// Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. >+template <int N, int M> >+int Compare(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ int limit = std::max(lhs.size(), rhs.size()); >+ for (int i = limit - 1; i >= 0; --i) { >+ const uint32_t lhs_word = lhs.GetWord(i); >+ const uint32_t rhs_word = rhs.GetWord(i); >+ if (lhs_word < rhs_word) { >+ return -1; >+ } else if (lhs_word > rhs_word) { >+ return 1; >+ } >+ } >+ return 0; >+} >+ >+template <int N, int M> >+bool operator==(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ int limit = std::max(lhs.size(), rhs.size()); >+ for (int i = 0; i < limit; ++i) { >+ if (lhs.GetWord(i) != rhs.GetWord(i)) { >+ return false; >+ } >+ } >+ return true; >+} >+ >+template <int N, int M> >+bool operator!=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ return !(lhs == rhs); >+} >+ >+template <int N, int M> >+bool operator<(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ return Compare(lhs, rhs) == -1; >+} >+ >+template <int N, int M> >+bool operator>(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ return rhs < lhs; >+} >+template <int N, int M> >+bool operator<=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ return !(rhs < lhs); >+} >+template <int N, int M> >+bool operator>=(const BigUnsigned<N>& lhs, const BigUnsigned<M>& rhs) { >+ return !(lhs < rhs); >+} >+ >+// Output operator for BigUnsigned, for testing purposes only. >+template <int N> >+std::ostream& operator<<(std::ostream& os, const BigUnsigned<N>& num) { >+ return os << num.ToString(); >+} >+ >+// Explicit instantiation declarations for the sizes of BigUnsigned that we >+// are using. >+// >+// For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is >+// still bigger than an int128, and 84 is a large value we will want to use >+// in the from_chars implementation. >+// >+// Comments justifying the use of 84 belong in the from_chars implementation, >+// and will be added in a follow-up CL. >+extern template class BigUnsigned<4>; >+extern template class BigUnsigned<84>; >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc >new file mode 100644 >index 00000000000..9b6357888fb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_bigint_test.cc >@@ -0,0 +1,203 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/charconv_bigint.h" >+ >+#include <string> >+ >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+TEST(BigUnsigned, ShiftLeft) { >+ { >+ // Check that 3 * 2**100 is calculated correctly >+ BigUnsigned<4> num(3u); >+ num.ShiftLeft(100); >+ EXPECT_EQ(num, BigUnsigned<4>("3802951800684688204490109616128")); >+ } >+ { >+ // Test that overflow is truncated properly. >+ // 15 is 4 bits long, and BigUnsigned<4> is a 128-bit bigint. >+ // Shifting left by 125 bits should truncate off the high bit, so that >+ // 15 << 125 == 7 << 125 >+ // after truncation. >+ BigUnsigned<4> a(15u); >+ BigUnsigned<4> b(7u); >+ BigUnsigned<4> c(3u); >+ a.ShiftLeft(125); >+ b.ShiftLeft(125); >+ c.ShiftLeft(125); >+ EXPECT_EQ(a, b); >+ EXPECT_NE(a, c); >+ } >+ { >+ // Same test, larger bigint: >+ BigUnsigned<84> a(15u); >+ BigUnsigned<84> b(7u); >+ BigUnsigned<84> c(3u); >+ a.ShiftLeft(84 * 32 - 3); >+ b.ShiftLeft(84 * 32 - 3); >+ c.ShiftLeft(84 * 32 - 3); >+ EXPECT_EQ(a, b); >+ EXPECT_NE(a, c); >+ } >+ { >+ // Check that incrementally shifting has the same result as doing it all at >+ // once (attempting to capture corner cases.) >+ const std::string seed = "1234567890123456789012345678901234567890"; >+ BigUnsigned<84> a(seed); >+ for (int i = 1; i <= 84 * 32; ++i) { >+ a.ShiftLeft(1); >+ BigUnsigned<84> b(seed); >+ b.ShiftLeft(i); >+ EXPECT_EQ(a, b); >+ } >+ // And we should have fully rotated all bits off by now: >+ EXPECT_EQ(a, BigUnsigned<84>(0u)); >+ } >+} >+ >+TEST(BigUnsigned, MultiplyByUint32) { >+ const BigUnsigned<84> factorial_100( >+ "933262154439441526816992388562667004907159682643816214685929638952175999" >+ "932299156089414639761565182862536979208272237582511852109168640000000000" >+ "00000000000000"); >+ BigUnsigned<84> a(1u); >+ for (uint32_t i = 1; i <= 100; ++i) { >+ a.MultiplyBy(i); >+ } >+ EXPECT_EQ(a, BigUnsigned<84>(factorial_100)); >+} >+ >+TEST(BigUnsigned, MultiplyByBigUnsigned) { >+ { >+ // Put the terms of factorial_200 into two bigints, and multiply them >+ // together. >+ const BigUnsigned<84> factorial_200( >+ "7886578673647905035523632139321850622951359776871732632947425332443594" >+ "4996340334292030428401198462390417721213891963883025764279024263710506" >+ "1926624952829931113462857270763317237396988943922445621451664240254033" >+ "2918641312274282948532775242424075739032403212574055795686602260319041" >+ "7032406235170085879617892222278962370389737472000000000000000000000000" >+ "0000000000000000000000000"); >+ BigUnsigned<84> evens(1u); >+ BigUnsigned<84> odds(1u); >+ for (uint32_t i = 1; i < 200; i += 2) { >+ odds.MultiplyBy(i); >+ evens.MultiplyBy(i + 1); >+ } >+ evens.MultiplyBy(odds); >+ EXPECT_EQ(evens, factorial_200); >+ } >+ { >+ // Multiply various powers of 10 together. >+ for (int a = 0 ; a < 700; a += 25) { >+ SCOPED_TRACE(a); >+ BigUnsigned<84> a_value("3" + std::string(a, '0')); >+ for (int b = 0; b < (700 - a); b += 25) { >+ SCOPED_TRACE(b); >+ BigUnsigned<84> b_value("2" + std::string(b, '0')); >+ BigUnsigned<84> expected_product("6" + std::string(a + b, '0')); >+ b_value.MultiplyBy(a_value); >+ EXPECT_EQ(b_value, expected_product); >+ } >+ } >+ } >+} >+ >+TEST(BigUnsigned, MultiplyByOverflow) { >+ { >+ // Check that multiplcation overflow predictably truncates. >+ >+ // A big int with all bits on. >+ BigUnsigned<4> all_bits_on("340282366920938463463374607431768211455"); >+ // Modulo 2**128, this is equal to -1. Therefore the square of this, >+ // modulo 2**128, should be 1. >+ all_bits_on.MultiplyBy(all_bits_on); >+ EXPECT_EQ(all_bits_on, BigUnsigned<4>(1u)); >+ } >+ { >+ // Try multiplying a large bigint by 2**50, and compare the result to >+ // shifting. >+ BigUnsigned<4> value_1("12345678901234567890123456789012345678"); >+ BigUnsigned<4> value_2("12345678901234567890123456789012345678"); >+ BigUnsigned<4> two_to_fiftieth(1u); >+ two_to_fiftieth.ShiftLeft(50); >+ >+ value_1.ShiftLeft(50); >+ value_2.MultiplyBy(two_to_fiftieth); >+ EXPECT_EQ(value_1, value_2); >+ } >+} >+ >+TEST(BigUnsigned, FiveToTheNth) { >+ { >+ // Sanity check that MultiplyByFiveToTheNth gives consistent answers, up to >+ // and including overflow. >+ for (int i = 0; i < 1160; ++i) { >+ SCOPED_TRACE(i); >+ BigUnsigned<84> value_1(123u); >+ BigUnsigned<84> value_2(123u); >+ value_1.MultiplyByFiveToTheNth(i); >+ for (int j = 0; j < i; j++) { >+ value_2.MultiplyBy(5u); >+ } >+ EXPECT_EQ(value_1, value_2); >+ } >+ } >+ { >+ // Check that the faster, table-lookup-based static method returns the same >+ // result that multiplying in-place would return, up to and including >+ // overflow. >+ for (int i = 0; i < 1160; ++i) { >+ SCOPED_TRACE(i); >+ BigUnsigned<84> value_1(1u); >+ value_1.MultiplyByFiveToTheNth(i); >+ BigUnsigned<84> value_2 = BigUnsigned<84>::FiveToTheNth(i); >+ EXPECT_EQ(value_1, value_2); >+ } >+ } >+} >+ >+TEST(BigUnsigned, TenToTheNth) { >+ { >+ // Sanity check MultiplyByTenToTheNth. >+ for (int i = 0; i < 800; ++i) { >+ SCOPED_TRACE(i); >+ BigUnsigned<84> value_1(123u); >+ BigUnsigned<84> value_2(123u); >+ value_1.MultiplyByTenToTheNth(i); >+ for (int j = 0; j < i; j++) { >+ value_2.MultiplyBy(10u); >+ } >+ EXPECT_EQ(value_1, value_2); >+ } >+ } >+ { >+ // Alternate testing approach, taking advantage of the decimal parser. >+ for (int i = 0; i < 200; ++i) { >+ SCOPED_TRACE(i); >+ BigUnsigned<84> value_1(135u); >+ value_1.MultiplyByTenToTheNth(i); >+ BigUnsigned<84> value_2("135" + std::string(i, '0')); >+ EXPECT_EQ(value_1, value_2); >+ } >+ } >+} >+ >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc >new file mode 100644 >index 00000000000..a04cc67669a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.cc >@@ -0,0 +1,496 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/charconv_parse.h" >+#include "absl/strings/charconv.h" >+ >+#include <cassert> >+#include <cstdint> >+#include <limits> >+ >+#include "absl/strings/internal/memutil.h" >+ >+namespace absl { >+namespace { >+ >+// ParseFloat<10> will read the first 19 significant digits of the mantissa. >+// This number was chosen for multiple reasons. >+// >+// (a) First, for whatever integer type we choose to represent the mantissa, we >+// want to choose the largest possible number of decimal digits for that integer >+// type. We are using uint64_t, which can express any 19-digit unsigned >+// integer. >+// >+// (b) Second, we need to parse enough digits that the binary value of any >+// mantissa we capture has more bits of resolution than the mantissa >+// representation in the target float. Our algorithm requires at least 3 bits >+// of headway, but 19 decimal digits give a little more than that. >+// >+// The following static assertions verify the above comments: >+constexpr int kDecimalMantissaDigitsMax = 19; >+ >+static_assert(std::numeric_limits<uint64_t>::digits10 == >+ kDecimalMantissaDigitsMax, >+ "(a) above"); >+ >+// IEEE doubles, which we assume in Abseil, have 53 binary bits of mantissa. >+static_assert(std::numeric_limits<double>::is_iec559, "IEEE double assumed"); >+static_assert(std::numeric_limits<double>::radix == 2, "IEEE double fact"); >+static_assert(std::numeric_limits<double>::digits == 53, "IEEE double fact"); >+ >+// The lowest valued 19-digit decimal mantissa we can read still contains >+// sufficient information to reconstruct a binary mantissa. >+static_assert(1000000000000000000u > (uint64_t(1) << (53 + 3)), "(b) above"); >+ >+// ParseFloat<16> will read the first 15 significant digits of the mantissa. >+// >+// Because a base-16-to-base-2 conversion can be done exactly, we do not need >+// to maximize the number of scanned hex digits to improve our conversion. What >+// is required is to scan two more bits than the mantissa can represent, so that >+// we always round correctly. >+// >+// (One extra bit does not suffice to perform correct rounding, since a number >+// exactly halfway between two representable floats has unique rounding rules, >+// so we need to differentiate between a "halfway between" number and a "closer >+// to the larger value" number.) >+constexpr int kHexadecimalMantissaDigitsMax = 15; >+ >+// The minimum number of significant bits that will be read from >+// kHexadecimalMantissaDigitsMax hex digits. We must subtract by three, since >+// the most significant digit can be a "1", which only contributes a single >+// significant bit. >+constexpr int kGuaranteedHexadecimalMantissaBitPrecision = >+ 4 * kHexadecimalMantissaDigitsMax - 3; >+ >+static_assert(kGuaranteedHexadecimalMantissaBitPrecision > >+ std::numeric_limits<double>::digits + 2, >+ "kHexadecimalMantissaDigitsMax too small"); >+ >+// We also impose a limit on the number of significant digits we will read from >+// an exponent, to avoid having to deal with integer overflow. We use 9 for >+// this purpose. >+// >+// If we read a 9 digit exponent, the end result of the conversion will >+// necessarily be infinity or zero, depending on the sign of the exponent. >+// Therefore we can just drop extra digits on the floor without any extra >+// logic. >+constexpr int kDecimalExponentDigitsMax = 9; >+static_assert(std::numeric_limits<int>::digits10 >= kDecimalExponentDigitsMax, >+ "int type too small"); >+ >+// To avoid incredibly large inputs causing integer overflow for our exponent, >+// we impose an arbitrary but very large limit on the number of significant >+// digits we will accept. The implementation refuses to match a std::string with >+// more consecutive significant mantissa digits than this. >+constexpr int kDecimalDigitLimit = 50000000; >+ >+// Corresponding limit for hexadecimal digit inputs. This is one fourth the >+// amount of kDecimalDigitLimit, since each dropped hexadecimal digit requires >+// a binary exponent adjustment of 4. >+constexpr int kHexadecimalDigitLimit = kDecimalDigitLimit / 4; >+ >+// The largest exponent we can read is 999999999 (per >+// kDecimalExponentDigitsMax), and the largest exponent adjustment we can get >+// from dropped mantissa digits is 2 * kDecimalDigitLimit, and the sum of these >+// comfortably fits in an integer. >+// >+// We count kDecimalDigitLimit twice because there are independent limits for >+// numbers before and after the decimal point. (In the case where there are no >+// significant digits before the decimal point, there are independent limits for >+// post-decimal-point leading zeroes and for significant digits.) >+static_assert(999999999 + 2 * kDecimalDigitLimit < >+ std::numeric_limits<int>::max(), >+ "int type too small"); >+static_assert(999999999 + 2 * (4 * kHexadecimalDigitLimit) < >+ std::numeric_limits<int>::max(), >+ "int type too small"); >+ >+// Returns true if the provided bitfield allows parsing an exponent value >+// (e.g., "1.5e100"). >+bool AllowExponent(chars_format flags) { >+ bool fixed = (flags & chars_format::fixed) == chars_format::fixed; >+ bool scientific = >+ (flags & chars_format::scientific) == chars_format::scientific; >+ return scientific || !fixed; >+} >+ >+// Returns true if the provided bitfield requires an exponent value be present. >+bool RequireExponent(chars_format flags) { >+ bool fixed = (flags & chars_format::fixed) == chars_format::fixed; >+ bool scientific = >+ (flags & chars_format::scientific) == chars_format::scientific; >+ return scientific && !fixed; >+} >+ >+const int8_t kAsciiToInt[256] = { >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, >+ 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, >+ -1, -1, -1, -1, -1, -1, -1, -1, -1}; >+ >+// Returns true if `ch` is a digit in the given base >+template <int base> >+bool IsDigit(char ch); >+ >+// Converts a valid `ch` to its digit value in the given base. >+template <int base> >+unsigned ToDigit(char ch); >+ >+// Returns true if `ch` is the exponent delimiter for the given base. >+template <int base> >+bool IsExponentCharacter(char ch); >+ >+// Returns the maximum number of significant digits we will read for a float >+// in the given base. >+template <int base> >+constexpr int MantissaDigitsMax(); >+ >+// Returns the largest consecutive run of digits we will accept when parsing a >+// number in the given base. >+template <int base> >+constexpr int DigitLimit(); >+ >+// Returns the amount the exponent must be adjusted by for each dropped digit. >+// (For decimal this is 1, since the digits are in base 10 and the exponent base >+// is also 10, but for hexadecimal this is 4, since the digits are base 16 but >+// the exponent base is 2.) >+template <int base> >+constexpr int DigitMagnitude(); >+ >+template <> >+bool IsDigit<10>(char ch) { >+ return ch >= '0' && ch <= '9'; >+} >+template <> >+bool IsDigit<16>(char ch) { >+ return kAsciiToInt[static_cast<unsigned char>(ch)] >= 0; >+} >+ >+template <> >+unsigned ToDigit<10>(char ch) { >+ return ch - '0'; >+} >+template <> >+unsigned ToDigit<16>(char ch) { >+ return kAsciiToInt[static_cast<unsigned char>(ch)]; >+} >+ >+template <> >+bool IsExponentCharacter<10>(char ch) { >+ return ch == 'e' || ch == 'E'; >+} >+ >+template <> >+bool IsExponentCharacter<16>(char ch) { >+ return ch == 'p' || ch == 'P'; >+} >+ >+template <> >+constexpr int MantissaDigitsMax<10>() { >+ return kDecimalMantissaDigitsMax; >+} >+template <> >+constexpr int MantissaDigitsMax<16>() { >+ return kHexadecimalMantissaDigitsMax; >+} >+ >+template <> >+constexpr int DigitLimit<10>() { >+ return kDecimalDigitLimit; >+} >+template <> >+constexpr int DigitLimit<16>() { >+ return kHexadecimalDigitLimit; >+} >+ >+template <> >+constexpr int DigitMagnitude<10>() { >+ return 1; >+} >+template <> >+constexpr int DigitMagnitude<16>() { >+ return 4; >+} >+ >+// Reads decimal digits from [begin, end) into *out. Returns the number of >+// digits consumed. >+// >+// After max_digits has been read, keeps consuming characters, but no longer >+// adjusts *out. If a nonzero digit is dropped this way, *dropped_nonzero_digit >+// is set; otherwise, it is left unmodified. >+// >+// If no digits are matched, returns 0 and leaves *out unchanged. >+// >+// ConsumeDigits does not protect against overflow on *out; max_digits must >+// be chosen with respect to type T to avoid the possibility of overflow. >+template <int base, typename T> >+std::size_t ConsumeDigits(const char* begin, const char* end, int max_digits, >+ T* out, bool* dropped_nonzero_digit) { >+ if (base == 10) { >+ assert(max_digits <= std::numeric_limits<T>::digits10); >+ } else if (base == 16) { >+ assert(max_digits * 4 <= std::numeric_limits<T>::digits); >+ } >+ const char* const original_begin = begin; >+ T accumulator = *out; >+ const char* significant_digits_end = >+ (end - begin > max_digits) ? begin + max_digits : end; >+ while (begin < significant_digits_end && IsDigit<base>(*begin)) { >+ // Do not guard against *out overflow; max_digits was chosen to avoid this. >+ // Do assert against it, to detect problems in debug builds. >+ auto digit = static_cast<T>(ToDigit<base>(*begin)); >+ assert(accumulator * base >= accumulator); >+ accumulator *= base; >+ assert(accumulator + digit >= accumulator); >+ accumulator += digit; >+ ++begin; >+ } >+ bool dropped_nonzero = false; >+ while (begin < end && IsDigit<base>(*begin)) { >+ dropped_nonzero = dropped_nonzero || (*begin != '0'); >+ ++begin; >+ } >+ if (dropped_nonzero && dropped_nonzero_digit != nullptr) { >+ *dropped_nonzero_digit = true; >+ } >+ *out = accumulator; >+ return begin - original_begin; >+} >+ >+// Returns true if `v` is one of the chars allowed inside parentheses following >+// a NaN. >+bool IsNanChar(char v) { >+ return (v == '_') || (v >= '0' && v <= '9') || (v >= 'a' && v <= 'z') || >+ (v >= 'A' && v <= 'Z'); >+} >+ >+// Checks the range [begin, end) for a strtod()-formatted infinity or NaN. If >+// one is found, sets `out` appropriately and returns true. >+bool ParseInfinityOrNan(const char* begin, const char* end, >+ strings_internal::ParsedFloat* out) { >+ if (end - begin < 3) { >+ return false; >+ } >+ switch (*begin) { >+ case 'i': >+ case 'I': { >+ // An infinity std::string consists of the characters "inf" or "infinity", >+ // case insensitive. >+ if (strings_internal::memcasecmp(begin + 1, "nf", 2) != 0) { >+ return false; >+ } >+ out->type = strings_internal::FloatType::kInfinity; >+ if (end - begin >= 8 && >+ strings_internal::memcasecmp(begin + 3, "inity", 5) == 0) { >+ out->end = begin + 8; >+ } else { >+ out->end = begin + 3; >+ } >+ return true; >+ } >+ case 'n': >+ case 'N': { >+ // A NaN consists of the characters "nan", case insensitive, optionally >+ // followed by a parenthesized sequence of zero or more alphanumeric >+ // characters and/or underscores. >+ if (strings_internal::memcasecmp(begin + 1, "an", 2) != 0) { >+ return false; >+ } >+ out->type = strings_internal::FloatType::kNan; >+ out->end = begin + 3; >+ // NaN is allowed to be followed by a parenthesized std::string, consisting of >+ // only the characters [a-zA-Z0-9_]. Match that if it's present. >+ begin += 3; >+ if (begin < end && *begin == '(') { >+ const char* nan_begin = begin + 1; >+ while (nan_begin < end && IsNanChar(*nan_begin)) { >+ ++nan_begin; >+ } >+ if (nan_begin < end && *nan_begin == ')') { >+ // We found an extra NaN specifier range >+ out->subrange_begin = begin + 1; >+ out->subrange_end = nan_begin; >+ out->end = nan_begin + 1; >+ } >+ } >+ return true; >+ } >+ default: >+ return false; >+ } >+} >+} // namespace >+ >+namespace strings_internal { >+ >+template <int base> >+strings_internal::ParsedFloat ParseFloat(const char* begin, const char* end, >+ chars_format format_flags) { >+ strings_internal::ParsedFloat result; >+ >+ // Exit early if we're given an empty range. >+ if (begin == end) return result; >+ >+ // Handle the infinity and NaN cases. >+ if (ParseInfinityOrNan(begin, end, &result)) { >+ return result; >+ } >+ >+ const char* const mantissa_begin = begin; >+ while (begin < end && *begin == '0') { >+ ++begin; // skip leading zeros >+ } >+ uint64_t mantissa = 0; >+ >+ int exponent_adjustment = 0; >+ bool mantissa_is_inexact = false; >+ std::size_t pre_decimal_digits = ConsumeDigits<base>( >+ begin, end, MantissaDigitsMax<base>(), &mantissa, &mantissa_is_inexact); >+ begin += pre_decimal_digits; >+ int digits_left; >+ if (pre_decimal_digits >= DigitLimit<base>()) { >+ // refuse to parse pathological inputs >+ return result; >+ } else if (pre_decimal_digits > MantissaDigitsMax<base>()) { >+ // We dropped some non-fraction digits on the floor. Adjust our exponent >+ // to compensate. >+ exponent_adjustment = >+ static_cast<int>(pre_decimal_digits - MantissaDigitsMax<base>()); >+ digits_left = 0; >+ } else { >+ digits_left = >+ static_cast<int>(MantissaDigitsMax<base>() - pre_decimal_digits); >+ } >+ if (begin < end && *begin == '.') { >+ ++begin; >+ if (mantissa == 0) { >+ // If we haven't seen any nonzero digits yet, keep skipping zeros. We >+ // have to adjust the exponent to reflect the changed place value. >+ const char* begin_zeros = begin; >+ while (begin < end && *begin == '0') { >+ ++begin; >+ } >+ std::size_t zeros_skipped = begin - begin_zeros; >+ if (zeros_skipped >= DigitLimit<base>()) { >+ // refuse to parse pathological inputs >+ return result; >+ } >+ exponent_adjustment -= static_cast<int>(zeros_skipped); >+ } >+ std::size_t post_decimal_digits = ConsumeDigits<base>( >+ begin, end, digits_left, &mantissa, &mantissa_is_inexact); >+ begin += post_decimal_digits; >+ >+ // Since `mantissa` is an integer, each significant digit we read after >+ // the decimal point requires an adjustment to the exponent. "1.23e0" will >+ // be stored as `mantissa` == 123 and `exponent` == -2 (that is, >+ // "123e-2"). >+ if (post_decimal_digits >= DigitLimit<base>()) { >+ // refuse to parse pathological inputs >+ return result; >+ } else if (post_decimal_digits > digits_left) { >+ exponent_adjustment -= digits_left; >+ } else { >+ exponent_adjustment -= post_decimal_digits; >+ } >+ } >+ // If we've found no mantissa whatsoever, this isn't a number. >+ if (mantissa_begin == begin) { >+ return result; >+ } >+ // A bare "." doesn't count as a mantissa either. >+ if (begin - mantissa_begin == 1 && *mantissa_begin == '.') { >+ return result; >+ } >+ >+ if (mantissa_is_inexact) { >+ // We dropped significant digits on the floor. Handle this appropriately. >+ if (base == 10) { >+ // If we truncated significant decimal digits, store the full range of the >+ // mantissa for future big integer math for exact rounding. >+ result.subrange_begin = mantissa_begin; >+ result.subrange_end = begin; >+ } else if (base == 16) { >+ // If we truncated hex digits, reflect this fact by setting the low >+ // ("sticky") bit. This allows for correct rounding in all cases. >+ mantissa |= 1; >+ } >+ } >+ result.mantissa = mantissa; >+ >+ const char* const exponent_begin = begin; >+ result.literal_exponent = 0; >+ bool found_exponent = false; >+ if (AllowExponent(format_flags) && begin < end && >+ IsExponentCharacter<base>(*begin)) { >+ bool negative_exponent = false; >+ ++begin; >+ if (begin < end && *begin == '-') { >+ negative_exponent = true; >+ ++begin; >+ } else if (begin < end && *begin == '+') { >+ ++begin; >+ } >+ const char* const exponent_digits_begin = begin; >+ // Exponent is always expressed in decimal, even for hexadecimal floats. >+ begin += ConsumeDigits<10>(begin, end, kDecimalExponentDigitsMax, >+ &result.literal_exponent, nullptr); >+ if (begin == exponent_digits_begin) { >+ // there were no digits where we expected an exponent. We failed to read >+ // an exponent and should not consume the 'e' after all. Rewind 'begin'. >+ found_exponent = false; >+ begin = exponent_begin; >+ } else { >+ found_exponent = true; >+ if (negative_exponent) { >+ result.literal_exponent = -result.literal_exponent; >+ } >+ } >+ } >+ >+ if (!found_exponent && RequireExponent(format_flags)) { >+ // Provided flags required an exponent, but none was found. This results >+ // in a failure to scan. >+ return result; >+ } >+ >+ // Success! >+ result.type = strings_internal::FloatType::kNumber; >+ if (result.mantissa > 0) { >+ result.exponent = result.literal_exponent + >+ (DigitMagnitude<base>() * exponent_adjustment); >+ } else { >+ result.exponent = 0; >+ } >+ result.end = begin; >+ return result; >+} >+ >+template ParsedFloat ParseFloat<10>(const char* begin, const char* end, >+ chars_format format_flags); >+template ParsedFloat ParseFloat<16>(const char* begin, const char* end, >+ chars_format format_flags); >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.h >new file mode 100644 >index 00000000000..7a5c0874b80 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse.h >@@ -0,0 +1,96 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ >+#define ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ >+ >+#include <cstdint> >+ >+#include "absl/strings/charconv.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+// Enum indicating whether a parsed float is a number or special value. >+enum class FloatType { kNumber, kInfinity, kNan }; >+ >+// The decomposed parts of a parsed `float` or `double`. >+struct ParsedFloat { >+ // Representation of the parsed mantissa, with the decimal point adjusted to >+ // make it an integer. >+ // >+ // During decimal scanning, this contains 19 significant digits worth of >+ // mantissa value. If digits beyond this point are found, they >+ // are truncated, and if any of these dropped digits are nonzero, then >+ // `mantissa` is inexact, and the full mantissa is stored in [subrange_begin, >+ // subrange_end). >+ // >+ // During hexadecimal scanning, this contains 15 significant hex digits worth >+ // of mantissa value. Digits beyond this point are sticky -- they are >+ // truncated, but if any dropped digits are nonzero, the low bit of mantissa >+ // will be set. (This allows for precise rounding, and avoids the need >+ // to store the full mantissa in [subrange_begin, subrange_end).) >+ uint64_t mantissa = 0; >+ >+ // Floating point expontent. This reflects any decimal point adjustments and >+ // any truncated digits from the mantissa. The absolute value of the parsed >+ // number is represented by mantissa * (base ** exponent), where base==10 for >+ // decimal floats, and base==2 for hexadecimal floats. >+ int exponent = 0; >+ >+ // The literal exponent value scanned from the input, or 0 if none was >+ // present. This does not reflect any adjustments applied to mantissa. >+ int literal_exponent = 0; >+ >+ // The type of number scanned. >+ FloatType type = FloatType::kNumber; >+ >+ // When non-null, [subrange_begin, subrange_end) marks a range of characters >+ // that require further processing. The meaning is dependent on float type. >+ // If type == kNumber and this is set, this is a "wide input": the input >+ // mantissa contained more than 19 digits. The range contains the full >+ // mantissa. It plus `literal_exponent` need to be examined to find the best >+ // floating point match. >+ // If type == kNan and this is set, the range marks the contents of a >+ // matched parenthesized character region after the NaN. >+ const char* subrange_begin = nullptr; >+ const char* subrange_end = nullptr; >+ >+ // One-past-the-end of the successfully parsed region, or nullptr if no >+ // matching pattern was found. >+ const char* end = nullptr; >+}; >+ >+// Read the floating point number in the provided range, and populate >+// ParsedFloat accordingly. >+// >+// format_flags is a bitmask value specifying what patterns this API will match. >+// `scientific` and `fixed` are honored per std::from_chars rules >+// ([utility.from.chars], C++17): if exactly one of these bits is set, then an >+// exponent is required, or dislallowed, respectively. >+// >+// Template parameter `base` must be either 10 or 16. For base 16, a "0x" is >+// *not* consumed. The `hex` bit from format_flags is ignored by ParseFloat. >+template <int base> >+ParsedFloat ParseFloat(const char* begin, const char* end, >+ absl::chars_format format_flags); >+ >+extern template ParsedFloat ParseFloat<10>(const char* begin, const char* end, >+ absl::chars_format format_flags); >+extern template ParsedFloat ParseFloat<16>(const char* begin, const char* end, >+ absl::chars_format format_flags); >+ >+} // namespace strings_internal >+} // namespace absl >+#endif // ABSL_STRINGS_INTERNAL_CHARCONV_PARSE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse_test.cc >new file mode 100644 >index 00000000000..1ff86004973 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/charconv_parse_test.cc >@@ -0,0 +1,357 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/charconv_parse.h" >+ >+#include <string> >+#include <utility> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/str_cat.h" >+ >+using absl::chars_format; >+using absl::strings_internal::FloatType; >+using absl::strings_internal::ParsedFloat; >+using absl::strings_internal::ParseFloat; >+ >+namespace { >+ >+// Check that a given std::string input is parsed to the expected mantissa and >+// exponent. >+// >+// Input std::string `s` must contain a '$' character. It marks the end of the >+// characters that should be consumed by the match. It is stripped from the >+// input to ParseFloat. >+// >+// If input std::string `s` contains '[' and ']' characters, these mark the region >+// of characters that should be marked as the "subrange". For NaNs, this is >+// the location of the extended NaN std::string. For numbers, this is the location >+// of the full, over-large mantissa. >+template <int base> >+void ExpectParsedFloat(std::string s, absl::chars_format format_flags, >+ FloatType expected_type, uint64_t expected_mantissa, >+ int expected_exponent, >+ int expected_literal_exponent = -999) { >+ SCOPED_TRACE(s); >+ >+ int begin_subrange = -1; >+ int end_subrange = -1; >+ // If s contains '[' and ']', then strip these characters and set the subrange >+ // indices appropriately. >+ std::string::size_type open_bracket_pos = s.find('['); >+ if (open_bracket_pos != std::string::npos) { >+ begin_subrange = static_cast<int>(open_bracket_pos); >+ s.replace(open_bracket_pos, 1, ""); >+ std::string::size_type close_bracket_pos = s.find(']'); >+ ABSL_RAW_CHECK(close_bracket_pos != absl::string_view::npos, >+ "Test input contains [ without matching ]"); >+ end_subrange = static_cast<int>(close_bracket_pos); >+ s.replace(close_bracket_pos, 1, ""); >+ } >+ const std::string::size_type expected_characters_matched = s.find('$'); >+ ABSL_RAW_CHECK(expected_characters_matched != std::string::npos, >+ "Input std::string must contain $"); >+ s.replace(expected_characters_matched, 1, ""); >+ >+ ParsedFloat parsed = >+ ParseFloat<base>(s.data(), s.data() + s.size(), format_flags); >+ >+ EXPECT_NE(parsed.end, nullptr); >+ if (parsed.end == nullptr) { >+ return; // The following tests are not useful if we fully failed to parse >+ } >+ EXPECT_EQ(parsed.type, expected_type); >+ if (begin_subrange == -1) { >+ EXPECT_EQ(parsed.subrange_begin, nullptr); >+ EXPECT_EQ(parsed.subrange_end, nullptr); >+ } else { >+ EXPECT_EQ(parsed.subrange_begin, s.data() + begin_subrange); >+ EXPECT_EQ(parsed.subrange_end, s.data() + end_subrange); >+ } >+ if (parsed.type == FloatType::kNumber) { >+ EXPECT_EQ(parsed.mantissa, expected_mantissa); >+ EXPECT_EQ(parsed.exponent, expected_exponent); >+ if (expected_literal_exponent != -999) { >+ EXPECT_EQ(parsed.literal_exponent, expected_literal_exponent); >+ } >+ } >+ auto characters_matched = static_cast<int>(parsed.end - s.data()); >+ EXPECT_EQ(characters_matched, expected_characters_matched); >+} >+ >+// Check that a given std::string input is parsed to the expected mantissa and >+// exponent. >+// >+// Input std::string `s` must contain a '$' character. It marks the end of the >+// characters that were consumed by the match. >+template <int base> >+void ExpectNumber(std::string s, absl::chars_format format_flags, >+ uint64_t expected_mantissa, int expected_exponent, >+ int expected_literal_exponent = -999) { >+ ExpectParsedFloat<base>(std::move(s), format_flags, FloatType::kNumber, >+ expected_mantissa, expected_exponent, >+ expected_literal_exponent); >+} >+ >+// Check that a given std::string input is parsed to the given special value. >+// >+// This tests against both number bases, since infinities and NaNs have >+// identical representations in both modes. >+void ExpectSpecial(const std::string& s, absl::chars_format format_flags, >+ FloatType type) { >+ ExpectParsedFloat<10>(s, format_flags, type, 0, 0); >+ ExpectParsedFloat<16>(s, format_flags, type, 0, 0); >+} >+ >+// Check that a given input std::string is not matched by Float. >+template <int base> >+void ExpectFailedParse(absl::string_view s, absl::chars_format format_flags) { >+ ParsedFloat parsed = >+ ParseFloat<base>(s.data(), s.data() + s.size(), format_flags); >+ EXPECT_EQ(parsed.end, nullptr); >+} >+ >+TEST(ParseFloat, SimpleValue) { >+ // Test that various forms of floating point numbers all parse correctly. >+ ExpectNumber<10>("1.23456789e5$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e+5$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789E5$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e05$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123.456789e3$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("0.000123456789e9$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123456.789$", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123456789e-3$", chars_format::general, 123456789, -3); >+ >+ ExpectNumber<16>("1.234abcdefp28$", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1.234abcdefp+28$", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1.234ABCDEFp28$", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1.234AbCdEfP0028$", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("123.4abcdefp20$", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("0.0001234abcdefp44$", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("1234abcd.ef$", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1234abcdefp-8$", chars_format::general, 0x1234abcdef, -8); >+ >+ // ExpectNumber does not attempt to drop trailing zeroes. >+ ExpectNumber<10>("0001.2345678900e005$", chars_format::general, 12345678900, >+ -5); >+ ExpectNumber<16>("0001.234abcdef000p28$", chars_format::general, >+ 0x1234abcdef000, -20); >+ >+ // Ensure non-matching characters after a number are ignored, even when they >+ // look like potentially matching characters. >+ ExpectNumber<10>("1.23456789e5$ ", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e5$e5e5", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e5$.25", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e5$-", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("1.23456789e5$PUPPERS!!!", chars_format::general, 123456789, >+ -3); >+ ExpectNumber<10>("123456.789$efghij", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123456.789$e", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123456.789$p5", chars_format::general, 123456789, -3); >+ ExpectNumber<10>("123456.789$.10", chars_format::general, 123456789, -3); >+ >+ ExpectNumber<16>("1.234abcdefp28$ ", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("1.234abcdefp28$p28", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("1.234abcdefp28$.125", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("1.234abcdefp28$-", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1.234abcdefp28$KITTEHS!!!", chars_format::general, >+ 0x1234abcdef, -8); >+ ExpectNumber<16>("1234abcd.ef$ghijk", chars_format::general, 0x1234abcdef, >+ -8); >+ ExpectNumber<16>("1234abcd.ef$p", chars_format::general, 0x1234abcdef, -8); >+ ExpectNumber<16>("1234abcd.ef$.10", chars_format::general, 0x1234abcdef, -8); >+ >+ // Ensure we can read a full resolution mantissa without overflow. >+ ExpectNumber<10>("9999999999999999999$", chars_format::general, >+ 9999999999999999999u, 0); >+ ExpectNumber<16>("fffffffffffffff$", chars_format::general, >+ 0xfffffffffffffffu, 0); >+ >+ // Check that zero is consistently read. >+ ExpectNumber<10>("0$", chars_format::general, 0, 0); >+ ExpectNumber<16>("0$", chars_format::general, 0, 0); >+ ExpectNumber<10>("000000000000000000000000000000000000000$", >+ chars_format::general, 0, 0); >+ ExpectNumber<16>("000000000000000000000000000000000000000$", >+ chars_format::general, 0, 0); >+ ExpectNumber<10>("0000000000000000000000.000000000000000000$", >+ chars_format::general, 0, 0); >+ ExpectNumber<16>("0000000000000000000000.000000000000000000$", >+ chars_format::general, 0, 0); >+ ExpectNumber<10>("0.00000000000000000000000000000000e123456$", >+ chars_format::general, 0, 0); >+ ExpectNumber<16>("0.00000000000000000000000000000000p123456$", >+ chars_format::general, 0, 0); >+} >+ >+TEST(ParseFloat, LargeDecimalMantissa) { >+ // After 19 significant decimal digits in the mantissa, ParsedFloat will >+ // truncate additional digits. We need to test that: >+ // 1) the truncation to 19 digits happens >+ // 2) the returned exponent reflects the dropped significant digits >+ // 3) a correct literal_exponent is set >+ // >+ // If and only if a significant digit is found after 19 digits, then the >+ // entirety of the mantissa in case the exact value is needed to make a >+ // rounding decision. The [ and ] characters below denote where such a >+ // subregion was marked by by ParseFloat. They are not part of the input. >+ >+ // Mark a capture group only if a dropped digit is significant (nonzero). >+ ExpectNumber<10>("100000000000000000000000000$", chars_format::general, >+ 1000000000000000000, >+ /* adjusted exponent */ 8); >+ >+ ExpectNumber<10>("123456789123456789100000000$", chars_format::general, >+ 1234567891234567891, >+ /* adjusted exponent */ 8); >+ >+ ExpectNumber<10>("[123456789123456789123456789]$", chars_format::general, >+ 1234567891234567891, >+ /* adjusted exponent */ 8, >+ /* literal exponent */ 0); >+ >+ ExpectNumber<10>("[123456789123456789100000009]$", chars_format::general, >+ 1234567891234567891, >+ /* adjusted exponent */ 8, >+ /* literal exponent */ 0); >+ >+ ExpectNumber<10>("[123456789123456789120000000]$", chars_format::general, >+ 1234567891234567891, >+ /* adjusted exponent */ 8, >+ /* literal exponent */ 0); >+ >+ // Leading zeroes should not count towards the 19 significant digit limit >+ ExpectNumber<10>("[00000000123456789123456789123456789]$", >+ chars_format::general, 1234567891234567891, >+ /* adjusted exponent */ 8, >+ /* literal exponent */ 0); >+ >+ ExpectNumber<10>("00000000123456789123456789100000000$", >+ chars_format::general, 1234567891234567891, >+ /* adjusted exponent */ 8); >+ >+ // Truncated digits after the decimal point should not cause a further >+ // exponent adjustment. >+ ExpectNumber<10>("1.234567891234567891e123$", chars_format::general, >+ 1234567891234567891, 105); >+ ExpectNumber<10>("[1.23456789123456789123456789]e123$", chars_format::general, >+ 1234567891234567891, >+ /* adjusted exponent */ 105, >+ /* literal exponent */ 123); >+ >+ // Ensure we truncate, and not round. (The from_chars algorithm we use >+ // depends on our guess missing low, if it misses, so we need the rounding >+ // error to be downward.) >+ ExpectNumber<10>("[1999999999999999999999]$", chars_format::general, >+ 1999999999999999999, >+ /* adjusted exponent */ 3, >+ /* literal exponent */ 0); >+} >+ >+TEST(ParseFloat, LargeHexadecimalMantissa) { >+ // After 15 significant hex digits in the mantissa, ParsedFloat will treat >+ // additional digits as sticky, We need to test that: >+ // 1) The truncation to 15 digits happens >+ // 2) The returned exponent reflects the dropped significant digits >+ // 3) If a nonzero digit is dropped, the low bit of mantissa is set. >+ >+ ExpectNumber<16>("123456789abcdef123456789abcdef$", chars_format::general, >+ 0x123456789abcdef, 60); >+ >+ // Leading zeroes should not count towards the 15 significant digit limit >+ ExpectNumber<16>("000000123456789abcdef123456789abcdef$", >+ chars_format::general, 0x123456789abcdef, 60); >+ >+ // Truncated digits after the radix point should not cause a further >+ // exponent adjustment. >+ ExpectNumber<16>("1.23456789abcdefp100$", chars_format::general, >+ 0x123456789abcdef, 44); >+ ExpectNumber<16>("1.23456789abcdef123456789abcdefp100$", >+ chars_format::general, 0x123456789abcdef, 44); >+ >+ // test sticky digit behavior. The low bit should be set iff any dropped >+ // digit is nonzero. >+ ExpectNumber<16>("123456789abcdee123456789abcdee$", chars_format::general, >+ 0x123456789abcdef, 60); >+ ExpectNumber<16>("123456789abcdee000000000000001$", chars_format::general, >+ 0x123456789abcdef, 60); >+ ExpectNumber<16>("123456789abcdee000000000000000$", chars_format::general, >+ 0x123456789abcdee, 60); >+} >+ >+TEST(ParseFloat, ScientificVsFixed) { >+ // In fixed mode, an exponent is never matched (but the remainder of the >+ // number will be matched.) >+ ExpectNumber<10>("1.23456789$e5", chars_format::fixed, 123456789, -8); >+ ExpectNumber<10>("123456.789$", chars_format::fixed, 123456789, -3); >+ ExpectNumber<16>("1.234abcdef$p28", chars_format::fixed, 0x1234abcdef, -36); >+ ExpectNumber<16>("1234abcd.ef$", chars_format::fixed, 0x1234abcdef, -8); >+ >+ // In scientific mode, numbers don't match *unless* they have an exponent. >+ ExpectNumber<10>("1.23456789e5$", chars_format::scientific, 123456789, -3); >+ ExpectFailedParse<10>("-123456.789$", chars_format::scientific); >+ ExpectNumber<16>("1.234abcdefp28$", chars_format::scientific, 0x1234abcdef, >+ -8); >+ ExpectFailedParse<16>("1234abcd.ef$", chars_format::scientific); >+} >+ >+TEST(ParseFloat, Infinity) { >+ ExpectFailedParse<10>("in", chars_format::general); >+ ExpectFailedParse<16>("in", chars_format::general); >+ ExpectFailedParse<10>("inx", chars_format::general); >+ ExpectFailedParse<16>("inx", chars_format::general); >+ ExpectSpecial("inf$", chars_format::general, FloatType::kInfinity); >+ ExpectSpecial("Inf$", chars_format::general, FloatType::kInfinity); >+ ExpectSpecial("INF$", chars_format::general, FloatType::kInfinity); >+ ExpectSpecial("inf$inite", chars_format::general, FloatType::kInfinity); >+ ExpectSpecial("iNfInItY$", chars_format::general, FloatType::kInfinity); >+ ExpectSpecial("infinity$!!!", chars_format::general, FloatType::kInfinity); >+} >+ >+TEST(ParseFloat, NaN) { >+ ExpectFailedParse<10>("na", chars_format::general); >+ ExpectFailedParse<16>("na", chars_format::general); >+ ExpectFailedParse<10>("nah", chars_format::general); >+ ExpectFailedParse<16>("nah", chars_format::general); >+ ExpectSpecial("nan$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("NaN$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("nAn$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("NAN$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("NaN$aNaNaNaNaBatman!", chars_format::general, FloatType::kNan); >+ >+ // A parenthesized sequence of the characters [a-zA-Z0-9_] is allowed to >+ // appear after an NaN. Check that this is allowed, and that the correct >+ // characters are grouped. >+ // >+ // (The characters [ and ] in the pattern below delimit the expected matched >+ // subgroup; they are not part of the input passed to ParseFloat.) >+ ExpectSpecial("nan([0xabcdef])$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("nan([0xabcdef])$...", chars_format::general, FloatType::kNan); >+ ExpectSpecial("nan([0xabcdef])$)...", chars_format::general, FloatType::kNan); >+ ExpectSpecial("nan([])$", chars_format::general, FloatType::kNan); >+ ExpectSpecial("nan([aAzZ09_])$", chars_format::general, FloatType::kNan); >+ // If the subgroup contains illegal characters, don't match it at all. >+ ExpectSpecial("nan$(bad-char)", chars_format::general, FloatType::kNan); >+ // Also cope with a missing close paren. >+ ExpectSpecial("nan$(0xabcdef", chars_format::general, FloatType::kNan); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/escaping_test_common.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/escaping_test_common.h >new file mode 100644 >index 00000000000..cc41f4312c7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/escaping_test_common.h >@@ -0,0 +1,131 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This test contains common things needed by both escaping_test.cc and >+// escaping_benchmark.cc. >+ >+#ifndef ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ >+#define ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ >+ >+#include <array> >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+struct base64_testcase { >+ absl::string_view plaintext; >+ absl::string_view cyphertext; >+}; >+ >+inline const std::array<base64_testcase, 5>& base64_strings() { >+ static const std::array<base64_testcase, 5> testcase{{ >+ // Some google quotes >+ // Cyphertext created with "uuencode (GNU sharutils) 4.6.3" >+ // (Note that we're testing the websafe encoding, though, so if >+ // you add messages, be sure to run "tr -- '+/' '-_'" on the output) >+ { "I was always good at math and science, and I never realized " >+ "that was unusual or somehow undesirable. So one of the things " >+ "I care a lot about is helping to remove that stigma, " >+ "to show girls that you can be feminine, you can like the things " >+ "that girls like, but you can also be really good at technology. " >+ "You can be really good at building things." >+ " - Marissa Meyer, Newsweek, 2010-12-22" "\n", >+ >+ "SSB3YXMgYWx3YXlzIGdvb2QgYXQgbWF0aCBhbmQgc2NpZW5jZSwgYW5kIEkg" >+ "bmV2ZXIgcmVhbGl6ZWQgdGhhdCB3YXMgdW51c3VhbCBvciBzb21laG93IHVu" >+ "ZGVzaXJhYmxlLiBTbyBvbmUgb2YgdGhlIHRoaW5ncyBJIGNhcmUgYSBsb3Qg" >+ "YWJvdXQgaXMgaGVscGluZyB0byByZW1vdmUgdGhhdCBzdGlnbWEsIHRvIHNo" >+ "b3cgZ2lybHMgdGhhdCB5b3UgY2FuIGJlIGZlbWluaW5lLCB5b3UgY2FuIGxp" >+ "a2UgdGhlIHRoaW5ncyB0aGF0IGdpcmxzIGxpa2UsIGJ1dCB5b3UgY2FuIGFs" >+ "c28gYmUgcmVhbGx5IGdvb2QgYXQgdGVjaG5vbG9neS4gWW91IGNhbiBiZSBy" >+ "ZWFsbHkgZ29vZCBhdCBidWlsZGluZyB0aGluZ3MuIC0gTWFyaXNzYSBNZXll" >+ "ciwgTmV3c3dlZWssIDIwMTAtMTItMjIK" }, >+ >+ { "Typical first year for a new cluster: " >+ "~0.5 overheating " >+ "~1 PDU failure " >+ "~1 rack-move " >+ "~1 network rewiring " >+ "~20 rack failures " >+ "~5 racks go wonky " >+ "~8 network maintenances " >+ "~12 router reloads " >+ "~3 router failures " >+ "~dozens of minor 30-second blips for dns " >+ "~1000 individual machine failures " >+ "~thousands of hard drive failures " >+ "slow disks, bad memory, misconfigured machines, flaky machines, etc." >+ " - Jeff Dean, The Joys of Real Hardware" "\n", >+ >+ "VHlwaWNhbCBmaXJzdCB5ZWFyIGZvciBhIG5ldyBjbHVzdGVyOiB-MC41IG92" >+ "ZXJoZWF0aW5nIH4xIFBEVSBmYWlsdXJlIH4xIHJhY2stbW92ZSB-MSBuZXR3" >+ "b3JrIHJld2lyaW5nIH4yMCByYWNrIGZhaWx1cmVzIH41IHJhY2tzIGdvIHdv" >+ "bmt5IH44IG5ldHdvcmsgbWFpbnRlbmFuY2VzIH4xMiByb3V0ZXIgcmVsb2Fk" >+ "cyB-MyByb3V0ZXIgZmFpbHVyZXMgfmRvemVucyBvZiBtaW5vciAzMC1zZWNv" >+ "bmQgYmxpcHMgZm9yIGRucyB-MTAwMCBpbmRpdmlkdWFsIG1hY2hpbmUgZmFp" >+ "bHVyZXMgfnRob3VzYW5kcyBvZiBoYXJkIGRyaXZlIGZhaWx1cmVzIHNsb3cg" >+ "ZGlza3MsIGJhZCBtZW1vcnksIG1pc2NvbmZpZ3VyZWQgbWFjaGluZXMsIGZs" >+ "YWt5IG1hY2hpbmVzLCBldGMuIC0gSmVmZiBEZWFuLCBUaGUgSm95cyBvZiBS" >+ "ZWFsIEhhcmR3YXJlCg" }, >+ >+ { "I'm the head of the webspam team at Google. " >+ "That means that if you type your name into Google and get porn back, " >+ "it's my fault. Unless you're a porn star, in which case porn is a " >+ "completely reasonable response." >+ " - Matt Cutts, Google Plus" "\n", >+ >+ "SSdtIHRoZSBoZWFkIG9mIHRoZSB3ZWJzcGFtIHRlYW0gYXQgR29vZ2xlLiAg" >+ "VGhhdCBtZWFucyB0aGF0IGlmIHlvdSB0eXBlIHlvdXIgbmFtZSBpbnRvIEdv" >+ "b2dsZSBhbmQgZ2V0IHBvcm4gYmFjaywgaXQncyBteSBmYXVsdC4gVW5sZXNz" >+ "IHlvdSdyZSBhIHBvcm4gc3RhciwgaW4gd2hpY2ggY2FzZSBwb3JuIGlzIGEg" >+ "Y29tcGxldGVseSByZWFzb25hYmxlIHJlc3BvbnNlLiAtIE1hdHQgQ3V0dHMs" >+ "IEdvb2dsZSBQbHVzCg" }, >+ >+ { "It will still be a long time before machines approach human " >+ "intelligence. " >+ "But luckily, machines don't actually have to be intelligent; " >+ "they just have to fake it. Access to a wealth of information, " >+ "combined with a rudimentary decision-making capacity, " >+ "can often be almost as useful. Of course, the results are better yet " >+ "when coupled with intelligence. A reference librarian with access to " >+ "a good search engine is a formidable tool." >+ " - Craig Silverstein, Siemens Pictures of the Future, Spring 2004" >+ "\n", >+ >+ "SXQgd2lsbCBzdGlsbCBiZSBhIGxvbmcgdGltZSBiZWZvcmUgbWFjaGluZXMg" >+ "YXBwcm9hY2ggaHVtYW4gaW50ZWxsaWdlbmNlLiBCdXQgbHVja2lseSwgbWFj" >+ "aGluZXMgZG9uJ3QgYWN0dWFsbHkgaGF2ZSB0byBiZSBpbnRlbGxpZ2VudDsg" >+ "dGhleSBqdXN0IGhhdmUgdG8gZmFrZSBpdC4gQWNjZXNzIHRvIGEgd2VhbHRo" >+ "IG9mIGluZm9ybWF0aW9uLCBjb21iaW5lZCB3aXRoIGEgcnVkaW1lbnRhcnkg" >+ "ZGVjaXNpb24tbWFraW5nIGNhcGFjaXR5LCBjYW4gb2Z0ZW4gYmUgYWxtb3N0" >+ "IGFzIHVzZWZ1bC4gT2YgY291cnNlLCB0aGUgcmVzdWx0cyBhcmUgYmV0dGVy" >+ "IHlldCB3aGVuIGNvdXBsZWQgd2l0aCBpbnRlbGxpZ2VuY2UuIEEgcmVmZXJl" >+ "bmNlIGxpYnJhcmlhbiB3aXRoIGFjY2VzcyB0byBhIGdvb2Qgc2VhcmNoIGVu" >+ "Z2luZSBpcyBhIGZvcm1pZGFibGUgdG9vbC4gLSBDcmFpZyBTaWx2ZXJzdGVp" >+ "biwgU2llbWVucyBQaWN0dXJlcyBvZiB0aGUgRnV0dXJlLCBTcHJpbmcgMjAw" >+ "NAo" }, >+ >+ // Degenerate edge case >+ { "", >+ "" }, >+ }}; >+ >+ return testcase; >+} >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_ESCAPING_TEST_COMMON_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.cc >new file mode 100644 >index 00000000000..a0de70dffdb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.cc >@@ -0,0 +1,110 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/memutil.h" >+ >+#include <cstdlib> >+ >+namespace absl { >+namespace strings_internal { >+ >+int memcasecmp(const char* s1, const char* s2, size_t len) { >+ const unsigned char* us1 = reinterpret_cast<const unsigned char*>(s1); >+ const unsigned char* us2 = reinterpret_cast<const unsigned char*>(s2); >+ >+ for (size_t i = 0; i < len; i++) { >+ const int diff = >+ int{static_cast<unsigned char>(absl::ascii_tolower(us1[i]))} - >+ int{static_cast<unsigned char>(absl::ascii_tolower(us2[i]))}; >+ if (diff != 0) return diff; >+ } >+ return 0; >+} >+ >+char* memdup(const char* s, size_t slen) { >+ void* copy; >+ if ((copy = malloc(slen)) == nullptr) return nullptr; >+ memcpy(copy, s, slen); >+ return reinterpret_cast<char*>(copy); >+} >+ >+char* memrchr(const char* s, int c, size_t slen) { >+ for (const char* e = s + slen - 1; e >= s; e--) { >+ if (*e == c) return const_cast<char*>(e); >+ } >+ return nullptr; >+} >+ >+size_t memspn(const char* s, size_t slen, const char* accept) { >+ const char* p = s; >+ const char* spanp; >+ char c, sc; >+ >+cont: >+ c = *p++; >+ if (slen-- == 0) return p - 1 - s; >+ for (spanp = accept; (sc = *spanp++) != '\0';) >+ if (sc == c) goto cont; >+ return p - 1 - s; >+} >+ >+size_t memcspn(const char* s, size_t slen, const char* reject) { >+ const char* p = s; >+ const char* spanp; >+ char c, sc; >+ >+ while (slen-- != 0) { >+ c = *p++; >+ for (spanp = reject; (sc = *spanp++) != '\0';) >+ if (sc == c) return p - 1 - s; >+ } >+ return p - s; >+} >+ >+char* mempbrk(const char* s, size_t slen, const char* accept) { >+ const char* scanp; >+ int sc; >+ >+ for (; slen; ++s, --slen) { >+ for (scanp = accept; (sc = *scanp++) != '\0';) >+ if (sc == *s) return const_cast<char*>(s); >+ } >+ return nullptr; >+} >+ >+// This is significantly faster for case-sensitive matches with very >+// few possible matches. See unit test for benchmarks. >+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, >+ size_t neelen) { >+ if (0 == neelen) { >+ return phaystack; // even if haylen is 0 >+ } >+ if (haylen < neelen) return nullptr; >+ >+ const char* match; >+ const char* hayend = phaystack + haylen - neelen + 1; >+ // A static cast is used here to work around the fact that memchr returns >+ // a void* on Posix-compliant systems and const void* on Windows. >+ while ((match = static_cast<const char*>( >+ memchr(phaystack, pneedle[0], hayend - phaystack)))) { >+ if (memcmp(match, pneedle, neelen) == 0) >+ return match; >+ else >+ phaystack = match + 1; >+ } >+ return nullptr; >+} >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.h >new file mode 100644 >index 00000000000..a6f1c69138e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil.h >@@ -0,0 +1,146 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// These routines provide mem versions of standard C std::string routines, >+// such as strpbrk. They function exactly the same as the str versions, >+// so if you wonder what they are, replace the word "mem" by >+// "str" and check out the man page. I could return void*, as the >+// strutil.h mem*() routines tend to do, but I return char* instead >+// since this is by far the most common way these functions are called. >+// >+// The difference between the mem and str versions is the mem version >+// takes a pointer and a length, rather than a '\0'-terminated std::string. >+// The memcase* routines defined here assume the locale is "C" >+// (they use absl::ascii_tolower instead of tolower). >+// >+// These routines are based on the BSD library. >+// >+// Here's a list of routines from std::string.h, and their mem analogues. >+// Functions in lowercase are defined in std::string.h; those in UPPERCASE >+// are defined here: >+// >+// strlen -- >+// strcat strncat MEMCAT >+// strcpy strncpy memcpy >+// -- memccpy (very cool function, btw) >+// -- memmove >+// -- memset >+// strcmp strncmp memcmp >+// strcasecmp strncasecmp MEMCASECMP >+// strchr memchr >+// strcoll -- >+// strxfrm -- >+// strdup strndup MEMDUP >+// strrchr MEMRCHR >+// strspn MEMSPN >+// strcspn MEMCSPN >+// strpbrk MEMPBRK >+// strstr MEMSTR MEMMEM >+// (g)strcasestr MEMCASESTR MEMCASEMEM >+// strtok -- >+// strprefix MEMPREFIX (strprefix is from strutil.h) >+// strcaseprefix MEMCASEPREFIX (strcaseprefix is from strutil.h) >+// strsuffix MEMSUFFIX (strsuffix is from strutil.h) >+// strcasesuffix MEMCASESUFFIX (strcasesuffix is from strutil.h) >+// -- MEMIS >+// -- MEMCASEIS >+// strcount MEMCOUNT (strcount is from strutil.h) >+ >+#ifndef ABSL_STRINGS_INTERNAL_MEMUTIL_H_ >+#define ABSL_STRINGS_INTERNAL_MEMUTIL_H_ >+ >+#include <cstddef> >+#include <cstring> >+ >+#include "absl/base/port.h" // disable some warnings on Windows >+#include "absl/strings/ascii.h" // for absl::ascii_tolower >+ >+namespace absl { >+namespace strings_internal { >+ >+inline char* memcat(char* dest, size_t destlen, const char* src, >+ size_t srclen) { >+ return reinterpret_cast<char*>(memcpy(dest + destlen, src, srclen)); >+} >+ >+int memcasecmp(const char* s1, const char* s2, size_t len); >+char* memdup(const char* s, size_t slen); >+char* memrchr(const char* s, int c, size_t slen); >+size_t memspn(const char* s, size_t slen, const char* accept); >+size_t memcspn(const char* s, size_t slen, const char* reject); >+char* mempbrk(const char* s, size_t slen, const char* accept); >+ >+// This is for internal use only. Don't call this directly >+template <bool case_sensitive> >+const char* int_memmatch(const char* haystack, size_t haylen, >+ const char* needle, size_t neelen) { >+ if (0 == neelen) { >+ return haystack; // even if haylen is 0 >+ } >+ const char* hayend = haystack + haylen; >+ const char* needlestart = needle; >+ const char* needleend = needlestart + neelen; >+ >+ for (; haystack < hayend; ++haystack) { >+ char hay = case_sensitive >+ ? *haystack >+ : absl::ascii_tolower(static_cast<unsigned char>(*haystack)); >+ char nee = case_sensitive >+ ? *needle >+ : absl::ascii_tolower(static_cast<unsigned char>(*needle)); >+ if (hay == nee) { >+ if (++needle == needleend) { >+ return haystack + 1 - neelen; >+ } >+ } else if (needle != needlestart) { >+ // must back up haystack in case a prefix matched (find "aab" in "aaab") >+ haystack -= needle - needlestart; // for loop will advance one more >+ needle = needlestart; >+ } >+ } >+ return nullptr; >+} >+ >+// These are the guys you can call directly >+inline const char* memstr(const char* phaystack, size_t haylen, >+ const char* pneedle) { >+ return int_memmatch<true>(phaystack, haylen, pneedle, strlen(pneedle)); >+} >+ >+inline const char* memcasestr(const char* phaystack, size_t haylen, >+ const char* pneedle) { >+ return int_memmatch<false>(phaystack, haylen, pneedle, strlen(pneedle)); >+} >+ >+inline const char* memmem(const char* phaystack, size_t haylen, >+ const char* pneedle, size_t needlelen) { >+ return int_memmatch<true>(phaystack, haylen, pneedle, needlelen); >+} >+ >+inline const char* memcasemem(const char* phaystack, size_t haylen, >+ const char* pneedle, size_t needlelen) { >+ return int_memmatch<false>(phaystack, haylen, pneedle, needlelen); >+} >+ >+// This is significantly faster for case-sensitive matches with very >+// few possible matches. See unit test for benchmarks. >+const char* memmatch(const char* phaystack, size_t haylen, const char* pneedle, >+ size_t neelen); >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_MEMUTIL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_benchmark.cc >new file mode 100644 >index 00000000000..77915adb958 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_benchmark.cc >@@ -0,0 +1,323 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/memutil.h" >+ >+#include <algorithm> >+#include <cstdlib> >+ >+#include "benchmark/benchmark.h" >+#include "absl/strings/ascii.h" >+ >+// We fill the haystack with aaaaaaaaaaaaaaaaaa...aaaab. >+// That gives us: >+// - an easy search: 'b' >+// - a medium search: 'ab'. That means every letter is a possible match. >+// - a pathological search: 'aaaaaa.......aaaaab' (half as many a's as haytack) >+// We benchmark case-sensitive and case-insensitive versions of >+// three memmem implementations: >+// - memmem() from memutil.h >+// - search() from STL >+// - memmatch(), a custom implementation using memchr and memcmp. >+// Here are sample results: >+// >+// Run on (12 X 3800 MHz CPU s) >+// CPU Caches: >+// L1 Data 32K (x6) >+// L1 Instruction 32K (x6) >+// L2 Unified 256K (x6) >+// L3 Unified 15360K (x1) >+// ---------------------------------------------------------------- >+// Benchmark Time CPU Iterations >+// ---------------------------------------------------------------- >+// BM_Memmem 3583 ns 3582 ns 196469 2.59966GB/s >+// BM_MemmemMedium 13743 ns 13742 ns 50901 693.986MB/s >+// BM_MemmemPathological 13695030 ns 13693977 ns 51 713.133kB/s >+// BM_Memcasemem 3299 ns 3299 ns 212942 2.82309GB/s >+// BM_MemcasememMedium 16407 ns 16406 ns 42170 581.309MB/s >+// BM_MemcasememPathological 17267745 ns 17266030 ns 41 565.598kB/s >+// BM_Search 1610 ns 1609 ns 431321 5.78672GB/s >+// BM_SearchMedium 11111 ns 11110 ns 63001 858.414MB/s >+// BM_SearchPathological 12117390 ns 12116397 ns 58 805.984kB/s >+// BM_Searchcase 3081 ns 3081 ns 229949 3.02313GB/s >+// BM_SearchcaseMedium 16003 ns 16001 ns 44170 595.998MB/s >+// BM_SearchcasePathological 15823413 ns 15821909 ns 44 617.222kB/s >+// BM_Memmatch 197 ns 197 ns 3584225 47.2951GB/s >+// BM_MemmatchMedium 52333 ns 52329 ns 13280 182.244MB/s >+// BM_MemmatchPathological 659799 ns 659727 ns 1058 14.4556MB/s >+// BM_Memcasematch 5460 ns 5460 ns 127606 1.70586GB/s >+// BM_MemcasematchMedium 32861 ns 32857 ns 21258 290.248MB/s >+// BM_MemcasematchPathological 15154243 ns 15153089 ns 46 644.464kB/s >+// BM_MemmemStartup 5 ns 5 ns 150821500 >+// BM_SearchStartup 5 ns 5 ns 150644203 >+// BM_MemmatchStartup 7 ns 7 ns 97068802 >+// >+// Conclusions: >+// >+// The following recommendations are based on the sample results above. However, >+// we have found that the performance of STL search can vary significantly >+// depending on compiler and standard library implementation. We recommend you >+// run the benchmarks for yourself on relevant platforms. >+// >+// If you need case-insensitive, STL search is slightly better than memmem for >+// all cases. >+// >+// Case-sensitive is more subtle: >+// Custom memmatch is _very_ fast at scanning, so if you have very few possible >+// matches in your haystack, that's the way to go. Performance drops >+// significantly with more matches. >+// >+// STL search is slightly faster than memmem in the medium and pathological >+// benchmarks. However, the performance of memmem is currently more dependable >+// across platforms and build configurations. >+ >+namespace { >+ >+constexpr int kHaystackSize = 10000; >+constexpr int64_t kHaystackSize64 = kHaystackSize; >+const char* MakeHaystack() { >+ char* haystack = new char[kHaystackSize]; >+ for (int i = 0; i < kHaystackSize - 1; ++i) haystack[i] = 'a'; >+ haystack[kHaystackSize - 1] = 'b'; >+ return haystack; >+} >+const char* const kHaystack = MakeHaystack(); >+ >+void BM_Memmem(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memmem(kHaystack, kHaystackSize, "b", 1)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Memmem); >+ >+void BM_MemmemMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memmem(kHaystack, kHaystackSize, "ab", 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemmemMedium); >+ >+void BM_MemmemPathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::strings_internal::memmem( >+ kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, >+ kHaystackSize - kHaystackSize / 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemmemPathological); >+ >+void BM_Memcasemem(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "b", 1)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Memcasemem); >+ >+void BM_MemcasememMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "ab", 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemcasememMedium); >+ >+void BM_MemcasememPathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::strings_internal::memcasemem( >+ kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, >+ kHaystackSize - kHaystackSize / 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemcasememPathological); >+ >+bool case_eq(const char a, const char b) { >+ return absl::ascii_tolower(a) == absl::ascii_tolower(b); >+} >+ >+void BM_Search(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize - 1, >+ kHaystack + kHaystackSize)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Search); >+ >+void BM_SearchMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize - 2, >+ kHaystack + kHaystackSize)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_SearchMedium); >+ >+void BM_SearchPathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize / 2, >+ kHaystack + kHaystackSize)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_SearchPathological); >+ >+void BM_Searchcase(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize - 1, >+ kHaystack + kHaystackSize, case_eq)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Searchcase); >+ >+void BM_SearchcaseMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize - 2, >+ kHaystack + kHaystackSize, case_eq)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_SearchcaseMedium); >+ >+void BM_SearchcasePathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize / 2, >+ kHaystack + kHaystackSize, case_eq)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_SearchcasePathological); >+ >+char* memcasechr(const char* s, int c, size_t slen) { >+ c = absl::ascii_tolower(c); >+ for (; slen; ++s, --slen) { >+ if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s); >+ } >+ return nullptr; >+} >+ >+const char* memcasematch(const char* phaystack, size_t haylen, >+ const char* pneedle, size_t neelen) { >+ if (0 == neelen) { >+ return phaystack; // even if haylen is 0 >+ } >+ if (haylen < neelen) return nullptr; >+ >+ const char* match; >+ const char* hayend = phaystack + haylen - neelen + 1; >+ while ((match = static_cast<char*>( >+ memcasechr(phaystack, pneedle[0], hayend - phaystack)))) { >+ if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0) >+ return match; >+ else >+ phaystack = match + 1; >+ } >+ return nullptr; >+} >+ >+void BM_Memmatch(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memmatch(kHaystack, kHaystackSize, "b", 1)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Memmatch); >+ >+void BM_MemmatchMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::strings_internal::memmatch(kHaystack, kHaystackSize, "ab", 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemmatchMedium); >+ >+void BM_MemmatchPathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::strings_internal::memmatch( >+ kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2, >+ kHaystackSize - kHaystackSize / 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemmatchPathological); >+ >+void BM_Memcasematch(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "b", 1)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_Memcasematch); >+ >+void BM_MemcasematchMedium(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "ab", 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemcasematchMedium); >+ >+void BM_MemcasematchPathological(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, >+ kHaystack + kHaystackSize / 2, >+ kHaystackSize - kHaystackSize / 2)); >+ } >+ state.SetBytesProcessed(kHaystackSize64 * state.iterations()); >+} >+BENCHMARK(BM_MemcasematchPathological); >+ >+void BM_MemmemStartup(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::strings_internal::memmem( >+ kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1)); >+ } >+} >+BENCHMARK(BM_MemmemStartup); >+ >+void BM_SearchStartup(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ std::search(kHaystack + kHaystackSize - 10, kHaystack + kHaystackSize, >+ kHaystack + kHaystackSize - 1, kHaystack + kHaystackSize)); >+ } >+} >+BENCHMARK(BM_SearchStartup); >+ >+void BM_MemmatchStartup(benchmark::State& state) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(absl::strings_internal::memmatch( >+ kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1)); >+ } >+} >+BENCHMARK(BM_MemmatchStartup); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_test.cc >new file mode 100644 >index 00000000000..09424de9a47 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/memutil_test.cc >@@ -0,0 +1,179 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit test for memutil.cc >+ >+#include "absl/strings/internal/memutil.h" >+ >+#include <cstdlib> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/ascii.h" >+ >+namespace { >+ >+static char* memcasechr(const char* s, int c, size_t slen) { >+ c = absl::ascii_tolower(c); >+ for (; slen; ++s, --slen) { >+ if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s); >+ } >+ return nullptr; >+} >+ >+static const char* memcasematch(const char* phaystack, size_t haylen, >+ const char* pneedle, size_t neelen) { >+ if (0 == neelen) { >+ return phaystack; // even if haylen is 0 >+ } >+ if (haylen < neelen) return nullptr; >+ >+ const char* match; >+ const char* hayend = phaystack + haylen - neelen + 1; >+ while ((match = static_cast<char*>( >+ memcasechr(phaystack, pneedle[0], hayend - phaystack)))) { >+ if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0) >+ return match; >+ else >+ phaystack = match + 1; >+ } >+ return nullptr; >+} >+ >+TEST(MemUtilTest, AllTests) { >+ // check memutil functions >+ char a[1000]; >+ absl::strings_internal::memcat(a, 0, "hello", sizeof("hello") - 1); >+ absl::strings_internal::memcat(a, 5, " there", sizeof(" there") - 1); >+ >+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO there", >+ sizeof("hello there") - 1), >+ 0); >+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf", >+ sizeof("hello there") - 1), >+ -1); >+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "heLLO therf", >+ sizeof("hello there") - 2), >+ 0); >+ EXPECT_EQ(absl::strings_internal::memcasecmp(a, "whatever", 0), 0); >+ >+ char* p = absl::strings_internal::memdup("hello", 5); >+ free(p); >+ >+ p = absl::strings_internal::memrchr("hello there", 'e', >+ sizeof("hello there") - 1); >+ EXPECT_TRUE(p && p[-1] == 'r'); >+ p = absl::strings_internal::memrchr("hello there", 'e', >+ sizeof("hello there") - 2); >+ EXPECT_TRUE(p && p[-1] == 'h'); >+ p = absl::strings_internal::memrchr("hello there", 'u', >+ sizeof("hello there") - 1); >+ EXPECT_TRUE(p == nullptr); >+ >+ int len = absl::strings_internal::memspn("hello there", >+ sizeof("hello there") - 1, "hole"); >+ EXPECT_EQ(len, sizeof("hello") - 1); >+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, >+ "u"); >+ EXPECT_EQ(len, 0); >+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, >+ ""); >+ EXPECT_EQ(len, 0); >+ len = absl::strings_internal::memspn("hello there", sizeof("hello there") - 1, >+ "trole h"); >+ EXPECT_EQ(len, sizeof("hello there") - 1); >+ len = absl::strings_internal::memspn("hello there!", >+ sizeof("hello there!") - 1, "trole h"); >+ EXPECT_EQ(len, sizeof("hello there") - 1); >+ len = absl::strings_internal::memspn("hello there!", >+ sizeof("hello there!") - 2, "trole h!"); >+ EXPECT_EQ(len, sizeof("hello there!") - 2); >+ >+ len = absl::strings_internal::memcspn("hello there", >+ sizeof("hello there") - 1, "leho"); >+ EXPECT_EQ(len, 0); >+ len = absl::strings_internal::memcspn("hello there", >+ sizeof("hello there") - 1, "u"); >+ EXPECT_EQ(len, sizeof("hello there") - 1); >+ len = absl::strings_internal::memcspn("hello there", >+ sizeof("hello there") - 1, ""); >+ EXPECT_EQ(len, sizeof("hello there") - 1); >+ len = absl::strings_internal::memcspn("hello there", >+ sizeof("hello there") - 1, " "); >+ EXPECT_EQ(len, 5); >+ >+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, >+ "leho"); >+ EXPECT_TRUE(p && p[1] == 'e' && p[2] == 'l'); >+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, >+ "nu"); >+ EXPECT_TRUE(p == nullptr); >+ p = absl::strings_internal::mempbrk("hello there!", >+ sizeof("hello there!") - 2, "!"); >+ EXPECT_TRUE(p == nullptr); >+ p = absl::strings_internal::mempbrk("hello there", sizeof("hello there") - 1, >+ " t "); >+ EXPECT_TRUE(p && p[-1] == 'o' && p[1] == 't'); >+ >+ { >+ const char kHaystack[] = "0123456789"; >+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 0, "", 0), kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "012", 3), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "0xx", 1), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "789", 3), >+ kHaystack + 7); >+ EXPECT_EQ(absl::strings_internal::memmem(kHaystack, 10, "9xx", 1), >+ kHaystack + 9); >+ EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "9xx", 3) == >+ nullptr); >+ EXPECT_TRUE(absl::strings_internal::memmem(kHaystack, 10, "xxx", 1) == >+ nullptr); >+ } >+ { >+ const char kHaystack[] = "aBcDeFgHiJ"; >+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 0, "", 0), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Abc", 3), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "Axx", 1), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "hIj", 3), >+ kHaystack + 7); >+ EXPECT_EQ(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 1), >+ kHaystack + 9); >+ EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "jxx", 3) == >+ nullptr); >+ EXPECT_TRUE(absl::strings_internal::memcasemem(kHaystack, 10, "xxx", 1) == >+ nullptr); >+ } >+ { >+ const char kHaystack[] = "0123456789"; >+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 0, "", 0), kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "012", 3), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "0xx", 1), >+ kHaystack); >+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "789", 3), >+ kHaystack + 7); >+ EXPECT_EQ(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 1), >+ kHaystack + 9); >+ EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "9xx", 3) == >+ nullptr); >+ EXPECT_TRUE(absl::strings_internal::memmatch(kHaystack, 10, "xxx", 1) == >+ nullptr); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/numbers_test_common.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/numbers_test_common.h >new file mode 100644 >index 00000000000..20e3af51141 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/numbers_test_common.h >@@ -0,0 +1,178 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This file contains common things needed by numbers_test.cc, >+// numbers_legacy_test.cc and numbers_benchmark.cc. >+ >+#ifndef ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ >+#define ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ >+ >+#include <array> >+#include <cstdint> >+#include <limits> >+#include <string> >+ >+namespace absl { >+namespace strings_internal { >+ >+template <typename IntType> >+inline bool Itoa(IntType value, int base, std::string* destination) { >+ destination->clear(); >+ if (base <= 1 || base > 36) { >+ return false; >+ } >+ >+ if (value == 0) { >+ destination->push_back('0'); >+ return true; >+ } >+ >+ bool negative = value < 0; >+ while (value != 0) { >+ const IntType next_value = value / base; >+ // Can't use std::abs here because of problems when IntType is unsigned. >+ int remainder = value > next_value * base ? value - next_value * base >+ : next_value * base - value; >+ char c = remainder < 10 ? '0' + remainder : 'A' + remainder - 10; >+ destination->insert(0, 1, c); >+ value = next_value; >+ } >+ >+ if (negative) { >+ destination->insert(0, 1, '-'); >+ } >+ return true; >+} >+ >+struct uint32_test_case { >+ const char* str; >+ bool expect_ok; >+ int base; // base to pass to the conversion function >+ uint32_t expected; >+}; >+ >+inline const std::array<uint32_test_case, 27>& strtouint32_test_cases() { >+ static const std::array<uint32_test_case, 27> test_cases{{ >+ {"0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, >+ {"0x34234324", true, 16, 0x34234324}, >+ {"34234324", true, 16, 0x34234324}, >+ {"0", true, 16, 0}, >+ {" \t\n 0xffffffff", true, 16, std::numeric_limits<uint32_t>::max()}, >+ {" \f\v 46", true, 10, 46}, // must accept weird whitespace >+ {" \t\n 72717222", true, 8, 072717222}, >+ {" \t\n 072717222", true, 8, 072717222}, >+ {" \t\n 072717228", false, 8, 07271722}, >+ {"0", true, 0, 0}, >+ >+ // Base-10 version. >+ {"34234324", true, 0, 34234324}, >+ {"4294967295", true, 0, std::numeric_limits<uint32_t>::max()}, >+ {"34234324 \n\t", true, 10, 34234324}, >+ >+ // Unusual base >+ {"0", true, 3, 0}, >+ {"2", true, 3, 2}, >+ {"11", true, 3, 4}, >+ >+ // Invalid uints. >+ {"", false, 0, 0}, >+ {" ", false, 0, 0}, >+ {"abc", false, 0, 0}, // would be valid hex, but prefix is missing >+ {"34234324a", false, 0, 34234324}, >+ {"34234.3", false, 0, 34234}, >+ {"-1", false, 0, 0}, >+ {" -123", false, 0, 0}, >+ {" \t\n -123", false, 0, 0}, >+ >+ // Out of bounds. >+ {"4294967296", false, 0, std::numeric_limits<uint32_t>::max()}, >+ {"0x100000000", false, 0, std::numeric_limits<uint32_t>::max()}, >+ {nullptr, false, 0, 0}, >+ }}; >+ return test_cases; >+} >+ >+struct uint64_test_case { >+ const char* str; >+ bool expect_ok; >+ int base; >+ uint64_t expected; >+}; >+ >+inline const std::array<uint64_test_case, 34>& strtouint64_test_cases() { >+ static const std::array<uint64_test_case, 34> test_cases{{ >+ {"0x3423432448783446", true, 16, int64_t{0x3423432448783446}}, >+ {"3423432448783446", true, 16, int64_t{0x3423432448783446}}, >+ >+ {"0", true, 16, 0}, >+ {"000", true, 0, 0}, >+ {"0", true, 0, 0}, >+ {" \t\n 0xffffffffffffffff", true, 16, >+ std::numeric_limits<uint64_t>::max()}, >+ >+ {"012345670123456701234", true, 8, int64_t{012345670123456701234}}, >+ {"12345670123456701234", true, 8, int64_t{012345670123456701234}}, >+ >+ {"12845670123456701234", false, 8, 0}, >+ >+ // Base-10 version. >+ {"34234324487834466", true, 0, int64_t{34234324487834466}}, >+ >+ {" \t\n 18446744073709551615", true, 0, >+ std::numeric_limits<uint64_t>::max()}, >+ >+ {"34234324487834466 \n\t ", true, 0, int64_t{34234324487834466}}, >+ >+ {" \f\v 46", true, 10, 46}, // must accept weird whitespace >+ >+ // Unusual base >+ {"0", true, 3, 0}, >+ {"2", true, 3, 2}, >+ {"11", true, 3, 4}, >+ >+ {"0", true, 0, 0}, >+ >+ // Invalid uints. >+ {"", false, 0, 0}, >+ {" ", false, 0, 0}, >+ {"abc", false, 0, 0}, >+ {"34234324487834466a", false, 0, 0}, >+ {"34234487834466.3", false, 0, 0}, >+ {"-1", false, 0, 0}, >+ {" -123", false, 0, 0}, >+ {" \t\n -123", false, 0, 0}, >+ >+ // Out of bounds. >+ {"18446744073709551616", false, 10, 0}, >+ {"18446744073709551616", false, 0, 0}, >+ {"0x10000000000000000", false, 16, std::numeric_limits<uint64_t>::max()}, >+ {"0X10000000000000000", false, 16, >+ std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. >+ {"0x10000000000000000", false, 0, std::numeric_limits<uint64_t>::max()}, >+ {"0X10000000000000000", false, 0, >+ std::numeric_limits<uint64_t>::max()}, // 0X versus 0x. >+ >+ {"0x1234", true, 16, 0x1234}, >+ >+ // Base-10 std::string version. >+ {"1234", true, 0, 1234}, >+ {nullptr, false, 0, 0}, >+ }}; >+ return test_cases; >+} >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_NUMBERS_TEST_COMMON_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.cc >new file mode 100644 >index 00000000000..6ee2b109088 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.cc >@@ -0,0 +1,34 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/ostringstream.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+OStringStream::Buf::int_type OStringStream::overflow(int c) { >+ assert(s_); >+ if (!Buf::traits_type::eq_int_type(c, Buf::traits_type::eof())) >+ s_->push_back(static_cast<char>(c)); >+ return 1; >+} >+ >+std::streamsize OStringStream::xsputn(const char* s, std::streamsize n) { >+ assert(s_); >+ s_->append(s, n); >+ return n; >+} >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.h >new file mode 100644 >index 00000000000..6e1325b9140 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream.h >@@ -0,0 +1,87 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ >+#define ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ >+ >+#include <cassert> >+#include <ostream> >+#include <streambuf> >+#include <string> >+ >+#include "absl/base/port.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+// The same as std::ostringstream but appends to a user-specified std::string, >+// and is faster. It is ~70% faster to create, ~50% faster to write to, and >+// completely free to extract the result std::string. >+// >+// std::string s; >+// OStringStream strm(&s); >+// strm << 42 << ' ' << 3.14; // appends to `s` >+// >+// The stream object doesn't have to be named. Starting from C++11 operator<< >+// works with rvalues of std::ostream. >+// >+// std::string s; >+// OStringStream(&s) << 42 << ' ' << 3.14; // appends to `s` >+// >+// OStringStream is faster to create than std::ostringstream but it's still >+// relatively slow. Avoid creating multiple streams where a single stream will >+// do. >+// >+// Creates unnecessary instances of OStringStream: slow. >+// >+// std::string s; >+// OStringStream(&s) << 42; >+// OStringStream(&s) << ' '; >+// OStringStream(&s) << 3.14; >+// >+// Creates a single instance of OStringStream and reuses it: fast. >+// >+// std::string s; >+// OStringStream strm(&s); >+// strm << 42; >+// strm << ' '; >+// strm << 3.14; >+// >+// Note: flush() has no effect. No reason to call it. >+class OStringStream : private std::basic_streambuf<char>, public std::ostream { >+ public: >+ // The argument can be null, in which case you'll need to call str(p) with a >+ // non-null argument before you can write to the stream. >+ // >+ // The destructor of OStringStream doesn't use the std::string. It's OK to destroy >+ // the std::string before the stream. >+ explicit OStringStream(std::string* s) : std::ostream(this), s_(s) {} >+ >+ std::string* str() { return s_; } >+ const std::string* str() const { return s_; } >+ void str(std::string* s) { s_ = s; } >+ >+ private: >+ using Buf = std::basic_streambuf<char>; >+ >+ Buf::int_type overflow(int c) override; >+ std::streamsize xsputn(const char* s, std::streamsize n) override; >+ >+ std::string* s_; >+}; >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_OSTRINGSTREAM_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_benchmark.cc >new file mode 100644 >index 00000000000..c93f96909d8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_benchmark.cc >@@ -0,0 +1,106 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/ostringstream.h" >+ >+#include <sstream> >+#include <string> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+enum StringType { >+ kNone, >+ kStdString, >+}; >+ >+// Benchmarks for std::ostringstream. >+template <StringType kOutput> >+void BM_StdStream(benchmark::State& state) { >+ const int num_writes = state.range(0); >+ const int bytes_per_write = state.range(1); >+ const std::string payload(bytes_per_write, 'x'); >+ for (auto _ : state) { >+ std::ostringstream strm; >+ benchmark::DoNotOptimize(strm); >+ for (int i = 0; i != num_writes; ++i) { >+ strm << payload; >+ } >+ switch (kOutput) { >+ case kNone: { >+ break; >+ } >+ case kStdString: { >+ std::string s = strm.str(); >+ benchmark::DoNotOptimize(s); >+ break; >+ } >+ } >+ } >+} >+ >+// Create the stream, optionally write to it, then destroy it. >+BENCHMARK_TEMPLATE(BM_StdStream, kNone) >+ ->ArgPair(0, 0) >+ ->ArgPair(1, 16) // 16 bytes is small enough for SSO >+ ->ArgPair(1, 256) // 256 bytes requires heap allocation >+ ->ArgPair(1024, 256); >+// Create the stream, write to it, get std::string out, then destroy. >+BENCHMARK_TEMPLATE(BM_StdStream, kStdString) >+ ->ArgPair(1, 16) // 16 bytes is small enough for SSO >+ ->ArgPair(1, 256) // 256 bytes requires heap allocation >+ ->ArgPair(1024, 256); >+ >+// Benchmarks for OStringStream. >+template <StringType kOutput> >+void BM_CustomStream(benchmark::State& state) { >+ const int num_writes = state.range(0); >+ const int bytes_per_write = state.range(1); >+ const std::string payload(bytes_per_write, 'x'); >+ for (auto _ : state) { >+ std::string out; >+ absl::strings_internal::OStringStream strm(&out); >+ benchmark::DoNotOptimize(strm); >+ for (int i = 0; i != num_writes; ++i) { >+ strm << payload; >+ } >+ switch (kOutput) { >+ case kNone: { >+ break; >+ } >+ case kStdString: { >+ std::string s = out; >+ benchmark::DoNotOptimize(s); >+ break; >+ } >+ } >+ } >+} >+ >+// Create the stream, optionally write to it, then destroy it. >+BENCHMARK_TEMPLATE(BM_CustomStream, kNone) >+ ->ArgPair(0, 0) >+ ->ArgPair(1, 16) // 16 bytes is small enough for SSO >+ ->ArgPair(1, 256) // 256 bytes requires heap allocation >+ ->ArgPair(1024, 256); >+// Create the stream, write to it, get std::string out, then destroy. >+// It's not useful in practice to extract std::string from OStringStream; we >+// measure it for completeness. >+BENCHMARK_TEMPLATE(BM_CustomStream, kStdString) >+ ->ArgPair(1, 16) // 16 bytes is small enough for SSO >+ ->ArgPair(1, 256) // 256 bytes requires heap allocation >+ ->ArgPair(1024, 256); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_test.cc >new file mode 100644 >index 00000000000..069a0e1fbbb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/ostringstream_test.cc >@@ -0,0 +1,102 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/ostringstream.h" >+ >+#include <memory> >+#include <ostream> >+#include <string> >+#include <type_traits> >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+TEST(OStringStream, IsOStream) { >+ static_assert( >+ std::is_base_of<std::ostream, absl::strings_internal::OStringStream>(), >+ ""); >+} >+ >+TEST(OStringStream, ConstructDestroy) { >+ { >+ absl::strings_internal::OStringStream strm(nullptr); >+ EXPECT_EQ(nullptr, strm.str()); >+ } >+ { >+ std::string s = "abc"; >+ { >+ absl::strings_internal::OStringStream strm(&s); >+ EXPECT_EQ(&s, strm.str()); >+ } >+ EXPECT_EQ("abc", s); >+ } >+ { >+ std::unique_ptr<std::string> s(new std::string); >+ absl::strings_internal::OStringStream strm(s.get()); >+ s.reset(); >+ } >+} >+ >+TEST(OStringStream, Str) { >+ std::string s1; >+ absl::strings_internal::OStringStream strm(&s1); >+ const absl::strings_internal::OStringStream& c_strm(strm); >+ >+ static_assert(std::is_same<decltype(strm.str()), std::string*>(), ""); >+ static_assert(std::is_same<decltype(c_strm.str()), const std::string*>(), ""); >+ >+ EXPECT_EQ(&s1, strm.str()); >+ EXPECT_EQ(&s1, c_strm.str()); >+ >+ strm.str(&s1); >+ EXPECT_EQ(&s1, strm.str()); >+ EXPECT_EQ(&s1, c_strm.str()); >+ >+ std::string s2; >+ strm.str(&s2); >+ EXPECT_EQ(&s2, strm.str()); >+ EXPECT_EQ(&s2, c_strm.str()); >+ >+ strm.str(nullptr); >+ EXPECT_EQ(nullptr, strm.str()); >+ EXPECT_EQ(nullptr, c_strm.str()); >+} >+ >+TEST(OStreamStream, WriteToLValue) { >+ std::string s = "abc"; >+ { >+ absl::strings_internal::OStringStream strm(&s); >+ EXPECT_EQ("abc", s); >+ strm << ""; >+ EXPECT_EQ("abc", s); >+ strm << 42; >+ EXPECT_EQ("abc42", s); >+ strm << 'x' << 'y'; >+ EXPECT_EQ("abc42xy", s); >+ } >+ EXPECT_EQ("abc42xy", s); >+} >+ >+TEST(OStreamStream, WriteToRValue) { >+ std::string s = "abc"; >+ absl::strings_internal::OStringStream(&s) << ""; >+ EXPECT_EQ("abc", s); >+ absl::strings_internal::OStringStream(&s) << 42; >+ EXPECT_EQ("abc42", s); >+ absl::strings_internal::OStringStream(&s) << 'x' << 'y'; >+ EXPECT_EQ("abc42xy", s); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized.h >new file mode 100644 >index 00000000000..0157ca0245f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized.h >@@ -0,0 +1,69 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ >+#define ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ >+ >+#include <string> >+#include <utility> >+ >+#include "absl/base/port.h" >+#include "absl/meta/type_traits.h" // for void_t >+ >+namespace absl { >+namespace strings_internal { >+ >+// Is a subclass of true_type or false_type, depending on whether or not >+// T has a resize_uninitialized member. >+template <typename T, typename = void> >+struct HasResizeUninitialized : std::false_type {}; >+template <typename T> >+struct HasResizeUninitialized< >+ T, absl::void_t<decltype(std::declval<T>().resize_uninitialized(237))>> >+ : std::true_type {}; >+ >+template <typename string_type> >+void ResizeUninit(string_type* s, size_t new_size, std::true_type) { >+ s->resize_uninitialized(new_size); >+} >+template <typename string_type> >+void ResizeUninit(string_type* s, size_t new_size, std::false_type) { >+ s->resize(new_size); >+} >+ >+// Returns true if the std::string implementation supports a resize where >+// the new characters added to the std::string are left untouched. >+// >+// (A better name might be "STLStringSupportsUninitializedResize", alluding to >+// the previous function.) >+template <typename string_type> >+inline constexpr bool STLStringSupportsNontrashingResize(string_type*) { >+ return HasResizeUninitialized<string_type>(); >+} >+ >+// Like str->resize(new_size), except any new characters added to "*str" as a >+// result of resizing may be left uninitialized, rather than being filled with >+// '0' bytes. Typically used when code is then going to overwrite the backing >+// store of the std::string with known data. Uses a Google extension to std::string. >+template <typename string_type, typename = void> >+inline void STLStringResizeUninitialized(string_type* s, size_t new_size) { >+ ResizeUninit(s, new_size, HasResizeUninitialized<string_type>()); >+} >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_RESIZE_UNINITIALIZED_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized_test.cc >new file mode 100644 >index 00000000000..ad282efcd9b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/resize_uninitialized_test.cc >@@ -0,0 +1,68 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/resize_uninitialized.h" >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+int resize_call_count = 0; >+ >+struct resizable_string { >+ void resize(size_t) { resize_call_count += 1; } >+}; >+ >+int resize_uninitialized_call_count = 0; >+ >+struct resize_uninitializable_string { >+ void resize(size_t) { resize_call_count += 1; } >+ void resize_uninitialized(size_t) { resize_uninitialized_call_count += 1; } >+}; >+ >+TEST(ResizeUninit, WithAndWithout) { >+ resize_call_count = 0; >+ resize_uninitialized_call_count = 0; >+ { >+ resizable_string rs; >+ >+ EXPECT_EQ(resize_call_count, 0); >+ EXPECT_EQ(resize_uninitialized_call_count, 0); >+ EXPECT_FALSE( >+ absl::strings_internal::STLStringSupportsNontrashingResize(&rs)); >+ EXPECT_EQ(resize_call_count, 0); >+ EXPECT_EQ(resize_uninitialized_call_count, 0); >+ absl::strings_internal::STLStringResizeUninitialized(&rs, 237); >+ EXPECT_EQ(resize_call_count, 1); >+ EXPECT_EQ(resize_uninitialized_call_count, 0); >+ } >+ >+ resize_call_count = 0; >+ resize_uninitialized_call_count = 0; >+ { >+ resize_uninitializable_string rus; >+ >+ EXPECT_EQ(resize_call_count, 0); >+ EXPECT_EQ(resize_uninitialized_call_count, 0); >+ EXPECT_TRUE( >+ absl::strings_internal::STLStringSupportsNontrashingResize(&rus)); >+ EXPECT_EQ(resize_call_count, 0); >+ EXPECT_EQ(resize_uninitialized_call_count, 0); >+ absl::strings_internal::STLStringResizeUninitialized(&rus, 237); >+ EXPECT_EQ(resize_call_count, 0); >+ EXPECT_EQ(resize_uninitialized_call_count, 1); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h >new file mode 100644 >index 00000000000..04c4a5323b8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/stl_type_traits.h >@@ -0,0 +1,246 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// Thie file provides the IsStrictlyBaseOfAndConvertibleToSTLContainer type >+// trait metafunction to assist in working with the _GLIBCXX_DEBUG debug >+// wrappers of STL containers. >+// >+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including >+// absl/strings/str_split.h. >+// >+// IWYU pragma: private, include "absl/strings/str_split.h" >+ >+#ifndef ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ >+#define ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ >+ >+#include <array> >+#include <bitset> >+#include <deque> >+#include <forward_list> >+#include <list> >+#include <map> >+#include <set> >+#include <type_traits> >+#include <unordered_map> >+#include <unordered_set> >+#include <vector> >+ >+#include "absl/meta/type_traits.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+template <typename C, template <typename...> class T> >+struct IsSpecializationImpl : std::false_type {}; >+template <template <typename...> class T, typename... Args> >+struct IsSpecializationImpl<T<Args...>, T> : std::true_type {}; >+template <typename C, template <typename...> class T> >+using IsSpecialization = IsSpecializationImpl<absl::decay_t<C>, T>; >+ >+template <typename C> >+struct IsArrayImpl : std::false_type {}; >+template <template <typename, size_t> class A, typename T, size_t N> >+struct IsArrayImpl<A<T, N>> : std::is_same<A<T, N>, std::array<T, N>> {}; >+template <typename C> >+using IsArray = IsArrayImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsBitsetImpl : std::false_type {}; >+template <template <size_t> class B, size_t N> >+struct IsBitsetImpl<B<N>> : std::is_same<B<N>, std::bitset<N>> {}; >+template <typename C> >+using IsBitset = IsBitsetImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsSTLContainer >+ : absl::disjunction< >+ IsArray<C>, IsBitset<C>, IsSpecialization<C, std::deque>, >+ IsSpecialization<C, std::forward_list>, >+ IsSpecialization<C, std::list>, IsSpecialization<C, std::map>, >+ IsSpecialization<C, std::multimap>, IsSpecialization<C, std::set>, >+ IsSpecialization<C, std::multiset>, >+ IsSpecialization<C, std::unordered_map>, >+ IsSpecialization<C, std::unordered_multimap>, >+ IsSpecialization<C, std::unordered_set>, >+ IsSpecialization<C, std::unordered_multiset>, >+ IsSpecialization<C, std::vector>> {}; >+ >+template <typename C, template <typename...> class T, typename = void> >+struct IsBaseOfSpecializationImpl : std::false_type {}; >+// IsBaseOfSpecializationImpl needs multiple partial specializations to SFINAE >+// on the existence of container dependent types and plug them into the STL >+// template. >+template <typename C, template <typename, typename> class T> >+struct IsBaseOfSpecializationImpl< >+ C, T, absl::void_t<typename C::value_type, typename C::allocator_type>> >+ : std::is_base_of<C, >+ T<typename C::value_type, typename C::allocator_type>> {}; >+template <typename C, template <typename, typename, typename> class T> >+struct IsBaseOfSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::key_compare, >+ typename C::allocator_type>> >+ : std::is_base_of<C, T<typename C::key_type, typename C::key_compare, >+ typename C::allocator_type>> {}; >+template <typename C, template <typename, typename, typename, typename> class T> >+struct IsBaseOfSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::mapped_type, >+ typename C::key_compare, typename C::allocator_type>> >+ : std::is_base_of<C, >+ T<typename C::key_type, typename C::mapped_type, >+ typename C::key_compare, typename C::allocator_type>> { >+}; >+template <typename C, template <typename, typename, typename, typename> class T> >+struct IsBaseOfSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::hasher, >+ typename C::key_equal, typename C::allocator_type>> >+ : std::is_base_of<C, T<typename C::key_type, typename C::hasher, >+ typename C::key_equal, typename C::allocator_type>> { >+}; >+template <typename C, >+ template <typename, typename, typename, typename, typename> class T> >+struct IsBaseOfSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::mapped_type, >+ typename C::hasher, typename C::key_equal, >+ typename C::allocator_type>> >+ : std::is_base_of<C, T<typename C::key_type, typename C::mapped_type, >+ typename C::hasher, typename C::key_equal, >+ typename C::allocator_type>> {}; >+template <typename C, template <typename...> class T> >+using IsBaseOfSpecialization = IsBaseOfSpecializationImpl<absl::decay_t<C>, T>; >+ >+template <typename C> >+struct IsBaseOfArrayImpl : std::false_type {}; >+template <template <typename, size_t> class A, typename T, size_t N> >+struct IsBaseOfArrayImpl<A<T, N>> : std::is_base_of<A<T, N>, std::array<T, N>> { >+}; >+template <typename C> >+using IsBaseOfArray = IsBaseOfArrayImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsBaseOfBitsetImpl : std::false_type {}; >+template <template <size_t> class B, size_t N> >+struct IsBaseOfBitsetImpl<B<N>> : std::is_base_of<B<N>, std::bitset<N>> {}; >+template <typename C> >+using IsBaseOfBitset = IsBaseOfBitsetImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsBaseOfSTLContainer >+ : absl::disjunction<IsBaseOfArray<C>, IsBaseOfBitset<C>, >+ IsBaseOfSpecialization<C, std::deque>, >+ IsBaseOfSpecialization<C, std::forward_list>, >+ IsBaseOfSpecialization<C, std::list>, >+ IsBaseOfSpecialization<C, std::map>, >+ IsBaseOfSpecialization<C, std::multimap>, >+ IsBaseOfSpecialization<C, std::set>, >+ IsBaseOfSpecialization<C, std::multiset>, >+ IsBaseOfSpecialization<C, std::unordered_map>, >+ IsBaseOfSpecialization<C, std::unordered_multimap>, >+ IsBaseOfSpecialization<C, std::unordered_set>, >+ IsBaseOfSpecialization<C, std::unordered_multiset>, >+ IsBaseOfSpecialization<C, std::vector>> {}; >+ >+template <typename C, template <typename...> class T, typename = void> >+struct IsConvertibleToSpecializationImpl : std::false_type {}; >+// IsConvertibleToSpecializationImpl needs multiple partial specializations to >+// SFINAE on the existence of container dependent types and plug them into the >+// STL template. >+template <typename C, template <typename, typename> class T> >+struct IsConvertibleToSpecializationImpl< >+ C, T, absl::void_t<typename C::value_type, typename C::allocator_type>> >+ : std::is_convertible< >+ C, T<typename C::value_type, typename C::allocator_type>> {}; >+template <typename C, template <typename, typename, typename> class T> >+struct IsConvertibleToSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::key_compare, >+ typename C::allocator_type>> >+ : std::is_convertible<C, T<typename C::key_type, typename C::key_compare, >+ typename C::allocator_type>> {}; >+template <typename C, template <typename, typename, typename, typename> class T> >+struct IsConvertibleToSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::mapped_type, >+ typename C::key_compare, typename C::allocator_type>> >+ : std::is_convertible< >+ C, T<typename C::key_type, typename C::mapped_type, >+ typename C::key_compare, typename C::allocator_type>> {}; >+template <typename C, template <typename, typename, typename, typename> class T> >+struct IsConvertibleToSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::hasher, >+ typename C::key_equal, typename C::allocator_type>> >+ : std::is_convertible< >+ C, T<typename C::key_type, typename C::hasher, typename C::key_equal, >+ typename C::allocator_type>> {}; >+template <typename C, >+ template <typename, typename, typename, typename, typename> class T> >+struct IsConvertibleToSpecializationImpl< >+ C, T, >+ absl::void_t<typename C::key_type, typename C::mapped_type, >+ typename C::hasher, typename C::key_equal, >+ typename C::allocator_type>> >+ : std::is_convertible<C, T<typename C::key_type, typename C::mapped_type, >+ typename C::hasher, typename C::key_equal, >+ typename C::allocator_type>> {}; >+template <typename C, template <typename...> class T> >+using IsConvertibleToSpecialization = >+ IsConvertibleToSpecializationImpl<absl::decay_t<C>, T>; >+ >+template <typename C> >+struct IsConvertibleToArrayImpl : std::false_type {}; >+template <template <typename, size_t> class A, typename T, size_t N> >+struct IsConvertibleToArrayImpl<A<T, N>> >+ : std::is_convertible<A<T, N>, std::array<T, N>> {}; >+template <typename C> >+using IsConvertibleToArray = IsConvertibleToArrayImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsConvertibleToBitsetImpl : std::false_type {}; >+template <template <size_t> class B, size_t N> >+struct IsConvertibleToBitsetImpl<B<N>> >+ : std::is_convertible<B<N>, std::bitset<N>> {}; >+template <typename C> >+using IsConvertibleToBitset = IsConvertibleToBitsetImpl<absl::decay_t<C>>; >+ >+template <typename C> >+struct IsConvertibleToSTLContainer >+ : absl::disjunction< >+ IsConvertibleToArray<C>, IsConvertibleToBitset<C>, >+ IsConvertibleToSpecialization<C, std::deque>, >+ IsConvertibleToSpecialization<C, std::forward_list>, >+ IsConvertibleToSpecialization<C, std::list>, >+ IsConvertibleToSpecialization<C, std::map>, >+ IsConvertibleToSpecialization<C, std::multimap>, >+ IsConvertibleToSpecialization<C, std::set>, >+ IsConvertibleToSpecialization<C, std::multiset>, >+ IsConvertibleToSpecialization<C, std::unordered_map>, >+ IsConvertibleToSpecialization<C, std::unordered_multimap>, >+ IsConvertibleToSpecialization<C, std::unordered_set>, >+ IsConvertibleToSpecialization<C, std::unordered_multiset>, >+ IsConvertibleToSpecialization<C, std::vector>> {}; >+ >+template <typename C> >+struct IsStrictlyBaseOfAndConvertibleToSTLContainer >+ : absl::conjunction<absl::negation<IsSTLContainer<C>>, >+ IsBaseOfSTLContainer<C>, >+ IsConvertibleToSTLContainer<C>> {}; >+ >+} // namespace strings_internal >+} // namespace absl >+#endif // ABSL_STRINGS_INTERNAL_STL_TYPE_TRAITS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc >new file mode 100644 >index 00000000000..eafb068fe28 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc >@@ -0,0 +1,399 @@ >+// >+// POSIX spec: >+// http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html >+// >+#include "absl/strings/internal/str_format/arg.h" >+ >+#include <cassert> >+#include <cerrno> >+#include <cstdlib> >+#include <string> >+#include <type_traits> >+ >+#include "absl/base/port.h" >+#include "absl/strings/internal/str_format/float_conversion.h" >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" }; >+ >+// Reduce *capacity by s.size(), clipped to a 0 minimum. >+void ReducePadding(string_view s, size_t *capacity) { >+ *capacity = Excess(s.size(), *capacity); >+} >+ >+// Reduce *capacity by n, clipped to a 0 minimum. >+void ReducePadding(size_t n, size_t *capacity) { >+ *capacity = Excess(n, *capacity); >+} >+ >+template <typename T> >+struct MakeUnsigned : std::make_unsigned<T> {}; >+template <> >+struct MakeUnsigned<absl::uint128> { >+ using type = absl::uint128; >+}; >+ >+template <typename T> >+struct IsSigned : std::is_signed<T> {}; >+template <> >+struct IsSigned<absl::uint128> : std::false_type {}; >+ >+class ConvertedIntInfo { >+ public: >+ template <typename T> >+ ConvertedIntInfo(T v, ConversionChar conv) { >+ using Unsigned = typename MakeUnsigned<T>::type; >+ auto u = static_cast<Unsigned>(v); >+ if (IsNeg(v)) { >+ is_neg_ = true; >+ u = Unsigned{} - u; >+ } else { >+ is_neg_ = false; >+ } >+ UnsignedToStringRight(u, conv); >+ } >+ >+ string_view digits() const { >+ return {end() - size_, static_cast<size_t>(size_)}; >+ } >+ bool is_neg() const { return is_neg_; } >+ >+ private: >+ template <typename T, bool IsSigned> >+ struct IsNegImpl { >+ static bool Eval(T v) { return v < 0; } >+ }; >+ template <typename T> >+ struct IsNegImpl<T, false> { >+ static bool Eval(T) { >+ return false; >+ } >+ }; >+ >+ template <typename T> >+ bool IsNeg(T v) { >+ return IsNegImpl<T, IsSigned<T>::value>::Eval(v); >+ } >+ >+ template <typename T> >+ void UnsignedToStringRight(T u, ConversionChar conv) { >+ char *p = end(); >+ switch (conv.radix()) { >+ default: >+ case 10: >+ for (; u; u /= 10) >+ *--p = static_cast<char>('0' + static_cast<size_t>(u % 10)); >+ break; >+ case 8: >+ for (; u; u /= 8) >+ *--p = static_cast<char>('0' + static_cast<size_t>(u % 8)); >+ break; >+ case 16: { >+ const char *digits = kDigit[conv.upper() ? 1 : 0]; >+ for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)]; >+ break; >+ } >+ } >+ size_ = static_cast<int>(end() - p); >+ } >+ >+ const char *end() const { return storage_ + sizeof(storage_); } >+ char *end() { return storage_ + sizeof(storage_); } >+ >+ bool is_neg_; >+ int size_; >+ // Max size: 128 bit value as octal -> 43 digits >+ char storage_[128 / 3 + 1]; >+}; >+ >+// Note: 'o' conversions do not have a base indicator, it's just that >+// the '#' flag is specified to modify the precision for 'o' conversions. >+string_view BaseIndicator(const ConvertedIntInfo &info, >+ const ConversionSpec &conv) { >+ bool alt = conv.flags().alt; >+ int radix = conv.conv().radix(); >+ if (conv.conv().id() == ConversionChar::p) >+ alt = true; // always show 0x for %p. >+ // From the POSIX description of '#' flag: >+ // "For x or X conversion specifiers, a non-zero result shall have >+ // 0x (or 0X) prefixed to it." >+ if (alt && radix == 16 && !info.digits().empty()) { >+ if (conv.conv().upper()) return "0X"; >+ return "0x"; >+ } >+ return {}; >+} >+ >+string_view SignColumn(bool neg, const ConversionSpec &conv) { >+ if (conv.conv().is_signed()) { >+ if (neg) return "-"; >+ if (conv.flags().show_pos) return "+"; >+ if (conv.flags().sign_col) return " "; >+ } >+ return {}; >+} >+ >+bool ConvertCharImpl(unsigned char v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ size_t fill = 0; >+ if (conv.width() >= 0) fill = conv.width(); >+ ReducePadding(1, &fill); >+ if (!conv.flags().left) sink->Append(fill, ' '); >+ sink->Append(1, v); >+ if (conv.flags().left) sink->Append(fill, ' '); >+ return true; >+} >+ >+bool ConvertIntImplInner(const ConvertedIntInfo &info, >+ const ConversionSpec &conv, FormatSinkImpl *sink) { >+ // Print as a sequence of Substrings: >+ // [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces] >+ size_t fill = 0; >+ if (conv.width() >= 0) fill = conv.width(); >+ >+ string_view formatted = info.digits(); >+ ReducePadding(formatted, &fill); >+ >+ string_view sign = SignColumn(info.is_neg(), conv); >+ ReducePadding(sign, &fill); >+ >+ string_view base_indicator = BaseIndicator(info, conv); >+ ReducePadding(base_indicator, &fill); >+ >+ int precision = conv.precision(); >+ bool precision_specified = precision >= 0; >+ if (!precision_specified) >+ precision = 1; >+ >+ if (conv.flags().alt && conv.conv().id() == ConversionChar::o) { >+ // From POSIX description of the '#' (alt) flag: >+ // "For o conversion, it increases the precision (if necessary) to >+ // force the first digit of the result to be zero." >+ if (formatted.empty() || *formatted.begin() != '0') { >+ int needed = static_cast<int>(formatted.size()) + 1; >+ precision = std::max(precision, needed); >+ } >+ } >+ >+ size_t num_zeroes = Excess(formatted.size(), precision); >+ ReducePadding(num_zeroes, &fill); >+ >+ size_t num_left_spaces = !conv.flags().left ? fill : 0; >+ size_t num_right_spaces = conv.flags().left ? fill : 0; >+ >+ // From POSIX description of the '0' (zero) flag: >+ // "For d, i, o, u, x, and X conversion specifiers, if a precision >+ // is specified, the '0' flag is ignored." >+ if (!precision_specified && conv.flags().zero) { >+ num_zeroes += num_left_spaces; >+ num_left_spaces = 0; >+ } >+ >+ sink->Append(num_left_spaces, ' '); >+ sink->Append(sign); >+ sink->Append(base_indicator); >+ sink->Append(num_zeroes, '0'); >+ sink->Append(formatted); >+ sink->Append(num_right_spaces, ' '); >+ return true; >+} >+ >+template <typename T> >+bool ConvertIntImplInner(T v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ ConvertedIntInfo info(v, conv.conv()); >+ if (conv.flags().basic && conv.conv().id() != ConversionChar::p) { >+ if (info.is_neg()) sink->Append(1, '-'); >+ if (info.digits().empty()) { >+ sink->Append(1, '0'); >+ } else { >+ sink->Append(info.digits()); >+ } >+ return true; >+ } >+ return ConvertIntImplInner(info, conv, sink); >+} >+ >+template <typename T> >+bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) { >+ if (conv.conv().is_float()) { >+ return FormatConvertImpl(static_cast<double>(v), conv, sink).value; >+ } >+ if (conv.conv().id() == ConversionChar::c) >+ return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink); >+ if (!conv.conv().is_integral()) >+ return false; >+ if (!conv.conv().is_signed() && IsSigned<T>::value) { >+ using U = typename MakeUnsigned<T>::type; >+ return FormatConvertImpl(static_cast<U>(v), conv, sink).value; >+ } >+ return ConvertIntImplInner(v, conv, sink); >+} >+ >+template <typename T> >+bool ConvertFloatArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) { >+ return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink); >+} >+ >+inline bool ConvertStringArg(string_view v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ if (conv.conv().id() != ConversionChar::s) >+ return false; >+ if (conv.flags().basic) { >+ sink->Append(v); >+ return true; >+ } >+ return sink->PutPaddedString(v, conv.width(), conv.precision(), >+ conv.flags().left); >+} >+ >+} // namespace >+ >+// ==================== Strings ==================== >+ConvertResult<Conv::s> FormatConvertImpl(const std::string &v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertStringArg(v, conv, sink)}; >+} >+ >+ConvertResult<Conv::s> FormatConvertImpl(string_view v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertStringArg(v, conv, sink)}; >+} >+ >+ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ if (conv.conv().id() == ConversionChar::p) >+ return {FormatConvertImpl(VoidPtr(v), conv, sink).value}; >+ size_t len; >+ if (v == nullptr) { >+ len = 0; >+ } else if (conv.precision() < 0) { >+ len = std::strlen(v); >+ } else { >+ // If precision is set, we look for the null terminator on the valid range. >+ len = std::find(v, v + conv.precision(), '\0') - v; >+ } >+ return {ConvertStringArg(string_view(v, len), conv, sink)}; >+} >+ >+// ==================== Raw pointers ==================== >+ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ if (conv.conv().id() != ConversionChar::p) >+ return {false}; >+ if (!v.value) { >+ sink->Append("(nil)"); >+ return {true}; >+ } >+ return {ConvertIntImplInner(v.value, conv, sink)}; >+} >+ >+// ==================== Floats ==================== >+FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertFloatArg(v, conv, sink)}; >+} >+FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertFloatArg(v, conv, sink)}; >+} >+FloatingConvertResult FormatConvertImpl(long double v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertFloatArg(v, conv, sink)}; >+} >+ >+// ==================== Chars ==================== >+IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(signed char v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(unsigned char v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+ >+// ==================== Ints ==================== >+IntegralConvertResult FormatConvertImpl(short v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(long v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(long long v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+IntegralConvertResult FormatConvertImpl(absl::uint128 v, >+ const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return {ConvertIntArg(v, conv, sink)}; >+} >+ >+template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>; >+ >+template struct FormatArgImpl::TypedVTable<bool>; >+template struct FormatArgImpl::TypedVTable<char>; >+template struct FormatArgImpl::TypedVTable<signed char>; >+template struct FormatArgImpl::TypedVTable<unsigned char>; >+template struct FormatArgImpl::TypedVTable<short>; // NOLINT >+template struct FormatArgImpl::TypedVTable<unsigned short>; // NOLINT >+template struct FormatArgImpl::TypedVTable<int>; >+template struct FormatArgImpl::TypedVTable<unsigned>; >+template struct FormatArgImpl::TypedVTable<long>; // NOLINT >+template struct FormatArgImpl::TypedVTable<unsigned long>; // NOLINT >+template struct FormatArgImpl::TypedVTable<long long>; // NOLINT >+template struct FormatArgImpl::TypedVTable<unsigned long long>; // NOLINT >+template struct FormatArgImpl::TypedVTable<absl::uint128>; >+ >+template struct FormatArgImpl::TypedVTable<float>; >+template struct FormatArgImpl::TypedVTable<double>; >+template struct FormatArgImpl::TypedVTable<long double>; >+ >+template struct FormatArgImpl::TypedVTable<const char *>; >+template struct FormatArgImpl::TypedVTable<std::string>; >+template struct FormatArgImpl::TypedVTable<string_view>; >+ >+} // namespace str_format_internal >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h >new file mode 100644 >index 00000000000..a9562188ea9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h >@@ -0,0 +1,434 @@ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ >+ >+#include <string.h> >+#include <wchar.h> >+ >+#include <cstdio> >+#include <iomanip> >+#include <limits> >+#include <sstream> >+#include <string> >+#include <type_traits> >+ >+#include "absl/base/port.h" >+#include "absl/meta/type_traits.h" >+#include "absl/numeric/int128.h" >+#include "absl/strings/internal/str_format/extension.h" >+#include "absl/strings/string_view.h" >+ >+class Cord; >+class CordReader; >+ >+namespace absl { >+ >+class FormatCountCapture; >+class FormatSink; >+ >+namespace str_format_internal { >+ >+template <typename T, typename = void> >+struct HasUserDefinedConvert : std::false_type {}; >+ >+template <typename T> >+struct HasUserDefinedConvert< >+ T, void_t<decltype(AbslFormatConvert( >+ std::declval<const T&>(), std::declval<const ConversionSpec&>(), >+ std::declval<FormatSink*>()))>> : std::true_type {}; >+template <typename T> >+class StreamedWrapper; >+ >+// If 'v' can be converted (in the printf sense) according to 'conv', >+// then convert it, appending to `sink` and return `true`. >+// Otherwise fail and return `false`. >+// Raw pointers. >+struct VoidPtr { >+ VoidPtr() = default; >+ template <typename T, >+ decltype(reinterpret_cast<uintptr_t>(std::declval<T*>())) = 0> >+ VoidPtr(T* ptr) // NOLINT >+ : value(ptr ? reinterpret_cast<uintptr_t>(ptr) : 0) {} >+ uintptr_t value; >+}; >+ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+ >+// Strings. >+ConvertResult<Conv::s> FormatConvertImpl(const std::string& v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+ConvertResult<Conv::s> FormatConvertImpl(string_view v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char* v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+template <class AbslCord, >+ typename std::enable_if< >+ std::is_same<AbslCord, ::Cord>::value>::type* = nullptr, >+ class AbslCordReader = ::CordReader> >+ConvertResult<Conv::s> FormatConvertImpl(const AbslCord& value, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink) { >+ if (conv.conv().id() != ConversionChar::s) return {false}; >+ >+ bool is_left = conv.flags().left; >+ size_t space_remaining = 0; >+ >+ int width = conv.width(); >+ if (width >= 0) space_remaining = width; >+ >+ size_t to_write = value.size(); >+ >+ int precision = conv.precision(); >+ if (precision >= 0) >+ to_write = std::min(to_write, static_cast<size_t>(precision)); >+ >+ space_remaining = Excess(to_write, space_remaining); >+ >+ if (space_remaining > 0 && !is_left) sink->Append(space_remaining, ' '); >+ >+ string_view piece; >+ for (AbslCordReader reader(value); >+ to_write > 0 && reader.ReadFragment(&piece); to_write -= piece.size()) { >+ if (piece.size() > to_write) piece.remove_suffix(piece.size() - to_write); >+ sink->Append(piece); >+ } >+ >+ if (space_remaining > 0 && is_left) sink->Append(space_remaining, ' '); >+ return {true}; >+} >+ >+using IntegralConvertResult = >+ ConvertResult<Conv::c | Conv::numeric | Conv::star>; >+using FloatingConvertResult = ConvertResult<Conv::floating>; >+ >+// Floats. >+FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+FloatingConvertResult FormatConvertImpl(long double v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+ >+// Chars. >+IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(signed char v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(unsigned char v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+ >+// Ints. >+IntegralConvertResult FormatConvertImpl(short v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(unsigned short v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(long v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(unsigned long v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(long long v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(unsigned long long v, // NOLINT >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+IntegralConvertResult FormatConvertImpl(uint128 v, const ConversionSpec& conv, >+ FormatSinkImpl* sink); >+template <typename T, enable_if_t<std::is_same<T, bool>::value, int> = 0> >+IntegralConvertResult FormatConvertImpl(T v, const ConversionSpec& conv, >+ FormatSinkImpl* sink) { >+ return FormatConvertImpl(static_cast<int>(v), conv, sink); >+} >+ >+// We provide this function to help the checker, but it is never defined. >+// FormatArgImpl will use the underlying Convert functions instead. >+template <typename T> >+typename std::enable_if<std::is_enum<T>::value && >+ !HasUserDefinedConvert<T>::value, >+ IntegralConvertResult>::type >+FormatConvertImpl(T v, const ConversionSpec& conv, FormatSinkImpl* sink); >+ >+template <typename T> >+ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<T>& v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* out) { >+ std::ostringstream oss; >+ oss << v.v_; >+ if (!oss) return {false}; >+ return str_format_internal::FormatConvertImpl(oss.str(), conv, out); >+} >+ >+// Use templates and dependent types to delay evaluation of the function >+// until after FormatCountCapture is fully defined. >+struct FormatCountCaptureHelper { >+ template <class T = int> >+ static ConvertResult<Conv::n> ConvertHelper(const FormatCountCapture& v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink) { >+ const absl::enable_if_t<sizeof(T) != 0, FormatCountCapture>& v2 = v; >+ >+ if (conv.conv().id() != str_format_internal::ConversionChar::n) >+ return {false}; >+ *v2.p_ = static_cast<int>(sink->size()); >+ return {true}; >+ } >+}; >+ >+template <class T = int> >+ConvertResult<Conv::n> FormatConvertImpl(const FormatCountCapture& v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* sink) { >+ return FormatCountCaptureHelper::ConvertHelper(v, conv, sink); >+} >+ >+// Helper friend struct to hide implementation details from the public API of >+// FormatArgImpl. >+struct FormatArgImplFriend { >+ template <typename Arg> >+ static bool ToInt(Arg arg, int* out) { >+ if (!arg.vtbl_->to_int) return false; >+ *out = arg.vtbl_->to_int(arg.data_); >+ return true; >+ } >+ >+ template <typename Arg> >+ static bool Convert(Arg arg, const str_format_internal::ConversionSpec& conv, >+ FormatSinkImpl* out) { >+ return arg.vtbl_->convert(arg.data_, conv, out); >+ } >+ >+ template <typename Arg> >+ static const void* GetVTablePtrForTest(Arg arg) { >+ return arg.vtbl_; >+ } >+}; >+ >+// A type-erased handle to a format argument. >+class FormatArgImpl { >+ private: >+ enum { kInlinedSpace = 8 }; >+ >+ using VoidPtr = str_format_internal::VoidPtr; >+ >+ union Data { >+ const void* ptr; >+ const volatile void* volatile_ptr; >+ char buf[kInlinedSpace]; >+ }; >+ >+ struct VTable { >+ bool (*convert)(Data, const str_format_internal::ConversionSpec& conv, >+ FormatSinkImpl* out); >+ int (*to_int)(Data); >+ }; >+ >+ template <typename T> >+ struct store_by_value >+ : std::integral_constant<bool, (sizeof(T) <= kInlinedSpace) && >+ (std::is_integral<T>::value || >+ std::is_floating_point<T>::value || >+ std::is_pointer<T>::value || >+ std::is_same<VoidPtr, T>::value)> {}; >+ >+ enum StoragePolicy { ByPointer, ByVolatilePointer, ByValue }; >+ template <typename T> >+ struct storage_policy >+ : std::integral_constant<StoragePolicy, >+ (std::is_volatile<T>::value >+ ? ByVolatilePointer >+ : (store_by_value<T>::value ? ByValue >+ : ByPointer))> { >+ }; >+ >+ // An instance of an FormatArgImpl::VTable suitable for 'T'. >+ template <typename T> >+ struct TypedVTable; >+ >+ // To reduce the number of vtables we will decay values before hand. >+ // Anything with a user-defined Convert will get its own vtable. >+ // For everything else: >+ // - Decay char* and char arrays into `const char*` >+ // - Decay any other pointer to `const void*` >+ // - Decay all enums to their underlying type. >+ // - Decay function pointers to void*. >+ template <typename T, typename = void> >+ struct DecayType { >+ static constexpr bool kHasUserDefined = >+ str_format_internal::HasUserDefinedConvert<T>::value; >+ using type = typename std::conditional< >+ !kHasUserDefined && std::is_convertible<T, const char*>::value, >+ const char*, >+ typename std::conditional<!kHasUserDefined && >+ std::is_convertible<T, VoidPtr>::value, >+ VoidPtr, const T&>::type>::type; >+ }; >+ template <typename T> >+ struct DecayType<T, >+ typename std::enable_if< >+ !str_format_internal::HasUserDefinedConvert<T>::value && >+ std::is_enum<T>::value>::type> { >+ using type = typename std::underlying_type<T>::type; >+ }; >+ >+ public: >+ template <typename T> >+ explicit FormatArgImpl(const T& value) { >+ using D = typename DecayType<T>::type; >+ static_assert( >+ std::is_same<D, const T&>::value || storage_policy<D>::value == ByValue, >+ "Decayed types must be stored by value"); >+ Init(static_cast<D>(value)); >+ } >+ >+ private: >+ friend struct str_format_internal::FormatArgImplFriend; >+ template <typename T, StoragePolicy = storage_policy<T>::value> >+ struct Manager; >+ >+ template <typename T> >+ struct Manager<T, ByPointer> { >+ static Data SetValue(const T& value) { >+ Data data; >+ data.ptr = &value; >+ return data; >+ } >+ >+ static const T& Value(Data arg) { return *static_cast<const T*>(arg.ptr); } >+ }; >+ >+ template <typename T> >+ struct Manager<T, ByVolatilePointer> { >+ static Data SetValue(const T& value) { >+ Data data; >+ data.volatile_ptr = &value; >+ return data; >+ } >+ >+ static const T& Value(Data arg) { >+ return *static_cast<const T*>(arg.volatile_ptr); >+ } >+ }; >+ >+ template <typename T> >+ struct Manager<T, ByValue> { >+ static Data SetValue(const T& value) { >+ Data data; >+ memcpy(data.buf, &value, sizeof(value)); >+ return data; >+ } >+ >+ static T Value(Data arg) { >+ T value; >+ memcpy(&value, arg.buf, sizeof(T)); >+ return value; >+ } >+ }; >+ >+ template <typename T> >+ void Init(const T& value); >+ >+ template <typename T> >+ static int ToIntVal(const T& val) { >+ using CommonType = typename std::conditional<std::is_signed<T>::value, >+ int64_t, uint64_t>::type; >+ if (static_cast<CommonType>(val) > >+ static_cast<CommonType>(std::numeric_limits<int>::max())) { >+ return std::numeric_limits<int>::max(); >+ } else if (std::is_signed<T>::value && >+ static_cast<CommonType>(val) < >+ static_cast<CommonType>(std::numeric_limits<int>::min())) { >+ return std::numeric_limits<int>::min(); >+ } >+ return static_cast<int>(val); >+ } >+ >+ Data data_; >+ const VTable* vtbl_; >+}; >+ >+template <typename T> >+struct FormatArgImpl::TypedVTable { >+ private: >+ static bool ConvertImpl(Data arg, >+ const str_format_internal::ConversionSpec& conv, >+ FormatSinkImpl* out) { >+ return str_format_internal::FormatConvertImpl(Manager<T>::Value(arg), conv, >+ out) >+ .value; >+ } >+ >+ template <typename U = T, typename = void> >+ struct ToIntImpl { >+ static constexpr int (*value)(Data) = nullptr; >+ }; >+ >+ template <typename U> >+ struct ToIntImpl<U, >+ typename std::enable_if<std::is_integral<U>::value>::type> { >+ static int Invoke(Data arg) { return ToIntVal(Manager<T>::Value(arg)); } >+ static constexpr int (*value)(Data) = &Invoke; >+ }; >+ >+ template <typename U> >+ struct ToIntImpl<U, typename std::enable_if<std::is_enum<U>::value>::type> { >+ static int Invoke(Data arg) { >+ return ToIntVal(static_cast<typename std::underlying_type<T>::type>( >+ Manager<T>::Value(arg))); >+ } >+ static constexpr int (*value)(Data) = &Invoke; >+ }; >+ >+ public: >+ static constexpr VTable value{&ConvertImpl, ToIntImpl<>::value}; >+}; >+ >+template <typename T> >+constexpr FormatArgImpl::VTable FormatArgImpl::TypedVTable<T>::value; >+ >+template <typename T> >+void FormatArgImpl::Init(const T& value) { >+ data_ = Manager<T>::SetValue(value); >+ vtbl_ = &TypedVTable<T>::value; >+} >+ >+extern template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>; >+ >+extern template struct FormatArgImpl::TypedVTable<bool>; >+extern template struct FormatArgImpl::TypedVTable<char>; >+extern template struct FormatArgImpl::TypedVTable<signed char>; >+extern template struct FormatArgImpl::TypedVTable<unsigned char>; >+extern template struct FormatArgImpl::TypedVTable<short>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable<unsigned short>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable<int>; >+extern template struct FormatArgImpl::TypedVTable<unsigned>; >+extern template struct FormatArgImpl::TypedVTable<long>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable<unsigned long>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable<long long>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable< >+ unsigned long long>; // NOLINT >+extern template struct FormatArgImpl::TypedVTable<uint128>; >+ >+extern template struct FormatArgImpl::TypedVTable<float>; >+extern template struct FormatArgImpl::TypedVTable<double>; >+extern template struct FormatArgImpl::TypedVTable<long double>; >+ >+extern template struct FormatArgImpl::TypedVTable<const char*>; >+extern template struct FormatArgImpl::TypedVTable<std::string>; >+extern template struct FormatArgImpl::TypedVTable<string_view>; >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc >new file mode 100644 >index 00000000000..83d59048ea2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/arg_test.cc >@@ -0,0 +1,111 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+#include "absl/strings/internal/str_format/arg.h" >+ >+#include <ostream> >+#include <string> >+#include "gtest/gtest.h" >+#include "absl/strings/str_format.h" >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+class FormatArgImplTest : public ::testing::Test { >+ public: >+ enum Color { kRed, kGreen, kBlue }; >+ >+ static const char *hi() { return "hi"; } >+}; >+ >+TEST_F(FormatArgImplTest, ToInt) { >+ int out = 0; >+ EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(1), &out)); >+ EXPECT_EQ(1, out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(-1), &out)); >+ EXPECT_EQ(-1, out); >+ EXPECT_TRUE( >+ FormatArgImplFriend::ToInt(FormatArgImpl(static_cast<char>(64)), &out)); >+ EXPECT_EQ(64, out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt( >+ FormatArgImpl(static_cast<unsigned long long>(123456)), &out)); // NOLINT >+ EXPECT_EQ(123456, out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt( >+ FormatArgImpl(static_cast<unsigned long long>( // NOLINT >+ std::numeric_limits<int>::max()) + >+ 1), >+ &out)); >+ EXPECT_EQ(std::numeric_limits<int>::max(), out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt( >+ FormatArgImpl(static_cast<long long>( // NOLINT >+ std::numeric_limits<int>::min()) - >+ 10), >+ &out)); >+ EXPECT_EQ(std::numeric_limits<int>::min(), out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(false), &out)); >+ EXPECT_EQ(0, out); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(true), &out)); >+ EXPECT_EQ(1, out); >+ EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(2.2), &out)); >+ EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(3.2f), &out)); >+ EXPECT_FALSE(FormatArgImplFriend::ToInt( >+ FormatArgImpl(static_cast<int *>(nullptr)), &out)); >+ EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl(hi()), &out)); >+ EXPECT_FALSE(FormatArgImplFriend::ToInt(FormatArgImpl("hi"), &out)); >+ EXPECT_TRUE(FormatArgImplFriend::ToInt(FormatArgImpl(kBlue), &out)); >+ EXPECT_EQ(2, out); >+} >+ >+extern const char kMyArray[]; >+ >+TEST_F(FormatArgImplTest, CharArraysDecayToCharPtr) { >+ const char* a = ""; >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)), >+ FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(""))); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)), >+ FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl("A"))); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)), >+ FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl("ABC"))); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(a)), >+ FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(kMyArray))); >+} >+ >+TEST_F(FormatArgImplTest, OtherPtrDecayToVoidPtr) { >+ auto expected = FormatArgImplFriend::GetVTablePtrForTest( >+ FormatArgImpl(static_cast<void *>(nullptr))); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest( >+ FormatArgImpl(static_cast<int *>(nullptr))), >+ expected); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest( >+ FormatArgImpl(static_cast<volatile int *>(nullptr))), >+ expected); >+ >+ auto p = static_cast<void (*)()>([] {}); >+ EXPECT_EQ(FormatArgImplFriend::GetVTablePtrForTest(FormatArgImpl(p)), >+ expected); >+} >+ >+TEST_F(FormatArgImplTest, WorksWithCharArraysOfUnknownSize) { >+ std::string s; >+ FormatSinkImpl sink(&s); >+ ConversionSpec conv; >+ conv.set_conv(ConversionChar::FromChar('s')); >+ conv.set_flags(Flags()); >+ conv.set_width(-1); >+ conv.set_precision(-1); >+ EXPECT_TRUE( >+ FormatArgImplFriend::Convert(FormatArgImpl(kMyArray), conv, &sink)); >+ sink.Flush(); >+ EXPECT_EQ("ABCDE", s); >+} >+const char kMyArray[] = "ABCDE"; >+ >+} // namespace >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc >new file mode 100644 >index 00000000000..33e8641558a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc >@@ -0,0 +1,232 @@ >+#include "absl/strings/internal/str_format/bind.h" >+ >+#include <cerrno> >+#include <limits> >+#include <sstream> >+#include <string> >+ >+namespace absl { >+namespace str_format_internal { >+ >+namespace { >+ >+inline bool BindFromPosition(int position, int* value, >+ absl::Span<const FormatArgImpl> pack) { >+ assert(position > 0); >+ if (static_cast<size_t>(position) > pack.size()) { >+ return false; >+ } >+ // -1 because positions are 1-based >+ return FormatArgImplFriend::ToInt(pack[position - 1], value); >+} >+ >+class ArgContext { >+ public: >+ explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {} >+ >+ // Fill 'bound' with the results of applying the context's argument pack >+ // to the specified 'props'. We synthesize a BoundConversion by >+ // lining up a UnboundConversion with a user argument. We also >+ // resolve any '*' specifiers for width and precision, so after >+ // this call, 'bound' has all the information it needs to be formatted. >+ // Returns false on failure. >+ bool Bind(const UnboundConversion *props, BoundConversion *bound); >+ >+ private: >+ absl::Span<const FormatArgImpl> pack_; >+}; >+ >+inline bool ArgContext::Bind(const UnboundConversion* unbound, >+ BoundConversion* bound) { >+ const FormatArgImpl* arg = nullptr; >+ int arg_position = unbound->arg_position; >+ if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false; >+ arg = &pack_[arg_position - 1]; // 1-based >+ >+ if (!unbound->flags.basic) { >+ int width = unbound->width.value(); >+ bool force_left = false; >+ if (unbound->width.is_from_arg()) { >+ if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_)) >+ return false; >+ if (width < 0) { >+ // "A negative field width is taken as a '-' flag followed by a >+ // positive field width." >+ force_left = true; >+ width = -width; >+ } >+ } >+ >+ int precision = unbound->precision.value(); >+ if (unbound->precision.is_from_arg()) { >+ if (!BindFromPosition(unbound->precision.get_from_arg(), &precision, >+ pack_)) >+ return false; >+ } >+ >+ bound->set_width(width); >+ bound->set_precision(precision); >+ bound->set_flags(unbound->flags); >+ if (force_left) >+ bound->set_left(true); >+ } else { >+ bound->set_flags(unbound->flags); >+ bound->set_width(-1); >+ bound->set_precision(-1); >+ } >+ >+ bound->set_length_mod(unbound->length_mod); >+ bound->set_conv(unbound->conv); >+ bound->set_arg(arg); >+ return true; >+} >+ >+template <typename Converter> >+class ConverterConsumer { >+ public: >+ ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack) >+ : converter_(converter), arg_context_(pack) {} >+ >+ bool Append(string_view s) { >+ converter_.Append(s); >+ return true; >+ } >+ bool ConvertOne(const UnboundConversion& conv, string_view conv_string) { >+ BoundConversion bound; >+ if (!arg_context_.Bind(&conv, &bound)) return false; >+ return converter_.ConvertOne(bound, conv_string); >+ } >+ >+ private: >+ Converter converter_; >+ ArgContext arg_context_; >+}; >+ >+template <typename Converter> >+bool ConvertAll(const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args, >+ const Converter& converter) { >+ const ParsedFormatBase* pc = format.parsed_conversion(); >+ if (pc) >+ return pc->ProcessFormat(ConverterConsumer<Converter>(converter, args)); >+ >+ return ParseFormatString(format.str(), >+ ConverterConsumer<Converter>(converter, args)); >+} >+ >+class DefaultConverter { >+ public: >+ explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {} >+ >+ void Append(string_view s) const { sink_->Append(s); } >+ >+ bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { >+ return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_); >+ } >+ >+ private: >+ FormatSinkImpl* sink_; >+}; >+ >+class SummarizingConverter { >+ public: >+ explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {} >+ >+ void Append(string_view s) const { sink_->Append(s); } >+ >+ bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const { >+ UntypedFormatSpecImpl spec("%d"); >+ >+ std::ostringstream ss; >+ ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags(); >+ if (bound.width() >= 0) ss << bound.width(); >+ if (bound.precision() >= 0) ss << "." << bound.precision(); >+ ss << bound.length_mod() << bound.conv() << "}"; >+ Append(ss.str()); >+ return true; >+ } >+ >+ private: >+ FormatSinkImpl* sink_; >+}; >+ >+} // namespace >+ >+bool BindWithPack(const UnboundConversion* props, >+ absl::Span<const FormatArgImpl> pack, >+ BoundConversion* bound) { >+ return ArgContext(pack).Bind(props, bound); >+} >+ >+std::string Summarize(const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ typedef SummarizingConverter Converter; >+ std::string out; >+ { >+ // inner block to destroy sink before returning out. It ensures a last >+ // flush. >+ FormatSinkImpl sink(&out); >+ if (!ConvertAll(format, args, Converter(&sink))) { >+ sink.Flush(); >+ out.clear(); >+ } >+ } >+ return out; >+} >+ >+bool FormatUntyped(FormatRawSinkImpl raw_sink, >+ const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ FormatSinkImpl sink(raw_sink); >+ using Converter = DefaultConverter; >+ if (!ConvertAll(format, args, Converter(&sink))) { >+ sink.Flush(); >+ return false; >+ } >+ return true; >+} >+ >+std::ostream& Streamable::Print(std::ostream& os) const { >+ if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit); >+ return os; >+} >+ >+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ size_t orig = out->size(); >+ if (!FormatUntyped(out, format, args)) out->resize(orig); >+ return *out; >+} >+ >+int FprintF(std::FILE* output, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ FILERawSink sink(output); >+ if (!FormatUntyped(&sink, format, args)) { >+ errno = EINVAL; >+ return -1; >+ } >+ if (sink.error()) { >+ errno = sink.error(); >+ return -1; >+ } >+ if (sink.count() > std::numeric_limits<int>::max()) { >+ errno = EFBIG; >+ return -1; >+ } >+ return static_cast<int>(sink.count()); >+} >+ >+int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ BufferRawSink sink(output, size ? size - 1 : 0); >+ if (!FormatUntyped(&sink, format, args)) { >+ errno = EINVAL; >+ return -1; >+ } >+ size_t total = sink.total_written(); >+ if (size) output[std::min(total, size - 1)] = 0; >+ return static_cast<int>(total); >+} >+ >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h >new file mode 100644 >index 00000000000..4008611211c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h >@@ -0,0 +1,189 @@ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ >+ >+#include <array> >+#include <cstdio> >+#include <sstream> >+#include <string> >+ >+#include "absl/base/port.h" >+#include "absl/container/inlined_vector.h" >+#include "absl/strings/internal/str_format/arg.h" >+#include "absl/strings/internal/str_format/checker.h" >+#include "absl/strings/internal/str_format/parser.h" >+#include "absl/types/span.h" >+ >+namespace absl { >+ >+class UntypedFormatSpec; >+ >+namespace str_format_internal { >+ >+class BoundConversion : public ConversionSpec { >+ public: >+ const FormatArgImpl* arg() const { return arg_; } >+ void set_arg(const FormatArgImpl* a) { arg_ = a; } >+ >+ private: >+ const FormatArgImpl* arg_; >+}; >+ >+// This is the type-erased class that the implementation uses. >+class UntypedFormatSpecImpl { >+ public: >+ UntypedFormatSpecImpl() = delete; >+ >+ explicit UntypedFormatSpecImpl(string_view s) : str_(s), pc_() {} >+ explicit UntypedFormatSpecImpl( >+ const str_format_internal::ParsedFormatBase* pc) >+ : pc_(pc) {} >+ string_view str() const { return str_; } >+ const str_format_internal::ParsedFormatBase* parsed_conversion() const { >+ return pc_; >+ } >+ >+ template <typename T> >+ static const UntypedFormatSpecImpl& Extract(const T& s) { >+ return s.spec_; >+ } >+ >+ private: >+ string_view str_; >+ const str_format_internal::ParsedFormatBase* pc_; >+}; >+ >+template <typename T, typename...> >+struct MakeDependent { >+ using type = T; >+}; >+ >+// Implicitly convertible from `const char*`, `string_view`, and the >+// `ExtendedParsedFormat` type. This abstraction allows all format functions to >+// operate on any without providing too many overloads. >+template <typename... Args> >+class FormatSpecTemplate >+ : public MakeDependent<UntypedFormatSpec, Args...>::type { >+ using Base = typename MakeDependent<UntypedFormatSpec, Args...>::type; >+ >+ public: >+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+ // Honeypot overload for when the std::string is not constexpr. >+ // We use the 'unavailable' attribute to give a better compiler error than >+ // just 'method is deleted'. >+ FormatSpecTemplate(...) // NOLINT >+ __attribute__((unavailable("Format std::string is not constexpr."))); >+ >+ // Honeypot overload for when the format is constexpr and invalid. >+ // We use the 'unavailable' attribute to give a better compiler error than >+ // just 'method is deleted'. >+ // To avoid checking the format twice, we just check that the format is >+ // constexpr. If is it valid, then the overload below will kick in. >+ // We add the template here to make this overload have lower priority. >+ template <typename = void> >+ FormatSpecTemplate(const char* s) // NOLINT >+ __attribute__(( >+ enable_if(str_format_internal::EnsureConstexpr(s), "constexpr trap"), >+ unavailable( >+ "Format specified does not match the arguments passed."))); >+ >+ template <typename T = void> >+ FormatSpecTemplate(string_view s) // NOLINT >+ __attribute__((enable_if(str_format_internal::EnsureConstexpr(s), >+ "constexpr trap"))) { >+ static_assert(sizeof(T*) == 0, >+ "Format specified does not match the arguments passed."); >+ } >+ >+ // Good format overload. >+ FormatSpecTemplate(const char* s) // NOLINT >+ __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), >+ "bad format trap"))) >+ : Base(s) {} >+ >+ FormatSpecTemplate(string_view s) // NOLINT >+ __attribute__((enable_if(ValidFormatImpl<ArgumentToConv<Args>()...>(s), >+ "bad format trap"))) >+ : Base(s) {} >+ >+#else // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+ FormatSpecTemplate(const char* s) : Base(s) {} // NOLINT >+ FormatSpecTemplate(string_view s) : Base(s) {} // NOLINT >+ >+#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+ template <Conv... C, typename = typename std::enable_if< >+ sizeof...(C) == sizeof...(Args) && >+ AllOf(Contains(ArgumentToConv<Args>(), >+ C)...)>::type> >+ FormatSpecTemplate(const ExtendedParsedFormat<C...>& pc) // NOLINT >+ : Base(&pc) {} >+}; >+ >+template <typename... Args> >+struct FormatSpecDeductionBarrier { >+ using type = FormatSpecTemplate<Args...>; >+}; >+ >+class Streamable { >+ public: >+ Streamable(const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) >+ : format_(format), args_(args.begin(), args.end()) {} >+ >+ std::ostream& Print(std::ostream& os) const; >+ >+ friend std::ostream& operator<<(std::ostream& os, const Streamable& l) { >+ return l.Print(os); >+ } >+ >+ private: >+ const UntypedFormatSpecImpl& format_; >+ absl::InlinedVector<FormatArgImpl, 4> args_; >+}; >+ >+// for testing >+std::string Summarize(const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args); >+bool BindWithPack(const UnboundConversion* props, >+ absl::Span<const FormatArgImpl> pack, BoundConversion* bound); >+ >+bool FormatUntyped(FormatRawSinkImpl raw_sink, >+ const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args); >+ >+std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args); >+ >+inline std::string FormatPack(const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args) { >+ std::string out; >+ AppendPack(&out, format, args); >+ return out; >+} >+ >+int FprintF(std::FILE* output, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args); >+int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl& format, >+ absl::Span<const FormatArgImpl> args); >+ >+// Returned by Streamed(v). Converts via '%s' to the std::string created >+// by std::ostream << v. >+template <typename T> >+class StreamedWrapper { >+ public: >+ explicit StreamedWrapper(const T& v) : v_(v) { } >+ >+ private: >+ template <typename S> >+ friend ConvertResult<Conv::s> FormatConvertImpl(const StreamedWrapper<S>& v, >+ const ConversionSpec& conv, >+ FormatSinkImpl* out); >+ const T& v_; >+}; >+ >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc >new file mode 100644 >index 00000000000..47575739ba1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc >@@ -0,0 +1,131 @@ >+#include "absl/strings/internal/str_format/bind.h" >+ >+#include <string.h> >+ >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+template <typename T, size_t N> >+size_t ArraySize(T (&)[N]) { >+ return N; >+} >+ >+class FormatBindTest : public ::testing::Test { >+ public: >+ bool Extract(const char *s, UnboundConversion *props, int *next) const { >+ absl::string_view src = s; >+ return ConsumeUnboundConversion(&src, props, next) && src.empty(); >+ } >+}; >+ >+TEST_F(FormatBindTest, BindSingle) { >+ struct Expectation { >+ int line; >+ const char *fmt; >+ int ok_phases; >+ const FormatArgImpl *arg; >+ int width; >+ int precision; >+ int next_arg; >+ }; >+ const int no = -1; >+ const int ia[] = { 10, 20, 30, 40}; >+ const FormatArgImpl args[] = {FormatArgImpl(ia[0]), FormatArgImpl(ia[1]), >+ FormatArgImpl(ia[2]), FormatArgImpl(ia[3])}; >+#pragma GCC diagnostic push >+#pragma GCC diagnostic ignored "-Wmissing-field-initializers" >+ const Expectation kExpect[] = { >+ {__LINE__, "d", 2, &args[0], no, no, 2}, >+ {__LINE__, "4d", 2, &args[0], 4, no, 2}, >+ {__LINE__, ".5d", 2, &args[0], no, 5, 2}, >+ {__LINE__, "4.5d", 2, &args[0], 4, 5, 2}, >+ {__LINE__, "*d", 2, &args[1], 10, no, 3}, >+ {__LINE__, ".*d", 2, &args[1], no, 10, 3}, >+ {__LINE__, "*.*d", 2, &args[2], 10, 20, 4}, >+ {__LINE__, "1$d", 2, &args[0], no, no, 0}, >+ {__LINE__, "2$d", 2, &args[1], no, no, 0}, >+ {__LINE__, "3$d", 2, &args[2], no, no, 0}, >+ {__LINE__, "4$d", 2, &args[3], no, no, 0}, >+ {__LINE__, "2$*1$d", 2, &args[1], 10, no, 0}, >+ {__LINE__, "2$*2$d", 2, &args[1], 20, no, 0}, >+ {__LINE__, "2$*3$d", 2, &args[1], 30, no, 0}, >+ {__LINE__, "2$.*1$d", 2, &args[1], no, 10, 0}, >+ {__LINE__, "2$.*2$d", 2, &args[1], no, 20, 0}, >+ {__LINE__, "2$.*3$d", 2, &args[1], no, 30, 0}, >+ {__LINE__, "2$*3$.*1$d", 2, &args[1], 30, 10, 0}, >+ {__LINE__, "2$*2$.*2$d", 2, &args[1], 20, 20, 0}, >+ {__LINE__, "2$*1$.*3$d", 2, &args[1], 10, 30, 0}, >+ {__LINE__, "2$*3$.*1$d", 2, &args[1], 30, 10, 0}, >+ {__LINE__, "1$*d", 0}, // indexed, then positional >+ {__LINE__, "*2$d", 0}, // positional, then indexed >+ {__LINE__, "6$d", 1}, // arg position out of bounds >+ {__LINE__, "1$6$d", 0}, // width position incorrectly specified >+ {__LINE__, "1$.6$d", 0}, // precision position incorrectly specified >+ {__LINE__, "1$*6$d", 1}, // width position out of bounds >+ {__LINE__, "1$.*6$d", 1}, // precision position out of bounds >+ }; >+#pragma GCC diagnostic pop >+ for (const Expectation &e : kExpect) { >+ SCOPED_TRACE(e.line); >+ SCOPED_TRACE(e.fmt); >+ UnboundConversion props; >+ BoundConversion bound; >+ int ok_phases = 0; >+ int next = 0; >+ if (Extract(e.fmt, &props, &next)) { >+ ++ok_phases; >+ if (BindWithPack(&props, args, &bound)) { >+ ++ok_phases; >+ } >+ } >+ EXPECT_EQ(e.ok_phases, ok_phases); >+ if (e.ok_phases < 2) continue; >+ if (e.arg != nullptr) { >+ EXPECT_EQ(e.arg, bound.arg()); >+ } >+ EXPECT_EQ(e.width, bound.width()); >+ EXPECT_EQ(e.precision, bound.precision()); >+ } >+} >+ >+TEST_F(FormatBindTest, FormatPack) { >+ struct Expectation { >+ int line; >+ const char *fmt; >+ const char *summary; >+ }; >+ const int ia[] = { 10, 20, 30, 40, -10 }; >+ const FormatArgImpl args[] = {FormatArgImpl(ia[0]), FormatArgImpl(ia[1]), >+ FormatArgImpl(ia[2]), FormatArgImpl(ia[3]), >+ FormatArgImpl(ia[4])}; >+ const Expectation kExpect[] = { >+ {__LINE__, "a%4db%dc", "a{10:4d}b{20:d}c"}, >+ {__LINE__, "a%.4db%dc", "a{10:.4d}b{20:d}c"}, >+ {__LINE__, "a%4.5db%dc", "a{10:4.5d}b{20:d}c"}, >+ {__LINE__, "a%db%4.5dc", "a{10:d}b{20:4.5d}c"}, >+ {__LINE__, "a%db%*.*dc", "a{10:d}b{40:20.30d}c"}, >+ {__LINE__, "a%.*fb", "a{20:.10f}b"}, >+ {__LINE__, "a%1$db%2$*3$.*4$dc", "a{10:d}b{20:30.40d}c"}, >+ {__LINE__, "a%4$db%3$*2$.*1$dc", "a{40:d}b{30:20.10d}c"}, >+ {__LINE__, "a%04ldb", "a{10:04ld}b"}, >+ {__LINE__, "a%-#04lldb", "a{10:-#04lld}b"}, >+ {__LINE__, "a%1$*5$db", "a{10:-10d}b"}, >+ {__LINE__, "a%1$.*5$db", "a{10:d}b"}, >+ }; >+ for (const Expectation &e : kExpect) { >+ absl::string_view fmt = e.fmt; >+ SCOPED_TRACE(e.line); >+ SCOPED_TRACE(e.fmt); >+ UntypedFormatSpecImpl format(fmt); >+ EXPECT_EQ(e.summary, >+ str_format_internal::Summarize(format, absl::MakeSpan(args))) >+ << "line:" << e.line; >+ } >+} >+ >+} // namespace >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h >new file mode 100644 >index 00000000000..8b594f2d5cc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h >@@ -0,0 +1,325 @@ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ >+ >+#include "absl/strings/internal/str_format/arg.h" >+#include "absl/strings/internal/str_format/extension.h" >+ >+// Compile time check support for entry points. >+ >+#ifndef ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+#if defined(__clang__) && !defined(__native_client__) >+#if __has_attribute(enable_if) >+#define ABSL_INTERNAL_ENABLE_FORMAT_CHECKER 1 >+#endif // __has_attribute(enable_if) >+#endif // defined(__clang__) && !defined(__native_client__) >+#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+namespace absl { >+namespace str_format_internal { >+ >+constexpr bool AllOf() { return true; } >+ >+template <typename... T> >+constexpr bool AllOf(bool b, T... t) { >+ return b && AllOf(t...); >+} >+ >+template <typename Arg> >+constexpr Conv ArgumentToConv() { >+ return decltype(str_format_internal::FormatConvertImpl( >+ std::declval<const Arg&>(), std::declval<const ConversionSpec&>(), >+ std::declval<FormatSinkImpl*>()))::kConv; >+} >+ >+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+constexpr bool ContainsChar(const char* chars, char c) { >+ return *chars == c || (*chars && ContainsChar(chars + 1, c)); >+} >+ >+// A constexpr compatible list of Convs. >+struct ConvList { >+ const Conv* array; >+ int count; >+ >+ // We do the bound check here to avoid having to do it on the callers. >+ // Returning an empty Conv has the same effect as short circuiting because it >+ // will never match any conversion. >+ constexpr Conv operator[](int i) const { >+ return i < count ? array[i] : Conv{}; >+ } >+ >+ constexpr ConvList without_front() const { >+ return count != 0 ? ConvList{array + 1, count - 1} : *this; >+ } >+}; >+ >+template <size_t count> >+struct ConvListT { >+ // Make sure the array has size > 0. >+ Conv list[count ? count : 1]; >+}; >+ >+constexpr char GetChar(string_view str, size_t index) { >+ return index < str.size() ? str[index] : char{}; >+} >+ >+constexpr string_view ConsumeFront(string_view str, size_t len = 1) { >+ return len <= str.size() ? string_view(str.data() + len, str.size() - len) >+ : string_view(); >+} >+ >+constexpr string_view ConsumeAnyOf(string_view format, const char* chars) { >+ return ContainsChar(chars, GetChar(format, 0)) >+ ? ConsumeAnyOf(ConsumeFront(format), chars) >+ : format; >+} >+ >+constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } >+ >+// Helper class for the ParseDigits function. >+// It encapsulates the two return values we need there. >+struct Integer { >+ string_view format; >+ int value; >+ >+ // If the next character is a '$', consume it. >+ // Otherwise, make `this` an invalid positional argument. >+ constexpr Integer ConsumePositionalDollar() const { >+ return GetChar(format, 0) == '$' ? Integer{ConsumeFront(format), value} >+ : Integer{format, 0}; >+ } >+}; >+ >+constexpr Integer ParseDigits(string_view format, int value = 0) { >+ return IsDigit(GetChar(format, 0)) >+ ? ParseDigits(ConsumeFront(format), >+ 10 * value + GetChar(format, 0) - '0') >+ : Integer{format, value}; >+} >+ >+// Parse digits for a positional argument. >+// The parsing also consumes the '$'. >+constexpr Integer ParsePositional(string_view format) { >+ return ParseDigits(format).ConsumePositionalDollar(); >+} >+ >+// Parses a single conversion specifier. >+// See ConvParser::Run() for post conditions. >+class ConvParser { >+ constexpr ConvParser SetFormat(string_view format) const { >+ return ConvParser(format, args_, error_, arg_position_, is_positional_); >+ } >+ >+ constexpr ConvParser SetArgs(ConvList args) const { >+ return ConvParser(format_, args, error_, arg_position_, is_positional_); >+ } >+ >+ constexpr ConvParser SetError(bool error) const { >+ return ConvParser(format_, args_, error_ || error, arg_position_, >+ is_positional_); >+ } >+ >+ constexpr ConvParser SetArgPosition(int arg_position) const { >+ return ConvParser(format_, args_, error_, arg_position, is_positional_); >+ } >+ >+ // Consumes the next arg and verifies that it matches `conv`. >+ // `error_` is set if there is no next arg or if it doesn't match `conv`. >+ constexpr ConvParser ConsumeNextArg(char conv) const { >+ return SetArgs(args_.without_front()).SetError(!Contains(args_[0], conv)); >+ } >+ >+ // Verify that positional argument `i.value` matches `conv`. >+ // `error_` is set if `i.value` is not a valid argument or if it doesn't >+ // match. >+ constexpr ConvParser VerifyPositional(Integer i, char conv) const { >+ return SetFormat(i.format).SetError(!Contains(args_[i.value - 1], conv)); >+ } >+ >+ // Parse the position of the arg and store it in `arg_position_`. >+ constexpr ConvParser ParseArgPosition(Integer arg) const { >+ return SetFormat(arg.format).SetArgPosition(arg.value); >+ } >+ >+ // Consume the flags. >+ constexpr ConvParser ParseFlags() const { >+ return SetFormat(ConsumeAnyOf(format_, "-+ #0")); >+ } >+ >+ // Consume the width. >+ // If it is '*', we verify that it matches `args_`. `error_` is set if it >+ // doesn't match. >+ constexpr ConvParser ParseWidth() const { >+ return IsDigit(GetChar(format_, 0)) >+ ? SetFormat(ParseDigits(format_).format) >+ : GetChar(format_, 0) == '*' >+ ? is_positional_ >+ ? VerifyPositional( >+ ParsePositional(ConsumeFront(format_)), '*') >+ : SetFormat(ConsumeFront(format_)) >+ .ConsumeNextArg('*') >+ : *this; >+ } >+ >+ // Consume the precision. >+ // If it is '*', we verify that it matches `args_`. `error_` is set if it >+ // doesn't match. >+ constexpr ConvParser ParsePrecision() const { >+ return GetChar(format_, 0) != '.' >+ ? *this >+ : GetChar(format_, 1) == '*' >+ ? is_positional_ >+ ? VerifyPositional( >+ ParsePositional(ConsumeFront(format_, 2)), '*') >+ : SetFormat(ConsumeFront(format_, 2)) >+ .ConsumeNextArg('*') >+ : SetFormat(ParseDigits(ConsumeFront(format_)).format); >+ } >+ >+ // Consume the length characters. >+ constexpr ConvParser ParseLength() const { >+ return SetFormat(ConsumeAnyOf(format_, "lLhjztq")); >+ } >+ >+ // Consume the conversion character and verify that it matches `args_`. >+ // `error_` is set if it doesn't match. >+ constexpr ConvParser ParseConversion() const { >+ return is_positional_ >+ ? VerifyPositional({ConsumeFront(format_), arg_position_}, >+ GetChar(format_, 0)) >+ : ConsumeNextArg(GetChar(format_, 0)) >+ .SetFormat(ConsumeFront(format_)); >+ } >+ >+ constexpr ConvParser(string_view format, ConvList args, bool error, >+ int arg_position, bool is_positional) >+ : format_(format), >+ args_(args), >+ error_(error), >+ arg_position_(arg_position), >+ is_positional_(is_positional) {} >+ >+ public: >+ constexpr ConvParser(string_view format, ConvList args, bool is_positional) >+ : format_(format), >+ args_(args), >+ error_(false), >+ arg_position_(0), >+ is_positional_(is_positional) {} >+ >+ // Consume the whole conversion specifier. >+ // `format()` will be set to the character after the conversion character. >+ // `error()` will be set if any of the arguments do not match. >+ constexpr ConvParser Run() const { >+ return (is_positional_ ? ParseArgPosition(ParsePositional(format_)) : *this) >+ .ParseFlags() >+ .ParseWidth() >+ .ParsePrecision() >+ .ParseLength() >+ .ParseConversion(); >+ } >+ >+ constexpr string_view format() const { return format_; } >+ constexpr ConvList args() const { return args_; } >+ constexpr bool error() const { return error_; } >+ constexpr bool is_positional() const { return is_positional_; } >+ >+ private: >+ string_view format_; >+ // Current list of arguments. If we are not in positional mode we will consume >+ // from the front. >+ ConvList args_; >+ bool error_; >+ // Holds the argument position of the conversion character, if we are in >+ // positional mode. Otherwise, it is unspecified. >+ int arg_position_; >+ // Whether we are in positional mode. >+ // It changes the behavior of '*' and where to find the converted argument. >+ bool is_positional_; >+}; >+ >+// Parses a whole format expression. >+// See FormatParser::Run(). >+class FormatParser { >+ static constexpr bool FoundPercent(string_view format) { >+ return format.empty() || >+ (GetChar(format, 0) == '%' && GetChar(format, 1) != '%'); >+ } >+ >+ // We use an inner function to increase the recursion limit. >+ // The inner function consumes up to `limit` characters on every run. >+ // This increases the limit from 512 to ~512*limit. >+ static constexpr string_view ConsumeNonPercentInner(string_view format, >+ int limit = 20) { >+ return FoundPercent(format) || !limit >+ ? format >+ : ConsumeNonPercentInner( >+ ConsumeFront(format, GetChar(format, 0) == '%' && >+ GetChar(format, 1) == '%' >+ ? 2 >+ : 1), >+ limit - 1); >+ } >+ >+ // Consume characters until the next conversion spec %. >+ // It skips %%. >+ static constexpr string_view ConsumeNonPercent(string_view format) { >+ return FoundPercent(format) >+ ? format >+ : ConsumeNonPercent(ConsumeNonPercentInner(format)); >+ } >+ >+ static constexpr bool IsPositional(string_view format) { >+ return IsDigit(GetChar(format, 0)) ? IsPositional(ConsumeFront(format)) >+ : GetChar(format, 0) == '$'; >+ } >+ >+ constexpr bool RunImpl(bool is_positional) const { >+ // In non-positional mode we require all arguments to be consumed. >+ // In positional mode just reaching the end of the format without errors is >+ // enough. >+ return (format_.empty() && (is_positional || args_.count == 0)) || >+ (!format_.empty() && >+ ValidateArg( >+ ConvParser(ConsumeFront(format_), args_, is_positional).Run())); >+ } >+ >+ constexpr bool ValidateArg(ConvParser conv) const { >+ return !conv.error() && FormatParser(conv.format(), conv.args()) >+ .RunImpl(conv.is_positional()); >+ } >+ >+ public: >+ constexpr FormatParser(string_view format, ConvList args) >+ : format_(ConsumeNonPercent(format)), args_(args) {} >+ >+ // Runs the parser for `format` and `args`. >+ // It verifies that the format is valid and that all conversion specifiers >+ // match the arguments passed. >+ // In non-positional mode it also verfies that all arguments are consumed. >+ constexpr bool Run() const { >+ return RunImpl(!format_.empty() && IsPositional(ConsumeFront(format_))); >+ } >+ >+ private: >+ string_view format_; >+ // Current list of arguments. >+ // If we are not in positional mode we will consume from the front and will >+ // have to be empty in the end. >+ ConvList args_; >+}; >+ >+template <Conv... C> >+constexpr bool ValidFormatImpl(string_view format) { >+ return FormatParser(format, >+ {ConvListT<sizeof...(C)>{{C...}}.list, sizeof...(C)}) >+ .Run(); >+} >+ >+#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc >new file mode 100644 >index 00000000000..14d11ea8bd3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc >@@ -0,0 +1,150 @@ >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/strings/str_format.h" >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+std::string ConvToString(Conv conv) { >+ std::string out; >+#define CONV_SET_CASE(c) \ >+ if (Contains(conv, Conv::c)) out += #c; >+ ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, ) >+#undef CONV_SET_CASE >+ if (Contains(conv, Conv::star)) out += "*"; >+ return out; >+} >+ >+TEST(StrFormatChecker, ArgumentToConv) { >+ Conv conv = ArgumentToConv<std::string>(); >+ EXPECT_EQ(ConvToString(conv), "s"); >+ >+ conv = ArgumentToConv<const char*>(); >+ EXPECT_EQ(ConvToString(conv), "sp"); >+ >+ conv = ArgumentToConv<double>(); >+ EXPECT_EQ(ConvToString(conv), "fFeEgGaA"); >+ >+ conv = ArgumentToConv<int>(); >+ EXPECT_EQ(ConvToString(conv), "cdiouxXfFeEgGaA*"); >+ >+ conv = ArgumentToConv<std::string*>(); >+ EXPECT_EQ(ConvToString(conv), "p"); >+} >+ >+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+struct Case { >+ bool result; >+ const char* format; >+}; >+ >+template <typename... Args> >+constexpr Case ValidFormat(const char* format) { >+ return {ValidFormatImpl<ArgumentToConv<Args>()...>(format), format}; >+} >+ >+TEST(StrFormatChecker, ValidFormat) { >+ // We want to make sure these expressions are constexpr and they have the >+ // expected value. >+ // If they are not constexpr the attribute will just ignore them and not give >+ // a compile time error. >+ enum e {}; >+ enum class e2 {}; >+ constexpr Case trues[] = { >+ ValidFormat<>("abc"), // >+ >+ ValidFormat<e>("%d"), // >+ ValidFormat<e2>("%d"), // >+ ValidFormat<int>("%% %d"), // >+ ValidFormat<int>("%ld"), // >+ ValidFormat<int>("%lld"), // >+ ValidFormat<std::string>("%s"), // >+ ValidFormat<std::string>("%10s"), // >+ ValidFormat<int>("%.10x"), // >+ ValidFormat<int, int>("%*.3x"), // >+ ValidFormat<int>("%1.d"), // >+ ValidFormat<int>("%.d"), // >+ ValidFormat<int, double>("%d %g"), // >+ ValidFormat<int, std::string>("%*s"), // >+ ValidFormat<int, double>("%.*f"), // >+ ValidFormat<void (*)(), volatile int*>("%p %p"), // >+ ValidFormat<string_view, const char*, double, void*>( >+ "string_view=%s const char*=%s double=%f void*=%p)"), >+ >+ ValidFormat<int>("%% %1$d"), // >+ ValidFormat<int>("%1$ld"), // >+ ValidFormat<int>("%1$lld"), // >+ ValidFormat<std::string>("%1$s"), // >+ ValidFormat<std::string>("%1$10s"), // >+ ValidFormat<int>("%1$.10x"), // >+ ValidFormat<int>("%1$*1$.*1$d"), // >+ ValidFormat<int, int>("%1$*2$.3x"), // >+ ValidFormat<int>("%1$1.d"), // >+ ValidFormat<int>("%1$.d"), // >+ ValidFormat<double, int>("%2$d %1$g"), // >+ ValidFormat<int, std::string>("%2$*1$s"), // >+ ValidFormat<int, double>("%2$.*1$f"), // >+ ValidFormat<void*, string_view, const char*, double>( >+ "string_view=%2$s const char*=%3$s double=%4$f void*=%1$p " >+ "repeat=%3$s)")}; >+ >+ for (Case c : trues) { >+ EXPECT_TRUE(c.result) << c.format; >+ } >+ >+ constexpr Case falses[] = { >+ ValidFormat<int>(""), // >+ >+ ValidFormat<e>("%s"), // >+ ValidFormat<e2>("%s"), // >+ ValidFormat<>("%s"), // >+ ValidFormat<>("%r"), // >+ ValidFormat<int>("%s"), // >+ ValidFormat<int>("%.1.d"), // >+ ValidFormat<int>("%*1d"), // >+ ValidFormat<int>("%1-d"), // >+ ValidFormat<std::string, int>("%*s"), // >+ ValidFormat<int>("%*d"), // >+ ValidFormat<std::string>("%p"), // >+ ValidFormat<int (*)(int)>("%d"), // >+ >+ ValidFormat<>("%3$d"), // >+ ValidFormat<>("%1$r"), // >+ ValidFormat<int>("%1$s"), // >+ ValidFormat<int>("%1$.1.d"), // >+ ValidFormat<int>("%1$*2$1d"), // >+ ValidFormat<int>("%1$1-d"), // >+ ValidFormat<std::string, int>("%2$*1$s"), // >+ ValidFormat<std::string>("%1$p"), >+ >+ ValidFormat<int, int>("%d %2$d"), // >+ }; >+ >+ for (Case c : falses) { >+ EXPECT_FALSE(c.result) << c.format; >+ } >+} >+ >+TEST(StrFormatChecker, LongFormat) { >+#define CHARS_X_40 "1234567890123456789012345678901234567890" >+#define CHARS_X_400 \ >+ CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 CHARS_X_40 \ >+ CHARS_X_40 CHARS_X_40 CHARS_X_40 >+#define CHARS_X_4000 \ >+ CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 \ >+ CHARS_X_400 CHARS_X_400 CHARS_X_400 CHARS_X_400 >+ constexpr char long_format[] = >+ CHARS_X_4000 "%d" CHARS_X_4000 "%s" CHARS_X_4000; >+ constexpr bool is_valid = ValidFormat<int, std::string>(long_format).result; >+ EXPECT_TRUE(is_valid); >+} >+ >+#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ >+} // namespace >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc >new file mode 100644 >index 00000000000..32f8a0f9ad1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc >@@ -0,0 +1,575 @@ >+#include <errno.h> >+#include <stdarg.h> >+#include <stdio.h> >+#include <cmath> >+#include <string> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/internal/str_format/bind.h" >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+template <typename T, size_t N> >+size_t ArraySize(T (&)[N]) { >+ return N; >+} >+ >+std::string LengthModFor(float) { return ""; } >+std::string LengthModFor(double) { return ""; } >+std::string LengthModFor(long double) { return "L"; } >+std::string LengthModFor(char) { return "hh"; } >+std::string LengthModFor(signed char) { return "hh"; } >+std::string LengthModFor(unsigned char) { return "hh"; } >+std::string LengthModFor(short) { return "h"; } // NOLINT >+std::string LengthModFor(unsigned short) { return "h"; } // NOLINT >+std::string LengthModFor(int) { return ""; } >+std::string LengthModFor(unsigned) { return ""; } >+std::string LengthModFor(long) { return "l"; } // NOLINT >+std::string LengthModFor(unsigned long) { return "l"; } // NOLINT >+std::string LengthModFor(long long) { return "ll"; } // NOLINT >+std::string LengthModFor(unsigned long long) { return "ll"; } // NOLINT >+ >+std::string EscCharImpl(int v) { >+ if (isprint(v)) return std::string(1, static_cast<char>(v)); >+ char buf[64]; >+ int n = snprintf(buf, sizeof(buf), "\\%#.2x", >+ static_cast<unsigned>(v & 0xff)); >+ assert(n > 0 && n < sizeof(buf)); >+ return std::string(buf, n); >+} >+ >+std::string Esc(char v) { return EscCharImpl(v); } >+std::string Esc(signed char v) { return EscCharImpl(v); } >+std::string Esc(unsigned char v) { return EscCharImpl(v); } >+ >+template <typename T> >+std::string Esc(const T &v) { >+ std::ostringstream oss; >+ oss << v; >+ return oss.str(); >+} >+ >+void StrAppend(std::string *dst, const char *format, va_list ap) { >+ // First try with a small fixed size buffer >+ static const int kSpaceLength = 1024; >+ char space[kSpaceLength]; >+ >+ // It's possible for methods that use a va_list to invalidate >+ // the data in it upon use. The fix is to make a copy >+ // of the structure before using it and use that copy instead. >+ va_list backup_ap; >+ va_copy(backup_ap, ap); >+ int result = vsnprintf(space, kSpaceLength, format, backup_ap); >+ va_end(backup_ap); >+ if (result < kSpaceLength) { >+ if (result >= 0) { >+ // Normal case -- everything fit. >+ dst->append(space, result); >+ return; >+ } >+ if (result < 0) { >+ // Just an error. >+ return; >+ } >+ } >+ >+ // Increase the buffer size to the size requested by vsnprintf, >+ // plus one for the closing \0. >+ int length = result + 1; >+ char *buf = new char[length]; >+ >+ // Restore the va_list before we use it again >+ va_copy(backup_ap, ap); >+ result = vsnprintf(buf, length, format, backup_ap); >+ va_end(backup_ap); >+ >+ if (result >= 0 && result < length) { >+ // It fit >+ dst->append(buf, result); >+ } >+ delete[] buf; >+} >+ >+std::string StrPrint(const char *format, ...) { >+ va_list ap; >+ va_start(ap, format); >+ std::string result; >+ StrAppend(&result, format, ap); >+ va_end(ap); >+ return result; >+} >+ >+class FormatConvertTest : public ::testing::Test { }; >+ >+template <typename T> >+void TestStringConvert(const T& str) { >+ const FormatArgImpl args[] = {FormatArgImpl(str)}; >+ struct Expectation { >+ const char *out; >+ const char *fmt; >+ }; >+ const Expectation kExpect[] = { >+ {"hello", "%1$s" }, >+ {"", "%1$.s" }, >+ {"", "%1$.0s" }, >+ {"h", "%1$.1s" }, >+ {"he", "%1$.2s" }, >+ {"hello", "%1$.10s" }, >+ {" hello", "%1$6s" }, >+ {" he", "%1$5.2s" }, >+ {"he ", "%1$-5.2s" }, >+ {"hello ", "%1$-6.10s" }, >+ }; >+ for (const Expectation &e : kExpect) { >+ UntypedFormatSpecImpl format(e.fmt); >+ EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))); >+ } >+} >+ >+TEST_F(FormatConvertTest, BasicString) { >+ TestStringConvert("hello"); // As char array. >+ TestStringConvert(static_cast<const char*>("hello")); >+ TestStringConvert(std::string("hello")); >+ TestStringConvert(string_view("hello")); >+} >+ >+TEST_F(FormatConvertTest, NullString) { >+ const char* p = nullptr; >+ UntypedFormatSpecImpl format("%s"); >+ EXPECT_EQ("", FormatPack(format, {FormatArgImpl(p)})); >+} >+ >+TEST_F(FormatConvertTest, StringPrecision) { >+ // We cap at the precision. >+ char c = 'a'; >+ const char* p = &c; >+ UntypedFormatSpecImpl format("%.1s"); >+ EXPECT_EQ("a", FormatPack(format, {FormatArgImpl(p)})); >+ >+ // We cap at the nul terminator. >+ p = "ABC"; >+ UntypedFormatSpecImpl format2("%.10s"); >+ EXPECT_EQ("ABC", FormatPack(format2, {FormatArgImpl(p)})); >+} >+ >+TEST_F(FormatConvertTest, Pointer) { >+#if _MSC_VER >+ // MSVC's printf implementation prints pointers differently. We can't easily >+ // compare our implementation to theirs. >+ return; >+#endif >+ static int x = 0; >+ const int *xp = &x; >+ char c = 'h'; >+ char *mcp = &c; >+ const char *cp = "hi"; >+ const char *cnil = nullptr; >+ const int *inil = nullptr; >+ using VoidF = void (*)(); >+ VoidF fp = [] {}, fnil = nullptr; >+ volatile char vc; >+ volatile char* vcp = &vc; >+ volatile char* vcnil = nullptr; >+ const FormatArgImpl args[] = { >+ FormatArgImpl(xp), FormatArgImpl(cp), FormatArgImpl(inil), >+ FormatArgImpl(cnil), FormatArgImpl(mcp), FormatArgImpl(fp), >+ FormatArgImpl(fnil), FormatArgImpl(vcp), FormatArgImpl(vcnil), >+ }; >+ struct Expectation { >+ std::string out; >+ const char *fmt; >+ }; >+ const Expectation kExpect[] = { >+ {StrPrint("%p", &x), "%p"}, >+ {StrPrint("%20p", &x), "%20p"}, >+ {StrPrint("%.1p", &x), "%.1p"}, >+ {StrPrint("%.20p", &x), "%.20p"}, >+ {StrPrint("%30.20p", &x), "%30.20p"}, >+ >+ {StrPrint("%-p", &x), "%-p"}, >+ {StrPrint("%-20p", &x), "%-20p"}, >+ {StrPrint("%-.1p", &x), "%-.1p"}, >+ {StrPrint("%.20p", &x), "%.20p"}, >+ {StrPrint("%-30.20p", &x), "%-30.20p"}, >+ >+ {StrPrint("%p", cp), "%2$p"}, // const char* >+ {"(nil)", "%3$p"}, // null const char * >+ {"(nil)", "%4$p"}, // null const int * >+ {StrPrint("%p", mcp), "%5$p"}, // nonconst char* >+ >+ {StrPrint("%p", fp), "%6$p"}, // function pointer >+ {StrPrint("%p", vcp), "%8$p"}, // function pointer >+ >+#ifndef __APPLE__ >+ // Apple's printf differs here (0x0 vs. nil) >+ {StrPrint("%p", fnil), "%7$p"}, // null function pointer >+ {StrPrint("%p", vcnil), "%9$p"}, // null function pointer >+#endif >+ }; >+ for (const Expectation &e : kExpect) { >+ UntypedFormatSpecImpl format(e.fmt); >+ EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))) << e.fmt; >+ } >+} >+ >+struct Cardinal { >+ enum Pos { k1 = 1, k2 = 2, k3 = 3 }; >+ enum Neg { kM1 = -1, kM2 = -2, kM3 = -3 }; >+}; >+ >+TEST_F(FormatConvertTest, Enum) { >+ const Cardinal::Pos k3 = Cardinal::k3; >+ const Cardinal::Neg km3 = Cardinal::kM3; >+ const FormatArgImpl args[] = {FormatArgImpl(k3), FormatArgImpl(km3)}; >+ UntypedFormatSpecImpl format("%1$d"); >+ UntypedFormatSpecImpl format2("%2$d"); >+ EXPECT_EQ("3", FormatPack(format, absl::MakeSpan(args))); >+ EXPECT_EQ("-3", FormatPack(format2, absl::MakeSpan(args))); >+} >+ >+template <typename T> >+class TypedFormatConvertTest : public FormatConvertTest { }; >+ >+TYPED_TEST_CASE_P(TypedFormatConvertTest); >+ >+std::vector<std::string> AllFlagCombinations() { >+ const char kFlags[] = {'-', '#', '0', '+', ' '}; >+ std::vector<std::string> result; >+ for (size_t fsi = 0; fsi < (1ull << ArraySize(kFlags)); ++fsi) { >+ std::string flag_set; >+ for (size_t fi = 0; fi < ArraySize(kFlags); ++fi) >+ if (fsi & (1ull << fi)) >+ flag_set += kFlags[fi]; >+ result.push_back(flag_set); >+ } >+ return result; >+} >+ >+TYPED_TEST_P(TypedFormatConvertTest, AllIntsWithFlags) { >+ typedef TypeParam T; >+ typedef typename std::make_unsigned<T>::type UnsignedT; >+ using remove_volatile_t = typename std::remove_volatile<T>::type; >+ const T kMin = std::numeric_limits<remove_volatile_t>::min(); >+ const T kMax = std::numeric_limits<remove_volatile_t>::max(); >+ const T kVals[] = { >+ remove_volatile_t(1), >+ remove_volatile_t(2), >+ remove_volatile_t(3), >+ remove_volatile_t(123), >+ remove_volatile_t(-1), >+ remove_volatile_t(-2), >+ remove_volatile_t(-3), >+ remove_volatile_t(-123), >+ remove_volatile_t(0), >+ kMax - remove_volatile_t(1), >+ kMax, >+ kMin + remove_volatile_t(1), >+ kMin, >+ }; >+ const char kConvChars[] = {'d', 'i', 'u', 'o', 'x', 'X'}; >+ const std::string kWid[] = {"", "4", "10"}; >+ const std::string kPrec[] = {"", ".", ".0", ".4", ".10"}; >+ >+ const std::vector<std::string> flag_sets = AllFlagCombinations(); >+ >+ for (size_t vi = 0; vi < ArraySize(kVals); ++vi) { >+ const T val = kVals[vi]; >+ SCOPED_TRACE(Esc(val)); >+ const FormatArgImpl args[] = {FormatArgImpl(val)}; >+ for (size_t ci = 0; ci < ArraySize(kConvChars); ++ci) { >+ const char conv_char = kConvChars[ci]; >+ for (size_t fsi = 0; fsi < flag_sets.size(); ++fsi) { >+ const std::string &flag_set = flag_sets[fsi]; >+ for (size_t wi = 0; wi < ArraySize(kWid); ++wi) { >+ const std::string &wid = kWid[wi]; >+ for (size_t pi = 0; pi < ArraySize(kPrec); ++pi) { >+ const std::string &prec = kPrec[pi]; >+ >+ const bool is_signed_conv = (conv_char == 'd' || conv_char == 'i'); >+ const bool is_unsigned_to_signed = >+ !std::is_signed<T>::value && is_signed_conv; >+ // Don't consider sign-related flags '+' and ' ' when doing >+ // unsigned to signed conversions. >+ if (is_unsigned_to_signed && >+ flag_set.find_first_of("+ ") != std::string::npos) { >+ continue; >+ } >+ >+ std::string new_fmt("%"); >+ new_fmt += flag_set; >+ new_fmt += wid; >+ new_fmt += prec; >+ // old and new always agree up to here. >+ std::string old_fmt = new_fmt; >+ new_fmt += conv_char; >+ std::string old_result; >+ if (is_unsigned_to_signed) { >+ // don't expect agreement on unsigned formatted as signed, >+ // as printf can't do that conversion properly. For those >+ // cases, we do expect agreement with printf with a "%u" >+ // and the unsigned equivalent of 'val'. >+ UnsignedT uval = val; >+ old_fmt += LengthModFor(uval); >+ old_fmt += "u"; >+ old_result = StrPrint(old_fmt.c_str(), uval); >+ } else { >+ old_fmt += LengthModFor(val); >+ old_fmt += conv_char; >+ old_result = StrPrint(old_fmt.c_str(), val); >+ } >+ >+ SCOPED_TRACE(std::string() + " old_fmt: \"" + old_fmt + >+ "\"'" >+ " new_fmt: \"" + >+ new_fmt + "\""); >+ UntypedFormatSpecImpl format(new_fmt); >+ EXPECT_EQ(old_result, FormatPack(format, absl::MakeSpan(args))); >+ } >+ } >+ } >+ } >+ } >+} >+ >+TYPED_TEST_P(TypedFormatConvertTest, Char) { >+ typedef TypeParam T; >+ using remove_volatile_t = typename std::remove_volatile<T>::type; >+ static const T kMin = std::numeric_limits<remove_volatile_t>::min(); >+ static const T kMax = std::numeric_limits<remove_volatile_t>::max(); >+ T kVals[] = { >+ remove_volatile_t(1), remove_volatile_t(2), remove_volatile_t(10), >+ remove_volatile_t(-1), remove_volatile_t(-2), remove_volatile_t(-10), >+ remove_volatile_t(0), >+ kMin + remove_volatile_t(1), kMin, >+ kMax - remove_volatile_t(1), kMax >+ }; >+ for (const T &c : kVals) { >+ const FormatArgImpl args[] = {FormatArgImpl(c)}; >+ UntypedFormatSpecImpl format("%c"); >+ EXPECT_EQ(StrPrint("%c", c), FormatPack(format, absl::MakeSpan(args))); >+ } >+} >+ >+REGISTER_TYPED_TEST_CASE_P(TypedFormatConvertTest, AllIntsWithFlags, Char); >+ >+typedef ::testing::Types< >+ int, unsigned, volatile int, >+ short, unsigned short, >+ long, unsigned long, >+ long long, unsigned long long, >+ signed char, unsigned char, char> >+ AllIntTypes; >+INSTANTIATE_TYPED_TEST_CASE_P(TypedFormatConvertTestWithAllIntTypes, >+ TypedFormatConvertTest, AllIntTypes); >+TEST_F(FormatConvertTest, Uint128) { >+ absl::uint128 v = static_cast<absl::uint128>(0x1234567890abcdef) * 1979; >+ absl::uint128 max = absl::Uint128Max(); >+ const FormatArgImpl args[] = {FormatArgImpl(v), FormatArgImpl(max)}; >+ >+ struct Case { >+ const char* format; >+ const char* expected; >+ } cases[] = { >+ {"%1$d", "2595989796776606496405"}, >+ {"%1$30d", " 2595989796776606496405"}, >+ {"%1$-30d", "2595989796776606496405 "}, >+ {"%1$u", "2595989796776606496405"}, >+ {"%1$x", "8cba9876066020f695"}, >+ {"%2$d", "340282366920938463463374607431768211455"}, >+ {"%2$u", "340282366920938463463374607431768211455"}, >+ {"%2$x", "ffffffffffffffffffffffffffffffff"}, >+ }; >+ >+ for (auto c : cases) { >+ UntypedFormatSpecImpl format(c.format); >+ EXPECT_EQ(c.expected, FormatPack(format, absl::MakeSpan(args))); >+ } >+} >+ >+TEST_F(FormatConvertTest, Float) { >+#if _MSC_VER >+ // MSVC has a different rounding policy than us so we can't test our >+ // implementation against the native one there. >+ return; >+#endif // _MSC_VER >+ >+ const char *const kFormats[] = { >+ "%", "%.3", "%8.5", "%9", "%.60", "%.30", "%03", "%+", >+ "% ", "%-10", "%#15.3", "%#.0", "%.0", "%1$*2$", "%1$.*2$"}; >+ >+ std::vector<double> doubles = {0.0, >+ -0.0, >+ .99999999999999, >+ 99999999999999., >+ std::numeric_limits<double>::max(), >+ -std::numeric_limits<double>::max(), >+ std::numeric_limits<double>::min(), >+ -std::numeric_limits<double>::min(), >+ std::numeric_limits<double>::lowest(), >+ -std::numeric_limits<double>::lowest(), >+ std::numeric_limits<double>::epsilon(), >+ std::numeric_limits<double>::epsilon() + 1, >+ std::numeric_limits<double>::infinity(), >+ -std::numeric_limits<double>::infinity()}; >+ >+#ifndef __APPLE__ >+ // Apple formats NaN differently (+nan) vs. (nan) >+ doubles.push_back(std::nan("")); >+#endif >+ >+ // Some regression tests. >+ doubles.push_back(0.99999999999999989); >+ >+ if (std::numeric_limits<double>::has_denorm != std::denorm_absent) { >+ doubles.push_back(std::numeric_limits<double>::denorm_min()); >+ doubles.push_back(-std::numeric_limits<double>::denorm_min()); >+ } >+ >+ for (double base : >+ {1., 12., 123., 1234., 12345., 123456., 1234567., 12345678., 123456789., >+ 1234567890., 12345678901., 123456789012., 1234567890123.}) { >+ for (int exp = -123; exp <= 123; ++exp) { >+ for (int sign : {1, -1}) { >+ doubles.push_back(sign * std::ldexp(base, exp)); >+ } >+ } >+ } >+ >+ for (const char *fmt : kFormats) { >+ for (char f : {'f', 'F', // >+ 'g', 'G', // >+ 'a', 'A', // >+ 'e', 'E'}) { >+ std::string fmt_str = std::string(fmt) + f; >+ for (double d : doubles) { >+ int i = -10; >+ FormatArgImpl args[2] = {FormatArgImpl(d), FormatArgImpl(i)}; >+ UntypedFormatSpecImpl format(fmt_str); >+ // We use ASSERT_EQ here because failures are usually correlated and a >+ // bug would print way too many failed expectations causing the test to >+ // time out. >+ ASSERT_EQ(StrPrint(fmt_str.c_str(), d, i), >+ FormatPack(format, absl::MakeSpan(args))) >+ << fmt_str << " " << StrPrint("%.18g", d) << " " >+ << StrPrint("%.999f", d); >+ } >+ } >+ } >+} >+ >+TEST_F(FormatConvertTest, LongDouble) { >+ const char *const kFormats[] = {"%", "%.3", "%8.5", "%9", >+ "%.60", "%+", "% ", "%-10"}; >+ >+ // This value is not representable in double, but it is in long double that >+ // uses the extended format. >+ // This is to verify that we are not truncating the value mistakenly through a >+ // double. >+ long double very_precise = 10000000000000000.25L; >+ >+ std::vector<long double> doubles = { >+ 0.0, >+ -0.0, >+ very_precise, >+ 1 / very_precise, >+ std::numeric_limits<long double>::max(), >+ -std::numeric_limits<long double>::max(), >+ std::numeric_limits<long double>::min(), >+ -std::numeric_limits<long double>::min(), >+ std::numeric_limits<long double>::infinity(), >+ -std::numeric_limits<long double>::infinity()}; >+ >+ for (const char *fmt : kFormats) { >+ for (char f : {'f', 'F', // >+ 'g', 'G', // >+ 'a', 'A', // >+ 'e', 'E'}) { >+ std::string fmt_str = std::string(fmt) + 'L' + f; >+ for (auto d : doubles) { >+ FormatArgImpl arg(d); >+ UntypedFormatSpecImpl format(fmt_str); >+ // We use ASSERT_EQ here because failures are usually correlated and a >+ // bug would print way too many failed expectations causing the test to >+ // time out. >+ ASSERT_EQ(StrPrint(fmt_str.c_str(), d), >+ FormatPack(format, {&arg, 1})) >+ << fmt_str << " " << StrPrint("%.18Lg", d) << " " >+ << StrPrint("%.999Lf", d); >+ } >+ } >+ } >+} >+ >+TEST_F(FormatConvertTest, IntAsFloat) { >+ const int kMin = std::numeric_limits<int>::min(); >+ const int kMax = std::numeric_limits<int>::max(); >+ const int ia[] = { >+ 1, 2, 3, 123, >+ -1, -2, -3, -123, >+ 0, kMax - 1, kMax, kMin + 1, kMin }; >+ for (const int fx : ia) { >+ SCOPED_TRACE(fx); >+ const FormatArgImpl args[] = {FormatArgImpl(fx)}; >+ struct Expectation { >+ int line; >+ std::string out; >+ const char *fmt; >+ }; >+ const double dx = static_cast<double>(fx); >+ const Expectation kExpect[] = { >+ { __LINE__, StrPrint("%f", dx), "%f" }, >+ { __LINE__, StrPrint("%12f", dx), "%12f" }, >+ { __LINE__, StrPrint("%.12f", dx), "%.12f" }, >+ { __LINE__, StrPrint("%12a", dx), "%12a" }, >+ { __LINE__, StrPrint("%.12a", dx), "%.12a" }, >+ }; >+ for (const Expectation &e : kExpect) { >+ SCOPED_TRACE(e.line); >+ SCOPED_TRACE(e.fmt); >+ UntypedFormatSpecImpl format(e.fmt); >+ EXPECT_EQ(e.out, FormatPack(format, absl::MakeSpan(args))); >+ } >+ } >+} >+ >+template <typename T> >+bool FormatFails(const char* test_format, T value) { >+ std::string format_string = std::string("<<") + test_format + ">>"; >+ UntypedFormatSpecImpl format(format_string); >+ >+ int one = 1; >+ const FormatArgImpl args[] = {FormatArgImpl(value), FormatArgImpl(one)}; >+ EXPECT_EQ(FormatPack(format, absl::MakeSpan(args)), "") >+ << "format=" << test_format << " value=" << value; >+ return FormatPack(format, absl::MakeSpan(args)).empty(); >+} >+ >+TEST_F(FormatConvertTest, ExpectedFailures) { >+ // Int input >+ EXPECT_TRUE(FormatFails("%p", 1)); >+ EXPECT_TRUE(FormatFails("%s", 1)); >+ EXPECT_TRUE(FormatFails("%n", 1)); >+ >+ // Double input >+ EXPECT_TRUE(FormatFails("%p", 1.)); >+ EXPECT_TRUE(FormatFails("%s", 1.)); >+ EXPECT_TRUE(FormatFails("%n", 1.)); >+ EXPECT_TRUE(FormatFails("%c", 1.)); >+ EXPECT_TRUE(FormatFails("%d", 1.)); >+ EXPECT_TRUE(FormatFails("%x", 1.)); >+ EXPECT_TRUE(FormatFails("%*d", 1.)); >+ >+ // String input >+ EXPECT_TRUE(FormatFails("%n", "")); >+ EXPECT_TRUE(FormatFails("%c", "")); >+ EXPECT_TRUE(FormatFails("%d", "")); >+ EXPECT_TRUE(FormatFails("%x", "")); >+ EXPECT_TRUE(FormatFails("%f", "")); >+ EXPECT_TRUE(FormatFails("%*d", "")); >+} >+ >+} // namespace >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.cc >new file mode 100644 >index 00000000000..c2174703c3e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.cc >@@ -0,0 +1,84 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/str_format/extension.h" >+ >+#include <errno.h> >+#include <algorithm> >+#include <string> >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+// clang-format off >+#define ABSL_LENGTH_MODS_EXPAND_ \ >+ X_VAL(h) X_SEP \ >+ X_VAL(hh) X_SEP \ >+ X_VAL(l) X_SEP \ >+ X_VAL(ll) X_SEP \ >+ X_VAL(L) X_SEP \ >+ X_VAL(j) X_SEP \ >+ X_VAL(z) X_SEP \ >+ X_VAL(t) X_SEP \ >+ X_VAL(q) >+// clang-format on >+} // namespace >+ >+const LengthMod::Spec LengthMod::kSpecs[] = { >+#define X_VAL(id) { LengthMod::id, #id, strlen(#id) } >+#define X_SEP , >+ ABSL_LENGTH_MODS_EXPAND_, {LengthMod::none, "", 0} >+#undef X_VAL >+#undef X_SEP >+}; >+ >+const ConversionChar::Spec ConversionChar::kSpecs[] = { >+#define X_VAL(id) { ConversionChar::id, #id[0] } >+#define X_SEP , >+ ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP), >+ {ConversionChar::none, '\0'}, >+#undef X_VAL >+#undef X_SEP >+}; >+ >+std::string Flags::ToString() const { >+ std::string s; >+ s.append(left ? "-" : ""); >+ s.append(show_pos ? "+" : ""); >+ s.append(sign_col ? " " : ""); >+ s.append(alt ? "#" : ""); >+ s.append(zero ? "0" : ""); >+ return s; >+} >+ >+const size_t LengthMod::kNumValues; >+ >+const size_t ConversionChar::kNumValues; >+ >+bool FormatSinkImpl::PutPaddedString(string_view v, int w, int p, bool l) { >+ size_t space_remaining = 0; >+ if (w >= 0) space_remaining = w; >+ size_t n = v.size(); >+ if (p >= 0) n = std::min(n, static_cast<size_t>(p)); >+ string_view shown(v.data(), n); >+ space_remaining = Excess(shown.size(), space_remaining); >+ if (!l) Append(space_remaining, ' '); >+ Append(shown); >+ if (l) Append(space_remaining, ' '); >+ return true; >+} >+ >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h >new file mode 100644 >index 00000000000..810330b9d71 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension.h >@@ -0,0 +1,406 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_ >+ >+#include <limits.h> >+#include <cstring> >+#include <ostream> >+ >+#include "absl/base/port.h" >+#include "absl/strings/internal/str_format/output.h" >+#include "absl/strings/string_view.h" >+ >+class Cord; >+ >+namespace absl { >+ >+namespace str_format_internal { >+ >+class FormatRawSinkImpl { >+ public: >+ // Implicitly convert from any type that provides the hook function as >+ // described above. >+ template <typename T, decltype(str_format_internal::InvokeFlush( >+ std::declval<T*>(), string_view()))* = nullptr> >+ FormatRawSinkImpl(T* raw) // NOLINT >+ : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {} >+ >+ void Write(string_view s) { write_(sink_, s); } >+ >+ template <typename T> >+ static FormatRawSinkImpl Extract(T s) { >+ return s.sink_; >+ } >+ >+ private: >+ template <typename T> >+ static void Flush(void* r, string_view s) { >+ str_format_internal::InvokeFlush(static_cast<T*>(r), s); >+ } >+ >+ void* sink_; >+ void (*write_)(void*, string_view); >+}; >+ >+// An abstraction to which conversions write their std::string data. >+class FormatSinkImpl { >+ public: >+ explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {} >+ >+ ~FormatSinkImpl() { Flush(); } >+ >+ void Flush() { >+ raw_.Write(string_view(buf_, pos_ - buf_)); >+ pos_ = buf_; >+ } >+ >+ void Append(size_t n, char c) { >+ if (n == 0) return; >+ size_ += n; >+ auto raw_append = [&](size_t count) { >+ memset(pos_, c, count); >+ pos_ += count; >+ }; >+ while (n > Avail()) { >+ n -= Avail(); >+ if (Avail() > 0) { >+ raw_append(Avail()); >+ } >+ Flush(); >+ } >+ raw_append(n); >+ } >+ >+ void Append(string_view v) { >+ size_t n = v.size(); >+ if (n == 0) return; >+ size_ += n; >+ if (n >= Avail()) { >+ Flush(); >+ raw_.Write(v); >+ return; >+ } >+ memcpy(pos_, v.data(), n); >+ pos_ += n; >+ } >+ >+ size_t size() const { return size_; } >+ >+ // Put 'v' to 'sink' with specified width, precision, and left flag. >+ bool PutPaddedString(string_view v, int w, int p, bool l); >+ >+ template <typename T> >+ T Wrap() { >+ return T(this); >+ } >+ >+ template <typename T> >+ static FormatSinkImpl* Extract(T* s) { >+ return s->sink_; >+ } >+ >+ private: >+ size_t Avail() const { return buf_ + sizeof(buf_) - pos_; } >+ >+ FormatRawSinkImpl raw_; >+ size_t size_ = 0; >+ char* pos_ = buf_; >+ char buf_[1024]; >+}; >+ >+struct Flags { >+ bool basic : 1; // fastest conversion: no flags, width, or precision >+ bool left : 1; // "-" >+ bool show_pos : 1; // "+" >+ bool sign_col : 1; // " " >+ bool alt : 1; // "#" >+ bool zero : 1; // "0" >+ std::string ToString() const; >+ friend std::ostream& operator<<(std::ostream& os, const Flags& v) { >+ return os << v.ToString(); >+ } >+}; >+ >+struct LengthMod { >+ public: >+ enum Id : uint8_t { >+ h, hh, l, ll, L, j, z, t, q, none >+ }; >+ static const size_t kNumValues = none + 1; >+ >+ LengthMod() : id_(none) {} >+ >+ // Index into the opaque array of LengthMod enums. >+ // Requires: i < kNumValues >+ static LengthMod FromIndex(size_t i) { >+ return LengthMod(kSpecs[i].value); >+ } >+ >+ static LengthMod FromId(Id id) { return LengthMod(id); } >+ >+ // The length modifier std::string associated with a specified LengthMod. >+ string_view name() const { >+ const Spec& spec = kSpecs[id_]; >+ return {spec.name, spec.name_length}; >+ } >+ >+ Id id() const { return id_; } >+ >+ friend bool operator==(const LengthMod& a, const LengthMod& b) { >+ return a.id() == b.id(); >+ } >+ friend bool operator!=(const LengthMod& a, const LengthMod& b) { >+ return !(a == b); >+ } >+ friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) { >+ return os << v.name(); >+ } >+ >+ private: >+ struct Spec { >+ Id value; >+ const char *name; >+ size_t name_length; >+ }; >+ static const Spec kSpecs[]; >+ >+ explicit LengthMod(Id id) : id_(id) {} >+ >+ Id id_; >+}; >+ >+// clang-format off >+#define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \ >+ /* text */ \ >+ X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \ >+ /* ints */ \ >+ X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \ >+ X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \ >+ /* floats */ \ >+ X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \ >+ X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \ >+ /* misc */ \ >+ X_VAL(n) X_SEP X_VAL(p) >+// clang-format on >+ >+struct ConversionChar { >+ public: >+ enum Id : uint8_t { >+ c, C, s, S, // text >+ d, i, o, u, x, X, // int >+ f, F, e, E, g, G, a, A, // float >+ n, p, // misc >+ none >+ }; >+ static const size_t kNumValues = none + 1; >+ >+ ConversionChar() : id_(none) {} >+ >+ public: >+ // Index into the opaque array of ConversionChar enums. >+ // Requires: i < kNumValues >+ static ConversionChar FromIndex(size_t i) { >+ return ConversionChar(kSpecs[i].value); >+ } >+ >+ static ConversionChar FromChar(char c) { >+ ConversionChar::Id out_id = ConversionChar::none; >+ switch (c) { >+#define X_VAL(id) \ >+ case #id[0]: \ >+ out_id = ConversionChar::id; \ >+ break; >+ ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, ) >+#undef X_VAL >+ default: >+ break; >+ } >+ return ConversionChar(out_id); >+ } >+ >+ static ConversionChar FromId(Id id) { return ConversionChar(id); } >+ Id id() const { return id_; } >+ >+ int radix() const { >+ switch (id()) { >+ case x: case X: case a: case A: case p: return 16; >+ case o: return 8; >+ default: return 10; >+ } >+ } >+ >+ bool upper() const { >+ switch (id()) { >+ case X: case F: case E: case G: case A: return true; >+ default: return false; >+ } >+ } >+ >+ bool is_signed() const { >+ switch (id()) { >+ case d: case i: return true; >+ default: return false; >+ } >+ } >+ >+ bool is_integral() const { >+ switch (id()) { >+ case d: case i: case u: case o: case x: case X: >+ return true; >+ default: return false; >+ } >+ } >+ >+ bool is_float() const { >+ switch (id()) { >+ case a: case e: case f: case g: case A: case E: case F: case G: >+ return true; >+ default: return false; >+ } >+ } >+ >+ bool IsValid() const { return id() != none; } >+ >+ // The associated char. >+ char Char() const { return kSpecs[id_].name; } >+ >+ friend bool operator==(const ConversionChar& a, const ConversionChar& b) { >+ return a.id() == b.id(); >+ } >+ friend bool operator!=(const ConversionChar& a, const ConversionChar& b) { >+ return !(a == b); >+ } >+ friend std::ostream& operator<<(std::ostream& os, const ConversionChar& v) { >+ char c = v.Char(); >+ if (!c) c = '?'; >+ return os << c; >+ } >+ >+ private: >+ struct Spec { >+ Id value; >+ char name; >+ }; >+ static const Spec kSpecs[]; >+ >+ explicit ConversionChar(Id id) : id_(id) {} >+ >+ Id id_; >+}; >+ >+class ConversionSpec { >+ public: >+ Flags flags() const { return flags_; } >+ LengthMod length_mod() const { return length_mod_; } >+ ConversionChar conv() const { return conv_; } >+ >+ // Returns the specified width. If width is unspecfied, it returns a negative >+ // value. >+ int width() const { return width_; } >+ // Returns the specified precision. If precision is unspecfied, it returns a >+ // negative value. >+ int precision() const { return precision_; } >+ >+ void set_flags(Flags f) { flags_ = f; } >+ void set_length_mod(LengthMod lm) { length_mod_ = lm; } >+ void set_conv(ConversionChar c) { conv_ = c; } >+ void set_width(int w) { width_ = w; } >+ void set_precision(int p) { precision_ = p; } >+ void set_left(bool b) { flags_.left = b; } >+ >+ private: >+ Flags flags_; >+ LengthMod length_mod_; >+ ConversionChar conv_; >+ int width_; >+ int precision_; >+}; >+ >+constexpr uint64_t ConversionCharToConvValue(char conv) { >+ return >+#define CONV_SET_CASE(c) \ >+ conv == #c[0] ? (uint64_t{1} << (1 + ConversionChar::Id::c)): >+ ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, ) >+#undef CONV_SET_CASE >+ conv == '*' >+ ? 1 >+ : 0; >+} >+ >+enum class Conv : uint64_t { >+#define CONV_SET_CASE(c) c = ConversionCharToConvValue(#c[0]), >+ ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, ) >+#undef CONV_SET_CASE >+ >+ // Used for width/precision '*' specification. >+ star = ConversionCharToConvValue('*'), >+ >+ // Some predefined values: >+ integral = d | i | u | o | x | X, >+ floating = a | e | f | g | A | E | F | G, >+ numeric = integral | floating, >+ string = s, // absl:ignore(std::string) >+ pointer = p >+}; >+ >+// Type safe OR operator. >+// We need this for two reasons: >+// 1. operator| on enums makes them decay to integers and the result is an >+// integer. We need the result to stay as an enum. >+// 2. We use "enum class" which would not work even if we accepted the decay. >+constexpr Conv operator|(Conv a, Conv b) { >+ return Conv(static_cast<uint64_t>(a) | static_cast<uint64_t>(b)); >+} >+ >+// Get a conversion with a single character in it. >+constexpr Conv ConversionCharToConv(char c) { >+ return Conv(ConversionCharToConvValue(c)); >+} >+ >+// Checks whether `c` exists in `set`. >+constexpr bool Contains(Conv set, char c) { >+ return (static_cast<uint64_t>(set) & ConversionCharToConvValue(c)) != 0; >+} >+ >+// Checks whether all the characters in `c` are contained in `set` >+constexpr bool Contains(Conv set, Conv c) { >+ return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) == >+ static_cast<uint64_t>(c); >+} >+ >+// Return type of the AbslFormatConvert() functions. >+// The Conv template parameter is used to inform the framework of what >+// conversion characters are supported by that AbslFormatConvert routine. >+template <Conv C> >+struct ConvertResult { >+ static constexpr Conv kConv = C; >+ bool value; >+}; >+template <Conv C> >+constexpr Conv ConvertResult<C>::kConv; >+ >+// Return capacity - used, clipped to a minimum of 0. >+inline size_t Excess(size_t used, size_t capacity) { >+ return used < capacity ? capacity - used : 0; >+} >+ >+} // namespace str_format_internal >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STR_FORMAT_EXTENSION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension_test.cc >new file mode 100644 >index 00000000000..224fc923d3e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/extension_test.cc >@@ -0,0 +1,65 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#include "absl/strings/internal/str_format/extension.h" >+ >+#include <random> >+#include <string> >+#include "absl/strings/str_format.h" >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+std::string MakeRandomString(size_t len) { >+ std::random_device rd; >+ std::mt19937 gen(rd()); >+ std::uniform_int_distribution<> dis('a', 'z'); >+ std::string s(len, '0'); >+ for (char& c : s) { >+ c = dis(gen); >+ } >+ return s; >+} >+ >+TEST(FormatExtensionTest, SinkAppendSubstring) { >+ for (size_t chunk_size : {1, 10, 100, 1000, 10000}) { >+ std::string expected, actual; >+ absl::str_format_internal::FormatSinkImpl sink(&actual); >+ for (size_t chunks = 0; chunks < 10; ++chunks) { >+ std::string rand = MakeRandomString(chunk_size); >+ expected += rand; >+ sink.Append(rand); >+ } >+ sink.Flush(); >+ EXPECT_EQ(actual, expected); >+ } >+} >+ >+TEST(FormatExtensionTest, SinkAppendChars) { >+ for (size_t chunk_size : {1, 10, 100, 1000, 10000}) { >+ std::string expected, actual; >+ absl::str_format_internal::FormatSinkImpl sink(&actual); >+ for (size_t chunks = 0; chunks < 10; ++chunks) { >+ std::string rand = MakeRandomString(1); >+ expected.append(chunk_size, rand[0]); >+ sink.Append(chunk_size, rand[0]); >+ } >+ sink.Flush(); >+ EXPECT_EQ(actual, expected); >+ } >+} >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc >new file mode 100644 >index 00000000000..6176db9cb5a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc >@@ -0,0 +1,483 @@ >+#include "absl/strings/internal/str_format/float_conversion.h" >+ >+#include <string.h> >+#include <algorithm> >+#include <cassert> >+#include <cmath> >+#include <string> >+ >+namespace absl { >+namespace str_format_internal { >+ >+namespace { >+ >+char *CopyStringTo(string_view v, char *out) { >+ std::memcpy(out, v.data(), v.size()); >+ return out + v.size(); >+} >+ >+template <typename Float> >+bool FallbackToSnprintf(const Float v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ int w = conv.width() >= 0 ? conv.width() : 0; >+ int p = conv.precision() >= 0 ? conv.precision() : -1; >+ char fmt[32]; >+ { >+ char *fp = fmt; >+ *fp++ = '%'; >+ fp = CopyStringTo(conv.flags().ToString(), fp); >+ fp = CopyStringTo("*.*", fp); >+ if (std::is_same<long double, Float>()) { >+ *fp++ = 'L'; >+ } >+ *fp++ = conv.conv().Char(); >+ *fp = 0; >+ assert(fp < fmt + sizeof(fmt)); >+ } >+ std::string space(512, '\0'); >+ string_view result; >+ while (true) { >+ int n = snprintf(&space[0], space.size(), fmt, w, p, v); >+ if (n < 0) return false; >+ if (static_cast<size_t>(n) < space.size()) { >+ result = string_view(space.data(), n); >+ break; >+ } >+ space.resize(n + 1); >+ } >+ sink->Append(result); >+ return true; >+} >+ >+// 128-bits in decimal: ceil(128*log(2)/log(10)) >+// or std::numeric_limits<__uint128_t>::digits10 >+constexpr int kMaxFixedPrecision = 39; >+ >+constexpr int kBufferLength = /*sign*/ 1 + >+ /*integer*/ kMaxFixedPrecision + >+ /*point*/ 1 + >+ /*fraction*/ kMaxFixedPrecision + >+ /*exponent e+123*/ 5; >+ >+struct Buffer { >+ void push_front(char c) { >+ assert(begin > data); >+ *--begin = c; >+ } >+ void push_back(char c) { >+ assert(end < data + sizeof(data)); >+ *end++ = c; >+ } >+ void pop_back() { >+ assert(begin < end); >+ --end; >+ } >+ >+ char &back() { >+ assert(begin < end); >+ return end[-1]; >+ } >+ >+ char last_digit() const { return end[-1] == '.' ? end[-2] : end[-1]; } >+ >+ int size() const { return static_cast<int>(end - begin); } >+ >+ char data[kBufferLength]; >+ char *begin; >+ char *end; >+}; >+ >+enum class FormatStyle { Fixed, Precision }; >+ >+// If the value is Inf or Nan, print it and return true. >+// Otherwise, return false. >+template <typename Float> >+bool ConvertNonNumericFloats(char sign_char, Float v, >+ const ConversionSpec &conv, FormatSinkImpl *sink) { >+ char text[4], *ptr = text; >+ if (sign_char) *ptr++ = sign_char; >+ if (std::isnan(v)) { >+ ptr = std::copy_n(conv.conv().upper() ? "NAN" : "nan", 3, ptr); >+ } else if (std::isinf(v)) { >+ ptr = std::copy_n(conv.conv().upper() ? "INF" : "inf", 3, ptr); >+ } else { >+ return false; >+ } >+ >+ return sink->PutPaddedString(string_view(text, ptr - text), conv.width(), -1, >+ conv.flags().left); >+} >+ >+// Round up the last digit of the value. >+// It will carry over and potentially overflow. 'exp' will be adjusted in that >+// case. >+template <FormatStyle mode> >+void RoundUp(Buffer *buffer, int *exp) { >+ char *p = &buffer->back(); >+ while (p >= buffer->begin && (*p == '9' || *p == '.')) { >+ if (*p == '9') *p = '0'; >+ --p; >+ } >+ >+ if (p < buffer->begin) { >+ *p = '1'; >+ buffer->begin = p; >+ if (mode == FormatStyle::Precision) { >+ std::swap(p[1], p[2]); // move the . >+ ++*exp; >+ buffer->pop_back(); >+ } >+ } else { >+ ++*p; >+ } >+} >+ >+void PrintExponent(int exp, char e, Buffer *out) { >+ out->push_back(e); >+ if (exp < 0) { >+ out->push_back('-'); >+ exp = -exp; >+ } else { >+ out->push_back('+'); >+ } >+ // Exponent digits. >+ if (exp > 99) { >+ out->push_back(exp / 100 + '0'); >+ out->push_back(exp / 10 % 10 + '0'); >+ out->push_back(exp % 10 + '0'); >+ } else { >+ out->push_back(exp / 10 + '0'); >+ out->push_back(exp % 10 + '0'); >+ } >+} >+ >+template <typename Float, typename Int> >+constexpr bool CanFitMantissa() { >+ return >+#if defined(__clang__) && !defined(__SSE3__) >+ // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 >+ // Casting from long double to uint64_t is miscompiled and drops bits. >+ (!std::is_same<Float, long double>::value || >+ !std::is_same<Int, uint64_t>::value) && >+#endif >+ std::numeric_limits<Float>::digits <= std::numeric_limits<Int>::digits; >+} >+ >+template <typename Float> >+struct Decomposed { >+ Float mantissa; >+ int exponent; >+}; >+ >+// Decompose the double into an integer mantissa and an exponent. >+template <typename Float> >+Decomposed<Float> Decompose(Float v) { >+ int exp; >+ Float m = std::frexp(v, &exp); >+ m = std::ldexp(m, std::numeric_limits<Float>::digits); >+ exp -= std::numeric_limits<Float>::digits; >+ return {m, exp}; >+} >+ >+// Print 'digits' as decimal. >+// In Fixed mode, we add a '.' at the end. >+// In Precision mode, we add a '.' after the first digit. >+template <FormatStyle mode, typename Int> >+int PrintIntegralDigits(Int digits, Buffer *out) { >+ int printed = 0; >+ if (digits) { >+ for (; digits; digits /= 10) out->push_front(digits % 10 + '0'); >+ printed = out->size(); >+ if (mode == FormatStyle::Precision) { >+ out->push_front(*out->begin); >+ out->begin[1] = '.'; >+ } else { >+ out->push_back('.'); >+ } >+ } else if (mode == FormatStyle::Fixed) { >+ out->push_front('0'); >+ out->push_back('.'); >+ printed = 1; >+ } >+ return printed; >+} >+ >+// Back out 'extra_digits' digits and round up if necessary. >+bool RemoveExtraPrecision(int extra_digits, bool has_leftover_value, >+ Buffer *out, int *exp_out) { >+ if (extra_digits <= 0) return false; >+ >+ // Back out the extra digits >+ out->end -= extra_digits; >+ >+ bool needs_to_round_up = [&] { >+ // We look at the digit just past the end. >+ // There must be 'extra_digits' extra valid digits after end. >+ if (*out->end > '5') return true; >+ if (*out->end < '5') return false; >+ if (has_leftover_value || std::any_of(out->end + 1, out->end + extra_digits, >+ [](char c) { return c != '0'; })) >+ return true; >+ >+ // Ends in ...50*, round to even. >+ return out->last_digit() % 2 == 1; >+ }(); >+ >+ if (needs_to_round_up) { >+ RoundUp<FormatStyle::Precision>(out, exp_out); >+ } >+ return true; >+} >+ >+// Print the value into the buffer. >+// This will not include the exponent, which will be returned in 'exp_out' for >+// Precision mode. >+template <typename Int, typename Float, FormatStyle mode> >+bool FloatToBufferImpl(Int int_mantissa, int exp, int precision, Buffer *out, >+ int *exp_out) { >+ assert((CanFitMantissa<Float, Int>())); >+ >+ const int int_bits = std::numeric_limits<Int>::digits; >+ >+ // In precision mode, we start printing one char to the right because it will >+ // also include the '.' >+ // In fixed mode we put the dot afterwards on the right. >+ out->begin = out->end = >+ out->data + 1 + kMaxFixedPrecision + (mode == FormatStyle::Precision); >+ >+ if (exp >= 0) { >+ if (std::numeric_limits<Float>::digits + exp > int_bits) { >+ // The value will overflow the Int >+ return false; >+ } >+ int digits_printed = PrintIntegralDigits<mode>(int_mantissa << exp, out); >+ int digits_to_zero_pad = precision; >+ if (mode == FormatStyle::Precision) { >+ *exp_out = digits_printed - 1; >+ digits_to_zero_pad -= digits_printed - 1; >+ if (RemoveExtraPrecision(-digits_to_zero_pad, false, out, exp_out)) { >+ return true; >+ } >+ } >+ for (; digits_to_zero_pad-- > 0;) out->push_back('0'); >+ return true; >+ } >+ >+ exp = -exp; >+ // We need at least 4 empty bits for the next decimal digit. >+ // We will multiply by 10. >+ if (exp > int_bits - 4) return false; >+ >+ const Int mask = (Int{1} << exp) - 1; >+ >+ // Print the integral part first. >+ int digits_printed = PrintIntegralDigits<mode>(int_mantissa >> exp, out); >+ int_mantissa &= mask; >+ >+ int fractional_count = precision; >+ if (mode == FormatStyle::Precision) { >+ if (digits_printed == 0) { >+ // Find the first non-zero digit, when in Precision mode. >+ *exp_out = 0; >+ if (int_mantissa) { >+ while (int_mantissa <= mask) { >+ int_mantissa *= 10; >+ --*exp_out; >+ } >+ } >+ out->push_front(static_cast<char>(int_mantissa >> exp) + '0'); >+ out->push_back('.'); >+ int_mantissa &= mask; >+ } else { >+ // We already have a digit, and a '.' >+ *exp_out = digits_printed - 1; >+ fractional_count -= *exp_out; >+ if (RemoveExtraPrecision(-fractional_count, int_mantissa != 0, out, >+ exp_out)) { >+ // If we had enough digits, return right away. >+ // The code below will try to round again otherwise. >+ return true; >+ } >+ } >+ } >+ >+ auto get_next_digit = [&] { >+ int_mantissa *= 10; >+ int digit = static_cast<int>(int_mantissa >> exp); >+ int_mantissa &= mask; >+ return digit; >+ }; >+ >+ // Print fractional_count more digits, if available. >+ for (; fractional_count > 0; --fractional_count) { >+ out->push_back(get_next_digit() + '0'); >+ } >+ >+ int next_digit = get_next_digit(); >+ if (next_digit > 5 || >+ (next_digit == 5 && (int_mantissa || out->last_digit() % 2 == 1))) { >+ RoundUp<mode>(out, exp_out); >+ } >+ >+ return true; >+} >+ >+template <FormatStyle mode, typename Float> >+bool FloatToBuffer(Decomposed<Float> decomposed, int precision, Buffer *out, >+ int *exp) { >+ if (precision > kMaxFixedPrecision) return false; >+ >+ // Try with uint64_t. >+ if (CanFitMantissa<Float, std::uint64_t>() && >+ FloatToBufferImpl<std::uint64_t, Float, mode>( >+ static_cast<std::uint64_t>(decomposed.mantissa), >+ static_cast<std::uint64_t>(decomposed.exponent), precision, out, exp)) >+ return true; >+ >+#if defined(__SIZEOF_INT128__) >+ // If that is not enough, try with __uint128_t. >+ return CanFitMantissa<Float, __uint128_t>() && >+ FloatToBufferImpl<__uint128_t, Float, mode>( >+ static_cast<__uint128_t>(decomposed.mantissa), >+ static_cast<__uint128_t>(decomposed.exponent), precision, out, >+ exp); >+#endif >+ return false; >+} >+ >+void WriteBufferToSink(char sign_char, string_view str, >+ const ConversionSpec &conv, FormatSinkImpl *sink) { >+ int left_spaces = 0, zeros = 0, right_spaces = 0; >+ int missing_chars = >+ conv.width() >= 0 ? std::max(conv.width() - static_cast<int>(str.size()) - >+ static_cast<int>(sign_char != 0), >+ 0) >+ : 0; >+ if (conv.flags().left) { >+ right_spaces = missing_chars; >+ } else if (conv.flags().zero) { >+ zeros = missing_chars; >+ } else { >+ left_spaces = missing_chars; >+ } >+ >+ sink->Append(left_spaces, ' '); >+ if (sign_char) sink->Append(1, sign_char); >+ sink->Append(zeros, '0'); >+ sink->Append(str); >+ sink->Append(right_spaces, ' '); >+} >+ >+template <typename Float> >+bool FloatToSink(const Float v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ // Print the sign or the sign column. >+ Float abs_v = v; >+ char sign_char = 0; >+ if (std::signbit(abs_v)) { >+ sign_char = '-'; >+ abs_v = -abs_v; >+ } else if (conv.flags().show_pos) { >+ sign_char = '+'; >+ } else if (conv.flags().sign_col) { >+ sign_char = ' '; >+ } >+ >+ // Print nan/inf. >+ if (ConvertNonNumericFloats(sign_char, abs_v, conv, sink)) { >+ return true; >+ } >+ >+ int precision = conv.precision() < 0 ? 6 : conv.precision(); >+ >+ int exp = 0; >+ >+ auto decomposed = Decompose(abs_v); >+ >+ Buffer buffer; >+ >+ switch (conv.conv().id()) { >+ case ConversionChar::f: >+ case ConversionChar::F: >+ if (!FloatToBuffer<FormatStyle::Fixed>(decomposed, precision, &buffer, >+ nullptr)) { >+ return FallbackToSnprintf(v, conv, sink); >+ } >+ if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back(); >+ break; >+ >+ case ConversionChar::e: >+ case ConversionChar::E: >+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, >+ &exp)) { >+ return FallbackToSnprintf(v, conv, sink); >+ } >+ if (!conv.flags().alt && buffer.back() == '.') buffer.pop_back(); >+ PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer); >+ break; >+ >+ case ConversionChar::g: >+ case ConversionChar::G: >+ precision = std::max(0, precision - 1); >+ if (!FloatToBuffer<FormatStyle::Precision>(decomposed, precision, &buffer, >+ &exp)) { >+ return FallbackToSnprintf(v, conv, sink); >+ } >+ if (precision + 1 > exp && exp >= -4) { >+ if (exp < 0) { >+ // Have 1.23456, needs 0.00123456 >+ // Move the first digit >+ buffer.begin[1] = *buffer.begin; >+ // Add some zeros >+ for (; exp < -1; ++exp) *buffer.begin-- = '0'; >+ *buffer.begin-- = '.'; >+ *buffer.begin = '0'; >+ } else if (exp > 0) { >+ // Have 1.23456, needs 1234.56 >+ // Move the '.' exp positions to the right. >+ std::rotate(buffer.begin + 1, buffer.begin + 2, >+ buffer.begin + exp + 2); >+ } >+ exp = 0; >+ } >+ if (!conv.flags().alt) { >+ while (buffer.back() == '0') buffer.pop_back(); >+ if (buffer.back() == '.') buffer.pop_back(); >+ } >+ if (exp) PrintExponent(exp, conv.conv().upper() ? 'E' : 'e', &buffer); >+ break; >+ >+ case ConversionChar::a: >+ case ConversionChar::A: >+ return FallbackToSnprintf(v, conv, sink); >+ >+ default: >+ return false; >+ } >+ >+ WriteBufferToSink(sign_char, >+ string_view(buffer.begin, buffer.end - buffer.begin), conv, >+ sink); >+ >+ return true; >+} >+ >+} // namespace >+ >+bool ConvertFloatImpl(long double v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return FloatToSink(v, conv, sink); >+} >+ >+bool ConvertFloatImpl(float v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return FloatToSink(v, conv, sink); >+} >+ >+bool ConvertFloatImpl(double v, const ConversionSpec &conv, >+ FormatSinkImpl *sink) { >+ return FloatToSink(v, conv, sink); >+} >+ >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h >new file mode 100644 >index 00000000000..8ba5566d3ee >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h >@@ -0,0 +1,21 @@ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ >+ >+#include "absl/strings/internal/str_format/extension.h" >+ >+namespace absl { >+namespace str_format_internal { >+ >+bool ConvertFloatImpl(float v, const ConversionSpec &conv, >+ FormatSinkImpl *sink); >+ >+bool ConvertFloatImpl(double v, const ConversionSpec &conv, >+ FormatSinkImpl *sink); >+ >+bool ConvertFloatImpl(long double v, const ConversionSpec &conv, >+ FormatSinkImpl *sink); >+ >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.cc >new file mode 100644 >index 00000000000..5c3795b737c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.cc >@@ -0,0 +1,47 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/str_format/output.h" >+ >+#include <errno.h> >+#include <cstring> >+ >+namespace absl { >+namespace str_format_internal { >+ >+void BufferRawSink::Write(string_view v) { >+ size_t to_write = std::min(v.size(), size_); >+ std::memcpy(buffer_, v.data(), to_write); >+ buffer_ += to_write; >+ size_ -= to_write; >+ total_written_ += v.size(); >+} >+ >+void FILERawSink::Write(string_view v) { >+ while (!v.empty() && !error_) { >+ if (size_t result = std::fwrite(v.data(), 1, v.size(), output_)) { >+ // Some progress was made. >+ count_ += result; >+ v.remove_prefix(result); >+ } else { >+ // Some error occurred. >+ if (errno != EINTR) { >+ error_ = errno; >+ } >+ } >+ } >+} >+ >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.h >new file mode 100644 >index 00000000000..3b0aa5e7157 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output.h >@@ -0,0 +1,101 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Output extension hooks for the Format library. >+// `internal::InvokeFlush` calls the appropriate flush function for the >+// specified output argument. >+// `BufferRawSink` is a simple output sink for a char buffer. Used by SnprintF. >+// `FILERawSink` is a std::FILE* based sink. Used by PrintF and FprintF. >+ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ >+ >+#include <cstdio> >+#include <ostream> >+#include <string> >+ >+#include "absl/base/port.h" >+#include "absl/strings/string_view.h" >+ >+class Cord; >+ >+namespace absl { >+namespace str_format_internal { >+ >+// RawSink implementation that writes into a char* buffer. >+// It will not overflow the buffer, but will keep the total count of chars >+// that would have been written. >+class BufferRawSink { >+ public: >+ BufferRawSink(char* buffer, size_t size) : buffer_(buffer), size_(size) {} >+ >+ size_t total_written() const { return total_written_; } >+ void Write(string_view v); >+ >+ private: >+ char* buffer_; >+ size_t size_; >+ size_t total_written_ = 0; >+}; >+ >+// RawSink implementation that writes into a FILE*. >+// It keeps track of the total number of bytes written and any error encountered >+// during the writes. >+class FILERawSink { >+ public: >+ explicit FILERawSink(std::FILE* output) : output_(output) {} >+ >+ void Write(string_view v); >+ >+ size_t count() const { return count_; } >+ int error() const { return error_; } >+ >+ private: >+ std::FILE* output_; >+ int error_ = 0; >+ size_t count_ = 0; >+}; >+ >+// Provide RawSink integration with common types from the STL. >+inline void AbslFormatFlush(std::string* out, string_view s) { >+ out->append(s.begin(), s.size()); >+} >+inline void AbslFormatFlush(std::ostream* out, string_view s) { >+ out->write(s.begin(), s.size()); >+} >+ >+template <class AbslCord, typename = typename std::enable_if< >+ std::is_same<AbslCord, ::Cord>::value>::type> >+inline void AbslFormatFlush(AbslCord* out, string_view s) { >+ out->Append(s); >+} >+ >+inline void AbslFormatFlush(FILERawSink* sink, string_view v) { >+ sink->Write(v); >+} >+ >+inline void AbslFormatFlush(BufferRawSink* sink, string_view v) { >+ sink->Write(v); >+} >+ >+template <typename T> >+auto InvokeFlush(T* out, string_view s) >+ -> decltype(str_format_internal::AbslFormatFlush(out, s)) { >+ str_format_internal::AbslFormatFlush(out, s); >+} >+ >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_OUTPUT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output_test.cc >new file mode 100644 >index 00000000000..cc3c615557f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/output_test.cc >@@ -0,0 +1,78 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/str_format/output.h" >+ >+#include <sstream> >+#include <string> >+ >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace { >+ >+TEST(InvokeFlush, String) { >+ std::string str = "ABC"; >+ str_format_internal::InvokeFlush(&str, "DEF"); >+ EXPECT_EQ(str, "ABCDEF"); >+ >+#if UTIL_FORMAT_HAS_GLOBAL_STRING >+ std::string str2 = "ABC"; >+ str_format_internal::InvokeFlush(&str2, "DEF"); >+ EXPECT_EQ(str2, "ABCDEF"); >+#endif // UTIL_FORMAT_HAS_GLOBAL_STRING >+} >+ >+TEST(InvokeFlush, Stream) { >+ std::stringstream str; >+ str << "ABC"; >+ str_format_internal::InvokeFlush(&str, "DEF"); >+ EXPECT_EQ(str.str(), "ABCDEF"); >+} >+ >+TEST(BufferRawSink, Limits) { >+ char buf[16]; >+ { >+ std::fill(std::begin(buf), std::end(buf), 'x'); >+ str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1); >+ str_format_internal::InvokeFlush(&bufsink, "Hello World237"); >+ EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World237xx"); >+ } >+ { >+ std::fill(std::begin(buf), std::end(buf), 'x'); >+ str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1); >+ str_format_internal::InvokeFlush(&bufsink, "Hello World237237"); >+ EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World2372x"); >+ } >+ { >+ std::fill(std::begin(buf), std::end(buf), 'x'); >+ str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1); >+ str_format_internal::InvokeFlush(&bufsink, "Hello World"); >+ str_format_internal::InvokeFlush(&bufsink, "237"); >+ EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World237xx"); >+ } >+ { >+ std::fill(std::begin(buf), std::end(buf), 'x'); >+ str_format_internal::BufferRawSink bufsink(buf, sizeof(buf) - 1); >+ str_format_internal::InvokeFlush(&bufsink, "Hello World"); >+ str_format_internal::InvokeFlush(&bufsink, "237237"); >+ EXPECT_EQ(std::string(buf, sizeof(buf)), "Hello World2372x"); >+ } >+} >+ >+} // namespace >+} // namespace absl >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc >new file mode 100644 >index 00000000000..10114f489c0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc >@@ -0,0 +1,294 @@ >+#include "absl/strings/internal/str_format/parser.h" >+ >+#include <assert.h> >+#include <string.h> >+#include <wchar.h> >+#include <cctype> >+#include <cstdint> >+ >+#include <algorithm> >+#include <initializer_list> >+#include <limits> >+#include <ostream> >+#include <string> >+#include <unordered_set> >+ >+namespace absl { >+namespace str_format_internal { >+namespace { >+ >+bool CheckFastPathSetting(const UnboundConversion& conv) { >+ bool should_be_basic = !conv.flags.left && // >+ !conv.flags.show_pos && // >+ !conv.flags.sign_col && // >+ !conv.flags.alt && // >+ !conv.flags.zero && // >+ (conv.width.value() == -1) && >+ (conv.precision.value() == -1); >+ if (should_be_basic != conv.flags.basic) { >+ fprintf(stderr, >+ "basic=%d left=%d show_pos=%d sign_col=%d alt=%d zero=%d " >+ "width=%d precision=%d\n", >+ conv.flags.basic, conv.flags.left, conv.flags.show_pos, >+ conv.flags.sign_col, conv.flags.alt, conv.flags.zero, >+ conv.width.value(), conv.precision.value()); >+ } >+ return should_be_basic == conv.flags.basic; >+} >+ >+// Keep a single table for all the conversion chars and length modifiers. >+// We invert the length modifiers to make them negative so that we can easily >+// test for them. >+// Everything else is `none`, which is a negative constant. >+using CC = ConversionChar::Id; >+using LM = LengthMod::Id; >+static constexpr std::int8_t none = -128; >+static constexpr std::int8_t kIds[] = { >+ none, none, none, none, none, none, none, none, // 00-07 >+ none, none, none, none, none, none, none, none, // 08-0f >+ none, none, none, none, none, none, none, none, // 10-17 >+ none, none, none, none, none, none, none, none, // 18-1f >+ none, none, none, none, none, none, none, none, // 20-27 >+ none, none, none, none, none, none, none, none, // 28-2f >+ none, none, none, none, none, none, none, none, // 30-37 >+ none, none, none, none, none, none, none, none, // 38-3f >+ none, CC::A, none, CC::C, none, CC::E, CC::F, CC::G, // @ABCDEFG >+ none, none, none, none, ~LM::L, none, none, none, // HIJKLMNO >+ none, none, none, CC::S, none, none, none, none, // PQRSTUVW >+ CC::X, none, none, none, none, none, none, none, // XYZ[\]^_ >+ none, CC::a, none, CC::c, CC::d, CC::e, CC::f, CC::g, // `abcdefg >+ ~LM::h, CC::i, ~LM::j, none, ~LM::l, none, CC::n, CC::o, // hijklmno >+ CC::p, ~LM::q, none, CC::s, ~LM::t, CC::u, none, none, // pqrstuvw >+ CC::x, none, ~LM::z, none, none, none, none, none, // xyz{|}~! >+ none, none, none, none, none, none, none, none, // 80-87 >+ none, none, none, none, none, none, none, none, // 88-8f >+ none, none, none, none, none, none, none, none, // 90-97 >+ none, none, none, none, none, none, none, none, // 98-9f >+ none, none, none, none, none, none, none, none, // a0-a7 >+ none, none, none, none, none, none, none, none, // a8-af >+ none, none, none, none, none, none, none, none, // b0-b7 >+ none, none, none, none, none, none, none, none, // b8-bf >+ none, none, none, none, none, none, none, none, // c0-c7 >+ none, none, none, none, none, none, none, none, // c8-cf >+ none, none, none, none, none, none, none, none, // d0-d7 >+ none, none, none, none, none, none, none, none, // d8-df >+ none, none, none, none, none, none, none, none, // e0-e7 >+ none, none, none, none, none, none, none, none, // e8-ef >+ none, none, none, none, none, none, none, none, // f0-f7 >+ none, none, none, none, none, none, none, none, // f8-ff >+}; >+ >+template <bool is_positional> >+bool ConsumeConversion(string_view *src, UnboundConversion *conv, >+ int *next_arg) { >+ const char *pos = src->begin(); >+ const char *const end = src->end(); >+ char c; >+ // Read the next char into `c` and update `pos`. Reads '\0' if at end. >+ const auto get_char = [&] { c = pos == end ? '\0' : *pos++; }; >+ >+ const auto parse_digits = [&] { >+ int digits = c - '0'; >+ // We do not want to overflow `digits` so we consume at most digits10-1 >+ // digits. If there are more digits the parsing will fail later on when the >+ // digit doesn't match the expected characters. >+ int num_digits = std::numeric_limits<int>::digits10 - 2; >+ for (get_char(); num_digits && std::isdigit(c); get_char()) { >+ --num_digits; >+ digits = 10 * digits + c - '0'; >+ } >+ return digits; >+ }; >+ >+ if (is_positional) { >+ get_char(); >+ if (c < '1' || c > '9') return false; >+ conv->arg_position = parse_digits(); >+ assert(conv->arg_position > 0); >+ if (c != '$') return false; >+ } >+ >+ get_char(); >+ >+ // We should start with the basic flag on. >+ assert(conv->flags.basic); >+ >+ // Any non alpha character makes this conversion not basic. >+ // This includes flags (-+ #0), width (1-9, *) or precision (.). >+ // All conversion characters and length modifiers are alpha characters. >+ if (c < 'A') { >+ conv->flags.basic = false; >+ >+ for (; c <= '0'; get_char()) { >+ switch (c) { >+ case '-': >+ conv->flags.left = true; >+ continue; >+ case '+': >+ conv->flags.show_pos = true; >+ continue; >+ case ' ': >+ conv->flags.sign_col = true; >+ continue; >+ case '#': >+ conv->flags.alt = true; >+ continue; >+ case '0': >+ conv->flags.zero = true; >+ continue; >+ } >+ break; >+ } >+ >+ if (c <= '9') { >+ if (c >= '0') { >+ int maybe_width = parse_digits(); >+ if (!is_positional && c == '$') { >+ if (*next_arg != 0) return false; >+ // Positional conversion. >+ *next_arg = -1; >+ conv->flags = Flags(); >+ conv->flags.basic = true; >+ return ConsumeConversion<true>(src, conv, next_arg); >+ } >+ conv->width.set_value(maybe_width); >+ } else if (c == '*') { >+ get_char(); >+ if (is_positional) { >+ if (c < '1' || c > '9') return false; >+ conv->width.set_from_arg(parse_digits()); >+ if (c != '$') return false; >+ get_char(); >+ } else { >+ conv->width.set_from_arg(++*next_arg); >+ } >+ } >+ } >+ >+ if (c == '.') { >+ get_char(); >+ if (std::isdigit(c)) { >+ conv->precision.set_value(parse_digits()); >+ } else if (c == '*') { >+ get_char(); >+ if (is_positional) { >+ if (c < '1' || c > '9') return false; >+ conv->precision.set_from_arg(parse_digits()); >+ if (c != '$') return false; >+ get_char(); >+ } else { >+ conv->precision.set_from_arg(++*next_arg); >+ } >+ } else { >+ conv->precision.set_value(0); >+ } >+ } >+ } >+ >+ std::int8_t id = kIds[static_cast<unsigned char>(c)]; >+ >+ if (id < 0) { >+ if (id == none) return false; >+ >+ // It is a length modifier. >+ using str_format_internal::LengthMod; >+ LengthMod length_mod = LengthMod::FromId(static_cast<LM>(~id)); >+ get_char(); >+ if (c == 'h' && length_mod.id() == LengthMod::h) { >+ conv->length_mod = LengthMod::FromId(LengthMod::hh); >+ get_char(); >+ } else if (c == 'l' && length_mod.id() == LengthMod::l) { >+ conv->length_mod = LengthMod::FromId(LengthMod::ll); >+ get_char(); >+ } else { >+ conv->length_mod = length_mod; >+ } >+ id = kIds[static_cast<unsigned char>(c)]; >+ if (id < 0) return false; >+ } >+ >+ assert(CheckFastPathSetting(*conv)); >+ (void)(&CheckFastPathSetting); >+ >+ conv->conv = ConversionChar::FromId(static_cast<CC>(id)); >+ if (!is_positional) conv->arg_position = ++*next_arg; >+ *src = string_view(pos, end - pos); >+ return true; >+} >+ >+} // namespace >+ >+bool ConsumeUnboundConversion(string_view *src, UnboundConversion *conv, >+ int *next_arg) { >+ if (*next_arg < 0) return ConsumeConversion<true>(src, conv, next_arg); >+ return ConsumeConversion<false>(src, conv, next_arg); >+} >+ >+struct ParsedFormatBase::ParsedFormatConsumer { >+ explicit ParsedFormatConsumer(ParsedFormatBase *parsedformat) >+ : parsed(parsedformat), data_pos(parsedformat->data_.get()) {} >+ >+ bool Append(string_view s) { >+ if (s.empty()) return true; >+ >+ size_t text_end = AppendText(s); >+ >+ if (!parsed->items_.empty() && !parsed->items_.back().is_conversion) { >+ // Let's extend the existing text run. >+ parsed->items_.back().text_end = text_end; >+ } else { >+ // Let's make a new text run. >+ parsed->items_.push_back({false, text_end, {}}); >+ } >+ return true; >+ } >+ >+ bool ConvertOne(const UnboundConversion &conv, string_view s) { >+ size_t text_end = AppendText(s); >+ parsed->items_.push_back({true, text_end, conv}); >+ return true; >+ } >+ >+ size_t AppendText(string_view s) { >+ memcpy(data_pos, s.data(), s.size()); >+ data_pos += s.size(); >+ return static_cast<size_t>(data_pos - parsed->data_.get()); >+ } >+ >+ ParsedFormatBase *parsed; >+ char* data_pos; >+}; >+ >+ParsedFormatBase::ParsedFormatBase(string_view format, bool allow_ignored, >+ std::initializer_list<Conv> convs) >+ : data_(format.empty() ? nullptr : new char[format.size()]) { >+ has_error_ = !ParseFormatString(format, ParsedFormatConsumer(this)) || >+ !MatchesConversions(allow_ignored, convs); >+} >+ >+bool ParsedFormatBase::MatchesConversions( >+ bool allow_ignored, std::initializer_list<Conv> convs) const { >+ std::unordered_set<int> used; >+ auto add_if_valid_conv = [&](int pos, char c) { >+ if (static_cast<size_t>(pos) > convs.size() || >+ !Contains(convs.begin()[pos - 1], c)) >+ return false; >+ used.insert(pos); >+ return true; >+ }; >+ for (const ConversionItem &item : items_) { >+ if (!item.is_conversion) continue; >+ auto &conv = item.conv; >+ if (conv.precision.is_from_arg() && >+ !add_if_valid_conv(conv.precision.get_from_arg(), '*')) >+ return false; >+ if (conv.width.is_from_arg() && >+ !add_if_valid_conv(conv.width.get_from_arg(), '*')) >+ return false; >+ if (!add_if_valid_conv(conv.arg_position, conv.conv.Char())) return false; >+ } >+ return used.size() == convs.size() || allow_ignored; >+} >+ >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h >new file mode 100644 >index 00000000000..5bebc95540e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h >@@ -0,0 +1,291 @@ >+#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ >+#define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ >+ >+#include <limits.h> >+#include <stddef.h> >+#include <stdlib.h> >+ >+#include <cassert> >+#include <initializer_list> >+#include <iosfwd> >+#include <iterator> >+#include <memory> >+#include <vector> >+ >+#include "absl/strings/internal/str_format/checker.h" >+#include "absl/strings/internal/str_format/extension.h" >+ >+namespace absl { >+namespace str_format_internal { >+ >+// The analyzed properties of a single specified conversion. >+struct UnboundConversion { >+ UnboundConversion() >+ : flags() /* This is required to zero all the fields of flags. */ { >+ flags.basic = true; >+ } >+ >+ class InputValue { >+ public: >+ void set_value(int value) { >+ assert(value >= 0); >+ value_ = value; >+ } >+ int value() const { return value_; } >+ >+ // Marks the value as "from arg". aka the '*' format. >+ // Requires `value >= 1`. >+ // When set, is_from_arg() return true and get_from_arg() returns the >+ // original value. >+ // `value()`'s return value is unspecfied in this state. >+ void set_from_arg(int value) { >+ assert(value > 0); >+ value_ = -value - 1; >+ } >+ bool is_from_arg() const { return value_ < -1; } >+ int get_from_arg() const { >+ assert(is_from_arg()); >+ return -value_ - 1; >+ } >+ >+ private: >+ int value_ = -1; >+ }; >+ >+ // No need to initialize. It will always be set in the parser. >+ int arg_position; >+ >+ InputValue width; >+ InputValue precision; >+ >+ Flags flags; >+ LengthMod length_mod; >+ ConversionChar conv; >+}; >+ >+// Consume conversion spec prefix (not including '%') of '*src' if valid. >+// Examples of valid specs would be e.g.: "s", "d", "-12.6f". >+// If valid, the front of src is advanced such that src becomes the >+// part following the conversion spec, and the spec part is broken down and >+// returned in 'conv'. >+// If invalid, returns false and leaves 'src' unmodified. >+// For example: >+// Given "d9", returns "d", and leaves src="9", >+// Given "!", returns "" and leaves src="!". >+bool ConsumeUnboundConversion(string_view* src, UnboundConversion* conv, >+ int* next_arg); >+ >+// Parse the format std::string provided in 'src' and pass the identified items into >+// 'consumer'. >+// Text runs will be passed by calling >+// Consumer::Append(string_view); >+// ConversionItems will be passed by calling >+// Consumer::ConvertOne(UnboundConversion, string_view); >+// In the case of ConvertOne, the string_view that is passed is the >+// portion of the format std::string corresponding to the conversion, not including >+// the leading %. On success, it returns true. On failure, it stops and returns >+// false. >+template <typename Consumer> >+bool ParseFormatString(string_view src, Consumer consumer) { >+ int next_arg = 0; >+ while (!src.empty()) { >+ const char* percent = >+ static_cast<const char*>(memchr(src.begin(), '%', src.size())); >+ if (!percent) { >+ // We found the last substring. >+ return consumer.Append(src); >+ } >+ // We found a percent, so push the text run then process the percent. >+ size_t percent_loc = percent - src.data(); >+ if (!consumer.Append(string_view(src.data(), percent_loc))) return false; >+ if (percent + 1 >= src.end()) return false; >+ >+ UnboundConversion conv; >+ >+ switch (percent[1]) { >+ case '%': >+ if (!consumer.Append("%")) return false; >+ src.remove_prefix(percent_loc + 2); >+ continue; >+ >+#define PARSER_CASE(ch) \ >+ case #ch[0]: \ >+ src.remove_prefix(percent_loc + 2); \ >+ conv.conv = ConversionChar::FromId(ConversionChar::ch); \ >+ conv.arg_position = ++next_arg; \ >+ break; >+ ABSL_CONVERSION_CHARS_EXPAND_(PARSER_CASE, ); >+#undef PARSER_CASE >+ >+ default: >+ src.remove_prefix(percent_loc + 1); >+ if (!ConsumeUnboundConversion(&src, &conv, &next_arg)) return false; >+ break; >+ } >+ if (next_arg == 0) { >+ // This indicates an error in the format std::string. >+ // The only way to get next_arg == 0 is to have a positional argument >+ // first which sets next_arg to -1 and then a non-positional argument >+ // which does ++next_arg. >+ // Checking here seems to be the cheapeast place to do it. >+ return false; >+ } >+ if (!consumer.ConvertOne( >+ conv, string_view(percent + 1, src.data() - (percent + 1)))) { >+ return false; >+ } >+ } >+ return true; >+} >+ >+// Always returns true, or fails to compile in a constexpr context if s does not >+// point to a constexpr char array. >+constexpr bool EnsureConstexpr(string_view s) { >+ return s.empty() || s[0] == s[0]; >+} >+ >+class ParsedFormatBase { >+ public: >+ explicit ParsedFormatBase(string_view format, bool allow_ignored, >+ std::initializer_list<Conv> convs); >+ >+ ParsedFormatBase(const ParsedFormatBase& other) { *this = other; } >+ >+ ParsedFormatBase(ParsedFormatBase&& other) { *this = std::move(other); } >+ >+ ParsedFormatBase& operator=(const ParsedFormatBase& other) { >+ if (this == &other) return *this; >+ has_error_ = other.has_error_; >+ items_ = other.items_; >+ size_t text_size = items_.empty() ? 0 : items_.back().text_end; >+ data_.reset(new char[text_size]); >+ memcpy(data_.get(), other.data_.get(), text_size); >+ return *this; >+ } >+ >+ ParsedFormatBase& operator=(ParsedFormatBase&& other) { >+ if (this == &other) return *this; >+ has_error_ = other.has_error_; >+ data_ = std::move(other.data_); >+ items_ = std::move(other.items_); >+ // Reset the vector to make sure the invariants hold. >+ other.items_.clear(); >+ return *this; >+ } >+ >+ template <typename Consumer> >+ bool ProcessFormat(Consumer consumer) const { >+ const char* const base = data_.get(); >+ string_view text(base, 0); >+ for (const auto& item : items_) { >+ text = string_view(text.end(), (base + item.text_end) - text.end()); >+ if (item.is_conversion) { >+ if (!consumer.ConvertOne(item.conv, text)) return false; >+ } else { >+ if (!consumer.Append(text)) return false; >+ } >+ } >+ return !has_error_; >+ } >+ >+ bool has_error() const { return has_error_; } >+ >+ private: >+ // Returns whether the conversions match and if !allow_ignored it verifies >+ // that all conversions are used by the format. >+ bool MatchesConversions(bool allow_ignored, >+ std::initializer_list<Conv> convs) const; >+ >+ struct ParsedFormatConsumer; >+ >+ struct ConversionItem { >+ bool is_conversion; >+ // Points to the past-the-end location of this element in the data_ array. >+ size_t text_end; >+ UnboundConversion conv; >+ }; >+ >+ bool has_error_; >+ std::unique_ptr<char[]> data_; >+ std::vector<ConversionItem> items_; >+}; >+ >+ >+// A value type representing a preparsed format. These can be created, copied >+// around, and reused to speed up formatting loops. >+// The user must specify through the template arguments the conversion >+// characters used in the format. This will be checked at compile time. >+// >+// This class uses Conv enum values to specify each argument. >+// This allows for more flexibility as you can specify multiple possible >+// conversion characters for each argument. >+// ParsedFormat<char...> is a simplified alias for when the user only >+// needs to specify a single conversion character for each argument. >+// >+// Example: >+// // Extended format supports multiple characters per argument: >+// using MyFormat = ExtendedParsedFormat<Conv::d | Conv::x>; >+// MyFormat GetFormat(bool use_hex) { >+// if (use_hex) return MyFormat("foo %x bar"); >+// return MyFormat("foo %d bar"); >+// } >+// // 'format' can be used with any value that supports 'd' and 'x', >+// // like `int`. >+// auto format = GetFormat(use_hex); >+// value = StringF(format, i); >+// >+// This class also supports runtime format checking with the ::New() and >+// ::NewAllowIgnored() factory functions. >+// This is the only API that allows the user to pass a runtime specified format >+// std::string. These factory functions will return NULL if the format does not match >+// the conversions requested by the user. >+template <str_format_internal::Conv... C> >+class ExtendedParsedFormat : public str_format_internal::ParsedFormatBase { >+ public: >+ explicit ExtendedParsedFormat(string_view format) >+#if ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ __attribute__(( >+ enable_if(str_format_internal::EnsureConstexpr(format), >+ "Format std::string is not constexpr."), >+ enable_if(str_format_internal::ValidFormatImpl<C...>(format), >+ "Format specified does not match the template arguments."))) >+#endif // ABSL_INTERNAL_ENABLE_FORMAT_CHECKER >+ : ExtendedParsedFormat(format, false) { >+ } >+ >+ // ExtendedParsedFormat factory function. >+ // The user still has to specify the conversion characters, but they will not >+ // be checked at compile time. Instead, it will be checked at runtime. >+ // This delays the checking to runtime, but allows the user to pass >+ // dynamically sourced formats. >+ // It returns NULL if the format does not match the conversion characters. >+ // The user is responsible for checking the return value before using it. >+ // >+ // The 'New' variant will check that all the specified arguments are being >+ // consumed by the format and return NULL if any argument is being ignored. >+ // The 'NewAllowIgnored' variant will not verify this and will allow formats >+ // that ignore arguments. >+ static std::unique_ptr<ExtendedParsedFormat> New(string_view format) { >+ return New(format, false); >+ } >+ static std::unique_ptr<ExtendedParsedFormat> NewAllowIgnored( >+ string_view format) { >+ return New(format, true); >+ } >+ >+ private: >+ static std::unique_ptr<ExtendedParsedFormat> New(string_view format, >+ bool allow_ignored) { >+ std::unique_ptr<ExtendedParsedFormat> conv( >+ new ExtendedParsedFormat(format, allow_ignored)); >+ if (conv->has_error()) return nullptr; >+ return conv; >+ } >+ >+ ExtendedParsedFormat(string_view s, bool allow_ignored) >+ : ParsedFormatBase(s, allow_ignored, {C...}) {} >+}; >+} // namespace str_format_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc >new file mode 100644 >index 00000000000..e698020b1ab >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc >@@ -0,0 +1,379 @@ >+#include "absl/strings/internal/str_format/parser.h" >+ >+#include <string.h> >+#include "gtest/gtest.h" >+#include "absl/base/macros.h" >+ >+namespace absl { >+namespace str_format_internal { >+ >+namespace { >+ >+TEST(LengthModTest, Names) { >+ struct Expectation { >+ int line; >+ LengthMod::Id id; >+ const char *name; >+ }; >+ const Expectation kExpect[] = { >+ {__LINE__, LengthMod::none, "" }, >+ {__LINE__, LengthMod::h, "h" }, >+ {__LINE__, LengthMod::hh, "hh"}, >+ {__LINE__, LengthMod::l, "l" }, >+ {__LINE__, LengthMod::ll, "ll"}, >+ {__LINE__, LengthMod::L, "L" }, >+ {__LINE__, LengthMod::j, "j" }, >+ {__LINE__, LengthMod::z, "z" }, >+ {__LINE__, LengthMod::t, "t" }, >+ {__LINE__, LengthMod::q, "q" }, >+ }; >+ EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), LengthMod::kNumValues); >+ for (auto e : kExpect) { >+ SCOPED_TRACE(e.line); >+ LengthMod mod = LengthMod::FromId(e.id); >+ EXPECT_EQ(e.id, mod.id()); >+ EXPECT_EQ(e.name, mod.name()); >+ } >+} >+ >+TEST(ConversionCharTest, Names) { >+ struct Expectation { >+ ConversionChar::Id id; >+ char name; >+ }; >+ // clang-format off >+ const Expectation kExpect[] = { >+#define X(c) {ConversionChar::c, #c[0]} >+ X(c), X(C), X(s), X(S), // text >+ X(d), X(i), X(o), X(u), X(x), X(X), // int >+ X(f), X(F), X(e), X(E), X(g), X(G), X(a), X(A), // float >+ X(n), X(p), // misc >+#undef X >+ {ConversionChar::none, '\0'}, >+ }; >+ // clang-format on >+ EXPECT_EQ(ABSL_ARRAYSIZE(kExpect), ConversionChar::kNumValues); >+ for (auto e : kExpect) { >+ SCOPED_TRACE(e.name); >+ ConversionChar v = ConversionChar::FromId(e.id); >+ EXPECT_EQ(e.id, v.id()); >+ EXPECT_EQ(e.name, v.Char()); >+ } >+} >+ >+class ConsumeUnboundConversionTest : public ::testing::Test { >+ public: >+ typedef UnboundConversion Props; >+ string_view Consume(string_view* src) { >+ int next = 0; >+ const char* prev_begin = src->begin(); >+ o = UnboundConversion(); // refresh >+ ConsumeUnboundConversion(src, &o, &next); >+ return {prev_begin, static_cast<size_t>(src->begin() - prev_begin)}; >+ } >+ >+ bool Run(const char *fmt, bool force_positional = false) { >+ string_view src = fmt; >+ int next = force_positional ? -1 : 0; >+ o = UnboundConversion(); // refresh >+ return ConsumeUnboundConversion(&src, &o, &next) && src.empty(); >+ } >+ UnboundConversion o; >+}; >+ >+TEST_F(ConsumeUnboundConversionTest, ConsumeSpecification) { >+ struct Expectation { >+ int line; >+ const char *src; >+ const char *out; >+ const char *src_post; >+ }; >+ const Expectation kExpect[] = { >+ {__LINE__, "", "", "" }, >+ {__LINE__, "b", "", "b" }, // 'b' is invalid >+ {__LINE__, "ba", "", "ba"}, // 'b' is invalid >+ {__LINE__, "l", "", "l" }, // just length mod isn't okay >+ {__LINE__, "d", "d", "" }, // basic >+ {__LINE__, "d ", "d", " " }, // leave suffix >+ {__LINE__, "dd", "d", "d" }, // don't be greedy >+ {__LINE__, "d9", "d", "9" }, // leave non-space suffix >+ {__LINE__, "dzz", "d", "zz"}, // length mod as suffix >+ {__LINE__, "1$*2$d", "1$*2$d", "" }, // arg indexing and * allowed. >+ {__LINE__, "0-14.3hhd", "0-14.3hhd", ""}, // precision, width >+ {__LINE__, " 0-+#14.3hhd", " 0-+#14.3hhd", ""}, // flags >+ }; >+ for (const auto& e : kExpect) { >+ SCOPED_TRACE(e.line); >+ string_view src = e.src; >+ EXPECT_EQ(e.src, src); >+ string_view out = Consume(&src); >+ EXPECT_EQ(e.out, out); >+ EXPECT_EQ(e.src_post, src); >+ } >+} >+ >+TEST_F(ConsumeUnboundConversionTest, BasicConversion) { >+ EXPECT_FALSE(Run("")); >+ EXPECT_FALSE(Run("z")); >+ >+ EXPECT_FALSE(Run("dd")); // no excess allowed >+ >+ EXPECT_TRUE(Run("d")); >+ EXPECT_EQ('d', o.conv.Char()); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_LT(o.width.value(), 0); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_LT(o.precision.value(), 0); >+ EXPECT_EQ(1, o.arg_position); >+ EXPECT_EQ(LengthMod::none, o.length_mod.id()); >+} >+ >+TEST_F(ConsumeUnboundConversionTest, ArgPosition) { >+ EXPECT_TRUE(Run("d")); >+ EXPECT_EQ(1, o.arg_position); >+ EXPECT_TRUE(Run("3$d")); >+ EXPECT_EQ(3, o.arg_position); >+ EXPECT_TRUE(Run("1$d")); >+ EXPECT_EQ(1, o.arg_position); >+ EXPECT_TRUE(Run("1$d", true)); >+ EXPECT_EQ(1, o.arg_position); >+ EXPECT_TRUE(Run("123$d")); >+ EXPECT_EQ(123, o.arg_position); >+ EXPECT_TRUE(Run("123$d", true)); >+ EXPECT_EQ(123, o.arg_position); >+ EXPECT_TRUE(Run("10$d")); >+ EXPECT_EQ(10, o.arg_position); >+ EXPECT_TRUE(Run("10$d", true)); >+ EXPECT_EQ(10, o.arg_position); >+ >+ // Position can't be zero. >+ EXPECT_FALSE(Run("0$d")); >+ EXPECT_FALSE(Run("0$d", true)); >+ EXPECT_FALSE(Run("1$*0$d")); >+ EXPECT_FALSE(Run("1$.*0$d")); >+ >+ // Position can't start with a zero digit at all. That is not a 'decimal'. >+ EXPECT_FALSE(Run("01$p")); >+ EXPECT_FALSE(Run("01$p", true)); >+ EXPECT_FALSE(Run("1$*01$p")); >+ EXPECT_FALSE(Run("1$.*01$p")); >+} >+ >+TEST_F(ConsumeUnboundConversionTest, WidthAndPrecision) { >+ EXPECT_TRUE(Run("14d")); >+ EXPECT_EQ('d', o.conv.Char()); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_EQ(14, o.width.value()); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_LT(o.precision.value(), 0); >+ >+ EXPECT_TRUE(Run("14.d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_EQ(14, o.width.value()); >+ EXPECT_EQ(0, o.precision.value()); >+ >+ EXPECT_TRUE(Run(".d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_LT(o.width.value(), 0); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_EQ(0, o.precision.value()); >+ >+ EXPECT_TRUE(Run(".5d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_LT(o.width.value(), 0); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_EQ(5, o.precision.value()); >+ >+ EXPECT_TRUE(Run(".0d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_LT(o.width.value(), 0); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_EQ(0, o.precision.value()); >+ >+ EXPECT_TRUE(Run("14.5d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_EQ(14, o.width.value()); >+ EXPECT_EQ(5, o.precision.value()); >+ >+ EXPECT_TRUE(Run("*.*d")); >+ EXPECT_TRUE(o.width.is_from_arg()); >+ EXPECT_EQ(1, o.width.get_from_arg()); >+ EXPECT_TRUE(o.precision.is_from_arg()); >+ EXPECT_EQ(2, o.precision.get_from_arg()); >+ EXPECT_EQ(3, o.arg_position); >+ >+ EXPECT_TRUE(Run("*d")); >+ EXPECT_TRUE(o.width.is_from_arg()); >+ EXPECT_EQ(1, o.width.get_from_arg()); >+ EXPECT_FALSE(o.precision.is_from_arg()); >+ EXPECT_LT(o.precision.value(), 0); >+ EXPECT_EQ(2, o.arg_position); >+ >+ EXPECT_TRUE(Run(".*d")); >+ EXPECT_FALSE(o.width.is_from_arg()); >+ EXPECT_LT(o.width.value(), 0); >+ EXPECT_TRUE(o.precision.is_from_arg()); >+ EXPECT_EQ(1, o.precision.get_from_arg()); >+ EXPECT_EQ(2, o.arg_position); >+ >+ // mixed implicit and explicit: didn't specify arg position. >+ EXPECT_FALSE(Run("*23$.*34$d")); >+ >+ EXPECT_TRUE(Run("12$*23$.*34$d")); >+ EXPECT_EQ(12, o.arg_position); >+ EXPECT_TRUE(o.width.is_from_arg()); >+ EXPECT_EQ(23, o.width.get_from_arg()); >+ EXPECT_TRUE(o.precision.is_from_arg()); >+ EXPECT_EQ(34, o.precision.get_from_arg()); >+ >+ EXPECT_TRUE(Run("2$*5$.*9$d")); >+ EXPECT_EQ(2, o.arg_position); >+ EXPECT_TRUE(o.width.is_from_arg()); >+ EXPECT_EQ(5, o.width.get_from_arg()); >+ EXPECT_TRUE(o.precision.is_from_arg()); >+ EXPECT_EQ(9, o.precision.get_from_arg()); >+ >+ EXPECT_FALSE(Run(".*0$d")) << "no arg 0"; >+} >+ >+TEST_F(ConsumeUnboundConversionTest, Flags) { >+ static const char kAllFlags[] = "-+ #0"; >+ static const int kNumFlags = ABSL_ARRAYSIZE(kAllFlags) - 1; >+ for (int rev = 0; rev < 2; ++rev) { >+ for (int i = 0; i < 1 << kNumFlags; ++i) { >+ std::string fmt; >+ for (int k = 0; k < kNumFlags; ++k) >+ if ((i >> k) & 1) fmt += kAllFlags[k]; >+ // flag order shouldn't matter >+ if (rev == 1) { std::reverse(fmt.begin(), fmt.end()); } >+ fmt += 'd'; >+ SCOPED_TRACE(fmt); >+ EXPECT_TRUE(Run(fmt.c_str())); >+ EXPECT_EQ(fmt.find('-') == std::string::npos, !o.flags.left); >+ EXPECT_EQ(fmt.find('+') == std::string::npos, !o.flags.show_pos); >+ EXPECT_EQ(fmt.find(' ') == std::string::npos, !o.flags.sign_col); >+ EXPECT_EQ(fmt.find('#') == std::string::npos, !o.flags.alt); >+ EXPECT_EQ(fmt.find('0') == std::string::npos, !o.flags.zero); >+ } >+ } >+} >+ >+TEST_F(ConsumeUnboundConversionTest, BasicFlag) { >+ // Flag is on >+ for (const char* fmt : {"d", "llx", "G", "1$X"}) { >+ SCOPED_TRACE(fmt); >+ EXPECT_TRUE(Run(fmt)); >+ EXPECT_TRUE(o.flags.basic); >+ } >+ >+ // Flag is off >+ for (const char* fmt : {"3d", ".llx", "-G", "1$#X"}) { >+ SCOPED_TRACE(fmt); >+ EXPECT_TRUE(Run(fmt)); >+ EXPECT_FALSE(o.flags.basic); >+ } >+} >+ >+struct SummarizeConsumer { >+ std::string* out; >+ explicit SummarizeConsumer(std::string* out) : out(out) {} >+ >+ bool Append(string_view s) { >+ *out += "[" + std::string(s) + "]"; >+ return true; >+ } >+ >+ bool ConvertOne(const UnboundConversion& conv, string_view s) { >+ *out += "{"; >+ *out += std::string(s); >+ *out += ":"; >+ *out += std::to_string(conv.arg_position) + "$"; >+ if (conv.width.is_from_arg()) { >+ *out += std::to_string(conv.width.get_from_arg()) + "$*"; >+ } >+ if (conv.precision.is_from_arg()) { >+ *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*"; >+ } >+ *out += conv.conv.Char(); >+ *out += "}"; >+ return true; >+ } >+}; >+ >+std::string SummarizeParsedFormat(const ParsedFormatBase& pc) { >+ std::string out; >+ if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!"; >+ return out; >+} >+ >+class ParsedFormatTest : public testing::Test {}; >+ >+TEST_F(ParsedFormatTest, ValueSemantics) { >+ ParsedFormatBase p1({}, true, {}); // empty format >+ EXPECT_EQ("", SummarizeParsedFormat(p1)); >+ >+ ParsedFormatBase p2 = p1; // copy construct (empty) >+ EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2)); >+ >+ p1 = ParsedFormatBase("hello%s", true, {Conv::s}); // move assign >+ EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p1)); >+ >+ ParsedFormatBase p3 = p1; // copy construct (nonempty) >+ EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p3)); >+ >+ using std::swap; >+ swap(p1, p2); >+ EXPECT_EQ("", SummarizeParsedFormat(p1)); >+ EXPECT_EQ("[hello]{s:1$s}", SummarizeParsedFormat(p2)); >+ swap(p1, p2); // undo >+ >+ p2 = p1; // copy assign >+ EXPECT_EQ(SummarizeParsedFormat(p1), SummarizeParsedFormat(p2)); >+} >+ >+struct ExpectParse { >+ const char* in; >+ std::initializer_list<Conv> conv_set; >+ const char* out; >+}; >+ >+TEST_F(ParsedFormatTest, Parsing) { >+ // Parse should be equivalent to that obtained by ConversionParseIterator. >+ // No need to retest the parsing edge cases here. >+ const ExpectParse kExpect[] = { >+ {"", {}, ""}, >+ {"ab", {}, "[ab]"}, >+ {"a%d", {Conv::d}, "[a]{d:1$d}"}, >+ {"a%+d", {Conv::d}, "[a]{+d:1$d}"}, >+ {"a% d", {Conv::d}, "[a]{ d:1$d}"}, >+ {"a%b %d", {}, "[a]!"}, // stop after error >+ }; >+ for (const auto& e : kExpect) { >+ SCOPED_TRACE(e.in); >+ EXPECT_EQ(e.out, >+ SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set))); >+ } >+} >+ >+TEST_F(ParsedFormatTest, ParsingFlagOrder) { >+ const ExpectParse kExpect[] = { >+ {"a%+ 0d", {Conv::d}, "[a]{+ 0d:1$d}"}, >+ {"a%+0 d", {Conv::d}, "[a]{+0 d:1$d}"}, >+ {"a%0+ d", {Conv::d}, "[a]{0+ d:1$d}"}, >+ {"a% +0d", {Conv::d}, "[a]{ +0d:1$d}"}, >+ {"a%0 +d", {Conv::d}, "[a]{0 +d:1$d}"}, >+ {"a% 0+d", {Conv::d}, "[a]{ 0+d:1$d}"}, >+ {"a%+ 0+d", {Conv::d}, "[a]{+ 0+d:1$d}"}, >+ }; >+ for (const auto& e : kExpect) { >+ SCOPED_TRACE(e.in); >+ EXPECT_EQ(e.out, >+ SummarizeParsedFormat(ParsedFormatBase(e.in, false, e.conv_set))); >+ } >+} >+ >+} // namespace >+} // namespace str_format_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h >new file mode 100644 >index 00000000000..a734758c21e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_join_internal.h >@@ -0,0 +1,311 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// This file declares INTERNAL parts of the Join API that are inlined/templated >+// or otherwise need to be available at compile time. The main abstractions >+// defined in this file are: >+// >+// - A handful of default Formatters >+// - JoinAlgorithm() overloads >+// - JoinRange() overloads >+// - JoinTuple() >+// >+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including >+// absl/strings/str_join.h >+// >+// IWYU pragma: private, include "absl/strings/str_join.h" >+ >+#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ >+#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ >+ >+#include <cstring> >+#include <iterator> >+#include <memory> >+#include <string> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/strings/internal/ostringstream.h" >+#include "absl/strings/internal/resize_uninitialized.h" >+#include "absl/strings/str_cat.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+// >+// Formatter objects >+// >+// The following are implementation classes for standard Formatter objects. The >+// factory functions that users will call to create and use these formatters are >+// defined and documented in strings/join.h. >+// >+ >+// The default formatter. Converts alpha-numeric types to strings. >+struct AlphaNumFormatterImpl { >+ // This template is needed in order to support passing in a dereferenced >+ // vector<bool>::iterator >+ template <typename T> >+ void operator()(std::string* out, const T& t) const { >+ StrAppend(out, AlphaNum(t)); >+ } >+ >+ void operator()(std::string* out, const AlphaNum& t) const { >+ StrAppend(out, t); >+ } >+}; >+ >+// A type that's used to overload the JoinAlgorithm() function (defined below) >+// for ranges that do not require additional formatting (e.g., a range of >+// strings). >+ >+struct NoFormatter : public AlphaNumFormatterImpl {}; >+ >+// Formats types to strings using the << operator. >+class StreamFormatterImpl { >+ public: >+ // The method isn't const because it mutates state. Making it const will >+ // render StreamFormatterImpl thread-hostile. >+ template <typename T> >+ void operator()(std::string* out, const T& t) { >+ // The stream is created lazily to avoid paying the relatively high cost >+ // of its construction when joining an empty range. >+ if (strm_) { >+ strm_->clear(); // clear the bad, fail and eof bits in case they were set >+ strm_->str(out); >+ } else { >+ strm_.reset(new strings_internal::OStringStream(out)); >+ } >+ *strm_ << t; >+ } >+ >+ private: >+ std::unique_ptr<strings_internal::OStringStream> strm_; >+}; >+ >+// Formats a std::pair<>. The 'first' member is formatted using f1_ and the >+// 'second' member is formatted using f2_. sep_ is the separator. >+template <typename F1, typename F2> >+class PairFormatterImpl { >+ public: >+ PairFormatterImpl(F1 f1, absl::string_view sep, F2 f2) >+ : f1_(std::move(f1)), sep_(sep), f2_(std::move(f2)) {} >+ >+ template <typename T> >+ void operator()(std::string* out, const T& p) { >+ f1_(out, p.first); >+ out->append(sep_); >+ f2_(out, p.second); >+ } >+ >+ template <typename T> >+ void operator()(std::string* out, const T& p) const { >+ f1_(out, p.first); >+ out->append(sep_); >+ f2_(out, p.second); >+ } >+ >+ private: >+ F1 f1_; >+ std::string sep_; >+ F2 f2_; >+}; >+ >+// Wraps another formatter and dereferences the argument to operator() then >+// passes the dereferenced argument to the wrapped formatter. This can be >+// useful, for example, to join a std::vector<int*>. >+template <typename Formatter> >+class DereferenceFormatterImpl { >+ public: >+ DereferenceFormatterImpl() : f_() {} >+ explicit DereferenceFormatterImpl(Formatter&& f) >+ : f_(std::forward<Formatter>(f)) {} >+ >+ template <typename T> >+ void operator()(std::string* out, const T& t) { >+ f_(out, *t); >+ } >+ >+ template <typename T> >+ void operator()(std::string* out, const T& t) const { >+ f_(out, *t); >+ } >+ >+ private: >+ Formatter f_; >+}; >+ >+// DefaultFormatter<T> is a traits class that selects a default Formatter to use >+// for the given type T. The ::Type member names the Formatter to use. This is >+// used by the strings::Join() functions that do NOT take a Formatter argument, >+// in which case a default Formatter must be chosen. >+// >+// AlphaNumFormatterImpl is the default in the base template, followed by >+// specializations for other types. >+template <typename ValueType> >+struct DefaultFormatter { >+ typedef AlphaNumFormatterImpl Type; >+}; >+template <> >+struct DefaultFormatter<const char*> { >+ typedef AlphaNumFormatterImpl Type; >+}; >+template <> >+struct DefaultFormatter<char*> { >+ typedef AlphaNumFormatterImpl Type; >+}; >+template <> >+struct DefaultFormatter<std::string> { >+ typedef NoFormatter Type; >+}; >+template <> >+struct DefaultFormatter<absl::string_view> { >+ typedef NoFormatter Type; >+}; >+template <typename ValueType> >+struct DefaultFormatter<ValueType*> { >+ typedef DereferenceFormatterImpl<typename DefaultFormatter<ValueType>::Type> >+ Type; >+}; >+ >+template <typename ValueType> >+struct DefaultFormatter<std::unique_ptr<ValueType>> >+ : public DefaultFormatter<ValueType*> {}; >+ >+// >+// JoinAlgorithm() functions >+// >+ >+// The main joining algorithm. This simply joins the elements in the given >+// iterator range, each separated by the given separator, into an output std::string, >+// and formats each element using the provided Formatter object. >+template <typename Iterator, typename Formatter> >+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, >+ Formatter&& f) { >+ std::string result; >+ absl::string_view sep(""); >+ for (Iterator it = start; it != end; ++it) { >+ result.append(sep.data(), sep.size()); >+ f(&result, *it); >+ sep = s; >+ } >+ return result; >+} >+ >+// A joining algorithm that's optimized for a forward iterator range of >+// std::string-like objects that do not need any additional formatting. This is to >+// optimize the common case of joining, say, a std::vector<std::string> or a >+// std::vector<absl::string_view>. >+// >+// This is an overload of the previous JoinAlgorithm() function. Here the >+// Formatter argument is of type NoFormatter. Since NoFormatter is an internal >+// type, this overload is only invoked when strings::Join() is called with a >+// range of std::string-like objects (e.g., std::string, absl::string_view), and an >+// explicit Formatter argument was NOT specified. >+// >+// The optimization is that the needed space will be reserved in the output >+// std::string to avoid the need to resize while appending. To do this, the iterator >+// range will be traversed twice: once to calculate the total needed size, and >+// then again to copy the elements and delimiters to the output std::string. >+template <typename Iterator, >+ typename = typename std::enable_if<std::is_convertible< >+ typename std::iterator_traits<Iterator>::iterator_category, >+ std::forward_iterator_tag>::value>::type> >+std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, >+ NoFormatter) { >+ std::string result; >+ if (start != end) { >+ // Sums size >+ size_t result_size = start->size(); >+ for (Iterator it = start; ++it != end;) { >+ result_size += s.size(); >+ result_size += it->size(); >+ } >+ >+ if (result_size > 0) { >+ STLStringResizeUninitialized(&result, result_size); >+ >+ // Joins strings >+ char* result_buf = &*result.begin(); >+ memcpy(result_buf, start->data(), start->size()); >+ result_buf += start->size(); >+ for (Iterator it = start; ++it != end;) { >+ memcpy(result_buf, s.data(), s.size()); >+ result_buf += s.size(); >+ memcpy(result_buf, it->data(), it->size()); >+ result_buf += it->size(); >+ } >+ } >+ } >+ >+ return result; >+} >+ >+// JoinTupleLoop implements a loop over the elements of a std::tuple, which >+// are heterogeneous. The primary template matches the tuple interior case. It >+// continues the iteration after appending a separator (for nonzero indices) >+// and formatting an element of the tuple. The specialization for the I=N case >+// matches the end-of-tuple, and terminates the iteration. >+template <size_t I, size_t N> >+struct JoinTupleLoop { >+ template <typename Tup, typename Formatter> >+ void operator()(std::string* out, const Tup& tup, absl::string_view sep, >+ Formatter&& fmt) { >+ if (I > 0) out->append(sep.data(), sep.size()); >+ fmt(out, std::get<I>(tup)); >+ JoinTupleLoop<I + 1, N>()(out, tup, sep, fmt); >+ } >+}; >+template <size_t N> >+struct JoinTupleLoop<N, N> { >+ template <typename Tup, typename Formatter> >+ void operator()(std::string*, const Tup&, absl::string_view, Formatter&&) {} >+}; >+ >+template <typename... T, typename Formatter> >+std::string JoinAlgorithm(const std::tuple<T...>& tup, absl::string_view sep, >+ Formatter&& fmt) { >+ std::string result; >+ JoinTupleLoop<0, sizeof...(T)>()(&result, tup, sep, fmt); >+ return result; >+} >+ >+template <typename Iterator> >+std::string JoinRange(Iterator first, Iterator last, absl::string_view separator) { >+ // No formatter was explicitly given, so a default must be chosen. >+ typedef typename std::iterator_traits<Iterator>::value_type ValueType; >+ typedef typename DefaultFormatter<ValueType>::Type Formatter; >+ return JoinAlgorithm(first, last, separator, Formatter()); >+} >+ >+template <typename Range, typename Formatter> >+std::string JoinRange(const Range& range, absl::string_view separator, >+ Formatter&& fmt) { >+ using std::begin; >+ using std::end; >+ return JoinAlgorithm(begin(range), end(range), separator, fmt); >+} >+ >+template <typename Range> >+std::string JoinRange(const Range& range, absl::string_view separator) { >+ using std::begin; >+ using std::end; >+ return JoinRange(begin(range), end(range), separator); >+} >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h >new file mode 100644 >index 00000000000..9cf0833f490 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/str_split_internal.h >@@ -0,0 +1,453 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// This file declares INTERNAL parts of the Split API that are inline/templated >+// or otherwise need to be available at compile time. The main abstractions >+// defined in here are >+// >+// - ConvertibleToStringView >+// - SplitIterator<> >+// - Splitter<> >+// >+// DO NOT INCLUDE THIS FILE DIRECTLY. Use this file by including >+// absl/strings/str_split.h. >+// >+// IWYU pragma: private, include "absl/strings/str_split.h" >+ >+#ifndef ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ >+#define ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ >+ >+#include <array> >+#include <initializer_list> >+#include <iterator> >+#include <map> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/meta/type_traits.h" >+#include "absl/strings/string_view.h" >+ >+#ifdef _GLIBCXX_DEBUG >+#include "absl/strings/internal/stl_type_traits.h" >+#endif // _GLIBCXX_DEBUG >+ >+namespace absl { >+namespace strings_internal { >+ >+// This class is implicitly constructible from everything that absl::string_view >+// is implicitly constructible from. If it's constructed from a temporary >+// std::string, the data is moved into a data member so its lifetime matches that of >+// the ConvertibleToStringView instance. >+class ConvertibleToStringView { >+ public: >+ ConvertibleToStringView(const char* s) // NOLINT(runtime/explicit) >+ : value_(s) {} >+ ConvertibleToStringView(char* s) : value_(s) {} // NOLINT(runtime/explicit) >+ ConvertibleToStringView(absl::string_view s) // NOLINT(runtime/explicit) >+ : value_(s) {} >+ ConvertibleToStringView(const std::string& s) // NOLINT(runtime/explicit) >+ : value_(s) {} >+ >+ // Matches rvalue strings and moves their data to a member. >+ConvertibleToStringView(std::string&& s) // NOLINT(runtime/explicit) >+ : copy_(std::move(s)), value_(copy_) {} >+ >+ ConvertibleToStringView(const ConvertibleToStringView& other) >+ : copy_(other.copy_), >+ value_(other.IsSelfReferential() ? copy_ : other.value_) {} >+ >+ ConvertibleToStringView(ConvertibleToStringView&& other) { >+ StealMembers(std::move(other)); >+ } >+ >+ ConvertibleToStringView& operator=(ConvertibleToStringView other) { >+ StealMembers(std::move(other)); >+ return *this; >+ } >+ >+ absl::string_view value() const { return value_; } >+ >+ private: >+ // Returns true if ctsp's value refers to its internal copy_ member. >+ bool IsSelfReferential() const { return value_.data() == copy_.data(); } >+ >+ void StealMembers(ConvertibleToStringView&& other) { >+ if (other.IsSelfReferential()) { >+ copy_ = std::move(other.copy_); >+ value_ = copy_; >+ other.value_ = other.copy_; >+ } else { >+ value_ = other.value_; >+ } >+ } >+ >+ // Holds the data moved from temporary std::string arguments. Declared first so >+ // that 'value' can refer to 'copy_'. >+ std::string copy_; >+ absl::string_view value_; >+}; >+ >+// An iterator that enumerates the parts of a std::string from a Splitter. The text >+// to be split, the Delimiter, and the Predicate are all taken from the given >+// Splitter object. Iterators may only be compared if they refer to the same >+// Splitter instance. >+// >+// This class is NOT part of the public splitting API. >+template <typename Splitter> >+class SplitIterator { >+ public: >+ using iterator_category = std::input_iterator_tag; >+ using value_type = absl::string_view; >+ using difference_type = ptrdiff_t; >+ using pointer = const value_type*; >+ using reference = const value_type&; >+ >+ enum State { kInitState, kLastState, kEndState }; >+ SplitIterator(State state, const Splitter* splitter) >+ : pos_(0), >+ state_(state), >+ splitter_(splitter), >+ delimiter_(splitter->delimiter()), >+ predicate_(splitter->predicate()) { >+ // Hack to maintain backward compatibility. This one block makes it so an >+ // empty absl::string_view whose .data() happens to be nullptr behaves >+ // *differently* from an otherwise empty absl::string_view whose .data() is >+ // not nullptr. This is an undesirable difference in general, but this >+ // behavior is maintained to avoid breaking existing code that happens to >+ // depend on this old behavior/bug. Perhaps it will be fixed one day. The >+ // difference in behavior is as follows: >+ // Split(absl::string_view(""), '-'); // {""} >+ // Split(absl::string_view(), '-'); // {} >+ if (splitter_->text().data() == nullptr) { >+ state_ = kEndState; >+ pos_ = splitter_->text().size(); >+ return; >+ } >+ >+ if (state_ == kEndState) { >+ pos_ = splitter_->text().size(); >+ } else { >+ ++(*this); >+ } >+ } >+ >+ bool at_end() const { return state_ == kEndState; } >+ >+ reference operator*() const { return curr_; } >+ pointer operator->() const { return &curr_; } >+ >+ SplitIterator& operator++() { >+ do { >+ if (state_ == kLastState) { >+ state_ = kEndState; >+ return *this; >+ } >+ const absl::string_view text = splitter_->text(); >+ const absl::string_view d = delimiter_.Find(text, pos_); >+ if (d.data() == text.end()) state_ = kLastState; >+ curr_ = text.substr(pos_, d.data() - (text.data() + pos_)); >+ pos_ += curr_.size() + d.size(); >+ } while (!predicate_(curr_)); >+ return *this; >+ } >+ >+ SplitIterator operator++(int) { >+ SplitIterator old(*this); >+ ++(*this); >+ return old; >+ } >+ >+ friend bool operator==(const SplitIterator& a, const SplitIterator& b) { >+ return a.state_ == b.state_ && a.pos_ == b.pos_; >+ } >+ >+ friend bool operator!=(const SplitIterator& a, const SplitIterator& b) { >+ return !(a == b); >+ } >+ >+ private: >+ size_t pos_; >+ State state_; >+ absl::string_view curr_; >+ const Splitter* splitter_; >+ typename Splitter::DelimiterType delimiter_; >+ typename Splitter::PredicateType predicate_; >+}; >+ >+// HasMappedType<T>::value is true iff there exists a type T::mapped_type. >+template <typename T, typename = void> >+struct HasMappedType : std::false_type {}; >+template <typename T> >+struct HasMappedType<T, absl::void_t<typename T::mapped_type>> >+ : std::true_type {}; >+ >+// HasValueType<T>::value is true iff there exists a type T::value_type. >+template <typename T, typename = void> >+struct HasValueType : std::false_type {}; >+template <typename T> >+struct HasValueType<T, absl::void_t<typename T::value_type>> : std::true_type { >+}; >+ >+// HasConstIterator<T>::value is true iff there exists a type T::const_iterator. >+template <typename T, typename = void> >+struct HasConstIterator : std::false_type {}; >+template <typename T> >+struct HasConstIterator<T, absl::void_t<typename T::const_iterator>> >+ : std::true_type {}; >+ >+// IsInitializerList<T>::value is true iff T is an std::initializer_list. More >+// details below in Splitter<> where this is used. >+std::false_type IsInitializerListDispatch(...); // default: No >+template <typename T> >+std::true_type IsInitializerListDispatch(std::initializer_list<T>*); >+template <typename T> >+struct IsInitializerList >+ : decltype(IsInitializerListDispatch(static_cast<T*>(nullptr))) {}; >+ >+// A SplitterIsConvertibleTo<C>::type alias exists iff the specified condition >+// is true for type 'C'. >+// >+// Restricts conversion to container-like types (by testing for the presence of >+// a const_iterator member type) and also to disable conversion to an >+// std::initializer_list (which also has a const_iterator). Otherwise, code >+// compiled in C++11 will get an error due to ambiguous conversion paths (in >+// C++11 std::vector<T>::operator= is overloaded to take either a std::vector<T> >+// or an std::initializer_list<T>). >+ >+template <typename C, bool has_value_type, bool has_mapped_type> >+struct SplitterIsConvertibleToImpl : std::false_type {}; >+ >+template <typename C> >+struct SplitterIsConvertibleToImpl<C, true, false> >+ : std::is_constructible<typename C::value_type, absl::string_view> {}; >+ >+template <typename C> >+struct SplitterIsConvertibleToImpl<C, true, true> >+ : absl::conjunction< >+ std::is_constructible<typename C::key_type, absl::string_view>, >+ std::is_constructible<typename C::mapped_type, absl::string_view>> {}; >+ >+template <typename C> >+struct SplitterIsConvertibleTo >+ : SplitterIsConvertibleToImpl< >+ C, >+#ifdef _GLIBCXX_DEBUG >+ !IsStrictlyBaseOfAndConvertibleToSTLContainer<C>::value && >+#endif // _GLIBCXX_DEBUG >+ !IsInitializerList< >+ typename std::remove_reference<C>::type>::value && >+ HasValueType<C>::value && HasConstIterator<C>::value, >+ HasMappedType<C>::value> { >+}; >+ >+// This class implements the range that is returned by absl::StrSplit(). This >+// class has templated conversion operators that allow it to be implicitly >+// converted to a variety of types that the caller may have specified on the >+// left-hand side of an assignment. >+// >+// The main interface for interacting with this class is through its implicit >+// conversion operators. However, this class may also be used like a container >+// in that it has .begin() and .end() member functions. It may also be used >+// within a range-for loop. >+// >+// Output containers can be collections of any type that is constructible from >+// an absl::string_view. >+// >+// An Predicate functor may be supplied. This predicate will be used to filter >+// the split strings: only strings for which the predicate returns true will be >+// kept. A Predicate object is any unary functor that takes an absl::string_view >+// and returns bool. >+template <typename Delimiter, typename Predicate> >+class Splitter { >+ public: >+ using DelimiterType = Delimiter; >+ using PredicateType = Predicate; >+ using const_iterator = strings_internal::SplitIterator<Splitter>; >+ using value_type = typename std::iterator_traits<const_iterator>::value_type; >+ >+ Splitter(ConvertibleToStringView input_text, Delimiter d, Predicate p) >+ : text_(std::move(input_text)), >+ delimiter_(std::move(d)), >+ predicate_(std::move(p)) {} >+ >+ absl::string_view text() const { return text_.value(); } >+ const Delimiter& delimiter() const { return delimiter_; } >+ const Predicate& predicate() const { return predicate_; } >+ >+ // Range functions that iterate the split substrings as absl::string_view >+ // objects. These methods enable a Splitter to be used in a range-based for >+ // loop. >+ const_iterator begin() const { return {const_iterator::kInitState, this}; } >+ const_iterator end() const { return {const_iterator::kEndState, this}; } >+ >+ // An implicit conversion operator that is restricted to only those containers >+ // that the splitter is convertible to. >+ template <typename Container, >+ typename = typename std::enable_if< >+ SplitterIsConvertibleTo<Container>::value>::type> >+ operator Container() const { // NOLINT(runtime/explicit) >+ return ConvertToContainer<Container, typename Container::value_type, >+ HasMappedType<Container>::value>()(*this); >+ } >+ >+ // Returns a pair with its .first and .second members set to the first two >+ // strings returned by the begin() iterator. Either/both of .first and .second >+ // will be constructed with empty strings if the iterator doesn't have a >+ // corresponding value. >+ template <typename First, typename Second> >+ operator std::pair<First, Second>() const { // NOLINT(runtime/explicit) >+ absl::string_view first, second; >+ auto it = begin(); >+ if (it != end()) { >+ first = *it; >+ if (++it != end()) { >+ second = *it; >+ } >+ } >+ return {First(first), Second(second)}; >+ } >+ >+ private: >+ // ConvertToContainer is a functor converting a Splitter to the requested >+ // Container of ValueType. It is specialized below to optimize splitting to >+ // certain combinations of Container and ValueType. >+ // >+ // This base template handles the generic case of storing the split results in >+ // the requested non-map-like container and converting the split substrings to >+ // the requested type. >+ template <typename Container, typename ValueType, bool is_map = false> >+ struct ConvertToContainer { >+ Container operator()(const Splitter& splitter) const { >+ Container c; >+ auto it = std::inserter(c, c.end()); >+ for (const auto sp : splitter) { >+ *it++ = ValueType(sp); >+ } >+ return c; >+ } >+ }; >+ >+ // Partial specialization for a std::vector<absl::string_view>. >+ // >+ // Optimized for the common case of splitting to a >+ // std::vector<absl::string_view>. In this case we first split the results to >+ // a small array of absl::string_view on the stack, to reduce reallocations. >+ template <typename A> >+ struct ConvertToContainer<std::vector<absl::string_view, A>, >+ absl::string_view, false> { >+ std::vector<absl::string_view, A> operator()( >+ const Splitter& splitter) const { >+ struct raw_view { >+ const char* data; >+ size_t size; >+ operator absl::string_view() const { // NOLINT(runtime/explicit) >+ return {data, size}; >+ } >+ }; >+ std::vector<absl::string_view, A> v; >+ std::array<raw_view, 16> ar; >+ for (auto it = splitter.begin(); !it.at_end();) { >+ size_t index = 0; >+ do { >+ ar[index].data = it->data(); >+ ar[index].size = it->size(); >+ ++it; >+ } while (++index != ar.size() && !it.at_end()); >+ v.insert(v.end(), ar.begin(), ar.begin() + index); >+ } >+ return v; >+ } >+ }; >+ >+ // Partial specialization for a std::vector<std::string>. >+ // >+ // Optimized for the common case of splitting to a std::vector<std::string>. In >+ // this case we first split the results to a std::vector<absl::string_view> so >+ // the returned std::vector<std::string> can have space reserved to avoid std::string >+ // moves. >+ template <typename A> >+ struct ConvertToContainer<std::vector<std::string, A>, std::string, false> { >+ std::vector<std::string, A> operator()(const Splitter& splitter) const { >+ const std::vector<absl::string_view> v = splitter; >+ return std::vector<std::string, A>(v.begin(), v.end()); >+ } >+ }; >+ >+ // Partial specialization for containers of pairs (e.g., maps). >+ // >+ // The algorithm is to insert a new pair into the map for each even-numbered >+ // item, with the even-numbered item as the key with a default-constructed >+ // value. Each odd-numbered item will then be assigned to the last pair's >+ // value. >+ template <typename Container, typename First, typename Second> >+ struct ConvertToContainer<Container, std::pair<const First, Second>, true> { >+ Container operator()(const Splitter& splitter) const { >+ Container m; >+ typename Container::iterator it; >+ bool insert = true; >+ for (const auto sp : splitter) { >+ if (insert) { >+ it = Inserter<Container>::Insert(&m, First(sp), Second()); >+ } else { >+ it->second = Second(sp); >+ } >+ insert = !insert; >+ } >+ return m; >+ } >+ >+ // Inserts the key and value into the given map, returning an iterator to >+ // the inserted item. Specialized for std::map and std::multimap to use >+ // emplace() and adapt emplace()'s return value. >+ template <typename Map> >+ struct Inserter { >+ using M = Map; >+ template <typename... Args> >+ static typename M::iterator Insert(M* m, Args&&... args) { >+ return m->insert(std::make_pair(std::forward<Args>(args)...)).first; >+ } >+ }; >+ >+ template <typename... Ts> >+ struct Inserter<std::map<Ts...>> { >+ using M = std::map<Ts...>; >+ template <typename... Args> >+ static typename M::iterator Insert(M* m, Args&&... args) { >+ return m->emplace(std::make_pair(std::forward<Args>(args)...)).first; >+ } >+ }; >+ >+ template <typename... Ts> >+ struct Inserter<std::multimap<Ts...>> { >+ using M = std::multimap<Ts...>; >+ template <typename... Args> >+ static typename M::iterator Insert(M* m, Args&&... args) { >+ return m->emplace(std::make_pair(std::forward<Args>(args)...)); >+ } >+ }; >+ }; >+ >+ ConvertibleToStringView text_; >+ Delimiter delimiter_; >+ Predicate predicate_; >+}; >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_STR_SPLIT_INTERNAL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.cc >new file mode 100644 >index 00000000000..2415c2ccc45 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.cc >@@ -0,0 +1,51 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// UTF8 utilities, implemented to reduce dependencies. >+ >+#include "absl/strings/internal/utf8.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char) { >+ if (utf8_char <= 0x7F) { >+ *buffer = static_cast<char>(utf8_char); >+ return 1; >+ } else if (utf8_char <= 0x7FF) { >+ buffer[1] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[0] = 0xC0 | utf8_char; >+ return 2; >+ } else if (utf8_char <= 0xFFFF) { >+ buffer[2] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[1] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[0] = 0xE0 | utf8_char; >+ return 3; >+ } else { >+ buffer[3] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[2] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[1] = 0x80 | (utf8_char & 0x3F); >+ utf8_char >>= 6; >+ buffer[0] = 0xF0 | utf8_char; >+ return 4; >+ } >+} >+ >+} // namespace strings_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.h >new file mode 100644 >index 00000000000..d2c3c0b0120 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8.h >@@ -0,0 +1,47 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// UTF8 utilities, implemented to reduce dependencies. >+// >+ >+#ifndef ABSL_STRINGS_INTERNAL_UTF8_H_ >+#define ABSL_STRINGS_INTERNAL_UTF8_H_ >+ >+#include <cstddef> >+#include <cstdint> >+ >+namespace absl { >+namespace strings_internal { >+ >+// For Unicode code points 0 through 0x10FFFF, EncodeUTF8Char writes >+// out the UTF-8 encoding into buffer, and returns the number of chars >+// it wrote. >+// >+// As described in https://tools.ietf.org/html/rfc3629#section-3 , the encodings >+// are: >+// 00 - 7F : 0xxxxxxx >+// 80 - 7FF : 110xxxxx 10xxxxxx >+// 800 - FFFF : 1110xxxx 10xxxxxx 10xxxxxx >+// 10000 - 10FFFF : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx >+// >+// Values greater than 0x10FFFF are not supported and may or may not write >+// characters into buffer, however never will more than kMaxEncodedUTF8Size >+// bytes be written, regardless of the value of utf8_char. >+enum { kMaxEncodedUTF8Size = 4 }; >+size_t EncodeUTF8Char(char *buffer, char32_t utf8_char); >+ >+} // namespace strings_internal >+} // namespace absl >+ >+#endif // ABSL_STRINGS_INTERNAL_UTF8_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc >new file mode 100644 >index 00000000000..64cec70df7e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/internal/utf8_test.cc >@@ -0,0 +1,57 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/internal/utf8.h" >+ >+#include <cstdint> >+#include <utility> >+ >+#include "gtest/gtest.h" >+#include "absl/base/port.h" >+ >+namespace { >+ >+TEST(EncodeUTF8Char, BasicFunction) { >+ std::pair<char32_t, std::string> tests[] = {{0x0030, u8"\u0030"}, >+ {0x00A3, u8"\u00A3"}, >+ {0x00010000, u8"\U00010000"}, >+ {0x0000FFFF, u8"\U0000FFFF"}, >+ {0x0010FFFD, u8"\U0010FFFD"}}; >+ for (auto &test : tests) { >+ char buf0[7] = {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; >+ char buf1[7] = {'\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'}; >+ char *buf0_written = >+ &buf0[absl::strings_internal::EncodeUTF8Char(buf0, test.first)]; >+ char *buf1_written = >+ &buf1[absl::strings_internal::EncodeUTF8Char(buf1, test.first)]; >+ int apparent_length = 7; >+ while (buf0[apparent_length - 1] == '\x00' && >+ buf1[apparent_length - 1] == '\xFF') { >+ if (--apparent_length == 0) break; >+ } >+ EXPECT_EQ(apparent_length, buf0_written - buf0); >+ EXPECT_EQ(apparent_length, buf1_written - buf1); >+ EXPECT_EQ(apparent_length, test.second.length()); >+ EXPECT_EQ(std::string(buf0, apparent_length), test.second); >+ EXPECT_EQ(std::string(buf1, apparent_length), test.second); >+ } >+ char buf[32] = "Don't Tread On Me"; >+ EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf, 0x00110000), >+ absl::strings_internal::kMaxEncodedUTF8Size); >+ char buf2[32] = "Negative is invalid but sane"; >+ EXPECT_LE(absl::strings_internal::EncodeUTF8Char(buf2, -1), >+ absl::strings_internal::kMaxEncodedUTF8Size); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.cc >new file mode 100644 >index 00000000000..25bd7f0b828 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.cc >@@ -0,0 +1,40 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/match.h" >+ >+#include "absl/strings/internal/memutil.h" >+ >+namespace absl { >+ >+namespace { >+bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { >+ return (piece1.size() == piece2.size() && >+ 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), >+ piece1.size())); >+ // memcasecmp uses ascii_tolower(). >+} >+} // namespace >+ >+bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix) { >+ return (text.size() >= prefix.size()) && >+ CaseEqual(text.substr(0, prefix.size()), prefix); >+} >+ >+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix) { >+ return (text.size() >= suffix.size()) && >+ CaseEqual(text.substr(text.size() - suffix.size()), suffix); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.h >new file mode 100644 >index 00000000000..108b6048b04 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match.h >@@ -0,0 +1,83 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: match.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains simple utilities for performing std::string matching checks. >+// All of these function parameters are specified as `absl::string_view`, >+// meaning that these functions can accept `std::string`, `absl::string_view` or >+// nul-terminated C-style strings. >+// >+// Examples: >+// std::string s = "foo"; >+// absl::string_view sv = "f"; >+// assert(absl::StrContains(s, sv)); >+// >+// Note: The order of parameters in these functions is designed to mimic the >+// order an equivalent member function would exhibit; >+// e.g. `s.Contains(x)` ==> `absl::StrContains(s, x). >+#ifndef ABSL_STRINGS_MATCH_H_ >+#define ABSL_STRINGS_MATCH_H_ >+ >+#include <cstring> >+ >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// StrContains() >+// >+// Returns whether a given std::string `haystack` contains the substring `needle`. >+inline bool StrContains(absl::string_view haystack, absl::string_view needle) { >+ return haystack.find(needle, 0) != haystack.npos; >+} >+ >+// StartsWith() >+// >+// Returns whether a given std::string `text` begins with `prefix`. >+inline bool StartsWith(absl::string_view text, absl::string_view prefix) { >+ return prefix.empty() || >+ (text.size() >= prefix.size() && >+ memcmp(text.data(), prefix.data(), prefix.size()) == 0); >+} >+ >+// EndsWith() >+// >+// Returns whether a given std::string `text` ends with `suffix`. >+inline bool EndsWith(absl::string_view text, absl::string_view suffix) { >+ return suffix.empty() || >+ (text.size() >= suffix.size() && >+ memcmp(text.data() + (text.size() - suffix.size()), suffix.data(), >+ suffix.size()) == 0 >+ ); >+} >+ >+// StartsWithIgnoreCase() >+// >+// Returns whether a given std::string `text` starts with `starts_with`, ignoring >+// case in the comparison. >+bool StartsWithIgnoreCase(absl::string_view text, absl::string_view prefix); >+ >+// EndsWithIgnoreCase() >+// >+// Returns whether a given std::string `text` ends with `ends_with`, ignoring case >+// in the comparison. >+bool EndsWithIgnoreCase(absl::string_view text, absl::string_view suffix); >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_MATCH_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match_test.cc >new file mode 100644 >index 00000000000..d194f0e689b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/match_test.cc >@@ -0,0 +1,99 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/match.h" >+ >+#include "gtest/gtest.h" >+ >+namespace { >+ >+TEST(MatchTest, StartsWith) { >+ const std::string s1("123" "\0" "456", 7); >+ const absl::string_view a("foobar"); >+ const absl::string_view b(s1); >+ const absl::string_view e; >+ EXPECT_TRUE(absl::StartsWith(a, a)); >+ EXPECT_TRUE(absl::StartsWith(a, "foo")); >+ EXPECT_TRUE(absl::StartsWith(a, e)); >+ EXPECT_TRUE(absl::StartsWith(b, s1)); >+ EXPECT_TRUE(absl::StartsWith(b, b)); >+ EXPECT_TRUE(absl::StartsWith(b, e)); >+ EXPECT_TRUE(absl::StartsWith(e, "")); >+ EXPECT_FALSE(absl::StartsWith(a, b)); >+ EXPECT_FALSE(absl::StartsWith(b, a)); >+ EXPECT_FALSE(absl::StartsWith(e, a)); >+} >+ >+TEST(MatchTest, EndsWith) { >+ const std::string s1("123" "\0" "456", 7); >+ const absl::string_view a("foobar"); >+ const absl::string_view b(s1); >+ const absl::string_view e; >+ EXPECT_TRUE(absl::EndsWith(a, a)); >+ EXPECT_TRUE(absl::EndsWith(a, "bar")); >+ EXPECT_TRUE(absl::EndsWith(a, e)); >+ EXPECT_TRUE(absl::EndsWith(b, s1)); >+ EXPECT_TRUE(absl::EndsWith(b, b)); >+ EXPECT_TRUE(absl::EndsWith(b, e)); >+ EXPECT_TRUE(absl::EndsWith(e, "")); >+ EXPECT_FALSE(absl::EndsWith(a, b)); >+ EXPECT_FALSE(absl::EndsWith(b, a)); >+ EXPECT_FALSE(absl::EndsWith(e, a)); >+} >+ >+TEST(MatchTest, Contains) { >+ absl::string_view a("abcdefg"); >+ absl::string_view b("abcd"); >+ absl::string_view c("efg"); >+ absl::string_view d("gh"); >+ EXPECT_TRUE(absl::StrContains(a, a)); >+ EXPECT_TRUE(absl::StrContains(a, b)); >+ EXPECT_TRUE(absl::StrContains(a, c)); >+ EXPECT_FALSE(absl::StrContains(a, d)); >+ EXPECT_TRUE(absl::StrContains("", "")); >+ EXPECT_TRUE(absl::StrContains("abc", "")); >+ EXPECT_FALSE(absl::StrContains("", "a")); >+} >+ >+TEST(MatchTest, ContainsNull) { >+ const std::string s = "foo"; >+ const char* cs = "foo"; >+ const absl::string_view sv("foo"); >+ const absl::string_view sv2("foo\0bar", 4); >+ EXPECT_EQ(s, "foo"); >+ EXPECT_EQ(sv, "foo"); >+ EXPECT_NE(sv2, "foo"); >+ EXPECT_TRUE(absl::EndsWith(s, sv)); >+ EXPECT_TRUE(absl::StartsWith(cs, sv)); >+ EXPECT_TRUE(absl::StrContains(cs, sv)); >+ EXPECT_FALSE(absl::StrContains(cs, sv2)); >+} >+ >+TEST(MatchTest, StartsWithIgnoreCase) { >+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "foo")); >+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "Fo")); >+ EXPECT_TRUE(absl::StartsWithIgnoreCase("foo", "")); >+ EXPECT_FALSE(absl::StartsWithIgnoreCase("foo", "fooo")); >+ EXPECT_FALSE(absl::StartsWithIgnoreCase("", "fo")); >+} >+ >+TEST(MatchTest, EndsWithIgnoreCase) { >+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "foo")); >+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "Oo")); >+ EXPECT_TRUE(absl::EndsWithIgnoreCase("foo", "")); >+ EXPECT_FALSE(absl::EndsWithIgnoreCase("foo", "fooo")); >+ EXPECT_FALSE(absl::EndsWithIgnoreCase("", "fo")); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.cc >new file mode 100644 >index 00000000000..f842ed85e9f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.cc >@@ -0,0 +1,912 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains std::string processing functions related to >+// numeric values. >+ >+#include "absl/strings/numbers.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <cfloat> // for DBL_DIG and FLT_DIG >+#include <cmath> // for HUGE_VAL >+#include <cstdint> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+#include <iterator> >+#include <limits> >+#include <memory> >+#include <utility> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/ascii.h" >+#include "absl/strings/charconv.h" >+#include "absl/strings/internal/bits.h" >+#include "absl/strings/internal/memutil.h" >+#include "absl/strings/str_cat.h" >+ >+namespace absl { >+ >+bool SimpleAtof(absl::string_view str, float* value) { >+ *value = 0.0; >+ str = StripAsciiWhitespace(str); >+ if (!str.empty() && str[0] == '+') { >+ str.remove_prefix(1); >+ } >+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); >+ if (result.ec == std::errc::invalid_argument) { >+ return false; >+ } >+ if (result.ptr != str.data() + str.size()) { >+ // not all non-whitespace characters consumed >+ return false; >+ } >+ // from_chars() with DR 3801's current wording will return max() on >+ // overflow. SimpleAtof returns infinity instead. >+ if (result.ec == std::errc::result_out_of_range) { >+ if (*value > 1.0) { >+ *value = std::numeric_limits<float>::infinity(); >+ } else if (*value < -1.0) { >+ *value = -std::numeric_limits<float>::infinity(); >+ } >+ } >+ return true; >+} >+ >+bool SimpleAtod(absl::string_view str, double* value) { >+ *value = 0.0; >+ str = StripAsciiWhitespace(str); >+ if (!str.empty() && str[0] == '+') { >+ str.remove_prefix(1); >+ } >+ auto result = absl::from_chars(str.data(), str.data() + str.size(), *value); >+ if (result.ec == std::errc::invalid_argument) { >+ return false; >+ } >+ if (result.ptr != str.data() + str.size()) { >+ // not all non-whitespace characters consumed >+ return false; >+ } >+ // from_chars() with DR 3801's current wording will return max() on >+ // overflow. SimpleAtod returns infinity instead. >+ if (result.ec == std::errc::result_out_of_range) { >+ if (*value > 1.0) { >+ *value = std::numeric_limits<double>::infinity(); >+ } else if (*value < -1.0) { >+ *value = -std::numeric_limits<double>::infinity(); >+ } >+ } >+ return true; >+} >+ >+namespace { >+ >+// TODO(rogeeff): replace with the real released thing once we figure out what >+// it is. >+inline bool CaseEqual(absl::string_view piece1, absl::string_view piece2) { >+ return (piece1.size() == piece2.size() && >+ 0 == strings_internal::memcasecmp(piece1.data(), piece2.data(), >+ piece1.size())); >+} >+ >+// Writes a two-character representation of 'i' to 'buf'. 'i' must be in the >+// range 0 <= i < 100, and buf must have space for two characters. Example: >+// char buf[2]; >+// PutTwoDigits(42, buf); >+// // buf[0] == '4' >+// // buf[1] == '2' >+inline void PutTwoDigits(size_t i, char* buf) { >+ static const char two_ASCII_digits[100][2] = { >+ {'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, >+ {'0', '5'}, {'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, >+ {'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, >+ {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '9'}, >+ {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'}, {'2', '4'}, >+ {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'}, >+ {'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, >+ {'3', '5'}, {'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, >+ {'4', '0'}, {'4', '1'}, {'4', '2'}, {'4', '3'}, {'4', '4'}, >+ {'4', '5'}, {'4', '6'}, {'4', '7'}, {'4', '8'}, {'4', '9'}, >+ {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'}, {'5', '4'}, >+ {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'}, >+ {'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, >+ {'6', '5'}, {'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, >+ {'7', '0'}, {'7', '1'}, {'7', '2'}, {'7', '3'}, {'7', '4'}, >+ {'7', '5'}, {'7', '6'}, {'7', '7'}, {'7', '8'}, {'7', '9'}, >+ {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'}, {'8', '4'}, >+ {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'}, >+ {'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, >+ {'9', '5'}, {'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'} >+ }; >+ assert(i < 100); >+ memcpy(buf, two_ASCII_digits[i], 2); >+} >+ >+} // namespace >+ >+bool SimpleAtob(absl::string_view str, bool* value) { >+ ABSL_RAW_CHECK(value != nullptr, "Output pointer must not be nullptr."); >+ if (CaseEqual(str, "true") || CaseEqual(str, "t") || >+ CaseEqual(str, "yes") || CaseEqual(str, "y") || >+ CaseEqual(str, "1")) { >+ *value = true; >+ return true; >+ } >+ if (CaseEqual(str, "false") || CaseEqual(str, "f") || >+ CaseEqual(str, "no") || CaseEqual(str, "n") || >+ CaseEqual(str, "0")) { >+ *value = false; >+ return true; >+ } >+ return false; >+} >+ >+// ---------------------------------------------------------------------- >+// FastIntToBuffer() overloads >+// >+// Like the Fast*ToBuffer() functions above, these are intended for speed. >+// Unlike the Fast*ToBuffer() functions, however, these functions write >+// their output to the beginning of the buffer. The caller is responsible >+// for ensuring that the buffer has enough space to hold the output. >+// >+// Returns a pointer to the end of the std::string (i.e. the null character >+// terminating the std::string). >+// ---------------------------------------------------------------------- >+ >+namespace { >+ >+// Used to optimize printing a decimal number's final digit. >+const char one_ASCII_final_digits[10][2] { >+ {'0', 0}, {'1', 0}, {'2', 0}, {'3', 0}, {'4', 0}, >+ {'5', 0}, {'6', 0}, {'7', 0}, {'8', 0}, {'9', 0}, >+}; >+ >+} // namespace >+ >+char* numbers_internal::FastIntToBuffer(uint32_t i, char* buffer) { >+ uint32_t digits; >+ // The idea of this implementation is to trim the number of divides to as few >+ // as possible, and also reducing memory stores and branches, by going in >+ // steps of two digits at a time rather than one whenever possible. >+ // The huge-number case is first, in the hopes that the compiler will output >+ // that case in one branch-free block of code, and only output conditional >+ // branches into it from below. >+ if (i >= 1000000000) { // >= 1,000,000,000 >+ digits = i / 100000000; // 100,000,000 >+ i -= digits * 100000000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ lt100_000_000: >+ digits = i / 1000000; // 1,000,000 >+ i -= digits * 1000000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ lt1_000_000: >+ digits = i / 10000; // 10,000 >+ i -= digits * 10000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ lt10_000: >+ digits = i / 100; >+ i -= digits * 100; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ lt100: >+ digits = i; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ *buffer = 0; >+ return buffer; >+ } >+ >+ if (i < 100) { >+ digits = i; >+ if (i >= 10) goto lt100; >+ memcpy(buffer, one_ASCII_final_digits[i], 2); >+ return buffer + 1; >+ } >+ if (i < 10000) { // 10,000 >+ if (i >= 1000) goto lt10_000; >+ digits = i / 100; >+ i -= digits * 100; >+ *buffer++ = '0' + digits; >+ goto lt100; >+ } >+ if (i < 1000000) { // 1,000,000 >+ if (i >= 100000) goto lt1_000_000; >+ digits = i / 10000; // 10,000 >+ i -= digits * 10000; >+ *buffer++ = '0' + digits; >+ goto lt10_000; >+ } >+ if (i < 100000000) { // 100,000,000 >+ if (i >= 10000000) goto lt100_000_000; >+ digits = i / 1000000; // 1,000,000 >+ i -= digits * 1000000; >+ *buffer++ = '0' + digits; >+ goto lt1_000_000; >+ } >+ // we already know that i < 1,000,000,000 >+ digits = i / 100000000; // 100,000,000 >+ i -= digits * 100000000; >+ *buffer++ = '0' + digits; >+ goto lt100_000_000; >+} >+ >+char* numbers_internal::FastIntToBuffer(int32_t i, char* buffer) { >+ uint32_t u = i; >+ if (i < 0) { >+ *buffer++ = '-'; >+ // We need to do the negation in modular (i.e., "unsigned") >+ // arithmetic; MSVC++ apprently warns for plain "-u", so >+ // we write the equivalent expression "0 - u" instead. >+ u = 0 - u; >+ } >+ return numbers_internal::FastIntToBuffer(u, buffer); >+} >+ >+char* numbers_internal::FastIntToBuffer(uint64_t i, char* buffer) { >+ uint32_t u32 = static_cast<uint32_t>(i); >+ if (u32 == i) return numbers_internal::FastIntToBuffer(u32, buffer); >+ >+ // Here we know i has at least 10 decimal digits. >+ uint64_t top_1to11 = i / 1000000000; >+ u32 = static_cast<uint32_t>(i - top_1to11 * 1000000000); >+ uint32_t top_1to11_32 = static_cast<uint32_t>(top_1to11); >+ >+ if (top_1to11_32 == top_1to11) { >+ buffer = numbers_internal::FastIntToBuffer(top_1to11_32, buffer); >+ } else { >+ // top_1to11 has more than 32 bits too; print it in two steps. >+ uint32_t top_8to9 = static_cast<uint32_t>(top_1to11 / 100); >+ uint32_t mid_2 = static_cast<uint32_t>(top_1to11 - top_8to9 * 100); >+ buffer = numbers_internal::FastIntToBuffer(top_8to9, buffer); >+ PutTwoDigits(mid_2, buffer); >+ buffer += 2; >+ } >+ >+ // We have only 9 digits now, again the maximum uint32_t can handle fully. >+ uint32_t digits = u32 / 10000000; // 10,000,000 >+ u32 -= digits * 10000000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ digits = u32 / 100000; // 100,000 >+ u32 -= digits * 100000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ digits = u32 / 1000; // 1,000 >+ u32 -= digits * 1000; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ digits = u32 / 10; >+ u32 -= digits * 10; >+ PutTwoDigits(digits, buffer); >+ buffer += 2; >+ memcpy(buffer, one_ASCII_final_digits[u32], 2); >+ return buffer + 1; >+} >+ >+char* numbers_internal::FastIntToBuffer(int64_t i, char* buffer) { >+ uint64_t u = i; >+ if (i < 0) { >+ *buffer++ = '-'; >+ u = 0 - u; >+ } >+ return numbers_internal::FastIntToBuffer(u, buffer); >+} >+ >+// Given a 128-bit number expressed as a pair of uint64_t, high half first, >+// return that number multiplied by the given 32-bit value. If the result is >+// too large to fit in a 128-bit number, divide it by 2 until it fits. >+static std::pair<uint64_t, uint64_t> Mul32(std::pair<uint64_t, uint64_t> num, >+ uint32_t mul) { >+ uint64_t bits0_31 = num.second & 0xFFFFFFFF; >+ uint64_t bits32_63 = num.second >> 32; >+ uint64_t bits64_95 = num.first & 0xFFFFFFFF; >+ uint64_t bits96_127 = num.first >> 32; >+ >+ // The picture so far: each of these 64-bit values has only the lower 32 bits >+ // filled in. >+ // bits96_127: [ 00000000 xxxxxxxx ] >+ // bits64_95: [ 00000000 xxxxxxxx ] >+ // bits32_63: [ 00000000 xxxxxxxx ] >+ // bits0_31: [ 00000000 xxxxxxxx ] >+ >+ bits0_31 *= mul; >+ bits32_63 *= mul; >+ bits64_95 *= mul; >+ bits96_127 *= mul; >+ >+ // Now the top halves may also have value, though all 64 of their bits will >+ // never be set at the same time, since they are a result of a 32x32 bit >+ // multiply. This makes the carry calculation slightly easier. >+ // bits96_127: [ mmmmmmmm | mmmmmmmm ] >+ // bits64_95: [ | mmmmmmmm mmmmmmmm | ] >+ // bits32_63: | [ mmmmmmmm | mmmmmmmm ] >+ // bits0_31: | [ | mmmmmmmm mmmmmmmm ] >+ // eventually: [ bits128_up | ...bits64_127.... | ..bits0_63... ] >+ >+ uint64_t bits0_63 = bits0_31 + (bits32_63 << 32); >+ uint64_t bits64_127 = bits64_95 + (bits96_127 << 32) + (bits32_63 >> 32) + >+ (bits0_63 < bits0_31); >+ uint64_t bits128_up = (bits96_127 >> 32) + (bits64_127 < bits64_95); >+ if (bits128_up == 0) return {bits64_127, bits0_63}; >+ >+ int shift = 64 - strings_internal::CountLeadingZeros64(bits128_up); >+ uint64_t lo = (bits0_63 >> shift) + (bits64_127 << (64 - shift)); >+ uint64_t hi = (bits64_127 >> shift) + (bits128_up << (64 - shift)); >+ return {hi, lo}; >+} >+ >+// Compute num * 5 ^ expfive, and return the first 128 bits of the result, >+// where the first bit is always a one. So PowFive(1, 0) starts 0b100000, >+// PowFive(1, 1) starts 0b101000, PowFive(1, 2) starts 0b110010, etc. >+static std::pair<uint64_t, uint64_t> PowFive(uint64_t num, int expfive) { >+ std::pair<uint64_t, uint64_t> result = {num, 0}; >+ while (expfive >= 13) { >+ // 5^13 is the highest power of five that will fit in a 32-bit integer. >+ result = Mul32(result, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5); >+ expfive -= 13; >+ } >+ constexpr int powers_of_five[13] = { >+ 1, >+ 5, >+ 5 * 5, >+ 5 * 5 * 5, >+ 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, >+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5}; >+ result = Mul32(result, powers_of_five[expfive & 15]); >+ int shift = strings_internal::CountLeadingZeros64(result.first); >+ if (shift != 0) { >+ result.first = (result.first << shift) + (result.second >> (64 - shift)); >+ result.second = (result.second << shift); >+ } >+ return result; >+} >+ >+struct ExpDigits { >+ int32_t exponent; >+ char digits[6]; >+}; >+ >+// SplitToSix converts value, a positive double-precision floating-point number, >+// into a base-10 exponent and 6 ASCII digits, where the first digit is never >+// zero. For example, SplitToSix(1) returns an exponent of zero and a digits >+// array of {'1', '0', '0', '0', '0', '0'}. If value is exactly halfway between >+// two possible representations, e.g. value = 100000.5, then "round to even" is >+// performed. >+static ExpDigits SplitToSix(const double value) { >+ ExpDigits exp_dig; >+ int exp = 5; >+ double d = value; >+ // First step: calculate a close approximation of the output, where the >+ // value d will be between 100,000 and 999,999, representing the digits >+ // in the output ASCII array, and exp is the base-10 exponent. It would be >+ // faster to use a table here, and to look up the base-2 exponent of value, >+ // however value is an IEEE-754 64-bit number, so the table would have 2,000 >+ // entries, which is not cache-friendly. >+ if (d >= 999999.5) { >+ if (d >= 1e+261) exp += 256, d *= 1e-256; >+ if (d >= 1e+133) exp += 128, d *= 1e-128; >+ if (d >= 1e+69) exp += 64, d *= 1e-64; >+ if (d >= 1e+37) exp += 32, d *= 1e-32; >+ if (d >= 1e+21) exp += 16, d *= 1e-16; >+ if (d >= 1e+13) exp += 8, d *= 1e-8; >+ if (d >= 1e+9) exp += 4, d *= 1e-4; >+ if (d >= 1e+7) exp += 2, d *= 1e-2; >+ if (d >= 1e+6) exp += 1, d *= 1e-1; >+ } else { >+ if (d < 1e-250) exp -= 256, d *= 1e256; >+ if (d < 1e-122) exp -= 128, d *= 1e128; >+ if (d < 1e-58) exp -= 64, d *= 1e64; >+ if (d < 1e-26) exp -= 32, d *= 1e32; >+ if (d < 1e-10) exp -= 16, d *= 1e16; >+ if (d < 1e-2) exp -= 8, d *= 1e8; >+ if (d < 1e+2) exp -= 4, d *= 1e4; >+ if (d < 1e+4) exp -= 2, d *= 1e2; >+ if (d < 1e+5) exp -= 1, d *= 1e1; >+ } >+ // At this point, d is in the range [99999.5..999999.5) and exp is in the >+ // range [-324..308]. Since we need to round d up, we want to add a half >+ // and truncate. >+ // However, the technique above may have lost some precision, due to its >+ // repeated multiplication by constants that each may be off by half a bit >+ // of precision. This only matters if we're close to the edge though. >+ // Since we'd like to know if the fractional part of d is close to a half, >+ // we multiply it by 65536 and see if the fractional part is close to 32768. >+ // (The number doesn't have to be a power of two,but powers of two are faster) >+ uint64_t d64k = d * 65536; >+ int dddddd; // A 6-digit decimal integer. >+ if ((d64k % 65536) == 32767 || (d64k % 65536) == 32768) { >+ // OK, it's fairly likely that precision was lost above, which is >+ // not a surprise given only 52 mantissa bits are available. Therefore >+ // redo the calculation using 128-bit numbers. (64 bits are not enough). >+ >+ // Start out with digits rounded down; maybe add one below. >+ dddddd = static_cast<int>(d64k / 65536); >+ >+ // mantissa is a 64-bit integer representing M.mmm... * 2^63. The actual >+ // value we're representing, of course, is M.mmm... * 2^exp2. >+ int exp2; >+ double m = std::frexp(value, &exp2); >+ uint64_t mantissa = m * (32768.0 * 65536.0 * 65536.0 * 65536.0); >+ // std::frexp returns an m value in the range [0.5, 1.0), however we >+ // can't multiply it by 2^64 and convert to an integer because some FPUs >+ // throw an exception when converting an number higher than 2^63 into an >+ // integer - even an unsigned 64-bit integer! Fortunately it doesn't matter >+ // since m only has 52 significant bits anyway. >+ mantissa <<= 1; >+ exp2 -= 64; // not needed, but nice for debugging >+ >+ // OK, we are here to compare: >+ // (dddddd + 0.5) * 10^(exp-5) vs. mantissa * 2^exp2 >+ // so we can round up dddddd if appropriate. Those values span the full >+ // range of 600 orders of magnitude of IEE 64-bit floating-point. >+ // Fortunately, we already know they are very close, so we don't need to >+ // track the base-2 exponent of both sides. This greatly simplifies the >+ // the math since the 2^exp2 calculation is unnecessary and the power-of-10 >+ // calculation can become a power-of-5 instead. >+ >+ std::pair<uint64_t, uint64_t> edge, val; >+ if (exp >= 6) { >+ // Compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa >+ // Since we're tossing powers of two, 2 * dddddd + 1 is the >+ // same as dddddd + 0.5 >+ edge = PowFive(2 * dddddd + 1, exp - 5); >+ >+ val.first = mantissa; >+ val.second = 0; >+ } else { >+ // We can't compare (dddddd + 0.5) * 5 ^ (exp - 5) to mantissa as we did >+ // above because (exp - 5) is negative. So we compare (dddddd + 0.5) to >+ // mantissa * 5 ^ (5 - exp) >+ edge = PowFive(2 * dddddd + 1, 0); >+ >+ val = PowFive(mantissa, 5 - exp); >+ } >+ // printf("exp=%d %016lx %016lx vs %016lx %016lx\n", exp, val.first, >+ // val.second, edge.first, edge.second); >+ if (val > edge) { >+ dddddd++; >+ } else if (val == edge) { >+ dddddd += (dddddd & 1); >+ } >+ } else { >+ // Here, we are not close to the edge. >+ dddddd = static_cast<int>((d64k + 32768) / 65536); >+ } >+ if (dddddd == 1000000) { >+ dddddd = 100000; >+ exp += 1; >+ } >+ exp_dig.exponent = exp; >+ >+ int two_digits = dddddd / 10000; >+ dddddd -= two_digits * 10000; >+ PutTwoDigits(two_digits, &exp_dig.digits[0]); >+ >+ two_digits = dddddd / 100; >+ dddddd -= two_digits * 100; >+ PutTwoDigits(two_digits, &exp_dig.digits[2]); >+ >+ PutTwoDigits(dddddd, &exp_dig.digits[4]); >+ return exp_dig; >+} >+ >+// Helper function for fast formatting of floating-point. >+// The result is the same as "%g", a.k.a. "%.6g". >+size_t numbers_internal::SixDigitsToBuffer(double d, char* const buffer) { >+ static_assert(std::numeric_limits<float>::is_iec559, >+ "IEEE-754/IEC-559 support only"); >+ >+ char* out = buffer; // we write data to out, incrementing as we go, but >+ // FloatToBuffer always returns the address of the buffer >+ // passed in. >+ >+ if (std::isnan(d)) { >+ strcpy(out, "nan"); // NOLINT(runtime/printf) >+ return 3; >+ } >+ if (d == 0) { // +0 and -0 are handled here >+ if (std::signbit(d)) *out++ = '-'; >+ *out++ = '0'; >+ *out = 0; >+ return out - buffer; >+ } >+ if (d < 0) { >+ *out++ = '-'; >+ d = -d; >+ } >+ if (std::isinf(d)) { >+ strcpy(out, "inf"); // NOLINT(runtime/printf) >+ return out + 3 - buffer; >+ } >+ >+ auto exp_dig = SplitToSix(d); >+ int exp = exp_dig.exponent; >+ const char* digits = exp_dig.digits; >+ out[0] = '0'; >+ out[1] = '.'; >+ switch (exp) { >+ case 5: >+ memcpy(out, &digits[0], 6), out += 6; >+ *out = 0; >+ return out - buffer; >+ case 4: >+ memcpy(out, &digits[0], 5), out += 5; >+ if (digits[5] != '0') { >+ *out++ = '.'; >+ *out++ = digits[5]; >+ } >+ *out = 0; >+ return out - buffer; >+ case 3: >+ memcpy(out, &digits[0], 4), out += 4; >+ if ((digits[5] | digits[4]) != '0') { >+ *out++ = '.'; >+ *out++ = digits[4]; >+ if (digits[5] != '0') *out++ = digits[5]; >+ } >+ *out = 0; >+ return out - buffer; >+ case 2: >+ memcpy(out, &digits[0], 3), out += 3; >+ *out++ = '.'; >+ memcpy(out, &digits[3], 3); >+ out += 3; >+ while (out[-1] == '0') --out; >+ if (out[-1] == '.') --out; >+ *out = 0; >+ return out - buffer; >+ case 1: >+ memcpy(out, &digits[0], 2), out += 2; >+ *out++ = '.'; >+ memcpy(out, &digits[2], 4); >+ out += 4; >+ while (out[-1] == '0') --out; >+ if (out[-1] == '.') --out; >+ *out = 0; >+ return out - buffer; >+ case 0: >+ memcpy(out, &digits[0], 1), out += 1; >+ *out++ = '.'; >+ memcpy(out, &digits[1], 5); >+ out += 5; >+ while (out[-1] == '0') --out; >+ if (out[-1] == '.') --out; >+ *out = 0; >+ return out - buffer; >+ case -4: >+ out[2] = '0'; >+ ++out; >+ ABSL_FALLTHROUGH_INTENDED; >+ case -3: >+ out[2] = '0'; >+ ++out; >+ ABSL_FALLTHROUGH_INTENDED; >+ case -2: >+ out[2] = '0'; >+ ++out; >+ ABSL_FALLTHROUGH_INTENDED; >+ case -1: >+ out += 2; >+ memcpy(out, &digits[0], 6); >+ out += 6; >+ while (out[-1] == '0') --out; >+ *out = 0; >+ return out - buffer; >+ } >+ assert(exp < -4 || exp >= 6); >+ out[0] = digits[0]; >+ assert(out[1] == '.'); >+ out += 2; >+ memcpy(out, &digits[1], 5), out += 5; >+ while (out[-1] == '0') --out; >+ if (out[-1] == '.') --out; >+ *out++ = 'e'; >+ if (exp > 0) { >+ *out++ = '+'; >+ } else { >+ *out++ = '-'; >+ exp = -exp; >+ } >+ if (exp > 99) { >+ int dig1 = exp / 100; >+ exp -= dig1 * 100; >+ *out++ = '0' + dig1; >+ } >+ PutTwoDigits(exp, out); >+ out += 2; >+ *out = 0; >+ return out - buffer; >+} >+ >+namespace { >+// Represents integer values of digits. >+// Uses 36 to indicate an invalid character since we support >+// bases up to 36. >+static const int8_t kAsciiToInt[256] = { >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, // 16 36s. >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 0, 1, 2, 3, 4, 5, >+ 6, 7, 8, 9, 36, 36, 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, >+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, >+ 36, 36, 36, 36, 36, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, >+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, >+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36}; >+ >+// Parse the sign and optional hex or oct prefix in text. >+inline bool safe_parse_sign_and_base(absl::string_view* text /*inout*/, >+ int* base_ptr /*inout*/, >+ bool* negative_ptr /*output*/) { >+ if (text->data() == nullptr) { >+ return false; >+ } >+ >+ const char* start = text->data(); >+ const char* end = start + text->size(); >+ int base = *base_ptr; >+ >+ // Consume whitespace. >+ while (start < end && absl::ascii_isspace(start[0])) { >+ ++start; >+ } >+ while (start < end && absl::ascii_isspace(end[-1])) { >+ --end; >+ } >+ if (start >= end) { >+ return false; >+ } >+ >+ // Consume sign. >+ *negative_ptr = (start[0] == '-'); >+ if (*negative_ptr || start[0] == '+') { >+ ++start; >+ if (start >= end) { >+ return false; >+ } >+ } >+ >+ // Consume base-dependent prefix. >+ // base 0: "0x" -> base 16, "0" -> base 8, default -> base 10 >+ // base 16: "0x" -> base 16 >+ // Also validate the base. >+ if (base == 0) { >+ if (end - start >= 2 && start[0] == '0' && >+ (start[1] == 'x' || start[1] == 'X')) { >+ base = 16; >+ start += 2; >+ if (start >= end) { >+ // "0x" with no digits after is invalid. >+ return false; >+ } >+ } else if (end - start >= 1 && start[0] == '0') { >+ base = 8; >+ start += 1; >+ } else { >+ base = 10; >+ } >+ } else if (base == 16) { >+ if (end - start >= 2 && start[0] == '0' && >+ (start[1] == 'x' || start[1] == 'X')) { >+ start += 2; >+ if (start >= end) { >+ // "0x" with no digits after is invalid. >+ return false; >+ } >+ } >+ } else if (base >= 2 && base <= 36) { >+ // okay >+ } else { >+ return false; >+ } >+ *text = absl::string_view(start, end - start); >+ *base_ptr = base; >+ return true; >+} >+ >+// Consume digits. >+// >+// The classic loop: >+// >+// for each digit >+// value = value * base + digit >+// value *= sign >+// >+// The classic loop needs overflow checking. It also fails on the most >+// negative integer, -2147483648 in 32-bit two's complement representation. >+// >+// My improved loop: >+// >+// if (!negative) >+// for each digit >+// value = value * base >+// value = value + digit >+// else >+// for each digit >+// value = value * base >+// value = value - digit >+// >+// Overflow checking becomes simple. >+ >+// Lookup tables per IntType: >+// vmax/base and vmin/base are precomputed because division costs at least 8ns. >+// TODO(junyer): Doing this per base instead (i.e. an array of structs, not a >+// struct of arrays) would probably be better in terms of d-cache for the most >+// commonly used bases. >+template <typename IntType> >+struct LookupTables { >+ static const IntType kVmaxOverBase[]; >+ static const IntType kVminOverBase[]; >+}; >+ >+// An array initializer macro for X/base where base in [0, 36]. >+// However, note that lookups for base in [0, 1] should never happen because >+// base has been validated to be in [2, 36] by safe_parse_sign_and_base(). >+#define X_OVER_BASE_INITIALIZER(X) \ >+ { \ >+ 0, 0, X / 2, X / 3, X / 4, X / 5, X / 6, X / 7, X / 8, X / 9, X / 10, \ >+ X / 11, X / 12, X / 13, X / 14, X / 15, X / 16, X / 17, X / 18, \ >+ X / 19, X / 20, X / 21, X / 22, X / 23, X / 24, X / 25, X / 26, \ >+ X / 27, X / 28, X / 29, X / 30, X / 31, X / 32, X / 33, X / 34, \ >+ X / 35, X / 36, \ >+ } >+ >+template <typename IntType> >+const IntType LookupTables<IntType>::kVmaxOverBase[] = >+ X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max()); >+ >+template <typename IntType> >+const IntType LookupTables<IntType>::kVminOverBase[] = >+ X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::min()); >+ >+#undef X_OVER_BASE_INITIALIZER >+ >+template <typename IntType> >+inline bool safe_parse_positive_int(absl::string_view text, int base, >+ IntType* value_p) { >+ IntType value = 0; >+ const IntType vmax = std::numeric_limits<IntType>::max(); >+ assert(vmax > 0); >+ assert(base >= 0); >+ assert(vmax >= static_cast<IntType>(base)); >+ const IntType vmax_over_base = LookupTables<IntType>::kVmaxOverBase[base]; >+ const char* start = text.data(); >+ const char* end = start + text.size(); >+ // loop over digits >+ for (; start < end; ++start) { >+ unsigned char c = static_cast<unsigned char>(start[0]); >+ int digit = kAsciiToInt[c]; >+ if (digit >= base) { >+ *value_p = value; >+ return false; >+ } >+ if (value > vmax_over_base) { >+ *value_p = vmax; >+ return false; >+ } >+ value *= base; >+ if (value > vmax - digit) { >+ *value_p = vmax; >+ return false; >+ } >+ value += digit; >+ } >+ *value_p = value; >+ return true; >+} >+ >+template <typename IntType> >+inline bool safe_parse_negative_int(absl::string_view text, int base, >+ IntType* value_p) { >+ IntType value = 0; >+ const IntType vmin = std::numeric_limits<IntType>::min(); >+ assert(vmin < 0); >+ assert(vmin <= 0 - base); >+ IntType vmin_over_base = LookupTables<IntType>::kVminOverBase[base]; >+ // 2003 c++ standard [expr.mul] >+ // "... the sign of the remainder is implementation-defined." >+ // Although (vmin/base)*base + vmin%base is always vmin. >+ // 2011 c++ standard tightens the spec but we cannot rely on it. >+ // TODO(junyer): Handle this in the lookup table generation. >+ if (vmin % base > 0) { >+ vmin_over_base += 1; >+ } >+ const char* start = text.data(); >+ const char* end = start + text.size(); >+ // loop over digits >+ for (; start < end; ++start) { >+ unsigned char c = static_cast<unsigned char>(start[0]); >+ int digit = kAsciiToInt[c]; >+ if (digit >= base) { >+ *value_p = value; >+ return false; >+ } >+ if (value < vmin_over_base) { >+ *value_p = vmin; >+ return false; >+ } >+ value *= base; >+ if (value < vmin + digit) { >+ *value_p = vmin; >+ return false; >+ } >+ value -= digit; >+ } >+ *value_p = value; >+ return true; >+} >+ >+// Input format based on POSIX.1-2008 strtol >+// http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtol.html >+template <typename IntType> >+inline bool safe_int_internal(absl::string_view text, IntType* value_p, >+ int base) { >+ *value_p = 0; >+ bool negative; >+ if (!safe_parse_sign_and_base(&text, &base, &negative)) { >+ return false; >+ } >+ if (!negative) { >+ return safe_parse_positive_int(text, base, value_p); >+ } else { >+ return safe_parse_negative_int(text, base, value_p); >+ } >+} >+ >+template <typename IntType> >+inline bool safe_uint_internal(absl::string_view text, IntType* value_p, >+ int base) { >+ *value_p = 0; >+ bool negative; >+ if (!safe_parse_sign_and_base(&text, &base, &negative) || negative) { >+ return false; >+ } >+ return safe_parse_positive_int(text, base, value_p); >+} >+} // anonymous namespace >+ >+namespace numbers_internal { >+bool safe_strto32_base(absl::string_view text, int32_t* value, int base) { >+ return safe_int_internal<int32_t>(text, value, base); >+} >+ >+bool safe_strto64_base(absl::string_view text, int64_t* value, int base) { >+ return safe_int_internal<int64_t>(text, value, base); >+} >+ >+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) { >+ return safe_uint_internal<uint32_t>(text, value, base); >+} >+ >+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base) { >+ return safe_uint_internal<uint64_t>(text, value, base); >+} >+} // namespace numbers_internal >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.h >new file mode 100644 >index 00000000000..cf3c597266c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers.h >@@ -0,0 +1,184 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: numbers.h >+// ----------------------------------------------------------------------------- >+// >+// This package contains functions for converting strings to numbers. For >+// converting numbers to strings, use `StrCat()` or `StrAppend()` in str_cat.h, >+// which automatically detect and convert most number values appropriately. >+ >+#ifndef ABSL_STRINGS_NUMBERS_H_ >+#define ABSL_STRINGS_NUMBERS_H_ >+ >+#include <cstddef> >+#include <cstdlib> >+#include <cstring> >+#include <ctime> >+#include <limits> >+#include <string> >+#include <type_traits> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/numeric/int128.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// SimpleAtoi() >+// >+// Converts the given std::string into an integer value, returning `true` if >+// successful. The std::string must reflect a base-10 integer (optionally followed or >+// preceded by ASCII whitespace) whose value falls within the range of the >+// integer type, >+template <typename int_type> >+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out); >+ >+// SimpleAtof() >+// >+// Converts the given std::string (optionally followed or preceded by ASCII >+// whitespace) into a float, which may be rounded on overflow or underflow. >+// See http://en.cppreference.com/w/c/std::string/byte/strtof for details about the >+// allowed formats for `str`. >+ABSL_MUST_USE_RESULT bool SimpleAtof(absl::string_view str, float* value); >+ >+// SimpleAtod() >+// >+// Converts the given std::string (optionally followed or preceded by ASCII >+// whitespace) into a double, which may be rounded on overflow or underflow. >+// See http://en.cppreference.com/w/c/std::string/byte/strtof for details about the >+// allowed formats for `str`. >+ABSL_MUST_USE_RESULT bool SimpleAtod(absl::string_view str, double* value); >+ >+// SimpleAtob() >+// >+// Converts the given std::string into a boolean, returning `true` if successful. >+// The following case-insensitive strings are interpreted as boolean `true`: >+// "true", "t", "yes", "y", "1". The following case-insensitive strings >+// are interpreted as boolean `false`: "false", "f", "no", "n", "0". >+ABSL_MUST_USE_RESULT bool SimpleAtob(absl::string_view str, bool* value); >+ >+} // namespace absl >+ >+// End of public API. Implementation details follow. >+ >+namespace absl { >+namespace numbers_internal { >+ >+// safe_strto?() functions for implementing SimpleAtoi() >+bool safe_strto32_base(absl::string_view text, int32_t* value, int base); >+bool safe_strto64_base(absl::string_view text, int64_t* value, int base); >+bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base); >+bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base); >+ >+static const int kFastToBufferSize = 32; >+static const int kSixDigitsToBufferSize = 16; >+ >+// Helper function for fast formatting of floating-point values. >+// The result is the same as printf's "%g", a.k.a. "%.6g"; that is, six >+// significant digits are returned, trailing zeros are removed, and numbers >+// outside the range 0.0001-999999 are output using scientific notation >+// (1.23456e+06). This routine is heavily optimized. >+// Required buffer size is `kSixDigitsToBufferSize`. >+size_t SixDigitsToBuffer(double d, char* buffer); >+ >+// These functions are intended for speed. All functions take an output buffer >+// as an argument and return a pointer to the last byte they wrote, which is the >+// terminating '\0'. At most `kFastToBufferSize` bytes are written. >+char* FastIntToBuffer(int32_t, char*); >+char* FastIntToBuffer(uint32_t, char*); >+char* FastIntToBuffer(int64_t, char*); >+char* FastIntToBuffer(uint64_t, char*); >+ >+// For enums and integer types that are not an exact match for the types above, >+// use templates to call the appropriate one of the four overloads above. >+template <typename int_type> >+char* FastIntToBuffer(int_type i, char* buffer) { >+ static_assert(sizeof(i) <= 64 / 8, >+ "FastIntToBuffer works only with 64-bit-or-less integers."); >+ // TODO(jorg): This signed-ness check is used because it works correctly >+ // with enums, and it also serves to check that int_type is not a pointer. >+ // If one day something like std::is_signed<enum E> works, switch to it. >+ if (static_cast<int_type>(1) - 2 < 0) { // Signed >+ if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit >+ return FastIntToBuffer(static_cast<int64_t>(i), buffer); >+ } else { // 32-bit or less >+ return FastIntToBuffer(static_cast<int32_t>(i), buffer); >+ } >+ } else { // Unsigned >+ if (sizeof(i) > 32 / 8) { // 33-bit to 64-bit >+ return FastIntToBuffer(static_cast<uint64_t>(i), buffer); >+ } else { // 32-bit or less >+ return FastIntToBuffer(static_cast<uint32_t>(i), buffer); >+ } >+ } >+} >+ >+// Implementation of SimpleAtoi, generalized to support arbitrary base (used >+// with base different from 10 elsewhere in Abseil implementation). >+template <typename int_type> >+ABSL_MUST_USE_RESULT bool safe_strtoi_base(absl::string_view s, int_type* out, >+ int base) { >+ static_assert(sizeof(*out) == 4 || sizeof(*out) == 8, >+ "SimpleAtoi works only with 32-bit or 64-bit integers."); >+ static_assert(!std::is_floating_point<int_type>::value, >+ "Use SimpleAtof or SimpleAtod instead."); >+ bool parsed; >+ // TODO(jorg): This signed-ness check is used because it works correctly >+ // with enums, and it also serves to check that int_type is not a pointer. >+ // If one day something like std::is_signed<enum E> works, switch to it. >+ if (static_cast<int_type>(1) - 2 < 0) { // Signed >+ if (sizeof(*out) == 64 / 8) { // 64-bit >+ int64_t val; >+ parsed = numbers_internal::safe_strto64_base(s, &val, base); >+ *out = static_cast<int_type>(val); >+ } else { // 32-bit >+ int32_t val; >+ parsed = numbers_internal::safe_strto32_base(s, &val, base); >+ *out = static_cast<int_type>(val); >+ } >+ } else { // Unsigned >+ if (sizeof(*out) == 64 / 8) { // 64-bit >+ uint64_t val; >+ parsed = numbers_internal::safe_strtou64_base(s, &val, base); >+ *out = static_cast<int_type>(val); >+ } else { // 32-bit >+ uint32_t val; >+ parsed = numbers_internal::safe_strtou32_base(s, &val, base); >+ *out = static_cast<int_type>(val); >+ } >+ } >+ return parsed; >+} >+ >+} // namespace numbers_internal >+ >+// SimpleAtoi() >+// >+// Converts a std::string to an integer, using `safe_strto?()` functions for actual >+// parsing, returning `true` if successful. The `safe_strto?()` functions apply >+// strict checking; the std::string must be a base-10 integer, optionally followed or >+// preceded by ASCII whitespace, with a value in the range of the corresponding >+// integer type. >+template <typename int_type> >+ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view s, int_type* out) { >+ return numbers_internal::safe_strtoi_base(s, out, 10); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_NUMBERS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_benchmark.cc >new file mode 100644 >index 00000000000..8ef650b9a3e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_benchmark.cc >@@ -0,0 +1,263 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstdint> >+#include <random> >+#include <string> >+#include <type_traits> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/numbers.h" >+ >+namespace { >+ >+template <typename T> >+void BM_FastIntToBuffer(benchmark::State& state) { >+ const int inc = state.range(0); >+ char buf[absl::numbers_internal::kFastToBufferSize]; >+ // Use the unsigned type to increment to take advantage of well-defined >+ // modular arithmetic. >+ typename std::make_unsigned<T>::type x = 0; >+ for (auto _ : state) { >+ absl::numbers_internal::FastIntToBuffer(static_cast<T>(x), buf); >+ x += inc; >+ } >+} >+BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int32_t)->Range(0, 1 << 15); >+BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int64_t)->Range(0, 1 << 30); >+ >+// Creates an integer that would be printed as `num_digits` repeated 7s in the >+// given `base`. `base` must be greater than or equal to 8. >+int64_t RepeatedSevens(int num_digits, int base) { >+ ABSL_RAW_CHECK(base >= 8, ""); >+ int64_t num = 7; >+ while (--num_digits) num = base * num + 7; >+ return num; >+} >+ >+void BM_safe_strto32_string(benchmark::State& state) { >+ const int digits = state.range(0); >+ const int base = state.range(1); >+ std::string str(digits, '7'); // valid in octal, decimal and hex >+ int32_t value = 0; >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::numbers_internal::safe_strto32_base(str, &value, base)); >+ } >+ ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), ""); >+} >+BENCHMARK(BM_safe_strto32_string) >+ ->ArgPair(1, 8) >+ ->ArgPair(1, 10) >+ ->ArgPair(1, 16) >+ ->ArgPair(2, 8) >+ ->ArgPair(2, 10) >+ ->ArgPair(2, 16) >+ ->ArgPair(4, 8) >+ ->ArgPair(4, 10) >+ ->ArgPair(4, 16) >+ ->ArgPair(8, 8) >+ ->ArgPair(8, 10) >+ ->ArgPair(8, 16) >+ ->ArgPair(10, 8) >+ ->ArgPair(9, 10); >+ >+void BM_safe_strto64_string(benchmark::State& state) { >+ const int digits = state.range(0); >+ const int base = state.range(1); >+ std::string str(digits, '7'); // valid in octal, decimal and hex >+ int64_t value = 0; >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::numbers_internal::safe_strto64_base(str, &value, base)); >+ } >+ ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), ""); >+} >+BENCHMARK(BM_safe_strto64_string) >+ ->ArgPair(1, 8) >+ ->ArgPair(1, 10) >+ ->ArgPair(1, 16) >+ ->ArgPair(2, 8) >+ ->ArgPair(2, 10) >+ ->ArgPair(2, 16) >+ ->ArgPair(4, 8) >+ ->ArgPair(4, 10) >+ ->ArgPair(4, 16) >+ ->ArgPair(8, 8) >+ ->ArgPair(8, 10) >+ ->ArgPair(8, 16) >+ ->ArgPair(16, 8) >+ ->ArgPair(16, 10) >+ ->ArgPair(16, 16); >+ >+void BM_safe_strtou32_string(benchmark::State& state) { >+ const int digits = state.range(0); >+ const int base = state.range(1); >+ std::string str(digits, '7'); // valid in octal, decimal and hex >+ uint32_t value = 0; >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::numbers_internal::safe_strtou32_base(str, &value, base)); >+ } >+ ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), ""); >+} >+BENCHMARK(BM_safe_strtou32_string) >+ ->ArgPair(1, 8) >+ ->ArgPair(1, 10) >+ ->ArgPair(1, 16) >+ ->ArgPair(2, 8) >+ ->ArgPair(2, 10) >+ ->ArgPair(2, 16) >+ ->ArgPair(4, 8) >+ ->ArgPair(4, 10) >+ ->ArgPair(4, 16) >+ ->ArgPair(8, 8) >+ ->ArgPair(8, 10) >+ ->ArgPair(8, 16) >+ ->ArgPair(10, 8) >+ ->ArgPair(9, 10); >+ >+void BM_safe_strtou64_string(benchmark::State& state) { >+ const int digits = state.range(0); >+ const int base = state.range(1); >+ std::string str(digits, '7'); // valid in octal, decimal and hex >+ uint64_t value = 0; >+ for (auto _ : state) { >+ benchmark::DoNotOptimize( >+ absl::numbers_internal::safe_strtou64_base(str, &value, base)); >+ } >+ ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), ""); >+} >+BENCHMARK(BM_safe_strtou64_string) >+ ->ArgPair(1, 8) >+ ->ArgPair(1, 10) >+ ->ArgPair(1, 16) >+ ->ArgPair(2, 8) >+ ->ArgPair(2, 10) >+ ->ArgPair(2, 16) >+ ->ArgPair(4, 8) >+ ->ArgPair(4, 10) >+ ->ArgPair(4, 16) >+ ->ArgPair(8, 8) >+ ->ArgPair(8, 10) >+ ->ArgPair(8, 16) >+ ->ArgPair(16, 8) >+ ->ArgPair(16, 10) >+ ->ArgPair(16, 16); >+ >+// Returns a vector of `num_strings` strings. Each std::string represents a >+// floating point number with `num_digits` digits before the decimal point and >+// another `num_digits` digits after. >+std::vector<std::string> MakeFloatStrings(int num_strings, int num_digits) { >+ // For convenience, use a random number generator to generate the test data. >+ // We don't actually need random properties, so use a fixed seed. >+ std::minstd_rand0 rng(1); >+ std::uniform_int_distribution<int> random_digit('0', '9'); >+ >+ std::vector<std::string> float_strings(num_strings); >+ for (std::string& s : float_strings) { >+ s.reserve(2 * num_digits + 1); >+ for (int i = 0; i < num_digits; ++i) { >+ s.push_back(static_cast<char>(random_digit(rng))); >+ } >+ s.push_back('.'); >+ for (int i = 0; i < num_digits; ++i) { >+ s.push_back(static_cast<char>(random_digit(rng))); >+ } >+ } >+ return float_strings; >+} >+ >+template <typename StringType> >+StringType GetStringAs(const std::string& s) { >+ return static_cast<StringType>(s); >+} >+template <> >+const char* GetStringAs<const char*>(const std::string& s) { >+ return s.c_str(); >+} >+ >+template <typename StringType> >+std::vector<StringType> GetStringsAs(const std::vector<std::string>& strings) { >+ std::vector<StringType> result; >+ result.reserve(strings.size()); >+ for (const std::string& s : strings) { >+ result.push_back(GetStringAs<StringType>(s)); >+ } >+ return result; >+} >+ >+template <typename T> >+void BM_SimpleAtof(benchmark::State& state) { >+ const int num_strings = state.range(0); >+ const int num_digits = state.range(1); >+ std::vector<std::string> backing_strings = >+ MakeFloatStrings(num_strings, num_digits); >+ std::vector<T> inputs = GetStringsAs<T>(backing_strings); >+ float value; >+ for (auto _ : state) { >+ for (const T& input : inputs) { >+ benchmark::DoNotOptimize(absl::SimpleAtof(input, &value)); >+ } >+ } >+} >+BENCHMARK_TEMPLATE(BM_SimpleAtof, absl::string_view) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+BENCHMARK_TEMPLATE(BM_SimpleAtof, const char*) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+BENCHMARK_TEMPLATE(BM_SimpleAtof, std::string) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+ >+template <typename T> >+void BM_SimpleAtod(benchmark::State& state) { >+ const int num_strings = state.range(0); >+ const int num_digits = state.range(1); >+ std::vector<std::string> backing_strings = >+ MakeFloatStrings(num_strings, num_digits); >+ std::vector<T> inputs = GetStringsAs<T>(backing_strings); >+ double value; >+ for (auto _ : state) { >+ for (const T& input : inputs) { >+ benchmark::DoNotOptimize(absl::SimpleAtod(input, &value)); >+ } >+ } >+} >+BENCHMARK_TEMPLATE(BM_SimpleAtod, absl::string_view) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+BENCHMARK_TEMPLATE(BM_SimpleAtod, const char*) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+BENCHMARK_TEMPLATE(BM_SimpleAtod, std::string) >+ ->ArgPair(10, 1) >+ ->ArgPair(10, 2) >+ ->ArgPair(10, 4) >+ ->ArgPair(10, 8); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_test.cc >new file mode 100644 >index 00000000000..27cc0479e34 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/numbers_test.cc >@@ -0,0 +1,1185 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file tests std::string processing functions related to numeric values. >+ >+#include "absl/strings/numbers.h" >+ >+#include <sys/types.h> >+#include <cfenv> // NOLINT(build/c++11) >+#include <cinttypes> >+#include <climits> >+#include <cmath> >+#include <cstddef> >+#include <cstdint> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+#include <limits> >+#include <numeric> >+#include <random> >+#include <set> >+#include <string> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/str_cat.h" >+ >+#include "absl/strings/internal/numbers_test_common.h" >+ >+namespace { >+ >+using absl::numbers_internal::kSixDigitsToBufferSize; >+using absl::numbers_internal::safe_strto32_base; >+using absl::numbers_internal::safe_strto64_base; >+using absl::numbers_internal::safe_strtou32_base; >+using absl::numbers_internal::safe_strtou64_base; >+using absl::numbers_internal::SixDigitsToBuffer; >+using absl::strings_internal::Itoa; >+using absl::strings_internal::strtouint32_test_cases; >+using absl::strings_internal::strtouint64_test_cases; >+using absl::SimpleAtoi; >+using testing::Eq; >+using testing::MatchesRegex; >+ >+// Number of floats to test with. >+// 5,000,000 is a reasonable default for a test that only takes a few seconds. >+// 1,000,000,000+ triggers checking for all possible mantissa values for >+// double-precision tests. 2,000,000,000+ triggers checking for every possible >+// single-precision float. >+const int kFloatNumCases = 5000000; >+ >+// This is a slow, brute-force routine to compute the exact base-10 >+// representation of a double-precision floating-point number. It >+// is useful for debugging only. >+std::string PerfectDtoa(double d) { >+ if (d == 0) return "0"; >+ if (d < 0) return "-" + PerfectDtoa(-d); >+ >+ // Basic theory: decompose d into mantissa and exp, where >+ // d = mantissa * 2^exp, and exp is as close to zero as possible. >+ int64_t mantissa, exp = 0; >+ while (d >= 1ULL << 63) ++exp, d *= 0.5; >+ while ((mantissa = d) != d) --exp, d *= 2.0; >+ >+ // Then convert mantissa to ASCII, and either double it (if >+ // exp > 0) or halve it (if exp < 0) repeatedly. "halve it" >+ // in this case means multiplying it by five and dividing by 10. >+ constexpr int maxlen = 1100; // worst case is actually 1030 or so. >+ char buf[maxlen + 5]; >+ for (int64_t num = mantissa, pos = maxlen; --pos >= 0;) { >+ buf[pos] = '0' + (num % 10); >+ num /= 10; >+ } >+ char* begin = &buf[0]; >+ char* end = buf + maxlen; >+ for (int i = 0; i != exp; i += (exp > 0) ? 1 : -1) { >+ int carry = 0; >+ for (char* p = end; --p != begin;) { >+ int dig = *p - '0'; >+ dig = dig * (exp > 0 ? 2 : 5) + carry; >+ carry = dig / 10; >+ dig %= 10; >+ *p = '0' + dig; >+ } >+ } >+ if (exp < 0) { >+ // "dividing by 10" above means we have to add the decimal point. >+ memmove(end + 1 + exp, end + exp, 1 - exp); >+ end[exp] = '.'; >+ ++end; >+ } >+ while (*begin == '0' && begin[1] != '.') ++begin; >+ return {begin, end}; >+} >+ >+TEST(ToString, PerfectDtoa) { >+ EXPECT_THAT(PerfectDtoa(1), Eq("1")); >+ EXPECT_THAT(PerfectDtoa(0.1), >+ Eq("0.1000000000000000055511151231257827021181583404541015625")); >+ EXPECT_THAT(PerfectDtoa(1e24), Eq("999999999999999983222784")); >+ EXPECT_THAT(PerfectDtoa(5e-324), MatchesRegex("0.0000.*625")); >+ for (int i = 0; i < 100; ++i) { >+ for (double multiplier : >+ {1e-300, 1e-200, 1e-100, 0.1, 1.0, 10.0, 1e100, 1e300}) { >+ double d = multiplier * i; >+ std::string s = PerfectDtoa(d); >+ EXPECT_DOUBLE_EQ(d, strtod(s.c_str(), nullptr)); >+ } >+ } >+} >+ >+template <typename integer> >+struct MyInteger { >+ integer i; >+ explicit constexpr MyInteger(integer i) : i(i) {} >+ constexpr operator integer() const { return i; } >+ >+ constexpr MyInteger operator+(MyInteger other) const { return i + other.i; } >+ constexpr MyInteger operator-(MyInteger other) const { return i - other.i; } >+ constexpr MyInteger operator*(MyInteger other) const { return i * other.i; } >+ constexpr MyInteger operator/(MyInteger other) const { return i / other.i; } >+ >+ constexpr bool operator<(MyInteger other) const { return i < other.i; } >+ constexpr bool operator<=(MyInteger other) const { return i <= other.i; } >+ constexpr bool operator==(MyInteger other) const { return i == other.i; } >+ constexpr bool operator>=(MyInteger other) const { return i >= other.i; } >+ constexpr bool operator>(MyInteger other) const { return i > other.i; } >+ constexpr bool operator!=(MyInteger other) const { return i != other.i; } >+ >+ integer as_integer() const { return i; } >+}; >+ >+typedef MyInteger<int64_t> MyInt64; >+typedef MyInteger<uint64_t> MyUInt64; >+ >+void CheckInt32(int32_t x) { >+ char buffer[absl::numbers_internal::kFastToBufferSize]; >+ char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer); >+ std::string expected = std::to_string(x); >+ EXPECT_EQ(expected, std::string(buffer, actual)) << " Input " << x; >+ >+ char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, buffer); >+ EXPECT_EQ(expected, std::string(buffer, generic_actual)) << " Input " << x; >+} >+ >+void CheckInt64(int64_t x) { >+ char buffer[absl::numbers_internal::kFastToBufferSize + 3]; >+ buffer[0] = '*'; >+ buffer[23] = '*'; >+ buffer[24] = '*'; >+ char* actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]); >+ std::string expected = std::to_string(x); >+ EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x; >+ EXPECT_EQ(buffer[0], '*'); >+ EXPECT_EQ(buffer[23], '*'); >+ EXPECT_EQ(buffer[24], '*'); >+ >+ char* my_actual = >+ absl::numbers_internal::FastIntToBuffer(MyInt64(x), &buffer[1]); >+ EXPECT_EQ(expected, std::string(&buffer[1], my_actual)) << " Input " << x; >+} >+ >+void CheckUInt32(uint32_t x) { >+ char buffer[absl::numbers_internal::kFastToBufferSize]; >+ char* actual = absl::numbers_internal::FastIntToBuffer(x, buffer); >+ std::string expected = std::to_string(x); >+ EXPECT_EQ(expected, std::string(buffer, actual)) << " Input " << x; >+ >+ char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, buffer); >+ EXPECT_EQ(expected, std::string(buffer, generic_actual)) << " Input " << x; >+} >+ >+void CheckUInt64(uint64_t x) { >+ char buffer[absl::numbers_internal::kFastToBufferSize + 1]; >+ char* actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]); >+ std::string expected = std::to_string(x); >+ EXPECT_EQ(expected, std::string(&buffer[1], actual)) << " Input " << x; >+ >+ char* generic_actual = absl::numbers_internal::FastIntToBuffer(x, &buffer[1]); >+ EXPECT_EQ(expected, std::string(&buffer[1], generic_actual)) << " Input " << x; >+ >+ char* my_actual = >+ absl::numbers_internal::FastIntToBuffer(MyUInt64(x), &buffer[1]); >+ EXPECT_EQ(expected, std::string(&buffer[1], my_actual)) << " Input " << x; >+} >+ >+void CheckHex64(uint64_t v) { >+ char expected[16 + 1]; >+ std::string actual = absl::StrCat(absl::Hex(v, absl::kZeroPad16)); >+ snprintf(expected, sizeof(expected), "%016" PRIx64, static_cast<uint64_t>(v)); >+ EXPECT_EQ(expected, actual) << " Input " << v; >+} >+ >+TEST(Numbers, TestFastPrints) { >+ for (int i = -100; i <= 100; i++) { >+ CheckInt32(i); >+ CheckInt64(i); >+ } >+ for (int i = 0; i <= 100; i++) { >+ CheckUInt32(i); >+ CheckUInt64(i); >+ } >+ // Test min int to make sure that works >+ CheckInt32(INT_MIN); >+ CheckInt32(INT_MAX); >+ CheckInt64(LONG_MIN); >+ CheckInt64(uint64_t{1000000000}); >+ CheckInt64(uint64_t{9999999999}); >+ CheckInt64(uint64_t{100000000000000}); >+ CheckInt64(uint64_t{999999999999999}); >+ CheckInt64(uint64_t{1000000000000000000}); >+ CheckInt64(uint64_t{1199999999999999999}); >+ CheckInt64(int64_t{-700000000000000000}); >+ CheckInt64(LONG_MAX); >+ CheckUInt32(std::numeric_limits<uint32_t>::max()); >+ CheckUInt64(uint64_t{1000000000}); >+ CheckUInt64(uint64_t{9999999999}); >+ CheckUInt64(uint64_t{100000000000000}); >+ CheckUInt64(uint64_t{999999999999999}); >+ CheckUInt64(uint64_t{1000000000000000000}); >+ CheckUInt64(uint64_t{1199999999999999999}); >+ CheckUInt64(std::numeric_limits<uint64_t>::max()); >+ >+ for (int i = 0; i < 10000; i++) { >+ CheckHex64(i); >+ } >+ CheckHex64(uint64_t{0x123456789abcdef0}); >+} >+ >+template <typename int_type, typename in_val_type> >+void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) { >+ std::string s = absl::StrCat(in_value); >+ int_type x = static_cast<int_type>(~exp_value); >+ EXPECT_TRUE(SimpleAtoi(s, &x)) >+ << "in_value=" << in_value << " s=" << s << " x=" << x; >+ EXPECT_EQ(exp_value, x); >+ x = static_cast<int_type>(~exp_value); >+ EXPECT_TRUE(SimpleAtoi(s.c_str(), &x)); >+ EXPECT_EQ(exp_value, x); >+} >+ >+template <typename int_type, typename in_val_type> >+void VerifySimpleAtoiBad(in_val_type in_value) { >+ std::string s = absl::StrCat(in_value); >+ int_type x; >+ EXPECT_FALSE(SimpleAtoi(s, &x)); >+ EXPECT_FALSE(SimpleAtoi(s.c_str(), &x)); >+} >+ >+TEST(NumbersTest, Atoi) { >+ // SimpleAtoi(absl::string_view, int32_t) >+ VerifySimpleAtoiGood<int32_t>(0, 0); >+ VerifySimpleAtoiGood<int32_t>(42, 42); >+ VerifySimpleAtoiGood<int32_t>(-42, -42); >+ >+ VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::min(), >+ std::numeric_limits<int32_t>::min()); >+ VerifySimpleAtoiGood<int32_t>(std::numeric_limits<int32_t>::max(), >+ std::numeric_limits<int32_t>::max()); >+ >+ // SimpleAtoi(absl::string_view, uint32_t) >+ VerifySimpleAtoiGood<uint32_t>(0, 0); >+ VerifySimpleAtoiGood<uint32_t>(42, 42); >+ VerifySimpleAtoiBad<uint32_t>(-42); >+ >+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int32_t>::min()); >+ VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<int32_t>::max(), >+ std::numeric_limits<int32_t>::max()); >+ VerifySimpleAtoiGood<uint32_t>(std::numeric_limits<uint32_t>::max(), >+ std::numeric_limits<uint32_t>::max()); >+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::min()); >+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<int64_t>::max()); >+ VerifySimpleAtoiBad<uint32_t>(std::numeric_limits<uint64_t>::max()); >+ >+ // SimpleAtoi(absl::string_view, int64_t) >+ VerifySimpleAtoiGood<int64_t>(0, 0); >+ VerifySimpleAtoiGood<int64_t>(42, 42); >+ VerifySimpleAtoiGood<int64_t>(-42, -42); >+ >+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::min(), >+ std::numeric_limits<int32_t>::min()); >+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int32_t>::max(), >+ std::numeric_limits<int32_t>::max()); >+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<uint32_t>::max(), >+ std::numeric_limits<uint32_t>::max()); >+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::min(), >+ std::numeric_limits<int64_t>::min()); >+ VerifySimpleAtoiGood<int64_t>(std::numeric_limits<int64_t>::max(), >+ std::numeric_limits<int64_t>::max()); >+ VerifySimpleAtoiBad<int64_t>(std::numeric_limits<uint64_t>::max()); >+ >+ // SimpleAtoi(absl::string_view, uint64_t) >+ VerifySimpleAtoiGood<uint64_t>(0, 0); >+ VerifySimpleAtoiGood<uint64_t>(42, 42); >+ VerifySimpleAtoiBad<uint64_t>(-42); >+ >+ VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int32_t>::min()); >+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int32_t>::max(), >+ std::numeric_limits<int32_t>::max()); >+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint32_t>::max(), >+ std::numeric_limits<uint32_t>::max()); >+ VerifySimpleAtoiBad<uint64_t>(std::numeric_limits<int64_t>::min()); >+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<int64_t>::max(), >+ std::numeric_limits<int64_t>::max()); >+ VerifySimpleAtoiGood<uint64_t>(std::numeric_limits<uint64_t>::max(), >+ std::numeric_limits<uint64_t>::max()); >+ >+ // Some other types >+ VerifySimpleAtoiGood<int>(-42, -42); >+ VerifySimpleAtoiGood<int32_t>(-42, -42); >+ VerifySimpleAtoiGood<uint32_t>(42, 42); >+ VerifySimpleAtoiGood<unsigned int>(42, 42); >+ VerifySimpleAtoiGood<int64_t>(-42, -42); >+ VerifySimpleAtoiGood<long>(-42, -42); // NOLINT(runtime/int) >+ VerifySimpleAtoiGood<uint64_t>(42, 42); >+ VerifySimpleAtoiGood<size_t>(42, 42); >+ VerifySimpleAtoiGood<std::string::size_type>(42, 42); >+} >+ >+TEST(NumbersTest, Atoenum) { >+ enum E01 { >+ E01_zero = 0, >+ E01_one = 1, >+ }; >+ >+ VerifySimpleAtoiGood<E01>(E01_zero, E01_zero); >+ VerifySimpleAtoiGood<E01>(E01_one, E01_one); >+ >+ enum E_101 { >+ E_101_minusone = -1, >+ E_101_zero = 0, >+ E_101_one = 1, >+ }; >+ >+ VerifySimpleAtoiGood<E_101>(E_101_minusone, E_101_minusone); >+ VerifySimpleAtoiGood<E_101>(E_101_zero, E_101_zero); >+ VerifySimpleAtoiGood<E_101>(E_101_one, E_101_one); >+ >+ enum E_bigint { >+ E_bigint_zero = 0, >+ E_bigint_one = 1, >+ E_bigint_max31 = static_cast<int32_t>(0x7FFFFFFF), >+ }; >+ >+ VerifySimpleAtoiGood<E_bigint>(E_bigint_zero, E_bigint_zero); >+ VerifySimpleAtoiGood<E_bigint>(E_bigint_one, E_bigint_one); >+ VerifySimpleAtoiGood<E_bigint>(E_bigint_max31, E_bigint_max31); >+ >+ enum E_fullint { >+ E_fullint_zero = 0, >+ E_fullint_one = 1, >+ E_fullint_max31 = static_cast<int32_t>(0x7FFFFFFF), >+ E_fullint_min32 = INT32_MIN, >+ }; >+ >+ VerifySimpleAtoiGood<E_fullint>(E_fullint_zero, E_fullint_zero); >+ VerifySimpleAtoiGood<E_fullint>(E_fullint_one, E_fullint_one); >+ VerifySimpleAtoiGood<E_fullint>(E_fullint_max31, E_fullint_max31); >+ VerifySimpleAtoiGood<E_fullint>(E_fullint_min32, E_fullint_min32); >+ >+ enum E_biguint { >+ E_biguint_zero = 0, >+ E_biguint_one = 1, >+ E_biguint_max31 = static_cast<uint32_t>(0x7FFFFFFF), >+ E_biguint_max32 = static_cast<uint32_t>(0xFFFFFFFF), >+ }; >+ >+ VerifySimpleAtoiGood<E_biguint>(E_biguint_zero, E_biguint_zero); >+ VerifySimpleAtoiGood<E_biguint>(E_biguint_one, E_biguint_one); >+ VerifySimpleAtoiGood<E_biguint>(E_biguint_max31, E_biguint_max31); >+ VerifySimpleAtoiGood<E_biguint>(E_biguint_max32, E_biguint_max32); >+} >+ >+TEST(stringtest, safe_strto32_base) { >+ int32_t value; >+ EXPECT_TRUE(safe_strto32_base("0x34234324", &value, 16)); >+ EXPECT_EQ(0x34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("0X34234324", &value, 16)); >+ EXPECT_EQ(0x34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("34234324", &value, 16)); >+ EXPECT_EQ(0x34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("0", &value, 16)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto32_base(" \t\n -0x34234324", &value, 16)); >+ EXPECT_EQ(-0x34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 16)); >+ EXPECT_EQ(-0x34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("7654321", &value, 8)); >+ EXPECT_EQ(07654321, value); >+ >+ EXPECT_TRUE(safe_strto32_base("-01234", &value, 8)); >+ EXPECT_EQ(-01234, value); >+ >+ EXPECT_FALSE(safe_strto32_base("1834", &value, 8)); >+ >+ // Autodetect base. >+ EXPECT_TRUE(safe_strto32_base("0", &value, 0)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto32_base("077", &value, 0)); >+ EXPECT_EQ(077, value); // Octal interpretation >+ >+ // Leading zero indicates octal, but then followed by invalid digit. >+ EXPECT_FALSE(safe_strto32_base("088", &value, 0)); >+ >+ // Leading 0x indicated hex, but then followed by invalid digit. >+ EXPECT_FALSE(safe_strto32_base("0xG", &value, 0)); >+ >+ // Base-10 version. >+ EXPECT_TRUE(safe_strto32_base("34234324", &value, 10)); >+ EXPECT_EQ(34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("0", &value, 10)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto32_base(" \t\n -34234324", &value, 10)); >+ EXPECT_EQ(-34234324, value); >+ >+ EXPECT_TRUE(safe_strto32_base("34234324 \n\t ", &value, 10)); >+ EXPECT_EQ(34234324, value); >+ >+ // Invalid ints. >+ EXPECT_FALSE(safe_strto32_base("", &value, 10)); >+ EXPECT_FALSE(safe_strto32_base(" ", &value, 10)); >+ EXPECT_FALSE(safe_strto32_base("abc", &value, 10)); >+ EXPECT_FALSE(safe_strto32_base("34234324a", &value, 10)); >+ EXPECT_FALSE(safe_strto32_base("34234.3", &value, 10)); >+ >+ // Out of bounds. >+ EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10)); >+ EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10)); >+ >+ // String version. >+ EXPECT_TRUE(safe_strto32_base(std::string("0x1234"), &value, 16)); >+ EXPECT_EQ(0x1234, value); >+ >+ // Base-10 std::string version. >+ EXPECT_TRUE(safe_strto32_base("1234", &value, 10)); >+ EXPECT_EQ(1234, value); >+} >+ >+TEST(stringtest, safe_strto32_range) { >+ // These tests verify underflow/overflow behaviour. >+ int32_t value; >+ EXPECT_FALSE(safe_strto32_base("2147483648", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int32_t>::max(), value); >+ >+ EXPECT_TRUE(safe_strto32_base("-2147483648", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value); >+ >+ EXPECT_FALSE(safe_strto32_base("-2147483649", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int32_t>::min(), value); >+} >+ >+TEST(stringtest, safe_strto64_range) { >+ // These tests verify underflow/overflow behaviour. >+ int64_t value; >+ EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), value); >+ >+ EXPECT_TRUE(safe_strto64_base("-9223372036854775808", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value); >+ >+ EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10)); >+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), value); >+} >+ >+TEST(stringtest, safe_strto32_leading_substring) { >+ // These tests verify this comment in numbers.h: >+ // On error, returns false, and sets *value to: [...] >+ // conversion of leading substring if available ("123@@@" -> 123) >+ // 0 if no leading substring available >+ int32_t value; >+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 10)); >+ EXPECT_EQ(4069, value); >+ >+ EXPECT_FALSE(safe_strto32_base("04069@@@", &value, 8)); >+ EXPECT_EQ(0406, value); >+ >+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 10)); >+ EXPECT_EQ(4069, value); >+ >+ EXPECT_FALSE(safe_strto32_base("04069balloons", &value, 16)); >+ EXPECT_EQ(0x4069ba, value); >+ >+ EXPECT_FALSE(safe_strto32_base("@@@", &value, 10)); >+ EXPECT_EQ(0, value); // there was no leading substring >+} >+ >+TEST(stringtest, safe_strto64_leading_substring) { >+ // These tests verify this comment in numbers.h: >+ // On error, returns false, and sets *value to: [...] >+ // conversion of leading substring if available ("123@@@" -> 123) >+ // 0 if no leading substring available >+ int64_t value; >+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 10)); >+ EXPECT_EQ(4069, value); >+ >+ EXPECT_FALSE(safe_strto64_base("04069@@@", &value, 8)); >+ EXPECT_EQ(0406, value); >+ >+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 10)); >+ EXPECT_EQ(4069, value); >+ >+ EXPECT_FALSE(safe_strto64_base("04069balloons", &value, 16)); >+ EXPECT_EQ(0x4069ba, value); >+ >+ EXPECT_FALSE(safe_strto64_base("@@@", &value, 10)); >+ EXPECT_EQ(0, value); // there was no leading substring >+} >+ >+TEST(stringtest, safe_strto64_base) { >+ int64_t value; >+ EXPECT_TRUE(safe_strto64_base("0x3423432448783446", &value, 16)); >+ EXPECT_EQ(int64_t{0x3423432448783446}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("3423432448783446", &value, 16)); >+ EXPECT_EQ(int64_t{0x3423432448783446}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("0", &value, 16)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto64_base(" \t\n -0x3423432448783446", &value, 16)); >+ EXPECT_EQ(int64_t{-0x3423432448783446}, value); >+ >+ EXPECT_TRUE(safe_strto64_base(" \t\n -3423432448783446", &value, 16)); >+ EXPECT_EQ(int64_t{-0x3423432448783446}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("123456701234567012", &value, 8)); >+ EXPECT_EQ(int64_t{0123456701234567012}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("-017777777777777", &value, 8)); >+ EXPECT_EQ(int64_t{-017777777777777}, value); >+ >+ EXPECT_FALSE(safe_strto64_base("19777777777777", &value, 8)); >+ >+ // Autodetect base. >+ EXPECT_TRUE(safe_strto64_base("0", &value, 0)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto64_base("077", &value, 0)); >+ EXPECT_EQ(077, value); // Octal interpretation >+ >+ // Leading zero indicates octal, but then followed by invalid digit. >+ EXPECT_FALSE(safe_strto64_base("088", &value, 0)); >+ >+ // Leading 0x indicated hex, but then followed by invalid digit. >+ EXPECT_FALSE(safe_strto64_base("0xG", &value, 0)); >+ >+ // Base-10 version. >+ EXPECT_TRUE(safe_strto64_base("34234324487834466", &value, 10)); >+ EXPECT_EQ(int64_t{34234324487834466}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("0", &value, 10)); >+ EXPECT_EQ(0, value); >+ >+ EXPECT_TRUE(safe_strto64_base(" \t\n -34234324487834466", &value, 10)); >+ EXPECT_EQ(int64_t{-34234324487834466}, value); >+ >+ EXPECT_TRUE(safe_strto64_base("34234324487834466 \n\t ", &value, 10)); >+ EXPECT_EQ(int64_t{34234324487834466}, value); >+ >+ // Invalid ints. >+ EXPECT_FALSE(safe_strto64_base("", &value, 10)); >+ EXPECT_FALSE(safe_strto64_base(" ", &value, 10)); >+ EXPECT_FALSE(safe_strto64_base("abc", &value, 10)); >+ EXPECT_FALSE(safe_strto64_base("34234324487834466a", &value, 10)); >+ EXPECT_FALSE(safe_strto64_base("34234487834466.3", &value, 10)); >+ >+ // Out of bounds. >+ EXPECT_FALSE(safe_strto64_base("9223372036854775808", &value, 10)); >+ EXPECT_FALSE(safe_strto64_base("-9223372036854775809", &value, 10)); >+ >+ // String version. >+ EXPECT_TRUE(safe_strto64_base(std::string("0x1234"), &value, 16)); >+ EXPECT_EQ(0x1234, value); >+ >+ // Base-10 std::string version. >+ EXPECT_TRUE(safe_strto64_base("1234", &value, 10)); >+ EXPECT_EQ(1234, value); >+} >+ >+const size_t kNumRandomTests = 10000; >+ >+template <typename IntType> >+void test_random_integer_parse_base(bool (*parse_func)(absl::string_view, >+ IntType* value, >+ int base)) { >+ using RandomEngine = std::minstd_rand0; >+ std::random_device rd; >+ RandomEngine rng(rd()); >+ std::uniform_int_distribution<IntType> random_int( >+ std::numeric_limits<IntType>::min()); >+ std::uniform_int_distribution<int> random_base(2, 35); >+ for (size_t i = 0; i < kNumRandomTests; i++) { >+ IntType value = random_int(rng); >+ int base = random_base(rng); >+ std::string str_value; >+ EXPECT_TRUE(Itoa<IntType>(value, base, &str_value)); >+ IntType parsed_value; >+ >+ // Test successful parse >+ EXPECT_TRUE(parse_func(str_value, &parsed_value, base)); >+ EXPECT_EQ(parsed_value, value); >+ >+ // Test overflow >+ EXPECT_FALSE( >+ parse_func(absl::StrCat(std::numeric_limits<IntType>::max(), value), >+ &parsed_value, base)); >+ >+ // Test underflow >+ if (std::numeric_limits<IntType>::min() < 0) { >+ EXPECT_FALSE( >+ parse_func(absl::StrCat(std::numeric_limits<IntType>::min(), value), >+ &parsed_value, base)); >+ } else { >+ EXPECT_FALSE(parse_func(absl::StrCat("-", value), &parsed_value, base)); >+ } >+ } >+} >+ >+TEST(stringtest, safe_strto32_random) { >+ test_random_integer_parse_base<int32_t>(&safe_strto32_base); >+} >+TEST(stringtest, safe_strto64_random) { >+ test_random_integer_parse_base<int64_t>(&safe_strto64_base); >+} >+TEST(stringtest, safe_strtou32_random) { >+ test_random_integer_parse_base<uint32_t>(&safe_strtou32_base); >+} >+TEST(stringtest, safe_strtou64_random) { >+ test_random_integer_parse_base<uint64_t>(&safe_strtou64_base); >+} >+ >+TEST(stringtest, safe_strtou32_base) { >+ for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) { >+ const auto& e = strtouint32_test_cases()[i]; >+ uint32_t value; >+ EXPECT_EQ(e.expect_ok, safe_strtou32_base(e.str, &value, e.base)) >+ << "str=\"" << e.str << "\" base=" << e.base; >+ if (e.expect_ok) { >+ EXPECT_EQ(e.expected, value) << "i=" << i << " str=\"" << e.str >+ << "\" base=" << e.base; >+ } >+ } >+} >+ >+TEST(stringtest, safe_strtou32_base_length_delimited) { >+ for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) { >+ const auto& e = strtouint32_test_cases()[i]; >+ std::string tmp(e.str); >+ tmp.append("12"); // Adds garbage at the end. >+ >+ uint32_t value; >+ EXPECT_EQ(e.expect_ok, >+ safe_strtou32_base(absl::string_view(tmp.data(), strlen(e.str)), >+ &value, e.base)) >+ << "str=\"" << e.str << "\" base=" << e.base; >+ if (e.expect_ok) { >+ EXPECT_EQ(e.expected, value) << "i=" << i << " str=" << e.str >+ << " base=" << e.base; >+ } >+ } >+} >+ >+TEST(stringtest, safe_strtou64_base) { >+ for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) { >+ const auto& e = strtouint64_test_cases()[i]; >+ uint64_t value; >+ EXPECT_EQ(e.expect_ok, safe_strtou64_base(e.str, &value, e.base)) >+ << "str=\"" << e.str << "\" base=" << e.base; >+ if (e.expect_ok) { >+ EXPECT_EQ(e.expected, value) << "str=" << e.str << " base=" << e.base; >+ } >+ } >+} >+ >+TEST(stringtest, safe_strtou64_base_length_delimited) { >+ for (int i = 0; strtouint64_test_cases()[i].str != nullptr; ++i) { >+ const auto& e = strtouint64_test_cases()[i]; >+ std::string tmp(e.str); >+ tmp.append("12"); // Adds garbage at the end. >+ >+ uint64_t value; >+ EXPECT_EQ(e.expect_ok, >+ safe_strtou64_base(absl::string_view(tmp.data(), strlen(e.str)), >+ &value, e.base)) >+ << "str=\"" << e.str << "\" base=" << e.base; >+ if (e.expect_ok) { >+ EXPECT_EQ(e.expected, value) << "str=\"" << e.str << "\" base=" << e.base; >+ } >+ } >+} >+ >+// feenableexcept() and fedisableexcept() are missing on Mac OS X, MSVC, >+// and WebAssembly. >+#if defined(_MSC_VER) || defined(__APPLE__) || defined(__EMSCRIPTEN__) >+#define ABSL_MISSING_FEENABLEEXCEPT 1 >+#define ABSL_MISSING_FEDISABLEEXCEPT 1 >+#endif >+ >+class SimpleDtoaTest : public testing::Test { >+ protected: >+ void SetUp() override { >+ // Store the current floating point env & clear away any pending exceptions. >+ feholdexcept(&fp_env_); >+#ifndef ABSL_MISSING_FEENABLEEXCEPT >+ // Turn on floating point exceptions. >+ feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); >+#endif >+ } >+ >+ void TearDown() override { >+ // Restore the floating point environment to the original state. >+ // In theory fedisableexcept is unnecessary; fesetenv will also do it. >+ // In practice, our toolchains have subtle bugs. >+#ifndef ABSL_MISSING_FEDISABLEEXCEPT >+ fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); >+#endif >+ fesetenv(&fp_env_); >+ } >+ >+ std::string ToNineDigits(double value) { >+ char buffer[16]; // more than enough for %.9g >+ snprintf(buffer, sizeof(buffer), "%.9g", value); >+ return buffer; >+ } >+ >+ fenv_t fp_env_; >+}; >+ >+// Run the given runnable functor for "cases" test cases, chosen over the >+// available range of float. pi and e and 1/e are seeded, and then all >+// available integer powers of 2 and 10 are multiplied against them. In >+// addition to trying all those values, we try the next higher and next lower >+// float, and then we add additional test cases evenly distributed between them. >+// Each test case is passed to runnable as both a positive and negative value. >+template <typename R> >+void ExhaustiveFloat(uint32_t cases, R&& runnable) { >+ runnable(0.0f); >+ runnable(-0.0f); >+ if (cases >= 2e9) { // more than 2 billion? Might as well run them all. >+ for (float f = 0; f < std::numeric_limits<float>::max(); ) { >+ f = nextafterf(f, std::numeric_limits<float>::max()); >+ runnable(-f); >+ runnable(f); >+ } >+ return; >+ } >+ std::set<float> floats = {3.4028234e38f}; >+ for (float f : {1.0, 3.14159265, 2.718281828, 1 / 2.718281828}) { >+ for (float testf = f; testf != 0; testf *= 0.1f) floats.insert(testf); >+ for (float testf = f; testf != 0; testf *= 0.5f) floats.insert(testf); >+ for (float testf = f; testf < 3e38f / 2; testf *= 2.0f) >+ floats.insert(testf); >+ for (float testf = f; testf < 3e38f / 10; testf *= 10) floats.insert(testf); >+ } >+ >+ float last = *floats.begin(); >+ >+ runnable(last); >+ runnable(-last); >+ int iters_per_float = cases / floats.size(); >+ if (iters_per_float == 0) iters_per_float = 1; >+ for (float f : floats) { >+ if (f == last) continue; >+ float testf = nextafter(last, std::numeric_limits<float>::max()); >+ runnable(testf); >+ runnable(-testf); >+ last = testf; >+ if (f == last) continue; >+ double step = (double{f} - last) / iters_per_float; >+ for (double d = last + step; d < f; d += step) { >+ testf = d; >+ if (testf != last) { >+ runnable(testf); >+ runnable(-testf); >+ last = testf; >+ } >+ } >+ testf = nextafter(f, 0.0f); >+ if (testf > last) { >+ runnable(testf); >+ runnable(-testf); >+ last = testf; >+ } >+ if (f != last) { >+ runnable(f); >+ runnable(-f); >+ last = f; >+ } >+ } >+} >+ >+TEST_F(SimpleDtoaTest, ExhaustiveDoubleToSixDigits) { >+ uint64_t test_count = 0; >+ std::vector<double> mismatches; >+ auto checker = [&](double d) { >+ if (d != d) return; // rule out NaNs >+ ++test_count; >+ char sixdigitsbuf[kSixDigitsToBufferSize] = {0}; >+ SixDigitsToBuffer(d, sixdigitsbuf); >+ char snprintfbuf[kSixDigitsToBufferSize] = {0}; >+ snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d); >+ if (strcmp(sixdigitsbuf, snprintfbuf) != 0) { >+ mismatches.push_back(d); >+ if (mismatches.size() < 10) { >+ ABSL_RAW_LOG(ERROR, "%s", >+ absl::StrCat("Six-digit failure with double. ", "d=", d, >+ "=", d, " sixdigits=", sixdigitsbuf, >+ " printf(%g)=", snprintfbuf) >+ .c_str()); >+ } >+ } >+ }; >+ // Some quick sanity checks... >+ checker(5e-324); >+ checker(1e-308); >+ checker(1.0); >+ checker(1.000005); >+ checker(1.7976931348623157e308); >+ checker(0.00390625); >+#ifndef _MSC_VER >+ // on MSVC, snprintf() rounds it to 0.00195313. SixDigitsToBuffer() rounds it >+ // to 0.00195312 (round half to even). >+ checker(0.001953125); >+#endif >+ checker(0.005859375); >+ // Some cases where the rounding is very very close >+ checker(1.089095e-15); >+ checker(3.274195e-55); >+ checker(6.534355e-146); >+ checker(2.920845e+234); >+ >+ if (mismatches.empty()) { >+ test_count = 0; >+ ExhaustiveFloat(kFloatNumCases, checker); >+ >+ test_count = 0; >+ std::vector<int> digit_testcases{ >+ 100000, 100001, 100002, 100005, 100010, 100020, 100050, 100100, // misc >+ 195312, 195313, // 1.953125 is a case where we round down, just barely. >+ 200000, 500000, 800000, // misc mid-range cases >+ 585937, 585938, // 5.859375 is a case where we round up, just barely. >+ 900000, 990000, 999000, 999900, 999990, 999996, 999997, 999998, 999999}; >+ if (kFloatNumCases >= 1e9) { >+ // If at least 1 billion test cases were requested, user wants an >+ // exhaustive test. So let's test all mantissas, too. >+ constexpr int min_mantissa = 100000, max_mantissa = 999999; >+ digit_testcases.resize(max_mantissa - min_mantissa + 1); >+ std::iota(digit_testcases.begin(), digit_testcases.end(), min_mantissa); >+ } >+ >+ for (int exponent = -324; exponent <= 308; ++exponent) { >+ double powten = pow(10.0, exponent); >+ if (powten == 0) powten = 5e-324; >+ if (kFloatNumCases >= 1e9) { >+ // The exhaustive test takes a very long time, so log progress. >+ char buf[kSixDigitsToBufferSize]; >+ ABSL_RAW_LOG( >+ INFO, "%s", >+ absl::StrCat("Exp ", exponent, " powten=", powten, "(", >+ powten, ") (", >+ std::string(buf, SixDigitsToBuffer(powten, buf)), ")") >+ .c_str()); >+ } >+ for (int digits : digit_testcases) { >+ if (exponent == 308 && digits >= 179769) break; // don't overflow! >+ double digiform = (digits + 0.5) * 0.00001; >+ double testval = digiform * powten; >+ double pretestval = nextafter(testval, 0); >+ double posttestval = nextafter(testval, 1.7976931348623157e308); >+ checker(testval); >+ checker(pretestval); >+ checker(posttestval); >+ } >+ } >+ } else { >+ EXPECT_EQ(mismatches.size(), 0); >+ for (size_t i = 0; i < mismatches.size(); ++i) { >+ if (i > 100) i = mismatches.size() - 1; >+ double d = mismatches[i]; >+ char sixdigitsbuf[kSixDigitsToBufferSize] = {0}; >+ SixDigitsToBuffer(d, sixdigitsbuf); >+ char snprintfbuf[kSixDigitsToBufferSize] = {0}; >+ snprintf(snprintfbuf, kSixDigitsToBufferSize, "%g", d); >+ double before = nextafter(d, 0.0); >+ double after = nextafter(d, 1.7976931348623157e308); >+ char b1[32], b2[kSixDigitsToBufferSize]; >+ ABSL_RAW_LOG( >+ ERROR, "%s", >+ absl::StrCat( >+ "Mismatch #", i, " d=", d, " (", ToNineDigits(d), ")", >+ " sixdigits='", sixdigitsbuf, "'", " snprintf='", snprintfbuf, >+ "'", " Before.=", PerfectDtoa(before), " ", >+ (SixDigitsToBuffer(before, b2), b2), >+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", before), b1), >+ " Perfect=", PerfectDtoa(d), " ", (SixDigitsToBuffer(d, b2), b2), >+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", d), b1), >+ " After.=.", PerfectDtoa(after), " ", >+ (SixDigitsToBuffer(after, b2), b2), >+ " vs snprintf=", (snprintf(b1, sizeof(b1), "%g", after), b1)) >+ .c_str()); >+ } >+ } >+} >+ >+TEST(StrToInt32, Partial) { >+ struct Int32TestLine { >+ std::string input; >+ bool status; >+ int32_t value; >+ }; >+ const int32_t int32_min = std::numeric_limits<int32_t>::min(); >+ const int32_t int32_max = std::numeric_limits<int32_t>::max(); >+ Int32TestLine int32_test_line[] = { >+ {"", false, 0}, >+ {" ", false, 0}, >+ {"-", false, 0}, >+ {"123@@@", false, 123}, >+ {absl::StrCat(int32_min, int32_max), false, int32_min}, >+ {absl::StrCat(int32_max, int32_max), false, int32_max}, >+ }; >+ >+ for (const Int32TestLine& test_line : int32_test_line) { >+ int32_t value = -2; >+ bool status = safe_strto32_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = -2; >+ status = safe_strto32_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = -2; >+ status = safe_strto32_base(absl::string_view(test_line.input), &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ } >+} >+ >+TEST(StrToUint32, Partial) { >+ struct Uint32TestLine { >+ std::string input; >+ bool status; >+ uint32_t value; >+ }; >+ const uint32_t uint32_max = std::numeric_limits<uint32_t>::max(); >+ Uint32TestLine uint32_test_line[] = { >+ {"", false, 0}, >+ {" ", false, 0}, >+ {"-", false, 0}, >+ {"123@@@", false, 123}, >+ {absl::StrCat(uint32_max, uint32_max), false, uint32_max}, >+ }; >+ >+ for (const Uint32TestLine& test_line : uint32_test_line) { >+ uint32_t value = 2; >+ bool status = safe_strtou32_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = 2; >+ status = safe_strtou32_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = 2; >+ status = safe_strtou32_base(absl::string_view(test_line.input), &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ } >+} >+ >+TEST(StrToInt64, Partial) { >+ struct Int64TestLine { >+ std::string input; >+ bool status; >+ int64_t value; >+ }; >+ const int64_t int64_min = std::numeric_limits<int64_t>::min(); >+ const int64_t int64_max = std::numeric_limits<int64_t>::max(); >+ Int64TestLine int64_test_line[] = { >+ {"", false, 0}, >+ {" ", false, 0}, >+ {"-", false, 0}, >+ {"123@@@", false, 123}, >+ {absl::StrCat(int64_min, int64_max), false, int64_min}, >+ {absl::StrCat(int64_max, int64_max), false, int64_max}, >+ }; >+ >+ for (const Int64TestLine& test_line : int64_test_line) { >+ int64_t value = -2; >+ bool status = safe_strto64_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = -2; >+ status = safe_strto64_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = -2; >+ status = safe_strto64_base(absl::string_view(test_line.input), &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ } >+} >+ >+TEST(StrToUint64, Partial) { >+ struct Uint64TestLine { >+ std::string input; >+ bool status; >+ uint64_t value; >+ }; >+ const uint64_t uint64_max = std::numeric_limits<uint64_t>::max(); >+ Uint64TestLine uint64_test_line[] = { >+ {"", false, 0}, >+ {" ", false, 0}, >+ {"-", false, 0}, >+ {"123@@@", false, 123}, >+ {absl::StrCat(uint64_max, uint64_max), false, uint64_max}, >+ }; >+ >+ for (const Uint64TestLine& test_line : uint64_test_line) { >+ uint64_t value = 2; >+ bool status = safe_strtou64_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = 2; >+ status = safe_strtou64_base(test_line.input, &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ value = 2; >+ status = safe_strtou64_base(absl::string_view(test_line.input), &value, 10); >+ EXPECT_EQ(test_line.status, status) << test_line.input; >+ EXPECT_EQ(test_line.value, value) << test_line.input; >+ } >+} >+ >+TEST(StrToInt32Base, PrefixOnly) { >+ struct Int32TestLine { >+ std::string input; >+ bool status; >+ int32_t value; >+ }; >+ Int32TestLine int32_test_line[] = { >+ { "", false, 0 }, >+ { "-", false, 0 }, >+ { "-0", true, 0 }, >+ { "0", true, 0 }, >+ { "0x", false, 0 }, >+ { "-0x", false, 0 }, >+ }; >+ const int base_array[] = { 0, 2, 8, 10, 16 }; >+ >+ for (const Int32TestLine& line : int32_test_line) { >+ for (const int base : base_array) { >+ int32_t value = 2; >+ bool status = safe_strto32_base(line.input.c_str(), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strto32_base(line.input, &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strto32_base(absl::string_view(line.input), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ } >+ } >+} >+ >+TEST(StrToUint32Base, PrefixOnly) { >+ struct Uint32TestLine { >+ std::string input; >+ bool status; >+ uint32_t value; >+ }; >+ Uint32TestLine uint32_test_line[] = { >+ { "", false, 0 }, >+ { "0", true, 0 }, >+ { "0x", false, 0 }, >+ }; >+ const int base_array[] = { 0, 2, 8, 10, 16 }; >+ >+ for (const Uint32TestLine& line : uint32_test_line) { >+ for (const int base : base_array) { >+ uint32_t value = 2; >+ bool status = safe_strtou32_base(line.input.c_str(), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strtou32_base(line.input, &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strtou32_base(absl::string_view(line.input), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ } >+ } >+} >+ >+TEST(StrToInt64Base, PrefixOnly) { >+ struct Int64TestLine { >+ std::string input; >+ bool status; >+ int64_t value; >+ }; >+ Int64TestLine int64_test_line[] = { >+ { "", false, 0 }, >+ { "-", false, 0 }, >+ { "-0", true, 0 }, >+ { "0", true, 0 }, >+ { "0x", false, 0 }, >+ { "-0x", false, 0 }, >+ }; >+ const int base_array[] = { 0, 2, 8, 10, 16 }; >+ >+ for (const Int64TestLine& line : int64_test_line) { >+ for (const int base : base_array) { >+ int64_t value = 2; >+ bool status = safe_strto64_base(line.input.c_str(), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strto64_base(line.input, &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strto64_base(absl::string_view(line.input), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ } >+ } >+} >+ >+TEST(StrToUint64Base, PrefixOnly) { >+ struct Uint64TestLine { >+ std::string input; >+ bool status; >+ uint64_t value; >+ }; >+ Uint64TestLine uint64_test_line[] = { >+ { "", false, 0 }, >+ { "0", true, 0 }, >+ { "0x", false, 0 }, >+ }; >+ const int base_array[] = { 0, 2, 8, 10, 16 }; >+ >+ for (const Uint64TestLine& line : uint64_test_line) { >+ for (const int base : base_array) { >+ uint64_t value = 2; >+ bool status = safe_strtou64_base(line.input.c_str(), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strtou64_base(line.input, &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ value = 2; >+ status = safe_strtou64_base(absl::string_view(line.input), &value, base); >+ EXPECT_EQ(line.status, status) << line.input << " " << base; >+ EXPECT_EQ(line.value, value) << line.input << " " << base; >+ } >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.cc >new file mode 100644 >index 00000000000..3fe8c95eca9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.cc >@@ -0,0 +1,239 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_cat.h" >+ >+#include <assert.h> >+#include <algorithm> >+#include <cstdint> >+#include <cstring> >+ >+#include "absl/strings/ascii.h" >+#include "absl/strings/internal/resize_uninitialized.h" >+ >+namespace absl { >+ >+AlphaNum::AlphaNum(Hex hex) { >+ char* const end = &digits_[numbers_internal::kFastToBufferSize]; >+ char* writer = end; >+ uint64_t value = hex.value; >+ static const char hexdigits[] = "0123456789abcdef"; >+ do { >+ *--writer = hexdigits[value & 0xF]; >+ value >>= 4; >+ } while (value != 0); >+ >+ char* beg; >+ if (end - writer < hex.width) { >+ beg = end - hex.width; >+ std::fill_n(beg, writer - beg, hex.fill); >+ } else { >+ beg = writer; >+ } >+ >+ piece_ = absl::string_view(beg, end - beg); >+} >+ >+AlphaNum::AlphaNum(Dec dec) { >+ assert(dec.width <= numbers_internal::kFastToBufferSize); >+ char* const end = &digits_[numbers_internal::kFastToBufferSize]; >+ char* const minfill = end - dec.width; >+ char* writer = end; >+ uint64_t value = dec.value; >+ bool neg = dec.neg; >+ while (value > 9) { >+ *--writer = '0' + (value % 10); >+ value /= 10; >+ } >+ *--writer = '0' + value; >+ if (neg) *--writer = '-'; >+ >+ ptrdiff_t fillers = writer - minfill; >+ if (fillers > 0) { >+ // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> >+ // But...: if the fill character is '0', then it's <+/-><fill><digits> >+ bool add_sign_again = false; >+ if (neg && dec.fill == '0') { // If filling with '0', >+ ++writer; // ignore the sign we just added >+ add_sign_again = true; // and re-add the sign later. >+ } >+ writer -= fillers; >+ std::fill_n(writer, fillers, dec.fill); >+ if (add_sign_again) *--writer = '-'; >+ } >+ >+ piece_ = absl::string_view(writer, end - writer); >+} >+ >+// ---------------------------------------------------------------------- >+// StrCat() >+// This merges the given strings or integers, with no delimiter. This >+// is designed to be the fastest possible way to construct a std::string out >+// of a mix of raw C strings, StringPieces, strings, and integer values. >+// ---------------------------------------------------------------------- >+ >+// Append is merely a version of memcpy that returns the address of the byte >+// after the area just overwritten. >+static char* Append(char* out, const AlphaNum& x) { >+ // memcpy is allowed to overwrite arbitrary memory, so doing this after the >+ // call would force an extra fetch of x.size(). >+ char* after = out + x.size(); >+ memcpy(out, x.data(), x.size()); >+ return after; >+} >+ >+std::string StrCat(const AlphaNum& a, const AlphaNum& b) { >+ std::string result; >+ absl::strings_internal::STLStringResizeUninitialized(&result, >+ a.size() + b.size()); >+ char* const begin = &*result.begin(); >+ char* out = begin; >+ out = Append(out, a); >+ out = Append(out, b); >+ assert(out == begin + result.size()); >+ return result; >+} >+ >+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { >+ std::string result; >+ strings_internal::STLStringResizeUninitialized( >+ &result, a.size() + b.size() + c.size()); >+ char* const begin = &*result.begin(); >+ char* out = begin; >+ out = Append(out, a); >+ out = Append(out, b); >+ out = Append(out, c); >+ assert(out == begin + result.size()); >+ return result; >+} >+ >+std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c, >+ const AlphaNum& d) { >+ std::string result; >+ strings_internal::STLStringResizeUninitialized( >+ &result, a.size() + b.size() + c.size() + d.size()); >+ char* const begin = &*result.begin(); >+ char* out = begin; >+ out = Append(out, a); >+ out = Append(out, b); >+ out = Append(out, c); >+ out = Append(out, d); >+ assert(out == begin + result.size()); >+ return result; >+} >+ >+namespace strings_internal { >+ >+// Do not call directly - these are not part of the public API. >+std::string CatPieces(std::initializer_list<absl::string_view> pieces) { >+ std::string result; >+ size_t total_size = 0; >+ for (const absl::string_view piece : pieces) total_size += piece.size(); >+ strings_internal::STLStringResizeUninitialized(&result, total_size); >+ >+ char* const begin = &*result.begin(); >+ char* out = begin; >+ for (const absl::string_view piece : pieces) { >+ const size_t this_size = piece.size(); >+ memcpy(out, piece.data(), this_size); >+ out += this_size; >+ } >+ assert(out == begin + result.size()); >+ return result; >+} >+ >+// It's possible to call StrAppend with an absl::string_view that is itself a >+// fragment of the std::string we're appending to. However the results of this are >+// random. Therefore, check for this in debug mode. Use unsigned math so we >+// only have to do one comparison. Note, there's an exception case: appending an >+// empty std::string is always allowed. >+#define ASSERT_NO_OVERLAP(dest, src) \ >+ assert(((src).size() == 0) || \ >+ (uintptr_t((src).data() - (dest).data()) > uintptr_t((dest).size()))) >+ >+void AppendPieces(std::string* dest, >+ std::initializer_list<absl::string_view> pieces) { >+ size_t old_size = dest->size(); >+ size_t total_size = old_size; >+ for (const absl::string_view piece : pieces) { >+ ASSERT_NO_OVERLAP(*dest, piece); >+ total_size += piece.size(); >+ } >+ strings_internal::STLStringResizeUninitialized(dest, total_size); >+ >+ char* const begin = &*dest->begin(); >+ char* out = begin + old_size; >+ for (const absl::string_view piece : pieces) { >+ const size_t this_size = piece.size(); >+ memcpy(out, piece.data(), this_size); >+ out += this_size; >+ } >+ assert(out == begin + dest->size()); >+} >+ >+} // namespace strings_internal >+ >+void StrAppend(std::string* dest, const AlphaNum& a) { >+ ASSERT_NO_OVERLAP(*dest, a); >+ dest->append(a.data(), a.size()); >+} >+ >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b) { >+ ASSERT_NO_OVERLAP(*dest, a); >+ ASSERT_NO_OVERLAP(*dest, b); >+ std::string::size_type old_size = dest->size(); >+ strings_internal::STLStringResizeUninitialized( >+ dest, old_size + a.size() + b.size()); >+ char* const begin = &*dest->begin(); >+ char* out = begin + old_size; >+ out = Append(out, a); >+ out = Append(out, b); >+ assert(out == begin + dest->size()); >+} >+ >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c) { >+ ASSERT_NO_OVERLAP(*dest, a); >+ ASSERT_NO_OVERLAP(*dest, b); >+ ASSERT_NO_OVERLAP(*dest, c); >+ std::string::size_type old_size = dest->size(); >+ strings_internal::STLStringResizeUninitialized( >+ dest, old_size + a.size() + b.size() + c.size()); >+ char* const begin = &*dest->begin(); >+ char* out = begin + old_size; >+ out = Append(out, a); >+ out = Append(out, b); >+ out = Append(out, c); >+ assert(out == begin + dest->size()); >+} >+ >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c, const AlphaNum& d) { >+ ASSERT_NO_OVERLAP(*dest, a); >+ ASSERT_NO_OVERLAP(*dest, b); >+ ASSERT_NO_OVERLAP(*dest, c); >+ ASSERT_NO_OVERLAP(*dest, d); >+ std::string::size_type old_size = dest->size(); >+ strings_internal::STLStringResizeUninitialized( >+ dest, old_size + a.size() + b.size() + c.size() + d.size()); >+ char* const begin = &*dest->begin(); >+ char* out = begin + old_size; >+ out = Append(out, a); >+ out = Append(out, b); >+ out = Append(out, c); >+ out = Append(out, d); >+ assert(out == begin + dest->size()); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.h >new file mode 100644 >index 00000000000..e5501a5012e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat.h >@@ -0,0 +1,385 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: str_cat.h >+// ----------------------------------------------------------------------------- >+// >+// This package contains functions for efficiently concatenating and appending >+// strings: `StrCat()` and `StrAppend()`. Most of the work within these routines >+// is actually handled through use of a special AlphaNum type, which was >+// designed to be used as a parameter type that efficiently manages conversion >+// to strings and avoids copies in the above operations. >+// >+// Any routine accepting either a std::string or a number may accept `AlphaNum`. >+// The basic idea is that by accepting a `const AlphaNum &` as an argument >+// to your function, your callers will automagically convert bools, integers, >+// and floating point values to strings for you. >+// >+// NOTE: Use of `AlphaNum` outside of the //absl/strings package is unsupported >+// except for the specific case of function parameters of type `AlphaNum` or >+// `const AlphaNum &`. In particular, instantiating `AlphaNum` directly as a >+// stack variable is not supported. >+// >+// Conversion from 8-bit values is not accepted because, if it were, then an >+// attempt to pass ':' instead of ":" might result in a 58 ending up in your >+// result. >+// >+// Bools convert to "0" or "1". >+// >+// Floating point numbers are formatted with six-digit precision, which is >+// the default for "std::cout <<" or printf "%g" (the same as "%.6g"). >+// >+// >+// You can convert to hexadecimal output rather than decimal output using the >+// `Hex` type contained here. To do so, pass `Hex(my_int)` as a parameter to >+// `StrCat()` or `StrAppend()`. You may specify a minimum hex field width using >+// a `PadSpec` enum. >+// >+// ----------------------------------------------------------------------------- >+ >+#ifndef ABSL_STRINGS_STR_CAT_H_ >+#define ABSL_STRINGS_STR_CAT_H_ >+ >+#include <array> >+#include <cstdint> >+#include <string> >+#include <type_traits> >+ >+#include "absl/base/port.h" >+#include "absl/strings/numbers.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+namespace strings_internal { >+// AlphaNumBuffer allows a way to pass a std::string to StrCat without having to do >+// memory allocation. It is simply a pair of a fixed-size character array, and >+// a size. Please don't use outside of absl, yet. >+template <size_t max_size> >+struct AlphaNumBuffer { >+ std::array<char, max_size> data; >+ size_t size; >+}; >+ >+} // namespace strings_internal >+ >+// Enum that specifies the number of significant digits to return in a `Hex` or >+// `Dec` conversion and fill character to use. A `kZeroPad2` value, for example, >+// would produce hexadecimal strings such as "0A","0F" and a 'kSpacePad5' value >+// would produce hexadecimal strings such as " A"," F". >+enum PadSpec : uint8_t { >+ kNoPad = 1, >+ kZeroPad2, >+ kZeroPad3, >+ kZeroPad4, >+ kZeroPad5, >+ kZeroPad6, >+ kZeroPad7, >+ kZeroPad8, >+ kZeroPad9, >+ kZeroPad10, >+ kZeroPad11, >+ kZeroPad12, >+ kZeroPad13, >+ kZeroPad14, >+ kZeroPad15, >+ kZeroPad16, >+ >+ kSpacePad2 = kZeroPad2 + 64, >+ kSpacePad3, >+ kSpacePad4, >+ kSpacePad5, >+ kSpacePad6, >+ kSpacePad7, >+ kSpacePad8, >+ kSpacePad9, >+ kSpacePad10, >+ kSpacePad11, >+ kSpacePad12, >+ kSpacePad13, >+ kSpacePad14, >+ kSpacePad15, >+ kSpacePad16, >+}; >+ >+// ----------------------------------------------------------------------------- >+// Hex >+// ----------------------------------------------------------------------------- >+// >+// `Hex` stores a set of hexadecimal std::string conversion parameters for use >+// within `AlphaNum` std::string conversions. >+struct Hex { >+ uint64_t value; >+ uint8_t width; >+ char fill; >+ >+ template <typename Int> >+ explicit Hex( >+ Int v, PadSpec spec = absl::kNoPad, >+ typename std::enable_if<sizeof(Int) == 1 && >+ !std::is_pointer<Int>::value>::type* = nullptr) >+ : Hex(spec, static_cast<uint8_t>(v)) {} >+ template <typename Int> >+ explicit Hex( >+ Int v, PadSpec spec = absl::kNoPad, >+ typename std::enable_if<sizeof(Int) == 2 && >+ !std::is_pointer<Int>::value>::type* = nullptr) >+ : Hex(spec, static_cast<uint16_t>(v)) {} >+ template <typename Int> >+ explicit Hex( >+ Int v, PadSpec spec = absl::kNoPad, >+ typename std::enable_if<sizeof(Int) == 4 && >+ !std::is_pointer<Int>::value>::type* = nullptr) >+ : Hex(spec, static_cast<uint32_t>(v)) {} >+ template <typename Int> >+ explicit Hex( >+ Int v, PadSpec spec = absl::kNoPad, >+ typename std::enable_if<sizeof(Int) == 8 && >+ !std::is_pointer<Int>::value>::type* = nullptr) >+ : Hex(spec, static_cast<uint64_t>(v)) {} >+ template <typename Pointee> >+ explicit Hex(Pointee* v, PadSpec spec = absl::kNoPad) >+ : Hex(spec, reinterpret_cast<uintptr_t>(v)) {} >+ >+ private: >+ Hex(PadSpec spec, uint64_t v) >+ : value(v), >+ width(spec == absl::kNoPad >+ ? 1 >+ : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 >+ : spec - absl::kZeroPad2 + 2), >+ fill(spec >= absl::kSpacePad2 ? ' ' : '0') {} >+}; >+ >+// ----------------------------------------------------------------------------- >+// Dec >+// ----------------------------------------------------------------------------- >+// >+// `Dec` stores a set of decimal std::string conversion parameters for use >+// within `AlphaNum` std::string conversions. Dec is slower than the default >+// integer conversion, so use it only if you need padding. >+struct Dec { >+ uint64_t value; >+ uint8_t width; >+ char fill; >+ bool neg; >+ >+ template <typename Int> >+ explicit Dec(Int v, PadSpec spec = absl::kNoPad, >+ typename std::enable_if<(sizeof(Int) <= 8)>::type* = nullptr) >+ : value(v >= 0 ? static_cast<uint64_t>(v) >+ : uint64_t{0} - static_cast<uint64_t>(v)), >+ width(spec == absl::kNoPad >+ ? 1 >+ : spec >= absl::kSpacePad2 ? spec - absl::kSpacePad2 + 2 >+ : spec - absl::kZeroPad2 + 2), >+ fill(spec >= absl::kSpacePad2 ? ' ' : '0'), >+ neg(v < 0) {} >+}; >+ >+// ----------------------------------------------------------------------------- >+// AlphaNum >+// ----------------------------------------------------------------------------- >+// >+// The `AlphaNum` class acts as the main parameter type for `StrCat()` and >+// `StrAppend()`, providing efficient conversion of numeric, boolean, and >+// hexadecimal values (through the `Hex` type) into strings. >+ >+class AlphaNum { >+ public: >+ // No bool ctor -- bools convert to an integral type. >+ // A bool ctor would also convert incoming pointers (bletch). >+ >+ AlphaNum(int x) // NOLINT(runtime/explicit) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ AlphaNum(unsigned int x) // NOLINT(runtime/explicit) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ AlphaNum(long x) // NOLINT(*) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ AlphaNum(unsigned long x) // NOLINT(*) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ AlphaNum(long long x) // NOLINT(*) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ AlphaNum(unsigned long long x) // NOLINT(*) >+ : piece_(digits_, >+ numbers_internal::FastIntToBuffer(x, digits_) - &digits_[0]) {} >+ >+ AlphaNum(float f) // NOLINT(runtime/explicit) >+ : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} >+ AlphaNum(double f) // NOLINT(runtime/explicit) >+ : piece_(digits_, numbers_internal::SixDigitsToBuffer(f, digits_)) {} >+ >+ AlphaNum(Hex hex); // NOLINT(runtime/explicit) >+ AlphaNum(Dec dec); // NOLINT(runtime/explicit) >+ >+ template <size_t size> >+ AlphaNum( // NOLINT(runtime/explicit) >+ const strings_internal::AlphaNumBuffer<size>& buf) >+ : piece_(&buf.data[0], buf.size) {} >+ >+ AlphaNum(const char* c_str) : piece_(c_str) {} // NOLINT(runtime/explicit) >+ AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit) >+ template <typename Allocator> >+ AlphaNum( // NOLINT(runtime/explicit) >+ const std::basic_string<char, std::char_traits<char>, Allocator>& str) >+ : piece_(str) {} >+ >+ // Use std::string literals ":" instead of character literals ':'. >+ AlphaNum(char c) = delete; // NOLINT(runtime/explicit) >+ >+ AlphaNum(const AlphaNum&) = delete; >+ AlphaNum& operator=(const AlphaNum&) = delete; >+ >+ absl::string_view::size_type size() const { return piece_.size(); } >+ const char* data() const { return piece_.data(); } >+ absl::string_view Piece() const { return piece_; } >+ >+ // Normal enums are already handled by the integer formatters. >+ // This overload matches only scoped enums. >+ template <typename T, >+ typename = typename std::enable_if< >+ std::is_enum<T>{} && !std::is_convertible<T, int>{}>::type> >+ AlphaNum(T e) // NOLINT(runtime/explicit) >+ : AlphaNum(static_cast<typename std::underlying_type<T>::type>(e)) {} >+ >+ private: >+ absl::string_view piece_; >+ char digits_[numbers_internal::kFastToBufferSize]; >+}; >+ >+// ----------------------------------------------------------------------------- >+// StrCat() >+// ----------------------------------------------------------------------------- >+// >+// Merges given strings or numbers, using no delimiter(s). >+// >+// `StrCat()` is designed to be the fastest possible way to construct a std::string >+// out of a mix of raw C strings, string_views, strings, bool values, >+// and numeric values. >+// >+// Don't use `StrCat()` for user-visible strings. The localization process >+// works poorly on strings built up out of fragments. >+// >+// For clarity and performance, don't use `StrCat()` when appending to a >+// std::string. Use `StrAppend()` instead. In particular, avoid using any of these >+// (anti-)patterns: >+// >+// str.append(StrCat(...)) >+// str += StrCat(...) >+// str = StrCat(str, ...) >+// >+// The last case is the worst, with a potential to change a loop >+// from a linear time operation with O(1) dynamic allocations into a >+// quadratic time operation with O(n) dynamic allocations. >+// >+// See `StrAppend()` below for more information. >+ >+namespace strings_internal { >+ >+// Do not call directly - this is not part of the public API. >+std::string CatPieces(std::initializer_list<absl::string_view> pieces); >+void AppendPieces(std::string* dest, >+ std::initializer_list<absl::string_view> pieces); >+ >+} // namespace strings_internal >+ >+ABSL_MUST_USE_RESULT inline std::string StrCat() { return std::string(); } >+ >+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a) { >+ return std::string(a.data(), a.size()); >+} >+ >+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b); >+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c); >+ABSL_MUST_USE_RESULT std::string StrCat(const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c, const AlphaNum& d); >+ >+// Support 5 or more arguments >+template <typename... AV> >+ABSL_MUST_USE_RESULT inline std::string StrCat(const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c, const AlphaNum& d, >+ const AlphaNum& e, >+ const AV&... args) { >+ return strings_internal::CatPieces( >+ {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), >+ static_cast<const AlphaNum&>(args).Piece()...}); >+} >+ >+// ----------------------------------------------------------------------------- >+// StrAppend() >+// ----------------------------------------------------------------------------- >+// >+// Appends a std::string or set of strings to an existing std::string, in a similar >+// fashion to `StrCat()`. >+// >+// WARNING: `StrAppend(&str, a, b, c, ...)` requires that none of the >+// a, b, c, parameters be a reference into str. For speed, `StrAppend()` does >+// not try to check each of its input arguments to be sure that they are not >+// a subset of the std::string being appended to. That is, while this will work: >+// >+// std::string s = "foo"; >+// s += s; >+// >+// This output is undefined: >+// >+// std::string s = "foo"; >+// StrAppend(&s, s); >+// >+// This output is undefined as well, since `absl::string_view` does not own its >+// data: >+// >+// std::string s = "foobar"; >+// absl::string_view p = s; >+// StrAppend(&s, p); >+ >+inline void StrAppend(std::string*) {} >+void StrAppend(std::string* dest, const AlphaNum& a); >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b); >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c); >+void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c, const AlphaNum& d); >+ >+// Support 5 or more arguments >+template <typename... AV> >+inline void StrAppend(std::string* dest, const AlphaNum& a, const AlphaNum& b, >+ const AlphaNum& c, const AlphaNum& d, const AlphaNum& e, >+ const AV&... args) { >+ strings_internal::AppendPieces( >+ dest, {a.Piece(), b.Piece(), c.Piece(), d.Piece(), e.Piece(), >+ static_cast<const AlphaNum&>(args).Piece()...}); >+} >+ >+// Helper function for the future StrCat default floating-point format, %.6g >+// This is fast. >+inline strings_internal::AlphaNumBuffer< >+ numbers_internal::kSixDigitsToBufferSize> >+SixDigits(double d) { >+ strings_internal::AlphaNumBuffer<numbers_internal::kSixDigitsToBufferSize> >+ result; >+ result.size = numbers_internal::SixDigitsToBuffer(d, &result.data[0]); >+ return result; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STR_CAT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_benchmark.cc >new file mode 100644 >index 00000000000..b6df9e309c4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_benchmark.cc >@@ -0,0 +1,140 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_cat.h" >+ >+#include <cstdint> >+#include <string> >+ >+#include "benchmark/benchmark.h" >+#include "absl/strings/substitute.h" >+ >+namespace { >+ >+const char kStringOne[] = "Once Upon A Time, "; >+const char kStringTwo[] = "There was a std::string benchmark"; >+ >+// We want to include negative numbers in the benchmark, so this function >+// is used to count 0, 1, -1, 2, -2, 3, -3, ... >+inline int IncrementAlternatingSign(int i) { >+ return i > 0 ? -i : 1 - i; >+} >+ >+void BM_Sum_By_StrCat(benchmark::State& state) { >+ int i = 0; >+ char foo[100]; >+ for (auto _ : state) { >+ // NOLINTNEXTLINE(runtime/printf) >+ strcpy(foo, absl::StrCat(kStringOne, i, kStringTwo, i * 65536ULL).c_str()); >+ int sum = 0; >+ for (char* f = &foo[0]; *f != 0; ++f) { >+ sum += *f; >+ } >+ benchmark::DoNotOptimize(sum); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_Sum_By_StrCat); >+ >+void BM_StrCat_By_snprintf(benchmark::State& state) { >+ int i = 0; >+ char on_stack[1000]; >+ for (auto _ : state) { >+ snprintf(on_stack, sizeof(on_stack), "%s %s:%d", kStringOne, kStringTwo, i); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_StrCat_By_snprintf); >+ >+void BM_StrCat_By_Strings(benchmark::State& state) { >+ int i = 0; >+ for (auto _ : state) { >+ std::string result = >+ std::string(kStringOne) + " " + kStringTwo + ":" + absl::StrCat(i); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_StrCat_By_Strings); >+ >+void BM_StrCat_By_StringOpPlus(benchmark::State& state) { >+ int i = 0; >+ for (auto _ : state) { >+ std::string result = kStringOne; >+ result += " "; >+ result += kStringTwo; >+ result += ":"; >+ result += absl::StrCat(i); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_StrCat_By_StringOpPlus); >+ >+void BM_StrCat_By_StrCat(benchmark::State& state) { >+ int i = 0; >+ for (auto _ : state) { >+ std::string result = absl::StrCat(kStringOne, " ", kStringTwo, ":", i); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_StrCat_By_StrCat); >+ >+void BM_HexCat_By_StrCat(benchmark::State& state) { >+ int i = 0; >+ for (auto _ : state) { >+ std::string result = >+ absl::StrCat(kStringOne, " ", absl::Hex(int64_t{i} + 0x10000000)); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_HexCat_By_StrCat); >+ >+void BM_HexCat_By_Substitute(benchmark::State& state) { >+ int i = 0; >+ for (auto _ : state) { >+ std::string result = absl::Substitute( >+ "$0 $1", kStringOne, reinterpret_cast<void*>(int64_t{i} + 0x10000000)); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_HexCat_By_Substitute); >+ >+void BM_FloatToString_By_StrCat(benchmark::State& state) { >+ int i = 0; >+ float foo = 0.0f; >+ for (auto _ : state) { >+ std::string result = absl::StrCat(foo += 1.001f, " != ", int64_t{i}); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_FloatToString_By_StrCat); >+ >+void BM_DoubleToString_By_SixDigits(benchmark::State& state) { >+ int i = 0; >+ double foo = 0.0; >+ for (auto _ : state) { >+ std::string result = >+ absl::StrCat(absl::SixDigits(foo += 1.001), " != ", int64_t{i}); >+ benchmark::DoNotOptimize(result); >+ i = IncrementAlternatingSign(i); >+ } >+} >+BENCHMARK(BM_DoubleToString_By_SixDigits); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_test.cc >new file mode 100644 >index 00000000000..e9d67690638 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_cat_test.cc >@@ -0,0 +1,549 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit tests for all str_cat.h functions >+ >+#include "absl/strings/str_cat.h" >+ >+#include <cstdint> >+#include <string> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/substitute.h" >+ >+#ifdef __ANDROID__ >+// Android assert messages only go to system log, so death tests cannot inspect >+// the message for matching. >+#define ABSL_EXPECT_DEBUG_DEATH(statement, regex) \ >+ EXPECT_DEBUG_DEATH(statement, ".*") >+#else >+#define ABSL_EXPECT_DEBUG_DEATH EXPECT_DEBUG_DEATH >+#endif >+ >+namespace { >+ >+// Test absl::StrCat of ints and longs of various sizes and signdedness. >+TEST(StrCat, Ints) { >+ const short s = -1; // NOLINT(runtime/int) >+ const uint16_t us = 2; >+ const int i = -3; >+ const unsigned int ui = 4; >+ const long l = -5; // NOLINT(runtime/int) >+ const unsigned long ul = 6; // NOLINT(runtime/int) >+ const long long ll = -7; // NOLINT(runtime/int) >+ const unsigned long long ull = 8; // NOLINT(runtime/int) >+ const ptrdiff_t ptrdiff = -9; >+ const size_t size = 10; >+ const intptr_t intptr = -12; >+ const uintptr_t uintptr = 13; >+ std::string answer; >+ answer = absl::StrCat(s, us); >+ EXPECT_EQ(answer, "-12"); >+ answer = absl::StrCat(i, ui); >+ EXPECT_EQ(answer, "-34"); >+ answer = absl::StrCat(l, ul); >+ EXPECT_EQ(answer, "-56"); >+ answer = absl::StrCat(ll, ull); >+ EXPECT_EQ(answer, "-78"); >+ answer = absl::StrCat(ptrdiff, size); >+ EXPECT_EQ(answer, "-910"); >+ answer = absl::StrCat(ptrdiff, intptr); >+ EXPECT_EQ(answer, "-9-12"); >+ answer = absl::StrCat(uintptr, 0); >+ EXPECT_EQ(answer, "130"); >+} >+ >+TEST(StrCat, Enums) { >+ enum SmallNumbers { One = 1, Ten = 10 } e = Ten; >+ EXPECT_EQ("10", absl::StrCat(e)); >+ EXPECT_EQ("-5", absl::StrCat(SmallNumbers(-5))); >+ >+ enum class Option { Boxers = 1, Briefs = -1 }; >+ >+ EXPECT_EQ("-1", absl::StrCat(Option::Briefs)); >+ >+ enum class Airplane : uint64_t { >+ Airbus = 1, >+ Boeing = 1000, >+ Canary = 10000000000 // too big for "int" >+ }; >+ >+ EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary)); >+ >+ enum class TwoGig : int32_t { >+ TwoToTheZero = 1, >+ TwoToTheSixteenth = 1 << 16, >+ TwoToTheThirtyFirst = INT32_MIN >+ }; >+ EXPECT_EQ("65536", absl::StrCat(TwoGig::TwoToTheSixteenth)); >+ EXPECT_EQ("-2147483648", absl::StrCat(TwoGig::TwoToTheThirtyFirst)); >+ EXPECT_EQ("-1", absl::StrCat(static_cast<TwoGig>(-1))); >+ >+ enum class FourGig : uint32_t { >+ TwoToTheZero = 1, >+ TwoToTheSixteenth = 1 << 16, >+ TwoToTheThirtyFirst = 1U << 31 // too big for "int" >+ }; >+ EXPECT_EQ("65536", absl::StrCat(FourGig::TwoToTheSixteenth)); >+ EXPECT_EQ("2147483648", absl::StrCat(FourGig::TwoToTheThirtyFirst)); >+ EXPECT_EQ("4294967295", absl::StrCat(static_cast<FourGig>(-1))); >+ >+ EXPECT_EQ("10000000000", absl::StrCat(Airplane::Canary)); >+} >+ >+TEST(StrCat, Basics) { >+ std::string result; >+ >+ std::string strs[] = { >+ "Hello", >+ "Cruel", >+ "World" >+ }; >+ >+ std::string stdstrs[] = { >+ "std::Hello", >+ "std::Cruel", >+ "std::World" >+ }; >+ >+ absl::string_view pieces[] = {"Hello", "Cruel", "World"}; >+ >+ const char* c_strs[] = { >+ "Hello", >+ "Cruel", >+ "World" >+ }; >+ >+ int32_t i32s[] = {'H', 'C', 'W'}; >+ uint64_t ui64s[] = {12345678910LL, 10987654321LL}; >+ >+ EXPECT_EQ(absl::StrCat(), ""); >+ >+ result = absl::StrCat(false, true, 2, 3); >+ EXPECT_EQ(result, "0123"); >+ >+ result = absl::StrCat(-1); >+ EXPECT_EQ(result, "-1"); >+ >+ result = absl::StrCat(absl::SixDigits(0.5)); >+ EXPECT_EQ(result, "0.5"); >+ >+ result = absl::StrCat(strs[1], pieces[2]); >+ EXPECT_EQ(result, "CruelWorld"); >+ >+ result = absl::StrCat(stdstrs[1], " ", stdstrs[2]); >+ EXPECT_EQ(result, "std::Cruel std::World"); >+ >+ result = absl::StrCat(strs[0], ", ", pieces[2]); >+ EXPECT_EQ(result, "Hello, World"); >+ >+ result = absl::StrCat(strs[0], ", ", strs[1], " ", strs[2], "!"); >+ EXPECT_EQ(result, "Hello, Cruel World!"); >+ >+ result = absl::StrCat(pieces[0], ", ", pieces[1], " ", pieces[2]); >+ EXPECT_EQ(result, "Hello, Cruel World"); >+ >+ result = absl::StrCat(c_strs[0], ", ", c_strs[1], " ", c_strs[2]); >+ EXPECT_EQ(result, "Hello, Cruel World"); >+ >+ result = absl::StrCat("ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!"); >+ EXPECT_EQ(result, "ASCII 72, 67 87!"); >+ >+ result = absl::StrCat(ui64s[0], ", ", ui64s[1], "!"); >+ EXPECT_EQ(result, "12345678910, 10987654321!"); >+ >+ std::string one = "1"; // Actually, it's the size of this std::string that we want; a >+ // 64-bit build distinguishes between size_t and uint64_t, >+ // even though they're both unsigned 64-bit values. >+ result = absl::StrCat("And a ", one.size(), " and a ", >+ &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); >+ EXPECT_EQ(result, "And a 1 and a 2 and a 1 2 3 4!"); >+ >+ // result = absl::StrCat("Single chars won't compile", '!'); >+ // result = absl::StrCat("Neither will nullptrs", nullptr); >+ result = >+ absl::StrCat("To output a char by ASCII/numeric value, use +: ", '!' + 0); >+ EXPECT_EQ(result, "To output a char by ASCII/numeric value, use +: 33"); >+ >+ float f = 100000.5; >+ result = absl::StrCat("A hundred K and a half is ", absl::SixDigits(f)); >+ EXPECT_EQ(result, "A hundred K and a half is 100000"); >+ >+ f = 100001.5; >+ result = >+ absl::StrCat("A hundred K and one and a half is ", absl::SixDigits(f)); >+ EXPECT_EQ(result, "A hundred K and one and a half is 100002"); >+ >+ double d = 100000.5; >+ d *= d; >+ result = >+ absl::StrCat("A hundred K and a half squared is ", absl::SixDigits(d)); >+ EXPECT_EQ(result, "A hundred K and a half squared is 1.00001e+10"); >+ >+ result = absl::StrCat(1, 2, 333, 4444, 55555, 666666, 7777777, 88888888, >+ 999999999); >+ EXPECT_EQ(result, "12333444455555666666777777788888888999999999"); >+} >+ >+// A minimal allocator that uses malloc(). >+template <typename T> >+struct Mallocator { >+ typedef T value_type; >+ typedef size_t size_type; >+ typedef ptrdiff_t difference_type; >+ typedef T* pointer; >+ typedef const T* const_pointer; >+ typedef T& reference; >+ typedef const T& const_reference; >+ >+ size_type max_size() const { >+ return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type); >+ } >+ template <typename U> >+ struct rebind { >+ typedef Mallocator<U> other; >+ }; >+ Mallocator() = default; >+ template <class U> >+ Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit) >+ >+ T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); } >+ void deallocate(T* p, size_t) { std::free(p); } >+}; >+template <typename T, typename U> >+bool operator==(const Mallocator<T>&, const Mallocator<U>&) { >+ return true; >+} >+template <typename T, typename U> >+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { >+ return false; >+} >+ >+TEST(StrCat, CustomAllocator) { >+ using mstring = >+ std::basic_string<char, std::char_traits<char>, Mallocator<char>>; >+ const mstring str1("PARACHUTE OFF A BLIMP INTO MOSCONE!!"); >+ >+ const mstring str2("Read this book about coffee tables"); >+ >+ std::string result = absl::StrCat(str1, str2); >+ EXPECT_EQ(result, >+ "PARACHUTE OFF A BLIMP INTO MOSCONE!!" >+ "Read this book about coffee tables"); >+} >+ >+TEST(StrCat, MaxArgs) { >+ std::string result; >+ // Test 10 up to 26 arguments, the old maximum >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a"); >+ EXPECT_EQ(result, "123456789a"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b"); >+ EXPECT_EQ(result, "123456789ab"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c"); >+ EXPECT_EQ(result, "123456789abc"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d"); >+ EXPECT_EQ(result, "123456789abcd"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e"); >+ EXPECT_EQ(result, "123456789abcde"); >+ result = >+ absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f"); >+ EXPECT_EQ(result, "123456789abcdef"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g"); >+ EXPECT_EQ(result, "123456789abcdefg"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h"); >+ EXPECT_EQ(result, "123456789abcdefgh"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i"); >+ EXPECT_EQ(result, "123456789abcdefghi"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j"); >+ EXPECT_EQ(result, "123456789abcdefghij"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k"); >+ EXPECT_EQ(result, "123456789abcdefghijk"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l"); >+ EXPECT_EQ(result, "123456789abcdefghijkl"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l", "m"); >+ EXPECT_EQ(result, "123456789abcdefghijklm"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l", "m", "n"); >+ EXPECT_EQ(result, "123456789abcdefghijklmn"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l", "m", "n", "o"); >+ EXPECT_EQ(result, "123456789abcdefghijklmno"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"); >+ EXPECT_EQ(result, "123456789abcdefghijklmnop"); >+ result = absl::StrCat(1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f", >+ "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q"); >+ EXPECT_EQ(result, "123456789abcdefghijklmnopq"); >+ // No limit thanks to C++11's variadic templates >+ result = absl::StrCat( >+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, "a", "b", "c", "d", "e", "f", "g", "h", >+ "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", >+ "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", >+ "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"); >+ EXPECT_EQ(result, >+ "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); >+} >+ >+TEST(StrAppend, Basics) { >+ std::string result = "existing text"; >+ >+ std::string strs[] = { >+ "Hello", >+ "Cruel", >+ "World" >+ }; >+ >+ std::string stdstrs[] = { >+ "std::Hello", >+ "std::Cruel", >+ "std::World" >+ }; >+ >+ absl::string_view pieces[] = {"Hello", "Cruel", "World"}; >+ >+ const char* c_strs[] = { >+ "Hello", >+ "Cruel", >+ "World" >+ }; >+ >+ int32_t i32s[] = {'H', 'C', 'W'}; >+ uint64_t ui64s[] = {12345678910LL, 10987654321LL}; >+ >+ std::string::size_type old_size = result.size(); >+ absl::StrAppend(&result); >+ EXPECT_EQ(result.size(), old_size); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, strs[0]); >+ EXPECT_EQ(result.substr(old_size), "Hello"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, strs[1], pieces[2]); >+ EXPECT_EQ(result.substr(old_size), "CruelWorld"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, stdstrs[0], ", ", pieces[2]); >+ EXPECT_EQ(result.substr(old_size), "std::Hello, World"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, strs[0], ", ", stdstrs[1], " ", strs[2], "!"); >+ EXPECT_EQ(result.substr(old_size), "Hello, std::Cruel World!"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, pieces[0], ", ", pieces[1], " ", pieces[2]); >+ EXPECT_EQ(result.substr(old_size), "Hello, Cruel World"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, c_strs[0], ", ", c_strs[1], " ", c_strs[2]); >+ EXPECT_EQ(result.substr(old_size), "Hello, Cruel World"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, "ASCII ", i32s[0], ", ", i32s[1], " ", i32s[2], "!"); >+ EXPECT_EQ(result.substr(old_size), "ASCII 72, 67 87!"); >+ >+ old_size = result.size(); >+ absl::StrAppend(&result, ui64s[0], ", ", ui64s[1], "!"); >+ EXPECT_EQ(result.substr(old_size), "12345678910, 10987654321!"); >+ >+ std::string one = "1"; // Actually, it's the size of this std::string that we want; a >+ // 64-bit build distinguishes between size_t and uint64_t, >+ // even though they're both unsigned 64-bit values. >+ old_size = result.size(); >+ absl::StrAppend(&result, "And a ", one.size(), " and a ", >+ &result[2] - &result[0], " and a ", one, " 2 3 4", "!"); >+ EXPECT_EQ(result.substr(old_size), "And a 1 and a 2 and a 1 2 3 4!"); >+ >+ // result = absl::StrCat("Single chars won't compile", '!'); >+ // result = absl::StrCat("Neither will nullptrs", nullptr); >+ old_size = result.size(); >+ absl::StrAppend(&result, >+ "To output a char by ASCII/numeric value, use +: ", '!' + 0); >+ EXPECT_EQ(result.substr(old_size), >+ "To output a char by ASCII/numeric value, use +: 33"); >+ >+ // Test 9 arguments, the old maximum >+ old_size = result.size(); >+ absl::StrAppend(&result, 1, 22, 333, 4444, 55555, 666666, 7777777, 88888888, >+ 9); >+ EXPECT_EQ(result.substr(old_size), "1223334444555556666667777777888888889"); >+ >+ // No limit thanks to C++11's variadic templates >+ old_size = result.size(); >+ absl::StrAppend( >+ &result, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // >+ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", // >+ "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", // >+ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", // >+ "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", // >+ "No limit thanks to C++11's variadic templates"); >+ EXPECT_EQ(result.substr(old_size), >+ "12345678910abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" >+ "No limit thanks to C++11's variadic templates"); >+} >+ >+#ifdef GTEST_HAS_DEATH_TEST >+TEST(StrAppend, Death) { >+ std::string s = "self"; >+ // on linux it's "assertion", on mac it's "Assertion", >+ // on chromiumos it's "Assertion ... failed". >+ ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s.c_str() + 1), >+ "ssertion.*failed"); >+ ABSL_EXPECT_DEBUG_DEATH(absl::StrAppend(&s, s), "ssertion.*failed"); >+} >+#endif // GTEST_HAS_DEATH_TEST >+ >+TEST(StrAppend, EmptyString) { >+ std::string s = ""; >+ absl::StrAppend(&s, s); >+ EXPECT_EQ(s, ""); >+} >+ >+template <typename IntType> >+void CheckHex(IntType v, const char* nopad_format, const char* zeropad_format, >+ const char* spacepad_format) { >+ char expected[256]; >+ >+ std::string actual = absl::StrCat(absl::Hex(v, absl::kNoPad)); >+ snprintf(expected, sizeof(expected), nopad_format, v); >+ EXPECT_EQ(expected, actual) << " decimal value " << v; >+ >+ for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) { >+ std::string actual = >+ absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec))); >+ snprintf(expected, sizeof(expected), zeropad_format, >+ spec - absl::kZeroPad2 + 2, v); >+ EXPECT_EQ(expected, actual) << " decimal value " << v; >+ } >+ >+ for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) { >+ std::string actual = >+ absl::StrCat(absl::Hex(v, static_cast<absl::PadSpec>(spec))); >+ snprintf(expected, sizeof(expected), spacepad_format, >+ spec - absl::kSpacePad2 + 2, v); >+ EXPECT_EQ(expected, actual) << " decimal value " << v; >+ } >+} >+ >+template <typename IntType> >+void CheckDec(IntType v, const char* nopad_format, const char* zeropad_format, >+ const char* spacepad_format) { >+ char expected[256]; >+ >+ std::string actual = absl::StrCat(absl::Dec(v, absl::kNoPad)); >+ snprintf(expected, sizeof(expected), nopad_format, v); >+ EXPECT_EQ(expected, actual) << " decimal value " << v; >+ >+ for (int spec = absl::kZeroPad2; spec <= absl::kZeroPad16; ++spec) { >+ std::string actual = >+ absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec))); >+ snprintf(expected, sizeof(expected), zeropad_format, >+ spec - absl::kZeroPad2 + 2, v); >+ EXPECT_EQ(expected, actual) >+ << " decimal value " << v << " format '" << zeropad_format >+ << "' digits " << (spec - absl::kZeroPad2 + 2); >+ } >+ >+ for (int spec = absl::kSpacePad2; spec <= absl::kSpacePad16; ++spec) { >+ std::string actual = >+ absl::StrCat(absl::Dec(v, static_cast<absl::PadSpec>(spec))); >+ snprintf(expected, sizeof(expected), spacepad_format, >+ spec - absl::kSpacePad2 + 2, v); >+ EXPECT_EQ(expected, actual) >+ << " decimal value " << v << " format '" << spacepad_format >+ << "' digits " << (spec - absl::kSpacePad2 + 2); >+ } >+} >+ >+void CheckHexDec64(uint64_t v) { >+ unsigned long long ullv = v; // NOLINT(runtime/int) >+ >+ CheckHex(ullv, "%llx", "%0*llx", "%*llx"); >+ CheckDec(ullv, "%llu", "%0*llu", "%*llu"); >+ >+ long long llv = static_cast<long long>(ullv); // NOLINT(runtime/int) >+ CheckDec(llv, "%lld", "%0*lld", "%*lld"); >+ >+ if (sizeof(v) == sizeof(&v)) { >+ auto uintptr = static_cast<uintptr_t>(v); >+ void* ptr = reinterpret_cast<void*>(uintptr); >+ CheckHex(ptr, "%llx", "%0*llx", "%*llx"); >+ } >+} >+ >+void CheckHexDec32(uint32_t uv) { >+ CheckHex(uv, "%x", "%0*x", "%*x"); >+ CheckDec(uv, "%u", "%0*u", "%*u"); >+ int32_t v = static_cast<int32_t>(uv); >+ CheckDec(v, "%d", "%0*d", "%*d"); >+ >+ if (sizeof(v) == sizeof(&v)) { >+ auto uintptr = static_cast<uintptr_t>(v); >+ void* ptr = reinterpret_cast<void*>(uintptr); >+ CheckHex(ptr, "%x", "%0*x", "%*x"); >+ } >+} >+ >+void CheckAll(uint64_t v) { >+ CheckHexDec64(v); >+ CheckHexDec32(static_cast<uint32_t>(v)); >+} >+ >+void TestFastPrints() { >+ // Test all small ints; there aren't many and they're common. >+ for (int i = 0; i < 10000; i++) { >+ CheckAll(i); >+ } >+ >+ CheckAll(std::numeric_limits<uint64_t>::max()); >+ CheckAll(std::numeric_limits<uint64_t>::max() - 1); >+ CheckAll(std::numeric_limits<int64_t>::min()); >+ CheckAll(std::numeric_limits<int64_t>::min() + 1); >+ CheckAll(std::numeric_limits<uint32_t>::max()); >+ CheckAll(std::numeric_limits<uint32_t>::max() - 1); >+ CheckAll(std::numeric_limits<int32_t>::min()); >+ CheckAll(std::numeric_limits<int32_t>::min() + 1); >+ CheckAll(999999999); // fits in 32 bits >+ CheckAll(1000000000); // fits in 32 bits >+ CheckAll(9999999999); // doesn't fit in 32 bits >+ CheckAll(10000000000); // doesn't fit in 32 bits >+ CheckAll(999999999999999999); // fits in signed 64-bit >+ CheckAll(9999999999999999999u); // fits in unsigned 64-bit, but not signed. >+ CheckAll(1000000000000000000); // fits in signed 64-bit >+ CheckAll(10000000000000000000u); // fits in unsigned 64-bit, but not signed. >+ >+ CheckAll(999999999876543210); // check all decimal digits, signed >+ CheckAll(9999999999876543210u); // check all decimal digits, unsigned. >+ CheckAll(0x123456789abcdef0); // check all hex digits >+ CheckAll(0x12345678); >+ >+ int8_t minus_one_8bit = -1; >+ EXPECT_EQ("ff", absl::StrCat(absl::Hex(minus_one_8bit))); >+ >+ int16_t minus_one_16bit = -1; >+ EXPECT_EQ("ffff", absl::StrCat(absl::Hex(minus_one_16bit))); >+} >+ >+TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) { >+ TestFastPrints(); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format.h >new file mode 100644 >index 00000000000..70a811b75e2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format.h >@@ -0,0 +1,512 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: str_format.h >+// ----------------------------------------------------------------------------- >+// >+// The `str_format` library is a typesafe replacement for the family of >+// `printf()` std::string formatting routines within the `<cstdio>` standard library >+// header. Like the `printf` family, the `str_format` uses a "format string" to >+// perform argument substitutions based on types. >+// >+// Example: >+// >+// std::string s = absl::StrFormat("%s %s You have $%d!", "Hello", name, dollars); >+// >+// The library consists of the following basic utilities: >+// >+// * `absl::StrFormat()`, a type-safe replacement for `std::sprintf()`, to >+// write a format std::string to a `string` value. >+// * `absl::StrAppendFormat()` to append a format std::string to a `string` >+// * `absl::StreamFormat()` to more efficiently write a format std::string to a >+// stream, such as`std::cout`. >+// * `absl::PrintF()`, `absl::FPrintF()` and `absl::SNPrintF()` as >+// replacements for `std::printf()`, `std::fprintf()` and `std::snprintf()`. >+// >+// Note: a version of `std::sprintf()` is not supported as it is >+// generally unsafe due to buffer overflows. >+// >+// Additionally, you can provide a format std::string (and its associated arguments) >+// using one of the following abstractions: >+// >+// * A `FormatSpec` class template fully encapsulates a format std::string and its >+// type arguments and is usually provided to `str_format` functions as a >+// variadic argument of type `FormatSpec<Arg...>`. The `FormatSpec<Args...>` >+// template is evaluated at compile-time, providing type safety. >+// * A `ParsedFormat` instance, which encapsulates a specific, pre-compiled >+// format std::string for a specific set of type(s), and which can be passed >+// between API boundaries. (The `FormatSpec` type should not be used >+// directly.) >+// >+// The `str_format` library provides the ability to output its format strings to >+// arbitrary sink types: >+// >+// * A generic `Format()` function to write outputs to arbitrary sink types, >+// which must implement a `RawSinkFormat` interface. (See >+// `str_format_sink.h` for more information.) >+// >+// * A `FormatUntyped()` function that is similar to `Format()` except it is >+// loosely typed. `FormatUntyped()` is not a template and does not perform >+// any compile-time checking of the format std::string; instead, it returns a >+// boolean from a runtime check. >+// >+// In addition, the `str_format` library provides extension points for >+// augmenting formatting to new types. These extensions are fully documented >+// within the `str_format_extension.h` header file. >+#ifndef ABSL_STRINGS_STR_FORMAT_H_ >+#define ABSL_STRINGS_STR_FORMAT_H_ >+ >+#include <cstdio> >+#include <string> >+ >+#include "absl/strings/internal/str_format/arg.h" // IWYU pragma: export >+#include "absl/strings/internal/str_format/bind.h" // IWYU pragma: export >+#include "absl/strings/internal/str_format/checker.h" // IWYU pragma: export >+#include "absl/strings/internal/str_format/extension.h" // IWYU pragma: export >+#include "absl/strings/internal/str_format/parser.h" // IWYU pragma: export >+ >+namespace absl { >+ >+// UntypedFormatSpec >+// >+// A type-erased class that can be used directly within untyped API entry >+// points. An `UntypedFormatSpec` is specifically used as an argument to >+// `FormatUntyped()`. >+// >+// Example: >+// >+// absl::UntypedFormatSpec format("%d"); >+// std::string out; >+// CHECK(absl::FormatUntyped(&out, format, {absl::FormatArg(1)})); >+class UntypedFormatSpec { >+ public: >+ UntypedFormatSpec() = delete; >+ UntypedFormatSpec(const UntypedFormatSpec&) = delete; >+ UntypedFormatSpec& operator=(const UntypedFormatSpec&) = delete; >+ >+ explicit UntypedFormatSpec(string_view s) : spec_(s) {} >+ >+ protected: >+ explicit UntypedFormatSpec(const str_format_internal::ParsedFormatBase* pc) >+ : spec_(pc) {} >+ >+ private: >+ friend str_format_internal::UntypedFormatSpecImpl; >+ str_format_internal::UntypedFormatSpecImpl spec_; >+}; >+ >+// FormatStreamed() >+// >+// Takes a streamable argument and returns an object that can print it >+// with '%s'. Allows printing of types that have an `operator<<` but no >+// intrinsic type support within `StrFormat()` itself. >+// >+// Example: >+// >+// absl::StrFormat("%s", absl::FormatStreamed(obj)); >+template <typename T> >+str_format_internal::StreamedWrapper<T> FormatStreamed(const T& v) { >+ return str_format_internal::StreamedWrapper<T>(v); >+} >+ >+// FormatCountCapture >+// >+// This class provides a way to safely wrap `StrFormat()` captures of `%n` >+// conversions, which denote the number of characters written by a formatting >+// operation to this point, into an integer value. >+// >+// This wrapper is designed to allow safe usage of `%n` within `StrFormat(); in >+// the `printf()` family of functions, `%n` is not safe to use, as the `int *` >+// buffer can be used to capture arbitrary data. >+// >+// Example: >+// >+// int n = 0; >+// std::string s = absl::StrFormat("%s%d%n", "hello", 123, >+// absl::FormatCountCapture(&n)); >+// EXPECT_EQ(8, n); >+class FormatCountCapture { >+ public: >+ explicit FormatCountCapture(int* p) : p_(p) {} >+ >+ private: >+ // FormatCountCaptureHelper is used to define FormatConvertImpl() for this >+ // class. >+ friend struct str_format_internal::FormatCountCaptureHelper; >+ // Unused() is here because of the false positive from -Wunused-private-field >+ // p_ is used in the templated function of the friend FormatCountCaptureHelper >+ // class. >+ int* Unused() { return p_; } >+ int* p_; >+}; >+ >+// FormatSpec >+// >+// The `FormatSpec` type defines the makeup of a format std::string within the >+// `str_format` library. You should not need to use or manipulate this type >+// directly. A `FormatSpec` is a variadic class template that is evaluated at >+// compile-time, according to the format std::string and arguments that are passed >+// to it. >+// >+// For a `FormatSpec` to be valid at compile-time, it must be provided as >+// either: >+// >+// * A `constexpr` literal or `absl::string_view`, which is how it most often >+// used. >+// * A `ParsedFormat` instantiation, which ensures the format std::string is >+// valid before use. (See below.) >+// >+// Example: >+// >+// // Provided as a std::string literal. >+// absl::StrFormat("Welcome to %s, Number %d!", "The Village", 6); >+// >+// // Provided as a constexpr absl::string_view. >+// constexpr absl::string_view formatString = "Welcome to %s, Number %d!"; >+// absl::StrFormat(formatString, "The Village", 6); >+// >+// // Provided as a pre-compiled ParsedFormat object. >+// // Note that this example is useful only for illustration purposes. >+// absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); >+// absl::StrFormat(formatString, "TheVillage", 6); >+// >+// A format std::string generally follows the POSIX syntax as used within the POSIX >+// `printf` specification. >+// >+// (See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html.) >+// >+// In specific, the `FormatSpec` supports the following type specifiers: >+// * `c` for characters >+// * `s` for strings >+// * `d` or `i` for integers >+// * `o` for unsigned integer conversions into octal >+// * `x` or `X` for unsigned integer conversions into hex >+// * `u` for unsigned integers >+// * `f` or `F` for floating point values into decimal notation >+// * `e` or `E` for floating point values into exponential notation >+// * `a` or `A` for floating point values into hex exponential notation >+// * `g` or `G` for floating point values into decimal or exponential >+// notation based on their precision >+// * `p` for pointer address values >+// * `n` for the special case of writing out the number of characters >+// written to this point. The resulting value must be captured within an >+// `absl::FormatCountCapture` type. >+// >+// NOTE: `o`, `x\X` and `u` will convert signed values to their unsigned >+// counterpart before formatting. >+// >+// Examples: >+// "%c", 'a' -> "a" >+// "%c", 32 -> " " >+// "%s", "C" -> "C" >+// "%s", std::string("C++") -> "C++" >+// "%d", -10 -> "-10" >+// "%o", 10 -> "12" >+// "%x", 16 -> "10" >+// "%f", 123456789 -> "123456789.000000" >+// "%e", .01 -> "1.00000e-2" >+// "%a", -3.0 -> "-0x1.8p+1" >+// "%g", .01 -> "1e-2" >+// "%p", *int -> "0x7ffdeb6ad2a4" >+// >+// int n = 0; >+// std::string s = absl::StrFormat( >+// "%s%d%n", "hello", 123, absl::FormatCountCapture(&n)); >+// EXPECT_EQ(8, n); >+// >+// The `FormatSpec` intrinsically supports all of these fundamental C++ types: >+// >+// * Characters: `char`, `signed char`, `unsigned char` >+// * Integers: `int`, `short`, `unsigned short`, `unsigned`, `long`, >+// `unsigned long`, `long long`, `unsigned long long` >+// * Floating-point: `float`, `double`, `long double` >+// >+// However, in the `str_format` library, a format conversion specifies a broader >+// C++ conceptual category instead of an exact type. For example, `%s` binds to >+// any std::string-like argument, so `std::string`, `absl::string_view`, and >+// `const char*` are all accepted. Likewise, `%d` accepts any integer-like >+// argument, etc. >+ >+template <typename... Args> >+using FormatSpec = >+ typename str_format_internal::FormatSpecDeductionBarrier<Args...>::type; >+ >+// ParsedFormat >+// >+// A `ParsedFormat` is a class template representing a preparsed `FormatSpec`, >+// with template arguments specifying the conversion characters used within the >+// format std::string. Such characters must be valid format type specifiers, and >+// these type specifiers are checked at compile-time. >+// >+// Instances of `ParsedFormat` can be created, copied, and reused to speed up >+// formatting loops. A `ParsedFormat` may either be constructed statically, or >+// dynamically through its `New()` factory function, which only constructs a >+// runtime object if the format is valid at that time. >+// >+// Example: >+// >+// // Verified at compile time. >+// absl::ParsedFormat<'s', 'd'> formatString("Welcome to %s, Number %d!"); >+// absl::StrFormat(formatString, "TheVillage", 6); >+// >+// // Verified at runtime. >+// auto format_runtime = absl::ParsedFormat<'d'>::New(format_string); >+// if (format_runtime) { >+// value = absl::StrFormat(*format_runtime, i); >+// } else { >+// ... error case ... >+// } >+template <char... Conv> >+using ParsedFormat = str_format_internal::ExtendedParsedFormat< >+ str_format_internal::ConversionCharToConv(Conv)...>; >+ >+// StrFormat() >+// >+// Returns a `string` given a `printf()`-style format std::string and zero or more >+// additional arguments. Use it as you would `sprintf()`. `StrFormat()` is the >+// primary formatting function within the `str_format` library, and should be >+// used in most cases where you need type-safe conversion of types into >+// formatted strings. >+// >+// The format std::string generally consists of ordinary character data along with >+// one or more format conversion specifiers (denoted by the `%` character). >+// Ordinary character data is returned unchanged into the result std::string, while >+// each conversion specification performs a type substitution from >+// `StrFormat()`'s other arguments. See the comments for `FormatSpec` for full >+// information on the makeup of this format std::string. >+// >+// Example: >+// >+// std::string s = absl::StrFormat( >+// "Welcome to %s, Number %d!", "The Village", 6); >+// EXPECT_EQ("Welcome to The Village, Number 6!", s); >+// >+// Returns an empty std::string in case of error. >+template <typename... Args> >+ABSL_MUST_USE_RESULT std::string StrFormat(const FormatSpec<Args...>& format, >+ const Args&... args) { >+ return str_format_internal::FormatPack( >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// StrAppendFormat() >+// >+// Appends to a `dst` std::string given a format std::string, and zero or more additional >+// arguments, returning `*dst` as a convenience for chaining purposes. Appends >+// nothing in case of error (but possibly alters its capacity). >+// >+// Example: >+// >+// std::string orig("For example PI is approximately "); >+// std::cout << StrAppendFormat(&orig, "%12.6f", 3.14); >+template <typename... Args> >+std::string& StrAppendFormat(std::string* dst, const FormatSpec<Args...>& format, >+ const Args&... args) { >+ return str_format_internal::AppendPack( >+ dst, str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// StreamFormat() >+// >+// Writes to an output stream given a format std::string and zero or more arguments, >+// generally in a manner that is more efficient than streaming the result of >+// `absl:: StrFormat()`. The returned object must be streamed before the full >+// expression ends. >+// >+// Example: >+// >+// std::cout << StreamFormat("%12.6f", 3.14); >+template <typename... Args> >+ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat( >+ const FormatSpec<Args...>& format, const Args&... args) { >+ return str_format_internal::Streamable( >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// PrintF() >+// >+// Writes to stdout given a format std::string and zero or more arguments. This >+// function is functionally equivalent to `std::printf()` (and type-safe); >+// prefer `absl::PrintF()` over `std::printf()`. >+// >+// Example: >+// >+// std::string_view s = "Ulaanbaatar"; >+// absl::PrintF("The capital of Mongolia is %s", s); >+// >+// Outputs: "The capital of Mongolia is Ulaanbaatar" >+// >+template <typename... Args> >+int PrintF(const FormatSpec<Args...>& format, const Args&... args) { >+ return str_format_internal::FprintF( >+ stdout, str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// FPrintF() >+// >+// Writes to a file given a format std::string and zero or more arguments. This >+// function is functionally equivalent to `std::fprintf()` (and type-safe); >+// prefer `absl::FPrintF()` over `std::fprintf()`. >+// >+// Example: >+// >+// std::string_view s = "Ulaanbaatar"; >+// absl::FPrintF("The capital of Mongolia is %s", s); >+// >+// Outputs: "The capital of Mongolia is Ulaanbaatar" >+// >+template <typename... Args> >+int FPrintF(std::FILE* output, const FormatSpec<Args...>& format, >+ const Args&... args) { >+ return str_format_internal::FprintF( >+ output, str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// SNPrintF() >+// >+// Writes to a sized buffer given a format std::string and zero or more arguments. >+// This function is functionally equivalent to `std::snprintf()` (and >+// type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`. >+// >+// Example: >+// >+// std::string_view s = "Ulaanbaatar"; >+// char output[128]; >+// absl::SNPrintF(output, sizeof(output), >+// "The capital of Mongolia is %s", s); >+// >+// Post-condition: output == "The capital of Mongolia is Ulaanbaatar" >+// >+template <typename... Args> >+int SNPrintF(char* output, std::size_t size, const FormatSpec<Args...>& format, >+ const Args&... args) { >+ return str_format_internal::SnprintF( >+ output, size, str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// ----------------------------------------------------------------------------- >+// Custom Output Formatting Functions >+// ----------------------------------------------------------------------------- >+ >+// FormatRawSink >+// >+// FormatRawSink is a type erased wrapper around arbitrary sink objects >+// specifically used as an argument to `Format()`. >+// FormatRawSink does not own the passed sink object. The passed object must >+// outlive the FormatRawSink. >+class FormatRawSink { >+ public: >+ // Implicitly convert from any type that provides the hook function as >+ // described above. >+ template <typename T, >+ typename = typename std::enable_if<std::is_constructible< >+ str_format_internal::FormatRawSinkImpl, T*>::value>::type> >+ FormatRawSink(T* raw) // NOLINT >+ : sink_(raw) {} >+ >+ private: >+ friend str_format_internal::FormatRawSinkImpl; >+ str_format_internal::FormatRawSinkImpl sink_; >+}; >+ >+// Format() >+// >+// Writes a formatted std::string to an arbitrary sink object (implementing the >+// `absl::FormatRawSink` interface), using a format std::string and zero or more >+// additional arguments. >+// >+// By default, `string` and `std::ostream` are supported as destination objects. >+// >+// `absl::Format()` is a generic version of `absl::StrFormat(), for custom >+// sinks. The format std::string, like format strings for `StrFormat()`, is checked >+// at compile-time. >+// >+// On failure, this function returns `false` and the state of the sink is >+// unspecified. >+template <typename... Args> >+bool Format(FormatRawSink raw_sink, const FormatSpec<Args...>& format, >+ const Args&... args) { >+ return str_format_internal::FormatUntyped( >+ str_format_internal::FormatRawSinkImpl::Extract(raw_sink), >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {str_format_internal::FormatArgImpl(args)...}); >+} >+ >+// FormatArg >+// >+// A type-erased handle to a format argument specifically used as an argument to >+// `FormatUntyped()`. You may construct `FormatArg` by passing >+// reference-to-const of any printable type. `FormatArg` is both copyable and >+// assignable. The source data must outlive the `FormatArg` instance. See >+// example below. >+// >+using FormatArg = str_format_internal::FormatArgImpl; >+ >+// FormatUntyped() >+// >+// Writes a formatted std::string to an arbitrary sink object (implementing the >+// `absl::FormatRawSink` interface), using an `UntypedFormatSpec` and zero or >+// more additional arguments. >+// >+// This function acts as the most generic formatting function in the >+// `str_format` library. The caller provides a raw sink, an unchecked format >+// std::string, and (usually) a runtime specified list of arguments; no compile-time >+// checking of formatting is performed within this function. As a result, a >+// caller should check the return value to verify that no error occurred. >+// On failure, this function returns `false` and the state of the sink is >+// unspecified. >+// >+// The arguments are provided in an `absl::Span<const absl::FormatArg>`. >+// Each `absl::FormatArg` object binds to a single argument and keeps a >+// reference to it. The values used to create the `FormatArg` objects must >+// outlive this function call. (See `str_format_arg.h` for information on >+// the `FormatArg` class.)_ >+// >+// Example: >+// >+// std::optional<std::string> FormatDynamic(const std::string& in_format, >+// const vector<std::string>& in_args) { >+// std::string out; >+// std::vector<absl::FormatArg> args; >+// for (const auto& v : in_args) { >+// // It is important that 'v' is a reference to the objects in in_args. >+// // The values we pass to FormatArg must outlive the call to >+// // FormatUntyped. >+// args.emplace_back(v); >+// } >+// absl::UntypedFormatSpec format(in_format); >+// if (!absl::FormatUntyped(&out, format, args)) { >+// return std::nullopt; >+// } >+// return std::move(out); >+// } >+// >+ABSL_MUST_USE_RESULT inline bool FormatUntyped( >+ FormatRawSink raw_sink, const UntypedFormatSpec& format, >+ absl::Span<const FormatArg> args) { >+ return str_format_internal::FormatUntyped( >+ str_format_internal::FormatRawSinkImpl::Extract(raw_sink), >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), args); >+} >+ >+} // namespace absl >+#endif // ABSL_STRINGS_STR_FORMAT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format_test.cc >new file mode 100644 >index 00000000000..fed75fafb5c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_format_test.cc >@@ -0,0 +1,603 @@ >+ >+#include <cstdarg> >+#include <cstdint> >+#include <cstdio> >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/strings/str_format.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace { >+using str_format_internal::FormatArgImpl; >+ >+class FormatEntryPointTest : public ::testing::Test { }; >+ >+TEST_F(FormatEntryPointTest, Format) { >+ std::string sink; >+ EXPECT_TRUE(Format(&sink, "A format %d", 123)); >+ EXPECT_EQ("A format 123", sink); >+ sink.clear(); >+ >+ ParsedFormat<'d'> pc("A format %d"); >+ EXPECT_TRUE(Format(&sink, pc, 123)); >+ EXPECT_EQ("A format 123", sink); >+} >+TEST_F(FormatEntryPointTest, UntypedFormat) { >+ constexpr const char* formats[] = { >+ "", >+ "a", >+ "%80d", >+#if !defined(_MSC_VER) && !defined(__ANDROID__) >+ // MSVC and Android don't support positional syntax. >+ "complicated multipart %% %1$d format %1$0999d", >+#endif // _MSC_VER >+ }; >+ for (const char* fmt : formats) { >+ std::string actual; >+ int i = 123; >+ FormatArgImpl arg_123(i); >+ absl::Span<const FormatArgImpl> args(&arg_123, 1); >+ UntypedFormatSpec format(fmt); >+ >+ EXPECT_TRUE(FormatUntyped(&actual, format, args)); >+ char buf[4096]{}; >+ snprintf(buf, sizeof(buf), fmt, 123); >+ EXPECT_EQ( >+ str_format_internal::FormatPack( >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), args), >+ buf); >+ EXPECT_EQ(actual, buf); >+ } >+ // The internal version works with a preparsed format. >+ ParsedFormat<'d'> pc("A format %d"); >+ int i = 345; >+ FormatArg arg(i); >+ std::string out; >+ EXPECT_TRUE(str_format_internal::FormatUntyped( >+ &out, str_format_internal::UntypedFormatSpecImpl(&pc), {&arg, 1})); >+ EXPECT_EQ("A format 345", out); >+} >+ >+TEST_F(FormatEntryPointTest, StringFormat) { >+ EXPECT_EQ("123", StrFormat("%d", 123)); >+ constexpr absl::string_view view("=%d=", 4); >+ EXPECT_EQ("=123=", StrFormat(view, 123)); >+} >+ >+TEST_F(FormatEntryPointTest, AppendFormat) { >+ std::string s; >+ std::string& r = StrAppendFormat(&s, "%d", 123); >+ EXPECT_EQ(&s, &r); // should be same object >+ EXPECT_EQ("123", r); >+} >+ >+TEST_F(FormatEntryPointTest, AppendFormatFail) { >+ std::string s = "orig"; >+ >+ UntypedFormatSpec format(" more %d"); >+ FormatArgImpl arg("not an int"); >+ >+ EXPECT_EQ("orig", >+ str_format_internal::AppendPack( >+ &s, str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ {&arg, 1})); >+} >+ >+ >+TEST_F(FormatEntryPointTest, ManyArgs) { >+ EXPECT_EQ("24", StrFormat("%24$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, >+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24)); >+ EXPECT_EQ("60", StrFormat("%60$d", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, >+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, >+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, >+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, >+ 53, 54, 55, 56, 57, 58, 59, 60)); >+} >+ >+TEST_F(FormatEntryPointTest, Preparsed) { >+ ParsedFormat<'d'> pc("%d"); >+ EXPECT_EQ("123", StrFormat(pc, 123)); >+ // rvalue ok? >+ EXPECT_EQ("123", StrFormat(ParsedFormat<'d'>("%d"), 123)); >+ constexpr absl::string_view view("=%d=", 4); >+ EXPECT_EQ("=123=", StrFormat(ParsedFormat<'d'>(view), 123)); >+} >+ >+TEST_F(FormatEntryPointTest, FormatCountCapture) { >+ int n = 0; >+ EXPECT_EQ("", StrFormat("%n", FormatCountCapture(&n))); >+ EXPECT_EQ(0, n); >+ EXPECT_EQ("123", StrFormat("%d%n", 123, FormatCountCapture(&n))); >+ EXPECT_EQ(3, n); >+} >+ >+TEST_F(FormatEntryPointTest, FormatCountCaptureWrongType) { >+ // Should reject int*. >+ int n = 0; >+ UntypedFormatSpec format("%d%n"); >+ int i = 123, *ip = &n; >+ FormatArgImpl args[2] = {FormatArgImpl(i), FormatArgImpl(ip)}; >+ >+ EXPECT_EQ("", str_format_internal::FormatPack( >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), >+ absl::MakeSpan(args))); >+} >+ >+TEST_F(FormatEntryPointTest, FormatCountCaptureMultiple) { >+ int n1 = 0; >+ int n2 = 0; >+ EXPECT_EQ(" 1 2", >+ StrFormat("%5d%n%10d%n", 1, FormatCountCapture(&n1), 2, >+ FormatCountCapture(&n2))); >+ EXPECT_EQ(5, n1); >+ EXPECT_EQ(15, n2); >+} >+ >+TEST_F(FormatEntryPointTest, FormatCountCaptureExample) { >+ int n; >+ std::string s; >+ StrAppendFormat(&s, "%s: %n%s\n", "(1,1)", FormatCountCapture(&n), "(1,2)"); >+ StrAppendFormat(&s, "%*s%s\n", n, "", "(2,2)"); >+ EXPECT_EQ(7, n); >+ EXPECT_EQ( >+ "(1,1): (1,2)\n" >+ " (2,2)\n", >+ s); >+} >+ >+TEST_F(FormatEntryPointTest, Stream) { >+ const std::string formats[] = { >+ "", >+ "a", >+ "%80d", >+#if !defined(_MSC_VER) && !defined(__ANDROID__) >+ // MSVC doesn't support positional syntax. >+ "complicated multipart %% %1$d format %1$080d", >+#endif // _MSC_VER >+ }; >+ std::string buf(4096, '\0'); >+ for (const auto& fmt : formats) { >+ const auto parsed = ParsedFormat<'d'>::NewAllowIgnored(fmt); >+ std::ostringstream oss; >+ oss << StreamFormat(*parsed, 123); >+ int fmt_result = snprintf(&*buf.begin(), buf.size(), fmt.c_str(), 123); >+ ASSERT_TRUE(oss) << fmt; >+ ASSERT_TRUE(fmt_result >= 0 && static_cast<size_t>(fmt_result) < buf.size()) >+ << fmt_result; >+ EXPECT_EQ(buf.c_str(), oss.str()); >+ } >+} >+ >+TEST_F(FormatEntryPointTest, StreamOk) { >+ std::ostringstream oss; >+ oss << StreamFormat("hello %d", 123); >+ EXPECT_EQ("hello 123", oss.str()); >+ EXPECT_TRUE(oss.good()); >+} >+ >+TEST_F(FormatEntryPointTest, StreamFail) { >+ std::ostringstream oss; >+ UntypedFormatSpec format("hello %d"); >+ FormatArgImpl arg("non-numeric"); >+ oss << str_format_internal::Streamable( >+ str_format_internal::UntypedFormatSpecImpl::Extract(format), {&arg, 1}); >+ EXPECT_EQ("hello ", oss.str()); // partial write >+ EXPECT_TRUE(oss.fail()); >+} >+ >+std::string WithSnprintf(const char* fmt, ...) { >+ std::string buf; >+ buf.resize(128); >+ va_list va; >+ va_start(va, fmt); >+ int r = vsnprintf(&*buf.begin(), buf.size(), fmt, va); >+ va_end(va); >+ EXPECT_GE(r, 0); >+ EXPECT_LT(r, buf.size()); >+ buf.resize(r); >+ return buf; >+} >+ >+TEST_F(FormatEntryPointTest, FloatPrecisionArg) { >+ // Test that positional parameters for width and precision >+ // are indexed to precede the value. >+ // Also sanity check the same formats against snprintf. >+ EXPECT_EQ("0.1", StrFormat("%.1f", 0.1)); >+ EXPECT_EQ("0.1", WithSnprintf("%.1f", 0.1)); >+ EXPECT_EQ(" 0.1", StrFormat("%*.1f", 5, 0.1)); >+ EXPECT_EQ(" 0.1", WithSnprintf("%*.1f", 5, 0.1)); >+ EXPECT_EQ("0.1", StrFormat("%.*f", 1, 0.1)); >+ EXPECT_EQ("0.1", WithSnprintf("%.*f", 1, 0.1)); >+ EXPECT_EQ(" 0.1", StrFormat("%*.*f", 5, 1, 0.1)); >+ EXPECT_EQ(" 0.1", WithSnprintf("%*.*f", 5, 1, 0.1)); >+} >+namespace streamed_test { >+struct X {}; >+std::ostream& operator<<(std::ostream& os, const X&) { >+ return os << "X"; >+} >+} // streamed_test >+ >+TEST_F(FormatEntryPointTest, FormatStreamed) { >+ EXPECT_EQ("123", StrFormat("%s", FormatStreamed(123))); >+ EXPECT_EQ(" 123", StrFormat("%5s", FormatStreamed(123))); >+ EXPECT_EQ("123 ", StrFormat("%-5s", FormatStreamed(123))); >+ EXPECT_EQ("X", StrFormat("%s", FormatStreamed(streamed_test::X()))); >+ EXPECT_EQ("123", StrFormat("%s", FormatStreamed(StreamFormat("%d", 123)))); >+} >+ >+// Helper class that creates a temporary file and exposes a FILE* to it. >+// It will close the file on destruction. >+class TempFile { >+ public: >+ TempFile() : file_(std::tmpfile()) {} >+ ~TempFile() { std::fclose(file_); } >+ >+ std::FILE* file() const { return file_; } >+ >+ // Read the file into a std::string. >+ std::string ReadFile() { >+ std::fseek(file_, 0, SEEK_END); >+ int size = std::ftell(file_); >+ std::rewind(file_); >+ std::string str(2 * size, ' '); >+ int read_bytes = std::fread(&str[0], 1, str.size(), file_); >+ EXPECT_EQ(read_bytes, size); >+ str.resize(read_bytes); >+ EXPECT_TRUE(std::feof(file_)); >+ return str; >+ } >+ >+ private: >+ std::FILE* file_; >+}; >+ >+TEST_F(FormatEntryPointTest, FPrintF) { >+ TempFile tmp; >+ int result = >+ FPrintF(tmp.file(), "STRING: %s NUMBER: %010d", std::string("ABC"), -19); >+ EXPECT_EQ(result, 30); >+ EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019"); >+} >+ >+TEST_F(FormatEntryPointTest, FPrintFError) { >+ errno = 0; >+ int result = FPrintF(stdin, "ABC"); >+ EXPECT_LT(result, 0); >+ EXPECT_EQ(errno, EBADF); >+} >+ >+#if __GNUC__ >+TEST_F(FormatEntryPointTest, FprintfTooLarge) { >+ std::FILE* f = std::fopen("/dev/null", "w"); >+ int width = 2000000000; >+ errno = 0; >+ int result = FPrintF(f, "%*d %*d", width, 0, width, 0); >+ EXPECT_LT(result, 0); >+ EXPECT_EQ(errno, EFBIG); >+ std::fclose(f); >+} >+ >+TEST_F(FormatEntryPointTest, PrintF) { >+ int stdout_tmp = dup(STDOUT_FILENO); >+ >+ TempFile tmp; >+ std::fflush(stdout); >+ dup2(fileno(tmp.file()), STDOUT_FILENO); >+ >+ int result = PrintF("STRING: %s NUMBER: %010d", std::string("ABC"), -19); >+ >+ std::fflush(stdout); >+ dup2(stdout_tmp, STDOUT_FILENO); >+ close(stdout_tmp); >+ >+ EXPECT_EQ(result, 30); >+ EXPECT_EQ(tmp.ReadFile(), "STRING: ABC NUMBER: -000000019"); >+} >+#endif // __GNUC__ >+ >+TEST_F(FormatEntryPointTest, SNPrintF) { >+ char buffer[16]; >+ int result = >+ SNPrintF(buffer, sizeof(buffer), "STRING: %s", std::string("ABC")); >+ EXPECT_EQ(result, 11); >+ EXPECT_EQ(std::string(buffer), "STRING: ABC"); >+ >+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456); >+ EXPECT_EQ(result, 14); >+ EXPECT_EQ(std::string(buffer), "NUMBER: 123456"); >+ >+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 1234567); >+ EXPECT_EQ(result, 15); >+ EXPECT_EQ(std::string(buffer), "NUMBER: 1234567"); >+ >+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 12345678); >+ EXPECT_EQ(result, 16); >+ EXPECT_EQ(std::string(buffer), "NUMBER: 1234567"); >+ >+ result = SNPrintF(buffer, sizeof(buffer), "NUMBER: %d", 123456789); >+ EXPECT_EQ(result, 17); >+ EXPECT_EQ(std::string(buffer), "NUMBER: 1234567"); >+ >+ result = SNPrintF(nullptr, 0, "Just checking the %s of the output.", "size"); >+ EXPECT_EQ(result, 37); >+} >+ >+TEST(StrFormat, BehavesAsDocumented) { >+ std::string s = absl::StrFormat("%s, %d!", "Hello", 123); >+ EXPECT_EQ("Hello, 123!", s); >+ // The format of a replacement is >+ // '%'[position][flags][width['.'precision]][length_modifier][format] >+ EXPECT_EQ(absl::StrFormat("%1$+3.2Lf", 1.1), "+1.10"); >+ // Text conversion: >+ // "c" - Character. Eg: 'a' -> "A", 20 -> " " >+ EXPECT_EQ(StrFormat("%c", 'a'), "a"); >+ EXPECT_EQ(StrFormat("%c", 0x20), " "); >+ // Formats char and integral types: int, long, uint64_t, etc. >+ EXPECT_EQ(StrFormat("%c", int{'a'}), "a"); >+ EXPECT_EQ(StrFormat("%c", long{'a'}), "a"); // NOLINT >+ EXPECT_EQ(StrFormat("%c", uint64_t{'a'}), "a"); >+ // "s" - std::string Eg: "C" -> "C", std::string("C++") -> "C++" >+ // Formats std::string, char*, string_view, and Cord. >+ EXPECT_EQ(StrFormat("%s", "C"), "C"); >+ EXPECT_EQ(StrFormat("%s", std::string("C++")), "C++"); >+ EXPECT_EQ(StrFormat("%s", string_view("view")), "view"); >+ // Integral Conversion >+ // These format integral types: char, int, long, uint64_t, etc. >+ EXPECT_EQ(StrFormat("%d", char{10}), "10"); >+ EXPECT_EQ(StrFormat("%d", int{10}), "10"); >+ EXPECT_EQ(StrFormat("%d", long{10}), "10"); // NOLINT >+ EXPECT_EQ(StrFormat("%d", uint64_t{10}), "10"); >+ // d,i - signed decimal Eg: -10 -> "-10" >+ EXPECT_EQ(StrFormat("%d", -10), "-10"); >+ EXPECT_EQ(StrFormat("%i", -10), "-10"); >+ // o - octal Eg: 10 -> "12" >+ EXPECT_EQ(StrFormat("%o", 10), "12"); >+ // u - unsigned decimal Eg: 10 -> "10" >+ EXPECT_EQ(StrFormat("%u", 10), "10"); >+ // x/X - lower,upper case hex Eg: 10 -> "a"/"A" >+ EXPECT_EQ(StrFormat("%x", 10), "a"); >+ EXPECT_EQ(StrFormat("%X", 10), "A"); >+ // Floating-point, with upper/lower-case output. >+ // These format floating points types: float, double, long double, etc. >+ EXPECT_EQ(StrFormat("%.1f", float{1}), "1.0"); >+ EXPECT_EQ(StrFormat("%.1f", double{1}), "1.0"); >+ const long double long_double = 1.0; >+ EXPECT_EQ(StrFormat("%.1f", long_double), "1.0"); >+ // These also format integral types: char, int, long, uint64_t, etc.: >+ EXPECT_EQ(StrFormat("%.1f", char{1}), "1.0"); >+ EXPECT_EQ(StrFormat("%.1f", int{1}), "1.0"); >+ EXPECT_EQ(StrFormat("%.1f", long{1}), "1.0"); // NOLINT >+ EXPECT_EQ(StrFormat("%.1f", uint64_t{1}), "1.0"); >+ // f/F - decimal. Eg: 123456789 -> "123456789.000000" >+ EXPECT_EQ(StrFormat("%f", 123456789), "123456789.000000"); >+ EXPECT_EQ(StrFormat("%F", 123456789), "123456789.000000"); >+ // e/E - exponentiated Eg: .01 -> "1.00000e-2"/"1.00000E-2" >+ EXPECT_EQ(StrFormat("%e", .01), "1.000000e-02"); >+ EXPECT_EQ(StrFormat("%E", .01), "1.000000E-02"); >+ // g/G - exponentiate to fit Eg: .01 -> "0.01", 1e10 ->"1e+10"/"1E+10" >+ EXPECT_EQ(StrFormat("%g", .01), "0.01"); >+ EXPECT_EQ(StrFormat("%g", 1e10), "1e+10"); >+ EXPECT_EQ(StrFormat("%G", 1e10), "1E+10"); >+ // a/A - lower,upper case hex Eg: -3.0 -> "-0x1.8p+1"/"-0X1.8P+1" >+ >+// On Android platform <=21, there is a regression in hexfloat formatting. >+#if !defined(__ANDROID_API__) || __ANDROID_API__ > 21 >+ EXPECT_EQ(StrFormat("%.1a", -3.0), "-0x1.8p+1"); // .1 to fix MSVC output >+ EXPECT_EQ(StrFormat("%.1A", -3.0), "-0X1.8P+1"); // .1 to fix MSVC output >+#endif >+ >+ // Other conversion >+ int64_t value = 0x7ffdeb6; >+ auto ptr_value = static_cast<uintptr_t>(value); >+ const int& something = *reinterpret_cast<const int*>(ptr_value); >+ EXPECT_EQ(StrFormat("%p", &something), StrFormat("0x%x", ptr_value)); >+ >+ // Output widths are supported, with optional flags. >+ EXPECT_EQ(StrFormat("%3d", 1), " 1"); >+ EXPECT_EQ(StrFormat("%3d", 123456), "123456"); >+ EXPECT_EQ(StrFormat("%06.2f", 1.234), "001.23"); >+ EXPECT_EQ(StrFormat("%+d", 1), "+1"); >+ EXPECT_EQ(StrFormat("% d", 1), " 1"); >+ EXPECT_EQ(StrFormat("%-4d", -1), "-1 "); >+ EXPECT_EQ(StrFormat("%#o", 10), "012"); >+ EXPECT_EQ(StrFormat("%#x", 15), "0xf"); >+ EXPECT_EQ(StrFormat("%04d", 8), "0008"); >+ // Posix positional substitution. >+ EXPECT_EQ(absl::StrFormat("%2$s, %3$s, %1$s!", "vici", "veni", "vidi"), >+ "veni, vidi, vici!"); >+ // Length modifiers are ignored. >+ EXPECT_EQ(StrFormat("%hhd", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%hd", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%ld", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%lld", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%Ld", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%jd", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%zd", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%td", int{1}), "1"); >+ EXPECT_EQ(StrFormat("%qd", int{1}), "1"); >+} >+ >+using str_format_internal::ExtendedParsedFormat; >+using str_format_internal::ParsedFormatBase; >+ >+struct SummarizeConsumer { >+ std::string* out; >+ explicit SummarizeConsumer(std::string* out) : out(out) {} >+ >+ bool Append(string_view s) { >+ *out += "[" + std::string(s) + "]"; >+ return true; >+ } >+ >+ bool ConvertOne(const str_format_internal::UnboundConversion& conv, >+ string_view s) { >+ *out += "{"; >+ *out += std::string(s); >+ *out += ":"; >+ *out += std::to_string(conv.arg_position) + "$"; >+ if (conv.width.is_from_arg()) { >+ *out += std::to_string(conv.width.get_from_arg()) + "$*"; >+ } >+ if (conv.precision.is_from_arg()) { >+ *out += "." + std::to_string(conv.precision.get_from_arg()) + "$*"; >+ } >+ *out += conv.conv.Char(); >+ *out += "}"; >+ return true; >+ } >+}; >+ >+std::string SummarizeParsedFormat(const ParsedFormatBase& pc) { >+ std::string out; >+ if (!pc.ProcessFormat(SummarizeConsumer(&out))) out += "!"; >+ return out; >+} >+ >+class ParsedFormatTest : public testing::Test {}; >+ >+TEST_F(ParsedFormatTest, SimpleChecked) { >+ EXPECT_EQ("[ABC]{d:1$d}[DEF]", >+ SummarizeParsedFormat(ParsedFormat<'d'>("ABC%dDEF"))); >+ EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", >+ SummarizeParsedFormat(ParsedFormat<'s', 'd', 'f'>("%sFFF%dZZZ%f"))); >+ EXPECT_EQ("{s:1$s}[ ]{.*d:3$.2$*d}", >+ SummarizeParsedFormat(ParsedFormat<'s', '*', 'd'>("%s %.*d"))); >+} >+ >+TEST_F(ParsedFormatTest, SimpleUncheckedCorrect) { >+ auto f = ParsedFormat<'d'>::New("ABC%dDEF"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f)); >+ >+ std::string format = "%sFFF%dZZZ%f"; >+ auto f2 = ParsedFormat<'s', 'd', 'f'>::New(format); >+ >+ ASSERT_TRUE(f2); >+ EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2)); >+ >+ f2 = ParsedFormat<'s', 'd', 'f'>::New("%s %d %f"); >+ >+ ASSERT_TRUE(f2); >+ EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2)); >+ >+ auto star = ParsedFormat<'*', 'd'>::New("%*d"); >+ ASSERT_TRUE(star); >+ EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star)); >+ >+ auto dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d"); >+ ASSERT_TRUE(dollar); >+ EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar)); >+ // with reuse >+ dollar = ParsedFormat<'d', 's'>::New("%2$s %1$d %1$d"); >+ ASSERT_TRUE(dollar); >+ EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}", >+ SummarizeParsedFormat(*dollar)); >+} >+ >+TEST_F(ParsedFormatTest, SimpleUncheckedIgnoredArgs) { >+ EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC"))); >+ EXPECT_FALSE((ParsedFormat<'d', 's'>::New("%dABC"))); >+ EXPECT_FALSE((ParsedFormat<'d', 's'>::New("ABC%2$s"))); >+ auto f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f)); >+ f = ParsedFormat<'d', 's'>::NewAllowIgnored("%dABC"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f)); >+ f = ParsedFormat<'d', 's'>::NewAllowIgnored("ABC%2$s"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f)); >+} >+ >+TEST_F(ParsedFormatTest, SimpleUncheckedUnsupported) { >+ EXPECT_FALSE(ParsedFormat<'d'>::New("%1$d %1$x")); >+ EXPECT_FALSE(ParsedFormat<'x'>::New("%1$d %1$x")); >+} >+ >+TEST_F(ParsedFormatTest, SimpleUncheckedIncorrect) { >+ EXPECT_FALSE(ParsedFormat<'d'>::New("")); >+ >+ EXPECT_FALSE(ParsedFormat<'d'>::New("ABC%dDEF%d")); >+ >+ std::string format = "%sFFF%dZZZ%f"; >+ EXPECT_FALSE((ParsedFormat<'s', 'd', 'g'>::New(format))); >+} >+ >+using str_format_internal::Conv; >+ >+TEST_F(ParsedFormatTest, UncheckedCorrect) { >+ auto f = ExtendedParsedFormat<Conv::d>::New("ABC%dDEF"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]{d:1$d}[DEF]", SummarizeParsedFormat(*f)); >+ >+ std::string format = "%sFFF%dZZZ%f"; >+ auto f2 = >+ ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New(format); >+ >+ ASSERT_TRUE(f2); >+ EXPECT_EQ("{s:1$s}[FFF]{d:2$d}[ZZZ]{f:3$f}", SummarizeParsedFormat(*f2)); >+ >+ f2 = ExtendedParsedFormat<Conv::string, Conv::d, Conv::floating>::New( >+ "%s %d %f"); >+ >+ ASSERT_TRUE(f2); >+ EXPECT_EQ("{s:1$s}[ ]{d:2$d}[ ]{f:3$f}", SummarizeParsedFormat(*f2)); >+ >+ auto star = ExtendedParsedFormat<Conv::star, Conv::d>::New("%*d"); >+ ASSERT_TRUE(star); >+ EXPECT_EQ("{*d:2$1$*d}", SummarizeParsedFormat(*star)); >+ >+ auto dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d"); >+ ASSERT_TRUE(dollar); >+ EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}", SummarizeParsedFormat(*dollar)); >+ // with reuse >+ dollar = ExtendedParsedFormat<Conv::d, Conv::s>::New("%2$s %1$d %1$d"); >+ ASSERT_TRUE(dollar); >+ EXPECT_EQ("{2$s:2$s}[ ]{1$d:1$d}[ ]{1$d:1$d}", >+ SummarizeParsedFormat(*dollar)); >+} >+ >+TEST_F(ParsedFormatTest, UncheckedIgnoredArgs) { >+ EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC"))); >+ EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("%dABC"))); >+ EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::s>::New("ABC%2$s"))); >+ auto f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]", SummarizeParsedFormat(*f)); >+ f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("%dABC"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("{d:1$d}[ABC]", SummarizeParsedFormat(*f)); >+ f = ExtendedParsedFormat<Conv::d, Conv::s>::NewAllowIgnored("ABC%2$s"); >+ ASSERT_TRUE(f); >+ EXPECT_EQ("[ABC]{2$s:2$s}", SummarizeParsedFormat(*f)); >+} >+ >+TEST_F(ParsedFormatTest, UncheckedMultipleTypes) { >+ auto dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d %1$x"); >+ EXPECT_TRUE(dx); >+ EXPECT_EQ("{1$d:1$d}[ ]{1$x:1$x}", SummarizeParsedFormat(*dx)); >+ >+ dx = ExtendedParsedFormat<Conv::d | Conv::x>::New("%1$d"); >+ EXPECT_TRUE(dx); >+ EXPECT_EQ("{1$d:1$d}", SummarizeParsedFormat(*dx)); >+} >+ >+TEST_F(ParsedFormatTest, UncheckedIncorrect) { >+ EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("")); >+ >+ EXPECT_FALSE(ExtendedParsedFormat<Conv::d>::New("ABC%dDEF%d")); >+ >+ std::string format = "%sFFF%dZZZ%f"; >+ EXPECT_FALSE((ExtendedParsedFormat<Conv::s, Conv::d, Conv::g>::New(format))); >+} >+ >+TEST_F(ParsedFormatTest, RegressionMixPositional) { >+ EXPECT_FALSE((ExtendedParsedFormat<Conv::d, Conv::o>::New("%1$d %o"))); >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join.h >new file mode 100644 >index 00000000000..bd4d0e1d932 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join.h >@@ -0,0 +1,288 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: str_join.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains functions for joining a range of elements and >+// returning the result as a std::string. StrJoin operations are specified by passing >+// a range, a separator std::string to use between the elements joined, and an >+// optional Formatter responsible for converting each argument in the range to a >+// std::string. If omitted, a default `AlphaNumFormatter()` is called on the elements >+// to be joined, using the same formatting that `absl::StrCat()` uses. This >+// package defines a number of default formatters, and you can define your own >+// implementations. >+// >+// Ranges are specified by passing a container with `std::begin()` and >+// `std::end()` iterators, container-specific `begin()` and `end()` iterators, a >+// brace-initialized `std::initializer_list`, or a `std::tuple` of heterogeneous >+// objects. The separator std::string is specified as an `absl::string_view`. >+// >+// Because the default formatter uses the `absl::AlphaNum` class, >+// `absl::StrJoin()`, like `absl::StrCat()`, will work out-of-the-box on >+// collections of strings, ints, floats, doubles, etc. >+// >+// Example: >+// >+// std::vector<std::string> v = {"foo", "bar", "baz"}; >+// std::string s = absl::StrJoin(v, "-"); >+// EXPECT_EQ("foo-bar-baz", s); >+// >+// See comments on the `absl::StrJoin()` function for more examples. >+ >+#ifndef ABSL_STRINGS_STR_JOIN_H_ >+#define ABSL_STRINGS_STR_JOIN_H_ >+ >+#include <cstdio> >+#include <cstring> >+#include <initializer_list> >+#include <iterator> >+#include <string> >+#include <tuple> >+#include <utility> >+ >+#include "absl/base/macros.h" >+#include "absl/strings/internal/str_join_internal.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// Concept: Formatter >+// ----------------------------------------------------------------------------- >+// >+// A Formatter is a function object that is responsible for formatting its >+// argument as a std::string and appending it to a given output std::string. Formatters >+// may be implemented as function objects, lambdas, or normal functions. You may >+// provide your own Formatter to enable `absl::StrJoin()` to work with arbitrary >+// types. >+// >+// The following is an example of a custom Formatter that simply uses >+// `std::to_string()` to format an integer as a std::string. >+// >+// struct MyFormatter { >+// void operator()(std::string* out, int i) const { >+// out->append(std::to_string(i)); >+// } >+// }; >+// >+// You would use the above formatter by passing an instance of it as the final >+// argument to `absl::StrJoin()`: >+// >+// std::vector<int> v = {1, 2, 3, 4}; >+// std::string s = absl::StrJoin(v, "-", MyFormatter()); >+// EXPECT_EQ("1-2-3-4", s); >+// >+// The following standard formatters are provided within this file: >+// >+// - `AlphaNumFormatter()` (the default) >+// - `StreamFormatter()` >+// - `PairFormatter()` >+// - `DereferenceFormatter()` >+ >+// AlphaNumFormatter() >+// >+// Default formatter used if none is specified. Uses `absl::AlphaNum` to convert >+// numeric arguments to strings. >+inline strings_internal::AlphaNumFormatterImpl AlphaNumFormatter() { >+ return strings_internal::AlphaNumFormatterImpl(); >+} >+ >+// StreamFormatter() >+// >+// Formats its argument using the << operator. >+inline strings_internal::StreamFormatterImpl StreamFormatter() { >+ return strings_internal::StreamFormatterImpl(); >+} >+ >+// Function Template: PairFormatter(Formatter, absl::string_view, Formatter) >+// >+// Formats a `std::pair` by putting a given separator between the pair's >+// `.first` and `.second` members. This formatter allows you to specify >+// custom Formatters for both the first and second member of each pair. >+template <typename FirstFormatter, typename SecondFormatter> >+inline strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter> >+PairFormatter(FirstFormatter f1, absl::string_view sep, SecondFormatter f2) { >+ return strings_internal::PairFormatterImpl<FirstFormatter, SecondFormatter>( >+ std::move(f1), sep, std::move(f2)); >+} >+ >+// Function overload of PairFormatter() for using a default >+// `AlphaNumFormatter()` for each Formatter in the pair. >+inline strings_internal::PairFormatterImpl< >+ strings_internal::AlphaNumFormatterImpl, >+ strings_internal::AlphaNumFormatterImpl> >+PairFormatter(absl::string_view sep) { >+ return PairFormatter(AlphaNumFormatter(), sep, AlphaNumFormatter()); >+} >+ >+// Function Template: DereferenceFormatter(Formatter) >+// >+// Formats its argument by dereferencing it and then applying the given >+// formatter. This formatter is useful for formatting a container of >+// pointer-to-T. This pattern often shows up when joining repeated fields in >+// protocol buffers. >+template <typename Formatter> >+strings_internal::DereferenceFormatterImpl<Formatter> DereferenceFormatter( >+ Formatter&& f) { >+ return strings_internal::DereferenceFormatterImpl<Formatter>( >+ std::forward<Formatter>(f)); >+} >+ >+// Function overload of `DererefenceFormatter()` for using a default >+// `AlphaNumFormatter()`. >+inline strings_internal::DereferenceFormatterImpl< >+ strings_internal::AlphaNumFormatterImpl> >+DereferenceFormatter() { >+ return strings_internal::DereferenceFormatterImpl< >+ strings_internal::AlphaNumFormatterImpl>(AlphaNumFormatter()); >+} >+ >+// ----------------------------------------------------------------------------- >+// StrJoin() >+// ----------------------------------------------------------------------------- >+// >+// Joins a range of elements and returns the result as a std::string. >+// `absl::StrJoin()` takes a range, a separator std::string to use between the >+// elements joined, and an optional Formatter responsible for converting each >+// argument in the range to a std::string. >+// >+// If omitted, the default `AlphaNumFormatter()` is called on the elements to be >+// joined. >+// >+// Example 1: >+// // Joins a collection of strings. This pattern also works with a collection >+// // of `absl::string_view` or even `const char*`. >+// std::vector<std::string> v = {"foo", "bar", "baz"}; >+// std::string s = absl::StrJoin(v, "-"); >+// EXPECT_EQ("foo-bar-baz", s); >+// >+// Example 2: >+// // Joins the values in the given `std::initializer_list<>` specified using >+// // brace initialization. This pattern also works with an initializer_list >+// // of ints or `absl::string_view` -- any `AlphaNum`-compatible type. >+// std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-"); >+// EXPECT_EQ("foo-bar-baz", s); >+// >+// Example 3: >+// // Joins a collection of ints. This pattern also works with floats, >+// // doubles, int64s -- any `StrCat()`-compatible type. >+// std::vector<int> v = {1, 2, 3, -4}; >+// std::string s = absl::StrJoin(v, "-"); >+// EXPECT_EQ("1-2-3--4", s); >+// >+// Example 4: >+// // Joins a collection of pointer-to-int. By default, pointers are >+// // dereferenced and the pointee is formatted using the default format for >+// // that type; such dereferencing occurs for all levels of indirection, so >+// // this pattern works just as well for `std::vector<int**>` as for >+// // `std::vector<int*>`. >+// int x = 1, y = 2, z = 3; >+// std::vector<int*> v = {&x, &y, &z}; >+// std::string s = absl::StrJoin(v, "-"); >+// EXPECT_EQ("1-2-3", s); >+// >+// Example 5: >+// // Dereferencing of `std::unique_ptr<>` is also supported: >+// std::vector<std::unique_ptr<int>> v >+// v.emplace_back(new int(1)); >+// v.emplace_back(new int(2)); >+// v.emplace_back(new int(3)); >+// std::string s = absl::StrJoin(v, "-"); >+// EXPECT_EQ("1-2-3", s); >+// >+// Example 6: >+// // Joins a `std::map`, with each key-value pair separated by an equals >+// // sign. This pattern would also work with, say, a >+// // `std::vector<std::pair<>>`. >+// std::map<std::string, int> m = { >+// std::make_pair("a", 1), >+// std::make_pair("b", 2), >+// std::make_pair("c", 3)}; >+// std::string s = absl::StrJoin(m, ",", absl::PairFormatter("=")); >+// EXPECT_EQ("a=1,b=2,c=3", s); >+// >+// Example 7: >+// // These examples show how `absl::StrJoin()` handles a few common edge >+// // cases: >+// std::vector<std::string> v_empty; >+// EXPECT_EQ("", absl::StrJoin(v_empty, "-")); >+// >+// std::vector<std::string> v_one_item = {"foo"}; >+// EXPECT_EQ("foo", absl::StrJoin(v_one_item, "-")); >+// >+// std::vector<std::string> v_empty_string = {""}; >+// EXPECT_EQ("", absl::StrJoin(v_empty_string, "-")); >+// >+// std::vector<std::string> v_one_item_empty_string = {"a", ""}; >+// EXPECT_EQ("a-", absl::StrJoin(v_one_item_empty_string, "-")); >+// >+// std::vector<std::string> v_two_empty_string = {"", ""}; >+// EXPECT_EQ("-", absl::StrJoin(v_two_empty_string, "-")); >+// >+// Example 8: >+// // Joins a `std::tuple<T...>` of heterogeneous types, converting each to >+// // a std::string using the `absl::AlphaNum` class. >+// std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); >+// EXPECT_EQ("123-abc-0.456", s); >+ >+template <typename Iterator, typename Formatter> >+std::string StrJoin(Iterator start, Iterator end, absl::string_view sep, >+ Formatter&& fmt) { >+ return strings_internal::JoinAlgorithm(start, end, sep, fmt); >+} >+ >+template <typename Range, typename Formatter> >+std::string StrJoin(const Range& range, absl::string_view separator, >+ Formatter&& fmt) { >+ return strings_internal::JoinRange(range, separator, fmt); >+} >+ >+template <typename T, typename Formatter> >+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator, >+ Formatter&& fmt) { >+ return strings_internal::JoinRange(il, separator, fmt); >+} >+ >+template <typename... T, typename Formatter> >+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator, >+ Formatter&& fmt) { >+ return strings_internal::JoinAlgorithm(value, separator, fmt); >+} >+ >+template <typename Iterator> >+std::string StrJoin(Iterator start, Iterator end, absl::string_view separator) { >+ return strings_internal::JoinRange(start, end, separator); >+} >+ >+template <typename Range> >+std::string StrJoin(const Range& range, absl::string_view separator) { >+ return strings_internal::JoinRange(range, separator); >+} >+ >+template <typename T> >+std::string StrJoin(std::initializer_list<T> il, absl::string_view separator) { >+ return strings_internal::JoinRange(il, separator); >+} >+ >+template <typename... T> >+std::string StrJoin(const std::tuple<T...>& value, absl::string_view separator) { >+ return strings_internal::JoinAlgorithm(value, separator, AlphaNumFormatter()); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STR_JOIN_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_benchmark.cc >new file mode 100644 >index 00000000000..7fb0e4973cb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_benchmark.cc >@@ -0,0 +1,96 @@ >+// >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_join.h" >+ >+#include <string> >+#include <vector> >+#include <utility> >+ >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+void BM_Join2_Strings(benchmark::State& state) { >+ const int string_len = state.range(0); >+ const int num_strings = state.range(1); >+ const std::string s(string_len, 'x'); >+ const std::vector<std::string> v(num_strings, s); >+ for (auto _ : state) { >+ std::string s = absl::StrJoin(v, "-"); >+ benchmark::DoNotOptimize(s); >+ } >+} >+BENCHMARK(BM_Join2_Strings) >+ ->ArgPair(1 << 0, 1 << 3) >+ ->ArgPair(1 << 10, 1 << 3) >+ ->ArgPair(1 << 13, 1 << 3) >+ ->ArgPair(1 << 0, 1 << 10) >+ ->ArgPair(1 << 10, 1 << 10) >+ ->ArgPair(1 << 13, 1 << 10) >+ ->ArgPair(1 << 0, 1 << 13) >+ ->ArgPair(1 << 10, 1 << 13) >+ ->ArgPair(1 << 13, 1 << 13); >+ >+void BM_Join2_Ints(benchmark::State& state) { >+ const int num_ints = state.range(0); >+ const std::vector<int> v(num_ints, 42); >+ for (auto _ : state) { >+ std::string s = absl::StrJoin(v, "-"); >+ benchmark::DoNotOptimize(s); >+ } >+} >+BENCHMARK(BM_Join2_Ints)->Range(0, 1 << 13); >+ >+void BM_Join2_KeysAndValues(benchmark::State& state) { >+ const int string_len = state.range(0); >+ const int num_pairs = state.range(1); >+ const std::string s(string_len, 'x'); >+ const std::vector<std::pair<std::string, int>> v(num_pairs, std::make_pair(s, 42)); >+ for (auto _ : state) { >+ std::string s = absl::StrJoin(v, ",", absl::PairFormatter("=")); >+ benchmark::DoNotOptimize(s); >+ } >+} >+BENCHMARK(BM_Join2_KeysAndValues) >+ ->ArgPair(1 << 0, 1 << 3) >+ ->ArgPair(1 << 10, 1 << 3) >+ ->ArgPair(1 << 13, 1 << 3) >+ ->ArgPair(1 << 0, 1 << 10) >+ ->ArgPair(1 << 10, 1 << 10) >+ ->ArgPair(1 << 13, 1 << 10) >+ ->ArgPair(1 << 0, 1 << 13) >+ ->ArgPair(1 << 10, 1 << 13) >+ ->ArgPair(1 << 13, 1 << 13); >+ >+void BM_JoinStreamable(benchmark::State& state) { >+ const int string_len = state.range(0); >+ const int num_strings = state.range(1); >+ const std::vector<std::string> v(num_strings, std::string(string_len, 'x')); >+ for (auto _ : state) { >+ std::string s = absl::StrJoin(v, "", absl::StreamFormatter()); >+ benchmark::DoNotOptimize(s); >+ } >+} >+BENCHMARK(BM_JoinStreamable) >+ ->ArgPair(0, 0) >+ ->ArgPair(16, 1) >+ ->ArgPair(256, 1) >+ ->ArgPair(16, 16) >+ ->ArgPair(256, 16) >+ ->ArgPair(16, 256) >+ ->ArgPair(256, 256); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_test.cc >new file mode 100644 >index 00000000000..c941f9c80d4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_join_test.cc >@@ -0,0 +1,472 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit tests for all join.h functions >+ >+#include "absl/strings/str_join.h" >+ >+#include <cstddef> >+#include <cstdint> >+#include <cstdio> >+#include <functional> >+#include <initializer_list> >+#include <map> >+#include <memory> >+#include <ostream> >+#include <tuple> >+#include <type_traits> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/macros.h" >+#include "absl/memory/memory.h" >+#include "absl/strings/str_cat.h" >+#include "absl/strings/str_split.h" >+ >+namespace { >+ >+TEST(StrJoin, APIExamples) { >+ { >+ // Collection of strings >+ std::vector<std::string> v = {"foo", "bar", "baz"}; >+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of absl::string_view >+ std::vector<absl::string_view> v = {"foo", "bar", "baz"}; >+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of const char* >+ std::vector<const char*> v = {"foo", "bar", "baz"}; >+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of non-const char* >+ std::string a = "foo", b = "bar", c = "baz"; >+ std::vector<char*> v = {&a[0], &b[0], &c[0]}; >+ EXPECT_EQ("foo-bar-baz", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of ints >+ std::vector<int> v = {1, 2, 3, -4}; >+ EXPECT_EQ("1-2-3--4", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Literals passed as a std::initializer_list >+ std::string s = absl::StrJoin({"a", "b", "c"}, "-"); >+ EXPECT_EQ("a-b-c", s); >+ } >+ { >+ // Join a std::tuple<T...>. >+ std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-"); >+ EXPECT_EQ("123-abc-0.456", s); >+ } >+ >+ { >+ // Collection of unique_ptrs >+ std::vector<std::unique_ptr<int>> v; >+ v.emplace_back(new int(1)); >+ v.emplace_back(new int(2)); >+ v.emplace_back(new int(3)); >+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Array of ints >+ const int a[] = {1, 2, 3, -4}; >+ EXPECT_EQ("1-2-3--4", absl::StrJoin(a, a + ABSL_ARRAYSIZE(a), "-")); >+ } >+ >+ { >+ // Collection of pointers >+ int x = 1, y = 2, z = 3; >+ std::vector<int*> v = {&x, &y, &z}; >+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of pointers to pointers >+ int x = 1, y = 2, z = 3; >+ int *px = &x, *py = &y, *pz = &z; >+ std::vector<int**> v = {&px, &py, &pz}; >+ EXPECT_EQ("1-2-3", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // Collection of pointers to std::string >+ std::string a("a"), b("b"); >+ std::vector<std::string*> v = {&a, &b}; >+ EXPECT_EQ("a-b", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A std::map, which is a collection of std::pair<>s. >+ std::map<std::string, int> m = { {"a", 1}, {"b", 2}, {"c", 3} }; >+ EXPECT_EQ("a=1,b=2,c=3", absl::StrJoin(m, ",", absl::PairFormatter("="))); >+ } >+ >+ { >+ // Shows absl::StrSplit and absl::StrJoin working together. This example is >+ // equivalent to s/=/-/g. >+ const std::string s = "a=b=c=d"; >+ EXPECT_EQ("a-b-c-d", absl::StrJoin(absl::StrSplit(s, "="), "-")); >+ } >+ >+ // >+ // A few examples of edge cases >+ // >+ >+ { >+ // Empty range yields an empty std::string. >+ std::vector<std::string> v; >+ EXPECT_EQ("", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A range of 1 element gives a std::string with that element but no separator. >+ std::vector<std::string> v = {"foo"}; >+ EXPECT_EQ("foo", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A range with a single empty std::string element >+ std::vector<std::string> v = {""}; >+ EXPECT_EQ("", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A range with 2 elements, one of which is an empty std::string >+ std::vector<std::string> v = {"a", ""}; >+ EXPECT_EQ("a-", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A range with 2 empty elements. >+ std::vector<std::string> v = {"", ""}; >+ EXPECT_EQ("-", absl::StrJoin(v, "-")); >+ } >+ >+ { >+ // A std::vector of bool. >+ std::vector<bool> v = {true, false, true}; >+ EXPECT_EQ("1-0-1", absl::StrJoin(v, "-")); >+ } >+} >+ >+TEST(StrJoin, CustomFormatter) { >+ std::vector<std::string> v{"One", "Two", "Three"}; >+ { >+ std::string joined = absl::StrJoin(v, "", [](std::string* out, const std::string& in) { >+ absl::StrAppend(out, "(", in, ")"); >+ }); >+ EXPECT_EQ("(One)(Two)(Three)", joined); >+ } >+ { >+ class ImmovableFormatter { >+ public: >+ void operator()(std::string* out, const std::string& in) { >+ absl::StrAppend(out, "(", in, ")"); >+ } >+ ImmovableFormatter() {} >+ ImmovableFormatter(const ImmovableFormatter&) = delete; >+ }; >+ EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", ImmovableFormatter())); >+ } >+ { >+ class OverloadedFormatter { >+ public: >+ void operator()(std::string* out, const std::string& in) { >+ absl::StrAppend(out, "(", in, ")"); >+ } >+ void operator()(std::string* out, const std::string& in) const { >+ absl::StrAppend(out, "[", in, "]"); >+ } >+ }; >+ EXPECT_EQ("(One)(Two)(Three)", absl::StrJoin(v, "", OverloadedFormatter())); >+ const OverloadedFormatter fmt = {}; >+ EXPECT_EQ("[One][Two][Three]", absl::StrJoin(v, "", fmt)); >+ } >+} >+ >+// >+// Tests the Formatters >+// >+ >+TEST(AlphaNumFormatter, FormatterAPI) { >+ // Not an exhaustive test. See strings/strcat_test.h for the exhaustive test >+ // of what AlphaNum can convert. >+ auto f = absl::AlphaNumFormatter(); >+ std::string s; >+ f(&s, "Testing: "); >+ f(&s, static_cast<int>(1)); >+ f(&s, static_cast<int16_t>(2)); >+ f(&s, static_cast<int64_t>(3)); >+ f(&s, static_cast<float>(4)); >+ f(&s, static_cast<double>(5)); >+ f(&s, static_cast<unsigned>(6)); >+ f(&s, static_cast<size_t>(7)); >+ f(&s, absl::string_view(" OK")); >+ EXPECT_EQ("Testing: 1234567 OK", s); >+} >+ >+// Make sure people who are mistakenly using std::vector<bool> even though >+// they're not memory-constrained can use absl::AlphaNumFormatter(). >+TEST(AlphaNumFormatter, VectorOfBool) { >+ auto f = absl::AlphaNumFormatter(); >+ std::string s; >+ std::vector<bool> v = {true, false, true}; >+ f(&s, *v.cbegin()); >+ f(&s, *v.begin()); >+ f(&s, v[1]); >+ EXPECT_EQ("110", s); >+} >+ >+TEST(AlphaNumFormatter, AlphaNum) { >+ auto f = absl::AlphaNumFormatter(); >+ std::string s; >+ f(&s, absl::AlphaNum("hello")); >+ EXPECT_EQ("hello", s); >+} >+ >+struct StreamableType { >+ std::string contents; >+}; >+inline std::ostream& operator<<(std::ostream& os, const StreamableType& t) { >+ os << "Streamable:" << t.contents; >+ return os; >+} >+ >+TEST(StreamFormatter, FormatterAPI) { >+ auto f = absl::StreamFormatter(); >+ std::string s; >+ f(&s, "Testing: "); >+ f(&s, static_cast<int>(1)); >+ f(&s, static_cast<int16_t>(2)); >+ f(&s, static_cast<int64_t>(3)); >+ f(&s, static_cast<float>(4)); >+ f(&s, static_cast<double>(5)); >+ f(&s, static_cast<unsigned>(6)); >+ f(&s, static_cast<size_t>(7)); >+ f(&s, absl::string_view(" OK ")); >+ StreamableType streamable = {"object"}; >+ f(&s, streamable); >+ EXPECT_EQ("Testing: 1234567 OK Streamable:object", s); >+} >+ >+// A dummy formatter that wraps each element in parens. Used in some tests >+// below. >+struct TestingParenFormatter { >+ template <typename T> >+ void operator()(std::string* s, const T& t) { >+ absl::StrAppend(s, "(", t, ")"); >+ } >+}; >+ >+TEST(PairFormatter, FormatterAPI) { >+ { >+ // Tests default PairFormatter(sep) that uses AlphaNumFormatter for the >+ // 'first' and 'second' members. >+ const auto f = absl::PairFormatter("="); >+ std::string s; >+ f(&s, std::make_pair("a", "b")); >+ f(&s, std::make_pair(1, 2)); >+ EXPECT_EQ("a=b1=2", s); >+ } >+ >+ { >+ // Tests using a custom formatter for the 'first' and 'second' members. >+ auto f = absl::PairFormatter(TestingParenFormatter(), "=", >+ TestingParenFormatter()); >+ std::string s; >+ f(&s, std::make_pair("a", "b")); >+ f(&s, std::make_pair(1, 2)); >+ EXPECT_EQ("(a)=(b)(1)=(2)", s); >+ } >+} >+ >+TEST(DereferenceFormatter, FormatterAPI) { >+ { >+ // Tests wrapping the default AlphaNumFormatter. >+ const absl::strings_internal::DereferenceFormatterImpl< >+ absl::strings_internal::AlphaNumFormatterImpl> >+ f; >+ int x = 1, y = 2, z = 3; >+ std::string s; >+ f(&s, &x); >+ f(&s, &y); >+ f(&s, &z); >+ EXPECT_EQ("123", s); >+ } >+ >+ { >+ // Tests wrapping std::string's default formatter. >+ absl::strings_internal::DereferenceFormatterImpl< >+ absl::strings_internal::DefaultFormatter<std::string>::Type> >+ f; >+ >+ std::string x = "x"; >+ std::string y = "y"; >+ std::string z = "z"; >+ std::string s; >+ f(&s, &x); >+ f(&s, &y); >+ f(&s, &z); >+ EXPECT_EQ(s, "xyz"); >+ } >+ >+ { >+ // Tests wrapping a custom formatter. >+ auto f = absl::DereferenceFormatter(TestingParenFormatter()); >+ int x = 1, y = 2, z = 3; >+ std::string s; >+ f(&s, &x); >+ f(&s, &y); >+ f(&s, &z); >+ EXPECT_EQ("(1)(2)(3)", s); >+ } >+ >+ { >+ absl::strings_internal::DereferenceFormatterImpl< >+ absl::strings_internal::AlphaNumFormatterImpl> >+ f; >+ auto x = std::unique_ptr<int>(new int(1)); >+ auto y = std::unique_ptr<int>(new int(2)); >+ auto z = std::unique_ptr<int>(new int(3)); >+ std::string s; >+ f(&s, x); >+ f(&s, y); >+ f(&s, z); >+ EXPECT_EQ("123", s); >+ } >+} >+ >+// >+// Tests the interfaces for the 4 public Join function overloads. The semantics >+// of the algorithm is covered in the above APIExamples test. >+// >+TEST(StrJoin, PublicAPIOverloads) { >+ std::vector<std::string> v = {"a", "b", "c"}; >+ >+ // Iterators + formatter >+ EXPECT_EQ("a-b-c", >+ absl::StrJoin(v.begin(), v.end(), "-", absl::AlphaNumFormatter())); >+ // Range + formatter >+ EXPECT_EQ("a-b-c", absl::StrJoin(v, "-", absl::AlphaNumFormatter())); >+ // Iterators, no formatter >+ EXPECT_EQ("a-b-c", absl::StrJoin(v.begin(), v.end(), "-")); >+ // Range, no formatter >+ EXPECT_EQ("a-b-c", absl::StrJoin(v, "-")); >+} >+ >+TEST(StrJoin, Array) { >+ const absl::string_view a[] = {"a", "b", "c"}; >+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-")); >+} >+ >+TEST(StrJoin, InitializerList) { >+ { EXPECT_EQ("a-b-c", absl::StrJoin({"a", "b", "c"}, "-")); } >+ >+ { >+ auto a = {"a", "b", "c"}; >+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-")); >+ } >+ >+ { >+ std::initializer_list<const char*> a = {"a", "b", "c"}; >+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-")); >+ } >+ >+ { >+ std::initializer_list<std::string> a = {"a", "b", "c"}; >+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-")); >+ } >+ >+ { >+ std::initializer_list<absl::string_view> a = {"a", "b", "c"}; >+ EXPECT_EQ("a-b-c", absl::StrJoin(a, "-")); >+ } >+ >+ { >+ // Tests initializer_list with a non-default formatter >+ auto a = {"a", "b", "c"}; >+ TestingParenFormatter f; >+ EXPECT_EQ("(a)-(b)-(c)", absl::StrJoin(a, "-", f)); >+ } >+ >+ { >+ // initializer_list of ints >+ EXPECT_EQ("1-2-3", absl::StrJoin({1, 2, 3}, "-")); >+ } >+ >+ { >+ // Tests initializer_list of ints with a non-default formatter >+ auto a = {1, 2, 3}; >+ TestingParenFormatter f; >+ EXPECT_EQ("(1)-(2)-(3)", absl::StrJoin(a, "-", f)); >+ } >+} >+ >+TEST(StrJoin, Tuple) { >+ EXPECT_EQ("", absl::StrJoin(std::make_tuple(), "-")); >+ EXPECT_EQ("hello", absl::StrJoin(std::make_tuple("hello"), "-")); >+ >+ int x(10); >+ std::string y("hello"); >+ double z(3.14); >+ EXPECT_EQ("10-hello-3.14", absl::StrJoin(std::make_tuple(x, y, z), "-")); >+ >+ // Faster! Faster!! >+ EXPECT_EQ("10-hello-3.14", >+ absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-")); >+ >+ struct TestFormatter { >+ char buffer[128]; >+ void operator()(std::string* out, int v) { >+ snprintf(buffer, sizeof(buffer), "%#.8x", v); >+ out->append(buffer); >+ } >+ void operator()(std::string* out, double v) { >+ snprintf(buffer, sizeof(buffer), "%#.0f", v); >+ out->append(buffer); >+ } >+ void operator()(std::string* out, const std::string& v) { >+ snprintf(buffer, sizeof(buffer), "%.4s", v.c_str()); >+ out->append(buffer); >+ } >+ }; >+ EXPECT_EQ("0x0000000a-hell-3.", >+ absl::StrJoin(std::make_tuple(x, y, z), "-", TestFormatter())); >+ EXPECT_EQ( >+ "0x0000000a-hell-3.", >+ absl::StrJoin(std::make_tuple(x, std::cref(y), z), "-", TestFormatter())); >+ EXPECT_EQ("0x0000000a-hell-3.", >+ absl::StrJoin(std::make_tuple(&x, &y, &z), "-", >+ absl::DereferenceFormatter(TestFormatter()))); >+ EXPECT_EQ("0x0000000a-hell-3.", >+ absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), >+ absl::make_unique<std::string>(y), >+ absl::make_unique<double>(z)), >+ "-", absl::DereferenceFormatter(TestFormatter()))); >+ EXPECT_EQ("0x0000000a-hell-3.", >+ absl::StrJoin(std::make_tuple(absl::make_unique<int>(x), &y, &z), >+ "-", absl::DereferenceFormatter(TestFormatter()))); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.cc >new file mode 100644 >index 00000000000..69efa357138 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.cc >@@ -0,0 +1,79 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_replace.h" >+ >+#include "absl/strings/str_cat.h" >+ >+namespace absl { >+namespace strings_internal { >+ >+using FixedMapping = >+ std::initializer_list<std::pair<absl::string_view, absl::string_view>>; >+ >+// Applies the ViableSubstitutions in subs_ptr to the absl::string_view s, and >+// stores the result in *result_ptr. Returns the number of substitutions that >+// occurred. >+int ApplySubstitutions( >+ absl::string_view s, >+ std::vector<strings_internal::ViableSubstitution>* subs_ptr, >+ std::string* result_ptr) { >+ auto& subs = *subs_ptr; >+ int substitutions = 0; >+ size_t pos = 0; >+ while (!subs.empty()) { >+ auto& sub = subs.back(); >+ if (sub.offset >= pos) { >+ if (pos <= s.size()) { >+ StrAppend(result_ptr, s.substr(pos, sub.offset - pos), sub.replacement); >+ } >+ pos = sub.offset + sub.old.size(); >+ substitutions += 1; >+ } >+ sub.offset = s.find(sub.old, pos); >+ if (sub.offset == s.npos) { >+ subs.pop_back(); >+ } else { >+ // Insertion sort to ensure the last ViableSubstitution continues to be >+ // before all the others. >+ size_t index = subs.size(); >+ while (--index && subs[index - 1].OccursBefore(subs[index])) { >+ std::swap(subs[index], subs[index - 1]); >+ } >+ } >+ } >+ result_ptr->append(s.data() + pos, s.size() - pos); >+ return substitutions; >+} >+ >+} // namespace strings_internal >+ >+// We can implement this in terms of the generic StrReplaceAll, but >+// we must specify the template overload because C++ cannot deduce the type >+// of an initializer_list parameter to a function, and also if we don't specify >+// the type, we just call ourselves. >+// >+// Note that we implement them here, rather than in the header, so that they >+// aren't inlined. >+ >+std::string StrReplaceAll(absl::string_view s, >+ strings_internal::FixedMapping replacements) { >+ return StrReplaceAll<strings_internal::FixedMapping>(s, replacements); >+} >+ >+int StrReplaceAll(strings_internal::FixedMapping replacements, std::string* target) { >+ return StrReplaceAll<strings_internal::FixedMapping>(replacements, target); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.h >new file mode 100644 >index 00000000000..f4d9bb9545d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace.h >@@ -0,0 +1,213 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: str_replace.h >+// ----------------------------------------------------------------------------- >+// >+// This file defines `absl::StrReplaceAll()`, a general-purpose std::string >+// replacement function designed for large, arbitrary text substitutions, >+// especially on strings which you are receiving from some other system for >+// further processing (e.g. processing regular expressions, escaping HTML >+// entities, etc. `StrReplaceAll` is designed to be efficient even when only >+// one substitution is being performed, or when substitution is rare. >+// >+// If the std::string being modified is known at compile-time, and the substitutions >+// vary, `absl::Substitute()` may be a better choice. >+// >+// Example: >+// >+// std::string html_escaped = absl::StrReplaceAll(user_input, { >+// {"&", "&"}, >+// {"<", "<"}, >+// {">", ">"}, >+// {"\"", """}, >+// {"'", "'"}}); >+#ifndef ABSL_STRINGS_STR_REPLACE_H_ >+#define ABSL_STRINGS_STR_REPLACE_H_ >+ >+#include <string> >+#include <utility> >+#include <vector> >+ >+#include "absl/base/attributes.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// StrReplaceAll() >+// >+// Replaces character sequences within a given std::string with replacements provided >+// within an initializer list of key/value pairs. Candidate replacements are >+// considered in order as they occur within the std::string, with earlier matches >+// taking precedence, and longer matches taking precedence for candidates >+// starting at the same position in the std::string. Once a substitution is made, the >+// replaced text is not considered for any further substitutions. >+// >+// Example: >+// >+// std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", >+// {{"$count", absl::StrCat(5)}, >+// {"$who", "Bob"}, >+// {"#Noun", "Apples"}}); >+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+ABSL_MUST_USE_RESULT std::string StrReplaceAll( >+ absl::string_view s, >+ std::initializer_list<std::pair<absl::string_view, absl::string_view>> >+ replacements); >+ >+// Overload of `StrReplaceAll()` to accept a container of key/value replacement >+// pairs (typically either an associative map or a `std::vector` of `std::pair` >+// elements). A vector of pairs is generally more efficient. >+// >+// Examples: >+// >+// std::map<const absl::string_view, const absl::string_view> replacements; >+// replacements["$who"] = "Bob"; >+// replacements["$count"] = "5"; >+// replacements["#Noun"] = "Apples"; >+// std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", >+// replacements); >+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+// >+// // A std::vector of std::pair elements can be more efficient. >+// std::vector<std::pair<const absl::string_view, std::string>> replacements; >+// replacements.push_back({"&", "&"}); >+// replacements.push_back({"<", "<"}); >+// replacements.push_back({">", ">"}); >+// std::string s = absl::StrReplaceAll("if (ptr < &foo)", >+// replacements); >+// EXPECT_EQ("if (ptr < &foo)", s); >+template <typename StrToStrMapping> >+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements); >+ >+// Overload of `StrReplaceAll()` to replace character sequences within a given >+// output std::string *in place* with replacements provided within an initializer >+// list of key/value pairs, returning the number of substitutions that occurred. >+// >+// Example: >+// >+// std::string s = std::string("$who bought $count #Noun. Thanks $who!"); >+// int count; >+// count = absl::StrReplaceAll({{"$count", absl::StrCat(5)}, >+// {"$who", "Bob"}, >+// {"#Noun", "Apples"}}, &s); >+// EXPECT_EQ(count, 4); >+// EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+int StrReplaceAll( >+ std::initializer_list<std::pair<absl::string_view, absl::string_view>> >+ replacements, >+ std::string* target); >+ >+// Overload of `StrReplaceAll()` to replace patterns within a given output >+// std::string *in place* with replacements provided within a container of key/value >+// pairs. >+// >+// Example: >+// >+// std::string s = std::string("if (ptr < &foo)"); >+// int count = absl::StrReplaceAll({{"&", "&"}, >+// {"<", "<"}, >+// {">", ">"}}, &s); >+// EXPECT_EQ(count, 2); >+// EXPECT_EQ("if (ptr < &foo)", s); >+template <typename StrToStrMapping> >+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target); >+ >+// Implementation details only, past this point. >+namespace strings_internal { >+ >+struct ViableSubstitution { >+ absl::string_view old; >+ absl::string_view replacement; >+ size_t offset; >+ >+ ViableSubstitution(absl::string_view old_str, >+ absl::string_view replacement_str, size_t offset_val) >+ : old(old_str), replacement(replacement_str), offset(offset_val) {} >+ >+ // One substitution occurs "before" another (takes priority) if either >+ // it has the lowest offset, or it has the same offset but a larger size. >+ bool OccursBefore(const ViableSubstitution& y) const { >+ if (offset != y.offset) return offset < y.offset; >+ return old.size() > y.old.size(); >+ } >+}; >+ >+// Build a vector of ViableSubstitutions based on the given list of >+// replacements. subs can be implemented as a priority_queue. However, it turns >+// out that most callers have small enough a list of substitutions that the >+// overhead of such a queue isn't worth it. >+template <typename StrToStrMapping> >+std::vector<ViableSubstitution> FindSubstitutions( >+ absl::string_view s, const StrToStrMapping& replacements) { >+ std::vector<ViableSubstitution> subs; >+ subs.reserve(replacements.size()); >+ >+ for (const auto& rep : replacements) { >+ using std::get; >+ absl::string_view old(get<0>(rep)); >+ >+ size_t pos = s.find(old); >+ if (pos == s.npos) continue; >+ >+ // Ignore attempts to replace "". This condition is almost never true, >+ // but above condition is frequently true. That's why we test for this >+ // now and not before. >+ if (old.empty()) continue; >+ >+ subs.emplace_back(old, get<1>(rep), pos); >+ >+ // Insertion sort to ensure the last ViableSubstitution comes before >+ // all the others. >+ size_t index = subs.size(); >+ while (--index && subs[index - 1].OccursBefore(subs[index])) { >+ std::swap(subs[index], subs[index - 1]); >+ } >+ } >+ return subs; >+} >+ >+int ApplySubstitutions(absl::string_view s, >+ std::vector<ViableSubstitution>* subs_ptr, >+ std::string* result_ptr); >+ >+} // namespace strings_internal >+ >+template <typename StrToStrMapping> >+std::string StrReplaceAll(absl::string_view s, const StrToStrMapping& replacements) { >+ auto subs = strings_internal::FindSubstitutions(s, replacements); >+ std::string result; >+ result.reserve(s.size()); >+ strings_internal::ApplySubstitutions(s, &subs, &result); >+ return result; >+} >+ >+template <typename StrToStrMapping> >+int StrReplaceAll(const StrToStrMapping& replacements, std::string* target) { >+ auto subs = strings_internal::FindSubstitutions(*target, replacements); >+ if (subs.empty()) return 0; >+ >+ std::string result; >+ result.reserve(target->size()); >+ int substitutions = >+ strings_internal::ApplySubstitutions(*target, &subs, &result); >+ target->swap(result); >+ return substitutions; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STR_REPLACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_benchmark.cc >new file mode 100644 >index 00000000000..e608de8d19e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_benchmark.cc >@@ -0,0 +1,122 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_replace.h" >+ >+#include <cstring> >+#include <string> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace { >+ >+std::string* big_string; >+std::string* after_replacing_the; >+std::string* after_replacing_many; >+ >+struct Replacement { >+ const char* needle; >+ const char* replacement; >+} replacements[] = { >+ {"the", "box"}, // >+ {"brown", "quick"}, // >+ {"jumped", "liquored"}, // >+ {"dozen", "brown"}, // >+ {"lazy", "pack"}, // >+ {"liquor", "shakes"}, // >+}; >+ >+// Here, we set up a std::string for use in global-replace benchmarks. >+// We started with a million blanks, and then deterministically insert >+// 10,000 copies each of two pangrams. The result is a std::string that is >+// 40% blank space and 60% these words. 'the' occurs 18,247 times and >+// all the substitutions together occur 49,004 times. >+// >+// We then create "after_replacing_the" to be a std::string that is a result of >+// replacing "the" with "box" in big_string. >+// >+// And then we create "after_replacing_many" to be a std::string that is result >+// of preferring several substitutions. >+void SetUpStrings() { >+ if (big_string == nullptr) { >+ size_t r = 0; >+ big_string = new std::string(1000 * 1000, ' '); >+ for (std::string phrase : {"the quick brown fox jumped over the lazy dogs", >+ "pack my box with the five dozen liquor jugs"}) { >+ for (int i = 0; i < 10 * 1000; ++i) { >+ r = r * 237 + 41; // not very random. >+ memcpy(&(*big_string)[r % (big_string->size() - phrase.size())], >+ phrase.data(), phrase.size()); >+ } >+ } >+ // big_string->resize(50); >+ // OK, we've set up the std::string, now let's set up expectations - first by >+ // just replacing "the" with "box" >+ after_replacing_the = new std::string(*big_string); >+ for (size_t pos = 0; >+ (pos = after_replacing_the->find("the", pos)) != std::string::npos;) { >+ memcpy(&(*after_replacing_the)[pos], "box", 3); >+ } >+ // And then with all the replacements. >+ after_replacing_many = new std::string(*big_string); >+ for (size_t pos = 0;;) { >+ size_t next_pos = static_cast<size_t>(-1); >+ const char* needle_string = nullptr; >+ const char* replacement_string = nullptr; >+ for (const auto& r : replacements) { >+ auto needlepos = after_replacing_many->find(r.needle, pos); >+ if (needlepos != std::string::npos && needlepos < next_pos) { >+ next_pos = needlepos; >+ needle_string = r.needle; >+ replacement_string = r.replacement; >+ } >+ } >+ if (next_pos > after_replacing_many->size()) break; >+ after_replacing_many->replace(next_pos, strlen(needle_string), >+ replacement_string); >+ next_pos += strlen(replacement_string); >+ pos = next_pos; >+ } >+ } >+} >+ >+void BM_StrReplaceAllOneReplacement(benchmark::State& state) { >+ SetUpStrings(); >+ std::string src = *big_string; >+ for (auto _ : state) { >+ std::string dest = absl::StrReplaceAll(src, {{"the", "box"}}); >+ ABSL_RAW_CHECK(dest == *after_replacing_the, >+ "not benchmarking intended behavior"); >+ } >+} >+BENCHMARK(BM_StrReplaceAllOneReplacement); >+ >+void BM_StrReplaceAll(benchmark::State& state) { >+ SetUpStrings(); >+ std::string src = *big_string; >+ for (auto _ : state) { >+ std::string dest = absl::StrReplaceAll(src, {{"the", "box"}, >+ {"brown", "quick"}, >+ {"jumped", "liquored"}, >+ {"dozen", "brown"}, >+ {"lazy", "pack"}, >+ {"liquor", "shakes"}}); >+ ABSL_RAW_CHECK(dest == *after_replacing_many, >+ "not benchmarking intended behavior"); >+ } >+} >+BENCHMARK(BM_StrReplaceAll); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_test.cc >new file mode 100644 >index 00000000000..5d003a224a4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_replace_test.cc >@@ -0,0 +1,341 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_replace.h" >+ >+#include <list> >+#include <map> >+#include <tuple> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/str_cat.h" >+#include "absl/strings/str_split.h" >+ >+TEST(StrReplaceAll, OneReplacement) { >+ std::string s; >+ >+ // Empty std::string. >+ s = absl::StrReplaceAll(s, {{"", ""}}); >+ EXPECT_EQ(s, ""); >+ s = absl::StrReplaceAll(s, {{"x", ""}}); >+ EXPECT_EQ(s, ""); >+ s = absl::StrReplaceAll(s, {{"", "y"}}); >+ EXPECT_EQ(s, ""); >+ s = absl::StrReplaceAll(s, {{"x", "y"}}); >+ EXPECT_EQ(s, ""); >+ >+ // Empty substring. >+ s = absl::StrReplaceAll("abc", {{"", ""}}); >+ EXPECT_EQ(s, "abc"); >+ s = absl::StrReplaceAll("abc", {{"", "y"}}); >+ EXPECT_EQ(s, "abc"); >+ s = absl::StrReplaceAll("abc", {{"x", ""}}); >+ EXPECT_EQ(s, "abc"); >+ >+ // Substring not found. >+ s = absl::StrReplaceAll("abc", {{"xyz", "123"}}); >+ EXPECT_EQ(s, "abc"); >+ >+ // Replace entire std::string. >+ s = absl::StrReplaceAll("abc", {{"abc", "xyz"}}); >+ EXPECT_EQ(s, "xyz"); >+ >+ // Replace once at the start. >+ s = absl::StrReplaceAll("abc", {{"a", "x"}}); >+ EXPECT_EQ(s, "xbc"); >+ >+ // Replace once in the middle. >+ s = absl::StrReplaceAll("abc", {{"b", "x"}}); >+ EXPECT_EQ(s, "axc"); >+ >+ // Replace once at the end. >+ s = absl::StrReplaceAll("abc", {{"c", "x"}}); >+ EXPECT_EQ(s, "abx"); >+ >+ // Replace multiple times with varying lengths of original/replacement. >+ s = absl::StrReplaceAll("ababa", {{"a", "xxx"}}); >+ EXPECT_EQ(s, "xxxbxxxbxxx"); >+ >+ s = absl::StrReplaceAll("ababa", {{"b", "xxx"}}); >+ EXPECT_EQ(s, "axxxaxxxa"); >+ >+ s = absl::StrReplaceAll("aaabaaabaaa", {{"aaa", "x"}}); >+ EXPECT_EQ(s, "xbxbx"); >+ >+ s = absl::StrReplaceAll("abbbabbba", {{"bbb", "x"}}); >+ EXPECT_EQ(s, "axaxa"); >+ >+ // Overlapping matches are replaced greedily. >+ s = absl::StrReplaceAll("aaa", {{"aa", "x"}}); >+ EXPECT_EQ(s, "xa"); >+ >+ // The replacements are not recursive. >+ s = absl::StrReplaceAll("aaa", {{"aa", "a"}}); >+ EXPECT_EQ(s, "aa"); >+} >+ >+TEST(StrReplaceAll, ManyReplacements) { >+ std::string s; >+ >+ // Empty std::string. >+ s = absl::StrReplaceAll("", {{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}); >+ EXPECT_EQ(s, ""); >+ >+ // Empty substring. >+ s = absl::StrReplaceAll("abc", {{"", ""}, {"", "y"}, {"x", ""}}); >+ EXPECT_EQ(s, "abc"); >+ >+ // Replace entire std::string, one char at a time >+ s = absl::StrReplaceAll("abc", {{"a", "x"}, {"b", "y"}, {"c", "z"}}); >+ EXPECT_EQ(s, "xyz"); >+ s = absl::StrReplaceAll("zxy", {{"z", "x"}, {"x", "y"}, {"y", "z"}}); >+ EXPECT_EQ(s, "xyz"); >+ >+ // Replace once at the start (longer matches take precedence) >+ s = absl::StrReplaceAll("abc", {{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}}); >+ EXPECT_EQ(s, "xyz"); >+ >+ // Replace once in the middle. >+ s = absl::StrReplaceAll( >+ "Abc!", {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}}); >+ EXPECT_EQ(s, "Ayz!"); >+ >+ // Replace once at the end. >+ s = absl::StrReplaceAll( >+ "Abc!", >+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}}); >+ EXPECT_EQ(s, "Ayz?"); >+ >+ // Replace multiple times with varying lengths of original/replacement. >+ s = absl::StrReplaceAll("ababa", {{"a", "xxx"}, {"b", "XXXX"}}); >+ EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx"); >+ >+ // Overlapping matches are replaced greedily. >+ s = absl::StrReplaceAll("aaa", {{"aa", "x"}, {"a", "X"}}); >+ EXPECT_EQ(s, "xX"); >+ s = absl::StrReplaceAll("aaa", {{"a", "X"}, {"aa", "x"}}); >+ EXPECT_EQ(s, "xX"); >+ >+ // Two well-known sentences >+ s = absl::StrReplaceAll("the quick brown fox jumped over the lazy dogs", >+ { >+ {"brown", "box"}, >+ {"dogs", "jugs"}, >+ {"fox", "with"}, >+ {"jumped", "five"}, >+ {"over", "dozen"}, >+ {"quick", "my"}, >+ {"the", "pack"}, >+ {"the lazy", "liquor"}, >+ }); >+ EXPECT_EQ(s, "pack my box with five dozen liquor jugs"); >+} >+ >+TEST(StrReplaceAll, ManyReplacementsInMap) { >+ std::map<const char *, const char *> replacements; >+ replacements["$who"] = "Bob"; >+ replacements["$count"] = "5"; >+ replacements["#Noun"] = "Apples"; >+ std::string s = absl::StrReplaceAll("$who bought $count #Noun. Thanks $who!", >+ replacements); >+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+} >+ >+TEST(StrReplaceAll, ReplacementsInPlace) { >+ std::string s = std::string("$who bought $count #Noun. Thanks $who!"); >+ int count; >+ count = absl::StrReplaceAll({{"$count", absl::StrCat(5)}, >+ {"$who", "Bob"}, >+ {"#Noun", "Apples"}}, &s); >+ EXPECT_EQ(count, 4); >+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+} >+ >+TEST(StrReplaceAll, ReplacementsInPlaceInMap) { >+ std::string s = std::string("$who bought $count #Noun. Thanks $who!"); >+ std::map<absl::string_view, absl::string_view> replacements; >+ replacements["$who"] = "Bob"; >+ replacements["$count"] = "5"; >+ replacements["#Noun"] = "Apples"; >+ int count; >+ count = absl::StrReplaceAll(replacements, &s); >+ EXPECT_EQ(count, 4); >+ EXPECT_EQ("Bob bought 5 Apples. Thanks Bob!", s); >+} >+ >+struct Cont { >+ Cont() {} >+ explicit Cont(absl::string_view src) : data(src) {} >+ >+ absl::string_view data; >+}; >+ >+template <int index> >+absl::string_view get(const Cont& c) { >+ auto splitter = absl::StrSplit(c.data, ':'); >+ auto it = splitter.begin(); >+ for (int i = 0; i < index; ++i) ++it; >+ >+ return *it; >+} >+ >+TEST(StrReplaceAll, VariableNumber) { >+ std::string s; >+ { >+ std::vector<std::pair<std::string, std::string>> replacements; >+ >+ s = "abc"; >+ EXPECT_EQ(0, absl::StrReplaceAll(replacements, &s)); >+ EXPECT_EQ("abc", s); >+ >+ s = "abc"; >+ replacements.push_back({"a", "A"}); >+ EXPECT_EQ(1, absl::StrReplaceAll(replacements, &s)); >+ EXPECT_EQ("Abc", s); >+ >+ s = "abc"; >+ replacements.push_back({"b", "B"}); >+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s)); >+ EXPECT_EQ("ABc", s); >+ >+ s = "abc"; >+ replacements.push_back({"d", "D"}); >+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s)); >+ EXPECT_EQ("ABc", s); >+ >+ EXPECT_EQ("ABcABc", absl::StrReplaceAll("abcabc", replacements)); >+ } >+ >+ { >+ std::map<const char*, const char*> replacements; >+ replacements["aa"] = "x"; >+ replacements["a"] = "X"; >+ s = "aaa"; >+ EXPECT_EQ(2, absl::StrReplaceAll(replacements, &s)); >+ EXPECT_EQ("xX", s); >+ >+ EXPECT_EQ("xxX", absl::StrReplaceAll("aaaaa", replacements)); >+ } >+ >+ { >+ std::list<std::pair<absl::string_view, absl::string_view>> replacements = { >+ {"a", "x"}, {"b", "y"}, {"c", "z"}}; >+ >+ std::string s = absl::StrReplaceAll("abc", replacements); >+ EXPECT_EQ(s, "xyz"); >+ } >+ >+ { >+ using X = std::tuple<absl::string_view, std::string, int>; >+ std::vector<X> replacements(3); >+ replacements[0] = X{"a", "x", 1}; >+ replacements[1] = X{"b", "y", 0}; >+ replacements[2] = X{"c", "z", -1}; >+ >+ std::string s = absl::StrReplaceAll("abc", replacements); >+ EXPECT_EQ(s, "xyz"); >+ } >+ >+ { >+ std::vector<Cont> replacements(3); >+ replacements[0] = Cont{"a:x"}; >+ replacements[1] = Cont{"b:y"}; >+ replacements[2] = Cont{"c:z"}; >+ >+ std::string s = absl::StrReplaceAll("abc", replacements); >+ EXPECT_EQ(s, "xyz"); >+ } >+} >+ >+// Same as above, but using the in-place variant of absl::StrReplaceAll, >+// that returns the # of replacements performed. >+TEST(StrReplaceAll, Inplace) { >+ std::string s; >+ int reps; >+ >+ // Empty std::string. >+ s = ""; >+ reps = absl::StrReplaceAll({{"", ""}, {"x", ""}, {"", "y"}, {"x", "y"}}, &s); >+ EXPECT_EQ(reps, 0); >+ EXPECT_EQ(s, ""); >+ >+ // Empty substring. >+ s = "abc"; >+ reps = absl::StrReplaceAll({{"", ""}, {"", "y"}, {"x", ""}}, &s); >+ EXPECT_EQ(reps, 0); >+ EXPECT_EQ(s, "abc"); >+ >+ // Replace entire std::string, one char at a time >+ s = "abc"; >+ reps = absl::StrReplaceAll({{"a", "x"}, {"b", "y"}, {"c", "z"}}, &s); >+ EXPECT_EQ(reps, 3); >+ EXPECT_EQ(s, "xyz"); >+ s = "zxy"; >+ reps = absl::StrReplaceAll({{"z", "x"}, {"x", "y"}, {"y", "z"}}, &s); >+ EXPECT_EQ(reps, 3); >+ EXPECT_EQ(s, "xyz"); >+ >+ // Replace once at the start (longer matches take precedence) >+ s = "abc"; >+ reps = absl::StrReplaceAll({{"a", "x"}, {"ab", "xy"}, {"abc", "xyz"}}, &s); >+ EXPECT_EQ(reps, 1); >+ EXPECT_EQ(s, "xyz"); >+ >+ // Replace once in the middle. >+ s = "Abc!"; >+ reps = absl::StrReplaceAll( >+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc", "yz"}, {"c", "z"}}, &s); >+ EXPECT_EQ(reps, 1); >+ EXPECT_EQ(s, "Ayz!"); >+ >+ // Replace once at the end. >+ s = "Abc!"; >+ reps = absl::StrReplaceAll( >+ {{"a", "x"}, {"ab", "xy"}, {"b", "y"}, {"bc!", "yz?"}, {"c!", "z;"}}, &s); >+ EXPECT_EQ(reps, 1); >+ EXPECT_EQ(s, "Ayz?"); >+ >+ // Replace multiple times with varying lengths of original/replacement. >+ s = "ababa"; >+ reps = absl::StrReplaceAll({{"a", "xxx"}, {"b", "XXXX"}}, &s); >+ EXPECT_EQ(reps, 5); >+ EXPECT_EQ(s, "xxxXXXXxxxXXXXxxx"); >+ >+ // Overlapping matches are replaced greedily. >+ s = "aaa"; >+ reps = absl::StrReplaceAll({{"aa", "x"}, {"a", "X"}}, &s); >+ EXPECT_EQ(reps, 2); >+ EXPECT_EQ(s, "xX"); >+ s = "aaa"; >+ reps = absl::StrReplaceAll({{"a", "X"}, {"aa", "x"}}, &s); >+ EXPECT_EQ(reps, 2); >+ EXPECT_EQ(s, "xX"); >+ >+ // Two well-known sentences >+ s = "the quick brown fox jumped over the lazy dogs"; >+ reps = absl::StrReplaceAll( >+ { >+ {"brown", "box"}, >+ {"dogs", "jugs"}, >+ {"fox", "with"}, >+ {"jumped", "five"}, >+ {"over", "dozen"}, >+ {"quick", "my"}, >+ {"the", "pack"}, >+ {"the lazy", "liquor"}, >+ }, >+ &s); >+ EXPECT_EQ(reps, 8); >+ EXPECT_EQ(s, "pack my box with five dozen liquor jugs"); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.cc >new file mode 100644 >index 00000000000..0207213c26b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.cc >@@ -0,0 +1,136 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_split.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <cstdint> >+#include <cstdlib> >+#include <cstring> >+#include <iterator> >+#include <limits> >+#include <memory> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/ascii.h" >+ >+namespace absl { >+ >+namespace { >+ >+// This GenericFind() template function encapsulates the finding algorithm >+// shared between the ByString and ByAnyChar delimiters. The FindPolicy >+// template parameter allows each delimiter to customize the actual find >+// function to use and the length of the found delimiter. For example, the >+// Literal delimiter will ultimately use absl::string_view::find(), and the >+// AnyOf delimiter will use absl::string_view::find_first_of(). >+template <typename FindPolicy> >+absl::string_view GenericFind(absl::string_view text, >+ absl::string_view delimiter, size_t pos, >+ FindPolicy find_policy) { >+ if (delimiter.empty() && text.length() > 0) { >+ // Special case for empty std::string delimiters: always return a zero-length >+ // absl::string_view referring to the item at position 1 past pos. >+ return absl::string_view(text.begin() + pos + 1, 0); >+ } >+ size_t found_pos = absl::string_view::npos; >+ absl::string_view found(text.end(), 0); // By default, not found >+ found_pos = find_policy.Find(text, delimiter, pos); >+ if (found_pos != absl::string_view::npos) { >+ found = absl::string_view(text.data() + found_pos, >+ find_policy.Length(delimiter)); >+ } >+ return found; >+} >+ >+// Finds using absl::string_view::find(), therefore the length of the found >+// delimiter is delimiter.length(). >+struct LiteralPolicy { >+ size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) { >+ return text.find(delimiter, pos); >+ } >+ size_t Length(absl::string_view delimiter) { return delimiter.length(); } >+}; >+ >+// Finds using absl::string_view::find_first_of(), therefore the length of the >+// found delimiter is 1. >+struct AnyOfPolicy { >+ size_t Find(absl::string_view text, absl::string_view delimiter, size_t pos) { >+ return text.find_first_of(delimiter, pos); >+ } >+ size_t Length(absl::string_view /* delimiter */) { return 1; } >+}; >+ >+} // namespace >+ >+// >+// ByString >+// >+ >+ByString::ByString(absl::string_view sp) : delimiter_(sp) {} >+ >+absl::string_view ByString::Find(absl::string_view text, size_t pos) const { >+ if (delimiter_.length() == 1) { >+ // Much faster to call find on a single character than on an >+ // absl::string_view. >+ size_t found_pos = text.find(delimiter_[0], pos); >+ if (found_pos == absl::string_view::npos) >+ return absl::string_view(text.end(), 0); >+ return text.substr(found_pos, 1); >+ } >+ return GenericFind(text, delimiter_, pos, LiteralPolicy()); >+} >+ >+// >+// ByChar >+// >+ >+absl::string_view ByChar::Find(absl::string_view text, size_t pos) const { >+ size_t found_pos = text.find(c_, pos); >+ if (found_pos == absl::string_view::npos) >+ return absl::string_view(text.end(), 0); >+ return text.substr(found_pos, 1); >+} >+ >+// >+// ByAnyChar >+// >+ >+ByAnyChar::ByAnyChar(absl::string_view sp) : delimiters_(sp) {} >+ >+absl::string_view ByAnyChar::Find(absl::string_view text, size_t pos) const { >+ return GenericFind(text, delimiters_, pos, AnyOfPolicy()); >+} >+ >+// >+// ByLength >+// >+ByLength::ByLength(ptrdiff_t length) : length_(length) { >+ ABSL_RAW_CHECK(length > 0, ""); >+} >+ >+absl::string_view ByLength::Find(absl::string_view text, >+ size_t pos) const { >+ pos = std::min(pos, text.size()); // truncate `pos` >+ absl::string_view substr = text.substr(pos); >+ // If the std::string is shorter than the chunk size we say we >+ // "can't find the delimiter" so this will be the last chunk. >+ if (substr.length() <= static_cast<size_t>(length_)) >+ return absl::string_view(text.end(), 0); >+ >+ return absl::string_view(substr.begin() + length_, 0); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.h >new file mode 100644 >index 00000000000..9a7be2b0534 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split.h >@@ -0,0 +1,511 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: str_split.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains functions for splitting strings. It defines the main >+// `StrSplit()` function, several delimiters for determining the boundaries on >+// which to split the std::string, and predicates for filtering delimited results. >+// `StrSplit()` adapts the returned collection to the type specified by the >+// caller. >+// >+// Example: >+// >+// // Splits the given std::string on commas. Returns the results in a >+// // vector of strings. >+// std::vector<std::string> v = absl::StrSplit("a,b,c", ','); >+// // Can also use "," >+// // v[0] == "a", v[1] == "b", v[2] == "c" >+// >+// See StrSplit() below for more information. >+#ifndef ABSL_STRINGS_STR_SPLIT_H_ >+#define ABSL_STRINGS_STR_SPLIT_H_ >+ >+#include <algorithm> >+#include <cstddef> >+#include <map> >+#include <set> >+#include <string> >+#include <utility> >+#include <vector> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/internal/str_split_internal.h" >+#include "absl/strings/string_view.h" >+#include "absl/strings/strip.h" >+ >+namespace absl { >+ >+//------------------------------------------------------------------------------ >+// Delimiters >+//------------------------------------------------------------------------------ >+// >+// `StrSplit()` uses delimiters to define the boundaries between elements in the >+// provided input. Several `Delimiter` types are defined below. If a std::string >+// (`const char*`, `std::string`, or `absl::string_view`) is passed in place of >+// an explicit `Delimiter` object, `StrSplit()` treats it the same way as if it >+// were passed a `ByString` delimiter. >+// >+// A `Delimiter` is an object with a `Find()` function that knows how to find >+// the first occurrence of itself in a given `absl::string_view`. >+// >+// The following `Delimiter` types are available for use within `StrSplit()`: >+// >+// - `ByString` (default for std::string arguments) >+// - `ByChar` (default for a char argument) >+// - `ByAnyChar` >+// - `ByLength` >+// - `MaxSplits` >+// >+// >+// A Delimiter's Find() member function will be passed the input text that is to >+// be split and the position to begin searching for the next delimiter in the >+// input text. The returned absl::string_view should refer to the next >+// occurrence (after pos) of the represented delimiter; this returned >+// absl::string_view represents the next location where the input std::string should >+// be broken. The returned absl::string_view may be zero-length if the Delimiter >+// does not represent a part of the std::string (e.g., a fixed-length delimiter). If >+// no delimiter is found in the given text, a zero-length absl::string_view >+// referring to text.end() should be returned (e.g., >+// absl::string_view(text.end(), 0)). It is important that the returned >+// absl::string_view always be within the bounds of input text given as an >+// argument--it must not refer to a std::string that is physically located outside of >+// the given std::string. >+// >+// The following example is a simple Delimiter object that is created with a >+// single char and will look for that char in the text passed to the Find() >+// function: >+// >+// struct SimpleDelimiter { >+// const char c_; >+// explicit SimpleDelimiter(char c) : c_(c) {} >+// absl::string_view Find(absl::string_view text, size_t pos) { >+// auto found = text.find(c_, pos); >+// if (found == absl::string_view::npos) >+// return absl::string_view(text.end(), 0); >+// >+// return absl::string_view(text, found, 1); >+// } >+// }; >+ >+// ByString >+// >+// A sub-std::string delimiter. If `StrSplit()` is passed a std::string in place of a >+// `Delimiter` object, the std::string will be implicitly converted into a >+// `ByString` delimiter. >+// >+// Example: >+// >+// // Because a std::string literal is converted to an `absl::ByString`, >+// // the following two splits are equivalent. >+// >+// std::vector<std::string> v1 = absl::StrSplit("a, b, c", ", "); >+// >+// using absl::ByString; >+// std::vector<std::string> v2 = absl::StrSplit("a, b, c", >+// ByString(", ")); >+// // v[0] == "a", v[1] == "b", v[2] == "c" >+class ByString { >+ public: >+ explicit ByString(absl::string_view sp); >+ absl::string_view Find(absl::string_view text, size_t pos) const; >+ >+ private: >+ const std::string delimiter_; >+}; >+ >+// ByChar >+// >+// A single character delimiter. `ByChar` is functionally equivalent to a >+// 1-char std::string within a `ByString` delimiter, but slightly more >+// efficient. >+// >+// Example: >+// >+// // Because a char literal is converted to a absl::ByChar, >+// // the following two splits are equivalent. >+// std::vector<std::string> v1 = absl::StrSplit("a,b,c", ','); >+// using absl::ByChar; >+// std::vector<std::string> v2 = absl::StrSplit("a,b,c", ByChar(',')); >+// // v[0] == "a", v[1] == "b", v[2] == "c" >+// >+// `ByChar` is also the default delimiter if a single character is given >+// as the delimiter to `StrSplit()`. For example, the following calls are >+// equivalent: >+// >+// std::vector<std::string> v = absl::StrSplit("a-b", '-'); >+// >+// using absl::ByChar; >+// std::vector<std::string> v = absl::StrSplit("a-b", ByChar('-')); >+// >+class ByChar { >+ public: >+ explicit ByChar(char c) : c_(c) {} >+ absl::string_view Find(absl::string_view text, size_t pos) const; >+ >+ private: >+ char c_; >+}; >+ >+// ByAnyChar >+// >+// A delimiter that will match any of the given byte-sized characters within >+// its provided std::string. >+// >+// Note: this delimiter works with single-byte std::string data, but does not work >+// with variable-width encodings, such as UTF-8. >+// >+// Example: >+// >+// using absl::ByAnyChar; >+// std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",=")); >+// // v[0] == "a", v[1] == "b", v[2] == "c" >+// >+// If `ByAnyChar` is given the empty std::string, it behaves exactly like >+// `ByString` and matches each individual character in the input std::string. >+// >+class ByAnyChar { >+ public: >+ explicit ByAnyChar(absl::string_view sp); >+ absl::string_view Find(absl::string_view text, size_t pos) const; >+ >+ private: >+ const std::string delimiters_; >+}; >+ >+// ByLength >+// >+// A delimiter for splitting into equal-length strings. The length argument to >+// the constructor must be greater than 0. >+// >+// Note: this delimiter works with single-byte std::string data, but does not work >+// with variable-width encodings, such as UTF-8. >+// >+// Example: >+// >+// using absl::ByLength; >+// std::vector<std::string> v = absl::StrSplit("123456789", ByLength(3)); >+ >+// // v[0] == "123", v[1] == "456", v[2] == "789" >+// >+// Note that the std::string does not have to be a multiple of the fixed split >+// length. In such a case, the last substring will be shorter. >+// >+// using absl::ByLength; >+// std::vector<std::string> v = absl::StrSplit("12345", ByLength(2)); >+// >+// // v[0] == "12", v[1] == "34", v[2] == "5" >+class ByLength { >+ public: >+ explicit ByLength(ptrdiff_t length); >+ absl::string_view Find(absl::string_view text, size_t pos) const; >+ >+ private: >+ const ptrdiff_t length_; >+}; >+ >+namespace strings_internal { >+ >+// A traits-like metafunction for selecting the default Delimiter object type >+// for a particular Delimiter type. The base case simply exposes type Delimiter >+// itself as the delimiter's Type. However, there are specializations for >+// std::string-like objects that map them to the ByString delimiter object. >+// This allows functions like absl::StrSplit() and absl::MaxSplits() to accept >+// std::string-like objects (e.g., ',') as delimiter arguments but they will be >+// treated as if a ByString delimiter was given. >+template <typename Delimiter> >+struct SelectDelimiter { >+ using type = Delimiter; >+}; >+ >+template <> >+struct SelectDelimiter<char> { >+ using type = ByChar; >+}; >+template <> >+struct SelectDelimiter<char*> { >+ using type = ByString; >+}; >+template <> >+struct SelectDelimiter<const char*> { >+ using type = ByString; >+}; >+template <> >+struct SelectDelimiter<absl::string_view> { >+ using type = ByString; >+}; >+template <> >+struct SelectDelimiter<std::string> { >+ using type = ByString; >+}; >+ >+// Wraps another delimiter and sets a max number of matches for that delimiter. >+template <typename Delimiter> >+class MaxSplitsImpl { >+ public: >+ MaxSplitsImpl(Delimiter delimiter, int limit) >+ : delimiter_(delimiter), limit_(limit), count_(0) {} >+ absl::string_view Find(absl::string_view text, size_t pos) { >+ if (count_++ == limit_) { >+ return absl::string_view(text.end(), 0); // No more matches. >+ } >+ return delimiter_.Find(text, pos); >+ } >+ >+ private: >+ Delimiter delimiter_; >+ const int limit_; >+ int count_; >+}; >+ >+} // namespace strings_internal >+ >+// MaxSplits() >+// >+// A delimiter that limits the number of matches which can occur to the passed >+// `limit`. The last element in the returned collection will contain all >+// remaining unsplit pieces, which may contain instances of the delimiter. >+// The collection will contain at most `limit` + 1 elements. >+// Example: >+// >+// using absl::MaxSplits; >+// std::vector<std::string> v = absl::StrSplit("a,b,c", MaxSplits(',', 1)); >+// >+// // v[0] == "a", v[1] == "b,c" >+template <typename Delimiter> >+inline strings_internal::MaxSplitsImpl< >+ typename strings_internal::SelectDelimiter<Delimiter>::type> >+MaxSplits(Delimiter delimiter, int limit) { >+ typedef >+ typename strings_internal::SelectDelimiter<Delimiter>::type DelimiterType; >+ return strings_internal::MaxSplitsImpl<DelimiterType>( >+ DelimiterType(delimiter), limit); >+} >+ >+//------------------------------------------------------------------------------ >+// Predicates >+//------------------------------------------------------------------------------ >+// >+// Predicates filter the results of a `StrSplit()` by determining whether or not >+// a resultant element is included in the result set. A predicate may be passed >+// as an optional third argument to the `StrSplit()` function. >+// >+// Predicates are unary functions (or functors) that take a single >+// `absl::string_view` argument and return a bool indicating whether the >+// argument should be included (`true`) or excluded (`false`). >+// >+// Predicates are useful when filtering out empty substrings. By default, empty >+// substrings may be returned by `StrSplit()`, which is similar to the way split >+// functions work in other programming languages. >+ >+// AllowEmpty() >+// >+// Always returns `true`, indicating that all strings--including empty >+// strings--should be included in the split output. This predicate is not >+// strictly needed because this is the default behavior of `StrSplit()`; >+// however, it might be useful at some call sites to make the intent explicit. >+// >+// Example: >+// >+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', AllowEmpty()); >+// >+// // v[0] == " a ", v[1] == " ", v[2] == "", v[3] = "b", v[4] == "" >+struct AllowEmpty { >+ bool operator()(absl::string_view) const { return true; } >+}; >+ >+// SkipEmpty() >+// >+// Returns `false` if the given `absl::string_view` is empty, indicating that >+// `StrSplit()` should omit the empty std::string. >+// >+// Example: >+// >+// std::vector<std::string> v = absl::StrSplit(",a,,b,", ',', SkipEmpty()); >+// >+// // v[0] == "a", v[1] == "b" >+// >+// Note: `SkipEmpty()` does not consider a std::string containing only whitespace >+// to be empty. To skip such whitespace as well, use the `SkipWhitespace()` >+// predicate. >+struct SkipEmpty { >+ bool operator()(absl::string_view sp) const { return !sp.empty(); } >+}; >+ >+// SkipWhitespace() >+// >+// Returns `false` if the given `absl::string_view` is empty *or* contains only >+// whitespace, indicating that `StrSplit()` should omit the std::string. >+// >+// Example: >+// >+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", >+// ',', SkipWhitespace()); >+// // v[0] == " a ", v[1] == "b" >+// >+// // SkipEmpty() would return whitespace elements >+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipEmpty()); >+// // v[0] == " a ", v[1] == " ", v[2] == "b" >+struct SkipWhitespace { >+ bool operator()(absl::string_view sp) const { >+ sp = absl::StripAsciiWhitespace(sp); >+ return !sp.empty(); >+ } >+}; >+ >+//------------------------------------------------------------------------------ >+// StrSplit() >+//------------------------------------------------------------------------------ >+ >+// StrSplit() >+// >+// Splits a given std::string based on the provided `Delimiter` object, returning the >+// elements within the type specified by the caller. Optionally, you may pass a >+// `Predicate` to `StrSplit()` indicating whether to include or exclude the >+// resulting element within the final result set. (See the overviews for >+// Delimiters and Predicates above.) >+// >+// Example: >+// >+// std::vector<std::string> v = absl::StrSplit("a,b,c,d", ','); >+// // v[0] == "a", v[1] == "b", v[2] == "c", v[3] == "d" >+// >+// You can also provide an explicit `Delimiter` object: >+// >+// Example: >+// >+// using absl::ByAnyChar; >+// std::vector<std::string> v = absl::StrSplit("a,b=c", ByAnyChar(",=")); >+// // v[0] == "a", v[1] == "b", v[2] == "c" >+// >+// See above for more information on delimiters. >+// >+// By default, empty strings are included in the result set. You can optionally >+// include a third `Predicate` argument to apply a test for whether the >+// resultant element should be included in the result set: >+// >+// Example: >+// >+// std::vector<std::string> v = absl::StrSplit(" a , ,,b,", >+// ',', SkipWhitespace()); >+// // v[0] == " a ", v[1] == "b" >+// >+// See above for more information on predicates. >+// >+//------------------------------------------------------------------------------ >+// StrSplit() Return Types >+//------------------------------------------------------------------------------ >+// >+// The `StrSplit()` function adapts the returned collection to the collection >+// specified by the caller (e.g. `std::vector` above). The returned collections >+// may contain `string`, `absl::string_view` (in which case the original std::string >+// being split must ensure that it outlives the collection), or any object that >+// can be explicitly created from an `absl::string_view`. This behavior works >+// for: >+// >+// 1) All standard STL containers including `std::vector`, `std::list`, >+// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap` >+// 2) `std::pair` (which is not actually a container). See below. >+// >+// Example: >+// >+// // The results are returned as `absl::string_view` objects. Note that we >+// // have to ensure that the input std::string outlives any results. >+// std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ','); >+// >+// // Stores results in a std::set<std::string>, which also performs >+// // de-duplication and orders the elements in ascending order. >+// std::set<std::string> a = absl::StrSplit("b,a,c,a,b", ','); >+// // v[0] == "a", v[1] == "b", v[2] = "c" >+// >+// // `StrSplit()` can be used within a range-based for loop, in which case >+// // each element will be of type `absl::string_view`. >+// std::vector<std::string> v; >+// for (const auto sv : absl::StrSplit("a,b,c", ',')) { >+// if (sv != "b") v.emplace_back(sv); >+// } >+// // v[0] == "a", v[1] == "c" >+// >+// // Stores results in a map. The map implementation assumes that the input >+// // is provided as a series of key/value pairs. For example, the 0th element >+// // resulting from the split will be stored as a key to the 1st element. If >+// // an odd number of elements are resolved, the last element is paired with >+// // a default-constructed value (e.g., empty std::string). >+// std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ','); >+// // m["a"] == "b", m["c"] == "" // last component value equals "" >+// >+// Splitting to `std::pair` is an interesting case because it can hold only two >+// elements and is not a collection type. When splitting to a `std::pair` the >+// first two split strings become the `std::pair` `.first` and `.second` >+// members, respectively. The remaining split substrings are discarded. If there >+// are less than two split substrings, the empty std::string is used for the >+// corresponding >+// `std::pair` member. >+// >+// Example: >+// >+// // Stores first two split strings as the members in a std::pair. >+// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ','); >+// // p.first == "a", p.second == "b" // "c" is omitted. >+// >+// The `StrSplit()` function can be used multiple times to perform more >+// complicated splitting logic, such as intelligently parsing key-value pairs. >+// >+// Example: >+// >+// // The input std::string "a=b=c,d=e,f=,g" becomes >+// // { "a" => "b=c", "d" => "e", "f" => "", "g" => "" } >+// std::map<std::string, std::string> m; >+// for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) { >+// m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1))); >+// } >+// EXPECT_EQ("b=c", m.find("a")->second); >+// EXPECT_EQ("e", m.find("d")->second); >+// EXPECT_EQ("", m.find("f")->second); >+// EXPECT_EQ("", m.find("g")->second); >+// >+// WARNING: Due to a legacy bug that is maintained for backward compatibility, >+// splitting the following empty string_views produces different results: >+// >+// absl::StrSplit(absl::string_view(""), '-'); // {""} >+// absl::StrSplit(absl::string_view(), '-'); // {}, but should be {""} >+// >+// Try not to depend on this distinction because the bug may one day be fixed. >+template <typename Delimiter> >+strings_internal::Splitter< >+ typename strings_internal::SelectDelimiter<Delimiter>::type, AllowEmpty> >+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d) { >+ using DelimiterType = >+ typename strings_internal::SelectDelimiter<Delimiter>::type; >+ return strings_internal::Splitter<DelimiterType, AllowEmpty>( >+ std::move(text), DelimiterType(d), AllowEmpty()); >+} >+ >+template <typename Delimiter, typename Predicate> >+strings_internal::Splitter< >+ typename strings_internal::SelectDelimiter<Delimiter>::type, Predicate> >+StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d, >+ Predicate p) { >+ using DelimiterType = >+ typename strings_internal::SelectDelimiter<Delimiter>::type; >+ return strings_internal::Splitter<DelimiterType, Predicate>( >+ std::move(text), DelimiterType(d), std::move(p)); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STR_SPLIT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_benchmark.cc >new file mode 100644 >index 00000000000..326ff744ebd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_benchmark.cc >@@ -0,0 +1,156 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_split.h" >+ >+#include <iterator> >+#include <string> >+#include <unordered_map> >+#include <unordered_set> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/string_view.h" >+ >+namespace { >+ >+std::string MakeTestString(int desired_length) { >+ static const int kAverageValueLen = 25; >+ std::string test(desired_length * kAverageValueLen, 'x'); >+ for (int i = 1; i < test.size(); i += kAverageValueLen) { >+ test[i] = ';'; >+ } >+ return test; >+} >+ >+void BM_Split2StringPiece(benchmark::State& state) { >+ std::string test = MakeTestString(state.range(0)); >+ for (auto _ : state) { >+ std::vector<absl::string_view> result = absl::StrSplit(test, ';'); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_Split2StringPiece, 0, 1 << 20); >+ >+void BM_Split2StringPieceLifted(benchmark::State& state) { >+ std::string test = MakeTestString(state.range(0)); >+ std::vector<absl::string_view> result; >+ for (auto _ : state) { >+ result = absl::StrSplit(test, ';'); >+ } >+ benchmark::DoNotOptimize(result); >+} >+BENCHMARK_RANGE(BM_Split2StringPieceLifted, 0, 1 << 20); >+ >+void BM_Split2String(benchmark::State& state) { >+ std::string test = MakeTestString(state.range(0)); >+ for (auto _ : state) { >+ std::vector<std::string> result = absl::StrSplit(test, ';'); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_Split2String, 0, 1 << 20); >+ >+// This benchmark is for comparing Split2 to Split1 (SplitStringUsing). In >+// particular, this benchmark uses SkipEmpty() to match SplitStringUsing's >+// behavior. >+void BM_Split2SplitStringUsing(benchmark::State& state) { >+ std::string test = MakeTestString(state.range(0)); >+ for (auto _ : state) { >+ std::vector<std::string> result = absl::StrSplit(test, ';', absl::SkipEmpty()); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_Split2SplitStringUsing, 0, 1 << 20); >+ >+void BM_SplitStringToUnorderedSet(benchmark::State& state) { >+ const int len = state.range(0); >+ std::string test(len, 'x'); >+ for (int i = 1; i < len; i += 2) { >+ test[i] = ';'; >+ } >+ for (auto _ : state) { >+ std::unordered_set<std::string> result = >+ absl::StrSplit(test, ':', absl::SkipEmpty()); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_SplitStringToUnorderedSet, 0, 1 << 20); >+ >+void BM_SplitStringToUnorderedMap(benchmark::State& state) { >+ const int len = state.range(0); >+ std::string test(len, 'x'); >+ for (int i = 1; i < len; i += 2) { >+ test[i] = ';'; >+ } >+ for (auto _ : state) { >+ std::unordered_map<std::string, std::string> result = >+ absl::StrSplit(test, ':', absl::SkipEmpty()); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_SplitStringToUnorderedMap, 0, 1 << 20); >+ >+void BM_SplitStringAllowEmpty(benchmark::State& state) { >+ const int len = state.range(0); >+ std::string test(len, 'x'); >+ for (int i = 1; i < len; i += 2) { >+ test[i] = ';'; >+ } >+ for (auto _ : state) { >+ std::vector<std::string> result = absl::StrSplit(test, ';'); >+ benchmark::DoNotOptimize(result); >+ } >+} >+BENCHMARK_RANGE(BM_SplitStringAllowEmpty, 0, 1 << 20); >+ >+struct OneCharLiteral { >+ char operator()() const { return 'X'; } >+}; >+ >+struct OneCharStringLiteral { >+ const char* operator()() const { return "X"; } >+}; >+ >+template <typename DelimiterFactory> >+void BM_SplitStringWithOneChar(benchmark::State& state) { >+ const auto delimiter = DelimiterFactory()(); >+ std::vector<absl::string_view> pieces; >+ size_t v = 0; >+ for (auto _ : state) { >+ pieces = absl::StrSplit("The quick brown fox jumps over the lazy dog", >+ delimiter); >+ v += pieces.size(); >+ } >+ ABSL_RAW_CHECK(v == state.iterations(), ""); >+} >+BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharLiteral); >+BENCHMARK_TEMPLATE(BM_SplitStringWithOneChar, OneCharStringLiteral); >+ >+template <typename DelimiterFactory> >+void BM_SplitStringWithOneCharNoVector(benchmark::State& state) { >+ const auto delimiter = DelimiterFactory()(); >+ size_t v = 0; >+ for (auto _ : state) { >+ auto splitter = absl::StrSplit( >+ "The quick brown fox jumps over the lazy dog", delimiter); >+ v += std::distance(splitter.begin(), splitter.end()); >+ } >+ ABSL_RAW_CHECK(v == state.iterations(), ""); >+} >+BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharLiteral); >+BENCHMARK_TEMPLATE(BM_SplitStringWithOneCharNoVector, OneCharStringLiteral); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_test.cc >new file mode 100644 >index 00000000000..29a68047c99 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/str_split_test.cc >@@ -0,0 +1,935 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/str_split.h" >+ >+#include <deque> >+#include <initializer_list> >+#include <list> >+#include <map> >+#include <memory> >+#include <string> >+#include <type_traits> >+#include <unordered_map> >+#include <unordered_set> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/dynamic_annotations.h" // for AbslRunningOnValgrind >+#include "absl/base/macros.h" >+#include "absl/strings/numbers.h" >+ >+namespace { >+ >+using ::testing::ElementsAre; >+using ::testing::Pair; >+using ::testing::UnorderedElementsAre; >+ >+TEST(Split, TraitsTest) { >+ static_assert(!absl::strings_internal::SplitterIsConvertibleTo<int>::value, >+ ""); >+ static_assert(!absl::strings_internal::SplitterIsConvertibleTo<std::string>::value, >+ ""); >+ static_assert(absl::strings_internal::SplitterIsConvertibleTo< >+ std::vector<std::string>>::value, >+ ""); >+ static_assert( >+ !absl::strings_internal::SplitterIsConvertibleTo<std::vector<int>>::value, >+ ""); >+ static_assert(absl::strings_internal::SplitterIsConvertibleTo< >+ std::vector<absl::string_view>>::value, >+ ""); >+ static_assert(absl::strings_internal::SplitterIsConvertibleTo< >+ std::map<std::string, std::string>>::value, >+ ""); >+ static_assert(absl::strings_internal::SplitterIsConvertibleTo< >+ std::map<absl::string_view, absl::string_view>>::value, >+ ""); >+ static_assert(!absl::strings_internal::SplitterIsConvertibleTo< >+ std::map<int, std::string>>::value, >+ ""); >+ static_assert(!absl::strings_internal::SplitterIsConvertibleTo< >+ std::map<std::string, int>>::value, >+ ""); >+} >+ >+// This tests the overall split API, which is made up of the absl::StrSplit() >+// function and the Delimiter objects in the absl:: namespace. >+// This TEST macro is outside of any namespace to require full specification of >+// namespaces just like callers will need to use. >+TEST(Split, APIExamples) { >+ { >+ // Passes std::string delimiter. Assumes the default of Literal. >+ std::vector<std::string> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ >+ // Equivalent to... >+ using absl::ByString; >+ v = absl::StrSplit("a,b,c", ByString(",")); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ >+ // Equivalent to... >+ EXPECT_THAT(absl::StrSplit("a,b,c", ByString(",")), >+ ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Same as above, but using a single character as the delimiter. >+ std::vector<std::string> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ >+ // Equivalent to... >+ using absl::ByChar; >+ v = absl::StrSplit("a,b,c", ByChar(',')); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Same as above, but using std::string >+ std::vector<std::string> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ >+ // Equivalent to... >+ using absl::ByChar; >+ v = absl::StrSplit("a,b,c", ByChar(',')); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Uses the Literal std::string "=>" as the delimiter. >+ const std::vector<std::string> v = absl::StrSplit("a=>b=>c", "=>"); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // The substrings are returned as string_views, eliminating copying. >+ std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Leading and trailing empty substrings. >+ std::vector<std::string> v = absl::StrSplit(",a,b,c,", ','); >+ EXPECT_THAT(v, ElementsAre("", "a", "b", "c", "")); >+ } >+ >+ { >+ // Splits on a delimiter that is not found. >+ std::vector<std::string> v = absl::StrSplit("abc", ','); >+ EXPECT_THAT(v, ElementsAre("abc")); >+ } >+ >+ { >+ // Splits the input std::string into individual characters by using an empty >+ // std::string as the delimiter. >+ std::vector<std::string> v = absl::StrSplit("abc", ""); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Splits std::string data with embedded NUL characters, using NUL as the >+ // delimiter. A simple delimiter of "\0" doesn't work because strlen() will >+ // say that's the empty std::string when constructing the absl::string_view >+ // delimiter. Instead, a non-empty std::string containing NUL can be used as the >+ // delimiter. >+ std::string embedded_nulls("a\0b\0c", 5); >+ std::string null_delim("\0", 1); >+ std::vector<std::string> v = absl::StrSplit(embedded_nulls, null_delim); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Stores first two split strings as the members in a std::pair. >+ std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ','); >+ EXPECT_EQ("a", p.first); >+ EXPECT_EQ("b", p.second); >+ // "c" is omitted because std::pair can hold only two elements. >+ } >+ >+ { >+ // Results stored in std::set<std::string> >+ std::set<std::string> v = absl::StrSplit("a,b,c,a,b,c,a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Uses a non-const char* delimiter. >+ char a[] = ","; >+ char* d = a + 0; >+ std::vector<std::string> v = absl::StrSplit("a,b,c", d); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Results split using either of , or ; >+ using absl::ByAnyChar; >+ std::vector<std::string> v = absl::StrSplit("a,b;c", ByAnyChar(",;")); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Uses the SkipWhitespace predicate. >+ using absl::SkipWhitespace; >+ std::vector<std::string> v = absl::StrSplit(" a , ,,b,", ',', SkipWhitespace()); >+ EXPECT_THAT(v, ElementsAre(" a ", "b")); >+ } >+ >+ { >+ // Uses the ByLength delimiter. >+ using absl::ByLength; >+ std::vector<std::string> v = absl::StrSplit("abcdefg", ByLength(3)); >+ EXPECT_THAT(v, ElementsAre("abc", "def", "g")); >+ } >+ >+ { >+ // Different forms of initialization / conversion. >+ std::vector<std::string> v1 = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v1, ElementsAre("a", "b", "c")); >+ std::vector<std::string> v2(absl::StrSplit("a,b,c", ',')); >+ EXPECT_THAT(v2, ElementsAre("a", "b", "c")); >+ auto v3 = std::vector<std::string>(absl::StrSplit("a,b,c", ',')); >+ EXPECT_THAT(v3, ElementsAre("a", "b", "c")); >+ v3 = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v3, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Results stored in a std::map. >+ std::map<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ','); >+ EXPECT_EQ(2, m.size()); >+ EXPECT_EQ("3", m["a"]); >+ EXPECT_EQ("2", m["b"]); >+ } >+ >+ { >+ // Results stored in a std::multimap. >+ std::multimap<std::string, std::string> m = absl::StrSplit("a,1,b,2,a,3", ','); >+ EXPECT_EQ(3, m.size()); >+ auto it = m.find("a"); >+ EXPECT_EQ("1", it->second); >+ ++it; >+ EXPECT_EQ("3", it->second); >+ it = m.find("b"); >+ EXPECT_EQ("2", it->second); >+ } >+ >+ { >+ // Demonstrates use in a range-based for loop in C++11. >+ std::string s = "x,x,x,x,x,x,x"; >+ for (absl::string_view sp : absl::StrSplit(s, ',')) { >+ EXPECT_EQ("x", sp); >+ } >+ } >+ >+ { >+ // Demonstrates use with a Predicate in a range-based for loop. >+ using absl::SkipWhitespace; >+ std::string s = " ,x,,x,,x,x,x,,"; >+ for (absl::string_view sp : absl::StrSplit(s, ',', SkipWhitespace())) { >+ EXPECT_EQ("x", sp); >+ } >+ } >+ >+ { >+ // Demonstrates a "smart" split to std::map using two separate calls to >+ // absl::StrSplit. One call to split the records, and another call to split >+ // the keys and values. This also uses the Limit delimiter so that the >+ // std::string "a=b=c" will split to "a" -> "b=c". >+ std::map<std::string, std::string> m; >+ for (absl::string_view sp : absl::StrSplit("a=b=c,d=e,f=,g", ',')) { >+ m.insert(absl::StrSplit(sp, absl::MaxSplits('=', 1))); >+ } >+ EXPECT_EQ("b=c", m.find("a")->second); >+ EXPECT_EQ("e", m.find("d")->second); >+ EXPECT_EQ("", m.find("f")->second); >+ EXPECT_EQ("", m.find("g")->second); >+ } >+} >+ >+// >+// Tests for SplitIterator >+// >+ >+TEST(SplitIterator, Basics) { >+ auto splitter = absl::StrSplit("a,b", ','); >+ auto it = splitter.begin(); >+ auto end = splitter.end(); >+ >+ EXPECT_NE(it, end); >+ EXPECT_EQ("a", *it); // tests dereference >+ ++it; // tests preincrement >+ EXPECT_NE(it, end); >+ EXPECT_EQ("b", std::string(it->data(), it->size())); // tests dereference as ptr >+ it++; // tests postincrement >+ EXPECT_EQ(it, end); >+} >+ >+// Simple Predicate to skip a particular std::string. >+class Skip { >+ public: >+ explicit Skip(const std::string& s) : s_(s) {} >+ bool operator()(absl::string_view sp) { return sp != s_; } >+ >+ private: >+ std::string s_; >+}; >+ >+TEST(SplitIterator, Predicate) { >+ auto splitter = absl::StrSplit("a,b,c", ',', Skip("b")); >+ auto it = splitter.begin(); >+ auto end = splitter.end(); >+ >+ EXPECT_NE(it, end); >+ EXPECT_EQ("a", *it); // tests dereference >+ ++it; // tests preincrement -- "b" should be skipped here. >+ EXPECT_NE(it, end); >+ EXPECT_EQ("c", std::string(it->data(), it->size())); // tests dereference as ptr >+ it++; // tests postincrement >+ EXPECT_EQ(it, end); >+} >+ >+TEST(SplitIterator, EdgeCases) { >+ // Expected input and output, assuming a delimiter of ',' >+ struct { >+ std::string in; >+ std::vector<std::string> expect; >+ } specs[] = { >+ {"", {""}}, >+ {"foo", {"foo"}}, >+ {",", {"", ""}}, >+ {",foo", {"", "foo"}}, >+ {"foo,", {"foo", ""}}, >+ {",foo,", {"", "foo", ""}}, >+ {"foo,bar", {"foo", "bar"}}, >+ }; >+ >+ for (const auto& spec : specs) { >+ SCOPED_TRACE(spec.in); >+ auto splitter = absl::StrSplit(spec.in, ','); >+ auto it = splitter.begin(); >+ auto end = splitter.end(); >+ for (const auto& expected : spec.expect) { >+ EXPECT_NE(it, end); >+ EXPECT_EQ(expected, *it++); >+ } >+ EXPECT_EQ(it, end); >+ } >+} >+ >+TEST(Splitter, Const) { >+ const auto splitter = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(splitter, ElementsAre("a", "b", "c")); >+} >+ >+TEST(Split, EmptyAndNull) { >+ // Attention: Splitting a null absl::string_view is different than splitting >+ // an empty absl::string_view even though both string_views are considered >+ // equal. This behavior is likely surprising and undesirable. However, to >+ // maintain backward compatibility, there is a small "hack" in >+ // str_split_internal.h that preserves this behavior. If that behavior is ever >+ // changed/fixed, this test will need to be updated. >+ EXPECT_THAT(absl::StrSplit(absl::string_view(""), '-'), ElementsAre("")); >+ EXPECT_THAT(absl::StrSplit(absl::string_view(), '-'), ElementsAre()); >+} >+ >+TEST(SplitIterator, EqualityAsEndCondition) { >+ auto splitter = absl::StrSplit("a,b,c", ','); >+ auto it = splitter.begin(); >+ auto it2 = it; >+ >+ // Increments it2 twice to point to "c" in the input text. >+ ++it2; >+ ++it2; >+ EXPECT_EQ("c", *it2); >+ >+ // This test uses a non-end SplitIterator as the terminating condition in a >+ // for loop. This relies on SplitIterator equality for non-end SplitIterators >+ // working correctly. At this point it2 points to "c", and we use that as the >+ // "end" condition in this test. >+ std::vector<absl::string_view> v; >+ for (; it != it2; ++it) { >+ v.push_back(*it); >+ } >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+} >+ >+// >+// Tests for Splitter >+// >+ >+TEST(Splitter, RangeIterators) { >+ auto splitter = absl::StrSplit("a,b,c", ','); >+ std::vector<absl::string_view> output; >+ for (const absl::string_view p : splitter) { >+ output.push_back(p); >+ } >+ EXPECT_THAT(output, ElementsAre("a", "b", "c")); >+} >+ >+// Some template functions for use in testing conversion operators >+template <typename ContainerType, typename Splitter> >+void TestConversionOperator(const Splitter& splitter) { >+ ContainerType output = splitter; >+ EXPECT_THAT(output, UnorderedElementsAre("a", "b", "c", "d")); >+} >+ >+template <typename MapType, typename Splitter> >+void TestMapConversionOperator(const Splitter& splitter) { >+ MapType m = splitter; >+ EXPECT_THAT(m, UnorderedElementsAre(Pair("a", "b"), Pair("c", "d"))); >+} >+ >+template <typename FirstType, typename SecondType, typename Splitter> >+void TestPairConversionOperator(const Splitter& splitter) { >+ std::pair<FirstType, SecondType> p = splitter; >+ EXPECT_EQ(p, (std::pair<FirstType, SecondType>("a", "b"))); >+} >+ >+TEST(Splitter, ConversionOperator) { >+ auto splitter = absl::StrSplit("a,b,c,d", ','); >+ >+ TestConversionOperator<std::vector<absl::string_view>>(splitter); >+ TestConversionOperator<std::vector<std::string>>(splitter); >+ TestConversionOperator<std::list<absl::string_view>>(splitter); >+ TestConversionOperator<std::list<std::string>>(splitter); >+ TestConversionOperator<std::deque<absl::string_view>>(splitter); >+ TestConversionOperator<std::deque<std::string>>(splitter); >+ TestConversionOperator<std::set<absl::string_view>>(splitter); >+ TestConversionOperator<std::set<std::string>>(splitter); >+ TestConversionOperator<std::multiset<absl::string_view>>(splitter); >+ TestConversionOperator<std::multiset<std::string>>(splitter); >+ TestConversionOperator<std::unordered_set<std::string>>(splitter); >+ >+ // Tests conversion to map-like objects. >+ >+ TestMapConversionOperator<std::map<absl::string_view, absl::string_view>>( >+ splitter); >+ TestMapConversionOperator<std::map<absl::string_view, std::string>>(splitter); >+ TestMapConversionOperator<std::map<std::string, absl::string_view>>(splitter); >+ TestMapConversionOperator<std::map<std::string, std::string>>(splitter); >+ TestMapConversionOperator< >+ std::multimap<absl::string_view, absl::string_view>>(splitter); >+ TestMapConversionOperator<std::multimap<absl::string_view, std::string>>(splitter); >+ TestMapConversionOperator<std::multimap<std::string, absl::string_view>>(splitter); >+ TestMapConversionOperator<std::multimap<std::string, std::string>>(splitter); >+ TestMapConversionOperator<std::unordered_map<std::string, std::string>>(splitter); >+ >+ // Tests conversion to std::pair >+ >+ TestPairConversionOperator<absl::string_view, absl::string_view>(splitter); >+ TestPairConversionOperator<absl::string_view, std::string>(splitter); >+ TestPairConversionOperator<std::string, absl::string_view>(splitter); >+ TestPairConversionOperator<std::string, std::string>(splitter); >+} >+ >+// A few additional tests for conversion to std::pair. This conversion is >+// different from others because a std::pair always has exactly two elements: >+// .first and .second. The split has to work even when the split has >+// less-than, equal-to, and more-than 2 strings. >+TEST(Splitter, ToPair) { >+ { >+ // Empty std::string >+ std::pair<std::string, std::string> p = absl::StrSplit("", ','); >+ EXPECT_EQ("", p.first); >+ EXPECT_EQ("", p.second); >+ } >+ >+ { >+ // Only first >+ std::pair<std::string, std::string> p = absl::StrSplit("a", ','); >+ EXPECT_EQ("a", p.first); >+ EXPECT_EQ("", p.second); >+ } >+ >+ { >+ // Only second >+ std::pair<std::string, std::string> p = absl::StrSplit(",b", ','); >+ EXPECT_EQ("", p.first); >+ EXPECT_EQ("b", p.second); >+ } >+ >+ { >+ // First and second. >+ std::pair<std::string, std::string> p = absl::StrSplit("a,b", ','); >+ EXPECT_EQ("a", p.first); >+ EXPECT_EQ("b", p.second); >+ } >+ >+ { >+ // First and second and then more stuff that will be ignored. >+ std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ','); >+ EXPECT_EQ("a", p.first); >+ EXPECT_EQ("b", p.second); >+ // "c" is omitted. >+ } >+} >+ >+TEST(Splitter, Predicates) { >+ static const char kTestChars[] = ",a, ,b,"; >+ using absl::AllowEmpty; >+ using absl::SkipEmpty; >+ using absl::SkipWhitespace; >+ >+ { >+ // No predicate. Does not skip empties. >+ auto splitter = absl::StrSplit(kTestChars, ','); >+ std::vector<std::string> v = splitter; >+ EXPECT_THAT(v, ElementsAre("", "a", " ", "b", "")); >+ } >+ >+ { >+ // Allows empty strings. Same behavior as no predicate at all. >+ auto splitter = absl::StrSplit(kTestChars, ',', AllowEmpty()); >+ std::vector<std::string> v_allowempty = splitter; >+ EXPECT_THAT(v_allowempty, ElementsAre("", "a", " ", "b", "")); >+ >+ // Ensures AllowEmpty equals the behavior with no predicate. >+ auto splitter_nopredicate = absl::StrSplit(kTestChars, ','); >+ std::vector<std::string> v_nopredicate = splitter_nopredicate; >+ EXPECT_EQ(v_allowempty, v_nopredicate); >+ } >+ >+ { >+ // Skips empty strings. >+ auto splitter = absl::StrSplit(kTestChars, ',', SkipEmpty()); >+ std::vector<std::string> v = splitter; >+ EXPECT_THAT(v, ElementsAre("a", " ", "b")); >+ } >+ >+ { >+ // Skips empty and all-whitespace strings. >+ auto splitter = absl::StrSplit(kTestChars, ',', SkipWhitespace()); >+ std::vector<std::string> v = splitter; >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+} >+ >+// >+// Tests for StrSplit() >+// >+ >+TEST(Split, Basics) { >+ { >+ // Doesn't really do anything useful because the return value is ignored, >+ // but it should work. >+ absl::StrSplit("a,b,c", ','); >+ } >+ >+ { >+ std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ std::vector<std::string> v = absl::StrSplit("a,b,c", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ } >+ >+ { >+ // Ensures that assignment works. This requires a little extra work with >+ // C++11 because of overloads with initializer_list. >+ std::vector<std::string> v; >+ v = absl::StrSplit("a,b,c", ','); >+ >+ EXPECT_THAT(v, ElementsAre("a", "b", "c")); >+ std::map<std::string, std::string> m; >+ m = absl::StrSplit("a,b,c", ','); >+ EXPECT_EQ(2, m.size()); >+ std::unordered_map<std::string, std::string> hm; >+ hm = absl::StrSplit("a,b,c", ','); >+ EXPECT_EQ(2, hm.size()); >+ } >+} >+ >+absl::string_view ReturnStringView() { return "Hello World"; } >+const char* ReturnConstCharP() { return "Hello World"; } >+char* ReturnCharP() { return const_cast<char*>("Hello World"); } >+ >+TEST(Split, AcceptsCertainTemporaries) { >+ std::vector<std::string> v; >+ v = absl::StrSplit(ReturnStringView(), ' '); >+ EXPECT_THAT(v, ElementsAre("Hello", "World")); >+ v = absl::StrSplit(ReturnConstCharP(), ' '); >+ EXPECT_THAT(v, ElementsAre("Hello", "World")); >+ v = absl::StrSplit(ReturnCharP(), ' '); >+ EXPECT_THAT(v, ElementsAre("Hello", "World")); >+} >+ >+TEST(Split, Temporary) { >+ // Use a std::string longer than the small-std::string-optimization length, so that when >+ // the temporary is destroyed, if the splitter keeps a reference to the >+ // std::string's contents, it'll reference freed memory instead of just dead >+ // on-stack memory. >+ const char input[] = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u"; >+ EXPECT_LT(sizeof(std::string), ABSL_ARRAYSIZE(input)) >+ << "Input should be larger than fits on the stack."; >+ >+ // This happens more often in C++11 as part of a range-based for loop. >+ auto splitter = absl::StrSplit(std::string(input), ','); >+ std::string expected = "a"; >+ for (absl::string_view letter : splitter) { >+ EXPECT_EQ(expected, letter); >+ ++expected[0]; >+ } >+ EXPECT_EQ("v", expected); >+ >+ // This happens more often in C++11 as part of a range-based for loop. >+ auto std_splitter = absl::StrSplit(std::string(input), ','); >+ expected = "a"; >+ for (absl::string_view letter : std_splitter) { >+ EXPECT_EQ(expected, letter); >+ ++expected[0]; >+ } >+ EXPECT_EQ("v", expected); >+} >+ >+template <typename T> >+static std::unique_ptr<T> CopyToHeap(const T& value) { >+ return std::unique_ptr<T>(new T(value)); >+} >+ >+TEST(Split, LvalueCaptureIsCopyable) { >+ std::string input = "a,b"; >+ auto heap_splitter = CopyToHeap(absl::StrSplit(input, ',')); >+ auto stack_splitter = *heap_splitter; >+ heap_splitter.reset(); >+ std::vector<std::string> result = stack_splitter; >+ EXPECT_THAT(result, testing::ElementsAre("a", "b")); >+} >+ >+TEST(Split, TemporaryCaptureIsCopyable) { >+ auto heap_splitter = CopyToHeap(absl::StrSplit(std::string("a,b"), ',')); >+ auto stack_splitter = *heap_splitter; >+ heap_splitter.reset(); >+ std::vector<std::string> result = stack_splitter; >+ EXPECT_THAT(result, testing::ElementsAre("a", "b")); >+} >+ >+TEST(Split, SplitterIsCopyableAndMoveable) { >+ auto a = absl::StrSplit("foo", '-'); >+ >+ // Ensures that the following expressions compile. >+ auto b = a; // Copy construct >+ auto c = std::move(a); // Move construct >+ b = c; // Copy assign >+ c = std::move(b); // Move assign >+ >+ EXPECT_THAT(c, ElementsAre("foo")); >+} >+ >+TEST(Split, StringDelimiter) { >+ { >+ std::vector<absl::string_view> v = absl::StrSplit("a,b", ','); >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+ >+ { >+ std::vector<absl::string_view> v = absl::StrSplit("a,b", std::string(",")); >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+ >+ { >+ std::vector<absl::string_view> v = >+ absl::StrSplit("a,b", absl::string_view(",")); >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+} >+ >+TEST(Split, UTF8) { >+ // Tests splitting utf8 strings and utf8 delimiters. >+ std::string utf8_string = u8"\u03BA\u1F79\u03C3\u03BC\u03B5"; >+ { >+ // A utf8 input std::string with an ascii delimiter. >+ std::string to_split = "a," + utf8_string; >+ std::vector<absl::string_view> v = absl::StrSplit(to_split, ','); >+ EXPECT_THAT(v, ElementsAre("a", utf8_string)); >+ } >+ >+ { >+ // A utf8 input std::string and a utf8 delimiter. >+ std::string to_split = "a," + utf8_string + ",b"; >+ std::string unicode_delimiter = "," + utf8_string + ","; >+ std::vector<absl::string_view> v = >+ absl::StrSplit(to_split, unicode_delimiter); >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+ >+ { >+ // A utf8 input std::string and ByAnyChar with ascii chars. >+ std::vector<absl::string_view> v = >+ absl::StrSplit(u8"Foo h\u00E4llo th\u4E1Ere", absl::ByAnyChar(" \t")); >+ EXPECT_THAT(v, ElementsAre("Foo", u8"h\u00E4llo", u8"th\u4E1Ere")); >+ } >+} >+ >+TEST(Split, EmptyStringDelimiter) { >+ { >+ std::vector<std::string> v = absl::StrSplit("", ""); >+ EXPECT_THAT(v, ElementsAre("")); >+ } >+ >+ { >+ std::vector<std::string> v = absl::StrSplit("a", ""); >+ EXPECT_THAT(v, ElementsAre("a")); >+ } >+ >+ { >+ std::vector<std::string> v = absl::StrSplit("ab", ""); >+ EXPECT_THAT(v, ElementsAre("a", "b")); >+ } >+ >+ { >+ std::vector<std::string> v = absl::StrSplit("a b", ""); >+ EXPECT_THAT(v, ElementsAre("a", " ", "b")); >+ } >+} >+ >+TEST(Split, SubstrDelimiter) { >+ std::vector<absl::string_view> results; >+ absl::string_view delim("//"); >+ >+ results = absl::StrSplit("", delim); >+ EXPECT_THAT(results, ElementsAre("")); >+ >+ results = absl::StrSplit("//", delim); >+ EXPECT_THAT(results, ElementsAre("", "")); >+ >+ results = absl::StrSplit("ab", delim); >+ EXPECT_THAT(results, ElementsAre("ab")); >+ >+ results = absl::StrSplit("ab//", delim); >+ EXPECT_THAT(results, ElementsAre("ab", "")); >+ >+ results = absl::StrSplit("ab/", delim); >+ EXPECT_THAT(results, ElementsAre("ab/")); >+ >+ results = absl::StrSplit("a/b", delim); >+ EXPECT_THAT(results, ElementsAre("a/b")); >+ >+ results = absl::StrSplit("a//b", delim); >+ EXPECT_THAT(results, ElementsAre("a", "b")); >+ >+ results = absl::StrSplit("a///b", delim); >+ EXPECT_THAT(results, ElementsAre("a", "/b")); >+ >+ results = absl::StrSplit("a////b", delim); >+ EXPECT_THAT(results, ElementsAre("a", "", "b")); >+} >+ >+TEST(Split, EmptyResults) { >+ std::vector<absl::string_view> results; >+ >+ results = absl::StrSplit("", '#'); >+ EXPECT_THAT(results, ElementsAre("")); >+ >+ results = absl::StrSplit("#", '#'); >+ EXPECT_THAT(results, ElementsAre("", "")); >+ >+ results = absl::StrSplit("#cd", '#'); >+ EXPECT_THAT(results, ElementsAre("", "cd")); >+ >+ results = absl::StrSplit("ab#cd#", '#'); >+ EXPECT_THAT(results, ElementsAre("ab", "cd", "")); >+ >+ results = absl::StrSplit("ab##cd", '#'); >+ EXPECT_THAT(results, ElementsAre("ab", "", "cd")); >+ >+ results = absl::StrSplit("ab##", '#'); >+ EXPECT_THAT(results, ElementsAre("ab", "", "")); >+ >+ results = absl::StrSplit("ab#ab#", '#'); >+ EXPECT_THAT(results, ElementsAre("ab", "ab", "")); >+ >+ results = absl::StrSplit("aaaa", 'a'); >+ EXPECT_THAT(results, ElementsAre("", "", "", "", "")); >+ >+ results = absl::StrSplit("", '#', absl::SkipEmpty()); >+ EXPECT_THAT(results, ElementsAre()); >+} >+ >+template <typename Delimiter> >+static bool IsFoundAtStartingPos(absl::string_view text, Delimiter d, >+ size_t starting_pos, int expected_pos) { >+ absl::string_view found = d.Find(text, starting_pos); >+ return found.data() != text.end() && >+ expected_pos == found.data() - text.data(); >+} >+ >+// Helper function for testing Delimiter objects. Returns true if the given >+// Delimiter is found in the given std::string at the given position. This function >+// tests two cases: >+// 1. The actual text given, staring at position 0 >+// 2. The text given with leading padding that should be ignored >+template <typename Delimiter> >+static bool IsFoundAt(absl::string_view text, Delimiter d, int expected_pos) { >+ const std::string leading_text = ",x,y,z,"; >+ return IsFoundAtStartingPos(text, d, 0, expected_pos) && >+ IsFoundAtStartingPos(leading_text + std::string(text), d, >+ leading_text.length(), >+ expected_pos + leading_text.length()); >+} >+ >+// >+// Tests for Literal >+// >+ >+// Tests using any delimiter that represents a single comma. >+template <typename Delimiter> >+void TestComma(Delimiter d) { >+ EXPECT_TRUE(IsFoundAt(",", d, 0)); >+ EXPECT_TRUE(IsFoundAt("a,", d, 1)); >+ EXPECT_TRUE(IsFoundAt(",b", d, 0)); >+ EXPECT_TRUE(IsFoundAt("a,b", d, 1)); >+ EXPECT_TRUE(IsFoundAt("a,b,", d, 1)); >+ EXPECT_TRUE(IsFoundAt("a,b,c", d, 1)); >+ EXPECT_FALSE(IsFoundAt("", d, -1)); >+ EXPECT_FALSE(IsFoundAt(" ", d, -1)); >+ EXPECT_FALSE(IsFoundAt("a", d, -1)); >+ EXPECT_FALSE(IsFoundAt("a b c", d, -1)); >+ EXPECT_FALSE(IsFoundAt("a;b;c", d, -1)); >+ EXPECT_FALSE(IsFoundAt(";", d, -1)); >+} >+ >+TEST(Delimiter, Literal) { >+ using absl::ByString; >+ TestComma(ByString(",")); >+ >+ // Works as named variable. >+ ByString comma_string(","); >+ TestComma(comma_string); >+ >+ // The first occurrence of empty std::string ("") in a std::string is at position 0. >+ // There is a test below that demonstrates this for absl::string_view::find(). >+ // If the ByString delimiter returned position 0 for this, there would >+ // be an infinite loop in the SplitIterator code. To avoid this, empty std::string >+ // is a special case in that it always returns the item at position 1. >+ absl::string_view abc("abc"); >+ EXPECT_EQ(0, abc.find("")); // "" is found at position 0 >+ ByString empty(""); >+ EXPECT_FALSE(IsFoundAt("", empty, 0)); >+ EXPECT_FALSE(IsFoundAt("a", empty, 0)); >+ EXPECT_TRUE(IsFoundAt("ab", empty, 1)); >+ EXPECT_TRUE(IsFoundAt("abc", empty, 1)); >+} >+ >+TEST(Split, ByChar) { >+ using absl::ByChar; >+ TestComma(ByChar(',')); >+ >+ // Works as named variable. >+ ByChar comma_char(','); >+ TestComma(comma_char); >+} >+ >+// >+// Tests for ByAnyChar >+// >+ >+TEST(Delimiter, ByAnyChar) { >+ using absl::ByAnyChar; >+ ByAnyChar one_delim(","); >+ // Found >+ EXPECT_TRUE(IsFoundAt(",", one_delim, 0)); >+ EXPECT_TRUE(IsFoundAt("a,", one_delim, 1)); >+ EXPECT_TRUE(IsFoundAt("a,b", one_delim, 1)); >+ EXPECT_TRUE(IsFoundAt(",b", one_delim, 0)); >+ // Not found >+ EXPECT_FALSE(IsFoundAt("", one_delim, -1)); >+ EXPECT_FALSE(IsFoundAt(" ", one_delim, -1)); >+ EXPECT_FALSE(IsFoundAt("a", one_delim, -1)); >+ EXPECT_FALSE(IsFoundAt("a;b;c", one_delim, -1)); >+ EXPECT_FALSE(IsFoundAt(";", one_delim, -1)); >+ >+ ByAnyChar two_delims(",;"); >+ // Found >+ EXPECT_TRUE(IsFoundAt(",", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt(";", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt(",;", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt(";,", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt(",;b", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt(";,b", two_delims, 0)); >+ EXPECT_TRUE(IsFoundAt("a;,", two_delims, 1)); >+ EXPECT_TRUE(IsFoundAt("a,;", two_delims, 1)); >+ EXPECT_TRUE(IsFoundAt("a;,b", two_delims, 1)); >+ EXPECT_TRUE(IsFoundAt("a,;b", two_delims, 1)); >+ // Not found >+ EXPECT_FALSE(IsFoundAt("", two_delims, -1)); >+ EXPECT_FALSE(IsFoundAt(" ", two_delims, -1)); >+ EXPECT_FALSE(IsFoundAt("a", two_delims, -1)); >+ EXPECT_FALSE(IsFoundAt("a=b=c", two_delims, -1)); >+ EXPECT_FALSE(IsFoundAt("=", two_delims, -1)); >+ >+ // ByAnyChar behaves just like ByString when given a delimiter of empty >+ // std::string. That is, it always returns a zero-length absl::string_view >+ // referring to the item at position 1, not position 0. >+ ByAnyChar empty(""); >+ EXPECT_FALSE(IsFoundAt("", empty, 0)); >+ EXPECT_FALSE(IsFoundAt("a", empty, 0)); >+ EXPECT_TRUE(IsFoundAt("ab", empty, 1)); >+ EXPECT_TRUE(IsFoundAt("abc", empty, 1)); >+} >+ >+// >+// Tests for ByLength >+// >+ >+TEST(Delimiter, ByLength) { >+ using absl::ByLength; >+ >+ ByLength four_char_delim(4); >+ >+ // Found >+ EXPECT_TRUE(IsFoundAt("abcde", four_char_delim, 4)); >+ EXPECT_TRUE(IsFoundAt("abcdefghijklmnopqrstuvwxyz", four_char_delim, 4)); >+ EXPECT_TRUE(IsFoundAt("a b,c\nd", four_char_delim, 4)); >+ // Not found >+ EXPECT_FALSE(IsFoundAt("", four_char_delim, 0)); >+ EXPECT_FALSE(IsFoundAt("a", four_char_delim, 0)); >+ EXPECT_FALSE(IsFoundAt("ab", four_char_delim, 0)); >+ EXPECT_FALSE(IsFoundAt("abc", four_char_delim, 0)); >+ EXPECT_FALSE(IsFoundAt("abcd", four_char_delim, 0)); >+} >+ >+TEST(Split, WorksWithLargeStrings) { >+ if (sizeof(size_t) > 4) { >+ std::string s((uint32_t{1} << 31) + 1, 'x'); // 2G + 1 byte >+ s.back() = '-'; >+ std::vector<absl::string_view> v = absl::StrSplit(s, '-'); >+ EXPECT_EQ(2, v.size()); >+ // The first element will contain 2G of 'x's. >+ // testing::StartsWith is too slow with a 2G std::string. >+ EXPECT_EQ('x', v[0][0]); >+ EXPECT_EQ('x', v[0][1]); >+ EXPECT_EQ('x', v[0][3]); >+ EXPECT_EQ("", v[1]); >+ } >+} >+ >+TEST(SplitInternalTest, TypeTraits) { >+ EXPECT_FALSE(absl::strings_internal::HasMappedType<int>::value); >+ EXPECT_TRUE( >+ (absl::strings_internal::HasMappedType<std::map<int, int>>::value)); >+ EXPECT_FALSE(absl::strings_internal::HasValueType<int>::value); >+ EXPECT_TRUE( >+ (absl::strings_internal::HasValueType<std::map<int, int>>::value)); >+ EXPECT_FALSE(absl::strings_internal::HasConstIterator<int>::value); >+ EXPECT_TRUE( >+ (absl::strings_internal::HasConstIterator<std::map<int, int>>::value)); >+ EXPECT_FALSE(absl::strings_internal::IsInitializerList<int>::value); >+ EXPECT_TRUE((absl::strings_internal::IsInitializerList< >+ std::initializer_list<int>>::value)); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.cc >new file mode 100644 >index 00000000000..4ceeb6bff58 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.cc >@@ -0,0 +1,245 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/string_view.h" >+ >+#ifndef ABSL_HAVE_STD_STRING_VIEW >+ >+#include <algorithm> >+#include <climits> >+#include <cstring> >+#include <ostream> >+ >+#include "absl/strings/internal/memutil.h" >+ >+namespace absl { >+ >+namespace { >+void WritePadding(std::ostream& o, size_t pad) { >+ char fill_buf[32]; >+ memset(fill_buf, o.fill(), sizeof(fill_buf)); >+ while (pad) { >+ size_t n = std::min(pad, sizeof(fill_buf)); >+ o.write(fill_buf, n); >+ pad -= n; >+ } >+} >+ >+class LookupTable { >+ public: >+ // For each character in wanted, sets the index corresponding >+ // to the ASCII code of that character. This is used by >+ // the find_.*_of methods below to tell whether or not a character is in >+ // the lookup table in constant time. >+ explicit LookupTable(string_view wanted) { >+ for (char c : wanted) { >+ table_[Index(c)] = true; >+ } >+ } >+ bool operator[](char c) const { return table_[Index(c)]; } >+ >+ private: >+ static unsigned char Index(char c) { return static_cast<unsigned char>(c); } >+ bool table_[UCHAR_MAX + 1] = {}; >+}; >+ >+} // namespace >+ >+std::ostream& operator<<(std::ostream& o, string_view piece) { >+ std::ostream::sentry sentry(o); >+ if (sentry) { >+ size_t lpad = 0; >+ size_t rpad = 0; >+ if (static_cast<size_t>(o.width()) > piece.size()) { >+ size_t pad = o.width() - piece.size(); >+ if ((o.flags() & o.adjustfield) == o.left) { >+ rpad = pad; >+ } else { >+ lpad = pad; >+ } >+ } >+ if (lpad) WritePadding(o, lpad); >+ o.write(piece.data(), piece.size()); >+ if (rpad) WritePadding(o, rpad); >+ o.width(0); >+ } >+ return o; >+} >+ >+string_view::size_type string_view::copy(char* buf, size_type n, >+ size_type pos) const { >+ size_type ulen = length_; >+ assert(pos <= ulen); >+ size_type rlen = std::min(ulen - pos, n); >+ if (rlen > 0) { >+ const char* start = ptr_ + pos; >+ std::copy(start, start + rlen, buf); >+ } >+ return rlen; >+} >+ >+string_view::size_type string_view::find(string_view s, size_type pos) const >+ noexcept { >+ if (empty() || pos > length_) { >+ if (empty() && pos == 0 && s.empty()) return 0; >+ return npos; >+ } >+ const char* result = >+ strings_internal::memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_); >+ return result ? result - ptr_ : npos; >+} >+ >+string_view::size_type string_view::find(char c, size_type pos) const noexcept { >+ if (empty() || pos >= length_) { >+ return npos; >+ } >+ const char* result = >+ static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos)); >+ return result != nullptr ? result - ptr_ : npos; >+} >+ >+string_view::size_type string_view::rfind(string_view s, size_type pos) const >+ noexcept { >+ if (length_ < s.length_) return npos; >+ if (s.empty()) return std::min(length_, pos); >+ const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_; >+ const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); >+ return result != last ? result - ptr_ : npos; >+} >+ >+// Search range is [0..pos] inclusive. If pos == npos, search everything. >+string_view::size_type string_view::rfind(char c, size_type pos) const >+ noexcept { >+ // Note: memrchr() is not available on Windows. >+ if (empty()) return npos; >+ for (size_type i = std::min(pos, length_ - 1);; --i) { >+ if (ptr_[i] == c) { >+ return i; >+ } >+ if (i == 0) break; >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_first_of(string_view s, >+ size_type pos) const >+ noexcept { >+ if (empty() || s.empty()) { >+ return npos; >+ } >+ // Avoid the cost of LookupTable() for a single-character search. >+ if (s.length_ == 1) return find_first_of(s.ptr_[0], pos); >+ LookupTable tbl(s); >+ for (size_type i = pos; i < length_; ++i) { >+ if (tbl[ptr_[i]]) { >+ return i; >+ } >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_first_not_of(string_view s, >+ size_type pos) const >+ noexcept { >+ if (empty()) return npos; >+ // Avoid the cost of LookupTable() for a single-character search. >+ if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos); >+ LookupTable tbl(s); >+ for (size_type i = pos; i < length_; ++i) { >+ if (!tbl[ptr_[i]]) { >+ return i; >+ } >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_first_not_of(char c, >+ size_type pos) const >+ noexcept { >+ if (empty()) return npos; >+ for (; pos < length_; ++pos) { >+ if (ptr_[pos] != c) { >+ return pos; >+ } >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_last_of(string_view s, >+ size_type pos) const noexcept { >+ if (empty() || s.empty()) return npos; >+ // Avoid the cost of LookupTable() for a single-character search. >+ if (s.length_ == 1) return find_last_of(s.ptr_[0], pos); >+ LookupTable tbl(s); >+ for (size_type i = std::min(pos, length_ - 1);; --i) { >+ if (tbl[ptr_[i]]) { >+ return i; >+ } >+ if (i == 0) break; >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_last_not_of(string_view s, >+ size_type pos) const >+ noexcept { >+ if (empty()) return npos; >+ size_type i = std::min(pos, length_ - 1); >+ if (s.empty()) return i; >+ // Avoid the cost of LookupTable() for a single-character search. >+ if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos); >+ LookupTable tbl(s); >+ for (;; --i) { >+ if (!tbl[ptr_[i]]) { >+ return i; >+ } >+ if (i == 0) break; >+ } >+ return npos; >+} >+ >+string_view::size_type string_view::find_last_not_of(char c, >+ size_type pos) const >+ noexcept { >+ if (empty()) return npos; >+ size_type i = std::min(pos, length_ - 1); >+ for (;; --i) { >+ if (ptr_[i] != c) { >+ return i; >+ } >+ if (i == 0) break; >+ } >+ return npos; >+} >+ >+// MSVC has non-standard behavior that implicitly creates definitions for static >+// const members. These implicit definitions conflict with explicit out-of-class >+// member definitions that are required by the C++ standard, resulting in >+// LNK1169 "multiply defined" errors at link time. __declspec(selectany) asks >+// MSVC to choose only one definition for the symbol it decorates. See details >+// at http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx >+#ifdef _MSC_VER >+#define ABSL_STRING_VIEW_SELECTANY __declspec(selectany) >+#else >+#define ABSL_STRING_VIEW_SELECTANY >+#endif >+ >+ABSL_STRING_VIEW_SELECTANY >+constexpr string_view::size_type string_view::npos; >+ABSL_STRING_VIEW_SELECTANY >+constexpr string_view::size_type string_view::kMaxSize; >+ >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_STRING_VIEW >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.h >new file mode 100644 >index 00000000000..a7f9199240a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view.h >@@ -0,0 +1,570 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: string_view.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains the definition of the `absl::string_view` class. A >+// `string_view` points to a contiguous span of characters, often part or all of >+// another `std::string`, double-quoted std::string literal, character array, or even >+// another `string_view`. >+// >+// This `absl::string_view` abstraction is designed to be a drop-in >+// replacement for the C++17 `std::string_view` abstraction. >+#ifndef ABSL_STRINGS_STRING_VIEW_H_ >+#define ABSL_STRINGS_STRING_VIEW_H_ >+ >+#include <algorithm> >+#include "absl/base/config.h" >+ >+#ifdef ABSL_HAVE_STD_STRING_VIEW >+ >+#include <string_view> >+ >+namespace absl { >+using std::string_view; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_STRING_VIEW >+ >+#include <cassert> >+#include <cstddef> >+#include <cstring> >+#include <iosfwd> >+#include <iterator> >+#include <limits> >+#include <string> >+ >+#include "absl/base/internal/throw_delegate.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+ >+// absl::string_view >+// >+// A `string_view` provides a lightweight view into the std::string data provided by >+// a `std::string`, double-quoted std::string literal, character array, or even >+// another `string_view`. A `string_view` does *not* own the std::string to which it >+// points, and that data cannot be modified through the view. >+// >+// You can use `string_view` as a function or method parameter anywhere a >+// parameter can receive a double-quoted std::string literal, `const char*`, >+// `std::string`, or another `absl::string_view` argument with no need to copy >+// the std::string data. Systematic use of `string_view` within function arguments >+// reduces data copies and `strlen()` calls. >+// >+// Because of its small size, prefer passing `string_view` by value: >+// >+// void MyFunction(absl::string_view arg); >+// >+// If circumstances require, you may also pass one by const reference: >+// >+// void MyFunction(const absl::string_view& arg); // not preferred >+// >+// Passing by value generates slightly smaller code for many architectures. >+// >+// In either case, the source data of the `string_view` must outlive the >+// `string_view` itself. >+// >+// A `string_view` is also suitable for local variables if you know that the >+// lifetime of the underlying object is longer than the lifetime of your >+// `string_view` variable. However, beware of binding a `string_view` to a >+// temporary value: >+// >+// // BAD use of string_view: lifetime problem >+// absl::string_view sv = obj.ReturnAString(); >+// >+// // GOOD use of string_view: str outlives sv >+// std::string str = obj.ReturnAString(); >+// absl::string_view sv = str; >+// >+// Due to lifetime issues, a `string_view` is sometimes a poor choice for a >+// return value and usually a poor choice for a data member. If you do use a >+// `string_view` this way, it is your responsibility to ensure that the object >+// pointed to by the `string_view` outlives the `string_view`. >+// >+// A `string_view` may represent a whole std::string or just part of a std::string. For >+// example, when splitting a std::string, `std::vector<absl::string_view>` is a >+// natural data type for the output. >+// >+// >+// When constructed from a source which is nul-terminated, the `string_view` >+// itself will not include the nul-terminator unless a specific size (including >+// the nul) is passed to the constructor. As a result, common idioms that work >+// on nul-terminated strings do not work on `string_view` objects. If you write >+// code that scans a `string_view`, you must check its length rather than test >+// for nul, for example. Note, however, that nuls may still be embedded within >+// a `string_view` explicitly. >+// >+// You may create a null `string_view` in two ways: >+// >+// absl::string_view sv(); >+// absl::string_view sv(nullptr, 0); >+// >+// For the above, `sv.data() == nullptr`, `sv.length() == 0`, and >+// `sv.empty() == true`. Also, if you create a `string_view` with a non-null >+// pointer then `sv.data() != nullptr`. Thus, you can use `string_view()` to >+// signal an undefined value that is different from other `string_view` values >+// in a similar fashion to how `const char* p1 = nullptr;` is different from >+// `const char* p2 = "";`. However, in practice, it is not recommended to rely >+// on this behavior. >+// >+// Be careful not to confuse a null `string_view` with an empty one. A null >+// `string_view` is an empty `string_view`, but some empty `string_view`s are >+// not null. Prefer checking for emptiness over checking for null. >+// >+// There are many ways to create an empty string_view: >+// >+// const char* nullcp = nullptr; >+// // string_view.size() will return 0 in all cases. >+// absl::string_view(); >+// absl::string_view(nullcp, 0); >+// absl::string_view(""); >+// absl::string_view("", 0); >+// absl::string_view("abcdef", 0); >+// absl::string_view("abcdef" + 6, 0); >+// >+// All empty `string_view` objects whether null or not, are equal: >+// >+// absl::string_view() == absl::string_view("", 0) >+// absl::string_view(nullptr, 0) == absl:: string_view("abcdef"+6, 0) >+class string_view { >+ public: >+ using traits_type = std::char_traits<char>; >+ using value_type = char; >+ using pointer = char*; >+ using const_pointer = const char*; >+ using reference = char&; >+ using const_reference = const char&; >+ using const_iterator = const char*; >+ using iterator = const_iterator; >+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; >+ using reverse_iterator = const_reverse_iterator; >+ using size_type = size_t; >+ using difference_type = std::ptrdiff_t; >+ >+ static constexpr size_type npos = static_cast<size_type>(-1); >+ >+ // Null `string_view` constructor >+ constexpr string_view() noexcept : ptr_(nullptr), length_(0) {} >+ >+ // Implicit constructors >+ >+ template <typename Allocator> >+ string_view( // NOLINT(runtime/explicit) >+ const std::basic_string<char, std::char_traits<char>, Allocator>& >+ str) noexcept >+ : ptr_(str.data()), length_(CheckLengthInternal(str.size())) {} >+ >+ // Implicit constructor of a `string_view` from nul-terminated `str`. When >+ // accepting possibly null strings, use `absl::NullSafeStringView(str)` >+ // instead (see below). >+ constexpr string_view(const char* str) // NOLINT(runtime/explicit) >+ : ptr_(str), length_(CheckLengthInternal(StrLenInternal(str))) {} >+ >+ // Implicit constructor of a `string_view` from a `const char*` and length. >+ constexpr string_view(const char* data, size_type len) >+ : ptr_(data), length_(CheckLengthInternal(len)) {} >+ >+ // NOTE: Harmlessly omitted to work around gdb bug. >+ // constexpr string_view(const string_view&) noexcept = default; >+ // string_view& operator=(const string_view&) noexcept = default; >+ >+ // Iterators >+ >+ // string_view::begin() >+ // >+ // Returns an iterator pointing to the first character at the beginning of the >+ // `string_view`, or `end()` if the `string_view` is empty. >+ constexpr const_iterator begin() const noexcept { return ptr_; } >+ >+ // string_view::end() >+ // >+ // Returns an iterator pointing just beyond the last character at the end of >+ // the `string_view`. This iterator acts as a placeholder; attempting to >+ // access it results in undefined behavior. >+ constexpr const_iterator end() const noexcept { return ptr_ + length_; } >+ >+ // string_view::cbegin() >+ // >+ // Returns a const iterator pointing to the first character at the beginning >+ // of the `string_view`, or `end()` if the `string_view` is empty. >+ constexpr const_iterator cbegin() const noexcept { return begin(); } >+ >+ // string_view::cend() >+ // >+ // Returns a const iterator pointing just beyond the last character at the end >+ // of the `string_view`. This pointer acts as a placeholder; attempting to >+ // access its element results in undefined behavior. >+ constexpr const_iterator cend() const noexcept { return end(); } >+ >+ // string_view::rbegin() >+ // >+ // Returns a reverse iterator pointing to the last character at the end of the >+ // `string_view`, or `rend()` if the `string_view` is empty. >+ const_reverse_iterator rbegin() const noexcept { >+ return const_reverse_iterator(end()); >+ } >+ >+ // string_view::rend() >+ // >+ // Returns a reverse iterator pointing just before the first character at the >+ // beginning of the `string_view`. This pointer acts as a placeholder; >+ // attempting to access its element results in undefined behavior. >+ const_reverse_iterator rend() const noexcept { >+ return const_reverse_iterator(begin()); >+ } >+ >+ // string_view::crbegin() >+ // >+ // Returns a const reverse iterator pointing to the last character at the end >+ // of the `string_view`, or `crend()` if the `string_view` is empty. >+ const_reverse_iterator crbegin() const noexcept { return rbegin(); } >+ >+ // string_view::crend() >+ // >+ // Returns a const reverse iterator pointing just before the first character >+ // at the beginning of the `string_view`. This pointer acts as a placeholder; >+ // attempting to access its element results in undefined behavior. >+ const_reverse_iterator crend() const noexcept { return rend(); } >+ >+ // Capacity Utilities >+ >+ // string_view::size() >+ // >+ // Returns the number of characters in the `string_view`. >+ constexpr size_type size() const noexcept { >+ return length_; >+ } >+ >+ // string_view::length() >+ // >+ // Returns the number of characters in the `string_view`. Alias for `size()`. >+ constexpr size_type length() const noexcept { return size(); } >+ >+ // string_view::max_size() >+ // >+ // Returns the maximum number of characters the `string_view` can hold. >+ constexpr size_type max_size() const noexcept { return kMaxSize; } >+ >+ // string_view::empty() >+ // >+ // Checks if the `string_view` is empty (refers to no characters). >+ constexpr bool empty() const noexcept { return length_ == 0; } >+ >+ // std::string:view::operator[] >+ // >+ // Returns the ith element of an `string_view` using the array operator. >+ // Note that this operator does not perform any bounds checking. >+ constexpr const_reference operator[](size_type i) const { return ptr_[i]; } >+ >+ // string_view::front() >+ // >+ // Returns the first element of a `string_view`. >+ constexpr const_reference front() const { return ptr_[0]; } >+ >+ // string_view::back() >+ // >+ // Returns the last element of a `string_view`. >+ constexpr const_reference back() const { return ptr_[size() - 1]; } >+ >+ // string_view::data() >+ // >+ // Returns a pointer to the underlying character array (which is of course >+ // stored elsewhere). Note that `string_view::data()` may contain embedded nul >+ // characters, but the returned buffer may or may not be nul-terminated; >+ // therefore, do not pass `data()` to a routine that expects a nul-terminated >+ // std::string. >+ constexpr const_pointer data() const noexcept { return ptr_; } >+ >+ // Modifiers >+ >+ // string_view::remove_prefix() >+ // >+ // Removes the first `n` characters from the `string_view`. Note that the >+ // underlying std::string is not changed, only the view. >+ void remove_prefix(size_type n) { >+ assert(n <= length_); >+ ptr_ += n; >+ length_ -= n; >+ } >+ >+ // string_view::remove_suffix() >+ // >+ // Removes the last `n` characters from the `string_view`. Note that the >+ // underlying std::string is not changed, only the view. >+ void remove_suffix(size_type n) { >+ assert(n <= length_); >+ length_ -= n; >+ } >+ >+ // string_view::swap() >+ // >+ // Swaps this `string_view` with another `string_view`. >+ void swap(string_view& s) noexcept { >+ auto t = *this; >+ *this = s; >+ s = t; >+ } >+ >+ // Explicit conversion operators >+ >+ // Converts to `std::basic_string`. >+ template <typename A> >+ explicit operator std::basic_string<char, traits_type, A>() const { >+ if (!data()) return {}; >+ return std::basic_string<char, traits_type, A>(data(), size()); >+ } >+ >+ // string_view::copy() >+ // >+ // Copies the contents of the `string_view` at offset `pos` and length `n` >+ // into `buf`. >+ size_type copy(char* buf, size_type n, size_type pos = 0) const; >+ >+ // string_view::substr() >+ // >+ // Returns a "substring" of the `string_view` (at offset `pos` and length >+ // `n`) as another string_view. This function throws `std::out_of_bounds` if >+ // `pos > size'. >+ string_view substr(size_type pos, size_type n = npos) const { >+ if (ABSL_PREDICT_FALSE(pos > length_)) >+ base_internal::ThrowStdOutOfRange("absl::string_view::substr"); >+ n = std::min(n, length_ - pos); >+ return string_view(ptr_ + pos, n); >+ } >+ >+ // string_view::compare() >+ // >+ // Performs a lexicographical comparison between the `string_view` and >+ // another `absl::string_view), returning -1 if `this` is less than, 0 if >+ // `this` is equal to, and 1 if `this` is greater than the passed std::string >+ // view. Note that in the case of data equality, a further comparison is made >+ // on the respective sizes of the two `string_view`s to determine which is >+ // smaller, equal, or greater. >+ int compare(string_view x) const noexcept { >+ auto min_length = std::min(length_, x.length_); >+ if (min_length > 0) { >+ int r = memcmp(ptr_, x.ptr_, min_length); >+ if (r < 0) return -1; >+ if (r > 0) return 1; >+ } >+ if (length_ < x.length_) return -1; >+ if (length_ > x.length_) return 1; >+ return 0; >+ } >+ >+ // Overload of `string_view::compare()` for comparing a substring of the >+ // 'string_view` and another `absl::string_view`. >+ int compare(size_type pos1, size_type count1, string_view v) const { >+ return substr(pos1, count1).compare(v); >+ } >+ >+ // Overload of `string_view::compare()` for comparing a substring of the >+ // `string_view` and a substring of another `absl::string_view`. >+ int compare(size_type pos1, size_type count1, string_view v, size_type pos2, >+ size_type count2) const { >+ return substr(pos1, count1).compare(v.substr(pos2, count2)); >+ } >+ >+ // Overload of `string_view::compare()` for comparing a `string_view` and a >+ // a different C-style std::string `s`. >+ int compare(const char* s) const { return compare(string_view(s)); } >+ >+ // Overload of `string_view::compare()` for comparing a substring of the >+ // `string_view` and a different std::string C-style std::string `s`. >+ int compare(size_type pos1, size_type count1, const char* s) const { >+ return substr(pos1, count1).compare(string_view(s)); >+ } >+ >+ // Overload of `string_view::compare()` for comparing a substring of the >+ // `string_view` and a substring of a different C-style std::string `s`. >+ int compare(size_type pos1, size_type count1, const char* s, >+ size_type count2) const { >+ return substr(pos1, count1).compare(string_view(s, count2)); >+ } >+ >+ // Find Utilities >+ >+ // string_view::find() >+ // >+ // Finds the first occurrence of the substring `s` within the `string_view`, >+ // returning the position of the first character's match, or `npos` if no >+ // match was found. >+ size_type find(string_view s, size_type pos = 0) const noexcept; >+ >+ // Overload of `string_view::find()` for finding the given character `c` >+ // within the `string_view`. >+ size_type find(char c, size_type pos = 0) const noexcept; >+ >+ // string_view::rfind() >+ // >+ // Finds the last occurrence of a substring `s` within the `string_view`, >+ // returning the position of the first character's match, or `npos` if no >+ // match was found. >+ size_type rfind(string_view s, size_type pos = npos) const >+ noexcept; >+ >+ // Overload of `string_view::rfind()` for finding the last given character `c` >+ // within the `string_view`. >+ size_type rfind(char c, size_type pos = npos) const noexcept; >+ >+ // string_view::find_first_of() >+ // >+ // Finds the first occurrence of any of the characters in `s` within the >+ // `string_view`, returning the start position of the match, or `npos` if no >+ // match was found. >+ size_type find_first_of(string_view s, size_type pos = 0) const >+ noexcept; >+ >+ // Overload of `string_view::find_first_of()` for finding a character `c` >+ // within the `string_view`. >+ size_type find_first_of(char c, size_type pos = 0) const >+ noexcept { >+ return find(c, pos); >+ } >+ >+ // string_view::find_last_of() >+ // >+ // Finds the last occurrence of any of the characters in `s` within the >+ // `string_view`, returning the start position of the match, or `npos` if no >+ // match was found. >+ size_type find_last_of(string_view s, size_type pos = npos) const >+ noexcept; >+ >+ // Overload of `string_view::find_last_of()` for finding a character `c` >+ // within the `string_view`. >+ size_type find_last_of(char c, size_type pos = npos) const >+ noexcept { >+ return rfind(c, pos); >+ } >+ >+ // string_view::find_first_not_of() >+ // >+ // Finds the first occurrence of any of the characters not in `s` within the >+ // `string_view`, returning the start position of the first non-match, or >+ // `npos` if no non-match was found. >+ size_type find_first_not_of(string_view s, size_type pos = 0) const noexcept; >+ >+ // Overload of `string_view::find_first_not_of()` for finding a character >+ // that is not `c` within the `string_view`. >+ size_type find_first_not_of(char c, size_type pos = 0) const noexcept; >+ >+ // string_view::find_last_not_of() >+ // >+ // Finds the last occurrence of any of the characters not in `s` within the >+ // `string_view`, returning the start position of the last non-match, or >+ // `npos` if no non-match was found. >+ size_type find_last_not_of(string_view s, >+ size_type pos = npos) const noexcept; >+ >+ // Overload of `string_view::find_last_not_of()` for finding a character >+ // that is not `c` within the `string_view`. >+ size_type find_last_not_of(char c, size_type pos = npos) const >+ noexcept; >+ >+ private: >+ static constexpr size_type kMaxSize = >+ std::numeric_limits<difference_type>::max(); >+ >+ // check whether __builtin_strlen is provided by the compiler. >+ // GCC doesn't have __has_builtin() >+ // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970), >+ // but has __builtin_strlen according to >+ // https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Other-Builtins.html. >+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+ static constexpr size_type StrLenInternal(const char* str) { >+ return str ? __builtin_strlen(str) : 0; >+ } >+#else >+ static constexpr size_type StrLenInternal(const char* str) { >+ return str ? strlen(str) : 0; >+ } >+#endif >+ >+ static constexpr size_type CheckLengthInternal(size_type len) { >+ return ABSL_ASSERT(len <= kMaxSize), len; >+ } >+ >+ const char* ptr_; >+ size_type length_; >+}; >+ >+// This large function is defined inline so that in a fairly common case where >+// one of the arguments is a literal, the compiler can elide a lot of the >+// following comparisons. >+inline bool operator==(string_view x, string_view y) noexcept { >+ auto len = x.size(); >+ if (len != y.size()) { >+ return false; >+ } >+ return x.data() == y.data() || len <= 0 || >+ memcmp(x.data(), y.data(), len) == 0; >+} >+ >+inline bool operator!=(string_view x, string_view y) noexcept { >+ return !(x == y); >+} >+ >+inline bool operator<(string_view x, string_view y) noexcept { >+ auto min_size = std::min(x.size(), y.size()); >+ const int r = min_size == 0 ? 0 : memcmp(x.data(), y.data(), min_size); >+ return (r < 0) || (r == 0 && x.size() < y.size()); >+} >+ >+inline bool operator>(string_view x, string_view y) noexcept { return y < x; } >+ >+inline bool operator<=(string_view x, string_view y) noexcept { >+ return !(y < x); >+} >+ >+inline bool operator>=(string_view x, string_view y) noexcept { >+ return !(x < y); >+} >+ >+// IO Insertion Operator >+std::ostream& operator<<(std::ostream& o, string_view piece); >+ >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_STRING_VIEW >+ >+namespace absl { >+ >+// ClippedSubstr() >+// >+// Like `s.substr(pos, n)`, but clips `pos` to an upper bound of `s.size()`. >+// Provided because std::string_view::substr throws if `pos > size()` >+inline string_view ClippedSubstr(string_view s, size_t pos, >+ size_t n = string_view::npos) { >+ pos = std::min(pos, static_cast<size_t>(s.size())); >+ return s.substr(pos, n); >+} >+ >+// NullSafeStringView() >+// >+// Creates an `absl::string_view` from a pointer `p` even if it's null-valued. >+// This function should be used where an `absl::string_view` can be created from >+// a possibly-null pointer. >+inline string_view NullSafeStringView(const char* p) { >+ return p ? string_view(p) : string_view(); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STRING_VIEW_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_benchmark.cc >new file mode 100644 >index 00000000000..fb46db18b3c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_benchmark.cc >@@ -0,0 +1,329 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/string_view.h" >+ >+#include <algorithm> >+#include <cstdint> >+#include <map> >+#include <random> >+#include <string> >+#include <unordered_set> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/macros.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+// Provide a forcibly out-of-line wrapper for operator== that can be used in >+// benchmarks to measure the impact of inlining. >+ABSL_ATTRIBUTE_NOINLINE >+bool NonInlinedEq(absl::string_view a, absl::string_view b) { return a == b; } >+ >+// We use functions that cannot be inlined to perform the comparison loops so >+// that inlining of the operator== can't optimize away *everything*. >+ABSL_ATTRIBUTE_NOINLINE >+void DoEqualityComparisons(benchmark::State& state, absl::string_view a, >+ absl::string_view b) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(a == b); >+ } >+} >+ >+void BM_EqualIdentical(benchmark::State& state) { >+ std::string x(state.range(0), 'a'); >+ DoEqualityComparisons(state, x, x); >+} >+BENCHMARK(BM_EqualIdentical)->DenseRange(0, 3)->Range(4, 1 << 10); >+ >+void BM_EqualSame(benchmark::State& state) { >+ std::string x(state.range(0), 'a'); >+ std::string y = x; >+ DoEqualityComparisons(state, x, y); >+} >+BENCHMARK(BM_EqualSame) >+ ->DenseRange(0, 10) >+ ->Arg(20) >+ ->Arg(40) >+ ->Arg(70) >+ ->Arg(110) >+ ->Range(160, 4096); >+ >+void BM_EqualDifferent(benchmark::State& state) { >+ const int len = state.range(0); >+ std::string x(len, 'a'); >+ std::string y = x; >+ if (len > 0) { >+ y[len - 1] = 'b'; >+ } >+ DoEqualityComparisons(state, x, y); >+} >+BENCHMARK(BM_EqualDifferent)->DenseRange(0, 3)->Range(4, 1 << 10); >+ >+// This benchmark is intended to check that important simplifications can be >+// made with absl::string_view comparisons against constant strings. The idea is >+// that if constant strings cause redundant components of the comparison, the >+// compiler should detect and eliminate them. Here we use 8 different strings, >+// each with the same size. Provided our comparison makes the implementation >+// inline-able by the compiler, it should fold all of these away into a single >+// size check once per loop iteration. >+ABSL_ATTRIBUTE_NOINLINE >+void DoConstantSizeInlinedEqualityComparisons(benchmark::State& state, >+ absl::string_view a) { >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(a == "aaa"); >+ benchmark::DoNotOptimize(a == "bbb"); >+ benchmark::DoNotOptimize(a == "ccc"); >+ benchmark::DoNotOptimize(a == "ddd"); >+ benchmark::DoNotOptimize(a == "eee"); >+ benchmark::DoNotOptimize(a == "fff"); >+ benchmark::DoNotOptimize(a == "ggg"); >+ benchmark::DoNotOptimize(a == "hhh"); >+ } >+} >+void BM_EqualConstantSizeInlined(benchmark::State& state) { >+ std::string x(state.range(0), 'a'); >+ DoConstantSizeInlinedEqualityComparisons(state, x); >+} >+// We only need to check for size of 3, and <> 3 as this benchmark only has to >+// do with size differences. >+BENCHMARK(BM_EqualConstantSizeInlined)->DenseRange(2, 4); >+ >+// This benchmark exists purely to give context to the above timings: this is >+// what they would look like if the compiler is completely unable to simplify >+// between two comparisons when they are comparing against constant strings. >+ABSL_ATTRIBUTE_NOINLINE >+void DoConstantSizeNonInlinedEqualityComparisons(benchmark::State& state, >+ absl::string_view a) { >+ for (auto _ : state) { >+ // Force these out-of-line to compare with the above function. >+ benchmark::DoNotOptimize(NonInlinedEq(a, "aaa")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "bbb")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "ccc")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "ddd")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "eee")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "fff")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "ggg")); >+ benchmark::DoNotOptimize(NonInlinedEq(a, "hhh")); >+ } >+} >+ >+void BM_EqualConstantSizeNonInlined(benchmark::State& state) { >+ std::string x(state.range(0), 'a'); >+ DoConstantSizeNonInlinedEqualityComparisons(state, x); >+} >+// We only need to check for size of 3, and <> 3 as this benchmark only has to >+// do with size differences. >+BENCHMARK(BM_EqualConstantSizeNonInlined)->DenseRange(2, 4); >+ >+void BM_CompareSame(benchmark::State& state) { >+ const int len = state.range(0); >+ std::string x; >+ for (int i = 0; i < len; i++) { >+ x += 'a'; >+ } >+ std::string y = x; >+ absl::string_view a = x; >+ absl::string_view b = y; >+ >+ for (auto _ : state) { >+ benchmark::DoNotOptimize(a.compare(b)); >+ } >+} >+BENCHMARK(BM_CompareSame)->DenseRange(0, 3)->Range(4, 1 << 10); >+ >+void BM_find_string_view_len_one(benchmark::State& state) { >+ std::string haystack(state.range(0), '0'); >+ absl::string_view s(haystack); >+ for (auto _ : state) { >+ s.find("x"); // not present; length 1 >+ } >+} >+BENCHMARK(BM_find_string_view_len_one)->Range(1, 1 << 20); >+ >+void BM_find_string_view_len_two(benchmark::State& state) { >+ std::string haystack(state.range(0), '0'); >+ absl::string_view s(haystack); >+ for (auto _ : state) { >+ s.find("xx"); // not present; length 2 >+ } >+} >+BENCHMARK(BM_find_string_view_len_two)->Range(1, 1 << 20); >+ >+void BM_find_one_char(benchmark::State& state) { >+ std::string haystack(state.range(0), '0'); >+ absl::string_view s(haystack); >+ for (auto _ : state) { >+ s.find('x'); // not present >+ } >+} >+BENCHMARK(BM_find_one_char)->Range(1, 1 << 20); >+ >+void BM_rfind_one_char(benchmark::State& state) { >+ std::string haystack(state.range(0), '0'); >+ absl::string_view s(haystack); >+ for (auto _ : state) { >+ s.rfind('x'); // not present >+ } >+} >+BENCHMARK(BM_rfind_one_char)->Range(1, 1 << 20); >+ >+void BM_worst_case_find_first_of(benchmark::State& state, int haystack_len) { >+ const int needle_len = state.range(0); >+ std::string needle; >+ for (int i = 0; i < needle_len; ++i) { >+ needle += 'a' + i; >+ } >+ std::string haystack(haystack_len, '0'); // 1000 zeros. >+ >+ absl::string_view s(haystack); >+ for (auto _ : state) { >+ s.find_first_of(needle); >+ } >+} >+ >+void BM_find_first_of_short(benchmark::State& state) { >+ BM_worst_case_find_first_of(state, 10); >+} >+ >+void BM_find_first_of_medium(benchmark::State& state) { >+ BM_worst_case_find_first_of(state, 100); >+} >+ >+void BM_find_first_of_long(benchmark::State& state) { >+ BM_worst_case_find_first_of(state, 1000); >+} >+ >+BENCHMARK(BM_find_first_of_short)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); >+BENCHMARK(BM_find_first_of_medium)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); >+BENCHMARK(BM_find_first_of_long)->DenseRange(0, 4)->Arg(8)->Arg(16)->Arg(32); >+ >+struct EasyMap : public std::map<absl::string_view, uint64_t> { >+ explicit EasyMap(size_t) {} >+}; >+ >+// This templated benchmark helper function is intended to stress operator== or >+// operator< in a realistic test. It surely isn't entirely realistic, but it's >+// a start. The test creates a map of type Map, a template arg, and populates >+// it with table_size key/value pairs. Each key has WordsPerKey words. After >+// creating the map, a number of lookups are done in random order. Some keys >+// are used much more frequently than others in this phase of the test. >+template <typename Map, int WordsPerKey> >+void StringViewMapBenchmark(benchmark::State& state) { >+ const int table_size = state.range(0); >+ const double kFractionOfKeysThatAreHot = 0.2; >+ const int kNumLookupsOfHotKeys = 20; >+ const int kNumLookupsOfColdKeys = 1; >+ const char* words[] = {"the", "quick", "brown", "fox", "jumped", >+ "over", "the", "lazy", "dog", "and", >+ "found", "a", "large", "mushroom", "and", >+ "a", "couple", "crickets", "eating", "pie"}; >+ // Create some keys that consist of words in random order. >+ std::random_device r; >+ std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()}); >+ std::mt19937 rng(seed); >+ std::vector<std::string> keys(table_size); >+ std::vector<int> all_indices; >+ const int kBlockSize = 1 << 12; >+ std::unordered_set<std::string> t(kBlockSize); >+ std::uniform_int_distribution<int> uniform(0, ABSL_ARRAYSIZE(words) - 1); >+ for (int i = 0; i < table_size; i++) { >+ all_indices.push_back(i); >+ do { >+ keys[i].clear(); >+ for (int j = 0; j < WordsPerKey; j++) { >+ absl::StrAppend(&keys[i], j > 0 ? " " : "", words[uniform(rng)]); >+ } >+ } while (!t.insert(keys[i]).second); >+ } >+ >+ // Create a list of strings to lookup: a permutation of the array of >+ // keys we just created, with repeats. "Hot" keys get repeated more. >+ std::shuffle(all_indices.begin(), all_indices.end(), rng); >+ const int num_hot = table_size * kFractionOfKeysThatAreHot; >+ const int num_cold = table_size - num_hot; >+ std::vector<int> hot_indices(all_indices.begin(), >+ all_indices.begin() + num_hot); >+ std::vector<int> indices; >+ for (int i = 0; i < kNumLookupsOfColdKeys; i++) { >+ indices.insert(indices.end(), all_indices.begin(), all_indices.end()); >+ } >+ for (int i = 0; i < kNumLookupsOfHotKeys - kNumLookupsOfColdKeys; i++) { >+ indices.insert(indices.end(), hot_indices.begin(), hot_indices.end()); >+ } >+ std::shuffle(indices.begin(), indices.end(), rng); >+ ABSL_RAW_CHECK( >+ num_cold * kNumLookupsOfColdKeys + num_hot * kNumLookupsOfHotKeys == >+ indices.size(), >+ ""); >+ // After constructing the array we probe it with absl::string_views built from >+ // test_strings. This means operator== won't see equal pointers, so >+ // it'll have to check for equal lengths and equal characters. >+ std::vector<std::string> test_strings(indices.size()); >+ for (int i = 0; i < indices.size(); i++) { >+ test_strings[i] = keys[indices[i]]; >+ } >+ >+ // Run the benchmark. It includes map construction but is mostly >+ // map lookups. >+ for (auto _ : state) { >+ Map h(table_size); >+ for (int i = 0; i < table_size; i++) { >+ h[keys[i]] = i * 2; >+ } >+ ABSL_RAW_CHECK(h.size() == table_size, ""); >+ uint64_t sum = 0; >+ for (int i = 0; i < indices.size(); i++) { >+ sum += h[test_strings[i]]; >+ } >+ benchmark::DoNotOptimize(sum); >+ } >+} >+ >+void BM_StdMap_4(benchmark::State& state) { >+ StringViewMapBenchmark<EasyMap, 4>(state); >+} >+BENCHMARK(BM_StdMap_4)->Range(1 << 10, 1 << 16); >+ >+void BM_StdMap_8(benchmark::State& state) { >+ StringViewMapBenchmark<EasyMap, 8>(state); >+} >+BENCHMARK(BM_StdMap_8)->Range(1 << 10, 1 << 16); >+ >+void BM_CopyToStringNative(benchmark::State& state) { >+ std::string src(state.range(0), 'x'); >+ absl::string_view sv(src); >+ std::string dst; >+ for (auto _ : state) { >+ dst.assign(sv.begin(), sv.end()); >+ } >+} >+BENCHMARK(BM_CopyToStringNative)->Range(1 << 3, 1 << 12); >+ >+void BM_AppendToStringNative(benchmark::State& state) { >+ std::string src(state.range(0), 'x'); >+ absl::string_view sv(src); >+ std::string dst; >+ for (auto _ : state) { >+ dst.clear(); >+ dst.insert(dst.end(), sv.begin(), sv.end()); >+ } >+} >+BENCHMARK(BM_AppendToStringNative)->Range(1 << 3, 1 << 12); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_test.cc >new file mode 100644 >index 00000000000..b19d07c7fd6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/string_view_test.cc >@@ -0,0 +1,1146 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/string_view.h" >+ >+#include <stdlib.h> >+#include <iomanip> >+#include <iterator> >+#include <limits> >+#include <map> >+#include <sstream> >+#include <stdexcept> >+#include <string> >+#include <type_traits> >+#include <utility> >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+#include "absl/base/dynamic_annotations.h" >+ >+#ifdef __ANDROID__ >+// Android assert messages only go to system log, so death tests cannot inspect >+// the message for matching. >+#define ABSL_EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ >+ EXPECT_DEATH_IF_SUPPORTED(statement, ".*") >+#else >+#define ABSL_EXPECT_DEATH_IF_SUPPORTED EXPECT_DEATH_IF_SUPPORTED >+#endif >+ >+namespace { >+ >+// A minimal allocator that uses malloc(). >+template <typename T> >+struct Mallocator { >+ typedef T value_type; >+ typedef size_t size_type; >+ typedef ptrdiff_t difference_type; >+ typedef T* pointer; >+ typedef const T* const_pointer; >+ typedef T& reference; >+ typedef const T& const_reference; >+ >+ size_type max_size() const { >+ return size_t(std::numeric_limits<size_type>::max()) / sizeof(value_type); >+ } >+ template <typename U> >+ struct rebind { >+ typedef Mallocator<U> other; >+ }; >+ Mallocator() = default; >+ template <class U> >+ Mallocator(const Mallocator<U>&) {} // NOLINT(runtime/explicit) >+ >+ T* allocate(size_t n) { return static_cast<T*>(std::malloc(n * sizeof(T))); } >+ void deallocate(T* p, size_t) { std::free(p); } >+}; >+template <typename T, typename U> >+bool operator==(const Mallocator<T>&, const Mallocator<U>&) { >+ return true; >+} >+template <typename T, typename U> >+bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { >+ return false; >+} >+ >+TEST(StringViewTest, Ctor) { >+ { >+ // Null. >+ absl::string_view s10; >+ EXPECT_TRUE(s10.data() == nullptr); >+ EXPECT_EQ(0, s10.length()); >+ } >+ >+ { >+ // const char* without length. >+ const char* hello = "hello"; >+ absl::string_view s20(hello); >+ EXPECT_TRUE(s20.data() == hello); >+ EXPECT_EQ(5, s20.length()); >+ >+ // const char* with length. >+ absl::string_view s21(hello, 4); >+ EXPECT_TRUE(s21.data() == hello); >+ EXPECT_EQ(4, s21.length()); >+ >+ // Not recommended, but valid C++ >+ absl::string_view s22(hello, 6); >+ EXPECT_TRUE(s22.data() == hello); >+ EXPECT_EQ(6, s22.length()); >+ } >+ >+ { >+ // std::string. >+ std::string hola = "hola"; >+ absl::string_view s30(hola); >+ EXPECT_TRUE(s30.data() == hola.data()); >+ EXPECT_EQ(4, s30.length()); >+ >+ // std::string with embedded '\0'. >+ hola.push_back('\0'); >+ hola.append("h2"); >+ hola.push_back('\0'); >+ absl::string_view s31(hola); >+ EXPECT_TRUE(s31.data() == hola.data()); >+ EXPECT_EQ(8, s31.length()); >+ } >+ >+ { >+ using mstring = >+ std::basic_string<char, std::char_traits<char>, Mallocator<char>>; >+ mstring str1("BUNGIE-JUMPING!"); >+ const mstring str2("SLEEPING!"); >+ >+ absl::string_view s1(str1); >+ s1.remove_prefix(strlen("BUNGIE-JUM")); >+ >+ absl::string_view s2(str2); >+ s2.remove_prefix(strlen("SLEE")); >+ >+ EXPECT_EQ(s1, s2); >+ EXPECT_EQ(s1, "PING!"); >+ } >+ >+ // TODO(mec): absl::string_view(const absl::string_view&); >+} >+ >+TEST(StringViewTest, Swap) { >+ absl::string_view a("a"); >+ absl::string_view b("bbb"); >+ EXPECT_TRUE(noexcept(a.swap(b))); >+ a.swap(b); >+ EXPECT_EQ(a, "bbb"); >+ EXPECT_EQ(b, "a"); >+ a.swap(b); >+ EXPECT_EQ(a, "a"); >+ EXPECT_EQ(b, "bbb"); >+} >+ >+TEST(StringViewTest, STLComparator) { >+ std::string s1("foo"); >+ std::string s2("bar"); >+ std::string s3("baz"); >+ >+ absl::string_view p1(s1); >+ absl::string_view p2(s2); >+ absl::string_view p3(s3); >+ >+ typedef std::map<absl::string_view, int> TestMap; >+ TestMap map; >+ >+ map.insert(std::make_pair(p1, 0)); >+ map.insert(std::make_pair(p2, 1)); >+ map.insert(std::make_pair(p3, 2)); >+ EXPECT_EQ(map.size(), 3); >+ >+ TestMap::const_iterator iter = map.begin(); >+ EXPECT_EQ(iter->second, 1); >+ ++iter; >+ EXPECT_EQ(iter->second, 2); >+ ++iter; >+ EXPECT_EQ(iter->second, 0); >+ ++iter; >+ EXPECT_TRUE(iter == map.end()); >+ >+ TestMap::iterator new_iter = map.find("zot"); >+ EXPECT_TRUE(new_iter == map.end()); >+ >+ new_iter = map.find("bar"); >+ EXPECT_TRUE(new_iter != map.end()); >+ >+ map.erase(new_iter); >+ EXPECT_EQ(map.size(), 2); >+ >+ iter = map.begin(); >+ EXPECT_EQ(iter->second, 2); >+ ++iter; >+ EXPECT_EQ(iter->second, 0); >+ ++iter; >+ EXPECT_TRUE(iter == map.end()); >+} >+ >+#define COMPARE(result, op, x, y) \ >+ EXPECT_EQ(result, absl::string_view((x)) op absl::string_view((y))); \ >+ EXPECT_EQ(result, absl::string_view((x)).compare(absl::string_view((y))) op 0) >+ >+TEST(StringViewTest, ComparisonOperators) { >+ COMPARE(true, ==, "", ""); >+ COMPARE(true, ==, "", absl::string_view()); >+ COMPARE(true, ==, absl::string_view(), ""); >+ COMPARE(true, ==, "a", "a"); >+ COMPARE(true, ==, "aa", "aa"); >+ COMPARE(false, ==, "a", ""); >+ COMPARE(false, ==, "", "a"); >+ COMPARE(false, ==, "a", "b"); >+ COMPARE(false, ==, "a", "aa"); >+ COMPARE(false, ==, "aa", "a"); >+ >+ COMPARE(false, !=, "", ""); >+ COMPARE(false, !=, "a", "a"); >+ COMPARE(false, !=, "aa", "aa"); >+ COMPARE(true, !=, "a", ""); >+ COMPARE(true, !=, "", "a"); >+ COMPARE(true, !=, "a", "b"); >+ COMPARE(true, !=, "a", "aa"); >+ COMPARE(true, !=, "aa", "a"); >+ >+ COMPARE(true, <, "a", "b"); >+ COMPARE(true, <, "a", "aa"); >+ COMPARE(true, <, "aa", "b"); >+ COMPARE(true, <, "aa", "bb"); >+ COMPARE(false, <, "a", "a"); >+ COMPARE(false, <, "b", "a"); >+ COMPARE(false, <, "aa", "a"); >+ COMPARE(false, <, "b", "aa"); >+ COMPARE(false, <, "bb", "aa"); >+ >+ COMPARE(true, <=, "a", "a"); >+ COMPARE(true, <=, "a", "b"); >+ COMPARE(true, <=, "a", "aa"); >+ COMPARE(true, <=, "aa", "b"); >+ COMPARE(true, <=, "aa", "bb"); >+ COMPARE(false, <=, "b", "a"); >+ COMPARE(false, <=, "aa", "a"); >+ COMPARE(false, <=, "b", "aa"); >+ COMPARE(false, <=, "bb", "aa"); >+ >+ COMPARE(false, >=, "a", "b"); >+ COMPARE(false, >=, "a", "aa"); >+ COMPARE(false, >=, "aa", "b"); >+ COMPARE(false, >=, "aa", "bb"); >+ COMPARE(true, >=, "a", "a"); >+ COMPARE(true, >=, "b", "a"); >+ COMPARE(true, >=, "aa", "a"); >+ COMPARE(true, >=, "b", "aa"); >+ COMPARE(true, >=, "bb", "aa"); >+ >+ COMPARE(false, >, "a", "a"); >+ COMPARE(false, >, "a", "b"); >+ COMPARE(false, >, "a", "aa"); >+ COMPARE(false, >, "aa", "b"); >+ COMPARE(false, >, "aa", "bb"); >+ COMPARE(true, >, "b", "a"); >+ COMPARE(true, >, "aa", "a"); >+ COMPARE(true, >, "b", "aa"); >+ COMPARE(true, >, "bb", "aa"); >+} >+ >+TEST(StringViewTest, ComparisonOperatorsByCharacterPosition) { >+ std::string x; >+ for (int i = 0; i < 256; i++) { >+ x += 'a'; >+ std::string y = x; >+ COMPARE(true, ==, x, y); >+ for (int j = 0; j < i; j++) { >+ std::string z = x; >+ z[j] = 'b'; // Differs in position 'j' >+ COMPARE(false, ==, x, z); >+ COMPARE(true, <, x, z); >+ COMPARE(true, >, z, x); >+ if (j + 1 < i) { >+ z[j + 1] = 'A'; // Differs in position 'j+1' as well >+ COMPARE(false, ==, x, z); >+ COMPARE(true, <, x, z); >+ COMPARE(true, >, z, x); >+ z[j + 1] = 'z'; // Differs in position 'j+1' as well >+ COMPARE(false, ==, x, z); >+ COMPARE(true, <, x, z); >+ COMPARE(true, >, z, x); >+ } >+ } >+ } >+} >+#undef COMPARE >+ >+// Sadly, our users often confuse std::string::npos with absl::string_view::npos; >+// So much so that we test here that they are the same. They need to >+// both be unsigned, and both be the maximum-valued integer of their type. >+ >+template <typename T> >+struct is_type { >+ template <typename U> >+ static bool same(U) { >+ return false; >+ } >+ static bool same(T) { return true; } >+}; >+ >+TEST(StringViewTest, NposMatchesStdStringView) { >+ EXPECT_EQ(absl::string_view::npos, std::string::npos); >+ >+ EXPECT_TRUE(is_type<size_t>::same(absl::string_view::npos)); >+ EXPECT_FALSE(is_type<size_t>::same("")); >+ >+ // Make sure absl::string_view::npos continues to be a header constant. >+ char test[absl::string_view::npos & 1] = {0}; >+ EXPECT_EQ(0, test[0]); >+} >+ >+TEST(StringViewTest, STL1) { >+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); >+ const absl::string_view b("abc"); >+ const absl::string_view c("xyz"); >+ const absl::string_view d("foobar"); >+ const absl::string_view e; >+ std::string temp("123"); >+ temp += '\0'; >+ temp += "456"; >+ const absl::string_view f(temp); >+ >+ EXPECT_EQ(a[6], 'g'); >+ EXPECT_EQ(b[0], 'a'); >+ EXPECT_EQ(c[2], 'z'); >+ EXPECT_EQ(f[3], '\0'); >+ EXPECT_EQ(f[5], '5'); >+ >+ EXPECT_EQ(*d.data(), 'f'); >+ EXPECT_EQ(d.data()[5], 'r'); >+ EXPECT_TRUE(e.data() == nullptr); >+ >+ EXPECT_EQ(*a.begin(), 'a'); >+ EXPECT_EQ(*(b.begin() + 2), 'c'); >+ EXPECT_EQ(*(c.end() - 1), 'z'); >+ >+ EXPECT_EQ(*a.rbegin(), 'z'); >+ EXPECT_EQ(*(b.rbegin() + 2), 'a'); >+ EXPECT_EQ(*(c.rend() - 1), 'x'); >+ EXPECT_TRUE(a.rbegin() + 26 == a.rend()); >+ >+ EXPECT_EQ(a.size(), 26); >+ EXPECT_EQ(b.size(), 3); >+ EXPECT_EQ(c.size(), 3); >+ EXPECT_EQ(d.size(), 6); >+ EXPECT_EQ(e.size(), 0); >+ EXPECT_EQ(f.size(), 7); >+ >+ EXPECT_TRUE(!d.empty()); >+ EXPECT_TRUE(d.begin() != d.end()); >+ EXPECT_TRUE(d.begin() + 6 == d.end()); >+ >+ EXPECT_TRUE(e.empty()); >+ EXPECT_TRUE(e.begin() == e.end()); >+ >+ char buf[4] = { '%', '%', '%', '%' }; >+ EXPECT_EQ(a.copy(buf, 4), 4); >+ EXPECT_EQ(buf[0], a[0]); >+ EXPECT_EQ(buf[1], a[1]); >+ EXPECT_EQ(buf[2], a[2]); >+ EXPECT_EQ(buf[3], a[3]); >+ EXPECT_EQ(a.copy(buf, 3, 7), 3); >+ EXPECT_EQ(buf[0], a[7]); >+ EXPECT_EQ(buf[1], a[8]); >+ EXPECT_EQ(buf[2], a[9]); >+ EXPECT_EQ(buf[3], a[3]); >+ EXPECT_EQ(c.copy(buf, 99), 3); >+ EXPECT_EQ(buf[0], c[0]); >+ EXPECT_EQ(buf[1], c[1]); >+ EXPECT_EQ(buf[2], c[2]); >+ EXPECT_EQ(buf[3], a[3]); >+} >+ >+// Separated from STL1() because some compilers produce an overly >+// large stack frame for the combined function. >+TEST(StringViewTest, STL2) { >+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); >+ const absl::string_view b("abc"); >+ const absl::string_view c("xyz"); >+ absl::string_view d("foobar"); >+ const absl::string_view e; >+ const absl::string_view f( >+ "123" >+ "\0" >+ "456", >+ 7); >+ >+ d = absl::string_view(); >+ EXPECT_EQ(d.size(), 0); >+ EXPECT_TRUE(d.empty()); >+ EXPECT_TRUE(d.data() == nullptr); >+ EXPECT_TRUE(d.begin() == d.end()); >+ >+ EXPECT_EQ(a.find(b), 0); >+ EXPECT_EQ(a.find(b, 1), absl::string_view::npos); >+ EXPECT_EQ(a.find(c), 23); >+ EXPECT_EQ(a.find(c, 9), 23); >+ EXPECT_EQ(a.find(c, absl::string_view::npos), absl::string_view::npos); >+ EXPECT_EQ(b.find(c), absl::string_view::npos); >+ EXPECT_EQ(b.find(c, absl::string_view::npos), absl::string_view::npos); >+ EXPECT_EQ(a.find(d), 0); >+ EXPECT_EQ(a.find(e), 0); >+ EXPECT_EQ(a.find(d, 12), 12); >+ EXPECT_EQ(a.find(e, 17), 17); >+ absl::string_view g("xx not found bb"); >+ EXPECT_EQ(a.find(g), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(d.find(b), absl::string_view::npos); >+ EXPECT_EQ(e.find(b), absl::string_view::npos); >+ EXPECT_EQ(d.find(b, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find(b, 7), absl::string_view::npos); >+ >+ size_t empty_search_pos = std::string().find(std::string()); >+ EXPECT_EQ(d.find(d), empty_search_pos); >+ EXPECT_EQ(d.find(e), empty_search_pos); >+ EXPECT_EQ(e.find(d), empty_search_pos); >+ EXPECT_EQ(e.find(e), empty_search_pos); >+ EXPECT_EQ(d.find(d, 4), std::string().find(std::string(), 4)); >+ EXPECT_EQ(d.find(e, 4), std::string().find(std::string(), 4)); >+ EXPECT_EQ(e.find(d, 4), std::string().find(std::string(), 4)); >+ EXPECT_EQ(e.find(e, 4), std::string().find(std::string(), 4)); >+ >+ EXPECT_EQ(a.find('a'), 0); >+ EXPECT_EQ(a.find('c'), 2); >+ EXPECT_EQ(a.find('z'), 25); >+ EXPECT_EQ(a.find('$'), absl::string_view::npos); >+ EXPECT_EQ(a.find('\0'), absl::string_view::npos); >+ EXPECT_EQ(f.find('\0'), 3); >+ EXPECT_EQ(f.find('3'), 2); >+ EXPECT_EQ(f.find('5'), 5); >+ EXPECT_EQ(g.find('o'), 4); >+ EXPECT_EQ(g.find('o', 4), 4); >+ EXPECT_EQ(g.find('o', 5), 8); >+ EXPECT_EQ(a.find('b', 5), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(d.find('\0'), absl::string_view::npos); >+ EXPECT_EQ(e.find('\0'), absl::string_view::npos); >+ EXPECT_EQ(d.find('\0', 4), absl::string_view::npos); >+ EXPECT_EQ(e.find('\0', 7), absl::string_view::npos); >+ EXPECT_EQ(d.find('x'), absl::string_view::npos); >+ EXPECT_EQ(e.find('x'), absl::string_view::npos); >+ EXPECT_EQ(d.find('x', 4), absl::string_view::npos); >+ EXPECT_EQ(e.find('x', 7), absl::string_view::npos); >+ >+ EXPECT_EQ(a.rfind(b), 0); >+ EXPECT_EQ(a.rfind(b, 1), 0); >+ EXPECT_EQ(a.rfind(c), 23); >+ EXPECT_EQ(a.rfind(c, 22), absl::string_view::npos); >+ EXPECT_EQ(a.rfind(c, 1), absl::string_view::npos); >+ EXPECT_EQ(a.rfind(c, 0), absl::string_view::npos); >+ EXPECT_EQ(b.rfind(c), absl::string_view::npos); >+ EXPECT_EQ(b.rfind(c, 0), absl::string_view::npos); >+ EXPECT_EQ(a.rfind(d), std::string(a).rfind(std::string())); >+ EXPECT_EQ(a.rfind(e), std::string(a).rfind(std::string())); >+ EXPECT_EQ(a.rfind(d, 12), 12); >+ EXPECT_EQ(a.rfind(e, 17), 17); >+ EXPECT_EQ(a.rfind(g), absl::string_view::npos); >+ EXPECT_EQ(d.rfind(b), absl::string_view::npos); >+ EXPECT_EQ(e.rfind(b), absl::string_view::npos); >+ EXPECT_EQ(d.rfind(b, 4), absl::string_view::npos); >+ EXPECT_EQ(e.rfind(b, 7), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(d.rfind(d, 4), std::string().rfind(std::string())); >+ EXPECT_EQ(e.rfind(d, 7), std::string().rfind(std::string())); >+ EXPECT_EQ(d.rfind(e, 4), std::string().rfind(std::string())); >+ EXPECT_EQ(e.rfind(e, 7), std::string().rfind(std::string())); >+ EXPECT_EQ(d.rfind(d), std::string().rfind(std::string())); >+ EXPECT_EQ(e.rfind(d), std::string().rfind(std::string())); >+ EXPECT_EQ(d.rfind(e), std::string().rfind(std::string())); >+ EXPECT_EQ(e.rfind(e), std::string().rfind(std::string())); >+ >+ EXPECT_EQ(g.rfind('o'), 8); >+ EXPECT_EQ(g.rfind('q'), absl::string_view::npos); >+ EXPECT_EQ(g.rfind('o', 8), 8); >+ EXPECT_EQ(g.rfind('o', 7), 4); >+ EXPECT_EQ(g.rfind('o', 3), absl::string_view::npos); >+ EXPECT_EQ(f.rfind('\0'), 3); >+ EXPECT_EQ(f.rfind('\0', 12), 3); >+ EXPECT_EQ(f.rfind('3'), 2); >+ EXPECT_EQ(f.rfind('5'), 5); >+ // empty std::string nonsense >+ EXPECT_EQ(d.rfind('o'), absl::string_view::npos); >+ EXPECT_EQ(e.rfind('o'), absl::string_view::npos); >+ EXPECT_EQ(d.rfind('o', 4), absl::string_view::npos); >+ EXPECT_EQ(e.rfind('o', 7), absl::string_view::npos); >+} >+ >+// Continued from STL2 >+TEST(StringViewTest, STL2FindFirst) { >+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); >+ const absl::string_view b("abc"); >+ const absl::string_view c("xyz"); >+ absl::string_view d("foobar"); >+ const absl::string_view e; >+ const absl::string_view f( >+ "123" >+ "\0" >+ "456", >+ 7); >+ absl::string_view g("xx not found bb"); >+ >+ d = absl::string_view(); >+ EXPECT_EQ(a.find_first_of(b), 0); >+ EXPECT_EQ(a.find_first_of(b, 0), 0); >+ EXPECT_EQ(a.find_first_of(b, 1), 1); >+ EXPECT_EQ(a.find_first_of(b, 2), 2); >+ EXPECT_EQ(a.find_first_of(b, 3), absl::string_view::npos); >+ EXPECT_EQ(a.find_first_of(c), 23); >+ EXPECT_EQ(a.find_first_of(c, 23), 23); >+ EXPECT_EQ(a.find_first_of(c, 24), 24); >+ EXPECT_EQ(a.find_first_of(c, 25), 25); >+ EXPECT_EQ(a.find_first_of(c, 26), absl::string_view::npos); >+ EXPECT_EQ(g.find_first_of(b), 13); >+ EXPECT_EQ(g.find_first_of(c), 0); >+ EXPECT_EQ(a.find_first_of(f), absl::string_view::npos); >+ EXPECT_EQ(f.find_first_of(a), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(a.find_first_of(d), absl::string_view::npos); >+ EXPECT_EQ(a.find_first_of(e), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_of(b), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_of(b), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_of(d), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_of(d), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_of(e), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_of(e), absl::string_view::npos); >+ >+ EXPECT_EQ(a.find_first_not_of(b), 3); >+ EXPECT_EQ(a.find_first_not_of(c), 0); >+ EXPECT_EQ(b.find_first_not_of(a), absl::string_view::npos); >+ EXPECT_EQ(c.find_first_not_of(a), absl::string_view::npos); >+ EXPECT_EQ(f.find_first_not_of(a), 0); >+ EXPECT_EQ(a.find_first_not_of(f), 0); >+ EXPECT_EQ(a.find_first_not_of(d), 0); >+ EXPECT_EQ(a.find_first_not_of(e), 0); >+ // empty std::string nonsense >+ EXPECT_EQ(a.find_first_not_of(d), 0); >+ EXPECT_EQ(a.find_first_not_of(e), 0); >+ EXPECT_EQ(a.find_first_not_of(d, 1), 1); >+ EXPECT_EQ(a.find_first_not_of(e, 1), 1); >+ EXPECT_EQ(a.find_first_not_of(d, a.size() - 1), a.size() - 1); >+ EXPECT_EQ(a.find_first_not_of(e, a.size() - 1), a.size() - 1); >+ EXPECT_EQ(a.find_first_not_of(d, a.size()), absl::string_view::npos); >+ EXPECT_EQ(a.find_first_not_of(e, a.size()), absl::string_view::npos); >+ EXPECT_EQ(a.find_first_not_of(d, absl::string_view::npos), >+ absl::string_view::npos); >+ EXPECT_EQ(a.find_first_not_of(e, absl::string_view::npos), >+ absl::string_view::npos); >+ EXPECT_EQ(d.find_first_not_of(a), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_not_of(a), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_not_of(d), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_not_of(d), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_not_of(e), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_not_of(e), absl::string_view::npos); >+ >+ absl::string_view h("===="); >+ EXPECT_EQ(h.find_first_not_of('='), absl::string_view::npos); >+ EXPECT_EQ(h.find_first_not_of('=', 3), absl::string_view::npos); >+ EXPECT_EQ(h.find_first_not_of('\0'), 0); >+ EXPECT_EQ(g.find_first_not_of('x'), 2); >+ EXPECT_EQ(f.find_first_not_of('\0'), 0); >+ EXPECT_EQ(f.find_first_not_of('\0', 3), 4); >+ EXPECT_EQ(f.find_first_not_of('\0', 2), 2); >+ // empty std::string nonsense >+ EXPECT_EQ(d.find_first_not_of('x'), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_not_of('x'), absl::string_view::npos); >+ EXPECT_EQ(d.find_first_not_of('\0'), absl::string_view::npos); >+ EXPECT_EQ(e.find_first_not_of('\0'), absl::string_view::npos); >+} >+ >+// Continued from STL2 >+TEST(StringViewTest, STL2FindLast) { >+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); >+ const absl::string_view b("abc"); >+ const absl::string_view c("xyz"); >+ absl::string_view d("foobar"); >+ const absl::string_view e; >+ const absl::string_view f( >+ "123" >+ "\0" >+ "456", >+ 7); >+ absl::string_view g("xx not found bb"); >+ absl::string_view h("===="); >+ absl::string_view i("56"); >+ >+ d = absl::string_view(); >+ EXPECT_EQ(h.find_last_of(a), absl::string_view::npos); >+ EXPECT_EQ(g.find_last_of(a), g.size()-1); >+ EXPECT_EQ(a.find_last_of(b), 2); >+ EXPECT_EQ(a.find_last_of(c), a.size()-1); >+ EXPECT_EQ(f.find_last_of(i), 6); >+ EXPECT_EQ(a.find_last_of('a'), 0); >+ EXPECT_EQ(a.find_last_of('b'), 1); >+ EXPECT_EQ(a.find_last_of('z'), 25); >+ EXPECT_EQ(a.find_last_of('a', 5), 0); >+ EXPECT_EQ(a.find_last_of('b', 5), 1); >+ EXPECT_EQ(a.find_last_of('b', 0), absl::string_view::npos); >+ EXPECT_EQ(a.find_last_of('z', 25), 25); >+ EXPECT_EQ(a.find_last_of('z', 24), absl::string_view::npos); >+ EXPECT_EQ(f.find_last_of(i, 5), 5); >+ EXPECT_EQ(f.find_last_of(i, 6), 6); >+ EXPECT_EQ(f.find_last_of(a, 4), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(f.find_last_of(d), absl::string_view::npos); >+ EXPECT_EQ(f.find_last_of(e), absl::string_view::npos); >+ EXPECT_EQ(f.find_last_of(d, 4), absl::string_view::npos); >+ EXPECT_EQ(f.find_last_of(e, 4), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(d), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(e), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(d), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(e), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(f), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(f), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(d, 4), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(e, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(d, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(e, 4), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_of(f, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_of(f, 4), absl::string_view::npos); >+ >+ EXPECT_EQ(a.find_last_not_of(b), a.size()-1); >+ EXPECT_EQ(a.find_last_not_of(c), 22); >+ EXPECT_EQ(b.find_last_not_of(a), absl::string_view::npos); >+ EXPECT_EQ(b.find_last_not_of(b), absl::string_view::npos); >+ EXPECT_EQ(f.find_last_not_of(i), 4); >+ EXPECT_EQ(a.find_last_not_of(c, 24), 22); >+ EXPECT_EQ(a.find_last_not_of(b, 3), 3); >+ EXPECT_EQ(a.find_last_not_of(b, 2), absl::string_view::npos); >+ // empty std::string nonsense >+ EXPECT_EQ(f.find_last_not_of(d), f.size()-1); >+ EXPECT_EQ(f.find_last_not_of(e), f.size()-1); >+ EXPECT_EQ(f.find_last_not_of(d, 4), 4); >+ EXPECT_EQ(f.find_last_not_of(e, 4), 4); >+ EXPECT_EQ(d.find_last_not_of(d), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of(e), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(d), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(e), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of(f), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(f), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of(d, 4), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of(e, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(d, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(e, 4), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of(f, 4), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of(f, 4), absl::string_view::npos); >+ >+ EXPECT_EQ(h.find_last_not_of('x'), h.size() - 1); >+ EXPECT_EQ(h.find_last_not_of('='), absl::string_view::npos); >+ EXPECT_EQ(b.find_last_not_of('c'), 1); >+ EXPECT_EQ(h.find_last_not_of('x', 2), 2); >+ EXPECT_EQ(h.find_last_not_of('=', 2), absl::string_view::npos); >+ EXPECT_EQ(b.find_last_not_of('b', 1), 0); >+ // empty std::string nonsense >+ EXPECT_EQ(d.find_last_not_of('x'), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of('x'), absl::string_view::npos); >+ EXPECT_EQ(d.find_last_not_of('\0'), absl::string_view::npos); >+ EXPECT_EQ(e.find_last_not_of('\0'), absl::string_view::npos); >+} >+ >+// Continued from STL2 >+TEST(StringViewTest, STL2Substr) { >+ const absl::string_view a("abcdefghijklmnopqrstuvwxyz"); >+ const absl::string_view b("abc"); >+ const absl::string_view c("xyz"); >+ absl::string_view d("foobar"); >+ const absl::string_view e; >+ >+ d = absl::string_view(); >+ EXPECT_EQ(a.substr(0, 3), b); >+ EXPECT_EQ(a.substr(23), c); >+ EXPECT_EQ(a.substr(23, 3), c); >+ EXPECT_EQ(a.substr(23, 99), c); >+ EXPECT_EQ(a.substr(0), a); >+ EXPECT_EQ(a.substr(3, 2), "de"); >+ // empty std::string nonsense >+ EXPECT_EQ(d.substr(0, 99), e); >+ // use of npos >+ EXPECT_EQ(a.substr(0, absl::string_view::npos), a); >+ EXPECT_EQ(a.substr(23, absl::string_view::npos), c); >+ // throw exception >+#ifdef ABSL_HAVE_EXCEPTIONS >+ EXPECT_THROW(a.substr(99, 2), std::out_of_range); >+#else >+ EXPECT_DEATH(a.substr(99, 2), "absl::string_view::substr"); >+#endif >+} >+ >+TEST(StringViewTest, TruncSubstr) { >+ const absl::string_view hi("hi"); >+ EXPECT_EQ("", absl::ClippedSubstr(hi, 0, 0)); >+ EXPECT_EQ("h", absl::ClippedSubstr(hi, 0, 1)); >+ EXPECT_EQ("hi", absl::ClippedSubstr(hi, 0)); >+ EXPECT_EQ("i", absl::ClippedSubstr(hi, 1)); >+ EXPECT_EQ("", absl::ClippedSubstr(hi, 2)); >+ EXPECT_EQ("", absl::ClippedSubstr(hi, 3)); // truncation >+ EXPECT_EQ("", absl::ClippedSubstr(hi, 3, 2)); // truncation >+} >+ >+TEST(StringViewTest, UTF8) { >+ std::string utf8 = "\u00E1"; >+ std::string utf8_twice = utf8 + " " + utf8; >+ int utf8_len = strlen(utf8.data()); >+ EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" ")); >+ EXPECT_EQ(utf8_len, absl::string_view(utf8_twice).find_first_of(" \t")); >+} >+ >+TEST(StringViewTest, FindConformance) { >+ struct { >+ std::string haystack; >+ std::string needle; >+ } specs[] = { >+ {"", ""}, >+ {"", "a"}, >+ {"a", ""}, >+ {"a", "a"}, >+ {"a", "b"}, >+ {"aa", ""}, >+ {"aa", "a"}, >+ {"aa", "b"}, >+ {"ab", "a"}, >+ {"ab", "b"}, >+ {"abcd", ""}, >+ {"abcd", "a"}, >+ {"abcd", "d"}, >+ {"abcd", "ab"}, >+ {"abcd", "bc"}, >+ {"abcd", "cd"}, >+ {"abcd", "abcd"}, >+ }; >+ for (const auto& s : specs) { >+ SCOPED_TRACE(s.haystack); >+ SCOPED_TRACE(s.needle); >+ std::string st = s.haystack; >+ absl::string_view sp = s.haystack; >+ for (size_t i = 0; i <= sp.size(); ++i) { >+ size_t pos = (i == sp.size()) ? absl::string_view::npos : i; >+ SCOPED_TRACE(pos); >+ EXPECT_EQ(sp.find(s.needle, pos), >+ st.find(s.needle, pos)); >+ EXPECT_EQ(sp.rfind(s.needle, pos), >+ st.rfind(s.needle, pos)); >+ EXPECT_EQ(sp.find_first_of(s.needle, pos), >+ st.find_first_of(s.needle, pos)); >+ EXPECT_EQ(sp.find_first_not_of(s.needle, pos), >+ st.find_first_not_of(s.needle, pos)); >+ EXPECT_EQ(sp.find_last_of(s.needle, pos), >+ st.find_last_of(s.needle, pos)); >+ EXPECT_EQ(sp.find_last_not_of(s.needle, pos), >+ st.find_last_not_of(s.needle, pos)); >+ } >+ } >+} >+ >+TEST(StringViewTest, Remove) { >+ absl::string_view a("foobar"); >+ std::string s1("123"); >+ s1 += '\0'; >+ s1 += "456"; >+ absl::string_view b(s1); >+ absl::string_view e; >+ std::string s2; >+ >+ // remove_prefix >+ absl::string_view c(a); >+ c.remove_prefix(3); >+ EXPECT_EQ(c, "bar"); >+ c = a; >+ c.remove_prefix(0); >+ EXPECT_EQ(c, a); >+ c.remove_prefix(c.size()); >+ EXPECT_EQ(c, e); >+ >+ // remove_suffix >+ c = a; >+ c.remove_suffix(3); >+ EXPECT_EQ(c, "foo"); >+ c = a; >+ c.remove_suffix(0); >+ EXPECT_EQ(c, a); >+ c.remove_suffix(c.size()); >+ EXPECT_EQ(c, e); >+} >+ >+TEST(StringViewTest, Set) { >+ absl::string_view a("foobar"); >+ absl::string_view empty; >+ absl::string_view b; >+ >+ // set >+ b = absl::string_view("foobar", 6); >+ EXPECT_EQ(b, a); >+ b = absl::string_view("foobar", 0); >+ EXPECT_EQ(b, empty); >+ b = absl::string_view("foobar", 7); >+ EXPECT_NE(b, a); >+ >+ b = absl::string_view("foobar"); >+ EXPECT_EQ(b, a); >+} >+ >+TEST(StringViewTest, FrontBack) { >+ static const char arr[] = "abcd"; >+ const absl::string_view csp(arr, 4); >+ EXPECT_EQ(&arr[0], &csp.front()); >+ EXPECT_EQ(&arr[3], &csp.back()); >+} >+ >+TEST(StringViewTest, FrontBackSingleChar) { >+ static const char c = 'a'; >+ const absl::string_view csp(&c, 1); >+ EXPECT_EQ(&c, &csp.front()); >+ EXPECT_EQ(&c, &csp.back()); >+} >+ >+// `std::string_view::string_view(const char*)` calls >+// `std::char_traits<char>::length(const char*)` to get the std::string length. In >+// libc++, it doesn't allow `nullptr` in the constexpr context, with the error >+// "read of dereferenced null pointer is not allowed in a constant expression". >+// At run time, the behavior of `std::char_traits::length()` on `nullptr` is >+// undefined by the standard and usually results in crash with libc++. This >+// conforms to the standard, but `absl::string_view` implements a different >+// behavior for historical reasons. We work around tests that construct >+// `string_view` from `nullptr` when using libc++. >+#if !defined(ABSL_HAVE_STD_STRING_VIEW) || !defined(_LIBCPP_VERSION) >+#define ABSL_HAVE_STRING_VIEW_FROM_NULLPTR 1 >+#endif // !defined(ABSL_HAVE_STD_STRING_VIEW) || !defined(_LIBCPP_VERSION) >+ >+TEST(StringViewTest, NULLInput) { >+ absl::string_view s; >+ EXPECT_EQ(s.data(), nullptr); >+ EXPECT_EQ(s.size(), 0); >+ >+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR >+ s = absl::string_view(nullptr); >+ EXPECT_EQ(s.data(), nullptr); >+ EXPECT_EQ(s.size(), 0); >+ >+ // .ToString() on a absl::string_view with nullptr should produce the empty >+ // std::string. >+ EXPECT_EQ("", std::string(s)); >+#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR >+} >+ >+TEST(StringViewTest, Comparisons2) { >+ // The `compare` member has 6 overloads (v: string_view, s: const char*): >+ // (1) compare(v) >+ // (2) compare(pos1, count1, v) >+ // (3) compare(pos1, count1, v, pos2, count2) >+ // (4) compare(s) >+ // (5) compare(pos1, count1, s) >+ // (6) compare(pos1, count1, s, count2) >+ >+ absl::string_view abc("abcdefghijklmnopqrstuvwxyz"); >+ >+ // check comparison operations on strings longer than 4 bytes. >+ EXPECT_EQ(abc, absl::string_view("abcdefghijklmnopqrstuvwxyz")); >+ EXPECT_EQ(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyz")), 0); >+ >+ EXPECT_LT(abc, absl::string_view("abcdefghijklmnopqrstuvwxzz")); >+ EXPECT_LT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxzz")), 0); >+ >+ EXPECT_GT(abc, absl::string_view("abcdefghijklmnopqrstuvwxyy")); >+ EXPECT_GT(abc.compare(absl::string_view("abcdefghijklmnopqrstuvwxyy")), 0); >+ >+ // The "substr" variants of `compare`. >+ absl::string_view digits("0123456789"); >+ auto npos = absl::string_view::npos; >+ >+ // Taking string_view >+ EXPECT_EQ(digits.compare(3, npos, absl::string_view("3456789")), 0); // 2 >+ EXPECT_EQ(digits.compare(3, 4, absl::string_view("3456")), 0); // 2 >+ EXPECT_EQ(digits.compare(10, 0, absl::string_view()), 0); // 2 >+ EXPECT_EQ(digits.compare(3, 4, absl::string_view("0123456789"), 3, 4), >+ 0); // 3 >+ EXPECT_LT(digits.compare(3, 4, absl::string_view("0123456789"), 3, 5), >+ 0); // 3 >+ EXPECT_LT(digits.compare(0, npos, absl::string_view("0123456789"), 3, 5), >+ 0); // 3 >+ // Taking const char* >+ EXPECT_EQ(digits.compare(3, 4, "3456"), 0); // 5 >+ EXPECT_EQ(digits.compare(3, npos, "3456789"), 0); // 5 >+ EXPECT_EQ(digits.compare(10, 0, ""), 0); // 5 >+ EXPECT_EQ(digits.compare(3, 4, "0123456789", 3, 4), 0); // 6 >+ EXPECT_LT(digits.compare(3, 4, "0123456789", 3, 5), 0); // 6 >+ EXPECT_LT(digits.compare(0, npos, "0123456789", 3, 5), 0); // 6 >+} >+ >+struct MyCharAlloc : std::allocator<char> {}; >+ >+TEST(StringViewTest, ExplicitConversionOperator) { >+ absl::string_view sp = "hi"; >+ EXPECT_EQ(sp, std::string(sp)); >+} >+ >+TEST(StringViewTest, NullSafeStringView) { >+ { >+ absl::string_view s = absl::NullSafeStringView(nullptr); >+ EXPECT_EQ(nullptr, s.data()); >+ EXPECT_EQ(0, s.size()); >+ EXPECT_EQ(absl::string_view(), s); >+ } >+ { >+ static const char kHi[] = "hi"; >+ absl::string_view s = absl::NullSafeStringView(kHi); >+ EXPECT_EQ(kHi, s.data()); >+ EXPECT_EQ(strlen(kHi), s.size()); >+ EXPECT_EQ(absl::string_view("hi"), s); >+ } >+} >+ >+TEST(StringViewTest, ConstexprCompiles) { >+ constexpr absl::string_view sp; >+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR >+ constexpr absl::string_view cstr(nullptr); >+#endif >+ constexpr absl::string_view cstr_len("cstr", 4); >+ >+#if defined(ABSL_HAVE_STD_STRING_VIEW) >+ // In libstdc++ (as of 7.2), `std::string_view::string_view(const char*)` >+ // calls `std::char_traits<char>::length(const char*)` to get the std::string >+ // length, but it is not marked constexpr yet. See GCC bug: >+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78156 >+ // Also, there is a LWG issue that adds constexpr to length() which was just >+ // resolved 2017-06-02. See >+ // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2232 >+ // TODO(zhangxy): Update the condition when libstdc++ adopts the constexpr >+ // length(). >+#if !defined(__GLIBCXX__) >+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 >+#endif // !__GLIBCXX__ >+ >+#else // ABSL_HAVE_STD_STRING_VIEW >+ >+// This duplicates the check for __builtin_strlen in the header. >+#if ABSL_HAVE_BUILTIN(__builtin_strlen) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+#define ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR 1 >+#elif defined(__GNUC__) // GCC or clang >+#error GCC/clang should have constexpr string_view. >+#endif >+ >+#endif // ABSL_HAVE_STD_STRING_VIEW >+ >+#ifdef ABSL_HAVE_CONSTEXPR_STRING_VIEW_FROM_CSTR >+ constexpr absl::string_view cstr_strlen("foo"); >+ EXPECT_EQ(cstr_strlen.length(), 3); >+ constexpr absl::string_view cstr_strlen2 = "bar"; >+ EXPECT_EQ(cstr_strlen2, "bar"); >+#endif >+ >+#if !defined(__clang__) || 3 < __clang_major__ || \ >+ (3 == __clang_major__ && 4 < __clang_minor__) >+ // older clang versions (< 3.5) complain that: >+ // "cannot perform pointer arithmetic on null pointer" >+ constexpr absl::string_view::iterator const_begin_empty = sp.begin(); >+ constexpr absl::string_view::iterator const_end_empty = sp.end(); >+ EXPECT_EQ(const_begin_empty, const_end_empty); >+ >+#ifdef ABSL_HAVE_STRING_VIEW_FROM_NULLPTR >+ constexpr absl::string_view::iterator const_begin_nullptr = cstr.begin(); >+ constexpr absl::string_view::iterator const_end_nullptr = cstr.end(); >+ EXPECT_EQ(const_begin_nullptr, const_end_nullptr); >+#endif // ABSL_HAVE_STRING_VIEW_FROM_NULLPTR >+#endif // !defined(__clang__) || ... >+ >+ constexpr absl::string_view::iterator const_begin = cstr_len.begin(); >+ constexpr absl::string_view::iterator const_end = cstr_len.end(); >+ constexpr absl::string_view::size_type const_size = cstr_len.size(); >+ constexpr absl::string_view::size_type const_length = cstr_len.length(); >+ EXPECT_EQ(const_begin + const_size, const_end); >+ EXPECT_EQ(const_begin + const_length, const_end); >+ >+ constexpr bool isempty = sp.empty(); >+ EXPECT_TRUE(isempty); >+ >+ constexpr const char c = cstr_len[2]; >+ EXPECT_EQ(c, 't'); >+ >+ constexpr const char cfront = cstr_len.front(); >+ constexpr const char cback = cstr_len.back(); >+ EXPECT_EQ(cfront, 'c'); >+ EXPECT_EQ(cback, 'r'); >+ >+ constexpr const char* np = sp.data(); >+ constexpr const char* cstr_ptr = cstr_len.data(); >+ EXPECT_EQ(np, nullptr); >+ EXPECT_NE(cstr_ptr, nullptr); >+ >+ constexpr size_t sp_npos = sp.npos; >+ EXPECT_EQ(sp_npos, -1); >+} >+ >+TEST(StringViewTest, Noexcept) { >+ EXPECT_TRUE((std::is_nothrow_constructible<absl::string_view, >+ const std::string&>::value)); >+ EXPECT_TRUE( >+ (std::is_nothrow_constructible<absl::string_view, const std::string&>::value)); >+ EXPECT_TRUE(std::is_nothrow_constructible<absl::string_view>::value); >+ constexpr absl::string_view sp; >+ EXPECT_TRUE(noexcept(sp.begin())); >+ EXPECT_TRUE(noexcept(sp.end())); >+ EXPECT_TRUE(noexcept(sp.cbegin())); >+ EXPECT_TRUE(noexcept(sp.cend())); >+ EXPECT_TRUE(noexcept(sp.rbegin())); >+ EXPECT_TRUE(noexcept(sp.rend())); >+ EXPECT_TRUE(noexcept(sp.crbegin())); >+ EXPECT_TRUE(noexcept(sp.crend())); >+ EXPECT_TRUE(noexcept(sp.size())); >+ EXPECT_TRUE(noexcept(sp.length())); >+ EXPECT_TRUE(noexcept(sp.empty())); >+ EXPECT_TRUE(noexcept(sp.data())); >+ EXPECT_TRUE(noexcept(sp.compare(sp))); >+ EXPECT_TRUE(noexcept(sp.find(sp))); >+ EXPECT_TRUE(noexcept(sp.find('f'))); >+ EXPECT_TRUE(noexcept(sp.rfind(sp))); >+ EXPECT_TRUE(noexcept(sp.rfind('f'))); >+ EXPECT_TRUE(noexcept(sp.find_first_of(sp))); >+ EXPECT_TRUE(noexcept(sp.find_first_of('f'))); >+ EXPECT_TRUE(noexcept(sp.find_last_of(sp))); >+ EXPECT_TRUE(noexcept(sp.find_last_of('f'))); >+ EXPECT_TRUE(noexcept(sp.find_first_not_of(sp))); >+ EXPECT_TRUE(noexcept(sp.find_first_not_of('f'))); >+ EXPECT_TRUE(noexcept(sp.find_last_not_of(sp))); >+ EXPECT_TRUE(noexcept(sp.find_last_not_of('f'))); >+} >+ >+TEST(ComparisonOpsTest, StringCompareNotAmbiguous) { >+ EXPECT_EQ("hello", std::string("hello")); >+ EXPECT_LT("hello", std::string("world")); >+} >+ >+TEST(ComparisonOpsTest, HeterogenousStringViewEquals) { >+ EXPECT_EQ(absl::string_view("hello"), std::string("hello")); >+ EXPECT_EQ("hello", absl::string_view("hello")); >+} >+ >+TEST(FindOneCharTest, EdgeCases) { >+ absl::string_view a("xxyyyxx"); >+ >+ // Set a = "xyyyx". >+ a.remove_prefix(1); >+ a.remove_suffix(1); >+ >+ EXPECT_EQ(0, a.find('x')); >+ EXPECT_EQ(0, a.find('x', 0)); >+ EXPECT_EQ(4, a.find('x', 1)); >+ EXPECT_EQ(4, a.find('x', 4)); >+ EXPECT_EQ(absl::string_view::npos, a.find('x', 5)); >+ >+ EXPECT_EQ(4, a.rfind('x')); >+ EXPECT_EQ(4, a.rfind('x', 5)); >+ EXPECT_EQ(4, a.rfind('x', 4)); >+ EXPECT_EQ(0, a.rfind('x', 3)); >+ EXPECT_EQ(0, a.rfind('x', 0)); >+ >+ // Set a = "yyy". >+ a.remove_prefix(1); >+ a.remove_suffix(1); >+ >+ EXPECT_EQ(absl::string_view::npos, a.find('x')); >+ EXPECT_EQ(absl::string_view::npos, a.rfind('x')); >+} >+ >+#ifndef THREAD_SANITIZER // Allocates too much memory for tsan. >+TEST(HugeStringView, TwoPointTwoGB) { >+ if (sizeof(size_t) <= 4 || AbslRunningOnValgrind()) >+ return; >+ // Try a huge std::string piece. >+ const size_t size = size_t{2200} * 1000 * 1000; >+ std::string s(size, 'a'); >+ absl::string_view sp(s); >+ EXPECT_EQ(size, sp.length()); >+ sp.remove_prefix(1); >+ EXPECT_EQ(size - 1, sp.length()); >+ sp.remove_suffix(2); >+ EXPECT_EQ(size - 1 - 2, sp.length()); >+} >+#endif // THREAD_SANITIZER >+ >+#if !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW) >+TEST(NonNegativeLenTest, NonNegativeLen) { >+ ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("xyz", -1), >+ "len <= kMaxSize"); >+} >+ >+TEST(LenExceedsMaxSizeTest, LenExceedsMaxSize) { >+ auto max_size = absl::string_view().max_size(); >+ >+ // This should construct ok (although the view itself is obviously invalid). >+ absl::string_view ok_view("", max_size); >+ >+ // Adding one to the max should trigger an assertion. >+ ABSL_EXPECT_DEATH_IF_SUPPORTED(absl::string_view("", max_size + 1), >+ "len <= kMaxSize"); >+} >+#endif // !defined(NDEBUG) && !defined(ABSL_HAVE_STD_STRING_VIEW) >+ >+class StringViewStreamTest : public ::testing::Test { >+ public: >+ // Set negative 'width' for right justification. >+ template <typename T> >+ std::string Pad(const T& s, int width, char fill = 0) { >+ std::ostringstream oss; >+ if (fill != 0) { >+ oss << std::setfill(fill); >+ } >+ if (width < 0) { >+ width = -width; >+ oss << std::right; >+ } >+ oss << std::setw(width) << s; >+ return oss.str(); >+ } >+}; >+ >+TEST_F(StringViewStreamTest, Padding) { >+ std::string s("hello"); >+ absl::string_view sp(s); >+ for (int w = -64; w < 64; ++w) { >+ SCOPED_TRACE(w); >+ EXPECT_EQ(Pad(s, w), Pad(sp, w)); >+ } >+ for (int w = -64; w < 64; ++w) { >+ SCOPED_TRACE(w); >+ EXPECT_EQ(Pad(s, w, '#'), Pad(sp, w, '#')); >+ } >+} >+ >+TEST_F(StringViewStreamTest, ResetsWidth) { >+ // Width should reset after one formatted write. >+ // If we weren't resetting width after formatting the string_view, >+ // we'd have width=5 carrying over to the printing of the "]", >+ // creating "[###hi####]". >+ std::string s = "hi"; >+ absl::string_view sp = s; >+ { >+ std::ostringstream oss; >+ oss << "[" << std::setfill('#') << std::setw(5) << s << "]"; >+ ASSERT_EQ("[###hi]", oss.str()); >+ } >+ { >+ std::ostringstream oss; >+ oss << "[" << std::setfill('#') << std::setw(5) << sp << "]"; >+ EXPECT_EQ("[###hi]", oss.str()); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip.h >new file mode 100644 >index 00000000000..2f8d21f7deb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip.h >@@ -0,0 +1,89 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: strip.h >+// ----------------------------------------------------------------------------- >+// >+// This file contains various functions for stripping substrings from a std::string. >+#ifndef ABSL_STRINGS_STRIP_H_ >+#define ABSL_STRINGS_STRIP_H_ >+ >+#include <cstddef> >+#include <string> >+ >+#include "absl/base/macros.h" >+#include "absl/strings/ascii.h" >+#include "absl/strings/match.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+ >+// ConsumePrefix() >+// >+// Strips the `expected` prefix from the start of the given std::string, returning >+// `true` if the strip operation succeeded or false otherwise. >+// >+// Example: >+// >+// absl::string_view input("abc"); >+// EXPECT_TRUE(absl::ConsumePrefix(&input, "a")); >+// EXPECT_EQ(input, "bc"); >+inline bool ConsumePrefix(absl::string_view* str, absl::string_view expected) { >+ if (!absl::StartsWith(*str, expected)) return false; >+ str->remove_prefix(expected.size()); >+ return true; >+} >+// ConsumeSuffix() >+// >+// Strips the `expected` suffix from the end of the given std::string, returning >+// `true` if the strip operation succeeded or false otherwise. >+// >+// Example: >+// >+// absl::string_view input("abcdef"); >+// EXPECT_TRUE(absl::ConsumeSuffix(&input, "def")); >+// EXPECT_EQ(input, "abc"); >+inline bool ConsumeSuffix(absl::string_view* str, absl::string_view expected) { >+ if (!absl::EndsWith(*str, expected)) return false; >+ str->remove_suffix(expected.size()); >+ return true; >+} >+ >+// StripPrefix() >+// >+// Returns a view into the input std::string 'str' with the given 'prefix' removed, >+// but leaving the original std::string intact. If the prefix does not match at the >+// start of the std::string, returns the original std::string instead. >+ABSL_MUST_USE_RESULT inline absl::string_view StripPrefix( >+ absl::string_view str, absl::string_view prefix) { >+ if (absl::StartsWith(str, prefix)) str.remove_prefix(prefix.size()); >+ return str; >+} >+ >+// StripSuffix() >+// >+// Returns a view into the input std::string 'str' with the given 'suffix' removed, >+// but leaving the original std::string intact. If the suffix does not match at the >+// end of the std::string, returns the original std::string instead. >+ABSL_MUST_USE_RESULT inline absl::string_view StripSuffix( >+ absl::string_view str, absl::string_view suffix) { >+ if (absl::EndsWith(str, suffix)) str.remove_suffix(suffix.size()); >+ return str; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_STRIP_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip_test.cc >new file mode 100644 >index 00000000000..205c160c192 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/strip_test.cc >@@ -0,0 +1,201 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains functions that remove a defined part from the std::string, >+// i.e., strip the std::string. >+ >+#include "absl/strings/strip.h" >+ >+#include <cassert> >+#include <cstdio> >+#include <cstring> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/strings/string_view.h" >+ >+namespace { >+ >+using testing::ElementsAre; >+using testing::IsEmpty; >+ >+TEST(Strip, ConsumePrefixOneChar) { >+ absl::string_view input("abc"); >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "a")); >+ EXPECT_EQ(input, "bc"); >+ >+ EXPECT_FALSE(absl::ConsumePrefix(&input, "x")); >+ EXPECT_EQ(input, "bc"); >+ >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "b")); >+ EXPECT_EQ(input, "c"); >+ >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "c")); >+ EXPECT_EQ(input, ""); >+ >+ EXPECT_FALSE(absl::ConsumePrefix(&input, "a")); >+ EXPECT_EQ(input, ""); >+} >+ >+TEST(Strip, ConsumePrefix) { >+ absl::string_view input("abcdef"); >+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdefg")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abce")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_FALSE(absl::ConsumePrefix(&input, "abcdeg")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "abcdef")); >+ EXPECT_EQ(input, ""); >+ >+ input = "abcdef"; >+ EXPECT_TRUE(absl::ConsumePrefix(&input, "abcde")); >+ EXPECT_EQ(input, "f"); >+} >+ >+TEST(Strip, ConsumeSuffix) { >+ absl::string_view input("abcdef"); >+ EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdefg")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "def")); >+ EXPECT_EQ(input, "abc"); >+ >+ input = "abcdef"; >+ EXPECT_FALSE(absl::ConsumeSuffix(&input, "abcdeg")); >+ EXPECT_EQ(input, "abcdef"); >+ >+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "f")); >+ EXPECT_EQ(input, "abcde"); >+ >+ EXPECT_TRUE(absl::ConsumeSuffix(&input, "abcde")); >+ EXPECT_EQ(input, ""); >+} >+ >+TEST(Strip, StripPrefix) { >+ const absl::string_view null_str; >+ >+ EXPECT_EQ(absl::StripPrefix("foobar", "foo"), "bar"); >+ EXPECT_EQ(absl::StripPrefix("foobar", ""), "foobar"); >+ EXPECT_EQ(absl::StripPrefix("foobar", null_str), "foobar"); >+ EXPECT_EQ(absl::StripPrefix("foobar", "foobar"), ""); >+ EXPECT_EQ(absl::StripPrefix("foobar", "bar"), "foobar"); >+ EXPECT_EQ(absl::StripPrefix("foobar", "foobarr"), "foobar"); >+ EXPECT_EQ(absl::StripPrefix("", ""), ""); >+} >+ >+TEST(Strip, StripSuffix) { >+ const absl::string_view null_str; >+ >+ EXPECT_EQ(absl::StripSuffix("foobar", "bar"), "foo"); >+ EXPECT_EQ(absl::StripSuffix("foobar", ""), "foobar"); >+ EXPECT_EQ(absl::StripSuffix("foobar", null_str), "foobar"); >+ EXPECT_EQ(absl::StripSuffix("foobar", "foobar"), ""); >+ EXPECT_EQ(absl::StripSuffix("foobar", "foo"), "foobar"); >+ EXPECT_EQ(absl::StripSuffix("foobar", "ffoobar"), "foobar"); >+ EXPECT_EQ(absl::StripSuffix("", ""), ""); >+} >+ >+TEST(Strip, RemoveExtraAsciiWhitespace) { >+ const char* inputs[] = { >+ "No extra space", >+ " Leading whitespace", >+ "Trailing whitespace ", >+ " Leading and trailing ", >+ " Whitespace \t in\v middle ", >+ "'Eeeeep! \n Newlines!\n", >+ "nospaces", >+ }; >+ const char* outputs[] = { >+ "No extra space", >+ "Leading whitespace", >+ "Trailing whitespace", >+ "Leading and trailing", >+ "Whitespace in middle", >+ "'Eeeeep! Newlines!", >+ "nospaces", >+ }; >+ int NUM_TESTS = 7; >+ >+ for (int i = 0; i < NUM_TESTS; i++) { >+ std::string s(inputs[i]); >+ absl::RemoveExtraAsciiWhitespace(&s); >+ EXPECT_STREQ(outputs[i], s.c_str()); >+ } >+ >+ // Test that absl::RemoveExtraAsciiWhitespace returns immediately for empty >+ // strings (It was adding the \0 character to the C++ std::string, which broke >+ // tests involving empty()) >+ std::string zero_string = ""; >+ assert(zero_string.empty()); >+ absl::RemoveExtraAsciiWhitespace(&zero_string); >+ EXPECT_EQ(zero_string.size(), 0); >+ EXPECT_TRUE(zero_string.empty()); >+} >+ >+TEST(Strip, StripTrailingAsciiWhitespace) { >+ std::string test = "foo "; >+ absl::StripTrailingAsciiWhitespace(&test); >+ EXPECT_EQ(test, "foo"); >+ >+ test = " "; >+ absl::StripTrailingAsciiWhitespace(&test); >+ EXPECT_EQ(test, ""); >+ >+ test = ""; >+ absl::StripTrailingAsciiWhitespace(&test); >+ EXPECT_EQ(test, ""); >+ >+ test = " abc\t"; >+ absl::StripTrailingAsciiWhitespace(&test); >+ EXPECT_EQ(test, " abc"); >+} >+ >+TEST(String, StripLeadingAsciiWhitespace) { >+ absl::string_view orig = "\t \n\f\r\n\vfoo"; >+ EXPECT_EQ("foo", absl::StripLeadingAsciiWhitespace(orig)); >+ orig = "\t \n\f\r\v\n\t \n\f\r\v\n"; >+ EXPECT_EQ(absl::string_view(), absl::StripLeadingAsciiWhitespace(orig)); >+} >+ >+TEST(Strip, StripAsciiWhitespace) { >+ std::string test2 = "\t \f\r\n\vfoo \t\f\r\v\n"; >+ absl::StripAsciiWhitespace(&test2); >+ EXPECT_EQ(test2, "foo"); >+ std::string test3 = "bar"; >+ absl::StripAsciiWhitespace(&test3); >+ EXPECT_EQ(test3, "bar"); >+ std::string test4 = "\t \f\r\n\vfoo"; >+ absl::StripAsciiWhitespace(&test4); >+ EXPECT_EQ(test4, "foo"); >+ std::string test5 = "foo \t\f\r\v\n"; >+ absl::StripAsciiWhitespace(&test5); >+ EXPECT_EQ(test5, "foo"); >+ absl::string_view test6("\t \f\r\n\vfoo \t\f\r\v\n"); >+ test6 = absl::StripAsciiWhitespace(test6); >+ EXPECT_EQ(test6, "foo"); >+ test6 = absl::StripAsciiWhitespace(test6); >+ EXPECT_EQ(test6, "foo"); // already stripped >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.cc >new file mode 100644 >index 00000000000..3b200594509 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.cc >@@ -0,0 +1,170 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/substitute.h" >+ >+#include <algorithm> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/strings/ascii.h" >+#include "absl/strings/escaping.h" >+#include "absl/strings/internal/resize_uninitialized.h" >+#include "absl/strings/string_view.h" >+ >+namespace absl { >+namespace substitute_internal { >+ >+void SubstituteAndAppendArray(std::string* output, absl::string_view format, >+ const absl::string_view* args_array, >+ size_t num_args) { >+ // Determine total size needed. >+ size_t size = 0; >+ for (size_t i = 0; i < format.size(); i++) { >+ if (format[i] == '$') { >+ if (i + 1 >= format.size()) { >+#ifndef NDEBUG >+ ABSL_RAW_LOG(FATAL, >+ "Invalid strings::Substitute() format std::string: \"%s\".", >+ absl::CEscape(format).c_str()); >+#endif >+ return; >+ } else if (absl::ascii_isdigit(format[i + 1])) { >+ int index = format[i + 1] - '0'; >+ if (static_cast<size_t>(index) >= num_args) { >+#ifndef NDEBUG >+ ABSL_RAW_LOG( >+ FATAL, >+ "Invalid strings::Substitute() format std::string: asked for \"$" >+ "%d\", but only %d args were given. Full format std::string was: " >+ "\"%s\".", >+ index, static_cast<int>(num_args), absl::CEscape(format).c_str()); >+#endif >+ return; >+ } >+ size += args_array[index].size(); >+ ++i; // Skip next char. >+ } else if (format[i + 1] == '$') { >+ ++size; >+ ++i; // Skip next char. >+ } else { >+#ifndef NDEBUG >+ ABSL_RAW_LOG(FATAL, >+ "Invalid strings::Substitute() format std::string: \"%s\".", >+ absl::CEscape(format).c_str()); >+#endif >+ return; >+ } >+ } else { >+ ++size; >+ } >+ } >+ >+ if (size == 0) return; >+ >+ // Build the std::string. >+ size_t original_size = output->size(); >+ strings_internal::STLStringResizeUninitialized(output, original_size + size); >+ char* target = &(*output)[original_size]; >+ for (size_t i = 0; i < format.size(); i++) { >+ if (format[i] == '$') { >+ if (absl::ascii_isdigit(format[i + 1])) { >+ const absl::string_view src = args_array[format[i + 1] - '0']; >+ target = std::copy(src.begin(), src.end(), target); >+ ++i; // Skip next char. >+ } else if (format[i + 1] == '$') { >+ *target++ = '$'; >+ ++i; // Skip next char. >+ } >+ } else { >+ *target++ = format[i]; >+ } >+ } >+ >+ assert(target == output->data() + output->size()); >+} >+ >+static const char kHexDigits[] = "0123456789abcdef"; >+Arg::Arg(const void* value) { >+ static_assert(sizeof(scratch_) >= sizeof(value) * 2 + 2, >+ "fix sizeof(scratch_)"); >+ if (value == nullptr) { >+ piece_ = "NULL"; >+ } else { >+ char* ptr = scratch_ + sizeof(scratch_); >+ uintptr_t num = reinterpret_cast<uintptr_t>(value); >+ do { >+ *--ptr = kHexDigits[num & 0xf]; >+ num >>= 4; >+ } while (num != 0); >+ *--ptr = 'x'; >+ *--ptr = '0'; >+ piece_ = absl::string_view(ptr, scratch_ + sizeof(scratch_) - ptr); >+ } >+} >+ >+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc >+Arg::Arg(Hex hex) { >+ char* const end = &scratch_[numbers_internal::kFastToBufferSize]; >+ char* writer = end; >+ uint64_t value = hex.value; >+ do { >+ *--writer = kHexDigits[value & 0xF]; >+ value >>= 4; >+ } while (value != 0); >+ >+ char* beg; >+ if (end - writer < hex.width) { >+ beg = end - hex.width; >+ std::fill_n(beg, writer - beg, hex.fill); >+ } else { >+ beg = writer; >+ } >+ >+ piece_ = absl::string_view(beg, end - beg); >+} >+ >+// TODO(jorg): Don't duplicate so much code between here and str_cat.cc >+Arg::Arg(Dec dec) { >+ assert(dec.width <= numbers_internal::kFastToBufferSize); >+ char* const end = &scratch_[numbers_internal::kFastToBufferSize]; >+ char* const minfill = end - dec.width; >+ char* writer = end; >+ uint64_t value = dec.value; >+ bool neg = dec.neg; >+ while (value > 9) { >+ *--writer = '0' + (value % 10); >+ value /= 10; >+ } >+ *--writer = '0' + value; >+ if (neg) *--writer = '-'; >+ >+ ptrdiff_t fillers = writer - minfill; >+ if (fillers > 0) { >+ // Tricky: if the fill character is ' ', then it's <fill><+/-><digits> >+ // But...: if the fill character is '0', then it's <+/-><fill><digits> >+ bool add_sign_again = false; >+ if (neg && dec.fill == '0') { // If filling with '0', >+ ++writer; // ignore the sign we just added >+ add_sign_again = true; // and re-add the sign later. >+ } >+ writer -= fillers; >+ std::fill_n(writer, fillers, dec.fill); >+ if (add_sign_again) *--writer = '-'; >+ } >+ >+ piece_ = absl::string_view(writer, end - writer); >+} >+ >+} // namespace substitute_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.h >new file mode 100644 >index 00000000000..c4b25ba7095 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute.h >@@ -0,0 +1,671 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: substitute.h >+// ----------------------------------------------------------------------------- >+// >+// This package contains functions for efficiently performing std::string >+// substitutions using a format std::string with positional notation: >+// `Substitute()` and `SubstituteAndAppend()`. >+// >+// Unlike printf-style format specifiers, `Substitute()` functions do not need >+// to specify the type of the substitution arguments. Supported arguments >+// following the format std::string, such as strings, string_views, ints, >+// floats, and bools, are automatically converted to strings during the >+// substitution process. (See below for a full list of supported types.) >+// >+// `Substitute()` does not allow you to specify *how* to format a value, beyond >+// the default conversion to std::string. For example, you cannot format an integer >+// in hex. >+// >+// The format std::string uses positional identifiers indicated by a dollar sign ($) >+// and single digit positional ids to indicate which substitution arguments to >+// use at that location within the format std::string. >+// >+// Example 1: >+// std::string s = Substitute("$1 purchased $0 $2. Thanks $1!", >+// 5, "Bob", "Apples"); >+// EXPECT_EQ("Bob purchased 5 Apples. Thanks Bob!", s); >+// >+// Example 2: >+// std::string s = "Hi. "; >+// SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5); >+// EXPECT_EQ("Hi. My name is Bob and I am 5 years old.", s); >+// >+// >+// Supported types: >+// * absl::string_view, std::string, const char* (null is equivalent to "") >+// * int32_t, int64_t, uint32_t, uint64 >+// * float, double >+// * bool (Printed as "true" or "false") >+// * pointer types other than char* (Printed as "0x<lower case hex std::string>", >+// except that null is printed as "NULL") >+// >+// If an invalid format std::string is provided, Substitute returns an empty std::string >+// and SubstituteAndAppend does not change the provided output std::string. >+// A format std::string is invalid if it: >+// * ends in an unescaped $ character, >+// e.g. "Hello $", or >+// * calls for a position argument which is not provided, >+// e.g. Substitute("Hello $2", "world"), or >+// * specifies a non-digit, non-$ character after an unescaped $ character, >+// e.g. "Hello $f". >+// In debug mode, i.e. #ifndef NDEBUG, such errors terminate the program. >+ >+#ifndef ABSL_STRINGS_SUBSTITUTE_H_ >+#define ABSL_STRINGS_SUBSTITUTE_H_ >+ >+#include <cstring> >+#include <string> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/strings/ascii.h" >+#include "absl/strings/escaping.h" >+#include "absl/strings/numbers.h" >+#include "absl/strings/str_cat.h" >+#include "absl/strings/str_split.h" >+#include "absl/strings/string_view.h" >+#include "absl/strings/strip.h" >+ >+namespace absl { >+namespace substitute_internal { >+ >+// Arg >+// >+// This class provides an argument type for `absl::Substitute()` and >+// `absl::SubstituteAndAppend()`. `Arg` handles implicit conversion of various >+// types to a std::string. (`Arg` is very similar to the `AlphaNum` class in >+// `StrCat()`.) >+// >+// This class has implicit constructors. >+class Arg { >+ public: >+ // Overloads for std::string-y things >+ // >+ // Explicitly overload `const char*` so the compiler doesn't cast to `bool`. >+ Arg(const char* value) // NOLINT(runtime/explicit) >+ : piece_(absl::NullSafeStringView(value)) {} >+ template <typename Allocator> >+ Arg( // NOLINT >+ const std::basic_string<char, std::char_traits<char>, Allocator>& >+ value) noexcept >+ : piece_(value) {} >+ Arg(absl::string_view value) // NOLINT(runtime/explicit) >+ : piece_(value) {} >+ >+ // Overloads for primitives >+ // >+ // No overloads are available for signed and unsigned char because if people >+ // are explicitly declaring their chars as signed or unsigned then they are >+ // probably using them as 8-bit integers and would probably prefer an integer >+ // representation. However, we can't really know, so we make the caller decide >+ // what to do. >+ Arg(char value) // NOLINT(runtime/explicit) >+ : piece_(scratch_, 1) { scratch_[0] = value; } >+ Arg(short value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(unsigned short value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(int value) // NOLINT(runtime/explicit) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(unsigned int value) // NOLINT(runtime/explicit) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(long value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(unsigned long value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(long long value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(unsigned long long value) // NOLINT(*) >+ : piece_(scratch_, >+ numbers_internal::FastIntToBuffer(value, scratch_) - scratch_) {} >+ Arg(float value) // NOLINT(runtime/explicit) >+ : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { >+ } >+ Arg(double value) // NOLINT(runtime/explicit) >+ : piece_(scratch_, numbers_internal::SixDigitsToBuffer(value, scratch_)) { >+ } >+ Arg(bool value) // NOLINT(runtime/explicit) >+ : piece_(value ? "true" : "false") {} >+ >+ Arg(Hex hex); // NOLINT(runtime/explicit) >+ Arg(Dec dec); // NOLINT(runtime/explicit) >+ >+ // `void*` values, with the exception of `char*`, are printed as >+ // "0x<hex value>". However, in the case of `nullptr`, "NULL" is printed. >+ Arg(const void* value); // NOLINT(runtime/explicit) >+ >+ Arg(const Arg&) = delete; >+ Arg& operator=(const Arg&) = delete; >+ >+ absl::string_view piece() const { return piece_; } >+ >+ private: >+ absl::string_view piece_; >+ char scratch_[numbers_internal::kFastToBufferSize]; >+}; >+ >+// Internal helper function. Don't call this from outside this implementation. >+// This interface may change without notice. >+void SubstituteAndAppendArray(std::string* output, absl::string_view format, >+ const absl::string_view* args_array, >+ size_t num_args); >+ >+#if defined(ABSL_BAD_CALL_IF) >+constexpr int CalculateOneBit(const char* format) { >+ return (*format < '0' || *format > '9') ? 0 : (1 << (*format - '0')); >+} >+ >+constexpr const char* SkipNumber(const char* format) { >+ return !*format ? format : (format + 1); >+} >+ >+constexpr int PlaceholderBitmask(const char* format) { >+ return !*format ? 0 : *format != '$' >+ ? PlaceholderBitmask(format + 1) >+ : (CalculateOneBit(format + 1) | >+ PlaceholderBitmask(SkipNumber(format + 1))); >+} >+#endif // ABSL_BAD_CALL_IF >+ >+} // namespace substitute_internal >+ >+// >+// PUBLIC API >+// >+ >+// SubstituteAndAppend() >+// >+// Substitutes variables into a given format std::string and appends to a given >+// output std::string. See file comments above for usage. >+// >+// The declarations of `SubstituteAndAppend()` below consist of overloads >+// for passing 0 to 10 arguments, respectively. >+// >+// NOTE: A zero-argument `SubstituteAndAppend()` may be used within variadic >+// templates to allow a variable number of arguments. >+// >+// Example: >+// template <typename... Args> >+// void VarMsg(std::string* boilerplate, absl::string_view format, >+// const Args&... args) { >+// absl::SubstituteAndAppend(boilerplate, format, args...); >+// } >+// >+inline void SubstituteAndAppend(std::string* output, absl::string_view format) { >+ substitute_internal::SubstituteAndAppendArray(output, format, nullptr, 0); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0) { >+ const absl::string_view args[] = {a0.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1) { >+ const absl::string_view args[] = {a0.piece(), a1.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece(), a4.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece(), a4.piece(), a5.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend(std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece(), a4.piece(), a5.piece(), >+ a6.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend( >+ std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece(), a4.piece(), a5.piece(), >+ a6.piece(), a7.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend( >+ std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, >+ const substitute_internal::Arg& a8) { >+ const absl::string_view args[] = {a0.piece(), a1.piece(), a2.piece(), >+ a3.piece(), a4.piece(), a5.piece(), >+ a6.piece(), a7.piece(), a8.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+inline void SubstituteAndAppend( >+ std::string* output, absl::string_view format, >+ const substitute_internal::Arg& a0, const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6, const substitute_internal::Arg& a7, >+ const substitute_internal::Arg& a8, const substitute_internal::Arg& a9) { >+ const absl::string_view args[] = { >+ a0.piece(), a1.piece(), a2.piece(), a3.piece(), a4.piece(), >+ a5.piece(), a6.piece(), a7.piece(), a8.piece(), a9.piece()}; >+ substitute_internal::SubstituteAndAppendArray(output, format, args, >+ ABSL_ARRAYSIZE(args)); >+} >+ >+#if defined(ABSL_BAD_CALL_IF) >+// This body of functions catches cases where the number of placeholders >+// doesn't match the number of data arguments. >+void SubstituteAndAppend(std::string* output, const char* format) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0, >+ "There were no substitution arguments " >+ "but this format std::string has a $[0-9] in it"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1, >+ "There was 1 substitution argument given, but " >+ "this format std::string is either missing its $0, or " >+ "contains one of $1-$9"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3, >+ "There were 2 substitution arguments given, but " >+ "this format std::string is either missing its $0/$1, or " >+ "contains one of $2-$9"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7, >+ "There were 3 substitution arguments given, but " >+ "this format std::string is either missing its $0/$1/$2, or " >+ "contains one of $3-$9"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15, >+ "There were 4 substitution arguments given, but " >+ "this format std::string is either missing its $0-$3, or " >+ "contains one of $4-$9"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31, >+ "There were 5 substitution arguments given, but " >+ "this format std::string is either missing its $0-$4, or " >+ "contains one of $5-$9"); >+ >+void SubstituteAndAppend(std::string* output, const char* format, >+ const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63, >+ "There were 6 substitution arguments given, but " >+ "this format std::string is either missing its $0-$5, or " >+ "contains one of $6-$9"); >+ >+void SubstituteAndAppend( >+ std::string* output, const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127, >+ "There were 7 substitution arguments given, but " >+ "this format std::string is either missing its $0-$6, or " >+ "contains one of $7-$9"); >+ >+void SubstituteAndAppend( >+ std::string* output, const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255, >+ "There were 8 substitution arguments given, but " >+ "this format std::string is either missing its $0-$7, or " >+ "contains one of $8-$9"); >+ >+void SubstituteAndAppend( >+ std::string* output, const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) >+ ABSL_BAD_CALL_IF( >+ substitute_internal::PlaceholderBitmask(format) != 511, >+ "There were 9 substitution arguments given, but " >+ "this format std::string is either missing its $0-$8, or contains a $9"); >+ >+void SubstituteAndAppend( >+ std::string* output, const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, >+ const substitute_internal::Arg& a9) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023, >+ "There were 10 substitution arguments given, but this " >+ "format std::string doesn't contain all of $0 through $9"); >+#endif // ABSL_BAD_CALL_IF >+ >+// Substitute() >+// >+// Substitutes variables into a given format std::string. See file comments above >+// for usage. >+// >+// The declarations of `Substitute()` below consist of overloads for passing 0 >+// to 10 arguments, respectively. >+// >+// NOTE: A zero-argument `Substitute()` may be used within variadic templates to >+// allow a variable number of arguments. >+// >+// Example: >+// template <typename... Args> >+// void VarMsg(absl::string_view format, const Args&... args) { >+// std::string s = absl::Substitute(format, args...); >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute(absl::string_view format) { >+ std::string result; >+ SubstituteAndAppend(&result, format); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8); >+ return result; >+} >+ >+ABSL_MUST_USE_RESULT inline std::string Substitute( >+ absl::string_view format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, >+ const substitute_internal::Arg& a9) { >+ std::string result; >+ SubstituteAndAppend(&result, format, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); >+ return result; >+} >+ >+#if defined(ABSL_BAD_CALL_IF) >+// This body of functions catches cases where the number of placeholders >+// doesn't match the number of data arguments. >+std::string Substitute(const char* format) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 0, >+ "There were no substitution arguments " >+ "but this format std::string has a $[0-9] in it"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1, >+ "There was 1 substitution argument given, but " >+ "this format std::string is either missing its $0, or " >+ "contains one of $1-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 3, >+ "There were 2 substitution arguments given, but " >+ "this format std::string is either missing its $0/$1, or " >+ "contains one of $2-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 7, >+ "There were 3 substitution arguments given, but " >+ "this format std::string is either missing its $0/$1/$2, or " >+ "contains one of $3-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 15, >+ "There were 4 substitution arguments given, but " >+ "this format std::string is either missing its $0-$3, or " >+ "contains one of $4-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 31, >+ "There were 5 substitution arguments given, but " >+ "this format std::string is either missing its $0-$4, or " >+ "contains one of $5-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 63, >+ "There were 6 substitution arguments given, but " >+ "this format std::string is either missing its $0-$5, or " >+ "contains one of $6-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 127, >+ "There were 7 substitution arguments given, but " >+ "this format std::string is either missing its $0-$6, or " >+ "contains one of $7-$9"); >+ >+std::string Substitute(const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, >+ const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, >+ const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, >+ const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 255, >+ "There were 8 substitution arguments given, but " >+ "this format std::string is either missing its $0-$7, or " >+ "contains one of $8-$9"); >+ >+std::string Substitute( >+ const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8) >+ ABSL_BAD_CALL_IF( >+ substitute_internal::PlaceholderBitmask(format) != 511, >+ "There were 9 substitution arguments given, but " >+ "this format std::string is either missing its $0-$8, or contains a $9"); >+ >+std::string Substitute( >+ const char* format, const substitute_internal::Arg& a0, >+ const substitute_internal::Arg& a1, const substitute_internal::Arg& a2, >+ const substitute_internal::Arg& a3, const substitute_internal::Arg& a4, >+ const substitute_internal::Arg& a5, const substitute_internal::Arg& a6, >+ const substitute_internal::Arg& a7, const substitute_internal::Arg& a8, >+ const substitute_internal::Arg& a9) >+ ABSL_BAD_CALL_IF(substitute_internal::PlaceholderBitmask(format) != 1023, >+ "There were 10 substitution arguments given, but this " >+ "format std::string doesn't contain all of $0 through $9"); >+#endif // ABSL_BAD_CALL_IF >+ >+} // namespace absl >+ >+#endif // ABSL_STRINGS_SUBSTITUTE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute_test.cc >new file mode 100644 >index 00000000000..144df01ec18 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/substitute_test.cc >@@ -0,0 +1,192 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/strings/substitute.h" >+ >+#include <cstdint> >+ >+#include "gtest/gtest.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+TEST(SubstituteTest, Substitute) { >+ // Basic. >+ EXPECT_EQ("Hello, world!", absl::Substitute("$0, $1!", "Hello", "world")); >+ >+ // Non-char* types. >+ EXPECT_EQ("123 0.2 0.1 foo true false x", >+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6", 123, 0.2, 0.1f, >+ std::string("foo"), true, false, 'x')); >+ >+ // All int types. >+ EXPECT_EQ( >+ "-32767 65535 " >+ "-1234567890 3234567890 " >+ "-1234567890 3234567890 " >+ "-1234567890123456789 9234567890123456789", >+ absl::Substitute( >+ "$0 $1 $2 $3 $4 $5 $6 $7", >+ static_cast<short>(-32767), // NOLINT(runtime/int) >+ static_cast<unsigned short>(65535), // NOLINT(runtime/int) >+ -1234567890, 3234567890U, -1234567890L, 3234567890UL, >+ -int64_t{1234567890123456789}, uint64_t{9234567890123456789u})); >+ >+ // Hex format >+ EXPECT_EQ("0 1 f ffff0ffff 0123456789abcdef", >+ absl::Substitute("$0$1$2$3$4 $5", // >+ absl::Hex(0), absl::Hex(1, absl::kSpacePad2), >+ absl::Hex(0xf, absl::kSpacePad2), >+ absl::Hex(int16_t{-1}, absl::kSpacePad5), >+ absl::Hex(int16_t{-1}, absl::kZeroPad5), >+ absl::Hex(0x123456789abcdef, absl::kZeroPad16))); >+ >+ // Dec format >+ EXPECT_EQ("0 115 -1-0001 81985529216486895", >+ absl::Substitute("$0$1$2$3$4 $5", // >+ absl::Dec(0), absl::Dec(1, absl::kSpacePad2), >+ absl::Dec(0xf, absl::kSpacePad2), >+ absl::Dec(int16_t{-1}, absl::kSpacePad5), >+ absl::Dec(int16_t{-1}, absl::kZeroPad5), >+ absl::Dec(0x123456789abcdef, absl::kZeroPad16))); >+ >+ // Pointer. >+ const int* int_p = reinterpret_cast<const int*>(0x12345); >+ std::string str = absl::Substitute("$0", int_p); >+ EXPECT_EQ(absl::StrCat("0x", absl::Hex(int_p)), str); >+ >+ // Volatile Pointer. >+ // Like C++ streamed I/O, such pointers implicitly become bool >+ volatile int vol = 237; >+ volatile int *volatile volptr = &vol; >+ str = absl::Substitute("$0", volptr); >+ EXPECT_EQ("true", str); >+ >+ // null is special. StrCat prints 0x0. Substitute prints NULL. >+ const uint64_t* null_p = nullptr; >+ str = absl::Substitute("$0", null_p); >+ EXPECT_EQ("NULL", str); >+ >+ // char* is also special. >+ const char* char_p = "print me"; >+ str = absl::Substitute("$0", char_p); >+ EXPECT_EQ("print me", str); >+ >+ char char_buf[16]; >+ strncpy(char_buf, "print me too", sizeof(char_buf)); >+ str = absl::Substitute("$0", char_buf); >+ EXPECT_EQ("print me too", str); >+ >+ // null char* is "doubly" special. Represented as the empty std::string. >+ char_p = nullptr; >+ str = absl::Substitute("$0", char_p); >+ EXPECT_EQ("", str); >+ >+ // Out-of-order. >+ EXPECT_EQ("b, a, c, b", absl::Substitute("$1, $0, $2, $1", "a", "b", "c")); >+ >+ // Literal $ >+ EXPECT_EQ("$", absl::Substitute("$$")); >+ >+ EXPECT_EQ("$1", absl::Substitute("$$1")); >+ >+ // Test all overloads. >+ EXPECT_EQ("a", absl::Substitute("$0", "a")); >+ EXPECT_EQ("a b", absl::Substitute("$0 $1", "a", "b")); >+ EXPECT_EQ("a b c", absl::Substitute("$0 $1 $2", "a", "b", "c")); >+ EXPECT_EQ("a b c d", absl::Substitute("$0 $1 $2 $3", "a", "b", "c", "d")); >+ EXPECT_EQ("a b c d e", >+ absl::Substitute("$0 $1 $2 $3 $4", "a", "b", "c", "d", "e")); >+ EXPECT_EQ("a b c d e f", absl::Substitute("$0 $1 $2 $3 $4 $5", "a", "b", "c", >+ "d", "e", "f")); >+ EXPECT_EQ("a b c d e f g", absl::Substitute("$0 $1 $2 $3 $4 $5 $6", "a", "b", >+ "c", "d", "e", "f", "g")); >+ EXPECT_EQ("a b c d e f g h", >+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d", "e", >+ "f", "g", "h")); >+ EXPECT_EQ("a b c d e f g h i", >+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c", "d", >+ "e", "f", "g", "h", "i")); >+ EXPECT_EQ("a b c d e f g h i j", >+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b", "c", >+ "d", "e", "f", "g", "h", "i", "j")); >+ EXPECT_EQ("a b c d e f g h i j b0", >+ absl::Substitute("$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10", "a", "b", "c", >+ "d", "e", "f", "g", "h", "i", "j")); >+ >+ const char* null_cstring = nullptr; >+ EXPECT_EQ("Text: ''", absl::Substitute("Text: '$0'", null_cstring)); >+} >+ >+TEST(SubstituteTest, SubstituteAndAppend) { >+ std::string str = "Hello"; >+ absl::SubstituteAndAppend(&str, ", $0!", "world"); >+ EXPECT_EQ("Hello, world!", str); >+ >+ // Test all overloads. >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0", "a"); >+ EXPECT_EQ("a", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1", "a", "b"); >+ EXPECT_EQ("a b", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2", "a", "b", "c"); >+ EXPECT_EQ("a b c", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3", "a", "b", "c", "d"); >+ EXPECT_EQ("a b c d", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4", "a", "b", "c", "d", "e"); >+ EXPECT_EQ("a b c d e", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5", "a", "b", "c", "d", "e", >+ "f"); >+ EXPECT_EQ("a b c d e f", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6", "a", "b", "c", "d", >+ "e", "f", "g"); >+ EXPECT_EQ("a b c d e f g", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7", "a", "b", "c", "d", >+ "e", "f", "g", "h"); >+ EXPECT_EQ("a b c d e f g h", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8", "a", "b", "c", >+ "d", "e", "f", "g", "h", "i"); >+ EXPECT_EQ("a b c d e f g h i", str); >+ str.clear(); >+ absl::SubstituteAndAppend(&str, "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9", "a", "b", >+ "c", "d", "e", "f", "g", "h", "i", "j"); >+ EXPECT_EQ("a b c d e f g h i j", str); >+} >+ >+#ifdef GTEST_HAS_DEATH_TEST >+ >+TEST(SubstituteDeathTest, SubstituteDeath) { >+ EXPECT_DEBUG_DEATH( >+ static_cast<void>(absl::Substitute(absl::string_view("-$2"), "a", "b")), >+ "Invalid strings::Substitute\\(\\) format std::string: asked for \"\\$2\", " >+ "but only 2 args were given."); >+ EXPECT_DEBUG_DEATH( >+ static_cast<void>(absl::Substitute("-$z-")), >+ "Invalid strings::Substitute\\(\\) format std::string: \"-\\$z-\""); >+ EXPECT_DEBUG_DEATH( >+ static_cast<void>(absl::Substitute("-$")), >+ "Invalid strings::Substitute\\(\\) format std::string: \"-\\$\""); >+} >+ >+#endif // GTEST_HAS_DEATH_TEST >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-1.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-1.txt >new file mode 100644 >index 00000000000..19b909733ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-1.txt >@@ -0,0 +1,3 @@ >+alpha >+ >+beta gamma >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-2.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-2.txt >new file mode 100644 >index 00000000000..d6842d8ee36 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/strings/testdata/getline-2.txt >@@ -0,0 +1 @@ >+one.two.three >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.bazel >new file mode 100644 >index 00000000000..8d302e01223 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.bazel >@@ -0,0 +1,234 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+# Internal data structure for efficiently detecting mutex dependency cycles >+cc_library( >+ name = "graphcycles_internal", >+ srcs = [ >+ "internal/graphcycles.cc", >+ ], >+ hdrs = [ >+ "internal/graphcycles.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl:__subpackages__", >+ ], >+ deps = [ >+ "//absl/base", >+ "//absl/base:base_internal", >+ "//absl/base:core_headers", >+ "//absl/base:malloc_internal", >+ ], >+) >+ >+cc_library( >+ name = "synchronization", >+ srcs = [ >+ "barrier.cc", >+ "blocking_counter.cc", >+ "internal/create_thread_identity.cc", >+ "internal/per_thread_sem.cc", >+ "internal/waiter.cc", >+ "notification.cc", >+ ] + select({ >+ "//conditions:default": ["mutex.cc"], >+ }), >+ hdrs = [ >+ "barrier.h", >+ "blocking_counter.h", >+ "internal/create_thread_identity.h", >+ "internal/kernel_timeout.h", >+ "internal/mutex_nonprod.inc", >+ "internal/per_thread_sem.h", >+ "internal/waiter.h", >+ "mutex.h", >+ "notification.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":graphcycles_internal", >+ "//absl/base", >+ "//absl/base:base_internal", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/base:dynamic_annotations", >+ "//absl/base:malloc_internal", >+ "//absl/debugging:stacktrace", >+ "//absl/debugging:symbolize", >+ "//absl/time", >+ ], >+) >+ >+cc_test( >+ name = "barrier_test", >+ size = "small", >+ srcs = ["barrier_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":synchronization", >+ "//absl/time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "blocking_counter_test", >+ size = "small", >+ srcs = ["blocking_counter_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":synchronization", >+ "//absl/time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "graphcycles_test", >+ size = "medium", >+ srcs = ["internal/graphcycles_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":graphcycles_internal", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "graphcycles_benchmark", >+ srcs = ["internal/graphcycles_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = [ >+ "benchmark", >+ ], >+ deps = [ >+ ":graphcycles_internal", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_library( >+ name = "thread_pool", >+ testonly = 1, >+ hdrs = ["internal/thread_pool.h"], >+ deps = [ >+ ":synchronization", >+ "//absl/base:core_headers", >+ ], >+) >+ >+cc_test( >+ name = "mutex_test", >+ size = "large", >+ srcs = ["mutex_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":synchronization", >+ ":thread_pool", >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "//absl/time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "mutex_benchmark", >+ srcs = ["mutex_benchmark.cc"], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ visibility = ["//visibility:private"], >+ deps = [ >+ ":synchronization", >+ ":thread_pool", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "notification_test", >+ size = "small", >+ srcs = ["notification_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":synchronization", >+ "//absl/time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "per_thread_sem_test_common", >+ testonly = 1, >+ srcs = ["internal/per_thread_sem_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":synchronization", >+ "//absl/base", >+ "//absl/strings", >+ "//absl/time", >+ "@com_google_googletest//:gtest", >+ ], >+ alwayslink = 1, >+) >+ >+cc_test( >+ name = "per_thread_sem_test", >+ size = "medium", >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":per_thread_sem_test_common", >+ ":synchronization", >+ "//absl/base", >+ "//absl/strings", >+ "//absl/time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "lifetime_test", >+ srcs = [ >+ "lifetime_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ linkopts = select({ >+ "//absl:windows": [], >+ "//conditions:default": ["-pthread"], >+ }), >+ tags = ["no_test_ios_x86_64"], >+ deps = [ >+ ":synchronization", >+ "//absl/base", >+ "//absl/base:core_headers", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.gn >new file mode 100644 >index 00000000000..3664aa13274 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/BUILD.gn >@@ -0,0 +1,116 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("graphcycles_internal") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/graphcycles.cc", >+ ] >+ public = [ >+ "internal/graphcycles.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:base_internal", >+ "../base:core_headers", >+ "../base:malloc_internal", >+ ] >+ visibility = [] >+ visibility += [ "../*" ] >+} >+ >+source_set("synchronization") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "barrier.cc", >+ "blocking_counter.cc", >+ "internal/create_thread_identity.cc", >+ "internal/per_thread_sem.cc", >+ "internal/waiter.cc", >+ "notification.cc", >+ "mutex.cc" >+ ] >+ public = [ >+ "barrier.h", >+ "blocking_counter.h", >+ "internal/create_thread_identity.h", >+ "internal/kernel_timeout.h", >+ "internal/mutex_nonprod.inc", >+ "internal/per_thread_sem.h", >+ "internal/waiter.h", >+ "mutex.h", >+ "notification.h", >+ ] >+ deps = [ >+ ":graphcycles_internal", >+ "../base", >+ "../base:base_internal", >+ "../base:config", >+ "../base:core_headers", >+ "../base:dynamic_annotations", >+ "../base:malloc_internal", >+ "../debugging:stacktrace", >+ "../debugging:symbolize", >+ "../time", >+ ] >+} >+ >+source_set("thread_pool") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "internal/thread_pool.h", >+ ] >+ deps = [ >+ ":synchronization", >+ "../base:core_headers", >+ ] >+} >+ >+source_set("per_thread_sem_test_common") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_test_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/per_thread_sem_test.cc", >+ ] >+ deps = [ >+ ":synchronization", >+ "../base", >+ "../strings", >+ "../time", >+ "//testing/gtest", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt >new file mode 100644 >index 00000000000..de0d7b7d450 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt >@@ -0,0 +1,155 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS >+ "barrier.h" >+ "blocking_counter.h" >+ "mutex.h" >+ "notification.h" >+) >+ >+ >+list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS >+ "internal/create_thread_identity.h" >+ "internal/graphcycles.h" >+ "internal/kernel_timeout.h" >+ "internal/per_thread_sem.h" >+ "internal/thread_pool.h" >+ "internal/waiter.h" >+) >+ >+ >+ >+# synchronization library >+list(APPEND SYNCHRONIZATION_SRC >+ "barrier.cc" >+ "blocking_counter.cc" >+ "internal/create_thread_identity.cc" >+ "internal/per_thread_sem.cc" >+ "internal/waiter.cc" >+ "internal/graphcycles.cc" >+ "notification.cc" >+ "mutex.cc" >+) >+ >+set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time) >+ >+absl_library( >+ TARGET >+ absl_synchronization >+ SOURCES >+ ${SYNCHRONIZATION_SRC} >+ PUBLIC_LIBRARIES >+ ${SYNCHRONIZATION_PUBLIC_LIBRARIES} >+ EXPORT_NAME >+ synchronization >+) >+ >+ >+# >+## TESTS >+# >+ >+ >+# test barrier_test >+set(BARRIER_TEST_SRC "barrier_test.cc") >+set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization) >+ >+absl_test( >+ TARGET >+ barrier_test >+ SOURCES >+ ${BARRIER_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${BARRIER_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test blocking_counter_test >+set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc") >+set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization) >+ >+absl_test( >+ TARGET >+ blocking_counter_test >+ SOURCES >+ ${BLOCKING_COUNTER_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test graphcycles_test >+set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc") >+set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization) >+ >+absl_test( >+ TARGET >+ graphcycles_test >+ SOURCES >+ ${GRAPHCYCLES_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test mutex_test >+set(MUTEX_TEST_SRC "mutex_test.cc") >+set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization) >+ >+absl_test( >+ TARGET >+ mutex_test >+ SOURCES >+ ${MUTEX_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${MUTEX_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test notification_test >+set(NOTIFICATION_TEST_SRC "notification_test.cc") >+set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization) >+ >+absl_test( >+ TARGET >+ notification_test >+ SOURCES >+ ${NOTIFICATION_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${NOTIFICATION_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test per_thread_sem_test_common >+set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc") >+set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings) >+ >+absl_test( >+ TARGET >+ per_thread_sem_test_common >+ SOURCES >+ ${PER_THREAD_SEM_TEST_COMMON_SRC} >+ PUBLIC_LIBRARIES >+ ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES} >+) >+ >+ >+ >+ >+ >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.cc >new file mode 100644 >index 00000000000..a1b3ad5c217 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.cc >@@ -0,0 +1,50 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/barrier.h" >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+ >+// Return whether int *arg is zero. >+static bool IsZero(void *arg) { >+ return 0 == *reinterpret_cast<int *>(arg); >+} >+ >+bool Barrier::Block() { >+ MutexLock l(&this->lock_); >+ >+ this->num_to_block_--; >+ if (this->num_to_block_ < 0) { >+ ABSL_RAW_LOG( >+ FATAL, >+ "Block() called too many times. num_to_block_=%d out of total=%d", >+ this->num_to_block_, this->num_to_exit_); >+ } >+ >+ this->lock_.Await(Condition(IsZero, &this->num_to_block_)); >+ >+ // Determine which thread can safely delete this Barrier object >+ this->num_to_exit_--; >+ ABSL_RAW_CHECK(this->num_to_exit_ >= 0, "barrier underflow"); >+ >+ // If num_to_exit_ == 0 then all other threads in the barrier have >+ // exited the Wait() and have released the Mutex so this thread is >+ // free to delete the barrier. >+ return this->num_to_exit_ == 0; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.h >new file mode 100644 >index 00000000000..f834feec11d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier.h >@@ -0,0 +1,77 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// barrier.h >+// ----------------------------------------------------------------------------- >+ >+#ifndef ABSL_SYNCHRONIZATION_BARRIER_H_ >+#define ABSL_SYNCHRONIZATION_BARRIER_H_ >+ >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+ >+// Barrier >+// >+// This class creates a barrier which blocks threads until a prespecified >+// threshold of threads (`num_threads`) utilizes the barrier. A thread utilizes >+// the `Barrier` by calling `Block()` on the barrier, which will block that >+// thread; no call to `Block()` will return until `num_threads` threads have >+// called it. >+// >+// Exactly one call to `Block()` will return `true`, which is then responsible >+// for destroying the barrier; because stack allocation will cause the barrier >+// to be deleted when it is out of scope, barriers should not be stack >+// allocated. >+// >+// Example: >+// >+// // Main thread creates a `Barrier`: >+// barrier = new Barrier(num_threads); >+// >+// // Each participating thread could then call: >+// if (barrier->Block()) delete barrier; // Exactly one call to `Block()` >+// // returns `true`; that call >+// // deletes the barrier. >+class Barrier { >+ public: >+ // `num_threads` is the number of threads that will participate in the barrier >+ explicit Barrier(int num_threads) >+ : num_to_block_(num_threads), num_to_exit_(num_threads) {} >+ >+ Barrier(const Barrier&) = delete; >+ Barrier& operator=(const Barrier&) = delete; >+ >+ // Barrier::Block() >+ // >+ // Blocks the current thread, and returns only when the `num_threads` >+ // threshold of threads utilizing this barrier has been reached. `Block()` >+ // returns `true` for precisely one caller, which may then destroy the >+ // barrier. >+ // >+ // Memory ordering: For any threads X and Y, any action taken by X >+ // before X calls `Block()` will be visible to Y after Y returns from >+ // `Block()`. >+ bool Block(); >+ >+ private: >+ Mutex lock_; >+ int num_to_block_ GUARDED_BY(lock_); >+ int num_to_exit_ GUARDED_BY(lock_); >+}; >+ >+} // namespace absl >+#endif // ABSL_SYNCHRONIZATION_BARRIER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier_test.cc >new file mode 100644 >index 00000000000..d6cababdf73 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/barrier_test.cc >@@ -0,0 +1,75 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/barrier.h" >+ >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/synchronization/mutex.h" >+#include "absl/time/clock.h" >+ >+ >+TEST(Barrier, SanityTest) { >+ constexpr int kNumThreads = 10; >+ absl::Barrier* barrier = new absl::Barrier(kNumThreads); >+ >+ absl::Mutex mutex; >+ int counter = 0; // Guarded by mutex. >+ >+ auto thread_func = [&] { >+ if (barrier->Block()) { >+ // This thread is the last thread to reach the barrier so it is >+ // responsible for deleting it. >+ delete barrier; >+ } >+ >+ // Increment the counter. >+ absl::MutexLock lock(&mutex); >+ ++counter; >+ }; >+ >+ // Start (kNumThreads - 1) threads running thread_func. >+ std::vector<std::thread> threads; >+ for (int i = 0; i < kNumThreads - 1; ++i) { >+ threads.push_back(std::thread(thread_func)); >+ } >+ >+ // Give (kNumThreads - 1) threads a chance to reach the barrier. >+ // This test assumes at least one thread will have run after the >+ // sleep has elapsed. Sleeping in a test is usually bad form, but we >+ // need to make sure that we are testing the barrier instead of some >+ // other synchronization method. >+ absl::SleepFor(absl::Seconds(1)); >+ >+ // The counter should still be zero since no thread should have >+ // been able to pass the barrier yet. >+ { >+ absl::MutexLock lock(&mutex); >+ EXPECT_EQ(counter, 0); >+ } >+ >+ // Start 1 more thread. This should make all threads pass the barrier. >+ threads.push_back(std::thread(thread_func)); >+ >+ // All threads should now be able to proceed and finish. >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ >+ // All threads should now have incremented the counter. >+ absl::MutexLock lock(&mutex); >+ EXPECT_EQ(counter, kNumThreads); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.cc >new file mode 100644 >index 00000000000..7e68e960bc3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.cc >@@ -0,0 +1,55 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/blocking_counter.h" >+ >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+// Return whether int *arg is zero. >+static bool IsZero(void *arg) { >+ return 0 == *reinterpret_cast<int *>(arg); >+} >+ >+bool BlockingCounter::DecrementCount() { >+ MutexLock l(&lock_); >+ count_--; >+ if (count_ < 0) { >+ ABSL_RAW_LOG( >+ FATAL, >+ "BlockingCounter::DecrementCount() called too many times. count=%d", >+ count_); >+ } >+ return count_ == 0; >+} >+ >+void BlockingCounter::Wait() { >+ MutexLock l(&this->lock_); >+ ABSL_RAW_CHECK(count_ >= 0, "BlockingCounter underflow"); >+ >+ // only one thread may call Wait(). To support more than one thread, >+ // implement a counter num_to_exit, like in the Barrier class. >+ ABSL_RAW_CHECK(num_waiting_ == 0, "multiple threads called Wait()"); >+ num_waiting_++; >+ >+ this->lock_.Await(Condition(IsZero, &this->count_)); >+ >+ // At this point, We know that all threads executing DecrementCount have >+ // released the lock, and so will not touch this object again. >+ // Therefore, the thread calling this method is free to delete the object >+ // after we return from this method. >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.h >new file mode 100644 >index 00000000000..557ed028fe5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter.h >@@ -0,0 +1,97 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// blocking_counter.h >+// ----------------------------------------------------------------------------- >+ >+#ifndef ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ >+#define ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ >+ >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+ >+// BlockingCounter >+// >+// This class allows a thread to block for a pre-specified number of actions. >+// `BlockingCounter` maintains a single non-negative abstract integer "count" >+// with an initial value `initial_count`. A thread can then call `Wait()` on >+// this blocking counter to block until the specified number of events occur; >+// worker threads then call 'DecrementCount()` on the counter upon completion of >+// their work. Once the counter's internal "count" reaches zero, the blocked >+// thread unblocks. >+// >+// A `BlockingCounter` requires the following: >+// - its `initial_count` is non-negative. >+// - the number of calls to `DecrementCount()` on it is at most >+// `initial_count`. >+// - `Wait()` is called at most once on it. >+// >+// Given the above requirements, a `BlockingCounter` provides the following >+// guarantees: >+// - Once its internal "count" reaches zero, no legal action on the object >+// can further change the value of "count". >+// - When `Wait()` returns, it is legal to destroy the `BlockingCounter`. >+// - When `Wait()` returns, the number of calls to `DecrementCount()` on >+// this blocking counter exactly equals `initial_count`. >+// >+// Example: >+// BlockingCounter bcount(N); // there are N items of work >+// ... Allow worker threads to start. >+// ... On completing each work item, workers do: >+// ... bcount.DecrementCount(); // an item of work has been completed >+// >+// bcount.Wait(); // wait for all work to be complete >+// >+class BlockingCounter { >+ public: >+ explicit BlockingCounter(int initial_count) >+ : count_(initial_count), num_waiting_(0) {} >+ >+ BlockingCounter(const BlockingCounter&) = delete; >+ BlockingCounter& operator=(const BlockingCounter&) = delete; >+ >+ // BlockingCounter::DecrementCount() >+ // >+ // Decrements the counter's "count" by one, and return "count == 0". This >+ // function requires that "count != 0" when it is called. >+ // >+ // Memory ordering: For any threads X and Y, any action taken by X >+ // before it calls `DecrementCount()` is visible to thread Y after >+ // Y's call to `DecrementCount()`, provided Y's call returns `true`. >+ bool DecrementCount(); >+ >+ // BlockingCounter::Wait() >+ // >+ // Blocks until the counter reaches zero. This function may be called at most >+ // once. On return, `DecrementCount()` will have been called "initial_count" >+ // times and the blocking counter may be destroyed. >+ // >+ // Memory ordering: For any threads X and Y, any action taken by X >+ // before X calls `DecrementCount()` is visible to Y after Y returns >+ // from `Wait()`. >+ void Wait(); >+ >+ private: >+ Mutex lock_; >+ int count_ GUARDED_BY(lock_); >+ int num_waiting_ GUARDED_BY(lock_); >+}; >+ >+} // namespace absl >+ >+#endif // ABSL_SYNCHRONIZATION_BLOCKING_COUNTER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter_test.cc >new file mode 100644 >index 00000000000..e8223f841a5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/blocking_counter_test.cc >@@ -0,0 +1,66 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/blocking_counter.h" >+ >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/time/clock.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+namespace { >+ >+void PauseAndDecreaseCounter(BlockingCounter* counter, int* done) { >+ absl::SleepFor(absl::Seconds(1)); >+ *done = 1; >+ counter->DecrementCount(); >+} >+ >+TEST(BlockingCounterTest, BasicFunctionality) { >+ // This test verifies that BlockingCounter functions correctly. Starts a >+ // number of threads that just sleep for a second and decrement a counter. >+ >+ // Initialize the counter. >+ const int num_workers = 10; >+ BlockingCounter counter(num_workers); >+ >+ std::vector<std::thread> workers; >+ std::vector<int> done(num_workers, 0); >+ >+ // Start a number of parallel tasks that will just wait for a seconds and >+ // then decrement the count. >+ workers.reserve(num_workers); >+ for (int k = 0; k < num_workers; k++) { >+ workers.emplace_back( >+ [&counter, &done, k] { PauseAndDecreaseCounter(&counter, &done[k]); }); >+ } >+ >+ // Wait for the threads to have all finished. >+ counter.Wait(); >+ >+ // Check that all the workers have completed. >+ for (int k = 0; k < num_workers; k++) { >+ EXPECT_EQ(1, done[k]); >+ } >+ >+ for (std::thread& w : workers) { >+ w.join(); >+ } >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc >new file mode 100644 >index 00000000000..e7a65cd884a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.cc >@@ -0,0 +1,112 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <stdint.h> >+#include <new> >+ >+// This file is a no-op if the required LowLevelAlloc support is missing. >+#include "absl/base/internal/low_level_alloc.h" >+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING >+ >+#include <string.h> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/synchronization/internal/per_thread_sem.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// ThreadIdentity storage is persistent, we maintain a free-list of previously >+// released ThreadIdentity objects. >+static base_internal::SpinLock freelist_lock(base_internal::kLinkerInitialized); >+static base_internal::ThreadIdentity* thread_identity_freelist; >+ >+// A per-thread destructor for reclaiming associated ThreadIdentity objects. >+// Since we must preserve their storage we cache them for re-use. >+static void ReclaimThreadIdentity(void* v) { >+ base_internal::ThreadIdentity* identity = >+ static_cast<base_internal::ThreadIdentity*>(v); >+ >+ // all_locks might have been allocated by the Mutex implementation. >+ // We free it here when we are notified that our thread is dying. >+ if (identity->per_thread_synch.all_locks != nullptr) { >+ base_internal::LowLevelAlloc::Free(identity->per_thread_synch.all_locks); >+ } >+ >+ // We must explicitly clear the current thread's identity: >+ // (a) Subsequent (unrelated) per-thread destructors may require an identity. >+ // We must guarantee a new identity is used in this case (this instructor >+ // will be reinvoked up to PTHREAD_DESTRUCTOR_ITERATIONS in this case). >+ // (b) ThreadIdentity implementations may depend on memory that is not >+ // reinitialized before reuse. We must allow explicit clearing of the >+ // association state in this case. >+ base_internal::ClearCurrentThreadIdentity(); >+ { >+ base_internal::SpinLockHolder l(&freelist_lock); >+ identity->next = thread_identity_freelist; >+ thread_identity_freelist = identity; >+ } >+} >+ >+// Return value rounded up to next multiple of align. >+// Align must be a power of two. >+static intptr_t RoundUp(intptr_t addr, intptr_t align) { >+ return (addr + align - 1) & ~(align - 1); >+} >+ >+static base_internal::ThreadIdentity* NewThreadIdentity() { >+ base_internal::ThreadIdentity* identity = nullptr; >+ >+ { >+ // Re-use a previously released object if possible. >+ base_internal::SpinLockHolder l(&freelist_lock); >+ if (thread_identity_freelist) { >+ identity = thread_identity_freelist; // Take list-head. >+ thread_identity_freelist = thread_identity_freelist->next; >+ } >+ } >+ >+ if (identity == nullptr) { >+ // Allocate enough space to align ThreadIdentity to a multiple of >+ // PerThreadSynch::kAlignment. This space is never released (it is >+ // added to a freelist by ReclaimThreadIdentity instead). >+ void* allocation = base_internal::LowLevelAlloc::Alloc( >+ sizeof(*identity) + base_internal::PerThreadSynch::kAlignment - 1); >+ // Round up the address to the required alignment. >+ identity = reinterpret_cast<base_internal::ThreadIdentity*>( >+ RoundUp(reinterpret_cast<intptr_t>(allocation), >+ base_internal::PerThreadSynch::kAlignment)); >+ } >+ memset(identity, 0, sizeof(*identity)); >+ >+ return identity; >+} >+ >+// Allocates and attaches ThreadIdentity object for the calling thread. Returns >+// the new identity. >+// REQUIRES: CurrentThreadIdentity(false) == nullptr >+base_internal::ThreadIdentity* CreateThreadIdentity() { >+ base_internal::ThreadIdentity* identity = NewThreadIdentity(); >+ PerThreadSem::Init(identity); >+ // Associate the value with the current thread, and attach our destructor. >+ base_internal::SetCurrentThreadIdentity(identity, ReclaimThreadIdentity); >+ return identity; >+} >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h >new file mode 100644 >index 00000000000..1bb87dee630 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/create_thread_identity.h >@@ -0,0 +1,53 @@ >+/* >+ * Copyright 2017 The Abseil Authors. >+ * >+ * Licensed under the Apache License, Version 2.0 (the "License"); >+ * you may not use this file except in compliance with the License. >+ * You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ */ >+ >+// Interface for getting the current ThreadIdentity, creating one if necessary. >+// See thread_identity.h. >+// >+// This file is separate from thread_identity.h because creating a new >+// ThreadIdentity requires slightly higher level libraries (per_thread_sem >+// and low_level_alloc) than accessing an existing one. This separation allows >+// us to have a smaller //absl/base:base. >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ >+ >+#include "absl/base/internal/thread_identity.h" >+#include "absl/base/port.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// Allocates and attaches a ThreadIdentity object for the calling thread. >+// For private use only. >+base_internal::ThreadIdentity* CreateThreadIdentity(); >+ >+// Returns the ThreadIdentity object representing the calling thread; guaranteed >+// to be unique for its lifetime. The returned object will remain valid for the >+// program's lifetime; although it may be re-assigned to a subsequent thread. >+// If one does not exist for the calling thread, allocate it now. >+inline base_internal::ThreadIdentity* GetOrCreateCurrentThreadIdentity() { >+ base_internal::ThreadIdentity* identity = >+ base_internal::CurrentThreadIdentityIfPresent(); >+ if (ABSL_PREDICT_FALSE(identity == nullptr)) { >+ return CreateThreadIdentity(); >+ } >+ return identity; >+} >+ >+} // namespace synchronization_internal >+} // namespace absl >+#endif // ABSL_SYNCHRONIZATION_INTERNAL_CREATE_THREAD_IDENTITY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc >new file mode 100644 >index 00000000000..ab1f3f84e74 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.cc >@@ -0,0 +1,699 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// GraphCycles provides incremental cycle detection on a dynamic >+// graph using the following algorithm: >+// >+// A dynamic topological sort algorithm for directed acyclic graphs >+// David J. Pearce, Paul H. J. Kelly >+// Journal of Experimental Algorithmics (JEA) JEA Homepage archive >+// Volume 11, 2006, Article No. 1.7 >+// >+// Brief summary of the algorithm: >+// >+// (1) Maintain a rank for each node that is consistent >+// with the topological sort of the graph. I.e., path from x to y >+// implies rank[x] < rank[y]. >+// (2) When a new edge (x->y) is inserted, do nothing if rank[x] < rank[y]. >+// (3) Otherwise: adjust ranks in the neighborhood of x and y. >+ >+#include "absl/base/attributes.h" >+// This file is a no-op if the required LowLevelAlloc support is missing. >+#include "absl/base/internal/low_level_alloc.h" >+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING >+ >+#include "absl/synchronization/internal/graphcycles.h" >+ >+#include <algorithm> >+#include <array> >+#include "absl/base/internal/hide_ptr.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+ >+// Do not use STL. This module does not use standard memory allocation. >+ >+namespace absl { >+namespace synchronization_internal { >+ >+namespace { >+ >+// Avoid LowLevelAlloc's default arena since it calls malloc hooks in >+// which people are doing things like acquiring Mutexes. >+static absl::base_internal::SpinLock arena_mu( >+ absl::base_internal::kLinkerInitialized); >+static base_internal::LowLevelAlloc::Arena* arena; >+ >+static void InitArenaIfNecessary() { >+ arena_mu.Lock(); >+ if (arena == nullptr) { >+ arena = base_internal::LowLevelAlloc::NewArena(0); >+ } >+ arena_mu.Unlock(); >+} >+ >+// Number of inlined elements in Vec. Hash table implementation >+// relies on this being a power of two. >+static const uint32_t kInline = 8; >+ >+// A simple LowLevelAlloc based resizable vector with inlined storage >+// for a few elements. T must be a plain type since constructor >+// and destructor are not run on elements of type T managed by Vec. >+template <typename T> >+class Vec { >+ public: >+ Vec() { Init(); } >+ ~Vec() { Discard(); } >+ >+ void clear() { >+ Discard(); >+ Init(); >+ } >+ >+ bool empty() const { return size_ == 0; } >+ uint32_t size() const { return size_; } >+ T* begin() { return ptr_; } >+ T* end() { return ptr_ + size_; } >+ const T& operator[](uint32_t i) const { return ptr_[i]; } >+ T& operator[](uint32_t i) { return ptr_[i]; } >+ const T& back() const { return ptr_[size_-1]; } >+ void pop_back() { size_--; } >+ >+ void push_back(const T& v) { >+ if (size_ == capacity_) Grow(size_ + 1); >+ ptr_[size_] = v; >+ size_++; >+ } >+ >+ void resize(uint32_t n) { >+ if (n > capacity_) Grow(n); >+ size_ = n; >+ } >+ >+ void fill(const T& val) { >+ for (uint32_t i = 0; i < size(); i++) { >+ ptr_[i] = val; >+ } >+ } >+ >+ // Guarantees src is empty at end. >+ // Provided for the hash table resizing code below. >+ void MoveFrom(Vec<T>* src) { >+ if (src->ptr_ == src->space_) { >+ // Need to actually copy >+ resize(src->size_); >+ std::copy(src->ptr_, src->ptr_ + src->size_, ptr_); >+ src->size_ = 0; >+ } else { >+ Discard(); >+ ptr_ = src->ptr_; >+ size_ = src->size_; >+ capacity_ = src->capacity_; >+ src->Init(); >+ } >+ } >+ >+ private: >+ T* ptr_; >+ T space_[kInline]; >+ uint32_t size_; >+ uint32_t capacity_; >+ >+ void Init() { >+ ptr_ = space_; >+ size_ = 0; >+ capacity_ = kInline; >+ } >+ >+ void Discard() { >+ if (ptr_ != space_) base_internal::LowLevelAlloc::Free(ptr_); >+ } >+ >+ void Grow(uint32_t n) { >+ while (capacity_ < n) { >+ capacity_ *= 2; >+ } >+ size_t request = static_cast<size_t>(capacity_) * sizeof(T); >+ T* copy = static_cast<T*>( >+ base_internal::LowLevelAlloc::AllocWithArena(request, arena)); >+ std::copy(ptr_, ptr_ + size_, copy); >+ Discard(); >+ ptr_ = copy; >+ } >+ >+ Vec(const Vec&) = delete; >+ Vec& operator=(const Vec&) = delete; >+}; >+ >+// A hash set of non-negative int32_t that uses Vec for its underlying storage. >+class NodeSet { >+ public: >+ NodeSet() { Init(); } >+ >+ void clear() { Init(); } >+ bool contains(int32_t v) const { return table_[FindIndex(v)] == v; } >+ >+ bool insert(int32_t v) { >+ uint32_t i = FindIndex(v); >+ if (table_[i] == v) { >+ return false; >+ } >+ if (table_[i] == kEmpty) { >+ // Only inserting over an empty cell increases the number of occupied >+ // slots. >+ occupied_++; >+ } >+ table_[i] = v; >+ // Double when 75% full. >+ if (occupied_ >= table_.size() - table_.size()/4) Grow(); >+ return true; >+ } >+ >+ void erase(uint32_t v) { >+ uint32_t i = FindIndex(v); >+ if (static_cast<uint32_t>(table_[i]) == v) { >+ table_[i] = kDel; >+ } >+ } >+ >+ // Iteration: is done via HASH_FOR_EACH >+ // Example: >+ // HASH_FOR_EACH(elem, node->out) { ... } >+#define HASH_FOR_EACH(elem, eset) \ >+ for (int32_t elem, _cursor = 0; (eset).Next(&_cursor, &elem); ) >+ bool Next(int32_t* cursor, int32_t* elem) { >+ while (static_cast<uint32_t>(*cursor) < table_.size()) { >+ int32_t v = table_[*cursor]; >+ (*cursor)++; >+ if (v >= 0) { >+ *elem = v; >+ return true; >+ } >+ } >+ return false; >+ } >+ >+ private: >+ static const int32_t kEmpty; >+ static const int32_t kDel; >+ Vec<int32_t> table_; >+ uint32_t occupied_; // Count of non-empty slots (includes deleted slots) >+ >+ static uint32_t Hash(uint32_t a) { return a * 41; } >+ >+ // Return index for storing v. May return an empty index or deleted index >+ int FindIndex(int32_t v) const { >+ // Search starting at hash index. >+ const uint32_t mask = table_.size() - 1; >+ uint32_t i = Hash(v) & mask; >+ int deleted_index = -1; // If >= 0, index of first deleted element we see >+ while (true) { >+ int32_t e = table_[i]; >+ if (v == e) { >+ return i; >+ } else if (e == kEmpty) { >+ // Return any previously encountered deleted slot. >+ return (deleted_index >= 0) ? deleted_index : i; >+ } else if (e == kDel && deleted_index < 0) { >+ // Keep searching since v might be present later. >+ deleted_index = i; >+ } >+ i = (i + 1) & mask; // Linear probing; quadratic is slightly slower. >+ } >+ } >+ >+ void Init() { >+ table_.clear(); >+ table_.resize(kInline); >+ table_.fill(kEmpty); >+ occupied_ = 0; >+ } >+ >+ void Grow() { >+ Vec<int32_t> copy; >+ copy.MoveFrom(&table_); >+ occupied_ = 0; >+ table_.resize(copy.size() * 2); >+ table_.fill(kEmpty); >+ >+ for (const auto& e : copy) { >+ if (e >= 0) insert(e); >+ } >+ } >+ >+ NodeSet(const NodeSet&) = delete; >+ NodeSet& operator=(const NodeSet&) = delete; >+}; >+ >+const int32_t NodeSet::kEmpty = -1; >+const int32_t NodeSet::kDel = -2; >+ >+// We encode a node index and a node version in GraphId. The version >+// number is incremented when the GraphId is freed which automatically >+// invalidates all copies of the GraphId. >+ >+inline GraphId MakeId(int32_t index, uint32_t version) { >+ GraphId g; >+ g.handle = >+ (static_cast<uint64_t>(version) << 32) | static_cast<uint32_t>(index); >+ return g; >+} >+ >+inline int32_t NodeIndex(GraphId id) { >+ return static_cast<uint32_t>(id.handle & 0xfffffffful); >+} >+ >+inline uint32_t NodeVersion(GraphId id) { >+ return static_cast<uint32_t>(id.handle >> 32); >+} >+ >+struct Node { >+ int32_t rank; // rank number assigned by Pearce-Kelly algorithm >+ uint32_t version; // Current version number >+ int32_t next_hash; // Next entry in hash table >+ bool visited; // Temporary marker used by depth-first-search >+ uintptr_t masked_ptr; // User-supplied pointer >+ NodeSet in; // List of immediate predecessor nodes in graph >+ NodeSet out; // List of immediate successor nodes in graph >+ int priority; // Priority of recorded stack trace. >+ int nstack; // Depth of recorded stack trace. >+ void* stack[40]; // stack[0,nstack-1] holds stack trace for node. >+}; >+ >+// Hash table for pointer to node index lookups. >+class PointerMap { >+ public: >+ explicit PointerMap(const Vec<Node*>* nodes) : nodes_(nodes) { >+ table_.fill(-1); >+ } >+ >+ int32_t Find(void* ptr) { >+ auto masked = base_internal::HidePtr(ptr); >+ for (int32_t i = table_[Hash(ptr)]; i != -1;) { >+ Node* n = (*nodes_)[i]; >+ if (n->masked_ptr == masked) return i; >+ i = n->next_hash; >+ } >+ return -1; >+ } >+ >+ void Add(void* ptr, int32_t i) { >+ int32_t* head = &table_[Hash(ptr)]; >+ (*nodes_)[i]->next_hash = *head; >+ *head = i; >+ } >+ >+ int32_t Remove(void* ptr) { >+ // Advance through linked list while keeping track of the >+ // predecessor slot that points to the current entry. >+ auto masked = base_internal::HidePtr(ptr); >+ for (int32_t* slot = &table_[Hash(ptr)]; *slot != -1; ) { >+ int32_t index = *slot; >+ Node* n = (*nodes_)[index]; >+ if (n->masked_ptr == masked) { >+ *slot = n->next_hash; // Remove n from linked list >+ n->next_hash = -1; >+ return index; >+ } >+ slot = &n->next_hash; >+ } >+ return -1; >+ } >+ >+ private: >+ // Number of buckets in hash table for pointer lookups. >+ static constexpr uint32_t kHashTableSize = 8171; // should be prime >+ >+ const Vec<Node*>* nodes_; >+ std::array<int32_t, kHashTableSize> table_; >+ >+ static uint32_t Hash(void* ptr) { >+ return reinterpret_cast<uintptr_t>(ptr) % kHashTableSize; >+ } >+}; >+ >+} // namespace >+ >+struct GraphCycles::Rep { >+ Vec<Node*> nodes_; >+ Vec<int32_t> free_nodes_; // Indices for unused entries in nodes_ >+ PointerMap ptrmap_; >+ >+ // Temporary state. >+ Vec<int32_t> deltaf_; // Results of forward DFS >+ Vec<int32_t> deltab_; // Results of backward DFS >+ Vec<int32_t> list_; // All nodes to reprocess >+ Vec<int32_t> merged_; // Rank values to assign to list_ entries >+ Vec<int32_t> stack_; // Emulates recursion stack for depth-first searches >+ >+ Rep() : ptrmap_(&nodes_) {} >+}; >+ >+static Node* FindNode(GraphCycles::Rep* rep, GraphId id) { >+ Node* n = rep->nodes_[NodeIndex(id)]; >+ return (n->version == NodeVersion(id)) ? n : nullptr; >+} >+ >+GraphCycles::GraphCycles() { >+ InitArenaIfNecessary(); >+ rep_ = new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Rep), arena)) >+ Rep; >+} >+ >+GraphCycles::~GraphCycles() { >+ for (auto* node : rep_->nodes_) { >+ node->Node::~Node(); >+ base_internal::LowLevelAlloc::Free(node); >+ } >+ rep_->Rep::~Rep(); >+ base_internal::LowLevelAlloc::Free(rep_); >+} >+ >+bool GraphCycles::CheckInvariants() const { >+ Rep* r = rep_; >+ NodeSet ranks; // Set of ranks seen so far. >+ for (uint32_t x = 0; x < r->nodes_.size(); x++) { >+ Node* nx = r->nodes_[x]; >+ void* ptr = base_internal::UnhidePtr<void>(nx->masked_ptr); >+ if (ptr != nullptr && static_cast<uint32_t>(r->ptrmap_.Find(ptr)) != x) { >+ ABSL_RAW_LOG(FATAL, "Did not find live node in hash table %u %p", x, ptr); >+ } >+ if (nx->visited) { >+ ABSL_RAW_LOG(FATAL, "Did not clear visited marker on node %u", x); >+ } >+ if (!ranks.insert(nx->rank)) { >+ ABSL_RAW_LOG(FATAL, "Duplicate occurrence of rank %d", nx->rank); >+ } >+ HASH_FOR_EACH(y, nx->out) { >+ Node* ny = r->nodes_[y]; >+ if (nx->rank >= ny->rank) { >+ ABSL_RAW_LOG(FATAL, "Edge %u->%d has bad rank assignment %d->%d", x, y, >+ nx->rank, ny->rank); >+ } >+ } >+ } >+ return true; >+} >+ >+GraphId GraphCycles::GetId(void* ptr) { >+ int32_t i = rep_->ptrmap_.Find(ptr); >+ if (i != -1) { >+ return MakeId(i, rep_->nodes_[i]->version); >+ } else if (rep_->free_nodes_.empty()) { >+ Node* n = >+ new (base_internal::LowLevelAlloc::AllocWithArena(sizeof(Node), arena)) >+ Node; >+ n->version = 1; // Avoid 0 since it is used by InvalidGraphId() >+ n->visited = false; >+ n->rank = rep_->nodes_.size(); >+ n->masked_ptr = base_internal::HidePtr(ptr); >+ n->nstack = 0; >+ n->priority = 0; >+ rep_->nodes_.push_back(n); >+ rep_->ptrmap_.Add(ptr, n->rank); >+ return MakeId(n->rank, n->version); >+ } else { >+ // Preserve preceding rank since the set of ranks in use must be >+ // a permutation of [0,rep_->nodes_.size()-1]. >+ int32_t r = rep_->free_nodes_.back(); >+ rep_->free_nodes_.pop_back(); >+ Node* n = rep_->nodes_[r]; >+ n->masked_ptr = base_internal::HidePtr(ptr); >+ n->nstack = 0; >+ n->priority = 0; >+ rep_->ptrmap_.Add(ptr, r); >+ return MakeId(r, n->version); >+ } >+} >+ >+void GraphCycles::RemoveNode(void* ptr) { >+ int32_t i = rep_->ptrmap_.Remove(ptr); >+ if (i == -1) { >+ return; >+ } >+ Node* x = rep_->nodes_[i]; >+ HASH_FOR_EACH(y, x->out) { >+ rep_->nodes_[y]->in.erase(i); >+ } >+ HASH_FOR_EACH(y, x->in) { >+ rep_->nodes_[y]->out.erase(i); >+ } >+ x->in.clear(); >+ x->out.clear(); >+ x->masked_ptr = base_internal::HidePtr<void>(nullptr); >+ if (x->version == std::numeric_limits<uint32_t>::max()) { >+ // Cannot use x any more >+ } else { >+ x->version++; // Invalidates all copies of node. >+ rep_->free_nodes_.push_back(i); >+ } >+} >+ >+void* GraphCycles::Ptr(GraphId id) { >+ Node* n = FindNode(rep_, id); >+ return n == nullptr ? nullptr >+ : base_internal::UnhidePtr<void>(n->masked_ptr); >+} >+ >+bool GraphCycles::HasNode(GraphId node) { >+ return FindNode(rep_, node) != nullptr; >+} >+ >+bool GraphCycles::HasEdge(GraphId x, GraphId y) const { >+ Node* xn = FindNode(rep_, x); >+ return xn && FindNode(rep_, y) && xn->out.contains(NodeIndex(y)); >+} >+ >+void GraphCycles::RemoveEdge(GraphId x, GraphId y) { >+ Node* xn = FindNode(rep_, x); >+ Node* yn = FindNode(rep_, y); >+ if (xn && yn) { >+ xn->out.erase(NodeIndex(y)); >+ yn->in.erase(NodeIndex(x)); >+ // No need to update the rank assignment since a previous valid >+ // rank assignment remains valid after an edge deletion. >+ } >+} >+ >+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound); >+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound); >+static void Reorder(GraphCycles::Rep* r); >+static void Sort(const Vec<Node*>&, Vec<int32_t>* delta); >+static void MoveToList( >+ GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst); >+ >+bool GraphCycles::InsertEdge(GraphId idx, GraphId idy) { >+ Rep* r = rep_; >+ const int32_t x = NodeIndex(idx); >+ const int32_t y = NodeIndex(idy); >+ Node* nx = FindNode(r, idx); >+ Node* ny = FindNode(r, idy); >+ if (nx == nullptr || ny == nullptr) return true; // Expired ids >+ >+ if (nx == ny) return false; // Self edge >+ if (!nx->out.insert(y)) { >+ // Edge already exists. >+ return true; >+ } >+ >+ ny->in.insert(x); >+ >+ if (nx->rank <= ny->rank) { >+ // New edge is consistent with existing rank assignment. >+ return true; >+ } >+ >+ // Current rank assignments are incompatible with the new edge. Recompute. >+ // We only need to consider nodes that fall in the range [ny->rank,nx->rank]. >+ if (!ForwardDFS(r, y, nx->rank)) { >+ // Found a cycle. Undo the insertion and tell caller. >+ nx->out.erase(y); >+ ny->in.erase(x); >+ // Since we do not call Reorder() on this path, clear any visited >+ // markers left by ForwardDFS. >+ for (const auto& d : r->deltaf_) { >+ r->nodes_[d]->visited = false; >+ } >+ return false; >+ } >+ BackwardDFS(r, x, ny->rank); >+ Reorder(r); >+ return true; >+} >+ >+static bool ForwardDFS(GraphCycles::Rep* r, int32_t n, int32_t upper_bound) { >+ // Avoid recursion since stack space might be limited. >+ // We instead keep a stack of nodes to visit. >+ r->deltaf_.clear(); >+ r->stack_.clear(); >+ r->stack_.push_back(n); >+ while (!r->stack_.empty()) { >+ n = r->stack_.back(); >+ r->stack_.pop_back(); >+ Node* nn = r->nodes_[n]; >+ if (nn->visited) continue; >+ >+ nn->visited = true; >+ r->deltaf_.push_back(n); >+ >+ HASH_FOR_EACH(w, nn->out) { >+ Node* nw = r->nodes_[w]; >+ if (nw->rank == upper_bound) { >+ return false; // Cycle >+ } >+ if (!nw->visited && nw->rank < upper_bound) { >+ r->stack_.push_back(w); >+ } >+ } >+ } >+ return true; >+} >+ >+static void BackwardDFS(GraphCycles::Rep* r, int32_t n, int32_t lower_bound) { >+ r->deltab_.clear(); >+ r->stack_.clear(); >+ r->stack_.push_back(n); >+ while (!r->stack_.empty()) { >+ n = r->stack_.back(); >+ r->stack_.pop_back(); >+ Node* nn = r->nodes_[n]; >+ if (nn->visited) continue; >+ >+ nn->visited = true; >+ r->deltab_.push_back(n); >+ >+ HASH_FOR_EACH(w, nn->in) { >+ Node* nw = r->nodes_[w]; >+ if (!nw->visited && lower_bound < nw->rank) { >+ r->stack_.push_back(w); >+ } >+ } >+ } >+} >+ >+static void Reorder(GraphCycles::Rep* r) { >+ Sort(r->nodes_, &r->deltab_); >+ Sort(r->nodes_, &r->deltaf_); >+ >+ // Adds contents of delta lists to list_ (backwards deltas first). >+ r->list_.clear(); >+ MoveToList(r, &r->deltab_, &r->list_); >+ MoveToList(r, &r->deltaf_, &r->list_); >+ >+ // Produce sorted list of all ranks that will be reassigned. >+ r->merged_.resize(r->deltab_.size() + r->deltaf_.size()); >+ std::merge(r->deltab_.begin(), r->deltab_.end(), >+ r->deltaf_.begin(), r->deltaf_.end(), >+ r->merged_.begin()); >+ >+ // Assign the ranks in order to the collected list. >+ for (uint32_t i = 0; i < r->list_.size(); i++) { >+ r->nodes_[r->list_[i]]->rank = r->merged_[i]; >+ } >+} >+ >+static void Sort(const Vec<Node*>& nodes, Vec<int32_t>* delta) { >+ struct ByRank { >+ const Vec<Node*>* nodes; >+ bool operator()(int32_t a, int32_t b) const { >+ return (*nodes)[a]->rank < (*nodes)[b]->rank; >+ } >+ }; >+ ByRank cmp; >+ cmp.nodes = &nodes; >+ std::sort(delta->begin(), delta->end(), cmp); >+} >+ >+static void MoveToList( >+ GraphCycles::Rep* r, Vec<int32_t>* src, Vec<int32_t>* dst) { >+ for (auto& v : *src) { >+ int32_t w = v; >+ v = r->nodes_[w]->rank; // Replace v entry with its rank >+ r->nodes_[w]->visited = false; // Prepare for future DFS calls >+ dst->push_back(w); >+ } >+} >+ >+int GraphCycles::FindPath(GraphId idx, GraphId idy, int max_path_len, >+ GraphId path[]) const { >+ Rep* r = rep_; >+ if (FindNode(r, idx) == nullptr || FindNode(r, idy) == nullptr) return 0; >+ const int32_t x = NodeIndex(idx); >+ const int32_t y = NodeIndex(idy); >+ >+ // Forward depth first search starting at x until we hit y. >+ // As we descend into a node, we push it onto the path. >+ // As we leave a node, we remove it from the path. >+ int path_len = 0; >+ >+ NodeSet seen; >+ r->stack_.clear(); >+ r->stack_.push_back(x); >+ while (!r->stack_.empty()) { >+ int32_t n = r->stack_.back(); >+ r->stack_.pop_back(); >+ if (n < 0) { >+ // Marker to indicate that we are leaving a node >+ path_len--; >+ continue; >+ } >+ >+ if (path_len < max_path_len) { >+ path[path_len] = MakeId(n, rep_->nodes_[n]->version); >+ } >+ path_len++; >+ r->stack_.push_back(-1); // Will remove tentative path entry >+ >+ if (n == y) { >+ return path_len; >+ } >+ >+ HASH_FOR_EACH(w, r->nodes_[n]->out) { >+ if (seen.insert(w)) { >+ r->stack_.push_back(w); >+ } >+ } >+ } >+ >+ return 0; >+} >+ >+bool GraphCycles::IsReachable(GraphId x, GraphId y) const { >+ return FindPath(x, y, 0, nullptr) > 0; >+} >+ >+void GraphCycles::UpdateStackTrace(GraphId id, int priority, >+ int (*get_stack_trace)(void** stack, int)) { >+ Node* n = FindNode(rep_, id); >+ if (n == nullptr || n->priority >= priority) { >+ return; >+ } >+ n->nstack = (*get_stack_trace)(n->stack, ABSL_ARRAYSIZE(n->stack)); >+ n->priority = priority; >+} >+ >+int GraphCycles::GetStackTrace(GraphId id, void*** ptr) { >+ Node* n = FindNode(rep_, id); >+ if (n == nullptr) { >+ *ptr = nullptr; >+ return 0; >+ } else { >+ *ptr = n->stack; >+ return n->nstack; >+ } >+} >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h >new file mode 100644 >index 00000000000..2e6686a4c06 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles.h >@@ -0,0 +1,137 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_GRAPHCYCLES_H_ >+ >+// GraphCycles detects the introduction of a cycle into a directed >+// graph that is being built up incrementally. >+// >+// Nodes are identified by small integers. It is not possible to >+// record multiple edges with the same (source, destination) pair; >+// requests to add an edge where one already exists are silently >+// ignored. >+// >+// It is also not possible to introduce a cycle; an attempt to insert >+// an edge that would introduce a cycle fails and returns false. >+// >+// GraphCycles uses no internal locking; calls into it should be >+// serialized externally. >+ >+// Performance considerations: >+// Works well on sparse graphs, poorly on dense graphs. >+// Extra information is maintained incrementally to detect cycles quickly. >+// InsertEdge() is very fast when the edge already exists, and reasonably fast >+// otherwise. >+// FindPath() is linear in the size of the graph. >+// The current implemenation uses O(|V|+|E|) space. >+ >+#include <cstdint> >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// Opaque identifier for a graph node. >+struct GraphId { >+ uint64_t handle; >+ >+ bool operator==(const GraphId& x) const { return handle == x.handle; } >+ bool operator!=(const GraphId& x) const { return handle != x.handle; } >+}; >+ >+// Return an invalid graph id that will never be assigned by GraphCycles. >+inline GraphId InvalidGraphId() { >+ return GraphId{0}; >+} >+ >+class GraphCycles { >+ public: >+ GraphCycles(); >+ ~GraphCycles(); >+ >+ // Return the id to use for ptr, assigning one if necessary. >+ // Subsequent calls with the same ptr value will return the same id >+ // until Remove(). >+ GraphId GetId(void* ptr); >+ >+ // Remove "ptr" from the graph. Its corresponding node and all >+ // edges to and from it are removed. >+ void RemoveNode(void* ptr); >+ >+ // Return the pointer associated with id, or nullptr if id is not >+ // currently in the graph. >+ void* Ptr(GraphId id); >+ >+ // Attempt to insert an edge from source_node to dest_node. If the >+ // edge would introduce a cycle, return false without making any >+ // changes. Otherwise add the edge and return true. >+ bool InsertEdge(GraphId source_node, GraphId dest_node); >+ >+ // Remove any edge that exists from source_node to dest_node. >+ void RemoveEdge(GraphId source_node, GraphId dest_node); >+ >+ // Return whether node exists in the graph. >+ bool HasNode(GraphId node); >+ >+ // Return whether there is an edge directly from source_node to dest_node. >+ bool HasEdge(GraphId source_node, GraphId dest_node) const; >+ >+ // Return whether dest_node is reachable from source_node >+ // by following edges. >+ bool IsReachable(GraphId source_node, GraphId dest_node) const; >+ >+ // Find a path from "source" to "dest". If such a path exists, >+ // place the nodes on the path in the array path[], and return >+ // the number of nodes on the path. If the path is longer than >+ // max_path_len nodes, only the first max_path_len nodes are placed >+ // in path[]. The client should compare the return value with >+ // max_path_len" to see when this occurs. If no path exists, return >+ // 0. Any valid path stored in path[] will start with "source" and >+ // end with "dest". There is no guarantee that the path is the >+ // shortest, but no node will appear twice in the path, except the >+ // source and destination node if they are identical; therefore, the >+ // return value is at most one greater than the number of nodes in >+ // the graph. >+ int FindPath(GraphId source, GraphId dest, int max_path_len, >+ GraphId path[]) const; >+ >+ // Update the stack trace recorded for id with the current stack >+ // trace if the last time it was updated had a smaller priority >+ // than the priority passed on this call. >+ // >+ // *get_stack_trace is called to get the stack trace. >+ void UpdateStackTrace(GraphId id, int priority, >+ int (*get_stack_trace)(void**, int)); >+ >+ // Set *ptr to the beginning of the array that holds the recorded >+ // stack trace for id and return the depth of the stack trace. >+ int GetStackTrace(GraphId id, void*** ptr); >+ >+ // Check internal invariants. Crashes on failure, returns true on success. >+ // Expensive: should only be called from graphcycles_test.cc. >+ bool CheckInvariants() const; >+ >+ // ---------------------------------------------------- >+ struct Rep; >+ private: >+ Rep *rep_; // opaque representation >+ GraphCycles(const GraphCycles&) = delete; >+ GraphCycles& operator=(const GraphCycles&) = delete; >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc >new file mode 100644 >index 00000000000..a239c25c3a8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_benchmark.cc >@@ -0,0 +1,44 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/internal/graphcycles.h" >+ >+#include <algorithm> >+#include <cstdint> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace { >+ >+void BM_StressTest(benchmark::State& state) { >+ const int num_nodes = state.range(0); >+ while (state.KeepRunningBatch(num_nodes)) { >+ absl::synchronization_internal::GraphCycles g; >+ std::vector<absl::synchronization_internal::GraphId> nodes(num_nodes); >+ for (int i = 0; i < num_nodes; i++) { >+ nodes[i] = g.GetId(reinterpret_cast<void*>(static_cast<uintptr_t>(i))); >+ } >+ for (int i = 0; i < num_nodes; i++) { >+ int end = std::min(num_nodes, i + 5); >+ for (int j = i + 1; j < end; j++) { >+ ABSL_RAW_CHECK(g.InsertEdge(nodes[i], nodes[j]), ""); >+ } >+ } >+ } >+} >+BENCHMARK(BM_StressTest)->Range(2048, 1048576); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc >new file mode 100644 >index 00000000000..9a85b39074d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/graphcycles_test.cc >@@ -0,0 +1,462 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/internal/graphcycles.h" >+ >+#include <map> >+#include <random> >+#include <unordered_set> >+#include <utility> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/macros.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// We emulate a GraphCycles object with a node vector and an edge vector. >+// We then compare the two implementations. >+ >+using Nodes = std::vector<int>; >+struct Edge { >+ int from; >+ int to; >+}; >+using Edges = std::vector<Edge>; >+using RandomEngine = std::mt19937_64; >+ >+// Mapping from integer index to GraphId. >+typedef std::map<int, GraphId> IdMap; >+static GraphId Get(const IdMap& id, int num) { >+ auto iter = id.find(num); >+ return (iter == id.end()) ? InvalidGraphId() : iter->second; >+} >+ >+// Return whether "to" is reachable from "from". >+static bool IsReachable(Edges *edges, int from, int to, >+ std::unordered_set<int> *seen) { >+ seen->insert(from); // we are investigating "from"; don't do it again >+ if (from == to) return true; >+ for (const auto &edge : *edges) { >+ if (edge.from == from) { >+ if (edge.to == to) { // success via edge directly >+ return true; >+ } else if (seen->find(edge.to) == seen->end() && // success via edge >+ IsReachable(edges, edge.to, to, seen)) { >+ return true; >+ } >+ } >+ } >+ return false; >+} >+ >+static void PrintEdges(Edges *edges) { >+ ABSL_RAW_LOG(INFO, "EDGES (%zu)", edges->size()); >+ for (const auto &edge : *edges) { >+ int a = edge.from; >+ int b = edge.to; >+ ABSL_RAW_LOG(INFO, "%d %d", a, b); >+ } >+ ABSL_RAW_LOG(INFO, "---"); >+} >+ >+static void PrintGCEdges(Nodes *nodes, const IdMap &id, GraphCycles *gc) { >+ ABSL_RAW_LOG(INFO, "GC EDGES"); >+ for (int a : *nodes) { >+ for (int b : *nodes) { >+ if (gc->HasEdge(Get(id, a), Get(id, b))) { >+ ABSL_RAW_LOG(INFO, "%d %d", a, b); >+ } >+ } >+ } >+ ABSL_RAW_LOG(INFO, "---"); >+} >+ >+static void PrintTransitiveClosure(Nodes *nodes, Edges *edges) { >+ ABSL_RAW_LOG(INFO, "Transitive closure"); >+ for (int a : *nodes) { >+ for (int b : *nodes) { >+ std::unordered_set<int> seen; >+ if (IsReachable(edges, a, b, &seen)) { >+ ABSL_RAW_LOG(INFO, "%d %d", a, b); >+ } >+ } >+ } >+ ABSL_RAW_LOG(INFO, "---"); >+} >+ >+static void PrintGCTransitiveClosure(Nodes *nodes, const IdMap &id, >+ GraphCycles *gc) { >+ ABSL_RAW_LOG(INFO, "GC Transitive closure"); >+ for (int a : *nodes) { >+ for (int b : *nodes) { >+ if (gc->IsReachable(Get(id, a), Get(id, b))) { >+ ABSL_RAW_LOG(INFO, "%d %d", a, b); >+ } >+ } >+ } >+ ABSL_RAW_LOG(INFO, "---"); >+} >+ >+static void CheckTransitiveClosure(Nodes *nodes, Edges *edges, const IdMap &id, >+ GraphCycles *gc) { >+ std::unordered_set<int> seen; >+ for (const auto &a : *nodes) { >+ for (const auto &b : *nodes) { >+ seen.clear(); >+ bool gc_reachable = gc->IsReachable(Get(id, a), Get(id, b)); >+ bool reachable = IsReachable(edges, a, b, &seen); >+ if (gc_reachable != reachable) { >+ PrintEdges(edges); >+ PrintGCEdges(nodes, id, gc); >+ PrintTransitiveClosure(nodes, edges); >+ PrintGCTransitiveClosure(nodes, id, gc); >+ ABSL_RAW_LOG(FATAL, "gc_reachable %s reachable %s a %d b %d", >+ gc_reachable ? "true" : "false", >+ reachable ? "true" : "false", a, b); >+ } >+ } >+ } >+} >+ >+static void CheckEdges(Nodes *nodes, Edges *edges, const IdMap &id, >+ GraphCycles *gc) { >+ int count = 0; >+ for (const auto &edge : *edges) { >+ int a = edge.from; >+ int b = edge.to; >+ if (!gc->HasEdge(Get(id, a), Get(id, b))) { >+ PrintEdges(edges); >+ PrintGCEdges(nodes, id, gc); >+ ABSL_RAW_LOG(FATAL, "!gc->HasEdge(%d, %d)", a, b); >+ } >+ } >+ for (const auto &a : *nodes) { >+ for (const auto &b : *nodes) { >+ if (gc->HasEdge(Get(id, a), Get(id, b))) { >+ count++; >+ } >+ } >+ } >+ if (count != edges->size()) { >+ PrintEdges(edges); >+ PrintGCEdges(nodes, id, gc); >+ ABSL_RAW_LOG(FATAL, "edges->size() %zu count %d", edges->size(), count); >+ } >+} >+ >+static void CheckInvariants(const GraphCycles &gc) { >+ if (ABSL_PREDICT_FALSE(!gc.CheckInvariants())) >+ ABSL_RAW_LOG(FATAL, "CheckInvariants"); >+} >+ >+// Returns the index of a randomly chosen node in *nodes. >+// Requires *nodes be non-empty. >+static int RandomNode(RandomEngine* rng, Nodes *nodes) { >+ std::uniform_int_distribution<int> uniform(0, nodes->size()-1); >+ return uniform(*rng); >+} >+ >+// Returns the index of a randomly chosen edge in *edges. >+// Requires *edges be non-empty. >+static int RandomEdge(RandomEngine* rng, Edges *edges) { >+ std::uniform_int_distribution<int> uniform(0, edges->size()-1); >+ return uniform(*rng); >+} >+ >+// Returns the index of edge (from, to) in *edges or -1 if it is not in *edges. >+static int EdgeIndex(Edges *edges, int from, int to) { >+ int i = 0; >+ while (i != edges->size() && >+ ((*edges)[i].from != from || (*edges)[i].to != to)) { >+ i++; >+ } >+ return i == edges->size()? -1 : i; >+} >+ >+TEST(GraphCycles, RandomizedTest) { >+ int next_node = 0; >+ Nodes nodes; >+ Edges edges; // from, to >+ IdMap id; >+ GraphCycles graph_cycles; >+ static const int kMaxNodes = 7; // use <= 7 nodes to keep test short >+ static const int kDataOffset = 17; // an offset to the node-specific data >+ int n = 100000; >+ int op = 0; >+ RandomEngine rng(testing::UnitTest::GetInstance()->random_seed()); >+ std::uniform_int_distribution<int> uniform(0, 5); >+ >+ auto ptr = [](intptr_t i) { >+ return reinterpret_cast<void*>(i + kDataOffset); >+ }; >+ >+ for (int iter = 0; iter != n; iter++) { >+ for (const auto &node : nodes) { >+ ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), ptr(node)) << " node " << node; >+ } >+ CheckEdges(&nodes, &edges, id, &graph_cycles); >+ CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles); >+ op = uniform(rng); >+ switch (op) { >+ case 0: // Add a node >+ if (nodes.size() < kMaxNodes) { >+ int new_node = next_node++; >+ GraphId new_gnode = graph_cycles.GetId(ptr(new_node)); >+ ASSERT_NE(new_gnode, InvalidGraphId()); >+ id[new_node] = new_gnode; >+ ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode)); >+ nodes.push_back(new_node); >+ } >+ break; >+ >+ case 1: // Remove a node >+ if (nodes.size() > 0) { >+ int node_index = RandomNode(&rng, &nodes); >+ int node = nodes[node_index]; >+ nodes[node_index] = nodes.back(); >+ nodes.pop_back(); >+ graph_cycles.RemoveNode(ptr(node)); >+ ASSERT_EQ(graph_cycles.Ptr(Get(id, node)), nullptr); >+ id.erase(node); >+ int i = 0; >+ while (i != edges.size()) { >+ if (edges[i].from == node || edges[i].to == node) { >+ edges[i] = edges.back(); >+ edges.pop_back(); >+ } else { >+ i++; >+ } >+ } >+ } >+ break; >+ >+ case 2: // Add an edge >+ if (nodes.size() > 0) { >+ int from = RandomNode(&rng, &nodes); >+ int to = RandomNode(&rng, &nodes); >+ if (EdgeIndex(&edges, nodes[from], nodes[to]) == -1) { >+ if (graph_cycles.InsertEdge(id[nodes[from]], id[nodes[to]])) { >+ Edge new_edge; >+ new_edge.from = nodes[from]; >+ new_edge.to = nodes[to]; >+ edges.push_back(new_edge); >+ } else { >+ std::unordered_set<int> seen; >+ ASSERT_TRUE(IsReachable(&edges, nodes[to], nodes[from], &seen)) >+ << "Edge " << nodes[to] << "->" << nodes[from]; >+ } >+ } >+ } >+ break; >+ >+ case 3: // Remove an edge >+ if (edges.size() > 0) { >+ int i = RandomEdge(&rng, &edges); >+ int from = edges[i].from; >+ int to = edges[i].to; >+ ASSERT_EQ(i, EdgeIndex(&edges, from, to)); >+ edges[i] = edges.back(); >+ edges.pop_back(); >+ ASSERT_EQ(-1, EdgeIndex(&edges, from, to)); >+ graph_cycles.RemoveEdge(id[from], id[to]); >+ } >+ break; >+ >+ case 4: // Check a path >+ if (nodes.size() > 0) { >+ int from = RandomNode(&rng, &nodes); >+ int to = RandomNode(&rng, &nodes); >+ GraphId path[2*kMaxNodes]; >+ int path_len = graph_cycles.FindPath(id[nodes[from]], id[nodes[to]], >+ ABSL_ARRAYSIZE(path), path); >+ std::unordered_set<int> seen; >+ bool reachable = IsReachable(&edges, nodes[from], nodes[to], &seen); >+ bool gc_reachable = >+ graph_cycles.IsReachable(Get(id, nodes[from]), Get(id, nodes[to])); >+ ASSERT_EQ(path_len != 0, reachable); >+ ASSERT_EQ(path_len != 0, gc_reachable); >+ // In the following line, we add one because a node can appear >+ // twice, if the path is from that node to itself, perhaps via >+ // every other node. >+ ASSERT_LE(path_len, kMaxNodes + 1); >+ if (path_len != 0) { >+ ASSERT_EQ(id[nodes[from]], path[0]); >+ ASSERT_EQ(id[nodes[to]], path[path_len-1]); >+ for (int i = 1; i < path_len; i++) { >+ ASSERT_TRUE(graph_cycles.HasEdge(path[i-1], path[i])); >+ } >+ } >+ } >+ break; >+ >+ case 5: // Check invariants >+ CheckInvariants(graph_cycles); >+ break; >+ >+ default: >+ ABSL_RAW_LOG(FATAL, "op %d", op); >+ } >+ >+ // Very rarely, test graph expansion by adding then removing many nodes. >+ std::bernoulli_distribution one_in_1024(1.0 / 1024); >+ if (one_in_1024(rng)) { >+ CheckEdges(&nodes, &edges, id, &graph_cycles); >+ CheckTransitiveClosure(&nodes, &edges, id, &graph_cycles); >+ for (int i = 0; i != 256; i++) { >+ int new_node = next_node++; >+ GraphId new_gnode = graph_cycles.GetId(ptr(new_node)); >+ ASSERT_NE(InvalidGraphId(), new_gnode); >+ id[new_node] = new_gnode; >+ ASSERT_EQ(ptr(new_node), graph_cycles.Ptr(new_gnode)); >+ for (const auto &node : nodes) { >+ ASSERT_NE(node, new_node); >+ } >+ nodes.push_back(new_node); >+ } >+ for (int i = 0; i != 256; i++) { >+ ASSERT_GT(nodes.size(), 0); >+ int node_index = RandomNode(&rng, &nodes); >+ int node = nodes[node_index]; >+ nodes[node_index] = nodes.back(); >+ nodes.pop_back(); >+ graph_cycles.RemoveNode(ptr(node)); >+ id.erase(node); >+ int j = 0; >+ while (j != edges.size()) { >+ if (edges[j].from == node || edges[j].to == node) { >+ edges[j] = edges.back(); >+ edges.pop_back(); >+ } else { >+ j++; >+ } >+ } >+ } >+ CheckInvariants(graph_cycles); >+ } >+ } >+} >+ >+class GraphCyclesTest : public ::testing::Test { >+ public: >+ IdMap id_; >+ GraphCycles g_; >+ >+ static void* Ptr(int i) { >+ return reinterpret_cast<void*>(static_cast<uintptr_t>(i)); >+ } >+ >+ static int Num(void* ptr) { >+ return static_cast<int>(reinterpret_cast<uintptr_t>(ptr)); >+ } >+ >+ // Test relies on ith NewNode() call returning Node numbered i >+ GraphCyclesTest() { >+ for (int i = 0; i < 100; i++) { >+ id_[i] = g_.GetId(Ptr(i)); >+ } >+ CheckInvariants(g_); >+ } >+ >+ bool AddEdge(int x, int y) { >+ return g_.InsertEdge(Get(id_, x), Get(id_, y)); >+ } >+ >+ void AddMultiples() { >+ // For every node x > 0: add edge to 2*x, 3*x >+ for (int x = 1; x < 25; x++) { >+ EXPECT_TRUE(AddEdge(x, 2*x)) << x; >+ EXPECT_TRUE(AddEdge(x, 3*x)) << x; >+ } >+ CheckInvariants(g_); >+ } >+ >+ std::string Path(int x, int y) { >+ GraphId path[5]; >+ int np = g_.FindPath(Get(id_, x), Get(id_, y), ABSL_ARRAYSIZE(path), path); >+ std::string result; >+ for (int i = 0; i < np; i++) { >+ if (i >= ABSL_ARRAYSIZE(path)) { >+ result += " ..."; >+ break; >+ } >+ if (!result.empty()) result.push_back(' '); >+ char buf[20]; >+ snprintf(buf, sizeof(buf), "%d", Num(g_.Ptr(path[i]))); >+ result += buf; >+ } >+ return result; >+ } >+}; >+ >+TEST_F(GraphCyclesTest, NoCycle) { >+ AddMultiples(); >+ CheckInvariants(g_); >+} >+ >+TEST_F(GraphCyclesTest, SimpleCycle) { >+ AddMultiples(); >+ EXPECT_FALSE(AddEdge(8, 4)); >+ EXPECT_EQ("4 8", Path(4, 8)); >+ CheckInvariants(g_); >+} >+ >+TEST_F(GraphCyclesTest, IndirectCycle) { >+ AddMultiples(); >+ EXPECT_TRUE(AddEdge(16, 9)); >+ CheckInvariants(g_); >+ EXPECT_FALSE(AddEdge(9, 2)); >+ EXPECT_EQ("2 4 8 16 9", Path(2, 9)); >+ CheckInvariants(g_); >+} >+ >+TEST_F(GraphCyclesTest, LongPath) { >+ ASSERT_TRUE(AddEdge(2, 4)); >+ ASSERT_TRUE(AddEdge(4, 6)); >+ ASSERT_TRUE(AddEdge(6, 8)); >+ ASSERT_TRUE(AddEdge(8, 10)); >+ ASSERT_TRUE(AddEdge(10, 12)); >+ ASSERT_FALSE(AddEdge(12, 2)); >+ EXPECT_EQ("2 4 6 8 10 ...", Path(2, 12)); >+ CheckInvariants(g_); >+} >+ >+TEST_F(GraphCyclesTest, RemoveNode) { >+ ASSERT_TRUE(AddEdge(1, 2)); >+ ASSERT_TRUE(AddEdge(2, 3)); >+ ASSERT_TRUE(AddEdge(3, 4)); >+ ASSERT_TRUE(AddEdge(4, 5)); >+ g_.RemoveNode(g_.Ptr(id_[3])); >+ id_.erase(3); >+ ASSERT_TRUE(AddEdge(5, 1)); >+} >+ >+TEST_F(GraphCyclesTest, ManyEdges) { >+ const int N = 50; >+ for (int i = 0; i < N; i++) { >+ for (int j = 1; j < N; j++) { >+ ASSERT_TRUE(AddEdge(i, i+j)); >+ } >+ } >+ CheckInvariants(g_); >+ ASSERT_TRUE(AddEdge(2*N-1, 0)); >+ CheckInvariants(g_); >+ ASSERT_FALSE(AddEdge(10, 9)); >+ CheckInvariants(g_); >+} >+ >+} // namespace synchronization_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h >new file mode 100644 >index 00000000000..bb7080004c7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h >@@ -0,0 +1,151 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// An optional absolute timeout, with nanosecond granularity, >+// compatible with absl::Time. Suitable for in-register >+// parameter-passing (e.g. syscalls.) >+// Constructible from a absl::Time (for a timeout to be respected) or {} >+// (for "no timeout".) >+// This is a private low-level API for use by a handful of low-level >+// components that are friends of this class. Higher-level components >+// should build APIs based on absl::Time and absl::Duration. >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ >+ >+#include <time.h> >+#include <algorithm> >+#include <limits> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/time/clock.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+class Futex; >+class Waiter; >+ >+class KernelTimeout { >+ public: >+ // A timeout that should expire at <t>. Any value, in the full >+ // InfinitePast() to InfiniteFuture() range, is valid here and will be >+ // respected. >+ explicit KernelTimeout(absl::Time t) : ns_(MakeNs(t)) {} >+ // No timeout. >+ KernelTimeout() : ns_(0) {} >+ >+ // A more explicit factory for those who prefer it. Equivalent to {}. >+ static KernelTimeout Never() { return {}; } >+ >+ // We explicitly do not support other custom formats: timespec, int64_t nanos. >+ // Unify on this and absl::Time, please. >+ bool has_timeout() const { return ns_ != 0; } >+ >+ private: >+ // internal rep, not user visible: ns after unix epoch. >+ // zero = no timeout. >+ // Negative we treat as an unlikely (and certainly expired!) but valid >+ // timeout. >+ int64_t ns_; >+ >+ static int64_t MakeNs(absl::Time t) { >+ // optimization--InfiniteFuture is common "no timeout" value >+ // and cheaper to compare than convert. >+ if (t == absl::InfiniteFuture()) return 0; >+ int64_t x = ToUnixNanos(t); >+ >+ // A timeout that lands exactly on the epoch (x=0) needs to be respected, >+ // so we alter it unnoticably to 1. Negative timeouts are in >+ // theory supported, but handled poorly by the kernel (long >+ // delays) so push them forward too; since all such times have >+ // already passed, it's indistinguishable. >+ if (x <= 0) x = 1; >+ // A time larger than what can be represented to the kernel is treated >+ // as no timeout. >+ if (x == std::numeric_limits<int64_t>::max()) x = 0; >+ return x; >+ } >+ >+ // Convert to parameter for sem_timedwait/futex/similar. Only for approved >+ // users. Do not call if !has_timeout. >+ struct timespec MakeAbsTimespec() { >+ int64_t n = ns_; >+ static const int64_t kNanosPerSecond = 1000 * 1000 * 1000; >+ if (n == 0) { >+ ABSL_RAW_LOG( >+ ERROR, >+ "Tried to create a timespec from a non-timeout; never do this."); >+ // But we'll try to continue sanely. no-timeout ~= saturated timeout. >+ n = std::numeric_limits<int64_t>::max(); >+ } >+ >+ // Kernel APIs validate timespecs as being at or after the epoch, >+ // despite the kernel time type being signed. However, no one can >+ // tell the difference between a timeout at or before the epoch (since >+ // all such timeouts have expired!) >+ if (n < 0) n = 0; >+ >+ struct timespec abstime; >+ int64_t seconds = std::min(n / kNanosPerSecond, >+ int64_t{std::numeric_limits<time_t>::max()}); >+ abstime.tv_sec = static_cast<time_t>(seconds); >+ abstime.tv_nsec = >+ static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond); >+ return abstime; >+ } >+ >+#ifdef _WIN32 >+ // Converts to milliseconds from now, or INFINITE when >+ // !has_timeout(). For use by SleepConditionVariableSRW on >+ // Windows. Callers should recognize that the return value is a >+ // relative duration (it should be recomputed by calling this method >+ // in the case of a spurious wakeup). >+ // This header file may be included transitively by public header files, >+ // so we define our own DWORD and INFINITE instead of getting them from >+ // <intsafe.h> and <WinBase.h>. >+ typedef unsigned long DWord; // NOLINT >+ DWord InMillisecondsFromNow() const { >+ constexpr DWord kInfinite = std::numeric_limits<DWord>::max(); >+ if (!has_timeout()) { >+ return kInfinite; >+ } >+ // The use of absl::Now() to convert from absolute time to >+ // relative time means that absl::Now() cannot use anything that >+ // depends on KernelTimeout (for example, Mutex) on Windows. >+ int64_t now = ToUnixNanos(absl::Now()); >+ if (ns_ >= now) { >+ // Round up so that Now() + ms_from_now >= ns_. >+ constexpr uint64_t max_nanos = >+ std::numeric_limits<int64_t>::max() - 999999u; >+ uint64_t ms_from_now = >+ (std::min<uint64_t>(max_nanos, ns_ - now) + 999999u) / 1000000u; >+ if (ms_from_now > kInfinite) { >+ return kInfinite; >+ } >+ return static_cast<DWord>(ms_from_now); >+ } >+ return 0; >+ } >+#endif >+ >+ friend class Futex; >+ friend class Waiter; >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >+#endif // ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc >new file mode 100644 >index 00000000000..45c60326dba >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.cc >@@ -0,0 +1,318 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Implementation of a small subset of Mutex and CondVar functionality >+// for platforms where the production implementation hasn't been fully >+// ported yet. >+ >+#include "absl/synchronization/mutex.h" >+ >+#if defined(_WIN32) >+#include <chrono> // NOLINT(build/c++11) >+#else >+#include <sys/time.h> >+#include <time.h> >+#endif >+ >+#include <algorithm> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+namespace { >+ >+// Return the current time plus the timeout. >+absl::Time DeadlineFromTimeout(absl::Duration timeout) { >+ return absl::Now() + timeout; >+} >+ >+// Limit the deadline to a positive, 32-bit time_t value to accommodate >+// implementation restrictions. This also deals with InfinitePast and >+// InfiniteFuture. >+absl::Time LimitedDeadline(absl::Time deadline) { >+ deadline = std::max(absl::FromTimeT(0), deadline); >+ deadline = std::min(deadline, absl::FromTimeT(0x7fffffff)); >+ return deadline; >+} >+ >+} // namespace >+ >+#if defined(_WIN32) >+ >+MutexImpl::MutexImpl() {} >+ >+MutexImpl::~MutexImpl() { >+ if (locked_) { >+ std_mutex_.unlock(); >+ } >+} >+ >+void MutexImpl::Lock() { >+ std_mutex_.lock(); >+ locked_ = true; >+} >+ >+bool MutexImpl::TryLock() { >+ bool locked = std_mutex_.try_lock(); >+ if (locked) locked_ = true; >+ return locked; >+} >+ >+void MutexImpl::Unlock() { >+ locked_ = false; >+ released_.SignalAll(); >+ std_mutex_.unlock(); >+} >+ >+CondVarImpl::CondVarImpl() {} >+ >+CondVarImpl::~CondVarImpl() {} >+ >+void CondVarImpl::Signal() { std_cv_.notify_one(); } >+ >+void CondVarImpl::SignalAll() { std_cv_.notify_all(); } >+ >+void CondVarImpl::Wait(MutexImpl* mu) { >+ mu->released_.SignalAll(); >+ std_cv_.wait(mu->std_mutex_); >+} >+ >+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) { >+ mu->released_.SignalAll(); >+ time_t when = ToTimeT(deadline); >+ int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when)); >+ std::chrono::system_clock::time_point deadline_tp = >+ std::chrono::system_clock::from_time_t(when) + >+ std::chrono::duration_cast<std::chrono::system_clock::duration>( >+ std::chrono::nanoseconds(nanos)); >+ auto deadline_since_epoch = >+ std::chrono::duration_cast<std::chrono::duration<double>>( >+ deadline_tp - std::chrono::system_clock::from_time_t(0)); >+ return std_cv_.wait_until(mu->std_mutex_, deadline_tp) == >+ std::cv_status::timeout; >+} >+ >+#else // ! _WIN32 >+ >+MutexImpl::MutexImpl() { >+ ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0, >+ "pthread error"); >+} >+ >+MutexImpl::~MutexImpl() { >+ if (locked_) { >+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error"); >+ } >+ ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error"); >+} >+ >+void MutexImpl::Lock() { >+ ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error"); >+ locked_ = true; >+} >+ >+bool MutexImpl::TryLock() { >+ bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_)); >+ if (locked) locked_ = true; >+ return locked; >+} >+ >+void MutexImpl::Unlock() { >+ locked_ = false; >+ released_.SignalAll(); >+ ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error"); >+} >+ >+CondVarImpl::CondVarImpl() { >+ ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0, >+ "pthread error"); >+} >+ >+CondVarImpl::~CondVarImpl() { >+ ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error"); >+} >+ >+void CondVarImpl::Signal() { >+ ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error"); >+} >+ >+void CondVarImpl::SignalAll() { >+ ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error"); >+} >+ >+void CondVarImpl::Wait(MutexImpl* mu) { >+ mu->released_.SignalAll(); >+ ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0, >+ "pthread error"); >+} >+ >+bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) { >+ mu->released_.SignalAll(); >+ struct timespec ts = ToTimespec(deadline); >+ int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts); >+ if (rc == ETIMEDOUT) return true; >+ ABSL_RAW_CHECK(rc == 0, "pthread error"); >+ return false; >+} >+ >+#endif // ! _WIN32 >+ >+void MutexImpl::Await(const Condition& cond) { >+ if (cond.Eval()) return; >+ released_.SignalAll(); >+ do { >+ released_.Wait(this); >+ } while (!cond.Eval()); >+} >+ >+bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) { >+ if (cond.Eval()) return true; >+ released_.SignalAll(); >+ while (true) { >+ if (released_.WaitWithDeadline(this, deadline)) return false; >+ if (cond.Eval()) return true; >+ } >+} >+ >+} // namespace synchronization_internal >+ >+Mutex::Mutex() {} >+ >+Mutex::~Mutex() {} >+ >+void Mutex::Lock() { impl()->Lock(); } >+ >+void Mutex::Unlock() { impl()->Unlock(); } >+ >+bool Mutex::TryLock() { return impl()->TryLock(); } >+ >+void Mutex::ReaderLock() { Lock(); } >+ >+void Mutex::ReaderUnlock() { Unlock(); } >+ >+void Mutex::Await(const Condition& cond) { impl()->Await(cond); } >+ >+void Mutex::LockWhen(const Condition& cond) { >+ Lock(); >+ Await(cond); >+} >+ >+bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) { >+ return impl()->AwaitWithDeadline( >+ cond, synchronization_internal::LimitedDeadline(deadline)); >+} >+ >+bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) { >+ return AwaitWithDeadline( >+ cond, synchronization_internal::DeadlineFromTimeout(timeout)); >+} >+ >+bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) { >+ Lock(); >+ return AwaitWithDeadline(cond, deadline); >+} >+ >+bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) { >+ return LockWhenWithDeadline( >+ cond, synchronization_internal::DeadlineFromTimeout(timeout)); >+} >+ >+void Mutex::ReaderLockWhen(const Condition& cond) { >+ ReaderLock(); >+ Await(cond); >+} >+ >+bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond, >+ absl::Duration timeout) { >+ return LockWhenWithTimeout(cond, timeout); >+} >+bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond, >+ absl::Time deadline) { >+ return LockWhenWithDeadline(cond, deadline); >+} >+ >+void Mutex::EnableDebugLog(const char*) {} >+void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {} >+void Mutex::ForgetDeadlockInfo() {} >+void Mutex::AssertHeld() const {} >+void Mutex::AssertReaderHeld() const {} >+void Mutex::AssertNotHeld() const {} >+ >+CondVar::CondVar() {} >+ >+CondVar::~CondVar() {} >+ >+void CondVar::Signal() { impl()->Signal(); } >+ >+void CondVar::SignalAll() { impl()->SignalAll(); } >+ >+void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); } >+ >+bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) { >+ return impl()->WaitWithDeadline( >+ mu->impl(), synchronization_internal::LimitedDeadline(deadline)); >+} >+ >+bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) { >+ return WaitWithDeadline(mu, absl::Now() + timeout); >+} >+ >+void CondVar::EnableDebugLog(const char*) {} >+ >+#ifdef THREAD_SANITIZER >+extern "C" void __tsan_read1(void *addr); >+#else >+#define __tsan_read1(addr) // do nothing if TSan not enabled >+#endif >+ >+// A function that just returns its argument, dereferenced >+static bool Dereference(void *arg) { >+ // ThreadSanitizer does not instrument this file for memory accesses. >+ // This function dereferences a user variable that can participate >+ // in a data race, so we need to manually tell TSan about this memory access. >+ __tsan_read1(arg); >+ return *(static_cast<bool *>(arg)); >+} >+ >+Condition::Condition() {} // null constructor, used for kTrue only >+const Condition Condition::kTrue; >+ >+Condition::Condition(bool (*func)(void *), void *arg) >+ : eval_(&CallVoidPtrFunction), >+ function_(func), >+ method_(nullptr), >+ arg_(arg) {} >+ >+bool Condition::CallVoidPtrFunction(const Condition *c) { >+ return (*c->function_)(c->arg_); >+} >+ >+Condition::Condition(const bool *cond) >+ : eval_(CallVoidPtrFunction), >+ function_(Dereference), >+ method_(nullptr), >+ // const_cast is safe since Dereference does not modify arg >+ arg_(const_cast<bool *>(cond)) {} >+ >+bool Condition::Eval() const { >+ // eval_ == null for kTrue >+ return (this->eval_ == nullptr) || (*this->eval_)(this); >+} >+ >+void RegisterSymbolizer(bool (*)(const void*, char*, int)) {} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc >new file mode 100644 >index 00000000000..0aab3d1314e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/mutex_nonprod.inc >@@ -0,0 +1,256 @@ >+// Do not include. This is an implementation detail of base/mutex.h. >+// >+// Declares three classes: >+// >+// base::internal::MutexImpl - implementation helper for Mutex >+// base::internal::CondVarImpl - implementation helper for CondVar >+// base::internal::SynchronizationStorage<T> - implementation helper for >+// Mutex, CondVar >+ >+#include <type_traits> >+ >+#if defined(_WIN32) >+#include <condition_variable> >+#include <mutex> >+#else >+#include <pthread.h> >+#endif >+ >+#include "absl/base/call_once.h" >+#include "absl/time/time.h" >+ >+// Declare that Mutex::ReaderLock is actually Lock(). Intended primarily >+// for tests, and even then as a last resort. >+#ifdef ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE >+#error ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE cannot be directly set >+#else >+#define ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE 1 >+#endif >+ >+// Declare that Mutex::EnableInvariantDebugging is not implemented. >+// Intended primarily for tests, and even then as a last resort. >+#ifdef ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED >+#error ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED cannot be directly set >+#else >+#define ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED 1 >+#endif >+ >+namespace absl { >+class Condition; >+ >+namespace synchronization_internal { >+ >+class MutexImpl; >+ >+// Do not use this implementation detail of CondVar. Provides most of the >+// implementation, but should not be placed directly in static storage >+// because it will not linker initialize properly. See >+// SynchronizationStorage<T> below for what we mean by linker >+// initialization. >+class CondVarImpl { >+ public: >+ CondVarImpl(); >+ CondVarImpl(const CondVarImpl&) = delete; >+ CondVarImpl& operator=(const CondVarImpl&) = delete; >+ ~CondVarImpl(); >+ >+ void Signal(); >+ void SignalAll(); >+ void Wait(MutexImpl* mutex); >+ bool WaitWithDeadline(MutexImpl* mutex, absl::Time deadline); >+ >+ private: >+#if defined(_WIN32) >+ std::condition_variable_any std_cv_; >+#else >+ pthread_cond_t pthread_cv_; >+#endif >+}; >+ >+// Do not use this implementation detail of Mutex. Provides most of the >+// implementation, but should not be placed directly in static storage >+// because it will not linker initialize properly. See >+// SynchronizationStorage<T> below for what we mean by linker >+// initialization. >+class MutexImpl { >+ public: >+ MutexImpl(); >+ MutexImpl(const MutexImpl&) = delete; >+ MutexImpl& operator=(const MutexImpl&) = delete; >+ ~MutexImpl(); >+ >+ void Lock(); >+ bool TryLock(); >+ void Unlock(); >+ void Await(const Condition& cond); >+ bool AwaitWithDeadline(const Condition& cond, absl::Time deadline); >+ >+ private: >+ friend class CondVarImpl; >+ >+#if defined(_WIN32) >+ std::mutex std_mutex_; >+#else >+ pthread_mutex_t pthread_mutex_; >+#endif >+ >+ // True if the underlying mutex is locked. If the destructor is entered >+ // while locked_, the underlying mutex is unlocked. Mutex supports >+ // destruction while locked, but the same is undefined behavior for both >+ // pthread_mutex_t and std::mutex. >+ bool locked_ = false; >+ >+ // Signaled before releasing the lock, in support of Await. >+ CondVarImpl released_; >+}; >+ >+// Do not use this implementation detail of CondVar and Mutex. A storage >+// space for T that supports a LinkerInitialized constructor. T must >+// have a default constructor, which is called by the first call to >+// get(). T's destructor is never called if the LinkerInitialized >+// constructor is called. >+// >+// Objects constructed with the default constructor are constructed and >+// destructed like any other object, and should never be allocated in >+// static storage. >+// >+// Objects constructed with the LinkerInitialized constructor should >+// always be in static storage. For such objects, calls to get() are always >+// valid, except from signal handlers. >+// >+// Note that this implementation relies on undefined language behavior that >+// are known to hold for the set of supported compilers. An analysis >+// follows. >+// >+// From the C++11 standard: >+// >+// [basic.life] says an object has non-trivial initialization if it is of >+// class type and it is initialized by a constructor other than a trivial >+// default constructor. (the LinkerInitialized constructor is >+// non-trivial) >+// >+// [basic.life] says the lifetime of an object with a non-trivial >+// constructor begins when the call to the constructor is complete. >+// >+// [basic.life] says the lifetime of an object with non-trivial destructor >+// ends when the call to the destructor begins. >+// >+// [basic.life] p5 specifies undefined behavior when accessing non-static >+// members of an instance outside its >+// lifetime. (SynchronizationStorage::get() access non-static members) >+// >+// So, LinkerInitialized object of SynchronizationStorage uses a >+// non-trivial constructor, which is called at some point during dynamic >+// initialization, and is therefore subject to order of dynamic >+// initialization bugs, where get() is called before the object's >+// constructor is, resulting in undefined behavior. >+// >+// Similarly, a LinkerInitialized SynchronizationStorage object has a >+// non-trivial destructor, and so its lifetime ends at some point during >+// destruction of objects with static storage duration [basic.start.term] >+// p4. There is a window where other exit code could call get() after this >+// occurs, resulting in undefined behavior. >+// >+// Combined, these statements imply that LinkerInitialized instances >+// of SynchronizationStorage<T> rely on undefined behavior. >+// >+// However, in practice, the implementation works on all supported >+// compilers. Specifically, we rely on: >+// >+// a) zero-initialization being sufficient to initialize >+// LinkerInitialized instances for the purposes of calling >+// get(), regardless of when the constructor is called. This is >+// because the is_dynamic_ boolean is correctly zero-initialized to >+// false. >+// >+// b) the LinkerInitialized constructor is a NOP, and immaterial to >+// even to concurrent calls to get(). >+// >+// c) the destructor being a NOP for LinkerInitialized objects >+// (guaranteed by a check for !is_dynamic_), and so any concurrent and >+// subsequent calls to get() functioning as if the destructor were not >+// called, by virtue of the instances' storage remaining valid after the >+// destructor runs. >+// >+// d) That a-c apply transitively when SynchronizationStorage<T> is the >+// only member of a class allocated in static storage. >+// >+// Nothing in the language standard guarantees that a-d hold. In practice, >+// these hold in all supported compilers. >+// >+// Future direction: >+// >+// Ideally, we would simply use std::mutex or a similar class, which when >+// allocated statically would support use immediately after static >+// initialization up until static storage is reclaimed (i.e. the properties >+// we require of all "linker initialized" instances). >+// >+// Regarding construction in static storage, std::mutex is required to >+// provide a constexpr default constructor [thread.mutex.class], which >+// ensures the instance's lifetime begins with static initialization >+// [basic.start.init], and so is immune to any problems caused by the order >+// of dynamic initialization. However, as of this writing Microsoft's >+// Visual Studio does not provide a constexpr constructor for std::mutex. >+// See >+// https://blogs.msdn.microsoft.com/vcblog/2015/06/02/constexpr-complete-for-vs-2015-rtm-c11-compiler-c17-stl/ >+// >+// Regarding destruction of instances in static storage, [basic.life] does >+// say an object ends when storage in which the occupies is released, in >+// the case of non-trivial destructor. However, std::mutex is not specified >+// to have a trivial destructor. >+// >+// So, we would need a class with a constexpr default constructor and a >+// trivial destructor. Today, we can achieve neither desired property using >+// std::mutex directly. >+template <typename T> >+class SynchronizationStorage { >+ public: >+ // Instances allocated on the heap or on the stack should use the default >+ // constructor. >+ SynchronizationStorage() >+ : is_dynamic_(true), once_() {} >+ >+ // Instances allocated in static storage (not on the heap, not on the >+ // stack) should use this constructor. >+ explicit SynchronizationStorage(base_internal::LinkerInitialized) {} >+ >+ SynchronizationStorage(SynchronizationStorage&) = delete; >+ SynchronizationStorage& operator=(SynchronizationStorage&) = delete; >+ >+ ~SynchronizationStorage() { >+ if (is_dynamic_) { >+ get()->~T(); >+ } >+ } >+ >+ // Retrieve the object in storage. This is fast and thread safe, but does >+ // incur the cost of absl::call_once(). >+ // >+ // For instances in static storage constructed with the >+ // LinkerInitialized constructor, may be called at any time without >+ // regard for order of dynamic initialization or destruction of objects >+ // in static storage. See the class comment for caveats. >+ T* get() { >+ absl::call_once(once_, SynchronizationStorage::Construct, this); >+ return reinterpret_cast<T*>(&space_); >+ } >+ >+ private: >+ static void Construct(SynchronizationStorage<T>* self) { >+ new (&self->space_) T(); >+ } >+ >+ // When true, T's destructor is run when this is destructed. >+ // >+ // The LinkerInitialized constructor assumes this value will be set >+ // false by static initialization. >+ bool is_dynamic_; >+ >+ absl::once_flag once_; >+ >+ // An aligned space for T. >+ typename std::aligned_storage<sizeof(T), alignof(T)>::type space_; >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc >new file mode 100644 >index 00000000000..caa2baf64bd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.cc >@@ -0,0 +1,99 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file is a no-op if the required LowLevelAlloc support is missing. >+#include "absl/base/internal/low_level_alloc.h" >+#ifndef ABSL_LOW_LEVEL_ALLOC_MISSING >+ >+#include "absl/synchronization/internal/per_thread_sem.h" >+ >+#include <atomic> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/synchronization/internal/waiter.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+void PerThreadSem::SetThreadBlockedCounter(std::atomic<int> *counter) { >+ base_internal::ThreadIdentity *identity; >+ identity = GetOrCreateCurrentThreadIdentity(); >+ identity->blocked_count_ptr = counter; >+} >+ >+std::atomic<int> *PerThreadSem::GetThreadBlockedCounter() { >+ base_internal::ThreadIdentity *identity; >+ identity = GetOrCreateCurrentThreadIdentity(); >+ return identity->blocked_count_ptr; >+} >+ >+void PerThreadSem::Init(base_internal::ThreadIdentity *identity) { >+ Waiter::GetWaiter(identity)->Init(); >+ identity->ticker.store(0, std::memory_order_relaxed); >+ identity->wait_start.store(0, std::memory_order_relaxed); >+ identity->is_idle.store(false, std::memory_order_relaxed); >+} >+ >+void PerThreadSem::Tick(base_internal::ThreadIdentity *identity) { >+ const int ticker = >+ identity->ticker.fetch_add(1, std::memory_order_relaxed) + 1; >+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed); >+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed); >+ if (wait_start && (ticker - wait_start > Waiter::kIdlePeriods) && !is_idle) { >+ // Wakeup the waiting thread since it is time for it to become idle. >+ Waiter::GetWaiter(identity)->Poke(); >+ } >+} >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+extern "C" { >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalPerThreadSemPost( >+ absl::base_internal::ThreadIdentity *identity) { >+ absl::synchronization_internal::Waiter::GetWaiter(identity)->Post(); >+} >+ >+ABSL_ATTRIBUTE_WEAK bool AbslInternalPerThreadSemWait( >+ absl::synchronization_internal::KernelTimeout t) { >+ bool timeout = false; >+ absl::base_internal::ThreadIdentity *identity; >+ identity = absl::synchronization_internal::GetOrCreateCurrentThreadIdentity(); >+ >+ // Ensure wait_start != 0. >+ int ticker = identity->ticker.load(std::memory_order_relaxed); >+ identity->wait_start.store(ticker ? ticker : 1, std::memory_order_relaxed); >+ identity->is_idle.store(false, std::memory_order_relaxed); >+ >+ if (identity->blocked_count_ptr != nullptr) { >+ // Increment count of threads blocked in a given thread pool. >+ identity->blocked_count_ptr->fetch_add(1, std::memory_order_relaxed); >+ } >+ >+ timeout = >+ !absl::synchronization_internal::Waiter::GetWaiter(identity)->Wait(t); >+ >+ if (identity->blocked_count_ptr != nullptr) { >+ identity->blocked_count_ptr->fetch_sub(1, std::memory_order_relaxed); >+ } >+ identity->is_idle.store(false, std::memory_order_relaxed); >+ identity->wait_start.store(0, std::memory_order_relaxed); >+ return !timeout; >+} >+ >+} // extern "C" >+ >+#endif // ABSL_LOW_LEVEL_ALLOC_MISSING >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h >new file mode 100644 >index 00000000000..678b69e487a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem.h >@@ -0,0 +1,107 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+// PerThreadSem is a low-level synchronization primitive controlling the >+// runnability of a single thread, used internally by Mutex and CondVar. >+// >+// This is NOT a general-purpose synchronization mechanism, and should not be >+// used directly by applications. Applications should use Mutex and CondVar. >+// >+// The semantics of PerThreadSem are the same as that of a counting semaphore. >+// Each thread maintains an abstract "count" value associated with its identity. >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ >+ >+#include <atomic> >+ >+#include "absl/base/internal/thread_identity.h" >+#include "absl/synchronization/internal/create_thread_identity.h" >+#include "absl/synchronization/internal/kernel_timeout.h" >+ >+namespace absl { >+ >+class Mutex; >+ >+namespace synchronization_internal { >+ >+class PerThreadSem { >+ public: >+ PerThreadSem() = delete; >+ PerThreadSem(const PerThreadSem&) = delete; >+ PerThreadSem& operator=(const PerThreadSem&) = delete; >+ >+ // Routine invoked periodically (once a second) by a background thread. >+ // Has no effect on user-visible state. >+ static void Tick(base_internal::ThreadIdentity* identity); >+ >+ // --------------------------------------------------------------------------- >+ // Routines used by autosizing threadpools to detect when threads are >+ // blocked. Each thread has a counter pointer, initially zero. If non-zero, >+ // the implementation atomically increments the counter when it blocks on a >+ // semaphore, a decrements it again when it wakes. This allows a threadpool >+ // to keep track of how many of its threads are blocked. >+ // SetThreadBlockedCounter() should be used only by threadpool >+ // implementations. GetThreadBlockedCounter() should be used by modules that >+ // block threads; if the pointer returned is non-zero, the location should be >+ // incremented before the thread blocks, and decremented after it wakes. >+ static void SetThreadBlockedCounter(std::atomic<int> *counter); >+ static std::atomic<int> *GetThreadBlockedCounter(); >+ >+ private: >+ // Create the PerThreadSem associated with "identity". Initializes count=0. >+ // REQUIRES: May only be called by ThreadIdentity. >+ static void Init(base_internal::ThreadIdentity* identity); >+ >+ // Increments "identity"'s count. >+ static inline void Post(base_internal::ThreadIdentity* identity); >+ >+ // Waits until either our count > 0 or t has expired. >+ // If count > 0, decrements count and returns true. Otherwise returns false. >+ // !t.has_timeout() => Wait(t) will return true. >+ static inline bool Wait(KernelTimeout t); >+ >+ // White-listed callers. >+ friend class PerThreadSemTest; >+ friend class absl::Mutex; >+ friend absl::base_internal::ThreadIdentity* CreateThreadIdentity(); >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+// In some build configurations we pass --detect-odr-violations to the >+// gold linker. This causes it to flag weak symbol overrides as ODR >+// violations. Because ODR only applies to C++ and not C, >+// --detect-odr-violations ignores symbols not mangled with C++ names. >+// By changing our extension points to be extern "C", we dodge this >+// check. >+extern "C" { >+void AbslInternalPerThreadSemPost( >+ absl::base_internal::ThreadIdentity* identity); >+bool AbslInternalPerThreadSemWait( >+ absl::synchronization_internal::KernelTimeout t); >+} // extern "C" >+ >+void absl::synchronization_internal::PerThreadSem::Post( >+ absl::base_internal::ThreadIdentity* identity) { >+ AbslInternalPerThreadSemPost(identity); >+} >+ >+bool absl::synchronization_internal::PerThreadSem::Wait( >+ absl::synchronization_internal::KernelTimeout t) { >+ return AbslInternalPerThreadSemWait(t); >+} >+#endif // ABSL_SYNCHRONIZATION_INTERNAL_PER_THREAD_SEM_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc >new file mode 100644 >index 00000000000..2b52ea76ab0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/per_thread_sem_test.cc >@@ -0,0 +1,172 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/internal/per_thread_sem.h" >+ >+#include <atomic> >+#include <condition_variable> // NOLINT(build/c++11) >+#include <functional> >+#include <limits> >+#include <mutex> // NOLINT(build/c++11) >+#include <string> >+#include <thread> // NOLINT(build/c++11) >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/cycleclock.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/strings/str_cat.h" >+#include "absl/time/clock.h" >+#include "absl/time/time.h" >+ >+// In this test we explicitly avoid the use of synchronization >+// primitives which might use PerThreadSem, most notably absl::Mutex. >+ >+namespace absl { >+namespace synchronization_internal { >+ >+class SimpleSemaphore { >+ public: >+ SimpleSemaphore() : count_(0) {} >+ >+ // Decrements (locks) the semaphore. If the semaphore's value is >+ // greater than zero, then the decrement proceeds, and the function >+ // returns, immediately. If the semaphore currently has the value >+ // zero, then the call blocks until it becomes possible to perform >+ // the decrement. >+ void Wait() { >+ std::unique_lock<std::mutex> lock(mu_); >+ cv_.wait(lock, [this]() { return count_ > 0; }); >+ --count_; >+ cv_.notify_one(); >+ } >+ >+ // Increments (unlocks) the semaphore. If the semaphore's value >+ // consequently becomes greater than zero, then another thread >+ // blocked Wait() call will be woken up and proceed to lock the >+ // semaphore. >+ void Post() { >+ std::lock_guard<std::mutex> lock(mu_); >+ ++count_; >+ cv_.notify_one(); >+ } >+ >+ private: >+ std::mutex mu_; >+ std::condition_variable cv_; >+ int count_; >+}; >+ >+struct ThreadData { >+ int num_iterations; // Number of replies to send. >+ SimpleSemaphore identity2_written; // Posted by thread writing identity2. >+ base_internal::ThreadIdentity *identity1; // First Post()-er. >+ base_internal::ThreadIdentity *identity2; // First Wait()-er. >+ KernelTimeout timeout; >+}; >+ >+// Need friendship with PerThreadSem. >+class PerThreadSemTest : public testing::Test { >+ public: >+ static void TimingThread(ThreadData* t) { >+ t->identity2 = GetOrCreateCurrentThreadIdentity(); >+ t->identity2_written.Post(); >+ while (t->num_iterations--) { >+ Wait(t->timeout); >+ Post(t->identity1); >+ } >+ } >+ >+ void TestTiming(const char *msg, bool timeout) { >+ static const int kNumIterations = 100; >+ ThreadData t; >+ t.num_iterations = kNumIterations; >+ t.timeout = timeout ? >+ KernelTimeout(absl::Now() + absl::Seconds(10000)) // far in the future >+ : KernelTimeout::Never(); >+ t.identity1 = GetOrCreateCurrentThreadIdentity(); >+ >+ // We can't use the Thread class here because it uses the Mutex >+ // class which will invoke PerThreadSem, so we use std::thread instead. >+ std::thread partner_thread(std::bind(TimingThread, &t)); >+ >+ // Wait for our partner thread to register their identity. >+ t.identity2_written.Wait(); >+ >+ int64_t min_cycles = std::numeric_limits<int64_t>::max(); >+ int64_t total_cycles = 0; >+ for (int i = 0; i < kNumIterations; ++i) { >+ absl::SleepFor(absl::Milliseconds(20)); >+ int64_t cycles = base_internal::CycleClock::Now(); >+ Post(t.identity2); >+ Wait(t.timeout); >+ cycles = base_internal::CycleClock::Now() - cycles; >+ min_cycles = std::min(min_cycles, cycles); >+ total_cycles += cycles; >+ } >+ std::string out = >+ StrCat(msg, "min cycle count=", min_cycles, " avg cycle count=", >+ absl::SixDigits(static_cast<double>(total_cycles) / >+ kNumIterations)); >+ printf("%s\n", out.c_str()); >+ >+ partner_thread.join(); >+ } >+ >+ protected: >+ static void Post(base_internal::ThreadIdentity *id) { >+ PerThreadSem::Post(id); >+ } >+ static bool Wait(KernelTimeout t) { >+ return PerThreadSem::Wait(t); >+ } >+ >+ // convenience overload >+ static bool Wait(absl::Time t) { >+ return Wait(KernelTimeout(t)); >+ } >+ >+ static void Tick(base_internal::ThreadIdentity *identity) { >+ PerThreadSem::Tick(identity); >+ } >+}; >+ >+namespace { >+ >+TEST_F(PerThreadSemTest, WithoutTimeout) { >+ PerThreadSemTest::TestTiming("Without timeout: ", false); >+} >+ >+TEST_F(PerThreadSemTest, WithTimeout) { >+ PerThreadSemTest::TestTiming("With timeout: ", true); >+} >+ >+TEST_F(PerThreadSemTest, Timeouts) { >+ absl::Time timeout = absl::Now() + absl::Milliseconds(50); >+ EXPECT_FALSE(Wait(timeout)); >+ EXPECT_LE(timeout, absl::Now()); >+ >+ absl::Time negative_timeout = absl::UnixEpoch() - absl::Milliseconds(100); >+ EXPECT_FALSE(Wait(negative_timeout)); >+ EXPECT_LE(negative_timeout, absl::Now()); // trivially true :) >+ >+ Post(GetOrCreateCurrentThreadIdentity()); >+ // The wait here has an expired timeout, but we have a wake to consume, >+ // so this should succeed >+ EXPECT_TRUE(Wait(negative_timeout)); >+} >+ >+} // namespace >+ >+} // namespace synchronization_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h >new file mode 100644 >index 00000000000..846404277a0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/thread_pool.h >@@ -0,0 +1,90 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_ >+ >+#include <cassert> >+#include <functional> >+#include <queue> >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// A simple ThreadPool implementation for tests. >+class ThreadPool { >+ public: >+ explicit ThreadPool(int num_threads) { >+ for (int i = 0; i < num_threads; ++i) { >+ threads_.push_back(std::thread(&ThreadPool::WorkLoop, this)); >+ } >+ } >+ >+ ThreadPool(const ThreadPool &) = delete; >+ ThreadPool &operator=(const ThreadPool &) = delete; >+ >+ ~ThreadPool() { >+ { >+ absl::MutexLock l(&mu_); >+ for (int i = 0; i < threads_.size(); ++i) { >+ queue_.push(nullptr); // Shutdown signal. >+ } >+ } >+ for (auto &t : threads_) { >+ t.join(); >+ } >+ } >+ >+ // Schedule a function to be run on a ThreadPool thread immediately. >+ void Schedule(std::function<void()> func) { >+ assert(func != nullptr); >+ absl::MutexLock l(&mu_); >+ queue_.push(std::move(func)); >+ } >+ >+ private: >+ bool WorkAvailable() const EXCLUSIVE_LOCKS_REQUIRED(mu_) { >+ return !queue_.empty(); >+ } >+ >+ void WorkLoop() { >+ while (true) { >+ std::function<void()> func; >+ { >+ absl::MutexLock l(&mu_); >+ mu_.Await(absl::Condition(this, &ThreadPool::WorkAvailable)); >+ func = std::move(queue_.front()); >+ queue_.pop(); >+ } >+ if (func == nullptr) { // Shutdown signal. >+ break; >+ } >+ func(); >+ } >+ } >+ >+ absl::Mutex mu_; >+ std::queue<std::function<void()>> queue_ GUARDED_BY(mu_); >+ std::vector<std::thread> threads_; >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+#endif // ABSL_SYNCHRONIZATION_INTERNAL_THREAD_POOL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc >new file mode 100644 >index 00000000000..768c52085cd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc >@@ -0,0 +1,412 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/internal/waiter.h" >+ >+#include "absl/base/config.h" >+ >+#ifdef _WIN32 >+#include <windows.h> >+#else >+#include <pthread.h> >+#include <sys/time.h> >+#include <unistd.h> >+#endif >+ >+#ifdef __linux__ >+#include <linux/futex.h> >+#include <sys/syscall.h> >+#endif >+ >+#ifdef ABSL_HAVE_SEMAPHORE_H >+#include <semaphore.h> >+#endif >+ >+#include <errno.h> >+#include <stdio.h> >+#include <time.h> >+ >+#include <atomic> >+#include <cassert> >+#include <cstdint> >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/base/optimization.h" >+#include "absl/synchronization/internal/kernel_timeout.h" >+ >+namespace absl { >+namespace synchronization_internal { >+ >+static void MaybeBecomeIdle() { >+ base_internal::ThreadIdentity *identity = >+ base_internal::CurrentThreadIdentityIfPresent(); >+ assert(identity != nullptr); >+ const bool is_idle = identity->is_idle.load(std::memory_order_relaxed); >+ const int ticker = identity->ticker.load(std::memory_order_relaxed); >+ const int wait_start = identity->wait_start.load(std::memory_order_relaxed); >+ if (!is_idle && ticker - wait_start > Waiter::kIdlePeriods) { >+ identity->is_idle.store(true, std::memory_order_relaxed); >+ } >+} >+ >+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX >+ >+// Some Android headers are missing these definitions even though they >+// support these futex operations. >+#ifdef __BIONIC__ >+#ifndef SYS_futex >+#define SYS_futex __NR_futex >+#endif >+#ifndef FUTEX_WAIT_BITSET >+#define FUTEX_WAIT_BITSET 9 >+#endif >+#ifndef FUTEX_PRIVATE_FLAG >+#define FUTEX_PRIVATE_FLAG 128 >+#endif >+#ifndef FUTEX_CLOCK_REALTIME >+#define FUTEX_CLOCK_REALTIME 256 >+#endif >+#ifndef FUTEX_BITSET_MATCH_ANY >+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF >+#endif >+#endif >+class Futex { >+ public: >+ static int WaitUntil(std::atomic<int32_t> *v, int32_t val, >+ KernelTimeout t) { >+ int err = 0; >+ if (t.has_timeout()) { >+ // https://locklessinc.com/articles/futex_cheat_sheet/ >+ // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time. >+ struct timespec abs_timeout = t.MakeAbsTimespec(); >+ // Atomically check that the futex value is still 0, and if it >+ // is, sleep until abs_timeout or until woken by FUTEX_WAKE. >+ err = syscall( >+ SYS_futex, reinterpret_cast<int32_t *>(v), >+ FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val, >+ &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY); >+ } else { >+ // Atomically check that the futex value is still 0, and if it >+ // is, sleep until woken by FUTEX_WAKE. >+ err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v), >+ FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr); >+ } >+ if (err != 0) { >+ err = -errno; >+ } >+ return err; >+ } >+ >+ static int Wake(std::atomic<int32_t> *v, int32_t count) { >+ int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v), >+ FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count); >+ if (ABSL_PREDICT_FALSE(err < 0)) { >+ err = -errno; >+ } >+ return err; >+ } >+}; >+ >+void Waiter::Init() { >+ futex_.store(0, std::memory_order_relaxed); >+} >+ >+bool Waiter::Wait(KernelTimeout t) { >+ // Loop until we can atomically decrement futex from a positive >+ // value, waiting on a futex while we believe it is zero. >+ while (true) { >+ int32_t x = futex_.load(std::memory_order_relaxed); >+ if (x != 0) { >+ if (!futex_.compare_exchange_weak(x, x - 1, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ continue; // Raced with someone, retry. >+ } >+ return true; // Consumed a wakeup, we are done. >+ } >+ >+ const int err = Futex::WaitUntil(&futex_, 0, t); >+ if (err != 0) { >+ if (err == -EINTR || err == -EWOULDBLOCK) { >+ // Do nothing, the loop will retry. >+ } else if (err == -ETIMEDOUT) { >+ return false; >+ } else { >+ ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err); >+ } >+ } >+ >+ MaybeBecomeIdle(); >+ } >+} >+ >+void Waiter::Post() { >+ if (futex_.fetch_add(1, std::memory_order_release) == 0) { >+ // We incremented from 0, need to wake a potential waker. >+ Poke(); >+ } >+} >+ >+void Waiter::Poke() { >+ // Wake one thread waiting on the futex. >+ const int err = Futex::Wake(&futex_, 1); >+ if (ABSL_PREDICT_FALSE(err < 0)) { >+ ABSL_RAW_LOG(FATAL, "Futex operation failed with error %d\n", err); >+ } >+} >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR >+ >+class PthreadMutexHolder { >+ public: >+ explicit PthreadMutexHolder(pthread_mutex_t *mu) : mu_(mu) { >+ const int err = pthread_mutex_lock(mu_); >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_mutex_lock failed: %d", err); >+ } >+ } >+ >+ PthreadMutexHolder(const PthreadMutexHolder &rhs) = delete; >+ PthreadMutexHolder &operator=(const PthreadMutexHolder &rhs) = delete; >+ >+ ~PthreadMutexHolder() { >+ const int err = pthread_mutex_unlock(mu_); >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_mutex_unlock failed: %d", err); >+ } >+ } >+ >+ private: >+ pthread_mutex_t *mu_; >+}; >+ >+void Waiter::Init() { >+ const int err = pthread_mutex_init(&mu_, 0); >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_mutex_init failed: %d", err); >+ } >+ >+ const int err2 = pthread_cond_init(&cv_, 0); >+ if (err2 != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_cond_init failed: %d", err2); >+ } >+ >+ waiter_count_.store(0, std::memory_order_relaxed); >+ wakeup_count_.store(0, std::memory_order_relaxed); >+} >+ >+bool Waiter::Wait(KernelTimeout t) { >+ struct timespec abs_timeout; >+ if (t.has_timeout()) { >+ abs_timeout = t.MakeAbsTimespec(); >+ } >+ >+ PthreadMutexHolder h(&mu_); >+ waiter_count_.fetch_add(1, std::memory_order_relaxed); >+ // Loop until we find a wakeup to consume or timeout. >+ while (true) { >+ int x = wakeup_count_.load(std::memory_order_relaxed); >+ if (x != 0) { >+ if (!wakeup_count_.compare_exchange_weak(x, x - 1, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ continue; // Raced with someone, retry. >+ } >+ // Successfully consumed a wakeup, we're done. >+ waiter_count_.fetch_sub(1, std::memory_order_relaxed); >+ return true; >+ } >+ >+ // No wakeups available, time to wait. >+ if (!t.has_timeout()) { >+ const int err = pthread_cond_wait(&cv_, &mu_); >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err); >+ } >+ } else { >+ const int err = pthread_cond_timedwait(&cv_, &mu_, &abs_timeout); >+ if (err == ETIMEDOUT) { >+ waiter_count_.fetch_sub(1, std::memory_order_relaxed); >+ return false; >+ } >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_cond_wait failed: %d", err); >+ } >+ } >+ MaybeBecomeIdle(); >+ } >+} >+ >+void Waiter::Post() { >+ wakeup_count_.fetch_add(1, std::memory_order_release); >+ Poke(); >+} >+ >+void Waiter::Poke() { >+ if (waiter_count_.load(std::memory_order_relaxed) == 0) { >+ return; >+ } >+ // Potentially a waker. Take the lock and check again. >+ PthreadMutexHolder h(&mu_); >+ if (waiter_count_.load(std::memory_order_relaxed) == 0) { >+ return; >+ } >+ const int err = pthread_cond_signal(&cv_); >+ if (err != 0) { >+ ABSL_RAW_LOG(FATAL, "pthread_cond_signal failed: %d", err); >+ } >+} >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM >+ >+void Waiter::Init() { >+ if (sem_init(&sem_, 0, 0) != 0) { >+ ABSL_RAW_LOG(FATAL, "sem_init failed with errno %d\n", errno); >+ } >+ wakeups_.store(0, std::memory_order_relaxed); >+} >+ >+bool Waiter::Wait(KernelTimeout t) { >+ struct timespec abs_timeout; >+ if (t.has_timeout()) { >+ abs_timeout = t.MakeAbsTimespec(); >+ } >+ >+ // Loop until we timeout or consume a wakeup. >+ while (true) { >+ int x = wakeups_.load(std::memory_order_relaxed); >+ if (x != 0) { >+ if (!wakeups_.compare_exchange_weak(x, x - 1, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ continue; // Raced with someone, retry. >+ } >+ // Successfully consumed a wakeup, we're done. >+ return true; >+ } >+ >+ // Nothing to consume, wait (looping on EINTR). >+ while (true) { >+ if (!t.has_timeout()) { >+ if (sem_wait(&sem_) == 0) break; >+ if (errno == EINTR) continue; >+ ABSL_RAW_LOG(FATAL, "sem_wait failed: %d", errno); >+ } else { >+ if (sem_timedwait(&sem_, &abs_timeout) == 0) break; >+ if (errno == EINTR) continue; >+ if (errno == ETIMEDOUT) return false; >+ ABSL_RAW_LOG(FATAL, "sem_timedwait failed: %d", errno); >+ } >+ } >+ MaybeBecomeIdle(); >+ } >+} >+ >+void Waiter::Post() { >+ wakeups_.fetch_add(1, std::memory_order_release); // Post a wakeup. >+ Poke(); >+} >+ >+void Waiter::Poke() { >+ if (sem_post(&sem_) != 0) { // Wake any semaphore waiter. >+ ABSL_RAW_LOG(FATAL, "sem_post failed with errno %d\n", errno); >+ } >+} >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 >+ >+class LockHolder { >+ public: >+ explicit LockHolder(SRWLOCK* mu) : mu_(mu) { >+ AcquireSRWLockExclusive(mu_); >+ } >+ >+ LockHolder(const LockHolder&) = delete; >+ LockHolder& operator=(const LockHolder&) = delete; >+ >+ ~LockHolder() { >+ ReleaseSRWLockExclusive(mu_); >+ } >+ >+ private: >+ SRWLOCK* mu_; >+}; >+ >+void Waiter::Init() { >+ InitializeSRWLock(&mu_); >+ InitializeConditionVariable(&cv_); >+ waiter_count_.store(0, std::memory_order_relaxed); >+ wakeup_count_.store(0, std::memory_order_relaxed); >+} >+ >+bool Waiter::Wait(KernelTimeout t) { >+ LockHolder h(&mu_); >+ waiter_count_.fetch_add(1, std::memory_order_relaxed); >+ >+ // Loop until we find a wakeup to consume or timeout. >+ while (true) { >+ int x = wakeup_count_.load(std::memory_order_relaxed); >+ if (x != 0) { >+ if (!wakeup_count_.compare_exchange_weak(x, x - 1, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ continue; // Raced with someone, retry. >+ } >+ // Successfully consumed a wakeup, we're done. >+ waiter_count_.fetch_sub(1, std::memory_order_relaxed); >+ return true; >+ } >+ >+ // No wakeups available, time to wait. >+ if (!SleepConditionVariableSRW( >+ &cv_, &mu_, t.InMillisecondsFromNow(), 0)) { >+ // GetLastError() returns a Win32 DWORD, but we assign to >+ // unsigned long to simplify the ABSL_RAW_LOG case below. The uniform >+ // initialization guarantees this is not a narrowing conversion. >+ const unsigned long err{GetLastError()}; // NOLINT(runtime/int) >+ if (err == ERROR_TIMEOUT) { >+ waiter_count_.fetch_sub(1, std::memory_order_relaxed); >+ return false; >+ } else { >+ ABSL_RAW_LOG(FATAL, "SleepConditionVariableSRW failed: %lu", err); >+ } >+ } >+ >+ MaybeBecomeIdle(); >+ } >+} >+ >+void Waiter::Post() { >+ wakeup_count_.fetch_add(1, std::memory_order_release); >+ Poke(); >+} >+ >+void Waiter::Poke() { >+ if (waiter_count_.load(std::memory_order_relaxed) == 0) { >+ return; >+ } >+ // Potentially a waker. Take the lock and check again. >+ LockHolder h(&mu_); >+ if (waiter_count_.load(std::memory_order_relaxed) == 0) { >+ return; >+ } >+ WakeConditionVariable(&cv_); >+} >+ >+#else >+#error Unknown ABSL_WAITER_MODE >+#endif >+ >+} // namespace synchronization_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.h >new file mode 100644 >index 00000000000..23166f4bfa3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/internal/waiter.h >@@ -0,0 +1,139 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+ >+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ >+#define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ >+ >+#include "absl/base/config.h" >+ >+#ifdef _WIN32 >+#include <windows.h> >+#else >+#include <pthread.h> >+#endif >+ >+#ifdef ABSL_HAVE_SEMAPHORE_H >+#include <semaphore.h> >+#endif >+ >+#include <atomic> >+#include <cstdint> >+ >+#include "absl/base/internal/thread_identity.h" >+#include "absl/synchronization/internal/kernel_timeout.h" >+ >+// May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index> >+#define ABSL_WAITER_MODE_FUTEX 0 >+#define ABSL_WAITER_MODE_SEM 1 >+#define ABSL_WAITER_MODE_CONDVAR 2 >+#define ABSL_WAITER_MODE_WIN32 3 >+ >+#if defined(ABSL_FORCE_WAITER_MODE) >+#define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE >+#elif defined(_WIN32) >+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32 >+#elif defined(__linux__) >+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX >+#elif defined(ABSL_HAVE_SEMAPHORE_H) >+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM >+#else >+#define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR >+#endif >+ >+namespace absl { >+namespace synchronization_internal { >+ >+// Waiter is an OS-specific semaphore. >+class Waiter { >+ public: >+ // No constructor, instances use the reserved space in ThreadIdentity. >+ // All initialization logic belongs in `Init()`. >+ Waiter() = delete; >+ Waiter(const Waiter&) = delete; >+ Waiter& operator=(const Waiter&) = delete; >+ >+ // Prepare any data to track waits. >+ void Init(); >+ >+ // Blocks the calling thread until a matching call to `Post()` or >+ // `t` has passed. Returns `true` if woken (`Post()` called), >+ // `false` on timeout. >+ bool Wait(KernelTimeout t); >+ >+ // Restart the caller of `Wait()` as with a normal semaphore. >+ void Post(); >+ >+ // If anyone is waiting, wake them up temporarily and cause them to >+ // call `MaybeBecomeIdle()`. They will then return to waiting for a >+ // `Post()` or timeout. >+ void Poke(); >+ >+ // Returns the Waiter associated with the identity. >+ static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) { >+ static_assert( >+ sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState), >+ "Insufficient space for Waiter"); >+ return reinterpret_cast<Waiter*>(identity->waiter_state.data); >+ } >+ >+ // How many periods to remain idle before releasing resources >+#ifndef THREAD_SANITIZER >+ static const int kIdlePeriods = 60; >+#else >+ // Memory consumption under ThreadSanitizer is a serious concern, >+ // so we release resources sooner. The value of 1 leads to 1 to 2 second >+ // delay before marking a thread as idle. >+ static const int kIdlePeriods = 1; >+#endif >+ >+ private: >+#if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX >+ // Futexes are defined by specification to be 32-bits. >+ // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods. >+ std::atomic<int32_t> futex_; >+ static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex"); >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR >+ pthread_mutex_t mu_; >+ pthread_cond_t cv_; >+ std::atomic<int> waiter_count_; >+ std::atomic<int> wakeup_count_; // Unclaimed wakeups, written under lock. >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM >+ sem_t sem_; >+ // This seems superfluous, but for Poke() we need to cause spurious >+ // wakeups on the semaphore. Hence we can't actually use the >+ // semaphore's count. >+ std::atomic<int> wakeups_; >+ >+#elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 >+ // The Windows API has lots of choices for synchronization >+ // primivitives. We are using SRWLOCK and CONDITION_VARIABLE >+ // because they don't require a destructor to release system >+ // resources. >+ SRWLOCK mu_; >+ CONDITION_VARIABLE cv_; >+ std::atomic<int> waiter_count_; >+ std::atomic<int> wakeup_count_; >+ >+#else >+ #error Unknown ABSL_WAITER_MODE >+#endif >+}; >+ >+} // namespace synchronization_internal >+} // namespace absl >+ >+#endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc >new file mode 100644 >index 00000000000..90c9009b18f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/lifetime_test.cc >@@ -0,0 +1,132 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstdlib> >+#include <thread> // NOLINT(build/c++11), Abseil test >+#include <type_traits> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/mutex.h" >+#include "absl/synchronization/notification.h" >+ >+namespace { >+ >+// A two-threaded test which checks that Mutex, CondVar, and Notification have >+// correct basic functionality. The intent is to establish that they >+// function correctly in various phases of construction and destruction. >+// >+// Thread one acquires a lock on 'mutex', wakes thread two via 'notification', >+// then waits for 'state' to be set, as signalled by 'condvar'. >+// >+// Thread two waits on 'notification', then sets 'state' inside the 'mutex', >+// signalling the change via 'condvar'. >+// >+// These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or >+// ASSERT from gUnit, because we need to invoke them during global destructors, >+// when gUnit teardown would have already begun. >+void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar, >+ absl::Notification* notification, bool* state) { >+ // Test that the notification is in a valid initial state. >+ ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification"); >+ ABSL_RAW_CHECK(*state == false, "*state not initialized"); >+ >+ { >+ absl::MutexLock lock(mutex); >+ >+ notification->Notify(); >+ ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification"); >+ >+ while (*state == false) { >+ condvar->Wait(mutex); >+ } >+ } >+} >+ >+void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar, >+ absl::Notification* notification, bool* state) { >+ ABSL_RAW_CHECK(*state == false, "*state not initialized"); >+ >+ // Wake thread one >+ notification->WaitForNotification(); >+ ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification"); >+ { >+ absl::MutexLock lock(mutex); >+ *state = true; >+ condvar->Signal(); >+ } >+} >+ >+// Launch thread 1 and thread 2, and block on their completion. >+// If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally >+// constructed instance instead. >+void RunTests(absl::Mutex* mutex, absl::CondVar* condvar, >+ absl::Notification* notification) { >+ absl::Mutex default_mutex; >+ absl::CondVar default_condvar; >+ absl::Notification default_notification; >+ if (!mutex) { >+ mutex = &default_mutex; >+ } >+ if (!condvar) { >+ condvar = &default_condvar; >+ } >+ if (!notification) { >+ notification = &default_notification; >+ } >+ bool state = false; >+ std::thread thread_one(ThreadOne, mutex, condvar, notification, &state); >+ std::thread thread_two(ThreadTwo, mutex, condvar, notification, &state); >+ thread_one.join(); >+ thread_two.join(); >+} >+ >+void TestLocals() { >+ absl::Mutex mutex; >+ absl::CondVar condvar; >+ absl::Notification notification; >+ RunTests(&mutex, &condvar, ¬ification); >+} >+ >+// Global variables during start and termination >+// >+// In a translation unit, static storage duration variables are initialized in >+// the order of their definitions, and destroyed in the reverse order of their >+// definitions. We can use this to arrange for tests to be run on these objects >+// before they are created, and after they are destroyed. >+ >+using Function = void (*)(); >+ >+class OnConstruction { >+ public: >+ explicit OnConstruction(Function fn) { fn(); } >+}; >+ >+class OnDestruction { >+ public: >+ explicit OnDestruction(Function fn) : fn_(fn) {} >+ ~OnDestruction() { fn_(); } >+ private: >+ Function fn_; >+}; >+ >+} // namespace >+ >+int main() { >+ TestLocals(); >+ // Explicitly call exit(0) here, to make it clear that we intend for the >+ // above global object destructors to run. >+ std::exit(0); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.cc >new file mode 100644 >index 00000000000..80f34f035fc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.cc >@@ -0,0 +1,2687 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/mutex.h" >+ >+#ifdef _WIN32 >+#include <windows.h> >+#ifdef ERROR >+#undef ERROR >+#endif >+#else >+#include <fcntl.h> >+#include <pthread.h> >+#include <sched.h> >+#include <sys/time.h> >+#endif >+ >+#include <assert.h> >+#include <errno.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <time.h> >+ >+#include <algorithm> >+#include <atomic> >+#include <cinttypes> >+#include <thread> // NOLINT(build/c++11) >+ >+#include "absl/base/attributes.h" >+#include "absl/base/config.h" >+#include "absl/base/dynamic_annotations.h" >+#include "absl/base/internal/atomic_hook.h" >+#include "absl/base/internal/cycleclock.h" >+#include "absl/base/internal/hide_ptr.h" >+#include "absl/base/internal/low_level_alloc.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/internal/sysinfo.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/base/port.h" >+#include "absl/debugging/stacktrace.h" >+#include "absl/debugging/symbolize.h" >+#include "absl/synchronization/internal/graphcycles.h" >+#include "absl/synchronization/internal/per_thread_sem.h" >+#include "absl/time/time.h" >+ >+using absl::base_internal::CurrentThreadIdentityIfPresent; >+using absl::base_internal::PerThreadSynch; >+using absl::base_internal::ThreadIdentity; >+using absl::synchronization_internal::GetOrCreateCurrentThreadIdentity; >+using absl::synchronization_internal::GraphCycles; >+using absl::synchronization_internal::GraphId; >+using absl::synchronization_internal::InvalidGraphId; >+using absl::synchronization_internal::KernelTimeout; >+using absl::synchronization_internal::PerThreadSem; >+ >+extern "C" { >+ABSL_ATTRIBUTE_WEAK void AbslInternalMutexYield() { std::this_thread::yield(); } >+} // extern "C" >+ >+namespace absl { >+ >+namespace { >+ >+#if defined(THREAD_SANITIZER) >+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kIgnore; >+#else >+constexpr OnDeadlockCycle kDeadlockDetectionDefault = OnDeadlockCycle::kAbort; >+#endif >+ >+ABSL_CONST_INIT std::atomic<OnDeadlockCycle> synch_deadlock_detection( >+ kDeadlockDetectionDefault); >+ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false); >+ >+// ------------------------------------------ spinlock support >+ >+// Make sure read-only globals used in the Mutex code are contained on the >+// same cacheline and cacheline aligned to eliminate any false sharing with >+// other globals from this and other modules. >+static struct MutexGlobals { >+ MutexGlobals() { >+ // Find machine-specific data needed for Delay() and >+ // TryAcquireWithSpinning(). This runs in the global constructor >+ // sequence, and before that zeros are safe values. >+ num_cpus = absl::base_internal::NumCPUs(); >+ spinloop_iterations = num_cpus > 1 ? 1500 : 0; >+ } >+ int num_cpus; >+ int spinloop_iterations; >+ // Pad this struct to a full cacheline to prevent false sharing. >+ char padding[ABSL_CACHELINE_SIZE - 2 * sizeof(int)]; >+} ABSL_CACHELINE_ALIGNED mutex_globals; >+static_assert( >+ sizeof(MutexGlobals) == ABSL_CACHELINE_SIZE, >+ "MutexGlobals must occupy an entire cacheline to prevent false sharing"); >+ >+ABSL_CONST_INIT absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)> >+ submit_profile_data; >+ABSL_CONST_INIT absl::base_internal::AtomicHook< >+ void (*)(const char *msg, const void *obj, int64_t wait_cycles)> mutex_tracer; >+ABSL_CONST_INIT absl::base_internal::AtomicHook< >+ void (*)(const char *msg, const void *cv)> cond_var_tracer; >+ABSL_CONST_INIT absl::base_internal::AtomicHook< >+ bool (*)(const void *pc, char *out, int out_size)> >+ symbolizer(absl::Symbolize); >+ >+} // namespace >+ >+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)) { >+ submit_profile_data.Store(fn); >+} >+ >+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, >+ int64_t wait_cycles)) { >+ mutex_tracer.Store(fn); >+} >+ >+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)) { >+ cond_var_tracer.Store(fn); >+} >+ >+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)) { >+ symbolizer.Store(fn); >+} >+ >+// spinlock delay on iteration c. Returns new c. >+namespace { >+ enum DelayMode { AGGRESSIVE, GENTLE }; >+}; >+static int Delay(int32_t c, DelayMode mode) { >+ // If this a uniprocessor, only yield/sleep. Otherwise, if the mode is >+ // aggressive then spin many times before yielding. If the mode is >+ // gentle then spin only a few times before yielding. Aggressive spinning is >+ // used to ensure that an Unlock() call, which must get the spin lock for >+ // any thread to make progress gets it without undue delay. >+ int32_t limit = (mutex_globals.num_cpus > 1) ? >+ ((mode == AGGRESSIVE) ? 5000 : 250) : 0; >+ if (c < limit) { >+ c++; // spin >+ } else { >+ ABSL_TSAN_MUTEX_PRE_DIVERT(0, 0); >+ if (c == limit) { // yield once >+ AbslInternalMutexYield(); >+ c++; >+ } else { // then wait >+ absl::SleepFor(absl::Microseconds(10)); >+ c = 0; >+ } >+ ABSL_TSAN_MUTEX_POST_DIVERT(0, 0); >+ } >+ return (c); >+} >+ >+// --------------------------Generic atomic ops >+// Ensure that "(*pv & bits) == bits" by doing an atomic update of "*pv" to >+// "*pv | bits" if necessary. Wait until (*pv & wait_until_clear)==0 >+// before making any change. >+// This is used to set flags in mutex and condition variable words. >+static void AtomicSetBits(std::atomic<intptr_t>* pv, intptr_t bits, >+ intptr_t wait_until_clear) { >+ intptr_t v; >+ do { >+ v = pv->load(std::memory_order_relaxed); >+ } while ((v & bits) != bits && >+ ((v & wait_until_clear) != 0 || >+ !pv->compare_exchange_weak(v, v | bits, >+ std::memory_order_release, >+ std::memory_order_relaxed))); >+} >+ >+// Ensure that "(*pv & bits) == 0" by doing an atomic update of "*pv" to >+// "*pv & ~bits" if necessary. Wait until (*pv & wait_until_clear)==0 >+// before making any change. >+// This is used to unset flags in mutex and condition variable words. >+static void AtomicClearBits(std::atomic<intptr_t>* pv, intptr_t bits, >+ intptr_t wait_until_clear) { >+ intptr_t v; >+ do { >+ v = pv->load(std::memory_order_relaxed); >+ } while ((v & bits) != 0 && >+ ((v & wait_until_clear) != 0 || >+ !pv->compare_exchange_weak(v, v & ~bits, >+ std::memory_order_release, >+ std::memory_order_relaxed))); >+} >+ >+//------------------------------------------------------------------ >+ >+// Data for doing deadlock detection. >+static absl::base_internal::SpinLock deadlock_graph_mu( >+ absl::base_internal::kLinkerInitialized); >+ >+// graph used to detect deadlocks. >+static GraphCycles *deadlock_graph GUARDED_BY(deadlock_graph_mu) >+ PT_GUARDED_BY(deadlock_graph_mu); >+ >+//------------------------------------------------------------------ >+// An event mechanism for debugging mutex use. >+// It also allows mutexes to be given names for those who can't handle >+// addresses, and instead like to give their data structures names like >+// "Henry", "Fido", or "Rupert IV, King of Yondavia". >+ >+namespace { // to prevent name pollution >+enum { // Mutex and CondVar events passed as "ev" to PostSynchEvent >+ // Mutex events >+ SYNCH_EV_TRYLOCK_SUCCESS, >+ SYNCH_EV_TRYLOCK_FAILED, >+ SYNCH_EV_READERTRYLOCK_SUCCESS, >+ SYNCH_EV_READERTRYLOCK_FAILED, >+ SYNCH_EV_LOCK, >+ SYNCH_EV_LOCK_RETURNING, >+ SYNCH_EV_READERLOCK, >+ SYNCH_EV_READERLOCK_RETURNING, >+ SYNCH_EV_UNLOCK, >+ SYNCH_EV_READERUNLOCK, >+ >+ // CondVar events >+ SYNCH_EV_WAIT, >+ SYNCH_EV_WAIT_RETURNING, >+ SYNCH_EV_SIGNAL, >+ SYNCH_EV_SIGNALALL, >+}; >+ >+enum { // Event flags >+ SYNCH_F_R = 0x01, // reader event >+ SYNCH_F_LCK = 0x02, // PostSynchEvent called with mutex held >+ SYNCH_F_ACQ = 0x04, // event is an acquire >+ >+ SYNCH_F_LCK_W = SYNCH_F_LCK, >+ SYNCH_F_LCK_R = SYNCH_F_LCK | SYNCH_F_R, >+ SYNCH_F_ACQ_W = SYNCH_F_ACQ, >+ SYNCH_F_ACQ_R = SYNCH_F_ACQ | SYNCH_F_R, >+}; >+} // anonymous namespace >+ >+// Properties of the events. >+static const struct { >+ int flags; >+ const char *msg; >+} event_properties[] = { >+ { SYNCH_F_LCK_W|SYNCH_F_ACQ_W, "TryLock succeeded " }, >+ { 0, "TryLock failed " }, >+ { SYNCH_F_LCK_R|SYNCH_F_ACQ_R, "ReaderTryLock succeeded " }, >+ { 0, "ReaderTryLock failed " }, >+ { SYNCH_F_ACQ_W, "Lock blocking " }, >+ { SYNCH_F_LCK_W, "Lock returning " }, >+ { SYNCH_F_ACQ_R, "ReaderLock blocking " }, >+ { SYNCH_F_LCK_R, "ReaderLock returning " }, >+ { SYNCH_F_LCK_W, "Unlock " }, >+ { SYNCH_F_LCK_R, "ReaderUnlock " }, >+ { 0, "Wait on " }, >+ { 0, "Wait unblocked " }, >+ { 0, "Signal on " }, >+ { 0, "SignalAll on " }, >+}; >+static absl::base_internal::SpinLock synch_event_mu( >+ absl::base_internal::kLinkerInitialized); >+// protects synch_event >+ >+// Hash table size; should be prime > 2. >+// Can't be too small, as it's used for deadlock detection information. >+static const uint32_t kNSynchEvent = 1031; >+ >+static struct SynchEvent { // this is a trivial hash table for the events >+ // struct is freed when refcount reaches 0 >+ int refcount GUARDED_BY(synch_event_mu); >+ >+ // buckets have linear, 0-terminated chains >+ SynchEvent *next GUARDED_BY(synch_event_mu); >+ >+ // Constant after initialization >+ uintptr_t masked_addr; // object at this address is called "name" >+ >+ // No explicit synchronization used. Instead we assume that the >+ // client who enables/disables invariants/logging on a Mutex does so >+ // while the Mutex is not being concurrently accessed by others. >+ void (*invariant)(void *arg); // called on each event >+ void *arg; // first arg to (*invariant)() >+ bool log; // logging turned on >+ >+ // Constant after initialization >+ char name[1]; // actually longer---null-terminated std::string >+} *synch_event[kNSynchEvent] GUARDED_BY(synch_event_mu); >+ >+// Ensure that the object at "addr" has a SynchEvent struct associated with it, >+// set "bits" in the word there (waiting until lockbit is clear before doing >+// so), and return a refcounted reference that will remain valid until >+// UnrefSynchEvent() is called. If a new SynchEvent is allocated, >+// the std::string name is copied into it. >+// When used with a mutex, the caller should also ensure that kMuEvent >+// is set in the mutex word, and similarly for condition variables and kCVEvent. >+static SynchEvent *EnsureSynchEvent(std::atomic<intptr_t> *addr, >+ const char *name, intptr_t bits, >+ intptr_t lockbit) { >+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent; >+ SynchEvent *e; >+ // first look for existing SynchEvent struct.. >+ synch_event_mu.Lock(); >+ for (e = synch_event[h]; >+ e != nullptr && e->masked_addr != base_internal::HidePtr(addr); >+ e = e->next) { >+ } >+ if (e == nullptr) { // no SynchEvent struct found; make one. >+ if (name == nullptr) { >+ name = ""; >+ } >+ size_t l = strlen(name); >+ e = reinterpret_cast<SynchEvent *>( >+ base_internal::LowLevelAlloc::Alloc(sizeof(*e) + l)); >+ e->refcount = 2; // one for return value, one for linked list >+ e->masked_addr = base_internal::HidePtr(addr); >+ e->invariant = nullptr; >+ e->arg = nullptr; >+ e->log = false; >+ strcpy(e->name, name); // NOLINT(runtime/printf) >+ e->next = synch_event[h]; >+ AtomicSetBits(addr, bits, lockbit); >+ synch_event[h] = e; >+ } else { >+ e->refcount++; // for return value >+ } >+ synch_event_mu.Unlock(); >+ return e; >+} >+ >+// Deallocate the SynchEvent *e, whose refcount has fallen to zero. >+static void DeleteSynchEvent(SynchEvent *e) { >+ base_internal::LowLevelAlloc::Free(e); >+} >+ >+// Decrement the reference count of *e, or do nothing if e==null. >+static void UnrefSynchEvent(SynchEvent *e) { >+ if (e != nullptr) { >+ synch_event_mu.Lock(); >+ bool del = (--(e->refcount) == 0); >+ synch_event_mu.Unlock(); >+ if (del) { >+ DeleteSynchEvent(e); >+ } >+ } >+} >+ >+// Forget the mapping from the object (Mutex or CondVar) at address addr >+// to SynchEvent object, and clear "bits" in its word (waiting until lockbit >+// is clear before doing so). >+static void ForgetSynchEvent(std::atomic<intptr_t> *addr, intptr_t bits, >+ intptr_t lockbit) { >+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent; >+ SynchEvent **pe; >+ SynchEvent *e; >+ synch_event_mu.Lock(); >+ for (pe = &synch_event[h]; >+ (e = *pe) != nullptr && e->masked_addr != base_internal::HidePtr(addr); >+ pe = &e->next) { >+ } >+ bool del = false; >+ if (e != nullptr) { >+ *pe = e->next; >+ del = (--(e->refcount) == 0); >+ } >+ AtomicClearBits(addr, bits, lockbit); >+ synch_event_mu.Unlock(); >+ if (del) { >+ DeleteSynchEvent(e); >+ } >+} >+ >+// Return a refcounted reference to the SynchEvent of the object at address >+// "addr", if any. The pointer returned is valid until the UnrefSynchEvent() is >+// called. >+static SynchEvent *GetSynchEvent(const void *addr) { >+ uint32_t h = reinterpret_cast<intptr_t>(addr) % kNSynchEvent; >+ SynchEvent *e; >+ synch_event_mu.Lock(); >+ for (e = synch_event[h]; >+ e != nullptr && e->masked_addr != base_internal::HidePtr(addr); >+ e = e->next) { >+ } >+ if (e != nullptr) { >+ e->refcount++; >+ } >+ synch_event_mu.Unlock(); >+ return e; >+} >+ >+// Called when an event "ev" occurs on a Mutex of CondVar "obj" >+// if event recording is on >+static void PostSynchEvent(void *obj, int ev) { >+ SynchEvent *e = GetSynchEvent(obj); >+ // logging is on if event recording is on and either there's no event struct, >+ // or it explicitly says to log >+ if (e == nullptr || e->log) { >+ void *pcs[40]; >+ int n = absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 1); >+ // A buffer with enough space for the ASCII for all the PCs, even on a >+ // 64-bit machine. >+ char buffer[ABSL_ARRAYSIZE(pcs) * 24]; >+ int pos = snprintf(buffer, sizeof (buffer), " @"); >+ for (int i = 0; i != n; i++) { >+ pos += snprintf(&buffer[pos], sizeof (buffer) - pos, " %p", pcs[i]); >+ } >+ ABSL_RAW_LOG(INFO, "%s%p %s %s", event_properties[ev].msg, obj, >+ (e == nullptr ? "" : e->name), buffer); >+ } >+ if ((event_properties[ev].flags & SYNCH_F_LCK) != 0 && e != nullptr && >+ e->invariant != nullptr) { >+ (*e->invariant)(e->arg); >+ } >+ UnrefSynchEvent(e); >+} >+ >+//------------------------------------------------------------------ >+ >+// The SynchWaitParams struct encapsulates the way in which a thread is waiting: >+// whether it has a timeout, the condition, exclusive/shared, and whether a >+// condition variable wait has an associated Mutex (as opposed to another >+// type of lock). It also points to the PerThreadSynch struct of its thread. >+// cv_word tells Enqueue() to enqueue on a CondVar using CondVarEnqueue(). >+// >+// This structure is held on the stack rather than directly in >+// PerThreadSynch because a thread can be waiting on multiple Mutexes if, >+// while waiting on one Mutex, the implementation calls a client callback >+// (such as a Condition function) that acquires another Mutex. We don't >+// strictly need to allow this, but programmers become confused if we do not >+// allow them to use functions such a LOG() within Condition functions. The >+// PerThreadSynch struct points at the most recent SynchWaitParams struct when >+// the thread is on a Mutex's waiter queue. >+struct SynchWaitParams { >+ SynchWaitParams(Mutex::MuHow how_arg, const Condition *cond_arg, >+ KernelTimeout timeout_arg, Mutex *cvmu_arg, >+ PerThreadSynch *thread_arg, >+ std::atomic<intptr_t> *cv_word_arg) >+ : how(how_arg), >+ cond(cond_arg), >+ timeout(timeout_arg), >+ cvmu(cvmu_arg), >+ thread(thread_arg), >+ cv_word(cv_word_arg), >+ contention_start_cycles(base_internal::CycleClock::Now()) {} >+ >+ const Mutex::MuHow how; // How this thread needs to wait. >+ const Condition *cond; // The condition that this thread is waiting for. >+ // In Mutex, this field is set to zero if a timeout >+ // expires. >+ KernelTimeout timeout; // timeout expiry---absolute time >+ // In Mutex, this field is set to zero if a timeout >+ // expires. >+ Mutex *const cvmu; // used for transfer from cond var to mutex >+ PerThreadSynch *const thread; // thread that is waiting >+ >+ // If not null, thread should be enqueued on the CondVar whose state >+ // word is cv_word instead of queueing normally on the Mutex. >+ std::atomic<intptr_t> *cv_word; >+ >+ int64_t contention_start_cycles; // Time (in cycles) when this thread started >+ // to contend for the mutex. >+}; >+ >+struct SynchLocksHeld { >+ int n; // number of valid entries in locks[] >+ bool overflow; // true iff we overflowed the array at some point >+ struct { >+ Mutex *mu; // lock acquired >+ int32_t count; // times acquired >+ GraphId id; // deadlock_graph id of acquired lock >+ } locks[40]; >+ // If a thread overfills the array during deadlock detection, we >+ // continue, discarding information as needed. If no overflow has >+ // taken place, we can provide more error checking, such as >+ // detecting when a thread releases a lock it does not hold. >+}; >+ >+// A sentinel value in lists that is not 0. >+// A 0 value is used to mean "not on a list". >+static PerThreadSynch *const kPerThreadSynchNull = >+ reinterpret_cast<PerThreadSynch *>(1); >+ >+static SynchLocksHeld *LocksHeldAlloc() { >+ SynchLocksHeld *ret = reinterpret_cast<SynchLocksHeld *>( >+ base_internal::LowLevelAlloc::Alloc(sizeof(SynchLocksHeld))); >+ ret->n = 0; >+ ret->overflow = false; >+ return ret; >+} >+ >+// Return the PerThreadSynch-struct for this thread. >+static PerThreadSynch *Synch_GetPerThread() { >+ ThreadIdentity *identity = GetOrCreateCurrentThreadIdentity(); >+ return &identity->per_thread_synch; >+} >+ >+static PerThreadSynch *Synch_GetPerThreadAnnotated(Mutex *mu) { >+ if (mu) { >+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); >+ } >+ PerThreadSynch *w = Synch_GetPerThread(); >+ if (mu) { >+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0); >+ } >+ return w; >+} >+ >+static SynchLocksHeld *Synch_GetAllLocks() { >+ PerThreadSynch *s = Synch_GetPerThread(); >+ if (s->all_locks == nullptr) { >+ s->all_locks = LocksHeldAlloc(); // Freed by ReclaimThreadIdentity. >+ } >+ return s->all_locks; >+} >+ >+// Post on "w"'s associated PerThreadSem. >+inline void Mutex::IncrementSynchSem(Mutex *mu, PerThreadSynch *w) { >+ if (mu) { >+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); >+ } >+ PerThreadSem::Post(w->thread_identity()); >+ if (mu) { >+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0); >+ } >+} >+ >+// Wait on "w"'s associated PerThreadSem; returns false if timeout expired. >+bool Mutex::DecrementSynchSem(Mutex *mu, PerThreadSynch *w, KernelTimeout t) { >+ if (mu) { >+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); >+ } >+ assert(w == Synch_GetPerThread()); >+ static_cast<void>(w); >+ bool res = PerThreadSem::Wait(t); >+ if (mu) { >+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0); >+ } >+ return res; >+} >+ >+// We're in a fatal signal handler that hopes to use Mutex and to get >+// lucky by not deadlocking. We try to improve its chances of success >+// by effectively disabling some of the consistency checks. This will >+// prevent certain ABSL_RAW_CHECK() statements from being triggered when >+// re-rentry is detected. The ABSL_RAW_CHECK() statements are those in the >+// Mutex code checking that the "waitp" field has not been reused. >+void Mutex::InternalAttemptToUseMutexInFatalSignalHandler() { >+ // Fix the per-thread state only if it exists. >+ ThreadIdentity *identity = CurrentThreadIdentityIfPresent(); >+ if (identity != nullptr) { >+ identity->per_thread_synch.suppress_fatal_errors = true; >+ } >+ // Don't do deadlock detection when we are already failing. >+ synch_deadlock_detection.store(OnDeadlockCycle::kIgnore, >+ std::memory_order_release); >+} >+ >+// --------------------------time support >+ >+// Return the current time plus the timeout. Use the same clock as >+// PerThreadSem::Wait() for consistency. Unfortunately, we don't have >+// such a choice when a deadline is given directly. >+static absl::Time DeadlineFromTimeout(absl::Duration timeout) { >+#ifndef _WIN32 >+ struct timeval tv; >+ gettimeofday(&tv, nullptr); >+ return absl::TimeFromTimeval(tv) + timeout; >+#else >+ return absl::Now() + timeout; >+#endif >+} >+ >+// --------------------------Mutexes >+ >+// In the layout below, the msb of the bottom byte is currently unused. Also, >+// the following constraints were considered in choosing the layout: >+// o Both the debug allocator's "uninitialized" and "freed" patterns (0xab and >+// 0xcd) are illegal: reader and writer lock both held. >+// o kMuWriter and kMuEvent should exceed kMuDesig and kMuWait, to enable the >+// bit-twiddling trick in Mutex::Unlock(). >+// o kMuWriter / kMuReader == kMuWrWait / kMuWait, >+// to enable the bit-twiddling trick in CheckForMutexCorruption(). >+static const intptr_t kMuReader = 0x0001L; // a reader holds the lock >+static const intptr_t kMuDesig = 0x0002L; // there's a designated waker >+static const intptr_t kMuWait = 0x0004L; // threads are waiting >+static const intptr_t kMuWriter = 0x0008L; // a writer holds the lock >+static const intptr_t kMuEvent = 0x0010L; // record this mutex's events >+// INVARIANT1: there's a thread that was blocked on the mutex, is >+// no longer, yet has not yet acquired the mutex. If there's a >+// designated waker, all threads can avoid taking the slow path in >+// unlock because the designated waker will subsequently acquire >+// the lock and wake someone. To maintain INVARIANT1 the bit is >+// set when a thread is unblocked(INV1a), and threads that were >+// unblocked reset the bit when they either acquire or re-block >+// (INV1b). >+static const intptr_t kMuWrWait = 0x0020L; // runnable writer is waiting >+ // for a reader >+static const intptr_t kMuSpin = 0x0040L; // spinlock protects wait list >+static const intptr_t kMuLow = 0x00ffL; // mask all mutex bits >+static const intptr_t kMuHigh = ~kMuLow; // mask pointer/reader count >+ >+// Hack to make constant values available to gdb pretty printer >+enum { >+ kGdbMuSpin = kMuSpin, >+ kGdbMuEvent = kMuEvent, >+ kGdbMuWait = kMuWait, >+ kGdbMuWriter = kMuWriter, >+ kGdbMuDesig = kMuDesig, >+ kGdbMuWrWait = kMuWrWait, >+ kGdbMuReader = kMuReader, >+ kGdbMuLow = kMuLow, >+}; >+ >+// kMuWrWait implies kMuWait. >+// kMuReader and kMuWriter are mutually exclusive. >+// If kMuReader is zero, there are no readers. >+// Otherwise, if kMuWait is zero, the high order bits contain a count of the >+// number of readers. Otherwise, the reader count is held in >+// PerThreadSynch::readers of the most recently queued waiter, again in the >+// bits above kMuLow. >+static const intptr_t kMuOne = 0x0100; // a count of one reader >+ >+// flags passed to Enqueue and LockSlow{,WithTimeout,Loop} >+static const int kMuHasBlocked = 0x01; // already blocked (MUST == 1) >+static const int kMuIsCond = 0x02; // conditional waiter (CV or Condition) >+ >+static_assert(PerThreadSynch::kAlignment > kMuLow, >+ "PerThreadSynch::kAlignment must be greater than kMuLow"); >+ >+// This struct contains various bitmasks to be used in >+// acquiring and releasing a mutex in a particular mode. >+struct MuHowS { >+ // if all the bits in fast_need_zero are zero, the lock can be acquired by >+ // adding fast_add and oring fast_or. The bit kMuDesig should be reset iff >+ // this is the designated waker. >+ intptr_t fast_need_zero; >+ intptr_t fast_or; >+ intptr_t fast_add; >+ >+ intptr_t slow_need_zero; // fast_need_zero with events (e.g. logging) >+ >+ intptr_t slow_inc_need_zero; // if all the bits in slow_inc_need_zero are >+ // zero a reader can acquire a read share by >+ // setting the reader bit and incrementing >+ // the reader count (in last waiter since >+ // we're now slow-path). kMuWrWait be may >+ // be ignored if we already waited once. >+}; >+ >+static const MuHowS kSharedS = { >+ // shared or read lock >+ kMuWriter | kMuWait | kMuEvent, // fast_need_zero >+ kMuReader, // fast_or >+ kMuOne, // fast_add >+ kMuWriter | kMuWait, // slow_need_zero >+ kMuSpin | kMuWriter | kMuWrWait, // slow_inc_need_zero >+}; >+static const MuHowS kExclusiveS = { >+ // exclusive or write lock >+ kMuWriter | kMuReader | kMuEvent, // fast_need_zero >+ kMuWriter, // fast_or >+ 0, // fast_add >+ kMuWriter | kMuReader, // slow_need_zero >+ ~static_cast<intptr_t>(0), // slow_inc_need_zero >+}; >+static const Mutex::MuHow kShared = &kSharedS; // shared lock >+static const Mutex::MuHow kExclusive = &kExclusiveS; // exclusive lock >+ >+#ifdef NDEBUG >+static constexpr bool kDebugMode = false; >+#else >+static constexpr bool kDebugMode = true; >+#endif >+ >+#ifdef THREAD_SANITIZER >+static unsigned TsanFlags(Mutex::MuHow how) { >+ return how == kShared ? __tsan_mutex_read_lock : 0; >+} >+#endif >+ >+static bool DebugOnlyIsExiting() { >+ return false; >+} >+ >+Mutex::~Mutex() { >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ if ((v & kMuEvent) != 0 && !DebugOnlyIsExiting()) { >+ ForgetSynchEvent(&this->mu_, kMuEvent, kMuSpin); >+ } >+ if (kDebugMode) { >+ this->ForgetDeadlockInfo(); >+ } >+ ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); >+} >+ >+void Mutex::EnableDebugLog(const char *name) { >+ SynchEvent *e = EnsureSynchEvent(&this->mu_, name, kMuEvent, kMuSpin); >+ e->log = true; >+ UnrefSynchEvent(e); >+} >+ >+void EnableMutexInvariantDebugging(bool enabled) { >+ synch_check_invariants.store(enabled, std::memory_order_release); >+} >+ >+void Mutex::EnableInvariantDebugging(void (*invariant)(void *), >+ void *arg) { >+ if (synch_check_invariants.load(std::memory_order_acquire) && >+ invariant != nullptr) { >+ SynchEvent *e = EnsureSynchEvent(&this->mu_, nullptr, kMuEvent, kMuSpin); >+ e->invariant = invariant; >+ e->arg = arg; >+ UnrefSynchEvent(e); >+ } >+} >+ >+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode) { >+ synch_deadlock_detection.store(mode, std::memory_order_release); >+} >+ >+// Return true iff threads x and y are waiting on the same condition for the >+// same type of lock. Requires that x and y be waiting on the same Mutex >+// queue. >+static bool MuSameCondition(PerThreadSynch *x, PerThreadSynch *y) { >+ return x->waitp->how == y->waitp->how && >+ Condition::GuaranteedEqual(x->waitp->cond, y->waitp->cond); >+} >+ >+// Given the contents of a mutex word containing a PerThreadSynch pointer, >+// return the pointer. >+static inline PerThreadSynch *GetPerThreadSynch(intptr_t v) { >+ return reinterpret_cast<PerThreadSynch *>(v & kMuHigh); >+} >+ >+// The next several routines maintain the per-thread next and skip fields >+// used in the Mutex waiter queue. >+// The queue is a circular singly-linked list, of which the "head" is the >+// last element, and head->next if the first element. >+// The skip field has the invariant: >+// For thread x, x->skip is one of: >+// - invalid (iff x is not in a Mutex wait queue), >+// - null, or >+// - a pointer to a distinct thread waiting later in the same Mutex queue >+// such that all threads in [x, x->skip] have the same condition and >+// lock type (MuSameCondition() is true for all pairs in [x, x->skip]). >+// In addition, if x->skip is valid, (x->may_skip || x->skip == null) >+// >+// By the spec of MuSameCondition(), it is not necessary when removing the >+// first runnable thread y from the front a Mutex queue to adjust the skip >+// field of another thread x because if x->skip==y, x->skip must (have) become >+// invalid before y is removed. The function TryRemove can remove a specified >+// thread from an arbitrary position in the queue whether runnable or not, so >+// it fixes up skip fields that would otherwise be left dangling. >+// The statement >+// if (x->may_skip && MuSameCondition(x, x->next)) { x->skip = x->next; } >+// maintains the invariant provided x is not the last waiter in a Mutex queue >+// The statement >+// if (x->skip != null) { x->skip = x->skip->skip; } >+// maintains the invariant. >+ >+// Returns the last thread y in a mutex waiter queue such that all threads in >+// [x, y] inclusive share the same condition. Sets skip fields of some threads >+// in that range to optimize future evaluation of Skip() on x values in >+// the range. Requires thread x is in a mutex waiter queue. >+// The locking is unusual. Skip() is called under these conditions: >+// - spinlock is held in call from Enqueue(), with maybe_unlocking == false >+// - Mutex is held in call from UnlockSlow() by last unlocker, with >+// maybe_unlocking == true >+// - both Mutex and spinlock are held in call from DequeueAllWakeable() (from >+// UnlockSlow()) and TryRemove() >+// These cases are mutually exclusive, so Skip() never runs concurrently >+// with itself on the same Mutex. The skip chain is used in these other places >+// that cannot occur concurrently: >+// - FixSkip() (from TryRemove()) - spinlock and Mutex are held) >+// - Dequeue() (with spinlock and Mutex held) >+// - UnlockSlow() (with spinlock and Mutex held) >+// A more complex case is Enqueue() >+// - Enqueue() (with spinlock held and maybe_unlocking == false) >+// This is the first case in which Skip is called, above. >+// - Enqueue() (without spinlock held; but queue is empty and being freshly >+// formed) >+// - Enqueue() (with spinlock held and maybe_unlocking == true) >+// The first case has mutual exclusion, and the second isolation through >+// working on an otherwise unreachable data structure. >+// In the last case, Enqueue() is required to change no skip/next pointers >+// except those in the added node and the former "head" node. This implies >+// that the new node is added after head, and so must be the new head or the >+// new front of the queue. >+static PerThreadSynch *Skip(PerThreadSynch *x) { >+ PerThreadSynch *x0 = nullptr; >+ PerThreadSynch *x1 = x; >+ PerThreadSynch *x2 = x->skip; >+ if (x2 != nullptr) { >+ // Each iteration attempts to advance sequence (x0,x1,x2) to next sequence >+ // such that x1 == x0->skip && x2 == x1->skip >+ while ((x0 = x1, x1 = x2, x2 = x2->skip) != nullptr) { >+ x0->skip = x2; // short-circuit skip from x0 to x2 >+ } >+ x->skip = x1; // short-circuit skip from x to result >+ } >+ return x1; >+} >+ >+// "ancestor" appears before "to_be_removed" in the same Mutex waiter queue. >+// The latter is going to be removed out of order, because of a timeout. >+// Check whether "ancestor" has a skip field pointing to "to_be_removed", >+// and fix it if it does. >+static void FixSkip(PerThreadSynch *ancestor, PerThreadSynch *to_be_removed) { >+ if (ancestor->skip == to_be_removed) { // ancestor->skip left dangling >+ if (to_be_removed->skip != nullptr) { >+ ancestor->skip = to_be_removed->skip; // can skip past to_be_removed >+ } else if (ancestor->next != to_be_removed) { // they are not adjacent >+ ancestor->skip = ancestor->next; // can skip one past ancestor >+ } else { >+ ancestor->skip = nullptr; // can't skip at all >+ } >+ } >+} >+ >+static void CondVarEnqueue(SynchWaitParams *waitp); >+ >+// Enqueue thread "waitp->thread" on a waiter queue. >+// Called with mutex spinlock held if head != nullptr >+// If head==nullptr and waitp->cv_word==nullptr, then Enqueue() is >+// idempotent; it alters no state associated with the existing (empty) >+// queue. >+// >+// If waitp->cv_word == nullptr, queue the thread at either the front or >+// the end (according to its priority) of the circular mutex waiter queue whose >+// head is "head", and return the new head. mu is the previous mutex state, >+// which contains the reader count (perhaps adjusted for the operation in >+// progress) if the list was empty and a read lock held, and the holder hint if >+// the list was empty and a write lock held. (flags & kMuIsCond) indicates >+// whether this thread was transferred from a CondVar or is waiting for a >+// non-trivial condition. In this case, Enqueue() never returns nullptr >+// >+// If waitp->cv_word != nullptr, CondVarEnqueue() is called, and "head" is >+// returned. This mechanism is used by CondVar to queue a thread on the >+// condition variable queue instead of the mutex queue in implementing Wait(). >+// In this case, Enqueue() can return nullptr (if head==nullptr). >+static PerThreadSynch *Enqueue(PerThreadSynch *head, >+ SynchWaitParams *waitp, intptr_t mu, int flags) { >+ // If we have been given a cv_word, call CondVarEnqueue() and return >+ // the previous head of the Mutex waiter queue. >+ if (waitp->cv_word != nullptr) { >+ CondVarEnqueue(waitp); >+ return head; >+ } >+ >+ PerThreadSynch *s = waitp->thread; >+ ABSL_RAW_CHECK( >+ s->waitp == nullptr || // normal case >+ s->waitp == waitp || // Fer()---transfer from condition variable >+ s->suppress_fatal_errors, >+ "detected illegal recursion into Mutex code"); >+ s->waitp = waitp; >+ s->skip = nullptr; // maintain skip invariant (see above) >+ s->may_skip = true; // always true on entering queue >+ s->wake = false; // not being woken >+ s->cond_waiter = ((flags & kMuIsCond) != 0); >+ if (head == nullptr) { // s is the only waiter >+ s->next = s; // it's the only entry in the cycle >+ s->readers = mu; // reader count is from mu word >+ s->maybe_unlocking = false; // no one is searching an empty list >+ head = s; // s is new head >+ } else { >+ PerThreadSynch *enqueue_after = nullptr; // we'll put s after this element >+#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM >+ int64_t now_cycles = base_internal::CycleClock::Now(); >+ if (s->next_priority_read_cycles < now_cycles) { >+ // Every so often, update our idea of the thread's priority. >+ // pthread_getschedparam() is 5% of the block/wakeup time; >+ // base_internal::CycleClock::Now() is 0.5%. >+ int policy; >+ struct sched_param param; >+ pthread_getschedparam(pthread_self(), &policy, ¶m); >+ s->priority = param.sched_priority; >+ s->next_priority_read_cycles = >+ now_cycles + >+ static_cast<int64_t>(base_internal::CycleClock::Frequency()); >+ } >+ if (s->priority > head->priority) { // s's priority is above head's >+ // try to put s in priority-fifo order, or failing that at the front. >+ if (!head->maybe_unlocking) { >+ // No unlocker can be scanning the queue, so we can insert between >+ // skip-chains, and within a skip-chain if it has the same condition as >+ // s. We insert in priority-fifo order, examining the end of every >+ // skip-chain, plus every element with the same condition as s. >+ PerThreadSynch *advance_to = head; // next value of enqueue_after >+ PerThreadSynch *cur; // successor of enqueue_after >+ do { >+ enqueue_after = advance_to; >+ cur = enqueue_after->next; // this advance ensures progress >+ advance_to = Skip(cur); // normally, advance to end of skip chain >+ // (side-effect: optimizes skip chain) >+ if (advance_to != cur && s->priority > advance_to->priority && >+ MuSameCondition(s, cur)) { >+ // but this skip chain is not a singleton, s has higher priority >+ // than its tail and has the same condition as the chain, >+ // so we can insert within the skip-chain >+ advance_to = cur; // advance by just one >+ } >+ } while (s->priority <= advance_to->priority); >+ // termination guaranteed because s->priority > head->priority >+ // and head is the end of a skip chain >+ } else if (waitp->how == kExclusive && >+ Condition::GuaranteedEqual(waitp->cond, nullptr)) { >+ // An unlocker could be scanning the queue, but we know it will recheck >+ // the queue front for writers that have no condition, which is what s >+ // is, so an insert at front is safe. >+ enqueue_after = head; // add after head, at front >+ } >+ } >+#endif >+ if (enqueue_after != nullptr) { >+ s->next = enqueue_after->next; >+ enqueue_after->next = s; >+ >+ // enqueue_after can be: head, Skip(...), or cur. >+ // The first two imply enqueue_after->skip == nullptr, and >+ // the last is used only if MuSameCondition(s, cur). >+ // We require this because clearing enqueue_after->skip >+ // is impossible; enqueue_after's predecessors might also >+ // incorrectly skip over s if we were to allow other >+ // insertion points. >+ ABSL_RAW_CHECK( >+ enqueue_after->skip == nullptr || MuSameCondition(enqueue_after, s), >+ "Mutex Enqueue failure"); >+ >+ if (enqueue_after != head && enqueue_after->may_skip && >+ MuSameCondition(enqueue_after, enqueue_after->next)) { >+ // enqueue_after can skip to its new successor, s >+ enqueue_after->skip = enqueue_after->next; >+ } >+ if (MuSameCondition(s, s->next)) { // s->may_skip is known to be true >+ s->skip = s->next; // s may skip to its successor >+ } >+ } else { // enqueue not done any other way, so >+ // we're inserting s at the back >+ // s will become new head; copy data from head into it >+ s->next = head->next; // add s after head >+ head->next = s; >+ s->readers = head->readers; // reader count is from previous head >+ s->maybe_unlocking = head->maybe_unlocking; // same for unlock hint >+ if (head->may_skip && MuSameCondition(head, s)) { >+ // head now has successor; may skip >+ head->skip = s; >+ } >+ head = s; // s is new head >+ } >+ } >+ s->state.store(PerThreadSynch::kQueued, std::memory_order_relaxed); >+ return head; >+} >+ >+// Dequeue the successor pw->next of thread pw from the Mutex waiter queue >+// whose last element is head. The new head element is returned, or null >+// if the list is made empty. >+// Dequeue is called with both spinlock and Mutex held. >+static PerThreadSynch *Dequeue(PerThreadSynch *head, PerThreadSynch *pw) { >+ PerThreadSynch *w = pw->next; >+ pw->next = w->next; // snip w out of list >+ if (head == w) { // we removed the head >+ head = (pw == w) ? nullptr : pw; // either emptied list, or pw is new head >+ } else if (pw != head && MuSameCondition(pw, pw->next)) { >+ // pw can skip to its new successor >+ if (pw->next->skip != >+ nullptr) { // either skip to its successors skip target >+ pw->skip = pw->next->skip; >+ } else { // or to pw's successor >+ pw->skip = pw->next; >+ } >+ } >+ return head; >+} >+ >+// Traverse the elements [ pw->next, h] of the circular list whose last element >+// is head. >+// Remove all elements with wake==true and place them in the >+// singly-linked list wake_list in the order found. Assumes that >+// there is only one such element if the element has how == kExclusive. >+// Return the new head. >+static PerThreadSynch *DequeueAllWakeable(PerThreadSynch *head, >+ PerThreadSynch *pw, >+ PerThreadSynch **wake_tail) { >+ PerThreadSynch *orig_h = head; >+ PerThreadSynch *w = pw->next; >+ bool skipped = false; >+ do { >+ if (w->wake) { // remove this element >+ ABSL_RAW_CHECK(pw->skip == nullptr, "bad skip in DequeueAllWakeable"); >+ // we're removing pw's successor so either pw->skip is zero or we should >+ // already have removed pw since if pw->skip!=null, pw has the same >+ // condition as w. >+ head = Dequeue(head, pw); >+ w->next = *wake_tail; // keep list terminated >+ *wake_tail = w; // add w to wake_list; >+ wake_tail = &w->next; // next addition to end >+ if (w->waitp->how == kExclusive) { // wake at most 1 writer >+ break; >+ } >+ } else { // not waking this one; skip >+ pw = Skip(w); // skip as much as possible >+ skipped = true; >+ } >+ w = pw->next; >+ // We want to stop processing after we've considered the original head, >+ // orig_h. We can't test for w==orig_h in the loop because w may skip over >+ // it; we are guaranteed only that w's predecessor will not skip over >+ // orig_h. When we've considered orig_h, either we've processed it and >+ // removed it (so orig_h != head), or we considered it and skipped it (so >+ // skipped==true && pw == head because skipping from head always skips by >+ // just one, leaving pw pointing at head). So we want to >+ // continue the loop with the negation of that expression. >+ } while (orig_h == head && (pw != head || !skipped)); >+ return head; >+} >+ >+// Try to remove thread s from the list of waiters on this mutex. >+// Does nothing if s is not on the waiter list. >+void Mutex::TryRemove(PerThreadSynch *s) { >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ // acquire spinlock & lock >+ if ((v & (kMuWait | kMuSpin | kMuWriter | kMuReader)) == kMuWait && >+ mu_.compare_exchange_strong(v, v | kMuSpin | kMuWriter, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ PerThreadSynch *h = GetPerThreadSynch(v); >+ if (h != nullptr) { >+ PerThreadSynch *pw = h; // pw is w's predecessor >+ PerThreadSynch *w; >+ if ((w = pw->next) != s) { // search for thread, >+ do { // processing at least one element >+ if (!MuSameCondition(s, w)) { // seeking different condition >+ pw = Skip(w); // so skip all that won't match >+ // we don't have to worry about dangling skip fields >+ // in the threads we skipped; none can point to s >+ // because their condition differs from s >+ } else { // seeking same condition >+ FixSkip(w, s); // fix up any skip pointer from w to s >+ pw = w; >+ } >+ // don't search further if we found the thread, or we're about to >+ // process the first thread again. >+ } while ((w = pw->next) != s && pw != h); >+ } >+ if (w == s) { // found thread; remove it >+ // pw->skip may be non-zero here; the loop above ensured that >+ // no ancestor of s can skip to s, so removal is safe anyway. >+ h = Dequeue(h, pw); >+ s->next = nullptr; >+ s->state.store(PerThreadSynch::kAvailable, std::memory_order_release); >+ } >+ } >+ intptr_t nv; >+ do { // release spinlock and lock >+ v = mu_.load(std::memory_order_relaxed); >+ nv = v & (kMuDesig | kMuEvent); >+ if (h != nullptr) { >+ nv |= kMuWait | reinterpret_cast<intptr_t>(h); >+ h->readers = 0; // we hold writer lock >+ h->maybe_unlocking = false; // finished unlocking >+ } >+ } while (!mu_.compare_exchange_weak(v, nv, >+ std::memory_order_release, >+ std::memory_order_relaxed)); >+ } >+} >+ >+// Wait until thread "s", which must be the current thread, is removed from the >+// this mutex's waiter queue. If "s->waitp->timeout" has a timeout, wake up >+// if the wait extends past the absolute time specified, even if "s" is still >+// on the mutex queue. In this case, remove "s" from the queue and return >+// true, otherwise return false. >+void Mutex::Block(PerThreadSynch *s) { >+ while (s->state.load(std::memory_order_acquire) == PerThreadSynch::kQueued) { >+ if (!DecrementSynchSem(this, s, s->waitp->timeout)) { >+ // After a timeout, we go into a spin loop until we remove ourselves >+ // from the queue, or someone else removes us. We can't be sure to be >+ // able to remove ourselves in a single lock acquisition because this >+ // mutex may be held, and the holder has the right to read the centre >+ // of the waiter queue without holding the spinlock. >+ this->TryRemove(s); >+ int c = 0; >+ while (s->next != nullptr) { >+ c = Delay(c, GENTLE); >+ this->TryRemove(s); >+ } >+ if (kDebugMode) { >+ // This ensures that we test the case that TryRemove() is called when s >+ // is not on the queue. >+ this->TryRemove(s); >+ } >+ s->waitp->timeout = KernelTimeout::Never(); // timeout is satisfied >+ s->waitp->cond = nullptr; // condition no longer relevant for wakeups >+ } >+ } >+ ABSL_RAW_CHECK(s->waitp != nullptr || s->suppress_fatal_errors, >+ "detected illegal recursion in Mutex code"); >+ s->waitp = nullptr; >+} >+ >+// Wake thread w, and return the next thread in the list. >+PerThreadSynch *Mutex::Wakeup(PerThreadSynch *w) { >+ PerThreadSynch *next = w->next; >+ w->next = nullptr; >+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release); >+ IncrementSynchSem(this, w); >+ >+ return next; >+} >+ >+static GraphId GetGraphIdLocked(Mutex *mu) >+ EXCLUSIVE_LOCKS_REQUIRED(deadlock_graph_mu) { >+ if (!deadlock_graph) { // (re)create the deadlock graph. >+ deadlock_graph = >+ new (base_internal::LowLevelAlloc::Alloc(sizeof(*deadlock_graph))) >+ GraphCycles; >+ } >+ return deadlock_graph->GetId(mu); >+} >+ >+static GraphId GetGraphId(Mutex *mu) LOCKS_EXCLUDED(deadlock_graph_mu) { >+ deadlock_graph_mu.Lock(); >+ GraphId id = GetGraphIdLocked(mu); >+ deadlock_graph_mu.Unlock(); >+ return id; >+} >+ >+// Record a lock acquisition. This is used in debug mode for deadlock >+// detection. The held_locks pointer points to the relevant data >+// structure for each case. >+static void LockEnter(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { >+ int n = held_locks->n; >+ int i = 0; >+ while (i != n && held_locks->locks[i].id != id) { >+ i++; >+ } >+ if (i == n) { >+ if (n == ABSL_ARRAYSIZE(held_locks->locks)) { >+ held_locks->overflow = true; // lost some data >+ } else { // we have room for lock >+ held_locks->locks[i].mu = mu; >+ held_locks->locks[i].count = 1; >+ held_locks->locks[i].id = id; >+ held_locks->n = n + 1; >+ } >+ } else { >+ held_locks->locks[i].count++; >+ } >+} >+ >+// Record a lock release. Each call to LockEnter(mu, id, x) should be >+// eventually followed by a call to LockLeave(mu, id, x) by the same thread. >+// It does not process the event if is not needed when deadlock detection is >+// disabled. >+static void LockLeave(Mutex* mu, GraphId id, SynchLocksHeld *held_locks) { >+ int n = held_locks->n; >+ int i = 0; >+ while (i != n && held_locks->locks[i].id != id) { >+ i++; >+ } >+ if (i == n) { >+ if (!held_locks->overflow) { >+ // The deadlock id may have been reassigned after ForgetDeadlockInfo, >+ // but in that case mu should still be present. >+ i = 0; >+ while (i != n && held_locks->locks[i].mu != mu) { >+ i++; >+ } >+ if (i == n) { // mu missing means releasing unheld lock >+ SynchEvent *mu_events = GetSynchEvent(mu); >+ ABSL_RAW_LOG(FATAL, >+ "thread releasing lock it does not hold: %p %s; " >+ , >+ static_cast<void *>(mu), >+ mu_events == nullptr ? "" : mu_events->name); >+ } >+ } >+ } else if (held_locks->locks[i].count == 1) { >+ held_locks->n = n - 1; >+ held_locks->locks[i] = held_locks->locks[n - 1]; >+ held_locks->locks[n - 1].id = InvalidGraphId(); >+ held_locks->locks[n - 1].mu = >+ nullptr; // clear mu to please the leak detector. >+ } else { >+ assert(held_locks->locks[i].count > 0); >+ held_locks->locks[i].count--; >+ } >+} >+ >+// Call LockEnter() if in debug mode and deadlock detection is enabled. >+static inline void DebugOnlyLockEnter(Mutex *mu) { >+ if (kDebugMode) { >+ if (synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ LockEnter(mu, GetGraphId(mu), Synch_GetAllLocks()); >+ } >+ } >+} >+ >+// Call LockEnter() if in debug mode and deadlock detection is enabled. >+static inline void DebugOnlyLockEnter(Mutex *mu, GraphId id) { >+ if (kDebugMode) { >+ if (synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ LockEnter(mu, id, Synch_GetAllLocks()); >+ } >+ } >+} >+ >+// Call LockLeave() if in debug mode and deadlock detection is enabled. >+static inline void DebugOnlyLockLeave(Mutex *mu) { >+ if (kDebugMode) { >+ if (synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ LockLeave(mu, GetGraphId(mu), Synch_GetAllLocks()); >+ } >+ } >+} >+ >+static char *StackString(void **pcs, int n, char *buf, int maxlen, >+ bool symbolize) { >+ static const int kSymLen = 200; >+ char sym[kSymLen]; >+ int len = 0; >+ for (int i = 0; i != n; i++) { >+ if (symbolize) { >+ if (!symbolizer(pcs[i], sym, kSymLen)) { >+ sym[0] = '\0'; >+ } >+ snprintf(buf + len, maxlen - len, "%s\t@ %p %s\n", >+ (i == 0 ? "\n" : ""), >+ pcs[i], sym); >+ } else { >+ snprintf(buf + len, maxlen - len, " %p", pcs[i]); >+ } >+ len += strlen(&buf[len]); >+ } >+ return buf; >+} >+ >+static char *CurrentStackString(char *buf, int maxlen, bool symbolize) { >+ void *pcs[40]; >+ return StackString(pcs, absl::GetStackTrace(pcs, ABSL_ARRAYSIZE(pcs), 2), buf, >+ maxlen, symbolize); >+} >+ >+namespace { >+enum { kMaxDeadlockPathLen = 10 }; // maximum length of a deadlock cycle; >+ // a path this long would be remarkable >+// Buffers required to report a deadlock. >+// We do not allocate them on stack to avoid large stack frame. >+struct DeadlockReportBuffers { >+ char buf[6100]; >+ GraphId path[kMaxDeadlockPathLen]; >+}; >+ >+struct ScopedDeadlockReportBuffers { >+ ScopedDeadlockReportBuffers() { >+ b = reinterpret_cast<DeadlockReportBuffers *>( >+ base_internal::LowLevelAlloc::Alloc(sizeof(*b))); >+ } >+ ~ScopedDeadlockReportBuffers() { base_internal::LowLevelAlloc::Free(b); } >+ DeadlockReportBuffers *b; >+}; >+ >+// Helper to pass to GraphCycles::UpdateStackTrace. >+int GetStack(void** stack, int max_depth) { >+ return absl::GetStackTrace(stack, max_depth, 3); >+} >+} // anonymous namespace >+ >+// Called in debug mode when a thread is about to acquire a lock in a way that >+// may block. >+static GraphId DeadlockCheck(Mutex *mu) { >+ if (synch_deadlock_detection.load(std::memory_order_acquire) == >+ OnDeadlockCycle::kIgnore) { >+ return InvalidGraphId(); >+ } >+ >+ SynchLocksHeld *all_locks = Synch_GetAllLocks(); >+ >+ absl::base_internal::SpinLockHolder lock(&deadlock_graph_mu); >+ const GraphId mu_id = GetGraphIdLocked(mu); >+ >+ if (all_locks->n == 0) { >+ // There are no other locks held. Return now so that we don't need to >+ // call GetSynchEvent(). This way we do not record the stack trace >+ // for this Mutex. It's ok, since if this Mutex is involved in a deadlock, >+ // it can't always be the first lock acquired by a thread. >+ return mu_id; >+ } >+ >+ // We prefer to keep stack traces that show a thread holding and acquiring >+ // as many locks as possible. This increases the chances that a given edge >+ // in the acquires-before graph will be represented in the stack traces >+ // recorded for the locks. >+ deadlock_graph->UpdateStackTrace(mu_id, all_locks->n + 1, GetStack); >+ >+ // For each other mutex already held by this thread: >+ for (int i = 0; i != all_locks->n; i++) { >+ const GraphId other_node_id = all_locks->locks[i].id; >+ const Mutex *other = >+ static_cast<const Mutex *>(deadlock_graph->Ptr(other_node_id)); >+ if (other == nullptr) { >+ // Ignore stale lock >+ continue; >+ } >+ >+ // Add the acquired-before edge to the graph. >+ if (!deadlock_graph->InsertEdge(other_node_id, mu_id)) { >+ ScopedDeadlockReportBuffers scoped_buffers; >+ DeadlockReportBuffers *b = scoped_buffers.b; >+ static int number_of_reported_deadlocks = 0; >+ number_of_reported_deadlocks++; >+ // Symbolize only 2 first deadlock report to avoid huge slowdowns. >+ bool symbolize = number_of_reported_deadlocks <= 2; >+ ABSL_RAW_LOG(ERROR, "Potential Mutex deadlock: %s", >+ CurrentStackString(b->buf, sizeof (b->buf), symbolize)); >+ int len = 0; >+ for (int j = 0; j != all_locks->n; j++) { >+ void* pr = deadlock_graph->Ptr(all_locks->locks[j].id); >+ if (pr != nullptr) { >+ snprintf(b->buf + len, sizeof (b->buf) - len, " %p", pr); >+ len += static_cast<int>(strlen(&b->buf[len])); >+ } >+ } >+ ABSL_RAW_LOG(ERROR, "Acquiring %p Mutexes held: %s", >+ static_cast<void *>(mu), b->buf); >+ ABSL_RAW_LOG(ERROR, "Cycle: "); >+ int path_len = deadlock_graph->FindPath( >+ mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path); >+ for (int j = 0; j != path_len; j++) { >+ GraphId id = b->path[j]; >+ Mutex *path_mu = static_cast<Mutex *>(deadlock_graph->Ptr(id)); >+ if (path_mu == nullptr) continue; >+ void** stack; >+ int depth = deadlock_graph->GetStackTrace(id, &stack); >+ snprintf(b->buf, sizeof(b->buf), >+ "mutex@%p stack: ", static_cast<void *>(path_mu)); >+ StackString(stack, depth, b->buf + strlen(b->buf), >+ static_cast<int>(sizeof(b->buf) - strlen(b->buf)), >+ symbolize); >+ ABSL_RAW_LOG(ERROR, "%s", b->buf); >+ } >+ if (synch_deadlock_detection.load(std::memory_order_acquire) == >+ OnDeadlockCycle::kAbort) { >+ deadlock_graph_mu.Unlock(); // avoid deadlock in fatal sighandler >+ ABSL_RAW_LOG(FATAL, "dying due to potential deadlock"); >+ return mu_id; >+ } >+ break; // report at most one potential deadlock per acquisition >+ } >+ } >+ >+ return mu_id; >+} >+ >+// Invoke DeadlockCheck() iff we're in debug mode and >+// deadlock checking has been enabled. >+static inline GraphId DebugOnlyDeadlockCheck(Mutex *mu) { >+ if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ return DeadlockCheck(mu); >+ } else { >+ return InvalidGraphId(); >+ } >+} >+ >+void Mutex::ForgetDeadlockInfo() { >+ if (kDebugMode && synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ deadlock_graph_mu.Lock(); >+ if (deadlock_graph != nullptr) { >+ deadlock_graph->RemoveNode(this); >+ } >+ deadlock_graph_mu.Unlock(); >+ } >+} >+ >+void Mutex::AssertNotHeld() const { >+ // We have the data to allow this check only if in debug mode and deadlock >+ // detection is enabled. >+ if (kDebugMode && >+ (mu_.load(std::memory_order_relaxed) & (kMuWriter | kMuReader)) != 0 && >+ synch_deadlock_detection.load(std::memory_order_acquire) != >+ OnDeadlockCycle::kIgnore) { >+ GraphId id = GetGraphId(const_cast<Mutex *>(this)); >+ SynchLocksHeld *locks = Synch_GetAllLocks(); >+ for (int i = 0; i != locks->n; i++) { >+ if (locks->locks[i].id == id) { >+ SynchEvent *mu_events = GetSynchEvent(this); >+ ABSL_RAW_LOG(FATAL, "thread should not hold mutex %p %s", >+ static_cast<const void *>(this), >+ (mu_events == nullptr ? "" : mu_events->name)); >+ } >+ } >+ } >+} >+ >+// Attempt to acquire *mu, and return whether successful. The implementation >+// may spin for a short while if the lock cannot be acquired immediately. >+static bool TryAcquireWithSpinning(std::atomic<intptr_t>* mu) { >+ int c = mutex_globals.spinloop_iterations; >+ int result = -1; // result of operation: 0=false, 1=true, -1=unknown >+ >+ do { // do/while somewhat faster on AMD >+ intptr_t v = mu->load(std::memory_order_relaxed); >+ if ((v & (kMuReader|kMuEvent)) != 0) { // a reader or tracing -> give up >+ result = 0; >+ } else if (((v & kMuWriter) == 0) && // no holder -> try to acquire >+ mu->compare_exchange_strong(v, kMuWriter | v, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ result = 1; >+ } >+ } while (result == -1 && --c > 0); >+ return result == 1; >+} >+ >+ABSL_XRAY_LOG_ARGS(1) void Mutex::Lock() { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ // try fast acquire, then spin loop >+ if ((v & (kMuWriter | kMuReader | kMuEvent)) != 0 || >+ !mu_.compare_exchange_strong(v, kMuWriter | v, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ // try spin acquire, then slow loop >+ if (!TryAcquireWithSpinning(&this->mu_)) { >+ this->LockSlow(kExclusive, nullptr, 0); >+ } >+ } >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); >+} >+ >+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderLock() { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ // try fast acquire, then slow loop >+ if ((v & (kMuWriter | kMuWait | kMuEvent)) != 0 || >+ !mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ this->LockSlow(kShared, nullptr, 0); >+ } >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); >+} >+ >+void Mutex::LockWhen(const Condition &cond) { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ this->LockSlow(kExclusive, &cond, 0); >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); >+} >+ >+bool Mutex::LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) { >+ return LockWhenWithDeadline(cond, DeadlineFromTimeout(timeout)); >+} >+ >+bool Mutex::LockWhenWithDeadline(const Condition &cond, absl::Time deadline) { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, 0); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ bool res = LockSlowWithDeadline(kExclusive, &cond, >+ KernelTimeout(deadline), 0); >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0); >+ return res; >+} >+ >+void Mutex::ReaderLockWhen(const Condition &cond) { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ this->LockSlow(kShared, &cond, 0); >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); >+} >+ >+bool Mutex::ReaderLockWhenWithTimeout(const Condition &cond, >+ absl::Duration timeout) { >+ return ReaderLockWhenWithDeadline(cond, DeadlineFromTimeout(timeout)); >+} >+ >+bool Mutex::ReaderLockWhenWithDeadline(const Condition &cond, >+ absl::Time deadline) { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_read_lock); >+ GraphId id = DebugOnlyDeadlockCheck(this); >+ bool res = LockSlowWithDeadline(kShared, &cond, KernelTimeout(deadline), 0); >+ DebugOnlyLockEnter(this, id); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_read_lock, 0); >+ return res; >+} >+ >+void Mutex::Await(const Condition &cond) { >+ if (cond.Eval()) { // condition already true; nothing to do >+ if (kDebugMode) { >+ this->AssertReaderHeld(); >+ } >+ } else { // normal case >+ ABSL_RAW_CHECK(this->AwaitCommon(cond, KernelTimeout::Never()), >+ "condition untrue on return from Await"); >+ } >+} >+ >+bool Mutex::AwaitWithTimeout(const Condition &cond, absl::Duration timeout) { >+ return AwaitWithDeadline(cond, DeadlineFromTimeout(timeout)); >+} >+ >+bool Mutex::AwaitWithDeadline(const Condition &cond, absl::Time deadline) { >+ if (cond.Eval()) { // condition already true; nothing to do >+ if (kDebugMode) { >+ this->AssertReaderHeld(); >+ } >+ return true; >+ } >+ >+ KernelTimeout t{deadline}; >+ bool res = this->AwaitCommon(cond, t); >+ ABSL_RAW_CHECK(res || t.has_timeout(), >+ "condition untrue on return from Await"); >+ return res; >+} >+ >+bool Mutex::AwaitCommon(const Condition &cond, KernelTimeout t) { >+ this->AssertReaderHeld(); >+ MuHow how = >+ (mu_.load(std::memory_order_relaxed) & kMuWriter) ? kExclusive : kShared; >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, TsanFlags(how)); >+ SynchWaitParams waitp( >+ how, &cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this), >+ nullptr /*no cv_word*/); >+ int flags = kMuHasBlocked; >+ if (!Condition::GuaranteedEqual(&cond, nullptr)) { >+ flags |= kMuIsCond; >+ } >+ this->UnlockSlow(&waitp); >+ this->Block(waitp.thread); >+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, TsanFlags(how)); >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, TsanFlags(how)); >+ this->LockSlowLoop(&waitp, flags); >+ bool res = waitp.cond != nullptr || // => cond known true from LockSlowLoop >+ cond.Eval(); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, TsanFlags(how), 0); >+ return res; >+} >+ >+ABSL_XRAY_LOG_ARGS(1) bool Mutex::TryLock() { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ if ((v & (kMuWriter | kMuReader | kMuEvent)) == 0 && // try fast acquire >+ mu_.compare_exchange_strong(v, kMuWriter | v, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ DebugOnlyLockEnter(this); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0); >+ return true; >+ } >+ if ((v & kMuEvent) != 0) { // we're recording events >+ if ((v & kExclusive->slow_need_zero) == 0 && // try fast acquire >+ mu_.compare_exchange_strong( >+ v, (kExclusive->fast_or | v) + kExclusive->fast_add, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ DebugOnlyLockEnter(this); >+ PostSynchEvent(this, SYNCH_EV_TRYLOCK_SUCCESS); >+ ABSL_TSAN_MUTEX_POST_LOCK(this, __tsan_mutex_try_lock, 0); >+ return true; >+ } else { >+ PostSynchEvent(this, SYNCH_EV_TRYLOCK_FAILED); >+ } >+ } >+ ABSL_TSAN_MUTEX_POST_LOCK( >+ this, __tsan_mutex_try_lock | __tsan_mutex_try_lock_failed, 0); >+ return false; >+} >+ >+ABSL_XRAY_LOG_ARGS(1) bool Mutex::ReaderTryLock() { >+ ABSL_TSAN_MUTEX_PRE_LOCK(this, >+ __tsan_mutex_read_lock | __tsan_mutex_try_lock); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ // The while-loops (here and below) iterate only if the mutex word keeps >+ // changing (typically because the reader count changes) under the CAS. We >+ // limit the number of attempts to avoid having to think about livelock. >+ int loop_limit = 5; >+ while ((v & (kMuWriter|kMuWait|kMuEvent)) == 0 && loop_limit != 0) { >+ if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ DebugOnlyLockEnter(this); >+ ABSL_TSAN_MUTEX_POST_LOCK( >+ this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0); >+ return true; >+ } >+ loop_limit--; >+ v = mu_.load(std::memory_order_relaxed); >+ } >+ if ((v & kMuEvent) != 0) { // we're recording events >+ loop_limit = 5; >+ while ((v & kShared->slow_need_zero) == 0 && loop_limit != 0) { >+ if (mu_.compare_exchange_strong(v, (kMuReader | v) + kMuOne, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ DebugOnlyLockEnter(this); >+ PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_SUCCESS); >+ ABSL_TSAN_MUTEX_POST_LOCK( >+ this, __tsan_mutex_read_lock | __tsan_mutex_try_lock, 0); >+ return true; >+ } >+ loop_limit--; >+ v = mu_.load(std::memory_order_relaxed); >+ } >+ if ((v & kMuEvent) != 0) { >+ PostSynchEvent(this, SYNCH_EV_READERTRYLOCK_FAILED); >+ } >+ } >+ ABSL_TSAN_MUTEX_POST_LOCK(this, >+ __tsan_mutex_read_lock | __tsan_mutex_try_lock | >+ __tsan_mutex_try_lock_failed, >+ 0); >+ return false; >+} >+ >+ABSL_XRAY_LOG_ARGS(1) void Mutex::Unlock() { >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0); >+ DebugOnlyLockLeave(this); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ >+ if (kDebugMode && ((v & (kMuWriter | kMuReader)) != kMuWriter)) { >+ ABSL_RAW_LOG(FATAL, "Mutex unlocked when destroyed or not locked: v=0x%x", >+ static_cast<unsigned>(v)); >+ } >+ >+ // should_try_cas is whether we'll try a compare-and-swap immediately. >+ // NOTE: optimized out when kDebugMode is false. >+ bool should_try_cas = ((v & (kMuEvent | kMuWriter)) == kMuWriter && >+ (v & (kMuWait | kMuDesig)) != kMuWait); >+ // But, we can use an alternate computation of it, that compilers >+ // currently don't find on their own. When that changes, this function >+ // can be simplified. >+ intptr_t x = (v ^ (kMuWriter | kMuWait)) & (kMuWriter | kMuEvent); >+ intptr_t y = (v ^ (kMuWriter | kMuWait)) & (kMuWait | kMuDesig); >+ // Claim: "x == 0 && y > 0" is equal to should_try_cas. >+ // Also, because kMuWriter and kMuEvent exceed kMuDesig and kMuWait, >+ // all possible non-zero values for x exceed all possible values for y. >+ // Therefore, (x == 0 && y > 0) == (x < y). >+ if (kDebugMode && should_try_cas != (x < y)) { >+ // We would usually use PRIdPTR here, but is not correctly implemented >+ // within the android toolchain. >+ ABSL_RAW_LOG(FATAL, "internal logic error %llx %llx %llx\n", >+ static_cast<long long>(v), static_cast<long long>(x), >+ static_cast<long long>(y)); >+ } >+ if (x < y && >+ mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter), >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ // fast writer release (writer with no waiters or with designated waker) >+ } else { >+ this->UnlockSlow(nullptr /*no waitp*/); // take slow path >+ } >+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0); >+} >+ >+// Requires v to represent a reader-locked state. >+static bool ExactlyOneReader(intptr_t v) { >+ assert((v & (kMuWriter|kMuReader)) == kMuReader); >+ assert((v & kMuHigh) != 0); >+ // The more straightforward "(v & kMuHigh) == kMuOne" also works, but >+ // on some architectures the following generates slightly smaller code. >+ // It may be faster too. >+ constexpr intptr_t kMuMultipleWaitersMask = kMuHigh ^ kMuOne; >+ return (v & kMuMultipleWaitersMask) == 0; >+} >+ >+ABSL_XRAY_LOG_ARGS(1) void Mutex::ReaderUnlock() { >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(this, __tsan_mutex_read_lock); >+ DebugOnlyLockLeave(this); >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ assert((v & (kMuWriter|kMuReader)) == kMuReader); >+ if ((v & (kMuReader|kMuWait|kMuEvent)) == kMuReader) { >+ // fast reader release (reader with no waiters) >+ intptr_t clear = ExactlyOneReader(v) ? kMuReader|kMuOne : kMuOne; >+ if (mu_.compare_exchange_strong(v, v - clear, >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock); >+ return; >+ } >+ } >+ this->UnlockSlow(nullptr /*no waitp*/); // take slow path >+ ABSL_TSAN_MUTEX_POST_UNLOCK(this, __tsan_mutex_read_lock); >+} >+ >+// The zap_desig_waker bitmask is used to clear the designated waker flag in >+// the mutex if this thread has blocked, and therefore may be the designated >+// waker. >+static const intptr_t zap_desig_waker[] = { >+ ~static_cast<intptr_t>(0), // not blocked >+ ~static_cast<intptr_t>( >+ kMuDesig) // blocked; turn off the designated waker bit >+}; >+ >+// The ignore_waiting_writers bitmask is used to ignore the existence >+// of waiting writers if a reader that has already blocked once >+// wakes up. >+static const intptr_t ignore_waiting_writers[] = { >+ ~static_cast<intptr_t>(0), // not blocked >+ ~static_cast<intptr_t>( >+ kMuWrWait) // blocked; pretend there are no waiting writers >+}; >+ >+// Internal version of LockWhen(). See LockSlowWithDeadline() >+void Mutex::LockSlow(MuHow how, const Condition *cond, int flags) { >+ ABSL_RAW_CHECK( >+ this->LockSlowWithDeadline(how, cond, KernelTimeout::Never(), flags), >+ "condition untrue on return from LockSlow"); >+} >+ >+// Compute cond->Eval() and tell race detectors that we do it under mutex mu. >+static inline bool EvalConditionAnnotated(const Condition *cond, Mutex *mu, >+ bool locking, Mutex::MuHow how) { >+ // Delicate annotation dance. >+ // We are currently inside of read/write lock/unlock operation. >+ // All memory accesses are ignored inside of mutex operations + for unlock >+ // operation tsan considers that we've already released the mutex. >+ bool res = false; >+ if (locking) { >+ // For lock we pretend that we have finished the operation, >+ // evaluate the predicate, then unlock the mutex and start locking it again >+ // to match the annotation at the end of outer lock operation. >+ // Note: we can't simply do POST_LOCK, Eval, PRE_LOCK, because then tsan >+ // will think the lock acquisition is recursive which will trigger >+ // deadlock detector. >+ ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); >+ res = cond->Eval(); >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); >+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); >+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); >+ } else { >+ // Similarly, for unlock we pretend that we have unlocked the mutex, >+ // lock the mutex, evaluate the predicate, and start unlocking it again >+ // to match the annotation at the end of outer unlock operation. >+ ABSL_TSAN_MUTEX_POST_UNLOCK(mu, TsanFlags(how)); >+ ABSL_TSAN_MUTEX_PRE_LOCK(mu, TsanFlags(how)); >+ ABSL_TSAN_MUTEX_POST_LOCK(mu, TsanFlags(how), 0); >+ res = cond->Eval(); >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mu, TsanFlags(how)); >+ } >+ // Prevent unused param warnings in non-TSAN builds. >+ static_cast<void>(mu); >+ static_cast<void>(how); >+ return res; >+} >+ >+// Compute cond->Eval() hiding it from race detectors. >+// We are hiding it because inside of UnlockSlow we can evaluate a predicate >+// that was just added by a concurrent Lock operation; Lock adds the predicate >+// to the internal Mutex list without actually acquiring the Mutex >+// (it only acquires the internal spinlock, which is rightfully invisible for >+// tsan). As the result there is no tsan-visible synchronization between the >+// addition and this thread. So if we would enable race detection here, >+// it would race with the predicate initialization. >+static inline bool EvalConditionIgnored(Mutex *mu, const Condition *cond) { >+ // Memory accesses are already ignored inside of lock/unlock operations, >+ // but synchronization operations are also ignored. When we evaluate the >+ // predicate we must ignore only memory accesses but not synchronization, >+ // because missed synchronization can lead to false reports later. >+ // So we "divert" (which un-ignores both memory accesses and synchronization) >+ // and then separately turn on ignores of memory accesses. >+ ABSL_TSAN_MUTEX_PRE_DIVERT(mu, 0); >+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN(); >+ bool res = cond->Eval(); >+ ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END(); >+ ABSL_TSAN_MUTEX_POST_DIVERT(mu, 0); >+ static_cast<void>(mu); // Prevent unused param warning in non-TSAN builds. >+ return res; >+} >+ >+// Internal equivalent of *LockWhenWithDeadline(), where >+// "t" represents the absolute timeout; !t.has_timeout() means "forever". >+// "how" is "kShared" (for ReaderLockWhen) or "kExclusive" (for LockWhen) >+// In flags, bits are ored together: >+// - kMuHasBlocked indicates that the client has already blocked on the call so >+// the designated waker bit must be cleared and waiting writers should not >+// obstruct this call >+// - kMuIsCond indicates that this is a conditional acquire (condition variable, >+// Await, LockWhen) so contention profiling should be suppressed. >+bool Mutex::LockSlowWithDeadline(MuHow how, const Condition *cond, >+ KernelTimeout t, int flags) { >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ bool unlock = false; >+ if ((v & how->fast_need_zero) == 0 && // try fast acquire >+ mu_.compare_exchange_strong( >+ v, (how->fast_or | (v & zap_desig_waker[flags & kMuHasBlocked])) + >+ how->fast_add, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ if (cond == nullptr || EvalConditionAnnotated(cond, this, true, how)) { >+ return true; >+ } >+ unlock = true; >+ } >+ SynchWaitParams waitp( >+ how, cond, t, nullptr /*no cvmu*/, Synch_GetPerThreadAnnotated(this), >+ nullptr /*no cv_word*/); >+ if (!Condition::GuaranteedEqual(cond, nullptr)) { >+ flags |= kMuIsCond; >+ } >+ if (unlock) { >+ this->UnlockSlow(&waitp); >+ this->Block(waitp.thread); >+ flags |= kMuHasBlocked; >+ } >+ this->LockSlowLoop(&waitp, flags); >+ return waitp.cond != nullptr || // => cond known true from LockSlowLoop >+ cond == nullptr || EvalConditionAnnotated(cond, this, true, how); >+} >+ >+// RAW_CHECK_FMT() takes a condition, a printf-style format std::string, and >+// the printf-style argument list. The format std::string must be a literal. >+// Arguments after the first are not evaluated unless the condition is true. >+#define RAW_CHECK_FMT(cond, ...) \ >+ do { \ >+ if (ABSL_PREDICT_FALSE(!(cond))) { \ >+ ABSL_RAW_LOG(FATAL, "Check " #cond " failed: " __VA_ARGS__); \ >+ } \ >+ } while (0) >+ >+static void CheckForMutexCorruption(intptr_t v, const char* label) { >+ // Test for either of two situations that should not occur in v: >+ // kMuWriter and kMuReader >+ // kMuWrWait and !kMuWait >+ const intptr_t w = v ^ kMuWait; >+ // By flipping that bit, we can now test for: >+ // kMuWriter and kMuReader in w >+ // kMuWrWait and kMuWait in w >+ // We've chosen these two pairs of values to be so that they will overlap, >+ // respectively, when the word is left shifted by three. This allows us to >+ // save a branch in the common (correct) case of them not being coincident. >+ static_assert(kMuReader << 3 == kMuWriter, "must match"); >+ static_assert(kMuWait << 3 == kMuWrWait, "must match"); >+ if (ABSL_PREDICT_TRUE((w & (w << 3) & (kMuWriter | kMuWrWait)) == 0)) return; >+ RAW_CHECK_FMT((v & (kMuWriter | kMuReader)) != (kMuWriter | kMuReader), >+ "%s: Mutex corrupt: both reader and writer lock held: %p", >+ label, reinterpret_cast<void *>(v)); >+ RAW_CHECK_FMT((v & (kMuWait | kMuWrWait)) != kMuWrWait, >+ "%s: Mutex corrupt: waiting writer with no waiters: %p", >+ label, reinterpret_cast<void *>(v)); >+ assert(false); >+} >+ >+void Mutex::LockSlowLoop(SynchWaitParams *waitp, int flags) { >+ int c = 0; >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ if ((v & kMuEvent) != 0) { >+ PostSynchEvent(this, >+ waitp->how == kExclusive? SYNCH_EV_LOCK: SYNCH_EV_READERLOCK); >+ } >+ ABSL_RAW_CHECK( >+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, >+ "detected illegal recursion into Mutex code"); >+ for (;;) { >+ v = mu_.load(std::memory_order_relaxed); >+ CheckForMutexCorruption(v, "Lock"); >+ if ((v & waitp->how->slow_need_zero) == 0) { >+ if (mu_.compare_exchange_strong( >+ v, (waitp->how->fast_or | >+ (v & zap_desig_waker[flags & kMuHasBlocked])) + >+ waitp->how->fast_add, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ if (waitp->cond == nullptr || >+ EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { >+ break; // we timed out, or condition true, so return >+ } >+ this->UnlockSlow(waitp); // got lock but condition false >+ this->Block(waitp->thread); >+ flags |= kMuHasBlocked; >+ c = 0; >+ } >+ } else { // need to access waiter list >+ bool dowait = false; >+ if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters >+ // This thread tries to become the one and only waiter. >+ PerThreadSynch *new_h = Enqueue(nullptr, waitp, v, flags); >+ intptr_t nv = (v & zap_desig_waker[flags & kMuHasBlocked] & kMuLow) | >+ kMuWait; >+ ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to empty list failed"); >+ if (waitp->how == kExclusive && (v & kMuReader) != 0) { >+ nv |= kMuWrWait; >+ } >+ if (mu_.compare_exchange_strong( >+ v, reinterpret_cast<intptr_t>(new_h) | nv, >+ std::memory_order_release, std::memory_order_relaxed)) { >+ dowait = true; >+ } else { // attempted Enqueue() failed >+ // zero out the waitp field set by Enqueue() >+ waitp->thread->waitp = nullptr; >+ } >+ } else if ((v & waitp->how->slow_inc_need_zero & >+ ignore_waiting_writers[flags & kMuHasBlocked]) == 0) { >+ // This is a reader that needs to increment the reader count, >+ // but the count is currently held in the last waiter. >+ if (mu_.compare_exchange_strong( >+ v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin | >+ kMuReader, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ PerThreadSynch *h = GetPerThreadSynch(v); >+ h->readers += kMuOne; // inc reader count in waiter >+ do { // release spinlock >+ v = mu_.load(std::memory_order_relaxed); >+ } while (!mu_.compare_exchange_weak(v, (v & ~kMuSpin) | kMuReader, >+ std::memory_order_release, >+ std::memory_order_relaxed)); >+ if (waitp->cond == nullptr || >+ EvalConditionAnnotated(waitp->cond, this, true, waitp->how)) { >+ break; // we timed out, or condition true, so return >+ } >+ this->UnlockSlow(waitp); // got lock but condition false >+ this->Block(waitp->thread); >+ flags |= kMuHasBlocked; >+ c = 0; >+ } >+ } else if ((v & kMuSpin) == 0 && // attempt to queue ourselves >+ mu_.compare_exchange_strong( >+ v, (v & zap_desig_waker[flags & kMuHasBlocked]) | kMuSpin | >+ kMuWait, >+ std::memory_order_acquire, std::memory_order_relaxed)) { >+ PerThreadSynch *h = GetPerThreadSynch(v); >+ PerThreadSynch *new_h = Enqueue(h, waitp, v, flags); >+ intptr_t wr_wait = 0; >+ ABSL_RAW_CHECK(new_h != nullptr, "Enqueue to list failed"); >+ if (waitp->how == kExclusive && (v & kMuReader) != 0) { >+ wr_wait = kMuWrWait; // give priority to a waiting writer >+ } >+ do { // release spinlock >+ v = mu_.load(std::memory_order_relaxed); >+ } while (!mu_.compare_exchange_weak( >+ v, (v & (kMuLow & ~kMuSpin)) | kMuWait | wr_wait | >+ reinterpret_cast<intptr_t>(new_h), >+ std::memory_order_release, std::memory_order_relaxed)); >+ dowait = true; >+ } >+ if (dowait) { >+ this->Block(waitp->thread); // wait until removed from list or timeout >+ flags |= kMuHasBlocked; >+ c = 0; >+ } >+ } >+ ABSL_RAW_CHECK( >+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, >+ "detected illegal recursion into Mutex code"); >+ c = Delay(c, GENTLE); // delay, then try again >+ } >+ ABSL_RAW_CHECK( >+ waitp->thread->waitp == nullptr || waitp->thread->suppress_fatal_errors, >+ "detected illegal recursion into Mutex code"); >+ if ((v & kMuEvent) != 0) { >+ PostSynchEvent(this, >+ waitp->how == kExclusive? SYNCH_EV_LOCK_RETURNING : >+ SYNCH_EV_READERLOCK_RETURNING); >+ } >+} >+ >+// Unlock this mutex, which is held by the current thread. >+// If waitp is non-zero, it must be the wait parameters for the current thread >+// which holds the lock but is not runnable because its condition is false >+// or it n the process of blocking on a condition variable; it must requeue >+// itself on the mutex/condvar to wait for its condition to become true. >+void Mutex::UnlockSlow(SynchWaitParams *waitp) { >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ this->AssertReaderHeld(); >+ CheckForMutexCorruption(v, "Unlock"); >+ if ((v & kMuEvent) != 0) { >+ PostSynchEvent(this, >+ (v & kMuWriter) != 0? SYNCH_EV_UNLOCK: SYNCH_EV_READERUNLOCK); >+ } >+ int c = 0; >+ // the waiter under consideration to wake, or zero >+ PerThreadSynch *w = nullptr; >+ // the predecessor to w or zero >+ PerThreadSynch *pw = nullptr; >+ // head of the list searched previously, or zero >+ PerThreadSynch *old_h = nullptr; >+ // a condition that's known to be false. >+ const Condition *known_false = nullptr; >+ PerThreadSynch *wake_list = kPerThreadSynchNull; // list of threads to wake >+ intptr_t wr_wait = 0; // set to kMuWrWait if we wake a reader and a >+ // later writer could have acquired the lock >+ // (starvation avoidance) >+ ABSL_RAW_CHECK(waitp == nullptr || waitp->thread->waitp == nullptr || >+ waitp->thread->suppress_fatal_errors, >+ "detected illegal recursion into Mutex code"); >+ // This loop finds threads wake_list to wakeup if any, and removes them from >+ // the list of waiters. In addition, it places waitp.thread on the queue of >+ // waiters if waitp is non-zero. >+ for (;;) { >+ v = mu_.load(std::memory_order_relaxed); >+ if ((v & kMuWriter) != 0 && (v & (kMuWait | kMuDesig)) != kMuWait && >+ waitp == nullptr) { >+ // fast writer release (writer with no waiters or with designated waker) >+ if (mu_.compare_exchange_strong(v, v & ~(kMuWrWait | kMuWriter), >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ return; >+ } >+ } else if ((v & (kMuReader | kMuWait)) == kMuReader && waitp == nullptr) { >+ // fast reader release (reader with no waiters) >+ intptr_t clear = ExactlyOneReader(v) ? kMuReader | kMuOne : kMuOne; >+ if (mu_.compare_exchange_strong(v, v - clear, >+ std::memory_order_release, >+ std::memory_order_relaxed)) { >+ return; >+ } >+ } else if ((v & kMuSpin) == 0 && // attempt to get spinlock >+ mu_.compare_exchange_strong(v, v | kMuSpin, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ if ((v & kMuWait) == 0) { // no one to wake >+ intptr_t nv; >+ bool do_enqueue = true; // always Enqueue() the first time >+ ABSL_RAW_CHECK(waitp != nullptr, >+ "UnlockSlow is confused"); // about to sleep >+ do { // must loop to release spinlock as reader count may change >+ v = mu_.load(std::memory_order_relaxed); >+ // decrement reader count if there are readers >+ intptr_t new_readers = (v >= kMuOne)? v - kMuOne : v; >+ PerThreadSynch *new_h = nullptr; >+ if (do_enqueue) { >+ // If we are enqueuing on a CondVar (waitp->cv_word != nullptr) then >+ // we must not retry here. The initial attempt will always have >+ // succeeded, further attempts would enqueue us against *this due to >+ // Fer() handling. >+ do_enqueue = (waitp->cv_word == nullptr); >+ new_h = Enqueue(nullptr, waitp, new_readers, kMuIsCond); >+ } >+ intptr_t clear = kMuWrWait | kMuWriter; // by default clear write bit >+ if ((v & kMuWriter) == 0 && ExactlyOneReader(v)) { // last reader >+ clear = kMuWrWait | kMuReader; // clear read bit >+ } >+ nv = (v & kMuLow & ~clear & ~kMuSpin); >+ if (new_h != nullptr) { >+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h); >+ } else { // new_h could be nullptr if we queued ourselves on a >+ // CondVar >+ // In that case, we must place the reader count back in the mutex >+ // word, as Enqueue() did not store it in the new waiter. >+ nv |= new_readers & kMuHigh; >+ } >+ // release spinlock & our lock; retry if reader-count changed >+ // (writer count cannot change since we hold lock) >+ } while (!mu_.compare_exchange_weak(v, nv, >+ std::memory_order_release, >+ std::memory_order_relaxed)); >+ break; >+ } >+ >+ // There are waiters. >+ // Set h to the head of the circular waiter list. >+ PerThreadSynch *h = GetPerThreadSynch(v); >+ if ((v & kMuReader) != 0 && (h->readers & kMuHigh) > kMuOne) { >+ // a reader but not the last >+ h->readers -= kMuOne; // release our lock >+ intptr_t nv = v; // normally just release spinlock >+ if (waitp != nullptr) { // but waitp!=nullptr => must queue ourselves >+ PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond); >+ ABSL_RAW_CHECK(new_h != nullptr, >+ "waiters disappeared during Enqueue()!"); >+ nv &= kMuLow; >+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h); >+ } >+ mu_.store(nv, std::memory_order_release); // release spinlock >+ // can release with a store because there were waiters >+ break; >+ } >+ >+ // Either we didn't search before, or we marked the queue >+ // as "maybe_unlocking" and no one else should have changed it. >+ ABSL_RAW_CHECK(old_h == nullptr || h->maybe_unlocking, >+ "Mutex queue changed beneath us"); >+ >+ // The lock is becoming free, and there's a waiter >+ if (old_h != nullptr && >+ !old_h->may_skip) { // we used old_h as a terminator >+ old_h->may_skip = true; // allow old_h to skip once more >+ ABSL_RAW_CHECK(old_h->skip == nullptr, "illegal skip from head"); >+ if (h != old_h && MuSameCondition(old_h, old_h->next)) { >+ old_h->skip = old_h->next; // old_h not head & can skip to successor >+ } >+ } >+ if (h->next->waitp->how == kExclusive && >+ Condition::GuaranteedEqual(h->next->waitp->cond, nullptr)) { >+ // easy case: writer with no condition; no need to search >+ pw = h; // wake w, the successor of h (=pw) >+ w = h->next; >+ w->wake = true; >+ // We are waking up a writer. This writer may be racing against >+ // an already awake reader for the lock. We want the >+ // writer to usually win this race, >+ // because if it doesn't, we can potentially keep taking a reader >+ // perpetually and writers will starve. Worse than >+ // that, this can also starve other readers if kMuWrWait gets set >+ // later. >+ wr_wait = kMuWrWait; >+ } else if (w != nullptr && (w->waitp->how == kExclusive || h == old_h)) { >+ // we found a waiter w to wake on a previous iteration and either it's >+ // a writer, or we've searched the entire list so we have all the >+ // readers. >+ if (pw == nullptr) { // if w's predecessor is unknown, it must be h >+ pw = h; >+ } >+ } else { >+ // At this point we don't know all the waiters to wake, and the first >+ // waiter has a condition or is a reader. We avoid searching over >+ // waiters we've searched on previous iterations by starting at >+ // old_h if it's set. If old_h==h, there's no one to wakeup at all. >+ if (old_h == h) { // we've searched before, and nothing's new >+ // so there's no one to wake. >+ intptr_t nv = (v & ~(kMuReader|kMuWriter|kMuWrWait)); >+ h->readers = 0; >+ h->maybe_unlocking = false; // finished unlocking >+ if (waitp != nullptr) { // we must queue ourselves and sleep >+ PerThreadSynch *new_h = Enqueue(h, waitp, v, kMuIsCond); >+ nv &= kMuLow; >+ if (new_h != nullptr) { >+ nv |= kMuWait | reinterpret_cast<intptr_t>(new_h); >+ } // else new_h could be nullptr if we queued ourselves on a >+ // CondVar >+ } >+ // release spinlock & lock >+ // can release with a store because there were waiters >+ mu_.store(nv, std::memory_order_release); >+ break; >+ } >+ >+ // set up to walk the list >+ PerThreadSynch *w_walk; // current waiter during list walk >+ PerThreadSynch *pw_walk; // previous waiter during list walk >+ if (old_h != nullptr) { // we've searched up to old_h before >+ pw_walk = old_h; >+ w_walk = old_h->next; >+ } else { // no prior search, start at beginning >+ pw_walk = >+ nullptr; // h->next's predecessor may change; don't record it >+ w_walk = h->next; >+ } >+ >+ h->may_skip = false; // ensure we never skip past h in future searches >+ // even if other waiters are queued after it. >+ ABSL_RAW_CHECK(h->skip == nullptr, "illegal skip from head"); >+ >+ h->maybe_unlocking = true; // we're about to scan the waiter list >+ // without the spinlock held. >+ // Enqueue must be conservative about >+ // priority queuing. >+ >+ // We must release the spinlock to evaluate the conditions. >+ mu_.store(v, std::memory_order_release); // release just spinlock >+ // can release with a store because there were waiters >+ >+ // h is the last waiter queued, and w_walk the first unsearched waiter. >+ // Without the spinlock, the locations mu_ and h->next may now change >+ // underneath us, but since we hold the lock itself, the only legal >+ // change is to add waiters between h and w_walk. Therefore, it's safe >+ // to walk the path from w_walk to h inclusive. (TryRemove() can remove >+ // a waiter anywhere, but it acquires both the spinlock and the Mutex) >+ >+ old_h = h; // remember we searched to here >+ >+ // Walk the path upto and including h looking for waiters we can wake. >+ while (pw_walk != h) { >+ w_walk->wake = false; >+ if (w_walk->waitp->cond == >+ nullptr || // no condition => vacuously true OR >+ (w_walk->waitp->cond != known_false && >+ // this thread's condition is not known false, AND >+ // is in fact true >+ EvalConditionIgnored(this, w_walk->waitp->cond))) { >+ if (w == nullptr) { >+ w_walk->wake = true; // can wake this waiter >+ w = w_walk; >+ pw = pw_walk; >+ if (w_walk->waitp->how == kExclusive) { >+ wr_wait = kMuWrWait; >+ break; // bail if waking this writer >+ } >+ } else if (w_walk->waitp->how == kShared) { // wake if a reader >+ w_walk->wake = true; >+ } else { // writer with true condition >+ wr_wait = kMuWrWait; >+ } >+ } else { // can't wake; condition false >+ known_false = w_walk->waitp->cond; // remember last false condition >+ } >+ if (w_walk->wake) { // we're waking reader w_walk >+ pw_walk = w_walk; // don't skip similar waiters >+ } else { // not waking; skip as much as possible >+ pw_walk = Skip(w_walk); >+ } >+ // If pw_walk == h, then load of pw_walk->next can race with >+ // concurrent write in Enqueue(). However, at the same time >+ // we do not need to do the load, because we will bail out >+ // from the loop anyway. >+ if (pw_walk != h) { >+ w_walk = pw_walk->next; >+ } >+ } >+ >+ continue; // restart for(;;)-loop to wakeup w or to find more waiters >+ } >+ ABSL_RAW_CHECK(pw->next == w, "pw not w's predecessor"); >+ // The first (and perhaps only) waiter we've chosen to wake is w, whose >+ // predecessor is pw. If w is a reader, we must wake all the other >+ // waiters with wake==true as well. We may also need to queue >+ // ourselves if waitp != null. The spinlock and the lock are still >+ // held. >+ >+ // This traverses the list in [ pw->next, h ], where h is the head, >+ // removing all elements with wake==true and placing them in the >+ // singly-linked list wake_list. Returns the new head. >+ h = DequeueAllWakeable(h, pw, &wake_list); >+ >+ intptr_t nv = (v & kMuEvent) | kMuDesig; >+ // assume no waiters left, >+ // set kMuDesig for INV1a >+ >+ if (waitp != nullptr) { // we must queue ourselves and sleep >+ h = Enqueue(h, waitp, v, kMuIsCond); >+ // h is new last waiter; could be null if we queued ourselves on a >+ // CondVar >+ } >+ >+ ABSL_RAW_CHECK(wake_list != kPerThreadSynchNull, >+ "unexpected empty wake list"); >+ >+ if (h != nullptr) { // there are waiters left >+ h->readers = 0; >+ h->maybe_unlocking = false; // finished unlocking >+ nv |= wr_wait | kMuWait | reinterpret_cast<intptr_t>(h); >+ } >+ >+ // release both spinlock & lock >+ // can release with a store because there were waiters >+ mu_.store(nv, std::memory_order_release); >+ break; // out of for(;;)-loop >+ } >+ c = Delay(c, AGGRESSIVE); // aggressive here; no one can proceed till we do >+ } // end of for(;;)-loop >+ >+ if (wake_list != kPerThreadSynchNull) { >+ int64_t enqueue_timestamp = wake_list->waitp->contention_start_cycles; >+ bool cond_waiter = wake_list->cond_waiter; >+ do { >+ wake_list = Wakeup(wake_list); // wake waiters >+ } while (wake_list != kPerThreadSynchNull); >+ if (!cond_waiter) { >+ // Sample lock contention events only if the (first) waiter was trying to >+ // acquire the lock, not waiting on a condition variable or Condition. >+ int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp; >+ mutex_tracer("slow release", this, wait_cycles); >+ ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0); >+ submit_profile_data(enqueue_timestamp); >+ ABSL_TSAN_MUTEX_POST_DIVERT(this, 0); >+ } >+ } >+} >+ >+// Used by CondVar implementation to reacquire mutex after waking from >+// condition variable. This routine is used instead of Lock() because the >+// waiting thread may have been moved from the condition variable queue to the >+// mutex queue without a wakeup, by Trans(). In that case, when the thread is >+// finally woken, the woken thread will believe it has been woken from the >+// condition variable (i.e. its PC will be in when in the CondVar code), when >+// in fact it has just been woken from the mutex. Thus, it must enter the slow >+// path of the mutex in the same state as if it had just woken from the mutex. >+// That is, it must ensure to clear kMuDesig (INV1b). >+void Mutex::Trans(MuHow how) { >+ this->LockSlow(how, nullptr, kMuHasBlocked | kMuIsCond); >+} >+ >+// Used by CondVar implementation to effectively wake thread w from the >+// condition variable. If this mutex is free, we simply wake the thread. >+// It will later acquire the mutex with high probability. Otherwise, we >+// enqueue thread w on this mutex. >+void Mutex::Fer(PerThreadSynch *w) { >+ int c = 0; >+ ABSL_RAW_CHECK(w->waitp->cond == nullptr, >+ "Mutex::Fer while waiting on Condition"); >+ ABSL_RAW_CHECK(!w->waitp->timeout.has_timeout(), >+ "Mutex::Fer while in timed wait"); >+ ABSL_RAW_CHECK(w->waitp->cv_word == nullptr, >+ "Mutex::Fer with pending CondVar queueing"); >+ for (;;) { >+ intptr_t v = mu_.load(std::memory_order_relaxed); >+ // Note: must not queue if the mutex is unlocked (nobody will wake it). >+ // For example, we can have only kMuWait (conditional) or maybe >+ // kMuWait|kMuWrWait. >+ // conflicting != 0 implies that the waking thread cannot currently take >+ // the mutex, which in turn implies that someone else has it and can wake >+ // us if we queue. >+ const intptr_t conflicting = >+ kMuWriter | (w->waitp->how == kShared ? 0 : kMuReader); >+ if ((v & conflicting) == 0) { >+ w->next = nullptr; >+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release); >+ IncrementSynchSem(this, w); >+ return; >+ } else { >+ if ((v & (kMuSpin|kMuWait)) == 0) { // no waiters >+ // This thread tries to become the one and only waiter. >+ PerThreadSynch *new_h = Enqueue(nullptr, w->waitp, v, kMuIsCond); >+ ABSL_RAW_CHECK(new_h != nullptr, >+ "Enqueue failed"); // we must queue ourselves >+ if (mu_.compare_exchange_strong( >+ v, reinterpret_cast<intptr_t>(new_h) | (v & kMuLow) | kMuWait, >+ std::memory_order_release, std::memory_order_relaxed)) { >+ return; >+ } >+ } else if ((v & kMuSpin) == 0 && >+ mu_.compare_exchange_strong(v, v | kMuSpin | kMuWait)) { >+ PerThreadSynch *h = GetPerThreadSynch(v); >+ PerThreadSynch *new_h = Enqueue(h, w->waitp, v, kMuIsCond); >+ ABSL_RAW_CHECK(new_h != nullptr, >+ "Enqueue failed"); // we must queue ourselves >+ do { >+ v = mu_.load(std::memory_order_relaxed); >+ } while (!mu_.compare_exchange_weak( >+ v, >+ (v & kMuLow & ~kMuSpin) | kMuWait | >+ reinterpret_cast<intptr_t>(new_h), >+ std::memory_order_release, std::memory_order_relaxed)); >+ return; >+ } >+ } >+ c = Delay(c, GENTLE); >+ } >+} >+ >+void Mutex::AssertHeld() const { >+ if ((mu_.load(std::memory_order_relaxed) & kMuWriter) == 0) { >+ SynchEvent *e = GetSynchEvent(this); >+ ABSL_RAW_LOG(FATAL, "thread should hold write lock on Mutex %p %s", >+ static_cast<const void *>(this), >+ (e == nullptr ? "" : e->name)); >+ } >+} >+ >+void Mutex::AssertReaderHeld() const { >+ if ((mu_.load(std::memory_order_relaxed) & (kMuReader | kMuWriter)) == 0) { >+ SynchEvent *e = GetSynchEvent(this); >+ ABSL_RAW_LOG( >+ FATAL, "thread should hold at least a read lock on Mutex %p %s", >+ static_cast<const void *>(this), (e == nullptr ? "" : e->name)); >+ } >+} >+ >+// -------------------------------- condition variables >+static const intptr_t kCvSpin = 0x0001L; // spinlock protects waiter list >+static const intptr_t kCvEvent = 0x0002L; // record events >+ >+static const intptr_t kCvLow = 0x0003L; // low order bits of CV >+ >+// Hack to make constant values available to gdb pretty printer >+enum { kGdbCvSpin = kCvSpin, kGdbCvEvent = kCvEvent, kGdbCvLow = kCvLow, }; >+ >+static_assert(PerThreadSynch::kAlignment > kCvLow, >+ "PerThreadSynch::kAlignment must be greater than kCvLow"); >+ >+void CondVar::EnableDebugLog(const char *name) { >+ SynchEvent *e = EnsureSynchEvent(&this->cv_, name, kCvEvent, kCvSpin); >+ e->log = true; >+ UnrefSynchEvent(e); >+} >+ >+CondVar::~CondVar() { >+ if ((cv_.load(std::memory_order_relaxed) & kCvEvent) != 0) { >+ ForgetSynchEvent(&this->cv_, kCvEvent, kCvSpin); >+ } >+} >+ >+ >+// Remove thread s from the list of waiters on this condition variable. >+void CondVar::Remove(PerThreadSynch *s) { >+ intptr_t v; >+ int c = 0; >+ for (v = cv_.load(std::memory_order_relaxed);; >+ v = cv_.load(std::memory_order_relaxed)) { >+ if ((v & kCvSpin) == 0 && // attempt to acquire spinlock >+ cv_.compare_exchange_strong(v, v | kCvSpin, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow); >+ if (h != nullptr) { >+ PerThreadSynch *w = h; >+ while (w->next != s && w->next != h) { // search for thread >+ w = w->next; >+ } >+ if (w->next == s) { // found thread; remove it >+ w->next = s->next; >+ if (h == s) { >+ h = (w == s) ? nullptr : w; >+ } >+ s->next = nullptr; >+ s->state.store(PerThreadSynch::kAvailable, std::memory_order_release); >+ } >+ } >+ // release spinlock >+ cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h), >+ std::memory_order_release); >+ return; >+ } else { >+ c = Delay(c, GENTLE); // try again after a delay >+ } >+ } >+} >+ >+// Queue thread waitp->thread on condition variable word cv_word using >+// wait parameters waitp. >+// We split this into a separate routine, rather than simply doing it as part >+// of WaitCommon(). If we were to queue ourselves on the condition variable >+// before calling Mutex::UnlockSlow(), the Mutex code might be re-entered (via >+// the logging code, or via a Condition function) and might potentially attempt >+// to block this thread. That would be a problem if the thread were already on >+// a the condition variable waiter queue. Thus, we use the waitp->cv_word >+// to tell the unlock code to call CondVarEnqueue() to queue the thread on the >+// condition variable queue just before the mutex is to be unlocked, and (most >+// importantly) after any call to an external routine that might re-enter the >+// mutex code. >+static void CondVarEnqueue(SynchWaitParams *waitp) { >+ // This thread might be transferred to the Mutex queue by Fer() when >+ // we are woken. To make sure that is what happens, Enqueue() doesn't >+ // call CondVarEnqueue() again but instead uses its normal code. We >+ // must do this before we queue ourselves so that cv_word will be null >+ // when seen by the dequeuer, who may wish immediately to requeue >+ // this thread on another queue. >+ std::atomic<intptr_t> *cv_word = waitp->cv_word; >+ waitp->cv_word = nullptr; >+ >+ intptr_t v = cv_word->load(std::memory_order_relaxed); >+ int c = 0; >+ while ((v & kCvSpin) != 0 || // acquire spinlock >+ !cv_word->compare_exchange_weak(v, v | kCvSpin, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ c = Delay(c, GENTLE); >+ v = cv_word->load(std::memory_order_relaxed); >+ } >+ ABSL_RAW_CHECK(waitp->thread->waitp == nullptr, "waiting when shouldn't be"); >+ waitp->thread->waitp = waitp; // prepare ourselves for waiting >+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow); >+ if (h == nullptr) { // add this thread to waiter list >+ waitp->thread->next = waitp->thread; >+ } else { >+ waitp->thread->next = h->next; >+ h->next = waitp->thread; >+ } >+ waitp->thread->state.store(PerThreadSynch::kQueued, >+ std::memory_order_relaxed); >+ cv_word->store((v & kCvEvent) | reinterpret_cast<intptr_t>(waitp->thread), >+ std::memory_order_release); >+} >+ >+bool CondVar::WaitCommon(Mutex *mutex, KernelTimeout t) { >+ bool rc = false; // return value; true iff we timed-out >+ >+ intptr_t mutex_v = mutex->mu_.load(std::memory_order_relaxed); >+ Mutex::MuHow mutex_how = ((mutex_v & kMuWriter) != 0) ? kExclusive : kShared; >+ ABSL_TSAN_MUTEX_PRE_UNLOCK(mutex, TsanFlags(mutex_how)); >+ >+ // maybe trace this call >+ intptr_t v = cv_.load(std::memory_order_relaxed); >+ cond_var_tracer("Wait", this); >+ if ((v & kCvEvent) != 0) { >+ PostSynchEvent(this, SYNCH_EV_WAIT); >+ } >+ >+ // Release mu and wait on condition variable. >+ SynchWaitParams waitp(mutex_how, nullptr, t, mutex, >+ Synch_GetPerThreadAnnotated(mutex), &cv_); >+ // UnlockSlow() will call CondVarEnqueue() just before releasing the >+ // Mutex, thus queuing this thread on the condition variable. See >+ // CondVarEnqueue() for the reasons. >+ mutex->UnlockSlow(&waitp); >+ >+ // wait for signal >+ while (waitp.thread->state.load(std::memory_order_acquire) == >+ PerThreadSynch::kQueued) { >+ if (!Mutex::DecrementSynchSem(mutex, waitp.thread, t)) { >+ this->Remove(waitp.thread); >+ rc = true; >+ } >+ } >+ >+ ABSL_RAW_CHECK(waitp.thread->waitp != nullptr, "not waiting when should be"); >+ waitp.thread->waitp = nullptr; // cleanup >+ >+ // maybe trace this call >+ cond_var_tracer("Unwait", this); >+ if ((v & kCvEvent) != 0) { >+ PostSynchEvent(this, SYNCH_EV_WAIT_RETURNING); >+ } >+ >+ // From synchronization point of view Wait is unlock of the mutex followed >+ // by lock of the mutex. We've annotated start of unlock in the beginning >+ // of the function. Now, finish unlock and annotate lock of the mutex. >+ // (Trans is effectively lock). >+ ABSL_TSAN_MUTEX_POST_UNLOCK(mutex, TsanFlags(mutex_how)); >+ ABSL_TSAN_MUTEX_PRE_LOCK(mutex, TsanFlags(mutex_how)); >+ mutex->Trans(mutex_how); // Reacquire mutex >+ ABSL_TSAN_MUTEX_POST_LOCK(mutex, TsanFlags(mutex_how), 0); >+ return rc; >+} >+ >+bool CondVar::WaitWithTimeout(Mutex *mu, absl::Duration timeout) { >+ return WaitWithDeadline(mu, DeadlineFromTimeout(timeout)); >+} >+ >+bool CondVar::WaitWithDeadline(Mutex *mu, absl::Time deadline) { >+ return WaitCommon(mu, KernelTimeout(deadline)); >+} >+ >+void CondVar::Wait(Mutex *mu) { >+ WaitCommon(mu, KernelTimeout::Never()); >+} >+ >+// Wake thread w >+// If it was a timed wait, w will be waiting on w->cv >+// Otherwise, if it was not a Mutex mutex, w will be waiting on w->sem >+// Otherwise, w is transferred to the Mutex mutex via Mutex::Fer(). >+void CondVar::Wakeup(PerThreadSynch *w) { >+ if (w->waitp->timeout.has_timeout() || w->waitp->cvmu == nullptr) { >+ // The waiting thread only needs to observe "w->state == kAvailable" to be >+ // released, we must cache "cvmu" before clearing "next". >+ Mutex *mu = w->waitp->cvmu; >+ w->next = nullptr; >+ w->state.store(PerThreadSynch::kAvailable, std::memory_order_release); >+ Mutex::IncrementSynchSem(mu, w); >+ } else { >+ w->waitp->cvmu->Fer(w); >+ } >+} >+ >+void CondVar::Signal() { >+ ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0); >+ intptr_t v; >+ int c = 0; >+ for (v = cv_.load(std::memory_order_relaxed); v != 0; >+ v = cv_.load(std::memory_order_relaxed)) { >+ if ((v & kCvSpin) == 0 && // attempt to acquire spinlock >+ cv_.compare_exchange_strong(v, v | kCvSpin, >+ std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow); >+ PerThreadSynch *w = nullptr; >+ if (h != nullptr) { // remove first waiter >+ w = h->next; >+ if (w == h) { >+ h = nullptr; >+ } else { >+ h->next = w->next; >+ } >+ } >+ // release spinlock >+ cv_.store((v & kCvEvent) | reinterpret_cast<intptr_t>(h), >+ std::memory_order_release); >+ if (w != nullptr) { >+ CondVar::Wakeup(w); // wake waiter, if there was one >+ cond_var_tracer("Signal wakeup", this); >+ } >+ if ((v & kCvEvent) != 0) { >+ PostSynchEvent(this, SYNCH_EV_SIGNAL); >+ } >+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0); >+ return; >+ } else { >+ c = Delay(c, GENTLE); >+ } >+ } >+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0); >+} >+ >+void CondVar::SignalAll () { >+ ABSL_TSAN_MUTEX_PRE_SIGNAL(0, 0); >+ intptr_t v; >+ int c = 0; >+ for (v = cv_.load(std::memory_order_relaxed); v != 0; >+ v = cv_.load(std::memory_order_relaxed)) { >+ // empty the list if spinlock free >+ // We do this by simply setting the list to empty using >+ // compare and swap. We then have the entire list in our hands, >+ // which cannot be changing since we grabbed it while no one >+ // held the lock. >+ if ((v & kCvSpin) == 0 && >+ cv_.compare_exchange_strong(v, v & kCvEvent, std::memory_order_acquire, >+ std::memory_order_relaxed)) { >+ PerThreadSynch *h = reinterpret_cast<PerThreadSynch *>(v & ~kCvLow); >+ if (h != nullptr) { >+ PerThreadSynch *w; >+ PerThreadSynch *n = h->next; >+ do { // for every thread, wake it up >+ w = n; >+ n = n->next; >+ CondVar::Wakeup(w); >+ } while (w != h); >+ cond_var_tracer("SignalAll wakeup", this); >+ } >+ if ((v & kCvEvent) != 0) { >+ PostSynchEvent(this, SYNCH_EV_SIGNALALL); >+ } >+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0); >+ return; >+ } else { >+ c = Delay(c, GENTLE); // try again after a delay >+ } >+ } >+ ABSL_TSAN_MUTEX_POST_SIGNAL(0, 0); >+} >+ >+void ReleasableMutexLock::Release() { >+ ABSL_RAW_CHECK(this->mu_ != nullptr, >+ "ReleasableMutexLock::Release may only be called once"); >+ this->mu_->Unlock(); >+ this->mu_ = nullptr; >+} >+ >+#ifdef THREAD_SANITIZER >+extern "C" void __tsan_read1(void *addr); >+#else >+#define __tsan_read1(addr) // do nothing if TSan not enabled >+#endif >+ >+// A function that just returns its argument, dereferenced >+static bool Dereference(void *arg) { >+ // ThreadSanitizer does not instrument this file for memory accesses. >+ // This function dereferences a user variable that can participate >+ // in a data race, so we need to manually tell TSan about this memory access. >+ __tsan_read1(arg); >+ return *(static_cast<bool *>(arg)); >+} >+ >+Condition::Condition() {} // null constructor, used for kTrue only >+const Condition Condition::kTrue; >+ >+Condition::Condition(bool (*func)(void *), void *arg) >+ : eval_(&CallVoidPtrFunction), >+ function_(func), >+ method_(nullptr), >+ arg_(arg) {} >+ >+bool Condition::CallVoidPtrFunction(const Condition *c) { >+ return (*c->function_)(c->arg_); >+} >+ >+Condition::Condition(const bool *cond) >+ : eval_(CallVoidPtrFunction), >+ function_(Dereference), >+ method_(nullptr), >+ // const_cast is safe since Dereference does not modify arg >+ arg_(const_cast<bool *>(cond)) {} >+ >+bool Condition::Eval() const { >+ // eval_ == null for kTrue >+ return (this->eval_ == nullptr) || (*this->eval_)(this); >+} >+ >+bool Condition::GuaranteedEqual(const Condition *a, const Condition *b) { >+ if (a == nullptr) { >+ return b == nullptr || b->eval_ == nullptr; >+ } >+ if (b == nullptr || b->eval_ == nullptr) { >+ return a->eval_ == nullptr; >+ } >+ return a->eval_ == b->eval_ && a->function_ == b->function_ && >+ a->arg_ == b->arg_ && a->method_ == b->method_; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.h >new file mode 100644 >index 00000000000..83c214867ac >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex.h >@@ -0,0 +1,1028 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// mutex.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines a `Mutex` -- a mutually exclusive lock -- and the >+// most common type of synchronization primitive for facilitating locks on >+// shared resources. A mutex is used to prevent multiple threads from accessing >+// and/or writing to a shared resource concurrently. >+// >+// Unlike a `std::mutex`, the Abseil `Mutex` provides the following additional >+// features: >+// * Conditional predicates intrinsic to the `Mutex` object >+// * Shared/reader locks, in addition to standard exclusive/writer locks >+// * Deadlock detection and debug support. >+// >+// The following helper classes are also defined within this file: >+// >+// MutexLock - An RAII wrapper to acquire and release a `Mutex` for exclusive/ >+// write access within the current scope. >+// ReaderMutexLock >+// - An RAII wrapper to acquire and release a `Mutex` for shared/read >+// access within the current scope. >+// >+// WriterMutexLock >+// - Alias for `MutexLock` above, designed for use in distinguishing >+// reader and writer locks within code. >+// >+// In addition to simple mutex locks, this file also defines ways to perform >+// locking under certain conditions. >+// >+// Condition - (Preferred) Used to wait for a particular predicate that >+// depends on state protected by the `Mutex` to become true. >+// CondVar - A lower-level variant of `Condition` that relies on >+// application code to explicitly signal the `CondVar` when >+// a condition has been met. >+// >+// See below for more information on using `Condition` or `CondVar`. >+// >+// Mutexes and mutex behavior can be quite complicated. The information within >+// this header file is limited, as a result. Please consult the Mutex guide for >+// more complete information and examples. >+ >+#ifndef ABSL_SYNCHRONIZATION_MUTEX_H_ >+#define ABSL_SYNCHRONIZATION_MUTEX_H_ >+ >+#include <atomic> >+#include <cstdint> >+#include <string> >+ >+#include "absl/base/internal/identity.h" >+#include "absl/base/internal/low_level_alloc.h" >+#include "absl/base/internal/thread_identity.h" >+#include "absl/base/internal/tsan_mutex_interface.h" >+#include "absl/base/port.h" >+#include "absl/base/thread_annotations.h" >+#include "absl/synchronization/internal/kernel_timeout.h" >+#include "absl/synchronization/internal/per_thread_sem.h" >+#include "absl/time/time.h" >+ >+// Decide if we should use the non-production implementation because >+// the production implementation hasn't been fully ported yet. >+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX >+#error ABSL_INTERNAL_USE_NONPROD_MUTEX cannot be directly set >+#elif defined(ABSL_LOW_LEVEL_ALLOC_MISSING) >+#define ABSL_INTERNAL_USE_NONPROD_MUTEX 1 >+#include "absl/synchronization/internal/mutex_nonprod.inc" >+#endif >+ >+namespace absl { >+ >+class Condition; >+struct SynchWaitParams; >+ >+// ----------------------------------------------------------------------------- >+// Mutex >+// ----------------------------------------------------------------------------- >+// >+// A `Mutex` is a non-reentrant (aka non-recursive) Mutually Exclusive lock >+// on some resource, typically a variable or data structure with associated >+// invariants. Proper usage of mutexes prevents concurrent access by different >+// threads to the same resource. >+// >+// A `Mutex` has two basic operations: `Mutex::Lock()` and `Mutex::Unlock()`. >+// The `Lock()` operation *acquires* a `Mutex` (in a state known as an >+// *exclusive* -- or write -- lock), while the `Unlock()` operation *releases* a >+// Mutex. During the span of time between the Lock() and Unlock() operations, >+// a mutex is said to be *held*. By design all mutexes support exclusive/write >+// locks, as this is the most common way to use a mutex. >+// >+// The `Mutex` state machine for basic lock/unlock operations is quite simple: >+// >+// | | Lock() | Unlock() | >+// |----------------+------------+----------| >+// | Free | Exclusive | invalid | >+// | Exclusive | blocks | Free | >+// >+// Attempts to `Unlock()` must originate from the thread that performed the >+// corresponding `Lock()` operation. >+// >+// An "invalid" operation is disallowed by the API. The `Mutex` implementation >+// is allowed to do anything on an invalid call, including but not limited to >+// crashing with a useful error message, silently succeeding, or corrupting >+// data structures. In debug mode, the implementation attempts to crash with a >+// useful error message. >+// >+// `Mutex` is not guaranteed to be "fair" in prioritizing waiting threads; it >+// is, however, approximately fair over long periods, and starvation-free for >+// threads at the same priority. >+// >+// The lock/unlock primitives are now annotated with lock annotations >+// defined in (base/thread_annotations.h). When writing multi-threaded code, >+// you should use lock annotations whenever possible to document your lock >+// synchronization policy. Besides acting as documentation, these annotations >+// also help compilers or static analysis tools to identify and warn about >+// issues that could potentially result in race conditions and deadlocks. >+// >+// For more information about the lock annotations, please see >+// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) >+// in the Clang documentation. >+// >+// See also `MutexLock`, below, for scoped `Mutex` acquisition. >+ >+class LOCKABLE Mutex { >+ public: >+ Mutex(); >+ ~Mutex(); >+ >+ // Mutex::Lock() >+ // >+ // Blocks the calling thread, if necessary, until this `Mutex` is free, and >+ // then acquires it exclusively. (This lock is also known as a "write lock.") >+ void Lock() EXCLUSIVE_LOCK_FUNCTION(); >+ >+ // Mutex::Unlock() >+ // >+ // Releases this `Mutex` and returns it from the exclusive/write state to the >+ // free state. Caller must hold the `Mutex` exclusively. >+ void Unlock() UNLOCK_FUNCTION(); >+ >+ // Mutex::TryLock() >+ // >+ // If the mutex can be acquired without blocking, does so exclusively and >+ // returns `true`. Otherwise, returns `false`. Returns `true` with high >+ // probability if the `Mutex` was free. >+ bool TryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true); >+ >+ // Mutex::AssertHeld() >+ // >+ // Return immediately if this thread holds the `Mutex` exclusively (in write >+ // mode). Otherwise, may report an error (typically by crashing with a >+ // diagnostic), or may return immediately. >+ void AssertHeld() const ASSERT_EXCLUSIVE_LOCK(); >+ >+ // --------------------------------------------------------------------------- >+ // Reader-Writer Locking >+ // --------------------------------------------------------------------------- >+ >+ // A Mutex can also be used as a starvation-free reader-writer lock. >+ // Neither read-locks nor write-locks are reentrant/recursive to avoid >+ // potential client programming errors. >+ // >+ // The Mutex API provides `Writer*()` aliases for the existing `Lock()`, >+ // `Unlock()` and `TryLock()` methods for use within applications mixing >+ // reader/writer locks. Using `Reader*()` and `Writer*()` operations in this >+ // manner can make locking behavior clearer when mixing read and write modes. >+ // >+ // Introducing reader locks necessarily complicates the `Mutex` state >+ // machine somewhat. The table below illustrates the allowed state transitions >+ // of a mutex in such cases. Note that ReaderLock() may block even if the lock >+ // is held in shared mode; this occurs when another thread is blocked on a >+ // call to WriterLock(). >+ // >+ // --------------------------------------------------------------------------- >+ // Operation: WriterLock() Unlock() ReaderLock() ReaderUnlock() >+ // --------------------------------------------------------------------------- >+ // State >+ // --------------------------------------------------------------------------- >+ // Free Exclusive invalid Shared(1) invalid >+ // Shared(1) blocks invalid Shared(2) or blocks Free >+ // Shared(n) n>1 blocks invalid Shared(n+1) or blocks Shared(n-1) >+ // Exclusive blocks Free blocks invalid >+ // --------------------------------------------------------------------------- >+ // >+ // In comments below, "shared" refers to a state of Shared(n) for any n > 0. >+ >+ // Mutex::ReaderLock() >+ // >+ // Blocks the calling thread, if necessary, until this `Mutex` is either free, >+ // or in shared mode, and then acquires a share of it. Note that >+ // `ReaderLock()` will block if some other thread has an exclusive/writer lock >+ // on the mutex. >+ >+ void ReaderLock() SHARED_LOCK_FUNCTION(); >+ >+ // Mutex::ReaderUnlock() >+ // >+ // Releases a read share of this `Mutex`. `ReaderUnlock` may return a mutex to >+ // the free state if this thread holds the last reader lock on the mutex. Note >+ // that you cannot call `ReaderUnlock()` on a mutex held in write mode. >+ void ReaderUnlock() UNLOCK_FUNCTION(); >+ >+ // Mutex::ReaderTryLock() >+ // >+ // If the mutex can be acquired without blocking, acquires this mutex for >+ // shared access and returns `true`. Otherwise, returns `false`. Returns >+ // `true` with high probability if the `Mutex` was free or shared. >+ bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true); >+ >+ // Mutex::AssertReaderHeld() >+ // >+ // Returns immediately if this thread holds the `Mutex` in at least shared >+ // mode (read mode). Otherwise, may report an error (typically by >+ // crashing with a diagnostic), or may return immediately. >+ void AssertReaderHeld() const ASSERT_SHARED_LOCK(); >+ >+ // Mutex::WriterLock() >+ // Mutex::WriterUnlock() >+ // Mutex::WriterTryLock() >+ // >+ // Aliases for `Mutex::Lock()`, `Mutex::Unlock()`, and `Mutex::TryLock()`. >+ // >+ // These methods may be used (along with the complementary `Reader*()` >+ // methods) to distingish simple exclusive `Mutex` usage (`Lock()`, >+ // etc.) from reader/writer lock usage. >+ void WriterLock() EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); } >+ >+ void WriterUnlock() UNLOCK_FUNCTION() { this->Unlock(); } >+ >+ bool WriterTryLock() EXCLUSIVE_TRYLOCK_FUNCTION(true) { >+ return this->TryLock(); >+ } >+ >+ // --------------------------------------------------------------------------- >+ // Conditional Critical Regions >+ // --------------------------------------------------------------------------- >+ >+ // Conditional usage of a `Mutex` can occur using two distinct paradigms: >+ // >+ // * Use of `Mutex` member functions with `Condition` objects. >+ // * Use of the separate `CondVar` abstraction. >+ // >+ // In general, prefer use of `Condition` and the `Mutex` member functions >+ // listed below over `CondVar`. When there are multiple threads waiting on >+ // distinctly different conditions, however, a battery of `CondVar`s may be >+ // more efficient. This section discusses use of `Condition` objects. >+ // >+ // `Mutex` contains member functions for performing lock operations only under >+ // certain conditions, of class `Condition`. For correctness, the `Condition` >+ // must return a boolean that is a pure function, only of state protected by >+ // the `Mutex`. The condition must be invariant w.r.t. environmental state >+ // such as thread, cpu id, or time, and must be `noexcept`. The condition will >+ // always be invoked with the mutex held in at least read mode, so you should >+ // not block it for long periods or sleep it on a timer. >+ // >+ // Since a condition must not depend directly on the current time, use >+ // `*WithTimeout()` member function variants to make your condition >+ // effectively true after a given duration, or `*WithDeadline()` variants to >+ // make your condition effectively true after a given time. >+ // >+ // The condition function should have no side-effects aside from debug >+ // logging; as a special exception, the function may acquire other mutexes >+ // provided it releases all those that it acquires. (This exception was >+ // required to allow logging.) >+ >+ // Mutex::Await() >+ // >+ // Unlocks this `Mutex` and blocks until simultaneously both `cond` is `true` >+ // and this `Mutex` can be reacquired, then reacquires this `Mutex` in the >+ // same mode in which it was previously held. If the condition is initially >+ // `true`, `Await()` *may* skip the release/re-acquire step. >+ // >+ // `Await()` requires that this thread holds this `Mutex` in some mode. >+ void Await(const Condition &cond); >+ >+ // Mutex::LockWhen() >+ // Mutex::ReaderLockWhen() >+ // Mutex::WriterLockWhen() >+ // >+ // Blocks until simultaneously both `cond` is `true` and this `Mutex` can >+ // be acquired, then atomically acquires this `Mutex`. `LockWhen()` is >+ // logically equivalent to `*Lock(); Await();` though they may have different >+ // performance characteristics. >+ void LockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION(); >+ >+ void ReaderLockWhen(const Condition &cond) SHARED_LOCK_FUNCTION(); >+ >+ void WriterLockWhen(const Condition &cond) EXCLUSIVE_LOCK_FUNCTION() { >+ this->LockWhen(cond); >+ } >+ >+ // --------------------------------------------------------------------------- >+ // Mutex Variants with Timeouts/Deadlines >+ // --------------------------------------------------------------------------- >+ >+ // Mutex::AwaitWithTimeout() >+ // Mutex::AwaitWithDeadline() >+ // >+ // If `cond` is initially true, do nothing, or act as though `cond` is >+ // initially false. >+ // >+ // If `cond` is initially false, unlock this `Mutex` and block until >+ // simultaneously: >+ // - either `cond` is true or the {timeout has expired, deadline has passed} >+ // and >+ // - this `Mutex` can be reacquired, >+ // then reacquire this `Mutex` in the same mode in which it was previously >+ // held, returning `true` iff `cond` is `true` on return. >+ // >+ // Deadlines in the past are equivalent to an immediate deadline. >+ // Negative timeouts are equivalent to a zero timeout. >+ // >+ // This method requires that this thread holds this `Mutex` in some mode. >+ bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout); >+ >+ bool AwaitWithDeadline(const Condition &cond, absl::Time deadline); >+ >+ // Mutex::LockWhenWithTimeout() >+ // Mutex::ReaderLockWhenWithTimeout() >+ // Mutex::WriterLockWhenWithTimeout() >+ // >+ // Blocks until simultaneously both: >+ // - either `cond` is `true` or the timeout has expired, and >+ // - this `Mutex` can be acquired, >+ // then atomically acquires this `Mutex`, returning `true` iff `cond` is >+ // `true` on return. >+ // >+ // Negative timeouts are equivalent to a zero timeout. >+ bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout) >+ EXCLUSIVE_LOCK_FUNCTION(); >+ bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout) >+ SHARED_LOCK_FUNCTION(); >+ bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout) >+ EXCLUSIVE_LOCK_FUNCTION() { >+ return this->LockWhenWithTimeout(cond, timeout); >+ } >+ >+ // Mutex::LockWhenWithDeadline() >+ // Mutex::ReaderLockWhenWithDeadline() >+ // Mutex::WriterLockWhenWithDeadline() >+ // >+ // Blocks until simultaneously both: >+ // - either `cond` is `true` or the deadline has been passed, and >+ // - this `Mutex` can be acquired, >+ // then atomically acquires this Mutex, returning `true` iff `cond` is `true` >+ // on return. >+ // >+ // Deadlines in the past are equivalent to an immediate deadline. >+ bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline) >+ EXCLUSIVE_LOCK_FUNCTION(); >+ bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline) >+ SHARED_LOCK_FUNCTION(); >+ bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline) >+ EXCLUSIVE_LOCK_FUNCTION() { >+ return this->LockWhenWithDeadline(cond, deadline); >+ } >+ >+ // --------------------------------------------------------------------------- >+ // Debug Support: Invariant Checking, Deadlock Detection, Logging. >+ // --------------------------------------------------------------------------- >+ >+ // Mutex::EnableInvariantDebugging() >+ // >+ // If `invariant`!=null and if invariant debugging has been enabled globally, >+ // cause `(*invariant)(arg)` to be called at moments when the invariant for >+ // this `Mutex` should hold (for example: just after acquire, just before >+ // release). >+ // >+ // The routine `invariant` should have no side-effects since it is not >+ // guaranteed how many times it will be called; it should check the invariant >+ // and crash if it does not hold. Enabling global invariant debugging may >+ // substantially reduce `Mutex` performance; it should be set only for >+ // non-production runs. Optimization options may also disable invariant >+ // checks. >+ void EnableInvariantDebugging(void (*invariant)(void *), void *arg); >+ >+ // Mutex::EnableDebugLog() >+ // >+ // Cause all subsequent uses of this `Mutex` to be logged via >+ // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if no previous >+ // call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made. >+ // >+ // Note: This method substantially reduces `Mutex` performance. >+ void EnableDebugLog(const char *name); >+ >+ // Deadlock detection >+ >+ // Mutex::ForgetDeadlockInfo() >+ // >+ // Forget any deadlock-detection information previously gathered >+ // about this `Mutex`. Call this method in debug mode when the lock ordering >+ // of a `Mutex` changes. >+ void ForgetDeadlockInfo(); >+ >+ // Mutex::AssertNotHeld() >+ // >+ // Return immediately if this thread does not hold this `Mutex` in any >+ // mode; otherwise, may report an error (typically by crashing with a >+ // diagnostic), or may return immediately. >+ // >+ // Currently this check is performed only if all of: >+ // - in debug mode >+ // - SetMutexDeadlockDetectionMode() has been set to kReport or kAbort >+ // - number of locks concurrently held by this thread is not large. >+ // are true. >+ void AssertNotHeld() const; >+ >+ // Special cases. >+ >+ // A `MuHow` is a constant that indicates how a lock should be acquired. >+ // Internal implementation detail. Clients should ignore. >+ typedef const struct MuHowS *MuHow; >+ >+ // Mutex::InternalAttemptToUseMutexInFatalSignalHandler() >+ // >+ // Causes the `Mutex` implementation to prepare itself for re-entry caused by >+ // future use of `Mutex` within a fatal signal handler. This method is >+ // intended for use only for last-ditch attempts to log crash information. >+ // It does not guarantee that attempts to use Mutexes within the handler will >+ // not deadlock; it merely makes other faults less likely. >+ // >+ // WARNING: This routine must be invoked from a signal handler, and the >+ // signal handler must either loop forever or terminate the process. >+ // Attempts to return from (or `longjmp` out of) the signal handler once this >+ // call has been made may cause arbitrary program behaviour including >+ // crashes and deadlocks. >+ static void InternalAttemptToUseMutexInFatalSignalHandler(); >+ >+ private: >+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX >+ friend class CondVar; >+ >+ synchronization_internal::MutexImpl *impl() { return impl_.get(); } >+ >+ synchronization_internal::SynchronizationStorage< >+ synchronization_internal::MutexImpl> >+ impl_; >+#else >+ std::atomic<intptr_t> mu_; // The Mutex state. >+ >+ // Post()/Wait() versus associated PerThreadSem; in class for required >+ // friendship with PerThreadSem. >+ static inline void IncrementSynchSem(Mutex *mu, >+ base_internal::PerThreadSynch *w); >+ static inline bool DecrementSynchSem( >+ Mutex *mu, base_internal::PerThreadSynch *w, >+ synchronization_internal::KernelTimeout t); >+ >+ // slow path acquire >+ void LockSlowLoop(SynchWaitParams *waitp, int flags); >+ // wrappers around LockSlowLoop() >+ bool LockSlowWithDeadline(MuHow how, const Condition *cond, >+ synchronization_internal::KernelTimeout t, >+ int flags); >+ void LockSlow(MuHow how, const Condition *cond, >+ int flags) ABSL_ATTRIBUTE_COLD; >+ // slow path release >+ void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD; >+ // Common code between Await() and AwaitWithTimeout/Deadline() >+ bool AwaitCommon(const Condition &cond, >+ synchronization_internal::KernelTimeout t); >+ // Attempt to remove thread s from queue. >+ void TryRemove(base_internal::PerThreadSynch *s); >+ // Block a thread on mutex. >+ void Block(base_internal::PerThreadSynch *s); >+ // Wake a thread; return successor. >+ base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w); >+ >+ friend class CondVar; // for access to Trans()/Fer(). >+ void Trans(MuHow how); // used for CondVar->Mutex transfer >+ void Fer( >+ base_internal::PerThreadSynch *w); // used for CondVar->Mutex transfer >+#endif >+ >+ // Catch the error of writing Mutex when intending MutexLock. >+ Mutex(const volatile Mutex * /*ignored*/) {} // NOLINT(runtime/explicit) >+ >+ Mutex(const Mutex&) = delete; >+ Mutex& operator=(const Mutex&) = delete; >+}; >+ >+// ----------------------------------------------------------------------------- >+// Mutex RAII Wrappers >+// ----------------------------------------------------------------------------- >+ >+// MutexLock >+// >+// `MutexLock` is a helper class, which acquires and releases a `Mutex` via >+// RAII. >+// >+// Example: >+// >+// Class Foo { >+// >+// Foo::Bar* Baz() { >+// MutexLock l(&lock_); >+// ... >+// return bar; >+// } >+// >+// private: >+// Mutex lock_; >+// }; >+class SCOPED_LOCKABLE MutexLock { >+ public: >+ explicit MutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) { >+ this->mu_->Lock(); >+ } >+ >+ MutexLock(const MutexLock &) = delete; // NOLINT(runtime/mutex) >+ MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex) >+ MutexLock& operator=(const MutexLock&) = delete; >+ MutexLock& operator=(MutexLock&&) = delete; >+ >+ ~MutexLock() UNLOCK_FUNCTION() { this->mu_->Unlock(); } >+ >+ private: >+ Mutex *const mu_; >+}; >+ >+// ReaderMutexLock >+// >+// The `ReaderMutexLock` is a helper class, like `MutexLock`, which acquires and >+// releases a shared lock on a `Mutex` via RAII. >+class SCOPED_LOCKABLE ReaderMutexLock { >+ public: >+ explicit ReaderMutexLock(Mutex *mu) SHARED_LOCK_FUNCTION(mu) >+ : mu_(mu) { >+ mu->ReaderLock(); >+ } >+ >+ ReaderMutexLock(const ReaderMutexLock&) = delete; >+ ReaderMutexLock(ReaderMutexLock&&) = delete; >+ ReaderMutexLock& operator=(const ReaderMutexLock&) = delete; >+ ReaderMutexLock& operator=(ReaderMutexLock&&) = delete; >+ >+ ~ReaderMutexLock() UNLOCK_FUNCTION() { >+ this->mu_->ReaderUnlock(); >+ } >+ >+ private: >+ Mutex *const mu_; >+}; >+ >+// WriterMutexLock >+// >+// The `WriterMutexLock` is a helper class, like `MutexLock`, which acquires and >+// releases a write (exclusive) lock on a `Mutex` via RAII. >+class SCOPED_LOCKABLE WriterMutexLock { >+ public: >+ explicit WriterMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) >+ : mu_(mu) { >+ mu->WriterLock(); >+ } >+ >+ WriterMutexLock(const WriterMutexLock&) = delete; >+ WriterMutexLock(WriterMutexLock&&) = delete; >+ WriterMutexLock& operator=(const WriterMutexLock&) = delete; >+ WriterMutexLock& operator=(WriterMutexLock&&) = delete; >+ >+ ~WriterMutexLock() UNLOCK_FUNCTION() { >+ this->mu_->WriterUnlock(); >+ } >+ >+ private: >+ Mutex *const mu_; >+}; >+ >+// ----------------------------------------------------------------------------- >+// Condition >+// ----------------------------------------------------------------------------- >+// >+// As noted above, `Mutex` contains a number of member functions which take a >+// `Condition` as a argument; clients can wait for conditions to become `true` >+// before attempting to acquire the mutex. These sections are known as >+// "condition critical" sections. To use a `Condition`, you simply need to >+// construct it, and use within an appropriate `Mutex` member function; >+// everything else in the `Condition` class is an implementation detail. >+// >+// A `Condition` is specified as a function pointer which returns a boolean. >+// `Condition` functions should be pure functions -- their results should depend >+// only on passed arguments, should not consult any external state (such as >+// clocks), and should have no side-effects, aside from debug logging. Any >+// objects that the function may access should be limited to those which are >+// constant while the mutex is blocked on the condition (e.g. a stack variable), >+// or objects of state protected explicitly by the mutex. >+// >+// No matter which construction is used for `Condition`, the underlying >+// function pointer / functor / callable must not throw any >+// exceptions. Correctness of `Mutex` / `Condition` is not guaranteed in >+// the face of a throwing `Condition`. (When Abseil is allowed to depend >+// on C++17, these function pointers will be explicitly marked >+// `noexcept`; until then this requirement cannot be enforced in the >+// type system.) >+// >+// Note: to use a `Condition`, you need only construct it and pass it within the >+// appropriate `Mutex' member function, such as `Mutex::Await()`. >+// >+// Example: >+// >+// // assume count_ is not internal reference count >+// int count_ GUARDED_BY(mu_); >+// >+// mu_.LockWhen(Condition(+[](int* count) { return *count == 0; }, >+// &count_)); >+// >+// When multiple threads are waiting on exactly the same condition, make sure >+// that they are constructed with the same parameters (same pointer to function >+// + arg, or same pointer to object + method), so that the mutex implementation >+// can avoid redundantly evaluating the same condition for each thread. >+class Condition { >+ public: >+ // A Condition that returns the result of "(*func)(arg)" >+ Condition(bool (*func)(void *), void *arg); >+ >+ // Templated version for people who are averse to casts. >+ // >+ // To use a lambda, prepend it with unary plus, which converts the lambda >+ // into a function pointer: >+ // Condition(+[](T* t) { return ...; }, arg). >+ // >+ // Note: lambdas in this case must contain no bound variables. >+ // >+ // See class comment for performance advice. >+ template<typename T> >+ Condition(bool (*func)(T *), T *arg); >+ >+ // Templated version for invoking a method that returns a `bool`. >+ // >+ // `Condition(object, &Class::Method)` constructs a `Condition` that evaluates >+ // `object->Method()`. >+ // >+ // Implementation Note: `absl::internal::identity` is used to allow methods to >+ // come from base classes. A simpler signature like >+ // `Condition(T*, bool (T::*)())` does not suffice. >+ template<typename T> >+ Condition(T *object, bool (absl::internal::identity<T>::type::* method)()); >+ >+ // Same as above, for const members >+ template<typename T> >+ Condition(const T *object, >+ bool (absl::internal::identity<T>::type::* method)() const); >+ >+ // A Condition that returns the value of `*cond` >+ explicit Condition(const bool *cond); >+ >+ // Templated version for invoking a functor that returns a `bool`. >+ // This approach accepts pointers to non-mutable lambdas, `std::function`, >+ // the result of` std::bind` and user-defined functors that define >+ // `bool F::operator()() const`. >+ // >+ // Example: >+ // >+ // auto reached = [this, current]() { >+ // mu_.AssertReaderHeld(); // For annotalysis. >+ // return processed_ >= current; >+ // }; >+ // mu_.Await(Condition(&reached)); >+ >+ // See class comment for performance advice. In particular, if there >+ // might be more than one waiter for the same condition, make sure >+ // that all waiters construct the condition with the same pointers. >+ >+ // Implementation note: The second template parameter ensures that this >+ // constructor doesn't participate in overload resolution if T doesn't have >+ // `bool operator() const`. >+ template <typename T, typename E = decltype( >+ static_cast<bool (T::*)() const>(&T::operator()))> >+ explicit Condition(const T *obj) >+ : Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {} >+ >+ // A Condition that always returns `true`. >+ static const Condition kTrue; >+ >+ // Evaluates the condition. >+ bool Eval() const; >+ >+ // Returns `true` if the two conditions are guaranteed to return the same >+ // value if evaluated at the same time, `false` if the evaluation *may* return >+ // different results. >+ // >+ // Two `Condition` values are guaranteed equal if both their `func` and `arg` >+ // components are the same. A null pointer is equivalent to a `true` >+ // condition. >+ static bool GuaranteedEqual(const Condition *a, const Condition *b); >+ >+ private: >+ typedef bool (*InternalFunctionType)(void * arg); >+ typedef bool (Condition::*InternalMethodType)(); >+ typedef bool (*InternalMethodCallerType)(void * arg, >+ InternalMethodType internal_method); >+ >+ bool (*eval_)(const Condition*); // Actual evaluator >+ InternalFunctionType function_; // function taking pointer returning bool >+ InternalMethodType method_; // method returning bool >+ void *arg_; // arg of function_ or object of method_ >+ >+ Condition(); // null constructor used only to create kTrue >+ >+ // Various functions eval_ can point to: >+ static bool CallVoidPtrFunction(const Condition*); >+ template <typename T> static bool CastAndCallFunction(const Condition* c); >+ template <typename T> static bool CastAndCallMethod(const Condition* c); >+}; >+ >+// ----------------------------------------------------------------------------- >+// CondVar >+// ----------------------------------------------------------------------------- >+// >+// A condition variable, reflecting state evaluated separately outside of the >+// `Mutex` object, which can be signaled to wake callers. >+// This class is not normally needed; use `Mutex` member functions such as >+// `Mutex::Await()` and intrinsic `Condition` abstractions. In rare cases >+// with many threads and many conditions, `CondVar` may be faster. >+// >+// The implementation may deliver signals to any condition variable at >+// any time, even when no call to `Signal()` or `SignalAll()` is made; as a >+// result, upon being awoken, you must check the logical condition you have >+// been waiting upon. >+// >+// Examples: >+// >+// Usage for a thread waiting for some condition C protected by mutex mu: >+// mu.Lock(); >+// while (!C) { cv->Wait(&mu); } // releases and reacquires mu >+// // C holds; process data >+// mu.Unlock(); >+// >+// Usage to wake T is: >+// mu.Lock(); >+// // process data, possibly establishing C >+// if (C) { cv->Signal(); } >+// mu.Unlock(); >+// >+// If C may be useful to more than one waiter, use `SignalAll()` instead of >+// `Signal()`. >+// >+// With this implementation it is efficient to use `Signal()/SignalAll()` inside >+// the locked region; this usage can make reasoning about your program easier. >+// >+class CondVar { >+ public: >+ CondVar(); >+ ~CondVar(); >+ >+ // CondVar::Wait() >+ // >+ // Atomically releases a `Mutex` and blocks on this condition variable. >+ // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a >+ // spurious wakeup), then reacquires the `Mutex` and returns. >+ // >+ // Requires and ensures that the current thread holds the `Mutex`. >+ void Wait(Mutex *mu); >+ >+ // CondVar::WaitWithTimeout() >+ // >+ // Atomically releases a `Mutex` and blocks on this condition variable. >+ // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a >+ // spurious wakeup), or until the timeout has expired, then reacquires >+ // the `Mutex` and returns. >+ // >+ // Returns true if the timeout has expired without this `CondVar` >+ // being signalled in any manner. If both the timeout has expired >+ // and this `CondVar` has been signalled, the implementation is free >+ // to return `true` or `false`. >+ // >+ // Requires and ensures that the current thread holds the `Mutex`. >+ bool WaitWithTimeout(Mutex *mu, absl::Duration timeout); >+ >+ // CondVar::WaitWithDeadline() >+ // >+ // Atomically releases a `Mutex` and blocks on this condition variable. >+ // Waits until awakened by a call to `Signal()` or `SignalAll()` (or a >+ // spurious wakeup), or until the deadline has passed, then reacquires >+ // the `Mutex` and returns. >+ // >+ // Deadlines in the past are equivalent to an immediate deadline. >+ // >+ // Returns true if the deadline has passed without this `CondVar` >+ // being signalled in any manner. If both the deadline has passed >+ // and this `CondVar` has been signalled, the implementation is free >+ // to return `true` or `false`. >+ // >+ // Requires and ensures that the current thread holds the `Mutex`. >+ bool WaitWithDeadline(Mutex *mu, absl::Time deadline); >+ >+ // CondVar::Signal() >+ // >+ // Signal this `CondVar`; wake at least one waiter if one exists. >+ void Signal(); >+ >+ // CondVar::SignalAll() >+ // >+ // Signal this `CondVar`; wake all waiters. >+ void SignalAll(); >+ >+ // CondVar::EnableDebugLog() >+ // >+ // Causes all subsequent uses of this `CondVar` to be logged via >+ // `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`. >+ // Note: this method substantially reduces `CondVar` performance. >+ void EnableDebugLog(const char *name); >+ >+ private: >+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX >+ synchronization_internal::CondVarImpl *impl() { return impl_.get(); } >+ synchronization_internal::SynchronizationStorage< >+ synchronization_internal::CondVarImpl> >+ impl_; >+#else >+ bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t); >+ void Remove(base_internal::PerThreadSynch *s); >+ void Wakeup(base_internal::PerThreadSynch *w); >+ std::atomic<intptr_t> cv_; // Condition variable state. >+#endif >+ CondVar(const CondVar&) = delete; >+ CondVar& operator=(const CondVar&) = delete; >+}; >+ >+ >+// Variants of MutexLock. >+// >+// If you find yourself using one of these, consider instead using >+// Mutex::Unlock() and/or if-statements for clarity. >+ >+// MutexLockMaybe >+// >+// MutexLockMaybe is like MutexLock, but is a no-op when mu is null. >+class SCOPED_LOCKABLE MutexLockMaybe { >+ public: >+ explicit MutexLockMaybe(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) >+ : mu_(mu) { if (this->mu_ != nullptr) { this->mu_->Lock(); } } >+ ~MutexLockMaybe() UNLOCK_FUNCTION() { >+ if (this->mu_ != nullptr) { this->mu_->Unlock(); } >+ } >+ private: >+ Mutex *const mu_; >+ MutexLockMaybe(const MutexLockMaybe&) = delete; >+ MutexLockMaybe(MutexLockMaybe&&) = delete; >+ MutexLockMaybe& operator=(const MutexLockMaybe&) = delete; >+ MutexLockMaybe& operator=(MutexLockMaybe&&) = delete; >+}; >+ >+// ReleasableMutexLock >+// >+// ReleasableMutexLock is like MutexLock, but permits `Release()` of its >+// mutex before destruction. `Release()` may be called at most once. >+class SCOPED_LOCKABLE ReleasableMutexLock { >+ public: >+ explicit ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu) >+ : mu_(mu) { >+ this->mu_->Lock(); >+ } >+ ~ReleasableMutexLock() UNLOCK_FUNCTION() { >+ if (this->mu_ != nullptr) { this->mu_->Unlock(); } >+ } >+ >+ void Release() UNLOCK_FUNCTION(); >+ >+ private: >+ Mutex *mu_; >+ ReleasableMutexLock(const ReleasableMutexLock&) = delete; >+ ReleasableMutexLock(ReleasableMutexLock&&) = delete; >+ ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete; >+ ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete; >+}; >+ >+#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX >+#else >+inline Mutex::Mutex() : mu_(0) { >+ ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); >+} >+ >+inline CondVar::CondVar() : cv_(0) {} >+#endif >+ >+// static >+template <typename T> >+bool Condition::CastAndCallMethod(const Condition *c) { >+ typedef bool (T::*MemberType)(); >+ MemberType rm = reinterpret_cast<MemberType>(c->method_); >+ T *x = static_cast<T *>(c->arg_); >+ return (x->*rm)(); >+} >+ >+// static >+template <typename T> >+bool Condition::CastAndCallFunction(const Condition *c) { >+ typedef bool (*FuncType)(T *); >+ FuncType fn = reinterpret_cast<FuncType>(c->function_); >+ T *x = static_cast<T *>(c->arg_); >+ return (*fn)(x); >+} >+ >+template <typename T> >+inline Condition::Condition(bool (*func)(T *), T *arg) >+ : eval_(&CastAndCallFunction<T>), >+ function_(reinterpret_cast<InternalFunctionType>(func)), >+ method_(nullptr), >+ arg_(const_cast<void *>(static_cast<const void *>(arg))) {} >+ >+template <typename T> >+inline Condition::Condition(T *object, >+ bool (absl::internal::identity<T>::type::*method)()) >+ : eval_(&CastAndCallMethod<T>), >+ function_(nullptr), >+ method_(reinterpret_cast<InternalMethodType>(method)), >+ arg_(object) {} >+ >+template <typename T> >+inline Condition::Condition(const T *object, >+ bool (absl::internal::identity<T>::type::*method)() >+ const) >+ : eval_(&CastAndCallMethod<T>), >+ function_(nullptr), >+ method_(reinterpret_cast<InternalMethodType>(method)), >+ arg_(reinterpret_cast<void *>(const_cast<T *>(object))) {} >+ >+// Register a hook for profiling support. >+// >+// The function pointer registered here will be called whenever a mutex is >+// contended. The callback is given the absl/base/cycleclock.h timestamp when >+// waiting began. >+// >+// Calls to this function do not race or block, but there is no ordering >+// guaranteed between calls to this function and call to the provided hook. >+// In particular, the previously registered hook may still be called for some >+// time after this function returns. >+void RegisterMutexProfiler(void (*fn)(int64_t wait_timestamp)); >+ >+// Register a hook for Mutex tracing. >+// >+// The function pointer registered here will be called whenever a mutex is >+// contended. The callback is given an opaque handle to the contended mutex, >+// an event name, and the number of wait cycles (as measured by >+// //absl/base/internal/cycleclock.h, and which may not be real >+// "cycle" counts.) >+// >+// The only event name currently sent is "slow release". >+// >+// This has the same memory ordering concerns as RegisterMutexProfiler() above. >+void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj, >+ int64_t wait_cycles)); >+ >+// TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer() >+// into a single interface, since they are only ever called in pairs. >+ >+// Register a hook for CondVar tracing. >+// >+// The function pointer registered here will be called here on various CondVar >+// events. The callback is given an opaque handle to the CondVar object and >+// a std::string identifying the event. This is thread-safe, but only a single >+// tracer can be registered. >+// >+// Events that can be sent are "Wait", "Unwait", "Signal wakeup", and >+// "SignalAll wakeup". >+// >+// This has the same memory ordering concerns as RegisterMutexProfiler() above. >+void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv)); >+ >+// Register a hook for symbolizing stack traces in deadlock detector reports. >+// >+// 'pc' is the program counter being symbolized, 'out' is the buffer to write >+// into, and 'out_size' is the size of the buffer. This function can return >+// false if symbolizing failed, or true if a null-terminated symbol was written >+// to 'out.' >+// >+// This has the same memory ordering concerns as RegisterMutexProfiler() above. >+// >+// DEPRECATED: The default symbolizer function is absl::Symbolize() and the >+// ability to register a different hook for symbolizing stack traces will be >+// removed on or after 2023-05-01. >+ABSL_DEPRECATED("absl::RegisterSymbolizer() is deprecated and will be removed " >+ "on or after 2023-05-01") >+void RegisterSymbolizer(bool (*fn)(const void *pc, char *out, int out_size)); >+ >+// EnableMutexInvariantDebugging() >+// >+// Enable or disable global support for Mutex invariant debugging. If enabled, >+// then invariant predicates can be registered per-Mutex for debug checking. >+// See Mutex::EnableInvariantDebugging(). >+void EnableMutexInvariantDebugging(bool enabled); >+ >+// When in debug mode, and when the feature has been enabled globally, the >+// implementation will keep track of lock ordering and complain (or optionally >+// crash) if a cycle is detected in the acquired-before graph. >+ >+// Possible modes of operation for the deadlock detector in debug mode. >+enum class OnDeadlockCycle { >+ kIgnore, // Neither report on nor attempt to track cycles in lock ordering >+ kReport, // Report lock cycles to stderr when detected >+ kAbort, // Report lock cycles to stderr when detected, then abort >+}; >+ >+// SetMutexDeadlockDetectionMode() >+// >+// Enable or disable global support for detection of potential deadlocks >+// due to Mutex lock ordering inversions. When set to 'kIgnore', tracking of >+// lock ordering is disabled. Otherwise, in debug builds, a lock ordering graph >+// will be maintained internally, and detected cycles will be reported in >+// the manner chosen here. >+void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode); >+ >+} // namespace absl >+ >+// In some build configurations we pass --detect-odr-violations to the >+// gold linker. This causes it to flag weak symbol overrides as ODR >+// violations. Because ODR only applies to C++ and not C, >+// --detect-odr-violations ignores symbols not mangled with C++ names. >+// By changing our extension points to be extern "C", we dodge this >+// check. >+extern "C" { >+void AbslInternalMutexYield(); >+} // extern "C" >+#endif // ABSL_SYNCHRONIZATION_MUTEX_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc >new file mode 100644 >index 00000000000..1e019e001ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_benchmark.cc >@@ -0,0 +1,94 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/base/internal/sysinfo.h" >+#include "absl/synchronization/blocking_counter.h" >+#include "absl/synchronization/internal/thread_pool.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace { >+ >+// Measure the overhead of conditions on mutex release (when they must be >+// evaluated). Mutex has (some) support for equivalence classes allowing >+// Conditions with the same function/argument to potentially not be multiply >+// evaluated. >+// >+// num_classes==0 is used for the special case of every waiter being distinct. >+void BM_ConditionWaiters(benchmark::State& state) { >+ int num_classes = state.range(0); >+ int num_waiters = state.range(1); >+ >+ struct Helper { >+ static void Waiter(absl::BlockingCounter* init, absl::Mutex* m, int* p) { >+ init->DecrementCount(); >+ m->LockWhen(absl::Condition( >+ static_cast<bool (*)(int*)>([](int* v) { return *v == 0; }), p)); >+ m->Unlock(); >+ } >+ }; >+ >+ if (num_classes == 0) { >+ // No equivalence classes. >+ num_classes = num_waiters; >+ } >+ >+ absl::BlockingCounter init(num_waiters); >+ absl::Mutex mu; >+ std::vector<int> equivalence_classes(num_classes, 1); >+ >+ // Must be declared last to be destroyed first. >+ absl::synchronization_internal::ThreadPool pool(num_waiters); >+ >+ for (int i = 0; i < num_waiters; i++) { >+ // Mutex considers Conditions with the same function and argument >+ // to be equivalent. >+ pool.Schedule([&, i] { >+ Helper::Waiter(&init, &mu, &equivalence_classes[i % num_classes]); >+ }); >+ } >+ init.Wait(); >+ >+ for (auto _ : state) { >+ mu.Lock(); >+ mu.Unlock(); // Each unlock requires Condition evaluation for our waiters. >+ } >+ >+ mu.Lock(); >+ for (int i = 0; i < num_classes; i++) { >+ equivalence_classes[i] = 0; >+ } >+ mu.Unlock(); >+} >+ >+// Some configurations have higher thread limits than others. >+#if defined(__linux__) && !defined(THREAD_SANITIZER) >+constexpr int kMaxConditionWaiters = 8192; >+#else >+constexpr int kMaxConditionWaiters = 1024; >+#endif >+BENCHMARK(BM_ConditionWaiters)->RangePair(0, 2, 1, kMaxConditionWaiters); >+ >+void BM_ContendedMutex(benchmark::State& state) { >+ static absl::Mutex* mu = new absl::Mutex; >+ for (auto _ : state) { >+ absl::MutexLock lock(mu); >+ } >+} >+BENCHMARK(BM_ContendedMutex)->Threads(1); >+BENCHMARK(BM_ContendedMutex)->ThreadPerCpu(); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_test.cc >new file mode 100644 >index 00000000000..b2820e2068d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/mutex_test.cc >@@ -0,0 +1,1660 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/mutex.h" >+ >+#ifdef WIN32 >+#include <windows.h> >+#endif >+ >+#include <algorithm> >+#include <atomic> >+#include <cstdlib> >+#include <functional> >+#include <memory> >+#include <random> >+#include <string> >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/base/internal/sysinfo.h" >+#include "absl/memory/memory.h" >+#include "absl/synchronization/internal/thread_pool.h" >+#include "absl/time/clock.h" >+#include "absl/time/time.h" >+ >+namespace { >+ >+// TODO(dmauro): Replace with a commandline flag. >+static constexpr bool kExtendedTest = false; >+ >+std::unique_ptr<absl::synchronization_internal::ThreadPool> CreatePool( >+ int threads) { >+ return absl::make_unique<absl::synchronization_internal::ThreadPool>(threads); >+} >+ >+std::unique_ptr<absl::synchronization_internal::ThreadPool> >+CreateDefaultPool() { >+ return CreatePool(kExtendedTest ? 32 : 10); >+} >+ >+// Hack to schedule a function to run on a thread pool thread after a >+// duration has elapsed. >+static void ScheduleAfter(absl::synchronization_internal::ThreadPool *tp, >+ absl::Duration after, >+ const std::function<void()> &func) { >+ tp->Schedule([func, after] { >+ absl::SleepFor(after); >+ func(); >+ }); >+} >+ >+struct TestContext { >+ int iterations; >+ int threads; >+ int g0; // global 0 >+ int g1; // global 1 >+ absl::Mutex mu; >+ absl::CondVar cv; >+}; >+ >+// To test whether the invariant check call occurs >+static std::atomic<bool> invariant_checked; >+ >+static bool GetInvariantChecked() { >+ return invariant_checked.load(std::memory_order_relaxed); >+} >+ >+static void SetInvariantChecked(bool new_value) { >+ invariant_checked.store(new_value, std::memory_order_relaxed); >+} >+ >+static void CheckSumG0G1(void *v) { >+ TestContext *cxt = static_cast<TestContext *>(v); >+ ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in CheckSumG0G1"); >+ SetInvariantChecked(true); >+} >+ >+static void TestMu(TestContext *cxt, int c) { >+ for (int i = 0; i != cxt->iterations; i++) { >+ absl::MutexLock l(&cxt->mu); >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ cxt->g1--; >+ } >+} >+ >+static void TestTry(TestContext *cxt, int c) { >+ for (int i = 0; i != cxt->iterations; i++) { >+ do { >+ std::this_thread::yield(); >+ } while (!cxt->mu.TryLock()); >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ cxt->g1--; >+ cxt->mu.Unlock(); >+ } >+} >+ >+static void TestR20ms(TestContext *cxt, int c) { >+ for (int i = 0; i != cxt->iterations; i++) { >+ absl::ReaderMutexLock l(&cxt->mu); >+ absl::SleepFor(absl::Milliseconds(20)); >+ cxt->mu.AssertReaderHeld(); >+ } >+} >+ >+static void TestRW(TestContext *cxt, int c) { >+ if ((c & 1) == 0) { >+ for (int i = 0; i != cxt->iterations; i++) { >+ absl::WriterMutexLock l(&cxt->mu); >+ cxt->g0++; >+ cxt->g1--; >+ cxt->mu.AssertHeld(); >+ cxt->mu.AssertReaderHeld(); >+ } >+ } else { >+ for (int i = 0; i != cxt->iterations; i++) { >+ absl::ReaderMutexLock l(&cxt->mu); >+ ABSL_RAW_CHECK(cxt->g0 == -cxt->g1, "Error in TestRW"); >+ cxt->mu.AssertReaderHeld(); >+ } >+ } >+} >+ >+struct MyContext { >+ int target; >+ TestContext *cxt; >+ bool MyTurn(); >+}; >+ >+bool MyContext::MyTurn() { >+ TestContext *cxt = this->cxt; >+ return cxt->g0 == this->target || cxt->g0 == cxt->iterations; >+} >+ >+static void TestAwait(TestContext *cxt, int c) { >+ MyContext mc; >+ mc.target = c; >+ mc.cxt = cxt; >+ absl::MutexLock l(&cxt->mu); >+ cxt->mu.AssertHeld(); >+ while (cxt->g0 < cxt->iterations) { >+ cxt->mu.Await(absl::Condition(&mc, &MyContext::MyTurn)); >+ ABSL_RAW_CHECK(mc.MyTurn(), "Error in TestAwait"); >+ cxt->mu.AssertHeld(); >+ if (cxt->g0 < cxt->iterations) { >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ mc.target += cxt->threads; >+ } >+ } >+} >+ >+static void TestSignalAll(TestContext *cxt, int c) { >+ int target = c; >+ absl::MutexLock l(&cxt->mu); >+ cxt->mu.AssertHeld(); >+ while (cxt->g0 < cxt->iterations) { >+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) { >+ cxt->cv.Wait(&cxt->mu); >+ } >+ if (cxt->g0 < cxt->iterations) { >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ cxt->cv.SignalAll(); >+ target += cxt->threads; >+ } >+ } >+} >+ >+static void TestSignal(TestContext *cxt, int c) { >+ ABSL_RAW_CHECK(cxt->threads == 2, "TestSignal should use 2 threads"); >+ int target = c; >+ absl::MutexLock l(&cxt->mu); >+ cxt->mu.AssertHeld(); >+ while (cxt->g0 < cxt->iterations) { >+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) { >+ cxt->cv.Wait(&cxt->mu); >+ } >+ if (cxt->g0 < cxt->iterations) { >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ cxt->cv.Signal(); >+ target += cxt->threads; >+ } >+ } >+} >+ >+static void TestCVTimeout(TestContext *cxt, int c) { >+ int target = c; >+ absl::MutexLock l(&cxt->mu); >+ cxt->mu.AssertHeld(); >+ while (cxt->g0 < cxt->iterations) { >+ while (cxt->g0 != target && cxt->g0 != cxt->iterations) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100)); >+ } >+ if (cxt->g0 < cxt->iterations) { >+ int a = cxt->g0 + 1; >+ cxt->g0 = a; >+ cxt->cv.SignalAll(); >+ target += cxt->threads; >+ } >+ } >+} >+ >+static bool G0GE2(TestContext *cxt) { return cxt->g0 >= 2; } >+ >+static void TestTime(TestContext *cxt, int c, bool use_cv) { >+ ABSL_RAW_CHECK(cxt->iterations == 1, "TestTime should only use 1 iteration"); >+ ABSL_RAW_CHECK(cxt->threads > 2, "TestTime should use more than 2 threads"); >+ const bool kFalse = false; >+ absl::Condition false_cond(&kFalse); >+ absl::Condition g0ge2(G0GE2, cxt); >+ if (c == 0) { >+ absl::MutexLock l(&cxt->mu); >+ >+ absl::Time start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); >+ } else { >+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), >+ "TestTime failed"); >+ } >+ absl::Duration elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK( >+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), >+ "TestTime failed"); >+ ABSL_RAW_CHECK(cxt->g0 == 1, "TestTime failed"); >+ >+ start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); >+ } else { >+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), >+ "TestTime failed"); >+ } >+ elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK( >+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), >+ "TestTime failed"); >+ cxt->g0++; >+ if (use_cv) { >+ cxt->cv.Signal(); >+ } >+ >+ start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(4)); >+ } else { >+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(4)), >+ "TestTime failed"); >+ } >+ elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK( >+ absl::Seconds(3.9) <= elapsed && elapsed <= absl::Seconds(6.0), >+ "TestTime failed"); >+ ABSL_RAW_CHECK(cxt->g0 >= 3, "TestTime failed"); >+ >+ start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); >+ } else { >+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), >+ "TestTime failed"); >+ } >+ elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK( >+ absl::Seconds(0.9) <= elapsed && elapsed <= absl::Seconds(2.0), >+ "TestTime failed"); >+ if (use_cv) { >+ cxt->cv.SignalAll(); >+ } >+ >+ start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(1)); >+ } else { >+ ABSL_RAW_CHECK(!cxt->mu.AwaitWithTimeout(false_cond, absl::Seconds(1)), >+ "TestTime failed"); >+ } >+ elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK(absl::Seconds(0.9) <= elapsed && >+ elapsed <= absl::Seconds(2.0), "TestTime failed"); >+ ABSL_RAW_CHECK(cxt->g0 == cxt->threads, "TestTime failed"); >+ >+ } else if (c == 1) { >+ absl::MutexLock l(&cxt->mu); >+ const absl::Time start = absl::Now(); >+ if (use_cv) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Milliseconds(500)); >+ } else { >+ ABSL_RAW_CHECK( >+ !cxt->mu.AwaitWithTimeout(false_cond, absl::Milliseconds(500)), >+ "TestTime failed"); >+ } >+ const absl::Duration elapsed = absl::Now() - start; >+ ABSL_RAW_CHECK( >+ absl::Seconds(0.4) <= elapsed && elapsed <= absl::Seconds(0.9), >+ "TestTime failed"); >+ cxt->g0++; >+ } else if (c == 2) { >+ absl::MutexLock l(&cxt->mu); >+ if (use_cv) { >+ while (cxt->g0 < 2) { >+ cxt->cv.WaitWithTimeout(&cxt->mu, absl::Seconds(100)); >+ } >+ } else { >+ ABSL_RAW_CHECK(cxt->mu.AwaitWithTimeout(g0ge2, absl::Seconds(100)), >+ "TestTime failed"); >+ } >+ cxt->g0++; >+ } else { >+ absl::MutexLock l(&cxt->mu); >+ if (use_cv) { >+ while (cxt->g0 < 2) { >+ cxt->cv.Wait(&cxt->mu); >+ } >+ } else { >+ cxt->mu.Await(g0ge2); >+ } >+ cxt->g0++; >+ } >+} >+ >+static void TestMuTime(TestContext *cxt, int c) { TestTime(cxt, c, false); } >+ >+static void TestCVTime(TestContext *cxt, int c) { TestTime(cxt, c, true); } >+ >+static void EndTest(int *c0, int *c1, absl::Mutex *mu, absl::CondVar *cv, >+ const std::function<void(int)>& cb) { >+ mu->Lock(); >+ int c = (*c0)++; >+ mu->Unlock(); >+ cb(c); >+ absl::MutexLock l(mu); >+ (*c1)++; >+ cv->Signal(); >+} >+ >+// Code common to RunTest() and RunTestWithInvariantDebugging(). >+static int RunTestCommon(TestContext *cxt, void (*test)(TestContext *cxt, int), >+ int threads, int iterations, int operations) { >+ absl::Mutex mu2; >+ absl::CondVar cv2; >+ int c0 = 0; >+ int c1 = 0; >+ cxt->g0 = 0; >+ cxt->g1 = 0; >+ cxt->iterations = iterations; >+ cxt->threads = threads; >+ absl::synchronization_internal::ThreadPool tp(threads); >+ for (int i = 0; i != threads; i++) { >+ tp.Schedule(std::bind(&EndTest, &c0, &c1, &mu2, &cv2, >+ std::function<void(int)>( >+ std::bind(test, cxt, std::placeholders::_1)))); >+ } >+ mu2.Lock(); >+ while (c1 != threads) { >+ cv2.Wait(&mu2); >+ } >+ mu2.Unlock(); >+ return cxt->g0; >+} >+ >+// Basis for the parameterized tests configured below. >+static int RunTest(void (*test)(TestContext *cxt, int), int threads, >+ int iterations, int operations) { >+ TestContext cxt; >+ return RunTestCommon(&cxt, test, threads, iterations, operations); >+} >+ >+// Like RunTest(), but sets an invariant on the tested Mutex and >+// verifies that the invariant check happened. The invariant function >+// will be passed the TestContext* as its arg and must call >+// SetInvariantChecked(true); >+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED) >+static int RunTestWithInvariantDebugging(void (*test)(TestContext *cxt, int), >+ int threads, int iterations, >+ int operations, >+ void (*invariant)(void *)) { >+ absl::EnableMutexInvariantDebugging(true); >+ SetInvariantChecked(false); >+ TestContext cxt; >+ cxt.mu.EnableInvariantDebugging(invariant, &cxt); >+ int ret = RunTestCommon(&cxt, test, threads, iterations, operations); >+ ABSL_RAW_CHECK(GetInvariantChecked(), "Invariant not checked"); >+ absl::EnableMutexInvariantDebugging(false); // Restore. >+ return ret; >+} >+#endif >+ >+// -------------------------------------------------------- >+// Test for fix of bug in TryRemove() >+struct TimeoutBugStruct { >+ absl::Mutex mu; >+ bool a; >+ int a_waiter_count; >+}; >+ >+static void WaitForA(TimeoutBugStruct *x) { >+ x->mu.LockWhen(absl::Condition(&x->a)); >+ x->a_waiter_count--; >+ x->mu.Unlock(); >+} >+ >+static bool NoAWaiters(TimeoutBugStruct *x) { return x->a_waiter_count == 0; } >+ >+// Test that a CondVar.Wait(&mutex) can un-block a call to mutex.Await() in >+// another thread. >+TEST(Mutex, CondVarWaitSignalsAwait) { >+ // Use a struct so the lock annotations apply. >+ struct { >+ absl::Mutex barrier_mu; >+ bool barrier GUARDED_BY(barrier_mu) = false; >+ >+ absl::Mutex release_mu; >+ bool release GUARDED_BY(release_mu) = false; >+ absl::CondVar released_cv; >+ } state; >+ >+ auto pool = CreateDefaultPool(); >+ >+ // Thread A. Sets barrier, waits for release using Mutex::Await, then >+ // signals released_cv. >+ pool->Schedule([&state] { >+ state.release_mu.Lock(); >+ >+ state.barrier_mu.Lock(); >+ state.barrier = true; >+ state.barrier_mu.Unlock(); >+ >+ state.release_mu.Await(absl::Condition(&state.release)); >+ state.released_cv.Signal(); >+ state.release_mu.Unlock(); >+ }); >+ >+ state.barrier_mu.LockWhen(absl::Condition(&state.barrier)); >+ state.barrier_mu.Unlock(); >+ state.release_mu.Lock(); >+ // Thread A is now blocked on release by way of Mutex::Await(). >+ >+ // Set release. Calling released_cv.Wait() should un-block thread A, >+ // which will signal released_cv. If not, the test will hang. >+ state.release = true; >+ state.released_cv.Wait(&state.release_mu); >+ state.release_mu.Unlock(); >+} >+ >+// Test that a CondVar.WaitWithTimeout(&mutex) can un-block a call to >+// mutex.Await() in another thread. >+TEST(Mutex, CondVarWaitWithTimeoutSignalsAwait) { >+ // Use a struct so the lock annotations apply. >+ struct { >+ absl::Mutex barrier_mu; >+ bool barrier GUARDED_BY(barrier_mu) = false; >+ >+ absl::Mutex release_mu; >+ bool release GUARDED_BY(release_mu) = false; >+ absl::CondVar released_cv; >+ } state; >+ >+ auto pool = CreateDefaultPool(); >+ >+ // Thread A. Sets barrier, waits for release using Mutex::Await, then >+ // signals released_cv. >+ pool->Schedule([&state] { >+ state.release_mu.Lock(); >+ >+ state.barrier_mu.Lock(); >+ state.barrier = true; >+ state.barrier_mu.Unlock(); >+ >+ state.release_mu.Await(absl::Condition(&state.release)); >+ state.released_cv.Signal(); >+ state.release_mu.Unlock(); >+ }); >+ >+ state.barrier_mu.LockWhen(absl::Condition(&state.barrier)); >+ state.barrier_mu.Unlock(); >+ state.release_mu.Lock(); >+ // Thread A is now blocked on release by way of Mutex::Await(). >+ >+ // Set release. Calling released_cv.Wait() should un-block thread A, >+ // which will signal released_cv. If not, the test will hang. >+ state.release = true; >+ EXPECT_TRUE( >+ !state.released_cv.WaitWithTimeout(&state.release_mu, absl::Seconds(10))) >+ << "; Unrecoverable test failure: CondVar::WaitWithTimeout did not " >+ "unblock the absl::Mutex::Await call in another thread."; >+ >+ state.release_mu.Unlock(); >+} >+ >+// Test for regression of a bug in loop of TryRemove() >+TEST(Mutex, MutexTimeoutBug) { >+ auto tp = CreateDefaultPool(); >+ >+ TimeoutBugStruct x; >+ x.a = false; >+ x.a_waiter_count = 2; >+ tp->Schedule(std::bind(&WaitForA, &x)); >+ tp->Schedule(std::bind(&WaitForA, &x)); >+ absl::SleepFor(absl::Seconds(1)); // Allow first two threads to hang. >+ // The skip field of the second will point to the first because there are >+ // only two. >+ >+ // Now cause a thread waiting on an always-false to time out >+ // This would deadlock when the bug was present. >+ bool always_false = false; >+ x.mu.LockWhenWithTimeout(absl::Condition(&always_false), >+ absl::Milliseconds(500)); >+ >+ // if we get here, the bug is not present. Cleanup the state. >+ >+ x.a = true; // wakeup the two waiters on A >+ x.mu.Await(absl::Condition(&NoAWaiters, &x)); // wait for them to exit >+ x.mu.Unlock(); >+} >+ >+struct CondVarWaitDeadlock : testing::TestWithParam<int> { >+ absl::Mutex mu; >+ absl::CondVar cv; >+ bool cond1 = false; >+ bool cond2 = false; >+ bool read_lock1; >+ bool read_lock2; >+ bool signal_unlocked; >+ >+ CondVarWaitDeadlock() { >+ read_lock1 = GetParam() & (1 << 0); >+ read_lock2 = GetParam() & (1 << 1); >+ signal_unlocked = GetParam() & (1 << 2); >+ } >+ >+ void Waiter1() { >+ if (read_lock1) { >+ mu.ReaderLock(); >+ while (!cond1) { >+ cv.Wait(&mu); >+ } >+ mu.ReaderUnlock(); >+ } else { >+ mu.Lock(); >+ while (!cond1) { >+ cv.Wait(&mu); >+ } >+ mu.Unlock(); >+ } >+ } >+ >+ void Waiter2() { >+ if (read_lock2) { >+ mu.ReaderLockWhen(absl::Condition(&cond2)); >+ mu.ReaderUnlock(); >+ } else { >+ mu.LockWhen(absl::Condition(&cond2)); >+ mu.Unlock(); >+ } >+ } >+}; >+ >+// Test for a deadlock bug in Mutex::Fer(). >+// The sequence of events that lead to the deadlock is: >+// 1. waiter1 blocks on cv in read mode (mu bits = 0). >+// 2. waiter2 blocks on mu in either mode (mu bits = kMuWait). >+// 3. main thread locks mu, sets cond1, unlocks mu (mu bits = kMuWait). >+// 4. main thread signals on cv and this eventually calls Mutex::Fer(). >+// Currently Fer wakes waiter1 since mu bits = kMuWait (mutex is unlocked). >+// Before the bug fix Fer neither woke waiter1 nor queued it on mutex, >+// which resulted in deadlock. >+TEST_P(CondVarWaitDeadlock, Test) { >+ auto waiter1 = CreatePool(1); >+ auto waiter2 = CreatePool(1); >+ waiter1->Schedule([this] { this->Waiter1(); }); >+ waiter2->Schedule([this] { this->Waiter2(); }); >+ >+ // Wait while threads block (best-effort is fine). >+ absl::SleepFor(absl::Milliseconds(100)); >+ >+ // Wake condwaiter. >+ mu.Lock(); >+ cond1 = true; >+ if (signal_unlocked) { >+ mu.Unlock(); >+ cv.Signal(); >+ } else { >+ cv.Signal(); >+ mu.Unlock(); >+ } >+ waiter1.reset(); // "join" waiter1 >+ >+ // Wake waiter. >+ mu.Lock(); >+ cond2 = true; >+ mu.Unlock(); >+ waiter2.reset(); // "join" waiter2 >+} >+ >+INSTANTIATE_TEST_CASE_P(CondVarWaitDeadlockTest, CondVarWaitDeadlock, >+ ::testing::Range(0, 8), >+ ::testing::PrintToStringParamName()); >+ >+// -------------------------------------------------------- >+// Test for fix of bug in DequeueAllWakeable() >+// Bug was that if there was more than one waiting reader >+// and all should be woken, the most recently blocked one >+// would not be. >+ >+struct DequeueAllWakeableBugStruct { >+ absl::Mutex mu; >+ absl::Mutex mu2; // protects all fields below >+ int unfinished_count; // count of unfinished readers; under mu2 >+ bool done1; // unfinished_count == 0; under mu2 >+ int finished_count; // count of finished readers, under mu2 >+ bool done2; // finished_count == 0; under mu2 >+}; >+ >+// Test for regression of a bug in loop of DequeueAllWakeable() >+static void AcquireAsReader(DequeueAllWakeableBugStruct *x) { >+ x->mu.ReaderLock(); >+ x->mu2.Lock(); >+ x->unfinished_count--; >+ x->done1 = (x->unfinished_count == 0); >+ x->mu2.Unlock(); >+ // make sure that both readers acquired mu before we release it. >+ absl::SleepFor(absl::Seconds(2)); >+ x->mu.ReaderUnlock(); >+ >+ x->mu2.Lock(); >+ x->finished_count--; >+ x->done2 = (x->finished_count == 0); >+ x->mu2.Unlock(); >+} >+ >+// Test for regression of a bug in loop of DequeueAllWakeable() >+TEST(Mutex, MutexReaderWakeupBug) { >+ auto tp = CreateDefaultPool(); >+ >+ DequeueAllWakeableBugStruct x; >+ x.unfinished_count = 2; >+ x.done1 = false; >+ x.finished_count = 2; >+ x.done2 = false; >+ x.mu.Lock(); // acquire mu exclusively >+ // queue two thread that will block on reader locks on x.mu >+ tp->Schedule(std::bind(&AcquireAsReader, &x)); >+ tp->Schedule(std::bind(&AcquireAsReader, &x)); >+ absl::SleepFor(absl::Seconds(1)); // give time for reader threads to block >+ x.mu.Unlock(); // wake them up >+ >+ // both readers should finish promptly >+ EXPECT_TRUE( >+ x.mu2.LockWhenWithTimeout(absl::Condition(&x.done1), absl::Seconds(10))); >+ x.mu2.Unlock(); >+ >+ EXPECT_TRUE( >+ x.mu2.LockWhenWithTimeout(absl::Condition(&x.done2), absl::Seconds(10))); >+ x.mu2.Unlock(); >+} >+ >+struct LockWhenTestStruct { >+ absl::Mutex mu1; >+ bool cond = false; >+ >+ absl::Mutex mu2; >+ bool waiting = false; >+}; >+ >+static bool LockWhenTestIsCond(LockWhenTestStruct* s) { >+ s->mu2.Lock(); >+ s->waiting = true; >+ s->mu2.Unlock(); >+ return s->cond; >+} >+ >+static void LockWhenTestWaitForIsCond(LockWhenTestStruct* s) { >+ s->mu1.LockWhen(absl::Condition(&LockWhenTestIsCond, s)); >+ s->mu1.Unlock(); >+} >+ >+TEST(Mutex, LockWhen) { >+ LockWhenTestStruct s; >+ >+ std::thread t(LockWhenTestWaitForIsCond, &s); >+ s.mu2.LockWhen(absl::Condition(&s.waiting)); >+ s.mu2.Unlock(); >+ >+ s.mu1.Lock(); >+ s.cond = true; >+ s.mu1.Unlock(); >+ >+ t.join(); >+} >+ >+// -------------------------------------------------------- >+// The following test requires Mutex::ReaderLock to be a real shared >+// lock, which is not the case in all builds. >+#if !defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE) >+ >+// Test for fix of bug in UnlockSlow() that incorrectly decremented the reader >+// count when putting a thread to sleep waiting for a false condition when the >+// lock was not held. >+ >+// For this bug to strike, we make a thread wait on a free mutex with no >+// waiters by causing its wakeup condition to be false. Then the >+// next two acquirers must be readers. The bug causes the lock >+// to be released when one reader unlocks, rather than both. >+ >+struct ReaderDecrementBugStruct { >+ bool cond; // to delay first thread (under mu) >+ int done; // reference count (under mu) >+ absl::Mutex mu; >+ >+ bool waiting_on_cond; // under mu2 >+ bool have_reader_lock; // under mu2 >+ bool complete; // under mu2 >+ absl::Mutex mu2; // > mu >+}; >+ >+// L >= mu, L < mu_waiting_on_cond >+static bool IsCond(void *v) { >+ ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v); >+ x->mu2.Lock(); >+ x->waiting_on_cond = true; >+ x->mu2.Unlock(); >+ return x->cond; >+} >+ >+// L >= mu >+static bool AllDone(void *v) { >+ ReaderDecrementBugStruct *x = reinterpret_cast<ReaderDecrementBugStruct *>(v); >+ return x->done == 0; >+} >+ >+// L={} >+static void WaitForCond(ReaderDecrementBugStruct *x) { >+ absl::Mutex dummy; >+ absl::MutexLock l(&dummy); >+ x->mu.LockWhen(absl::Condition(&IsCond, x)); >+ x->done--; >+ x->mu.Unlock(); >+} >+ >+// L={} >+static void GetReadLock(ReaderDecrementBugStruct *x) { >+ x->mu.ReaderLock(); >+ x->mu2.Lock(); >+ x->have_reader_lock = true; >+ x->mu2.Await(absl::Condition(&x->complete)); >+ x->mu2.Unlock(); >+ x->mu.ReaderUnlock(); >+ x->mu.Lock(); >+ x->done--; >+ x->mu.Unlock(); >+} >+ >+// Test for reader counter being decremented incorrectly by waiter >+// with false condition. >+TEST(Mutex, MutexReaderDecrementBug) NO_THREAD_SAFETY_ANALYSIS { >+ ReaderDecrementBugStruct x; >+ x.cond = false; >+ x.waiting_on_cond = false; >+ x.have_reader_lock = false; >+ x.complete = false; >+ x.done = 2; // initial ref count >+ >+ // Run WaitForCond() and wait for it to sleep >+ std::thread thread1(WaitForCond, &x); >+ x.mu2.LockWhen(absl::Condition(&x.waiting_on_cond)); >+ x.mu2.Unlock(); >+ >+ // Run GetReadLock(), and wait for it to get the read lock >+ std::thread thread2(GetReadLock, &x); >+ x.mu2.LockWhen(absl::Condition(&x.have_reader_lock)); >+ x.mu2.Unlock(); >+ >+ // Get the reader lock ourselves, and release it. >+ x.mu.ReaderLock(); >+ x.mu.ReaderUnlock(); >+ >+ // The lock should be held in read mode by GetReadLock(). >+ // If we have the bug, the lock will be free. >+ x.mu.AssertReaderHeld(); >+ >+ // Wake up all the threads. >+ x.mu2.Lock(); >+ x.complete = true; >+ x.mu2.Unlock(); >+ >+ // TODO(delesley): turn on analysis once lock upgrading is supported. >+ // (This call upgrades the lock from shared to exclusive.) >+ x.mu.Lock(); >+ x.cond = true; >+ x.mu.Await(absl::Condition(&AllDone, &x)); >+ x.mu.Unlock(); >+ >+ thread1.join(); >+ thread2.join(); >+} >+#endif // !ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE >+ >+// Test that we correctly handle the situation when a lock is >+// held and then destroyed (w/o unlocking). >+TEST(Mutex, LockedMutexDestructionBug) NO_THREAD_SAFETY_ANALYSIS { >+ for (int i = 0; i != 10; i++) { >+ // Create, lock and destroy 10 locks. >+ const int kNumLocks = 10; >+ auto mu = absl::make_unique<absl::Mutex[]>(kNumLocks); >+ for (int j = 0; j != kNumLocks; j++) { >+ if ((j % 2) == 0) { >+ mu[j].WriterLock(); >+ } else { >+ mu[j].ReaderLock(); >+ } >+ } >+ } >+} >+ >+// -------------------------------------------------------- >+// Test for bug with pattern of readers using a condvar. The bug was that if a >+// reader went to sleep on a condition variable while one or more other readers >+// held the lock, but there were no waiters, the reader count (held in the >+// mutex word) would be lost. (This is because Enqueue() had at one time >+// always placed the thread on the Mutex queue. Later (CL 4075610), to >+// tolerate re-entry into Mutex from a Condition predicate, Enqueue() was >+// changed so that it could also place a thread on a condition-variable. This >+// introduced the case where Enqueue() returned with an empty queue, and this >+// case was handled incorrectly in one place.) >+ >+static void ReaderForReaderOnCondVar(absl::Mutex *mu, absl::CondVar *cv, >+ int *running) { >+ std::random_device dev; >+ std::mt19937 gen(dev()); >+ std::uniform_int_distribution<int> random_millis(0, 15); >+ mu->ReaderLock(); >+ while (*running == 3) { >+ absl::SleepFor(absl::Milliseconds(random_millis(gen))); >+ cv->WaitWithTimeout(mu, absl::Milliseconds(random_millis(gen))); >+ } >+ mu->ReaderUnlock(); >+ mu->Lock(); >+ (*running)--; >+ mu->Unlock(); >+} >+ >+struct True { >+ template <class... Args> >+ bool operator()(Args...) const { >+ return true; >+ } >+}; >+ >+struct DerivedTrue : True {}; >+ >+TEST(Mutex, FunctorCondition) { >+ { // Variadic >+ True f; >+ EXPECT_TRUE(absl::Condition(&f).Eval()); >+ } >+ >+ { // Inherited >+ DerivedTrue g; >+ EXPECT_TRUE(absl::Condition(&g).Eval()); >+ } >+ >+ { // lambda >+ int value = 3; >+ auto is_zero = [&value] { return value == 0; }; >+ absl::Condition c(&is_zero); >+ EXPECT_FALSE(c.Eval()); >+ value = 0; >+ EXPECT_TRUE(c.Eval()); >+ } >+ >+ { // bind >+ int value = 0; >+ auto is_positive = std::bind(std::less<int>(), 0, std::cref(value)); >+ absl::Condition c(&is_positive); >+ EXPECT_FALSE(c.Eval()); >+ value = 1; >+ EXPECT_TRUE(c.Eval()); >+ } >+ >+ { // std::function >+ int value = 3; >+ std::function<bool()> is_zero = [&value] { return value == 0; }; >+ absl::Condition c(&is_zero); >+ EXPECT_FALSE(c.Eval()); >+ value = 0; >+ EXPECT_TRUE(c.Eval()); >+ } >+} >+ >+static bool IntIsZero(int *x) { return *x == 0; } >+ >+// Test for reader waiting condition variable when there are other readers >+// but no waiters. >+TEST(Mutex, TestReaderOnCondVar) { >+ auto tp = CreateDefaultPool(); >+ absl::Mutex mu; >+ absl::CondVar cv; >+ int running = 3; >+ tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running)); >+ tp->Schedule(std::bind(&ReaderForReaderOnCondVar, &mu, &cv, &running)); >+ absl::SleepFor(absl::Seconds(2)); >+ mu.Lock(); >+ running--; >+ mu.Await(absl::Condition(&IntIsZero, &running)); >+ mu.Unlock(); >+} >+ >+// -------------------------------------------------------- >+struct AcquireFromConditionStruct { >+ absl::Mutex mu0; // protects value, done >+ int value; // times condition function is called; under mu0, >+ bool done; // done with test? under mu0 >+ absl::Mutex mu1; // used to attempt to mess up state of mu0 >+ absl::CondVar cv; // so the condition function can be invoked from >+ // CondVar::Wait(). >+}; >+ >+static bool ConditionWithAcquire(AcquireFromConditionStruct *x) { >+ x->value++; // count times this function is called >+ >+ if (x->value == 2 || x->value == 3) { >+ // On the second and third invocation of this function, sleep for 100ms, >+ // but with the side-effect of altering the state of a Mutex other than >+ // than one for which this is a condition. The spec now explicitly allows >+ // this side effect; previously it did not. it was illegal. >+ bool always_false = false; >+ x->mu1.LockWhenWithTimeout(absl::Condition(&always_false), >+ absl::Milliseconds(100)); >+ x->mu1.Unlock(); >+ } >+ ABSL_RAW_CHECK(x->value < 4, "should not be invoked a fourth time"); >+ >+ // We arrange for the condition to return true on only the 2nd and 3rd calls. >+ return x->value == 2 || x->value == 3; >+} >+ >+static void WaitForCond2(AcquireFromConditionStruct *x) { >+ // wait for cond0 to become true >+ x->mu0.LockWhen(absl::Condition(&ConditionWithAcquire, x)); >+ x->done = true; >+ x->mu0.Unlock(); >+} >+ >+// Test for Condition whose function acquires other Mutexes >+TEST(Mutex, AcquireFromCondition) { >+ auto tp = CreateDefaultPool(); >+ >+ AcquireFromConditionStruct x; >+ x.value = 0; >+ x.done = false; >+ tp->Schedule( >+ std::bind(&WaitForCond2, &x)); // run WaitForCond2() in a thread T >+ // T will hang because the first invocation of ConditionWithAcquire() will >+ // return false. >+ absl::SleepFor(absl::Milliseconds(500)); // allow T time to hang >+ >+ x.mu0.Lock(); >+ x.cv.WaitWithTimeout(&x.mu0, absl::Milliseconds(500)); // wake T >+ // T will be woken because the Wait() will call ConditionWithAcquire() >+ // for the second time, and it will return true. >+ >+ x.mu0.Unlock(); >+ >+ // T will then acquire the lock and recheck its own condition. >+ // It will find the condition true, as this is the third invocation, >+ // but the use of another Mutex by the calling function will >+ // cause the old mutex implementation to think that the outer >+ // LockWhen() has timed out because the inner LockWhenWithTimeout() did. >+ // T will then check the condition a fourth time because it finds a >+ // timeout occurred. This should not happen in the new >+ // implementation that allows the Condition function to use Mutexes. >+ >+ // It should also succeed, even though the Condition function >+ // is being invoked from CondVar::Wait, and thus this thread >+ // is conceptually waiting both on the condition variable, and on mu2. >+ >+ x.mu0.LockWhen(absl::Condition(&x.done)); >+ x.mu0.Unlock(); >+} >+ >+// The deadlock detector is not part of non-prod builds, so do not test it. >+#if !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX) >+ >+TEST(Mutex, DeadlockDetector) { >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); >+ >+ // check that we can call ForgetDeadlockInfo() on a lock with the lock held >+ absl::Mutex m1; >+ absl::Mutex m2; >+ absl::Mutex m3; >+ absl::Mutex m4; >+ >+ m1.Lock(); // m1 gets ID1 >+ m2.Lock(); // m2 gets ID2 >+ m3.Lock(); // m3 gets ID3 >+ m3.Unlock(); >+ m2.Unlock(); >+ // m1 still held >+ m1.ForgetDeadlockInfo(); // m1 loses ID >+ m2.Lock(); // m2 gets ID2 >+ m3.Lock(); // m3 gets ID3 >+ m4.Lock(); // m4 gets ID4 >+ m3.Unlock(); >+ m2.Unlock(); >+ m4.Unlock(); >+ m1.Unlock(); >+} >+ >+// Bazel has a test "warning" file that programs can write to if the >+// test should pass with a warning. This class disables the warning >+// file until it goes out of scope. >+class ScopedDisableBazelTestWarnings { >+ public: >+ ScopedDisableBazelTestWarnings() { >+#ifdef WIN32 >+ char file[MAX_PATH]; >+ if (GetEnvironmentVariable(kVarName, file, sizeof(file)) < sizeof(file)) { >+ warnings_output_file_ = file; >+ SetEnvironmentVariable(kVarName, nullptr); >+ } >+#else >+ const char *file = getenv(kVarName); >+ if (file != nullptr) { >+ warnings_output_file_ = file; >+ unsetenv(kVarName); >+ } >+#endif >+ } >+ >+ ~ScopedDisableBazelTestWarnings() { >+ if (!warnings_output_file_.empty()) { >+#ifdef WIN32 >+ SetEnvironmentVariable(kVarName, warnings_output_file_.c_str()); >+#else >+ setenv(kVarName, warnings_output_file_.c_str(), 0); >+#endif >+ } >+ } >+ >+ private: >+ static const char kVarName[]; >+ std::string warnings_output_file_; >+}; >+const char ScopedDisableBazelTestWarnings::kVarName[] = >+ "TEST_WARNINGS_OUTPUT_FILE"; >+ >+TEST(Mutex, DeadlockDetectorBazelWarning) { >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport); >+ >+ // Cause deadlock detection to detect something, if it's >+ // compiled in and enabled. But turn off the bazel warning. >+ ScopedDisableBazelTestWarnings disable_bazel_test_warnings; >+ >+ absl::Mutex mu0; >+ absl::Mutex mu1; >+ bool got_mu0 = mu0.TryLock(); >+ mu1.Lock(); // acquire mu1 while holding mu0 >+ if (got_mu0) { >+ mu0.Unlock(); >+ } >+ if (mu0.TryLock()) { // try lock shouldn't cause deadlock detector to fire >+ mu0.Unlock(); >+ } >+ mu0.Lock(); // acquire mu0 while holding mu1; should get one deadlock >+ // report here >+ mu0.Unlock(); >+ mu1.Unlock(); >+ >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); >+} >+ >+// This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the >+// annotation-based static thread-safety analysis is not currently >+// predicate-aware and cannot tell if the two for-loops that acquire and >+// release the locks have the same predicates. >+TEST(Mutex, DeadlockDetectorStessTest) NO_THREAD_SAFETY_ANALYSIS { >+ // Stress test: Here we create a large number of locks and use all of them. >+ // If a deadlock detector keeps a full graph of lock acquisition order, >+ // it will likely be too slow for this test to pass. >+ const int n_locks = 1 << 17; >+ auto array_of_locks = absl::make_unique<absl::Mutex[]>(n_locks); >+ for (int i = 0; i < n_locks; i++) { >+ int end = std::min(n_locks, i + 5); >+ // acquire and then release locks i, i+1, ..., i+4 >+ for (int j = i; j < end; j++) { >+ array_of_locks[j].Lock(); >+ } >+ for (int j = i; j < end; j++) { >+ array_of_locks[j].Unlock(); >+ } >+ } >+} >+ >+TEST(Mutex, DeadlockIdBug) NO_THREAD_SAFETY_ANALYSIS { >+ // Test a scenario where a cached deadlock graph node id in the >+ // list of held locks is not invalidated when the corresponding >+ // mutex is deleted. >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); >+ // Mutex that will be destroyed while being held >+ absl::Mutex *a = new absl::Mutex; >+ // Other mutexes needed by test >+ absl::Mutex b, c; >+ >+ // Hold mutex. >+ a->Lock(); >+ >+ // Force deadlock id assignment by acquiring another lock. >+ b.Lock(); >+ b.Unlock(); >+ >+ // Delete the mutex. The Mutex destructor tries to remove held locks, >+ // but the attempt isn't foolproof. It can fail if: >+ // (a) Deadlock detection is currently disabled. >+ // (b) The destruction is from another thread. >+ // We exploit (a) by temporarily disabling deadlock detection. >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore); >+ delete a; >+ absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); >+ >+ // Now acquire another lock which will force a deadlock id assignment. >+ // We should end up getting assigned the same deadlock id that was >+ // freed up when "a" was deleted, which will cause a spurious deadlock >+ // report if the held lock entry for "a" was not invalidated. >+ c.Lock(); >+ c.Unlock(); >+} >+#endif // !defined(ABSL_INTERNAL_USE_NONPROD_MUTEX) >+ >+// -------------------------------------------------------- >+// Test for timeouts/deadlines on condition waits that are specified using >+// absl::Duration and absl::Time. For each waiting function we test with >+// a timeout/deadline that has already expired/passed, one that is infinite >+// and so never expires/passes, and one that will expire/pass in the near >+// future. >+ >+static absl::Duration TimeoutTestAllowedSchedulingDelay() { >+ // Note: we use a function here because Microsoft Visual Studio fails to >+ // properly initialize constexpr static absl::Duration variables. >+ return absl::Milliseconds(150); >+} >+ >+// Returns true if `actual_delay` is close enough to `expected_delay` to pass >+// the timeouts/deadlines test. Otherwise, logs warnings and returns false. >+ABSL_MUST_USE_RESULT >+static bool DelayIsWithinBounds(absl::Duration expected_delay, >+ absl::Duration actual_delay) { >+ bool pass = true; >+ // Do not allow the observed delay to be less than expected. This may occur >+ // in practice due to clock skew or when the synchronization primitives use a >+ // different clock than absl::Now(), but these cases should be handled by the >+ // the retry mechanism in each TimeoutTest. >+ if (actual_delay < expected_delay) { >+ ABSL_RAW_LOG(WARNING, >+ "Actual delay %s was too short, expected %s (difference %s)", >+ absl::FormatDuration(actual_delay).c_str(), >+ absl::FormatDuration(expected_delay).c_str(), >+ absl::FormatDuration(actual_delay - expected_delay).c_str()); >+ pass = false; >+ } >+ // If the expected delay is <= zero then allow a small error tolerance, since >+ // we do not expect context switches to occur during test execution. >+ // Otherwise, thread scheduling delays may be substantial in rare cases, so >+ // tolerate up to kTimeoutTestAllowedSchedulingDelay of error. >+ absl::Duration tolerance = expected_delay <= absl::ZeroDuration() >+ ? absl::Milliseconds(10) >+ : TimeoutTestAllowedSchedulingDelay(); >+ if (actual_delay > expected_delay + tolerance) { >+ ABSL_RAW_LOG(WARNING, >+ "Actual delay %s was too long, expected %s (difference %s)", >+ absl::FormatDuration(actual_delay).c_str(), >+ absl::FormatDuration(expected_delay).c_str(), >+ absl::FormatDuration(actual_delay - expected_delay).c_str()); >+ pass = false; >+ } >+ return pass; >+} >+ >+// Parameters for TimeoutTest, below. >+struct TimeoutTestParam { >+ // The file and line number (used for logging purposes only). >+ const char *from_file; >+ int from_line; >+ >+ // Should the absolute deadline API based on absl::Time be tested? If false, >+ // the relative deadline API based on absl::Duration is tested. >+ bool use_absolute_deadline; >+ >+ // The deadline/timeout used when calling the API being tested >+ // (e.g. Mutex::LockWhenWithDeadline). >+ absl::Duration wait_timeout; >+ >+ // The delay before the condition will be set true by the test code. If zero >+ // or negative, the condition is set true immediately (before calling the API >+ // being tested). Otherwise, if infinite, the condition is never set true. >+ // Otherwise a closure is scheduled for the future that sets the condition >+ // true. >+ absl::Duration satisfy_condition_delay; >+ >+ // The expected result of the condition after the call to the API being >+ // tested. Generally `true` means the condition was true when the API returns, >+ // `false` indicates an expected timeout. >+ bool expected_result; >+ >+ // The expected delay before the API under test returns. This is inherently >+ // flaky, so some slop is allowed (see `DelayIsWithinBounds` above), and the >+ // test keeps trying indefinitely until this constraint passes. >+ absl::Duration expected_delay; >+}; >+ >+// Print a `TimeoutTestParam` to a debug log. >+std::ostream &operator<<(std::ostream &os, const TimeoutTestParam ¶m) { >+ return os << "from: " << param.from_file << ":" << param.from_line >+ << " use_absolute_deadline: " >+ << (param.use_absolute_deadline ? "true" : "false") >+ << " wait_timeout: " << param.wait_timeout >+ << " satisfy_condition_delay: " << param.satisfy_condition_delay >+ << " expected_result: " >+ << (param.expected_result ? "true" : "false") >+ << " expected_delay: " << param.expected_delay; >+} >+ >+std::string FormatString(const TimeoutTestParam ¶m) { >+ std::ostringstream os; >+ os << param; >+ return os.str(); >+} >+ >+// Like `thread::Executor::ScheduleAt` except: >+// a) Delays zero or negative are executed immediately in the current thread. >+// b) Infinite delays are never scheduled. >+// c) Calls this test's `ScheduleAt` helper instead of using `pool` directly. >+static void RunAfterDelay(absl::Duration delay, >+ absl::synchronization_internal::ThreadPool *pool, >+ const std::function<void()> &callback) { >+ if (delay <= absl::ZeroDuration()) { >+ callback(); // immediate >+ } else if (delay != absl::InfiniteDuration()) { >+ ScheduleAfter(pool, delay, callback); >+ } >+} >+ >+class TimeoutTest : public ::testing::Test, >+ public ::testing::WithParamInterface<TimeoutTestParam> {}; >+ >+std::vector<TimeoutTestParam> MakeTimeoutTestParamValues() { >+ // The `finite` delay is a finite, relatively short, delay. We make it larger >+ // than our allowed scheduling delay (slop factor) to avoid confusion when >+ // diagnosing test failures. The other constants here have clear meanings. >+ const absl::Duration finite = 3 * TimeoutTestAllowedSchedulingDelay(); >+ const absl::Duration never = absl::InfiniteDuration(); >+ const absl::Duration negative = -absl::InfiniteDuration(); >+ const absl::Duration immediate = absl::ZeroDuration(); >+ >+ // Every test case is run twice; once using the absolute deadline API and once >+ // using the relative timeout API. >+ std::vector<TimeoutTestParam> values; >+ for (bool use_absolute_deadline : {false, true}) { >+ // Tests with a negative timeout (deadline in the past), which should >+ // immediately return current state of the condition. >+ >+ // The condition is already true: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ negative, // wait_timeout >+ immediate, // satisfy_condition_delay >+ true, // expected_result >+ immediate, // expected_delay >+ }); >+ >+ // The condition becomes true, but the timeout has already expired: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ negative, // wait_timeout >+ finite, // satisfy_condition_delay >+ false, // expected_result >+ immediate // expected_delay >+ }); >+ >+ // The condition never becomes true: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ negative, // wait_timeout >+ never, // satisfy_condition_delay >+ false, // expected_result >+ immediate // expected_delay >+ }); >+ >+ // Tests with an infinite timeout (deadline in the infinite future), which >+ // should only return when the condition becomes true. >+ >+ // The condition is already true: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ never, // wait_timeout >+ immediate, // satisfy_condition_delay >+ true, // expected_result >+ immediate // expected_delay >+ }); >+ >+ // The condition becomes true before the (infinite) expiry: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ never, // wait_timeout >+ finite, // satisfy_condition_delay >+ true, // expected_result >+ finite, // expected_delay >+ }); >+ >+ // Tests with a (small) finite timeout (deadline soon), with the condition >+ // becoming true both before and after its expiry. >+ >+ // The condition is already true: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ never, // wait_timeout >+ immediate, // satisfy_condition_delay >+ true, // expected_result >+ immediate // expected_delay >+ }); >+ >+ // The condition becomes true before the expiry: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ finite * 2, // wait_timeout >+ finite, // satisfy_condition_delay >+ true, // expected_result >+ finite // expected_delay >+ }); >+ >+ // The condition becomes true, but the timeout has already expired: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ finite, // wait_timeout >+ finite * 2, // satisfy_condition_delay >+ false, // expected_result >+ finite // expected_delay >+ }); >+ >+ // The condition never becomes true: >+ values.push_back(TimeoutTestParam{ >+ __FILE__, __LINE__, use_absolute_deadline, >+ finite, // wait_timeout >+ never, // satisfy_condition_delay >+ false, // expected_result >+ finite // expected_delay >+ }); >+ } >+ return values; >+} >+ >+// Instantiate `TimeoutTest` with `MakeTimeoutTestParamValues()`. >+INSTANTIATE_TEST_CASE_P(All, TimeoutTest, >+ testing::ValuesIn(MakeTimeoutTestParamValues())); >+ >+TEST_P(TimeoutTest, Await) { >+ const TimeoutTestParam params = GetParam(); >+ ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); >+ >+ // Because this test asserts bounds on scheduling delays it is flaky. To >+ // compensate it loops forever until it passes. Failures express as test >+ // timeouts, in which case the test log can be used to diagnose the issue. >+ for (int attempt = 1;; ++attempt) { >+ ABSL_RAW_LOG(INFO, "Attempt %d", attempt); >+ >+ absl::Mutex mu; >+ bool value = false; // condition value (under mu) >+ >+ std::unique_ptr<absl::synchronization_internal::ThreadPool> pool = >+ CreateDefaultPool(); >+ RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] { >+ absl::MutexLock l(&mu); >+ value = true; >+ }); >+ >+ absl::MutexLock lock(&mu); >+ absl::Time start_time = absl::Now(); >+ absl::Condition cond(&value); >+ bool result = >+ params.use_absolute_deadline >+ ? mu.AwaitWithDeadline(cond, start_time + params.wait_timeout) >+ : mu.AwaitWithTimeout(cond, params.wait_timeout); >+ if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) { >+ EXPECT_EQ(params.expected_result, result); >+ break; >+ } >+ } >+} >+ >+TEST_P(TimeoutTest, LockWhen) { >+ const TimeoutTestParam params = GetParam(); >+ ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); >+ >+ // Because this test asserts bounds on scheduling delays it is flaky. To >+ // compensate it loops forever until it passes. Failures express as test >+ // timeouts, in which case the test log can be used to diagnose the issue. >+ for (int attempt = 1;; ++attempt) { >+ ABSL_RAW_LOG(INFO, "Attempt %d", attempt); >+ >+ absl::Mutex mu; >+ bool value = false; // condition value (under mu) >+ >+ std::unique_ptr<absl::synchronization_internal::ThreadPool> pool = >+ CreateDefaultPool(); >+ RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] { >+ absl::MutexLock l(&mu); >+ value = true; >+ }); >+ >+ absl::Time start_time = absl::Now(); >+ absl::Condition cond(&value); >+ bool result = >+ params.use_absolute_deadline >+ ? mu.LockWhenWithDeadline(cond, start_time + params.wait_timeout) >+ : mu.LockWhenWithTimeout(cond, params.wait_timeout); >+ mu.Unlock(); >+ >+ if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) { >+ EXPECT_EQ(params.expected_result, result); >+ break; >+ } >+ } >+} >+ >+TEST_P(TimeoutTest, ReaderLockWhen) { >+ const TimeoutTestParam params = GetParam(); >+ ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); >+ >+ // Because this test asserts bounds on scheduling delays it is flaky. To >+ // compensate it loops forever until it passes. Failures express as test >+ // timeouts, in which case the test log can be used to diagnose the issue. >+ for (int attempt = 0;; ++attempt) { >+ ABSL_RAW_LOG(INFO, "Attempt %d", attempt); >+ >+ absl::Mutex mu; >+ bool value = false; // condition value (under mu) >+ >+ std::unique_ptr<absl::synchronization_internal::ThreadPool> pool = >+ CreateDefaultPool(); >+ RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] { >+ absl::MutexLock l(&mu); >+ value = true; >+ }); >+ >+ absl::Time start_time = absl::Now(); >+ bool result = >+ params.use_absolute_deadline >+ ? mu.ReaderLockWhenWithDeadline(absl::Condition(&value), >+ start_time + params.wait_timeout) >+ : mu.ReaderLockWhenWithTimeout(absl::Condition(&value), >+ params.wait_timeout); >+ mu.ReaderUnlock(); >+ >+ if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) { >+ EXPECT_EQ(params.expected_result, result); >+ break; >+ } >+ } >+} >+ >+TEST_P(TimeoutTest, Wait) { >+ const TimeoutTestParam params = GetParam(); >+ ABSL_RAW_LOG(INFO, "Params: %s", FormatString(params).c_str()); >+ >+ // Because this test asserts bounds on scheduling delays it is flaky. To >+ // compensate it loops forever until it passes. Failures express as test >+ // timeouts, in which case the test log can be used to diagnose the issue. >+ for (int attempt = 0;; ++attempt) { >+ ABSL_RAW_LOG(INFO, "Attempt %d", attempt); >+ >+ absl::Mutex mu; >+ bool value = false; // condition value (under mu) >+ absl::CondVar cv; // signals a change of `value` >+ >+ std::unique_ptr<absl::synchronization_internal::ThreadPool> pool = >+ CreateDefaultPool(); >+ RunAfterDelay(params.satisfy_condition_delay, pool.get(), [&] { >+ absl::MutexLock l(&mu); >+ value = true; >+ cv.Signal(); >+ }); >+ >+ absl::MutexLock lock(&mu); >+ absl::Time start_time = absl::Now(); >+ absl::Duration timeout = params.wait_timeout; >+ absl::Time deadline = start_time + timeout; >+ while (!value) { >+ if (params.use_absolute_deadline ? cv.WaitWithDeadline(&mu, deadline) >+ : cv.WaitWithTimeout(&mu, timeout)) { >+ break; // deadline/timeout exceeded >+ } >+ timeout = deadline - absl::Now(); // recompute >+ } >+ bool result = value; // note: `mu` is still held >+ >+ if (DelayIsWithinBounds(params.expected_delay, absl::Now() - start_time)) { >+ EXPECT_EQ(params.expected_result, result); >+ break; >+ } >+ } >+} >+ >+TEST(Mutex, Logging) { >+ // Allow user to look at logging output >+ absl::Mutex logged_mutex; >+ logged_mutex.EnableDebugLog("fido_mutex"); >+ absl::CondVar logged_cv; >+ logged_cv.EnableDebugLog("rover_cv"); >+ logged_mutex.Lock(); >+ logged_cv.WaitWithTimeout(&logged_mutex, absl::Milliseconds(20)); >+ logged_mutex.Unlock(); >+ logged_mutex.ReaderLock(); >+ logged_mutex.ReaderUnlock(); >+ logged_mutex.Lock(); >+ logged_mutex.Unlock(); >+ logged_cv.Signal(); >+ logged_cv.SignalAll(); >+} >+ >+// -------------------------------------------------------- >+ >+// Generate the vector of thread counts for tests parameterized on thread count. >+static std::vector<int> AllThreadCountValues() { >+ if (kExtendedTest) { >+ return {2, 4, 8, 10, 16, 20, 24, 30, 32}; >+ } >+ return {2, 4, 10}; >+} >+ >+// A test fixture parameterized by thread count. >+class MutexVariableThreadCountTest : public ::testing::TestWithParam<int> {}; >+ >+// Instantiate the above with AllThreadCountOptions(). >+INSTANTIATE_TEST_CASE_P(ThreadCounts, MutexVariableThreadCountTest, >+ ::testing::ValuesIn(AllThreadCountValues()), >+ ::testing::PrintToStringParamName()); >+ >+// Reduces iterations by some factor for slow platforms >+// (determined empirically). >+static int ScaleIterations(int x) { >+ // ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE is set in the implementation >+ // of Mutex that uses either std::mutex or pthread_mutex_t. Use >+ // these as keys to determine the slow implementation. >+#if defined(ABSL_MUTEX_READER_LOCK_IS_EXCLUSIVE) >+ return x / 10; >+#else >+ return x; >+#endif >+} >+ >+TEST_P(MutexVariableThreadCountTest, Mutex) { >+ int threads = GetParam(); >+ int iterations = ScaleIterations(10000000) / threads; >+ int operations = threads * iterations; >+ EXPECT_EQ(RunTest(&TestMu, threads, iterations, operations), operations); >+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED) >+ iterations = std::min(iterations, 10); >+ operations = threads * iterations; >+ EXPECT_EQ(RunTestWithInvariantDebugging(&TestMu, threads, iterations, >+ operations, CheckSumG0G1), >+ operations); >+#endif >+} >+ >+TEST_P(MutexVariableThreadCountTest, Try) { >+ int threads = GetParam(); >+ int iterations = 1000000 / threads; >+ int operations = iterations * threads; >+ EXPECT_EQ(RunTest(&TestTry, threads, iterations, operations), operations); >+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED) >+ iterations = std::min(iterations, 10); >+ operations = threads * iterations; >+ EXPECT_EQ(RunTestWithInvariantDebugging(&TestTry, threads, iterations, >+ operations, CheckSumG0G1), >+ operations); >+#endif >+} >+ >+TEST_P(MutexVariableThreadCountTest, R20ms) { >+ int threads = GetParam(); >+ int iterations = 100; >+ int operations = iterations * threads; >+ EXPECT_EQ(RunTest(&TestR20ms, threads, iterations, operations), 0); >+} >+ >+TEST_P(MutexVariableThreadCountTest, RW) { >+ int threads = GetParam(); >+ int iterations = ScaleIterations(20000000) / threads; >+ int operations = iterations * threads; >+ EXPECT_EQ(RunTest(&TestRW, threads, iterations, operations), operations / 2); >+#if !defined(ABSL_MUTEX_ENABLE_INVARIANT_DEBUGGING_NOT_IMPLEMENTED) >+ iterations = std::min(iterations, 10); >+ operations = threads * iterations; >+ EXPECT_EQ(RunTestWithInvariantDebugging(&TestRW, threads, iterations, >+ operations, CheckSumG0G1), >+ operations / 2); >+#endif >+} >+ >+TEST_P(MutexVariableThreadCountTest, Await) { >+ int threads = GetParam(); >+ int iterations = ScaleIterations(500000); >+ int operations = iterations; >+ EXPECT_EQ(RunTest(&TestAwait, threads, iterations, operations), operations); >+} >+ >+TEST_P(MutexVariableThreadCountTest, SignalAll) { >+ int threads = GetParam(); >+ int iterations = 200000 / threads; >+ int operations = iterations; >+ EXPECT_EQ(RunTest(&TestSignalAll, threads, iterations, operations), >+ operations); >+} >+ >+TEST(Mutex, Signal) { >+ int threads = 2; // TestSignal must use two threads >+ int iterations = 200000; >+ int operations = iterations; >+ EXPECT_EQ(RunTest(&TestSignal, threads, iterations, operations), operations); >+} >+ >+TEST(Mutex, Timed) { >+ int threads = 10; // Use a fixed thread count of 10 >+ int iterations = 1000; >+ int operations = iterations; >+ EXPECT_EQ(RunTest(&TestCVTimeout, threads, iterations, operations), >+ operations); >+} >+ >+TEST(Mutex, CVTime) { >+ int threads = 10; // Use a fixed thread count of 10 >+ int iterations = 1; >+ EXPECT_EQ(RunTest(&TestCVTime, threads, iterations, 1), >+ threads * iterations); >+} >+ >+TEST(Mutex, MuTime) { >+ int threads = 10; // Use a fixed thread count of 10 >+ int iterations = 1; >+ EXPECT_EQ(RunTest(&TestMuTime, threads, iterations, 1), threads * iterations); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.cc >new file mode 100644 >index 00000000000..ed8cc906774 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.cc >@@ -0,0 +1,84 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/notification.h" >+ >+#include <atomic> >+ >+#include "absl/base/attributes.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/synchronization/mutex.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+void Notification::Notify() { >+ MutexLock l(&this->mutex_); >+ >+#ifndef NDEBUG >+ if (ABSL_PREDICT_FALSE(notified_yet_.load(std::memory_order_relaxed))) { >+ ABSL_RAW_LOG( >+ FATAL, >+ "Notify() method called more than once for Notification object %p", >+ static_cast<void *>(this)); >+ } >+#endif >+ >+ notified_yet_.store(true, std::memory_order_release); >+} >+ >+Notification::~Notification() { >+ // Make sure that the thread running Notify() exits before the object is >+ // destructed. >+ MutexLock l(&this->mutex_); >+} >+ >+static inline bool HasBeenNotifiedInternal( >+ const std::atomic<bool> *notified_yet) { >+ return notified_yet->load(std::memory_order_acquire); >+} >+ >+bool Notification::HasBeenNotified() const { >+ return HasBeenNotifiedInternal(&this->notified_yet_); >+} >+ >+void Notification::WaitForNotification() const { >+ if (!HasBeenNotifiedInternal(&this->notified_yet_)) { >+ this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal, >+ &this->notified_yet_)); >+ this->mutex_.Unlock(); >+ } >+} >+ >+bool Notification::WaitForNotificationWithTimeout( >+ absl::Duration timeout) const { >+ bool notified = HasBeenNotifiedInternal(&this->notified_yet_); >+ if (!notified) { >+ notified = this->mutex_.LockWhenWithTimeout( >+ Condition(&HasBeenNotifiedInternal, &this->notified_yet_), timeout); >+ this->mutex_.Unlock(); >+ } >+ return notified; >+} >+ >+bool Notification::WaitForNotificationWithDeadline(absl::Time deadline) const { >+ bool notified = HasBeenNotifiedInternal(&this->notified_yet_); >+ if (!notified) { >+ notified = this->mutex_.LockWhenWithDeadline( >+ Condition(&HasBeenNotifiedInternal, &this->notified_yet_), deadline); >+ this->mutex_.Unlock(); >+ } >+ return notified; >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.h >new file mode 100644 >index 00000000000..107932f2909 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification.h >@@ -0,0 +1,112 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// notification.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines a `Notification` abstraction, which allows threads >+// to receive notification of a single occurrence of a single event. >+// >+// The `Notification` object maintains a private boolean "notified" state that >+// transitions to `true` at most once. The `Notification` class provides the >+// following primary member functions: >+// * `HasBeenNotified() `to query its state >+// * `WaitForNotification*()` to have threads wait until the "notified" state >+// is `true`. >+// * `Notify()` to set the notification's "notified" state to `true` and >+// notify all waiting threads that the event has occurred. >+// This method may only be called once. >+// >+// Note that while `Notify()` may only be called once, it is perfectly valid to >+// call any of the `WaitForNotification*()` methods multiple times, from >+// multiple threads -- even after the notification's "notified" state has been >+// set -- in which case those methods will immediately return. >+// >+// Note that the lifetime of a `Notification` requires careful consideration; >+// it might not be safe to destroy a notification after calling `Notify()` since >+// it is still legal for other threads to call `WaitForNotification*()` methods >+// on the notification. However, observers responding to a "notified" state of >+// `true` can safely delete the notification without interfering with the call >+// to `Notify()` in the other thread. >+// >+// Memory ordering: For any threads X and Y, if X calls `Notify()`, then any >+// action taken by X before it calls `Notify()` is visible to thread Y after: >+// * Y returns from `WaitForNotification()`, or >+// * Y receives a `true` return value from either `HasBeenNotified()` or >+// `WaitForNotificationWithTimeout()`. >+ >+#ifndef ABSL_SYNCHRONIZATION_NOTIFICATION_H_ >+#define ABSL_SYNCHRONIZATION_NOTIFICATION_H_ >+ >+#include <atomic> >+ >+#include "absl/synchronization/mutex.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// Notification >+// ----------------------------------------------------------------------------- >+class Notification { >+ public: >+ // Initializes the "notified" state to unnotified. >+ Notification() : notified_yet_(false) {} >+ explicit Notification(bool prenotify) : notified_yet_(prenotify) {} >+ Notification(const Notification&) = delete; >+ Notification& operator=(const Notification&) = delete; >+ ~Notification(); >+ >+ // Notification::HasBeenNotified() >+ // >+ // Returns the value of the notification's internal "notified" state. >+ bool HasBeenNotified() const; >+ >+ // Notification::WaitForNotification() >+ // >+ // Blocks the calling thread until the notification's "notified" state is >+ // `true`. Note that if `Notify()` has been previously called on this >+ // notification, this function will immediately return. >+ void WaitForNotification() const; >+ >+ // Notification::WaitForNotificationWithTimeout() >+ // >+ // Blocks until either the notification's "notified" state is `true` (which >+ // may occur immediately) or the timeout has elapsed, returning the value of >+ // its "notified" state in either case. >+ bool WaitForNotificationWithTimeout(absl::Duration timeout) const; >+ >+ // Notification::WaitForNotificationWithDeadline() >+ // >+ // Blocks until either the notification's "notified" state is `true` (which >+ // may occur immediately) or the deadline has expired, returning the value of >+ // its "notified" state in either case. >+ bool WaitForNotificationWithDeadline(absl::Time deadline) const; >+ >+ // Notification::Notify() >+ // >+ // Sets the "notified" state of this notification to `true` and wakes waiting >+ // threads. Note: do not call `Notify()` multiple times on the same >+ // `Notification`; calling `Notify()` more than once on the same notification >+ // results in undefined behavior. >+ void Notify(); >+ >+ private: >+ mutable Mutex mutex_; >+ std::atomic<bool> notified_yet_; // written under mutex_ >+}; >+ >+} // namespace absl >+#endif // ABSL_SYNCHRONIZATION_NOTIFICATION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification_test.cc >new file mode 100644 >index 00000000000..9b3b6a5a9e8 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/synchronization/notification_test.cc >@@ -0,0 +1,124 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/synchronization/notification.h" >+ >+#include <thread> // NOLINT(build/c++11) >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/synchronization/mutex.h" >+ >+namespace absl { >+ >+// A thread-safe class that holds a counter. >+class ThreadSafeCounter { >+ public: >+ ThreadSafeCounter() : count_(0) {} >+ >+ void Increment() { >+ MutexLock lock(&mutex_); >+ ++count_; >+ } >+ >+ int Get() const { >+ MutexLock lock(&mutex_); >+ return count_; >+ } >+ >+ void WaitUntilGreaterOrEqual(int n) { >+ MutexLock lock(&mutex_); >+ auto cond = [this, n]() { return count_ >= n; }; >+ mutex_.Await(Condition(&cond)); >+ } >+ >+ private: >+ mutable Mutex mutex_; >+ int count_; >+}; >+ >+// Runs the |i|'th worker thread for the tests in BasicTests(). Increments the >+// |ready_counter|, waits on the |notification|, and then increments the >+// |done_counter|. >+static void RunWorker(int i, ThreadSafeCounter* ready_counter, >+ Notification* notification, >+ ThreadSafeCounter* done_counter) { >+ ready_counter->Increment(); >+ notification->WaitForNotification(); >+ done_counter->Increment(); >+} >+ >+// Tests that the |notification| properly blocks and awakens threads. Assumes >+// that the |notification| is not yet triggered. If |notify_before_waiting| is >+// true, the |notification| is triggered before any threads are created, so the >+// threads never block in WaitForNotification(). Otherwise, the |notification| >+// is triggered at a later point when most threads are likely to be blocking in >+// WaitForNotification(). >+static void BasicTests(bool notify_before_waiting, Notification* notification) { >+ EXPECT_FALSE(notification->HasBeenNotified()); >+ EXPECT_FALSE( >+ notification->WaitForNotificationWithTimeout(absl::Milliseconds(0))); >+ EXPECT_FALSE(notification->WaitForNotificationWithDeadline(absl::Now())); >+ >+ absl::Time start = absl::Now(); >+ EXPECT_FALSE( >+ notification->WaitForNotificationWithTimeout(absl::Milliseconds(50))); >+ EXPECT_LE(start + absl::Milliseconds(50), absl::Now()); >+ >+ ThreadSafeCounter ready_counter; >+ ThreadSafeCounter done_counter; >+ >+ if (notify_before_waiting) { >+ notification->Notify(); >+ } >+ >+ // Create a bunch of threads that increment the |done_counter| after being >+ // notified. >+ const int kNumThreads = 10; >+ std::vector<std::thread> workers; >+ for (int i = 0; i < kNumThreads; ++i) { >+ workers.push_back(std::thread(&RunWorker, i, &ready_counter, notification, >+ &done_counter)); >+ } >+ >+ if (!notify_before_waiting) { >+ ready_counter.WaitUntilGreaterOrEqual(kNumThreads); >+ >+ // Workers have not been notified yet, so the |done_counter| should be >+ // unmodified. >+ EXPECT_EQ(0, done_counter.Get()); >+ >+ notification->Notify(); >+ } >+ >+ // After notifying and then joining the workers, both counters should be >+ // fully incremented. >+ notification->WaitForNotification(); // should exit immediately >+ EXPECT_TRUE(notification->HasBeenNotified()); >+ EXPECT_TRUE(notification->WaitForNotificationWithTimeout(absl::Seconds(0))); >+ EXPECT_TRUE(notification->WaitForNotificationWithDeadline(absl::Now())); >+ for (std::thread& worker : workers) { >+ worker.join(); >+ } >+ EXPECT_EQ(kNumThreads, ready_counter.Get()); >+ EXPECT_EQ(kNumThreads, done_counter.Get()); >+} >+ >+TEST(NotificationTest, SanityTest) { >+ Notification local_notification1, local_notification2; >+ BasicTests(false, &local_notification1); >+ BasicTests(true, &local_notification2); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.bazel >new file mode 100644 >index 00000000000..c7c16d4376c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.bazel >@@ -0,0 +1,112 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "time", >+ srcs = [ >+ "clock.cc", >+ "duration.cc", >+ "format.cc", >+ "internal/get_current_time_chrono.inc", >+ "internal/get_current_time_posix.inc", >+ "time.cc", >+ ], >+ hdrs = [ >+ "clock.h", >+ "time.h", >+ ], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base", >+ "//absl/base:core_headers", >+ "//absl/numeric:int128", >+ "//absl/strings", >+ "//absl/time/internal/cctz:civil_time", >+ "//absl/time/internal/cctz:time_zone", >+ ], >+) >+ >+cc_library( >+ name = "test_util", >+ testonly = 1, >+ srcs = [ >+ "internal/test_util.cc", >+ "internal/zoneinfo.inc", >+ ], >+ hdrs = ["internal/test_util.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ visibility = [ >+ "//absl/time:__pkg__", >+ ], >+ deps = [ >+ ":time", >+ "//absl/base", >+ "//absl/time/internal/cctz:time_zone", >+ "@com_google_googletest//:gtest", >+ ], >+) >+ >+cc_test( >+ name = "time_test", >+ srcs = [ >+ "clock_test.cc", >+ "duration_test.cc", >+ "format_test.cc", >+ "time_norm_test.cc", >+ "time_test.cc", >+ "time_zone_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":test_util", >+ ":time", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/time/internal/cctz:time_zone", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "time_benchmark", >+ srcs = [ >+ "clock_benchmark.cc", >+ "duration_benchmark.cc", >+ "format_benchmark.cc", >+ "time_benchmark.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ tags = [ >+ "benchmark", >+ ], >+ deps = [ >+ ":test_util", >+ ":time", >+ "//absl/base", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.gn >new file mode 100644 >index 00000000000..9927af8343c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/BUILD.gn >@@ -0,0 +1,70 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("time") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "clock.cc", >+ "duration.cc", >+ "format.cc", >+ "internal/get_current_time_chrono.inc", >+ "internal/get_current_time_posix.inc", >+ "time.cc", >+ ] >+ public = [ >+ "clock.h", >+ "time.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:core_headers", >+ "../numeric:int128", >+ "../strings", >+ "../time/internal/cctz:civil_time", >+ "../time/internal/cctz:time_zone", >+ ] >+} >+ >+source_set("test_util") { >+ testonly = true >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/test_util.cc", >+ "internal/zoneinfo.inc", >+ ] >+ public = [ >+ "internal/test_util.h", >+ ] >+ deps = [ >+ ":time", >+ "../base", >+ "../time/internal/cctz:time_zone", >+ "//testing/gtest", >+ "//testing/gmock", >+ ] >+ visibility = [] >+ visibility += [ "../time:*" ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/CMakeLists.txt >new file mode 100644 >index 00000000000..06272364f14 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/CMakeLists.txt >@@ -0,0 +1,96 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND TIME_PUBLIC_HEADERS >+ "clock.h" >+ "time.h" >+) >+ >+ >+list(APPEND TIME_INTERNAL_HEADERS >+ "internal/test_util.h" >+ "internal/cctz/include/cctz/civil_time.h" >+ "internal/cctz/include/cctz/civil_time_detail.h" >+ "internal/cctz/include/cctz/time_zone.h" >+ "internal/cctz/include/cctz/zone_info_source.h" >+) >+ >+list(APPEND TIME_SRC >+ "time.cc" >+ "clock.cc" >+ "duration.cc" >+ "format.cc" >+ "internal/cctz/src/civil_time_detail.cc" >+ "internal/cctz/src/time_zone_fixed.cc" >+ "internal/cctz/src/time_zone_fixed.h" >+ "internal/cctz/src/time_zone_format.cc" >+ "internal/cctz/src/time_zone_if.cc" >+ "internal/cctz/src/time_zone_if.h" >+ "internal/cctz/src/time_zone_impl.cc" >+ "internal/cctz/src/time_zone_impl.h" >+ "internal/cctz/src/time_zone_info.cc" >+ "internal/cctz/src/time_zone_info.h" >+ "internal/cctz/src/time_zone_libc.cc" >+ "internal/cctz/src/time_zone_libc.h" >+ "internal/cctz/src/time_zone_lookup.cc" >+ "internal/cctz/src/time_zone_posix.cc" >+ "internal/cctz/src/time_zone_posix.h" >+ "internal/cctz/src/tzfile.h" >+ "internal/cctz/src/zone_info_source.cc" >+ ${TIME_PUBLIC_HEADERS} >+ ${TIME_INTERNAL_HEADERS} >+) >+set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings) >+ >+absl_library( >+ TARGET >+ absl_time >+ SOURCES >+ ${TIME_SRC} >+ PUBLIC_LIBRARIES >+ ${TIME_PUBLIC_LIBRARIES} >+ EXPORT_NAME >+ time >+) >+ >+ >+ >+# >+## TESTS >+# >+ >+# test time_test >+list(APPEND TIME_TEST_SRC >+ "time_test.cc" >+ "clock_test.cc" >+ "duration_test.cc" >+ "format_test.cc" >+ "time_norm_test.cc" >+ "time_test.cc" >+ "time_zone_test.cc" >+ "internal/test_util.cc" >+) >+set(TIME_TEST_PUBLIC_LIBRARIES absl::time) >+ >+absl_test( >+ TARGET >+ time_test >+ SOURCES >+ ${TIME_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${TIME_TEST_PUBLIC_LIBRARIES} >+) >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.cc >new file mode 100644 >index 00000000000..74ee1401b98 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.cc >@@ -0,0 +1,561 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/clock.h" >+ >+#include "absl/base/attributes.h" >+ >+#ifdef _WIN32 >+#include <windows.h> >+#endif >+ >+#include <algorithm> >+#include <atomic> >+#include <cerrno> >+#include <cstdint> >+#include <ctime> >+#include <limits> >+ >+#include "absl/base/internal/spinlock.h" >+#include "absl/base/internal/unscaledcycleclock.h" >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/base/thread_annotations.h" >+ >+namespace absl { >+Time Now() { >+ // TODO(bww): Get a timespec instead so we don't have to divide. >+ int64_t n = absl::GetCurrentTimeNanos(); >+ if (n >= 0) { >+ return time_internal::FromUnixDuration( >+ time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4)); >+ } >+ return time_internal::FromUnixDuration(absl::Nanoseconds(n)); >+} >+} // namespace absl >+ >+// Decide if we should use the fast GetCurrentTimeNanos() algorithm >+// based on the cyclecounter, otherwise just get the time directly >+// from the OS on every call. This can be chosen at compile-time via >+// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1] >+#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS >+#if ABSL_USE_UNSCALED_CYCLECLOCK >+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1 >+#else >+#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0 >+#endif >+#endif >+ >+#if defined(__APPLE__) || defined(_WIN32) >+#include "absl/time/internal/get_current_time_chrono.inc" >+#else >+#include "absl/time/internal/get_current_time_posix.inc" >+#endif >+ >+// Allows override by test. >+#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM >+#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \ >+ ::absl::time_internal::GetCurrentTimeNanosFromSystem() >+#endif >+ >+#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS >+namespace absl { >+int64_t GetCurrentTimeNanos() { >+ return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); >+} >+} // namespace absl >+#else // Use the cyclecounter-based implementation below. >+ >+// Allows override by test. >+#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW >+#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \ >+ ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now() >+#endif >+ >+// The following counters are used only by the test code. >+static int64_t stats_initializations; >+static int64_t stats_reinitializations; >+static int64_t stats_calibrations; >+static int64_t stats_slow_paths; >+static int64_t stats_fast_slow_paths; >+ >+namespace absl { >+namespace time_internal { >+// This is a friend wrapper around UnscaledCycleClock::Now() >+// (needed to access UnscaledCycleClock). >+class UnscaledCycleClockWrapperForGetCurrentTime { >+ public: >+ static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); } >+}; >+} // namespace time_internal >+ >+// uint64_t is used in this module to provide an extra bit in multiplications >+ >+// Return the time in ns as told by the kernel interface. Place in *cycleclock >+// the value of the cycleclock at about the time of the syscall. >+// This call represents the time base that this module synchronizes to. >+// Ensures that *cycleclock does not step back by up to (1 << 16) from >+// last_cycleclock, to discard small backward counter steps. (Larger steps are >+// assumed to be complete resyncs, which shouldn't happen. If they do, a full >+// reinitialization of the outer algorithm should occur.) >+static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock, >+ uint64_t *cycleclock) { >+ // We try to read clock values at about the same time as the kernel clock. >+ // This value gets adjusted up or down as estimate of how long that should >+ // take, so we can reject attempts that take unusually long. >+ static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000}; >+ >+ uint64_t local_approx_syscall_time_in_cycles = // local copy >+ approx_syscall_time_in_cycles.load(std::memory_order_relaxed); >+ >+ int64_t current_time_nanos_from_system; >+ uint64_t before_cycles; >+ uint64_t after_cycles; >+ uint64_t elapsed_cycles; >+ int loops = 0; >+ do { >+ before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); >+ current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); >+ after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); >+ // elapsed_cycles is unsigned, so is large on overflow >+ elapsed_cycles = after_cycles - before_cycles; >+ if (elapsed_cycles >= local_approx_syscall_time_in_cycles && >+ ++loops == 20) { // clock changed frequencies? Back off. >+ loops = 0; >+ if (local_approx_syscall_time_in_cycles < 1000 * 1000) { >+ local_approx_syscall_time_in_cycles = >+ (local_approx_syscall_time_in_cycles + 1) << 1; >+ } >+ approx_syscall_time_in_cycles.store( >+ local_approx_syscall_time_in_cycles, >+ std::memory_order_relaxed); >+ } >+ } while (elapsed_cycles >= local_approx_syscall_time_in_cycles || >+ last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16)); >+ >+ // Number of times in a row we've seen a kernel time call take substantially >+ // less than approx_syscall_time_in_cycles. >+ static std::atomic<uint32_t> seen_smaller{ 0 }; >+ >+ // Adjust approx_syscall_time_in_cycles to be within a factor of 2 >+ // of the typical time to execute one iteration of the loop above. >+ if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) { >+ // measured time is no smaller than half current approximation >+ seen_smaller.store(0, std::memory_order_relaxed); >+ } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) { >+ // smaller delays several times in a row; reduce approximation by 12.5% >+ const uint64_t new_approximation = >+ local_approx_syscall_time_in_cycles - >+ (local_approx_syscall_time_in_cycles >> 3); >+ approx_syscall_time_in_cycles.store(new_approximation, >+ std::memory_order_relaxed); >+ seen_smaller.store(0, std::memory_order_relaxed); >+ } >+ >+ *cycleclock = after_cycles; >+ return current_time_nanos_from_system; >+} >+ >+ >+// --------------------------------------------------------------------- >+// An implementation of reader-write locks that use no atomic ops in the read >+// case. This is a generalization of Lamport's method for reading a multiword >+// clock. Increment a word on each write acquisition, using the low-order bit >+// as a spinlock; the word is the high word of the "clock". Readers read the >+// high word, then all other data, then the high word again, and repeat the >+// read if the reads of the high words yields different answers, or an odd >+// value (either case suggests possible interference from a writer). >+// Here we use a spinlock to ensure only one writer at a time, rather than >+// spinning on the bottom bit of the word to benefit from SpinLock >+// spin-delay tuning. >+ >+// Acquire seqlock (*seq) and return the value to be written to unlock. >+static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) { >+ uint64_t x = seq->fetch_add(1, std::memory_order_relaxed); >+ >+ // We put a release fence between update to *seq and writes to shared data. >+ // Thus all stores to shared data are effectively release operations and >+ // update to *seq above cannot be re-ordered past any of them. Note that >+ // this barrier is not for the fetch_add above. A release barrier for the >+ // fetch_add would be before it, not after. >+ std::atomic_thread_fence(std::memory_order_release); >+ >+ return x + 2; // original word plus 2 >+} >+ >+// Release seqlock (*seq) by writing x to it---a value previously returned by >+// SeqAcquire. >+static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) { >+ // The unlock store to *seq must have release ordering so that all >+ // updates to shared data must finish before this store. >+ seq->store(x, std::memory_order_release); // release lock for readers >+} >+ >+// --------------------------------------------------------------------- >+ >+// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond. >+enum { kScale = 30 }; >+ >+// The minimum interval between samples of the time base. >+// We pick enough time to amortize the cost of the sample, >+// to get a reasonably accurate cycle counter rate reading, >+// and not so much that calculations will overflow 64-bits. >+static const uint64_t kMinNSBetweenSamples = 2000 << 20; >+ >+// We require that kMinNSBetweenSamples shifted by kScale >+// have at least a bit left over for 64-bit calculations. >+static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) == >+ kMinNSBetweenSamples, >+ "cannot represent kMaxBetweenSamplesNSScaled"); >+ >+// A reader-writer lock protecting the static locations below. >+// See SeqAcquire() and SeqRelease() above. >+static absl::base_internal::SpinLock lock( >+ absl::base_internal::kLinkerInitialized); >+static std::atomic<uint64_t> seq(0); >+ >+// data from a sample of the kernel's time value >+struct TimeSampleAtomic { >+ std::atomic<uint64_t> raw_ns; // raw kernel time >+ std::atomic<uint64_t> base_ns; // our estimate of time >+ std::atomic<uint64_t> base_cycles; // cycle counter reading >+ std::atomic<uint64_t> nsscaled_per_cycle; // cycle period >+ // cycles before we'll sample again (a scaled reciprocal of the period, >+ // to avoid a division on the fast path). >+ std::atomic<uint64_t> min_cycles_per_sample; >+}; >+// Same again, but with non-atomic types >+struct TimeSample { >+ uint64_t raw_ns; // raw kernel time >+ uint64_t base_ns; // our estimate of time >+ uint64_t base_cycles; // cycle counter reading >+ uint64_t nsscaled_per_cycle; // cycle period >+ uint64_t min_cycles_per_sample; // approx cycles before next sample >+}; >+ >+static struct TimeSampleAtomic last_sample; // the last sample; under seq >+ >+static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD; >+ >+// Read the contents of *atomic into *sample. >+// Each field is read atomically, but to maintain atomicity between fields, >+// the access must be done under a lock. >+static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic, >+ struct TimeSample *sample) { >+ sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed); >+ sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed); >+ sample->nsscaled_per_cycle = >+ atomic->nsscaled_per_cycle.load(std::memory_order_relaxed); >+ sample->min_cycles_per_sample = >+ atomic->min_cycles_per_sample.load(std::memory_order_relaxed); >+ sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed); >+} >+ >+// Public routine. >+// Algorithm: We wish to compute real time from a cycle counter. In normal >+// operation, we construct a piecewise linear approximation to the kernel time >+// source, using the cycle counter value. The start of each line segment is at >+// the same point as the end of the last, but may have a different slope (that >+// is, a different idea of the cycle counter frequency). Every couple of >+// seconds, the kernel time source is sampled and compared with the current >+// approximation. A new slope is chosen that, if followed for another couple >+// of seconds, will correct the error at the current position. The information >+// for a sample is in the "last_sample" struct. The linear approximation is >+// estimated_time = last_sample.base_ns + >+// last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles) >+// (ns_per_cycle is actually stored in different units and scaled, to avoid >+// overflow). The base_ns of the next linear approximation is the >+// estimated_time using the last approximation; the base_cycles is the cycle >+// counter value at that time; the ns_per_cycle is the number of ns per cycle >+// measured since the last sample, but adjusted so that most of the difference >+// between the estimated_time and the kernel time will be corrected by the >+// estimated time to the next sample. In normal operation, this algorithm >+// relies on: >+// - the cycle counter and kernel time rates not changing a lot in a few >+// seconds. >+// - the client calling into the code often compared to a couple of seconds, so >+// the time to the next correction can be estimated. >+// Any time ns_per_cycle is not known, a major error is detected, or the >+// assumption about frequent calls is violated, the implementation returns the >+// kernel time. It records sufficient data that a linear approximation can >+// resume a little later. >+ >+int64_t GetCurrentTimeNanos() { >+ // read the data from the "last_sample" struct (but don't need raw_ns yet) >+ // The reads of "seq" and test of the values emulate a reader lock. >+ uint64_t base_ns; >+ uint64_t base_cycles; >+ uint64_t nsscaled_per_cycle; >+ uint64_t min_cycles_per_sample; >+ uint64_t seq_read0; >+ uint64_t seq_read1; >+ >+ // If we have enough information to interpolate, the value returned will be >+ // derived from this cycleclock-derived time estimate. On some platforms >+ // (POWER) the function to retrieve this value has enough complexity to >+ // contribute to register pressure - reading it early before initializing >+ // the other pieces of the calculation minimizes spill/restore instructions, >+ // minimizing icache cost. >+ uint64_t now_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); >+ >+ // Acquire pairs with the barrier in SeqRelease - if this load sees that >+ // store, the shared-data reads necessarily see that SeqRelease's updates >+ // to the same shared data. >+ seq_read0 = seq.load(std::memory_order_acquire); >+ >+ base_ns = last_sample.base_ns.load(std::memory_order_relaxed); >+ base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed); >+ nsscaled_per_cycle = >+ last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed); >+ min_cycles_per_sample = >+ last_sample.min_cycles_per_sample.load(std::memory_order_relaxed); >+ >+ // This acquire fence pairs with the release fence in SeqAcquire. Since it >+ // is sequenced between reads of shared data and seq_read1, the reads of >+ // shared data are effectively acquiring. >+ std::atomic_thread_fence(std::memory_order_acquire); >+ >+ // The shared-data reads are effectively acquire ordered, and the >+ // shared-data writes are effectively release ordered. Therefore if our >+ // shared-data reads see any of a particular update's shared-data writes, >+ // seq_read1 is guaranteed to see that update's SeqAcquire. >+ seq_read1 = seq.load(std::memory_order_relaxed); >+ >+ // Fast path. Return if min_cycles_per_sample has not yet elapsed since the >+ // last sample, and we read a consistent sample. The fast path activates >+ // only when min_cycles_per_sample is non-zero, which happens when we get an >+ // estimate for the cycle time. The predicate will fail if now_cycles < >+ // base_cycles, or if some other thread is in the slow path. >+ // >+ // Since we now read now_cycles before base_ns, it is possible for now_cycles >+ // to be less than base_cycles (if we were interrupted between those loads and >+ // last_sample was updated). This is harmless, because delta_cycles will wrap >+ // and report a time much much bigger than min_cycles_per_sample. In that case >+ // we will take the slow path. >+ uint64_t delta_cycles = now_cycles - base_cycles; >+ if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 && >+ delta_cycles < min_cycles_per_sample) { >+ return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale); >+ } >+ return GetCurrentTimeNanosSlowPath(); >+} >+ >+// Return (a << kScale)/b. >+// Zero is returned if b==0. Scaling is performed internally to >+// preserve precision without overflow. >+static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) { >+ // Find maximum safe_shift so that >+ // 0 <= safe_shift <= kScale and (a << safe_shift) does not overflow. >+ int safe_shift = kScale; >+ while (((a << safe_shift) >> safe_shift) != a) { >+ safe_shift--; >+ } >+ uint64_t scaled_b = b >> (kScale - safe_shift); >+ uint64_t quotient = 0; >+ if (scaled_b != 0) { >+ quotient = (a << safe_shift) / scaled_b; >+ } >+ return quotient; >+} >+ >+static uint64_t UpdateLastSample( >+ uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles, >+ const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD; >+ >+// The slow path of GetCurrentTimeNanos(). This is taken while gathering >+// initial samples, when enough time has elapsed since the last sample, and if >+// any other thread is writing to last_sample. >+// >+// Manually mark this 'noinline' to minimize stack frame size of the fast >+// path. Without this, sometimes a compiler may inline this big block of code >+// into the fast past. That causes lots of register spills and reloads that >+// are unnecessary unless the slow path is taken. >+// >+// TODO(absl-team): Remove this attribute when our compiler is smart enough >+// to do the right thing. >+ABSL_ATTRIBUTE_NOINLINE >+static int64_t GetCurrentTimeNanosSlowPath() LOCKS_EXCLUDED(lock) { >+ // Serialize access to slow-path. Fast-path readers are not blocked yet, and >+ // code below must not modify last_sample until the seqlock is acquired. >+ lock.Lock(); >+ >+ // Sample the kernel time base. This is the definition of >+ // "now" if we take the slow path. >+ static uint64_t last_now_cycles; // protected by lock >+ uint64_t now_cycles; >+ uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles); >+ last_now_cycles = now_cycles; >+ >+ uint64_t estimated_base_ns; >+ >+ // ---------- >+ // Read the "last_sample" values again; this time holding the write lock. >+ struct TimeSample sample; >+ ReadTimeSampleAtomic(&last_sample, &sample); >+ >+ // ---------- >+ // Try running the fast path again; another thread may have updated the >+ // sample between our run of the fast path and the sample we just read. >+ uint64_t delta_cycles = now_cycles - sample.base_cycles; >+ if (delta_cycles < sample.min_cycles_per_sample) { >+ // Another thread updated the sample. This path does not take the seqlock >+ // so that blocked readers can make progress without blocking new readers. >+ estimated_base_ns = sample.base_ns + >+ ((delta_cycles * sample.nsscaled_per_cycle) >> kScale); >+ stats_fast_slow_paths++; >+ } else { >+ estimated_base_ns = >+ UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample); >+ } >+ >+ lock.Unlock(); >+ >+ return estimated_base_ns; >+} >+ >+// Main part of the algorithm. Locks out readers, updates the approximation >+// using the new sample from the kernel, and stores the result in last_sample >+// for readers. Returns the new estimated time. >+static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns, >+ uint64_t delta_cycles, >+ const struct TimeSample *sample) >+ EXCLUSIVE_LOCKS_REQUIRED(lock) { >+ uint64_t estimated_base_ns = now_ns; >+ uint64_t lock_value = SeqAcquire(&seq); // acquire seqlock to block readers >+ >+ // The 5s in the next if-statement limits the time for which we will trust >+ // the cycle counter and our last sample to give a reasonable result. >+ // Errors in the rate of the source clock can be multiplied by the ratio >+ // between this limit and kMinNSBetweenSamples. >+ if (sample->raw_ns == 0 || // no recent sample, or clock went backwards >+ sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns || >+ now_ns < sample->raw_ns || now_cycles < sample->base_cycles) { >+ // record this sample, and forget any previously known slope. >+ last_sample.raw_ns.store(now_ns, std::memory_order_relaxed); >+ last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed); >+ last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed); >+ last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed); >+ last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed); >+ stats_initializations++; >+ } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns && >+ sample->base_cycles + 100 < now_cycles) { >+ // Enough time has passed to compute the cycle time. >+ if (sample->nsscaled_per_cycle != 0) { // Have a cycle time estimate. >+ // Compute time from counter reading, but avoiding overflow >+ // delta_cycles may be larger than on the fast path. >+ uint64_t estimated_scaled_ns; >+ int s = -1; >+ do { >+ s++; >+ estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle; >+ } while (estimated_scaled_ns / sample->nsscaled_per_cycle != >+ (delta_cycles >> s)); >+ estimated_base_ns = sample->base_ns + >+ (estimated_scaled_ns >> (kScale - s)); >+ } >+ >+ // Compute the assumed cycle time kMinNSBetweenSamples ns into the future >+ // assuming the cycle counter rate stays the same as the last interval. >+ uint64_t ns = now_ns - sample->raw_ns; >+ uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles); >+ >+ uint64_t assumed_next_sample_delta_cycles = >+ SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle); >+ >+ int64_t diff_ns = now_ns - estimated_base_ns; // estimate low by this much >+ >+ // We want to set nsscaled_per_cycle so that our estimate of the ns time >+ // at the assumed cycle time is the assumed ns time. >+ // That is, we want to set nsscaled_per_cycle so: >+ // kMinNSBetweenSamples + diff_ns == >+ // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale >+ // But we wish to damp oscillations, so instead correct only most >+ // of our current error, by solving: >+ // kMinNSBetweenSamples + diff_ns - (diff_ns / 16) == >+ // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale >+ ns = kMinNSBetweenSamples + diff_ns - (diff_ns / 16); >+ uint64_t new_nsscaled_per_cycle = >+ SafeDivideAndScale(ns, assumed_next_sample_delta_cycles); >+ if (new_nsscaled_per_cycle != 0 && >+ diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) { >+ // record the cycle time measurement >+ last_sample.nsscaled_per_cycle.store( >+ new_nsscaled_per_cycle, std::memory_order_relaxed); >+ uint64_t new_min_cycles_per_sample = >+ SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle); >+ last_sample.min_cycles_per_sample.store( >+ new_min_cycles_per_sample, std::memory_order_relaxed); >+ stats_calibrations++; >+ } else { // something went wrong; forget the slope >+ last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed); >+ last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed); >+ estimated_base_ns = now_ns; >+ stats_reinitializations++; >+ } >+ last_sample.raw_ns.store(now_ns, std::memory_order_relaxed); >+ last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed); >+ last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed); >+ } else { >+ // have a sample, but no slope; waiting for enough time for a calibration >+ stats_slow_paths++; >+ } >+ >+ SeqRelease(&seq, lock_value); // release the readers >+ >+ return estimated_base_ns; >+} >+} // namespace absl >+#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS >+ >+namespace absl { >+namespace { >+ >+// Returns the maximum duration that SleepOnce() can sleep for. >+constexpr absl::Duration MaxSleep() { >+#ifdef _WIN32 >+ // Windows Sleep() takes unsigned long argument in milliseconds. >+ return absl::Milliseconds( >+ std::numeric_limits<unsigned long>::max()); // NOLINT(runtime/int) >+#else >+ return absl::Seconds(std::numeric_limits<time_t>::max()); >+#endif >+} >+ >+// Sleeps for the given duration. >+// REQUIRES: to_sleep <= MaxSleep(). >+void SleepOnce(absl::Duration to_sleep) { >+#ifdef _WIN32 >+ Sleep(to_sleep / absl::Milliseconds(1)); >+#else >+ struct timespec sleep_time = absl::ToTimespec(to_sleep); >+ while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) { >+ // Ignore signals and wait for the full interval to elapse. >+ } >+#endif >+} >+ >+} // namespace >+} // namespace absl >+ >+extern "C" { >+ >+ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) { >+ while (duration > absl::ZeroDuration()) { >+ absl::Duration to_sleep = std::min(duration, absl::MaxSleep()); >+ absl::SleepOnce(to_sleep); >+ duration -= to_sleep; >+ } >+} >+ >+} // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.h >new file mode 100644 >index 00000000000..3753d4ee43a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock.h >@@ -0,0 +1,72 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: clock.h >+// ----------------------------------------------------------------------------- >+// >+// This header file contains utility functions for working with the system-wide >+// realtime clock. For descriptions of the main time abstractions used within >+// this header file, consult the time.h header file. >+#ifndef ABSL_TIME_CLOCK_H_ >+#define ABSL_TIME_CLOCK_H_ >+ >+#include "absl/base/macros.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+ >+// Now() >+// >+// Returns the current time, expressed as an `absl::Time` absolute time value. >+absl::Time Now(); >+ >+// GetCurrentTimeNanos() >+// >+// Returns the current time, expressed as a count of nanoseconds since the Unix >+// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead >+// for all but the most performance-sensitive cases (i.e. when you are calling >+// this function hundreds of thousands of times per second). >+int64_t GetCurrentTimeNanos(); >+ >+// SleepFor() >+// >+// Sleeps for the specified duration, expressed as an `absl::Duration`. >+// >+// Notes: >+// * Signal interruptions will not reduce the sleep duration. >+// * Returns immediately when passed a nonpositive duration. >+void SleepFor(absl::Duration duration); >+ >+} // namespace absl >+ >+// ----------------------------------------------------------------------------- >+// Implementation Details >+// ----------------------------------------------------------------------------- >+ >+// In some build configurations we pass --detect-odr-violations to the >+// gold linker. This causes it to flag weak symbol overrides as ODR >+// violations. Because ODR only applies to C++ and not C, >+// --detect-odr-violations ignores symbols not mangled with C++ names. >+// By changing our extension points to be extern "C", we dodge this >+// check. >+extern "C" { >+void AbslInternalSleepFor(absl::Duration duration); >+} // extern "C" >+ >+inline void absl::SleepFor(absl::Duration duration) { >+ AbslInternalSleepFor(duration); >+} >+ >+#endif // ABSL_TIME_CLOCK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_benchmark.cc >new file mode 100644 >index 00000000000..3d3cd9d5c42 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_benchmark.cc >@@ -0,0 +1,72 @@ >+// Copyright 2018 The Abseil Authors. >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/clock.h" >+ >+#if !defined(_WIN32) >+#include <sys/time.h> >+#endif // _WIN32 >+#include <cstdio> >+ >+#include "absl/base/internal/cycleclock.h" >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+void BM_Clock_Now_AbslTime(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Now()); >+ } >+} >+BENCHMARK(BM_Clock_Now_AbslTime); >+ >+void BM_Clock_Now_GetCurrentTimeNanos(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::GetCurrentTimeNanos()); >+ } >+} >+BENCHMARK(BM_Clock_Now_GetCurrentTimeNanos); >+ >+void BM_Clock_Now_AbslTime_ToUnixNanos(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToUnixNanos(absl::Now())); >+ } >+} >+BENCHMARK(BM_Clock_Now_AbslTime_ToUnixNanos); >+ >+void BM_Clock_Now_CycleClock(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::base_internal::CycleClock::Now()); >+ } >+} >+BENCHMARK(BM_Clock_Now_CycleClock); >+ >+#if !defined(_WIN32) >+static void BM_Clock_Now_gettimeofday(benchmark::State& state) { >+ struct timeval tv; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(gettimeofday(&tv, nullptr)); >+ } >+} >+BENCHMARK(BM_Clock_Now_gettimeofday); >+ >+static void BM_Clock_Now_clock_gettime(benchmark::State& state) { >+ struct timespec ts; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ts)); >+ } >+} >+BENCHMARK(BM_Clock_Now_clock_gettime); >+#endif // _WIN32 >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_test.cc >new file mode 100644 >index 00000000000..707166d0c28 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/clock_test.cc >@@ -0,0 +1,118 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/clock.h" >+ >+#include "absl/base/config.h" >+#if defined(ABSL_HAVE_ALARM) >+#include <signal.h> >+#include <unistd.h> >+#elif defined(__linux__) || defined(__APPLE__) >+#error all known Linux and Apple targets have alarm >+#endif >+ >+#include "gtest/gtest.h" >+#include "absl/time/time.h" >+ >+namespace { >+ >+TEST(Time, Now) { >+ const absl::Time before = absl::FromUnixNanos(absl::GetCurrentTimeNanos()); >+ const absl::Time now = absl::Now(); >+ const absl::Time after = absl::FromUnixNanos(absl::GetCurrentTimeNanos()); >+ EXPECT_GE(now, before); >+ EXPECT_GE(after, now); >+} >+ >+enum class AlarmPolicy { kWithoutAlarm, kWithAlarm }; >+ >+#if defined(ABSL_HAVE_ALARM) >+bool alarm_handler_invoked = false; >+ >+void AlarmHandler(int signo) { >+ ASSERT_EQ(signo, SIGALRM); >+ alarm_handler_invoked = true; >+} >+#endif >+ >+// Does SleepFor(d) take between lower_bound and upper_bound at least >+// once between now and (now + timeout)? If requested (and supported), >+// add an alarm for the middle of the sleep period and expect it to fire. >+bool SleepForBounded(absl::Duration d, absl::Duration lower_bound, >+ absl::Duration upper_bound, absl::Duration timeout, >+ AlarmPolicy alarm_policy, int* attempts) { >+ const absl::Time deadline = absl::Now() + timeout; >+ while (absl::Now() < deadline) { >+#if defined(ABSL_HAVE_ALARM) >+ sig_t old_alarm = SIG_DFL; >+ if (alarm_policy == AlarmPolicy::kWithAlarm) { >+ alarm_handler_invoked = false; >+ old_alarm = signal(SIGALRM, AlarmHandler); >+ alarm(absl::ToInt64Seconds(d / 2)); >+ } >+#else >+ EXPECT_EQ(alarm_policy, AlarmPolicy::kWithoutAlarm); >+#endif >+ ++*attempts; >+ absl::Time start = absl::Now(); >+ absl::SleepFor(d); >+ absl::Duration actual = absl::Now() - start; >+#if defined(ABSL_HAVE_ALARM) >+ if (alarm_policy == AlarmPolicy::kWithAlarm) { >+ signal(SIGALRM, old_alarm); >+ if (!alarm_handler_invoked) continue; >+ } >+#endif >+ if (lower_bound <= actual && actual <= upper_bound) { >+ return true; // yes, the SleepFor() was correctly bounded >+ } >+ } >+ return false; >+} >+ >+testing::AssertionResult AssertSleepForBounded(absl::Duration d, >+ absl::Duration early, >+ absl::Duration late, >+ absl::Duration timeout, >+ AlarmPolicy alarm_policy) { >+ const absl::Duration lower_bound = d - early; >+ const absl::Duration upper_bound = d + late; >+ int attempts = 0; >+ if (SleepForBounded(d, lower_bound, upper_bound, timeout, alarm_policy, >+ &attempts)) { >+ return testing::AssertionSuccess(); >+ } >+ return testing::AssertionFailure() >+ << "SleepFor(" << d << ") did not return within [" << lower_bound >+ << ":" << upper_bound << "] in " << attempts << " attempt" >+ << (attempts == 1 ? "" : "s") << " over " << timeout >+ << (alarm_policy == AlarmPolicy::kWithAlarm ? " with" : " without") >+ << " an alarm"; >+} >+ >+// Tests that SleepFor() returns neither too early nor too late. >+TEST(SleepFor, Bounded) { >+ const absl::Duration d = absl::Milliseconds(2500); >+ const absl::Duration early = absl::Milliseconds(100); >+ const absl::Duration late = absl::Milliseconds(300); >+ const absl::Duration timeout = 48 * d; >+ EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout, >+ AlarmPolicy::kWithoutAlarm)); >+#if defined(ABSL_HAVE_ALARM) >+ EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout, >+ AlarmPolicy::kWithAlarm)); >+#endif >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration.cc >new file mode 100644 >index 00000000000..f402137b0a6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration.cc >@@ -0,0 +1,904 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// The implementation of the absl::Duration class, which is declared in >+// //absl/time.h. This class behaves like a numeric type; it has no public >+// methods and is used only through the operators defined here. >+// >+// Implementation notes: >+// >+// An absl::Duration is represented as >+// >+// rep_hi_ : (int64_t) Whole seconds >+// rep_lo_ : (uint32_t) Fractions of a second >+// >+// The seconds value (rep_hi_) may be positive or negative as appropriate. >+// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_. >+// The API for Duration guarantees at least nanosecond resolution, which >+// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds. >+// However, to utilize more of the available 32 bits of space in rep_lo_, >+// we instead store quarters of a nanosecond in rep_lo_ resulting in a max >+// value of 4B - 1. This allows us to correctly handle calculations like >+// 0.5 nanos + 0.5 nanos = 1 nano. The following example shows the actual >+// Duration rep using quarters of a nanosecond. >+// >+// 2.5 sec = {rep_hi_=2, rep_lo_=2000000000} // lo = 4 * 500000000 >+// -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000} >+// >+// Infinite durations are represented as Durations with the rep_lo_ field set >+// to all 1s. >+// >+// +InfiniteDuration: >+// rep_hi_ : kint64max >+// rep_lo_ : ~0U >+// >+// -InfiniteDuration: >+// rep_hi_ : kint64min >+// rep_lo_ : ~0U >+// >+// Arithmetic overflows/underflows to +/- infinity and saturates. >+ >+#include <algorithm> >+#include <cassert> >+#include <cctype> >+#include <cerrno> >+#include <cmath> >+#include <cstdint> >+#include <cstdlib> >+#include <cstring> >+#include <ctime> >+#include <functional> >+#include <limits> >+#include <string> >+ >+#include "absl/base/casts.h" >+#include "absl/numeric/int128.h" >+#include "absl/time/time.h" >+ >+namespace absl { >+ >+namespace { >+ >+using time_internal::kTicksPerNanosecond; >+using time_internal::kTicksPerSecond; >+ >+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max(); >+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min(); >+ >+// Can't use std::isinfinite() because it doesn't exist on windows. >+inline bool IsFinite(double d) { >+ return d != std::numeric_limits<double>::infinity() && >+ d != -std::numeric_limits<double>::infinity(); >+} >+ >+// Can't use std::round() because it is only available in C++11. >+// Note that we ignore the possibility of floating-point over/underflow. >+template <typename Double> >+inline double Round(Double d) { >+ return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5); >+} >+ >+// *sec may be positive or negative. *ticks must be in the range >+// -kTicksPerSecond < *ticks < kTicksPerSecond. If *ticks is negative it >+// will be normalized to a positive value by adjusting *sec accordingly. >+inline void NormalizeTicks(int64_t* sec, int64_t* ticks) { >+ if (*ticks < 0) { >+ --*sec; >+ *ticks += kTicksPerSecond; >+ } >+} >+ >+// Makes a uint128 from the absolute value of the given scalar. >+inline uint128 MakeU128(int64_t a) { >+ uint128 u128 = 0; >+ if (a < 0) { >+ ++u128; >+ ++a; // Makes it safe to negate 'a' >+ a = -a; >+ } >+ u128 += static_cast<uint64_t>(a); >+ return u128; >+} >+ >+// Makes a uint128 count of ticks out of the absolute value of the Duration. >+inline uint128 MakeU128Ticks(Duration d) { >+ int64_t rep_hi = time_internal::GetRepHi(d); >+ uint32_t rep_lo = time_internal::GetRepLo(d); >+ if (rep_hi < 0) { >+ ++rep_hi; >+ rep_hi = -rep_hi; >+ rep_lo = kTicksPerSecond - rep_lo; >+ } >+ uint128 u128 = static_cast<uint64_t>(rep_hi); >+ u128 *= static_cast<uint64_t>(kTicksPerSecond); >+ u128 += rep_lo; >+ return u128; >+} >+ >+// Breaks a uint128 of ticks into a Duration. >+inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) { >+ int64_t rep_hi; >+ uint32_t rep_lo; >+ const uint64_t h64 = Uint128High64(u128); >+ const uint64_t l64 = Uint128Low64(u128); >+ if (h64 == 0) { // fastpath >+ const uint64_t hi = l64 / kTicksPerSecond; >+ rep_hi = static_cast<int64_t>(hi); >+ rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond); >+ } else { >+ // kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond). >+ // Any positive tick count whose high 64 bits are >= kMaxRepHi64 >+ // is not representable as a Duration. A negative tick count can >+ // have its high 64 bits == kMaxRepHi64 but only when the low 64 >+ // bits are all zero, otherwise it is not representable either. >+ const uint64_t kMaxRepHi64 = 0x77359400UL; >+ if (h64 >= kMaxRepHi64) { >+ if (is_neg && h64 == kMaxRepHi64 && l64 == 0) { >+ // Avoid trying to represent -kint64min below. >+ return time_internal::MakeDuration(kint64min); >+ } >+ return is_neg ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond); >+ const uint128 hi = u128 / kTicksPerSecond128; >+ rep_hi = static_cast<int64_t>(Uint128Low64(hi)); >+ rep_lo = >+ static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128)); >+ } >+ if (is_neg) { >+ rep_hi = -rep_hi; >+ if (rep_lo != 0) { >+ --rep_hi; >+ rep_lo = kTicksPerSecond - rep_lo; >+ } >+ } >+ return time_internal::MakeDuration(rep_hi, rep_lo); >+} >+ >+// Convert between int64_t and uint64_t, preserving representation. This >+// allows us to do arithmetic in the unsigned domain, where overflow has >+// well-defined behavior. See operator+=() and operator-=(). >+// >+// C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef >+// name intN_t designates a signed integer type with width N, no padding >+// bits, and a two's complement representation." So, we can convert to >+// and from the corresponding uint64_t value using a bit cast. >+inline uint64_t EncodeTwosComp(int64_t v) { >+ return absl::bit_cast<uint64_t>(v); >+} >+inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); } >+ >+// Note: The overflow detection in this function is done using greater/less *or >+// equal* because kint64max/min is too large to be represented exactly in a >+// double (which only has 53 bits of precision). In order to avoid assigning to >+// rep->hi a double value that is too large for an int64_t (and therefore is >+// undefined), we must consider computations that equal kint64max/min as a >+// double as overflow cases. >+inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) { >+ double c = a_hi + b_hi; >+ if (c >= kint64max) { >+ *d = InfiniteDuration(); >+ return false; >+ } >+ if (c <= kint64min) { >+ *d = -InfiniteDuration(); >+ return false; >+ } >+ *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d)); >+ return true; >+} >+ >+// A functor that's similar to std::multiplies<T>, except this returns the max >+// T value instead of overflowing. This is only defined for uint128. >+template <typename Ignored> >+struct SafeMultiply { >+ uint128 operator()(uint128 a, uint128 b) const { >+ // b hi is always zero because it originated as an int64_t. >+ assert(Uint128High64(b) == 0); >+ // Fastpath to avoid the expensive overflow check with division. >+ if (Uint128High64(a) == 0) { >+ return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0) >+ ? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b)) >+ : a * b; >+ } >+ return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b; >+ } >+}; >+ >+// Scales (i.e., multiplies or divides, depending on the Operation template) >+// the Duration d by the int64_t r. >+template <template <typename> class Operation> >+inline Duration ScaleFixed(Duration d, int64_t r) { >+ const uint128 a = MakeU128Ticks(d); >+ const uint128 b = MakeU128(r); >+ const uint128 q = Operation<uint128>()(a, b); >+ const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0); >+ return MakeDurationFromU128(q, is_neg); >+} >+ >+// Scales (i.e., multiplies or divides, depending on the Operation template) >+// the Duration d by the double r. >+template <template <typename> class Operation> >+inline Duration ScaleDouble(Duration d, double r) { >+ Operation<double> op; >+ double hi_doub = op(time_internal::GetRepHi(d), r); >+ double lo_doub = op(time_internal::GetRepLo(d), r); >+ >+ double hi_int = 0; >+ double hi_frac = std::modf(hi_doub, &hi_int); >+ >+ // Moves hi's fractional bits to lo. >+ lo_doub /= kTicksPerSecond; >+ lo_doub += hi_frac; >+ >+ double lo_int = 0; >+ double lo_frac = std::modf(lo_doub, &lo_int); >+ >+ // Rolls lo into hi if necessary. >+ int64_t lo64 = Round(lo_frac * kTicksPerSecond); >+ >+ Duration ans; >+ if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans; >+ int64_t hi64 = time_internal::GetRepHi(ans); >+ if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans; >+ hi64 = time_internal::GetRepHi(ans); >+ lo64 %= kTicksPerSecond; >+ NormalizeTicks(&hi64, &lo64); >+ return time_internal::MakeDuration(hi64, lo64); >+} >+ >+// Tries to divide num by den as fast as possible by looking for common, easy >+// cases. If the division was done, the quotient is in *q and the remainder is >+// in *rem and true will be returned. >+inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q, >+ Duration* rem) { >+ // Bail if num or den is an infinity. >+ if (time_internal::IsInfiniteDuration(num) || >+ time_internal::IsInfiniteDuration(den)) >+ return false; >+ >+ int64_t num_hi = time_internal::GetRepHi(num); >+ uint32_t num_lo = time_internal::GetRepLo(num); >+ int64_t den_hi = time_internal::GetRepHi(den); >+ uint32_t den_lo = time_internal::GetRepLo(den); >+ >+ if (den_hi == 0 && den_lo == kTicksPerNanosecond) { >+ // Dividing by 1ns >+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) { >+ *q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond; >+ *rem = time_internal::MakeDuration(0, num_lo % den_lo); >+ return true; >+ } >+ } else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) { >+ // Dividing by 100ns (common when converting to Universal time) >+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) { >+ *q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond); >+ *rem = time_internal::MakeDuration(0, num_lo % den_lo); >+ return true; >+ } >+ } else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) { >+ // Dividing by 1us >+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) { >+ *q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond); >+ *rem = time_internal::MakeDuration(0, num_lo % den_lo); >+ return true; >+ } >+ } else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) { >+ // Dividing by 1ms >+ if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) { >+ *q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond); >+ *rem = time_internal::MakeDuration(0, num_lo % den_lo); >+ return true; >+ } >+ } else if (den_hi > 0 && den_lo == 0) { >+ // Dividing by positive multiple of 1s >+ if (num_hi >= 0) { >+ if (den_hi == 1) { >+ *q = num_hi; >+ *rem = time_internal::MakeDuration(0, num_lo); >+ return true; >+ } >+ *q = num_hi / den_hi; >+ *rem = time_internal::MakeDuration(num_hi % den_hi, num_lo); >+ return true; >+ } >+ if (num_lo != 0) { >+ num_hi += 1; >+ } >+ int64_t quotient = num_hi / den_hi; >+ int64_t rem_sec = num_hi % den_hi; >+ if (rem_sec > 0) { >+ rem_sec -= den_hi; >+ quotient += 1; >+ } >+ if (num_lo != 0) { >+ rem_sec -= 1; >+ } >+ *q = quotient; >+ *rem = time_internal::MakeDuration(rem_sec, num_lo); >+ return true; >+ } >+ >+ return false; >+} >+ >+} // namespace >+ >+namespace time_internal { >+ >+// The 'satq' argument indicates whether the quotient should saturate at the >+// bounds of int64_t. If it does saturate, the difference will spill over to >+// the remainder. If it does not saturate, the remainder remain accurate, >+// but the returned quotient will over/underflow int64_t and should not be used. >+int64_t IDivDuration(bool satq, const Duration num, const Duration den, >+ Duration* rem) { >+ int64_t q = 0; >+ if (IDivFastPath(num, den, &q, rem)) { >+ return q; >+ } >+ >+ const bool num_neg = num < ZeroDuration(); >+ const bool den_neg = den < ZeroDuration(); >+ const bool quotient_neg = num_neg != den_neg; >+ >+ if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) { >+ *rem = num_neg ? -InfiniteDuration() : InfiniteDuration(); >+ return quotient_neg ? kint64min : kint64max; >+ } >+ if (time_internal::IsInfiniteDuration(den)) { >+ *rem = num; >+ return 0; >+ } >+ >+ const uint128 a = MakeU128Ticks(num); >+ const uint128 b = MakeU128Ticks(den); >+ uint128 quotient128 = a / b; >+ >+ if (satq) { >+ // Limits the quotient to the range of int64_t. >+ if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) { >+ quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min)) >+ : uint128(static_cast<uint64_t>(kint64max)); >+ } >+ } >+ >+ const uint128 remainder128 = a - quotient128 * b; >+ *rem = MakeDurationFromU128(remainder128, num_neg); >+ >+ if (!quotient_neg || quotient128 == 0) { >+ return Uint128Low64(quotient128) & kint64max; >+ } >+ // The quotient needs to be negated, but we need to carefully handle >+ // quotient128s with the top bit on. >+ return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1; >+} >+ >+} // namespace time_internal >+ >+// >+// Additive operators. >+// >+ >+Duration& Duration::operator+=(Duration rhs) { >+ if (time_internal::IsInfiniteDuration(*this)) return *this; >+ if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs; >+ const int64_t orig_rep_hi = rep_hi_; >+ rep_hi_ = >+ DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_)); >+ if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) { >+ rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1); >+ rep_lo_ -= kTicksPerSecond; >+ } >+ rep_lo_ += rhs.rep_lo_; >+ if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) { >+ return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this; >+} >+ >+Duration& Duration::operator-=(Duration rhs) { >+ if (time_internal::IsInfiniteDuration(*this)) return *this; >+ if (time_internal::IsInfiniteDuration(rhs)) { >+ return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ const int64_t orig_rep_hi = rep_hi_; >+ rep_hi_ = >+ DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_)); >+ if (rep_lo_ < rhs.rep_lo_) { >+ rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1); >+ rep_lo_ += kTicksPerSecond; >+ } >+ rep_lo_ -= rhs.rep_lo_; >+ if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) { >+ return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this; >+} >+ >+// >+// Multiplicative operators. >+// >+ >+Duration& Duration::operator*=(int64_t r) { >+ if (time_internal::IsInfiniteDuration(*this)) { >+ const bool is_neg = (r < 0) != (rep_hi_ < 0); >+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this = ScaleFixed<SafeMultiply>(*this, r); >+} >+ >+Duration& Duration::operator*=(double r) { >+ if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) { >+ const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); >+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this = ScaleDouble<std::multiplies>(*this, r); >+} >+ >+Duration& Duration::operator/=(int64_t r) { >+ if (time_internal::IsInfiniteDuration(*this) || r == 0) { >+ const bool is_neg = (r < 0) != (rep_hi_ < 0); >+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this = ScaleFixed<std::divides>(*this, r); >+} >+ >+Duration& Duration::operator/=(double r) { >+ if (time_internal::IsInfiniteDuration(*this) || r == 0.0) { >+ const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); >+ return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); >+ } >+ return *this = ScaleDouble<std::divides>(*this, r); >+} >+ >+Duration& Duration::operator%=(Duration rhs) { >+ time_internal::IDivDuration(false, *this, rhs, this); >+ return *this; >+} >+ >+double FDivDuration(Duration num, Duration den) { >+ // Arithmetic with infinity is sticky. >+ if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) { >+ return (num < ZeroDuration()) == (den < ZeroDuration()) >+ ? std::numeric_limits<double>::infinity() >+ : -std::numeric_limits<double>::infinity(); >+ } >+ if (time_internal::IsInfiniteDuration(den)) return 0.0; >+ >+ double a = >+ static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond + >+ time_internal::GetRepLo(num); >+ double b = >+ static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond + >+ time_internal::GetRepLo(den); >+ return a / b; >+} >+ >+// >+// Trunc/Floor/Ceil. >+// >+ >+Duration Trunc(Duration d, Duration unit) { >+ return d - (d % unit); >+} >+ >+Duration Floor(const Duration d, const Duration unit) { >+ const absl::Duration td = Trunc(d, unit); >+ return td <= d ? td : td - AbsDuration(unit); >+} >+ >+Duration Ceil(const Duration d, const Duration unit) { >+ const absl::Duration td = Trunc(d, unit); >+ return td >= d ? td : td + AbsDuration(unit); >+} >+ >+// >+// Factory functions. >+// >+ >+Duration DurationFromTimespec(timespec ts) { >+ if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) { >+ int64_t ticks = ts.tv_nsec * kTicksPerNanosecond; >+ return time_internal::MakeDuration(ts.tv_sec, ticks); >+ } >+ return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec); >+} >+ >+Duration DurationFromTimeval(timeval tv) { >+ if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) { >+ int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond; >+ return time_internal::MakeDuration(tv.tv_sec, ticks); >+ } >+ return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec); >+} >+ >+// >+// Conversion to other duration types. >+// >+ >+int64_t ToInt64Nanoseconds(Duration d) { >+ if (time_internal::GetRepHi(d) >= 0 && >+ time_internal::GetRepHi(d) >> 33 == 0) { >+ return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) + >+ (time_internal::GetRepLo(d) / kTicksPerNanosecond); >+ } >+ return d / Nanoseconds(1); >+} >+int64_t ToInt64Microseconds(Duration d) { >+ if (time_internal::GetRepHi(d) >= 0 && >+ time_internal::GetRepHi(d) >> 43 == 0) { >+ return (time_internal::GetRepHi(d) * 1000 * 1000) + >+ (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000)); >+ } >+ return d / Microseconds(1); >+} >+int64_t ToInt64Milliseconds(Duration d) { >+ if (time_internal::GetRepHi(d) >= 0 && >+ time_internal::GetRepHi(d) >> 53 == 0) { >+ return (time_internal::GetRepHi(d) * 1000) + >+ (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000)); >+ } >+ return d / Milliseconds(1); >+} >+int64_t ToInt64Seconds(Duration d) { >+ int64_t hi = time_internal::GetRepHi(d); >+ if (time_internal::IsInfiniteDuration(d)) return hi; >+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; >+ return hi; >+} >+int64_t ToInt64Minutes(Duration d) { >+ int64_t hi = time_internal::GetRepHi(d); >+ if (time_internal::IsInfiniteDuration(d)) return hi; >+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; >+ return hi / 60; >+} >+int64_t ToInt64Hours(Duration d) { >+ int64_t hi = time_internal::GetRepHi(d); >+ if (time_internal::IsInfiniteDuration(d)) return hi; >+ if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; >+ return hi / (60 * 60); >+} >+ >+double ToDoubleNanoseconds(Duration d) { >+ return FDivDuration(d, Nanoseconds(1)); >+} >+double ToDoubleMicroseconds(Duration d) { >+ return FDivDuration(d, Microseconds(1)); >+} >+double ToDoubleMilliseconds(Duration d) { >+ return FDivDuration(d, Milliseconds(1)); >+} >+double ToDoubleSeconds(Duration d) { >+ return FDivDuration(d, Seconds(1)); >+} >+double ToDoubleMinutes(Duration d) { >+ return FDivDuration(d, Minutes(1)); >+} >+double ToDoubleHours(Duration d) { >+ return FDivDuration(d, Hours(1)); >+} >+ >+timespec ToTimespec(Duration d) { >+ timespec ts; >+ if (!time_internal::IsInfiniteDuration(d)) { >+ int64_t rep_hi = time_internal::GetRepHi(d); >+ uint32_t rep_lo = time_internal::GetRepLo(d); >+ if (rep_hi < 0) { >+ // Tweak the fields so that unsigned division of rep_lo >+ // maps to truncation (towards zero) for the timespec. >+ rep_lo += kTicksPerNanosecond - 1; >+ if (rep_lo >= kTicksPerSecond) { >+ rep_hi += 1; >+ rep_lo -= kTicksPerSecond; >+ } >+ } >+ ts.tv_sec = rep_hi; >+ if (ts.tv_sec == rep_hi) { // no time_t narrowing >+ ts.tv_nsec = rep_lo / kTicksPerNanosecond; >+ return ts; >+ } >+ } >+ if (d >= ZeroDuration()) { >+ ts.tv_sec = std::numeric_limits<time_t>::max(); >+ ts.tv_nsec = 1000 * 1000 * 1000 - 1; >+ } else { >+ ts.tv_sec = std::numeric_limits<time_t>::min(); >+ ts.tv_nsec = 0; >+ } >+ return ts; >+} >+ >+timeval ToTimeval(Duration d) { >+ timeval tv; >+ timespec ts = ToTimespec(d); >+ if (ts.tv_sec < 0) { >+ // Tweak the fields so that positive division of tv_nsec >+ // maps to truncation (towards zero) for the timeval. >+ ts.tv_nsec += 1000 - 1; >+ if (ts.tv_nsec >= 1000 * 1000 * 1000) { >+ ts.tv_sec += 1; >+ ts.tv_nsec -= 1000 * 1000 * 1000; >+ } >+ } >+ tv.tv_sec = ts.tv_sec; >+ if (tv.tv_sec != ts.tv_sec) { // narrowing >+ if (ts.tv_sec < 0) { >+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min(); >+ tv.tv_usec = 0; >+ } else { >+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max(); >+ tv.tv_usec = 1000 * 1000 - 1; >+ } >+ return tv; >+ } >+ tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t >+ return tv; >+} >+ >+std::chrono::nanoseconds ToChronoNanoseconds(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d); >+} >+std::chrono::microseconds ToChronoMicroseconds(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::microseconds>(d); >+} >+std::chrono::milliseconds ToChronoMilliseconds(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::milliseconds>(d); >+} >+std::chrono::seconds ToChronoSeconds(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::seconds>(d); >+} >+std::chrono::minutes ToChronoMinutes(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::minutes>(d); >+} >+std::chrono::hours ToChronoHours(Duration d) { >+ return time_internal::ToChronoDuration<std::chrono::hours>(d); >+} >+ >+// >+// To/From std::string formatting. >+// >+ >+namespace { >+ >+// Formats a positive 64-bit integer in the given field width. Note that >+// it is up to the caller of Format64() to ensure that there is sufficient >+// space before ep to hold the conversion. >+char* Format64(char* ep, int width, int64_t v) { >+ do { >+ --width; >+ *--ep = '0' + (v % 10); // contiguous digits >+ } while (v /= 10); >+ while (--width >= 0) *--ep = '0'; // zero pad >+ return ep; >+} >+ >+// Helpers for FormatDuration() that format 'n' and append it to 'out' >+// followed by the given 'unit'. If 'n' formats to "0", nothing is >+// appended (not even the unit). >+ >+// A type that encapsulates how to display a value of a particular unit. For >+// values that are displayed with fractional parts, the precision indicates >+// where to round the value. The precision varies with the display unit because >+// a Duration can hold only quarters of a nanosecond, so displaying information >+// beyond that is just noise. >+// >+// For example, a microsecond value of 42.00025xxxxx should not display beyond 5 >+// fractional digits, because it is in the noise of what a Duration can >+// represent. >+struct DisplayUnit { >+ const char* abbr; >+ int prec; >+ double pow10; >+}; >+const DisplayUnit kDisplayNano = {"ns", 2, 1e2}; >+const DisplayUnit kDisplayMicro = {"us", 5, 1e5}; >+const DisplayUnit kDisplayMilli = {"ms", 8, 1e8}; >+const DisplayUnit kDisplaySec = {"s", 11, 1e11}; >+const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored >+const DisplayUnit kDisplayHour = {"h", -1, 0.0}; // prec ignored >+ >+void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) { >+ char buf[sizeof("2562047788015216")]; // hours in max duration >+ char* const ep = buf + sizeof(buf); >+ char* bp = Format64(ep, 0, n); >+ if (*bp != '0' || bp + 1 != ep) { >+ out->append(bp, ep - bp); >+ out->append(unit.abbr); >+ } >+} >+ >+// Note: unit.prec is limited to double's digits10 value (typically 15) so it >+// always fits in buf[]. >+void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) { >+ const int buf_size = std::numeric_limits<double>::digits10; >+ const int prec = std::min(buf_size, unit.prec); >+ char buf[buf_size]; // also large enough to hold integer part >+ char* ep = buf + sizeof(buf); >+ double d = 0; >+ int64_t frac_part = Round(std::modf(n, &d) * unit.pow10); >+ int64_t int_part = d; >+ if (int_part != 0 || frac_part != 0) { >+ char* bp = Format64(ep, 0, int_part); // always < 1000 >+ out->append(bp, ep - bp); >+ if (frac_part != 0) { >+ out->push_back('.'); >+ bp = Format64(ep, prec, frac_part); >+ while (ep[-1] == '0') --ep; >+ out->append(bp, ep - bp); >+ } >+ out->append(unit.abbr); >+ } >+} >+ >+} // namespace >+ >+// From Go's doc at http://golang.org/pkg/time/#Duration.String >+// [FormatDuration] returns a std::string representing the duration in the >+// form "72h3m0.5s". Leading zero units are omitted. As a special >+// case, durations less than one second format use a smaller unit >+// (milli-, micro-, or nanoseconds) to ensure that the leading digit >+// is non-zero. The zero duration formats as 0, with no unit. >+std::string FormatDuration(Duration d) { >+ const Duration min_duration = Seconds(kint64min); >+ if (d == min_duration) { >+ // Avoid needing to negate kint64min by directly returning what the >+ // following code should produce in that case. >+ return "-2562047788015215h30m8s"; >+ } >+ std::string s; >+ if (d < ZeroDuration()) { >+ s.append("-"); >+ d = -d; >+ } >+ if (d == InfiniteDuration()) { >+ s.append("inf"); >+ } else if (d < Seconds(1)) { >+ // Special case for durations with a magnitude < 1 second. The duration >+ // is printed as a fraction of a single unit, e.g., "1.2ms". >+ if (d < Microseconds(1)) { >+ AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano); >+ } else if (d < Milliseconds(1)) { >+ AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro); >+ } else { >+ AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli); >+ } >+ } else { >+ AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour); >+ AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin); >+ AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec); >+ } >+ if (s.empty() || s == "-") { >+ s = "0"; >+ } >+ return s; >+} >+ >+namespace { >+ >+// A helper for ParseDuration() that parses a leading number from the given >+// std::string and stores the result in *int_part/*frac_part/*frac_scale. The >+// given std::string pointer is modified to point to the first unconsumed char. >+bool ConsumeDurationNumber(const char** dpp, int64_t* int_part, >+ int64_t* frac_part, int64_t* frac_scale) { >+ *int_part = 0; >+ *frac_part = 0; >+ *frac_scale = 1; // invariant: *frac_part < *frac_scale >+ const char* start = *dpp; >+ for (; std::isdigit(**dpp); *dpp += 1) { >+ const int d = **dpp - '0'; // contiguous digits >+ if (*int_part > kint64max / 10) return false; >+ *int_part *= 10; >+ if (*int_part > kint64max - d) return false; >+ *int_part += d; >+ } >+ const bool int_part_empty = (*dpp == start); >+ if (**dpp != '.') return !int_part_empty; >+ for (*dpp += 1; std::isdigit(**dpp); *dpp += 1) { >+ const int d = **dpp - '0'; // contiguous digits >+ if (*frac_scale <= kint64max / 10) { >+ *frac_part *= 10; >+ *frac_part += d; >+ *frac_scale *= 10; >+ } >+ } >+ return !int_part_empty || *frac_scale != 1; >+} >+ >+// A helper for ParseDuration() that parses a leading unit designator (e.g., >+// ns, us, ms, s, m, h) from the given std::string and stores the resulting unit >+// in "*unit". The given std::string pointer is modified to point to the first >+// unconsumed char. >+bool ConsumeDurationUnit(const char** start, Duration* unit) { >+ const char *s = *start; >+ bool ok = true; >+ if (strncmp(s, "ns", 2) == 0) { >+ s += 2; >+ *unit = Nanoseconds(1); >+ } else if (strncmp(s, "us", 2) == 0) { >+ s += 2; >+ *unit = Microseconds(1); >+ } else if (strncmp(s, "ms", 2) == 0) { >+ s += 2; >+ *unit = Milliseconds(1); >+ } else if (strncmp(s, "s", 1) == 0) { >+ s += 1; >+ *unit = Seconds(1); >+ } else if (strncmp(s, "m", 1) == 0) { >+ s += 1; >+ *unit = Minutes(1); >+ } else if (strncmp(s, "h", 1) == 0) { >+ s += 1; >+ *unit = Hours(1); >+ } else { >+ ok = false; >+ } >+ *start = s; >+ return ok; >+} >+ >+} // namespace >+ >+// From Go's doc at http://golang.org/pkg/time/#ParseDuration >+// [ParseDuration] parses a duration std::string. A duration std::string is >+// a possibly signed sequence of decimal numbers, each with optional >+// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". >+// Valid time units are "ns", "us" "ms", "s", "m", "h". >+bool ParseDuration(const std::string& dur_string, Duration* d) { >+ const char* start = dur_string.c_str(); >+ int sign = 1; >+ >+ if (*start == '-' || *start == '+') { >+ sign = *start == '-' ? -1 : 1; >+ ++start; >+ } >+ >+ // Can't parse a duration from an empty std::string. >+ if (*start == '\0') { >+ return false; >+ } >+ >+ // Special case for a std::string of "0". >+ if (*start == '0' && *(start + 1) == '\0') { >+ *d = ZeroDuration(); >+ return true; >+ } >+ >+ if (strcmp(start, "inf") == 0) { >+ *d = sign * InfiniteDuration(); >+ return true; >+ } >+ >+ Duration dur; >+ while (*start != '\0') { >+ int64_t int_part; >+ int64_t frac_part; >+ int64_t frac_scale; >+ Duration unit; >+ if (!ConsumeDurationNumber(&start, &int_part, &frac_part, &frac_scale) || >+ !ConsumeDurationUnit(&start, &unit)) { >+ return false; >+ } >+ if (int_part != 0) dur += sign * int_part * unit; >+ if (frac_part != 0) dur += sign * frac_part * unit / frac_scale; >+ } >+ *d = dur; >+ return true; >+} >+bool ParseFlag(const std::string& text, Duration* dst, std::string* ) { >+ return ParseDuration(text, dst); >+} >+ >+std::string UnparseFlag(Duration d) { return FormatDuration(d); } >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_benchmark.cc >new file mode 100644 >index 00000000000..d5657bd576a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_benchmark.cc >@@ -0,0 +1,427 @@ >+// Copyright 2018 The Abseil Authors. >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cmath> >+#include <cstddef> >+#include <cstdint> >+#include <ctime> >+#include <string> >+ >+#include "absl/time/time.h" >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+// >+// Factory functions >+// >+ >+void BM_Duration_Factory_Nanoseconds(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Nanoseconds(i)); >+ i += 314159; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Nanoseconds); >+ >+void BM_Duration_Factory_Microseconds(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Microseconds(i)); >+ i += 314; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Microseconds); >+ >+void BM_Duration_Factory_Milliseconds(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Milliseconds(i)); >+ i += 1; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Milliseconds); >+ >+void BM_Duration_Factory_Seconds(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Seconds(i)); >+ i += 1; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Seconds); >+ >+void BM_Duration_Factory_Minutes(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Minutes(i)); >+ i += 1; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Minutes); >+ >+void BM_Duration_Factory_Hours(benchmark::State& state) { >+ int64_t i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Hours(i)); >+ i += 1; >+ } >+} >+BENCHMARK(BM_Duration_Factory_Hours); >+ >+void BM_Duration_Factory_DoubleNanoseconds(benchmark::State& state) { >+ double d = 1; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Nanoseconds(d)); >+ d = d * 1.00000001 + 1; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleNanoseconds); >+ >+void BM_Duration_Factory_DoubleMicroseconds(benchmark::State& state) { >+ double d = 1e-3; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Microseconds(d)); >+ d = d * 1.00000001 + 1e-3; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleMicroseconds); >+ >+void BM_Duration_Factory_DoubleMilliseconds(benchmark::State& state) { >+ double d = 1e-6; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Milliseconds(d)); >+ d = d * 1.00000001 + 1e-6; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleMilliseconds); >+ >+void BM_Duration_Factory_DoubleSeconds(benchmark::State& state) { >+ double d = 1e-9; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Seconds(d)); >+ d = d * 1.00000001 + 1e-9; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleSeconds); >+ >+void BM_Duration_Factory_DoubleMinutes(benchmark::State& state) { >+ double d = 1e-9; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Minutes(d)); >+ d = d * 1.00000001 + 1e-9; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleMinutes); >+ >+void BM_Duration_Factory_DoubleHours(benchmark::State& state) { >+ double d = 1e-9; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::Hours(d)); >+ d = d * 1.00000001 + 1e-9; >+ } >+} >+BENCHMARK(BM_Duration_Factory_DoubleHours); >+ >+// >+// Arithmetic >+// >+ >+void BM_Duration_Addition(benchmark::State& state) { >+ absl::Duration d = absl::Nanoseconds(1); >+ absl::Duration step = absl::Milliseconds(1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(d += step); >+ } >+} >+BENCHMARK(BM_Duration_Addition); >+ >+void BM_Duration_Subtraction(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(std::numeric_limits<int64_t>::max()); >+ absl::Duration step = absl::Milliseconds(1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(d -= step); >+ } >+} >+BENCHMARK(BM_Duration_Subtraction); >+ >+void BM_Duration_Multiplication_Fixed(benchmark::State& state) { >+ absl::Duration d = absl::Milliseconds(1); >+ absl::Duration s; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(s += d * (i + 1)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_Multiplication_Fixed); >+ >+void BM_Duration_Multiplication_Double(benchmark::State& state) { >+ absl::Duration d = absl::Milliseconds(1); >+ absl::Duration s; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(s += d * (i + 1.0)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_Multiplication_Double); >+ >+void BM_Duration_Division_Fixed(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(1); >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(d /= i + 1); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_Division_Fixed); >+ >+void BM_Duration_Division_Double(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(1); >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(d /= i + 1.0); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_Division_Double); >+ >+void BM_Duration_FDivDuration_Nanoseconds(benchmark::State& state) { >+ double d = 1; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize( >+ d += absl::FDivDuration(absl::Milliseconds(i), absl::Nanoseconds(1))); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_FDivDuration_Nanoseconds); >+ >+void BM_Duration_IDivDuration_Nanoseconds(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(a += >+ absl::IDivDuration(absl::Nanoseconds(i), >+ absl::Nanoseconds(1), &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Nanoseconds); >+ >+void BM_Duration_IDivDuration_Microseconds(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Microseconds(i), >+ absl::Microseconds(1), >+ &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Microseconds); >+ >+void BM_Duration_IDivDuration_Milliseconds(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Milliseconds(i), >+ absl::Milliseconds(1), >+ &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Milliseconds); >+ >+void BM_Duration_IDivDuration_Seconds(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize( >+ a += absl::IDivDuration(absl::Seconds(i), absl::Seconds(1), &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Seconds); >+ >+void BM_Duration_IDivDuration_Minutes(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize( >+ a += absl::IDivDuration(absl::Minutes(i), absl::Minutes(1), &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Minutes); >+ >+void BM_Duration_IDivDuration_Hours(benchmark::State& state) { >+ int64_t a = 1; >+ absl::Duration ignore; >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize( >+ a += absl::IDivDuration(absl::Hours(i), absl::Hours(1), &ignore)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Duration_IDivDuration_Hours); >+ >+void BM_Duration_ToInt64Nanoseconds(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Nanoseconds(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Nanoseconds); >+ >+void BM_Duration_ToInt64Microseconds(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Microseconds(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Microseconds); >+ >+void BM_Duration_ToInt64Milliseconds(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Milliseconds(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Milliseconds); >+ >+void BM_Duration_ToInt64Seconds(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Seconds(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Seconds); >+ >+void BM_Duration_ToInt64Minutes(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Minutes(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Minutes); >+ >+void BM_Duration_ToInt64Hours(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(100000); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToInt64Hours(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToInt64Hours); >+ >+// >+// To/FromTimespec >+// >+ >+void BM_Duration_ToTimespec_AbslTime(benchmark::State& state) { >+ absl::Duration d = absl::Seconds(1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToTimespec(d)); >+ } >+} >+BENCHMARK(BM_Duration_ToTimespec_AbslTime); >+ >+ABSL_ATTRIBUTE_NOINLINE timespec DoubleToTimespec(double seconds) { >+ timespec ts; >+ ts.tv_sec = seconds; >+ ts.tv_nsec = (seconds - ts.tv_sec) * (1000 * 1000 * 1000); >+ return ts; >+} >+ >+void BM_Duration_ToTimespec_Double(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(DoubleToTimespec(1.0)); >+ } >+} >+BENCHMARK(BM_Duration_ToTimespec_Double); >+ >+void BM_Duration_FromTimespec_AbslTime(benchmark::State& state) { >+ timespec ts; >+ ts.tv_sec = 0; >+ ts.tv_nsec = 0; >+ while (state.KeepRunning()) { >+ if (++ts.tv_nsec == 1000 * 1000 * 1000) { >+ ++ts.tv_sec; >+ ts.tv_nsec = 0; >+ } >+ benchmark::DoNotOptimize(absl::DurationFromTimespec(ts)); >+ } >+} >+BENCHMARK(BM_Duration_FromTimespec_AbslTime); >+ >+ABSL_ATTRIBUTE_NOINLINE double TimespecToDouble(timespec ts) { >+ return ts.tv_sec + (ts.tv_nsec / (1000 * 1000 * 1000)); >+} >+ >+void BM_Duration_FromTimespec_Double(benchmark::State& state) { >+ timespec ts; >+ ts.tv_sec = 0; >+ ts.tv_nsec = 0; >+ while (state.KeepRunning()) { >+ if (++ts.tv_nsec == 1000 * 1000 * 1000) { >+ ++ts.tv_sec; >+ ts.tv_nsec = 0; >+ } >+ benchmark::DoNotOptimize(TimespecToDouble(ts)); >+ } >+} >+BENCHMARK(BM_Duration_FromTimespec_Double); >+ >+// >+// String conversions >+// >+ >+const char* const kDurations[] = { >+ "0", // 0 >+ "123ns", // 1 >+ "1h2m3s", // 2 >+ "-2h3m4.005006007s", // 3 >+ "2562047788015215h30m7.99999999975s", // 4 >+}; >+const int kNumDurations = sizeof(kDurations) / sizeof(kDurations[0]); >+ >+void BM_Duration_FormatDuration(benchmark::State& state) { >+ const std::string s = kDurations[state.range(0)]; >+ state.SetLabel(s); >+ absl::Duration d; >+ absl::ParseDuration(kDurations[state.range(0)], &d); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::FormatDuration(d)); >+ } >+} >+BENCHMARK(BM_Duration_FormatDuration)->DenseRange(0, kNumDurations - 1); >+ >+void BM_Duration_ParseDuration(benchmark::State& state) { >+ const std::string s = kDurations[state.range(0)]; >+ state.SetLabel(s); >+ absl::Duration d; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ParseDuration(s, &d)); >+ } >+} >+BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_test.cc >new file mode 100644 >index 00000000000..7ae25dc68f9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/duration_test.cc >@@ -0,0 +1,1764 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <chrono> // NOLINT(build/c++11) >+#include <cmath> >+#include <cstdint> >+#include <ctime> >+#include <iomanip> >+#include <limits> >+#include <random> >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/time/time.h" >+ >+namespace { >+ >+constexpr int64_t kint64max = std::numeric_limits<int64_t>::max(); >+constexpr int64_t kint64min = std::numeric_limits<int64_t>::min(); >+ >+// Approximates the given number of years. This is only used to make some test >+// code more readable. >+absl::Duration ApproxYears(int64_t n) { return absl::Hours(n) * 365 * 24; } >+ >+// A gMock matcher to match timespec values. Use this matcher like: >+// timespec ts1, ts2; >+// EXPECT_THAT(ts1, TimespecMatcher(ts2)); >+MATCHER_P(TimespecMatcher, ts, "") { >+ if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) >+ return true; >+ *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} "; >+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}"; >+ return false; >+} >+ >+// A gMock matcher to match timeval values. Use this matcher like: >+// timeval tv1, tv2; >+// EXPECT_THAT(tv1, TimevalMatcher(tv2)); >+MATCHER_P(TimevalMatcher, tv, "") { >+ if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) >+ return true; >+ *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} "; >+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}"; >+ return false; >+} >+ >+TEST(Duration, ValueSemantics) { >+ // If this compiles, the test passes. >+ constexpr absl::Duration a; // Default construction >+ constexpr absl::Duration b = a; // Copy construction >+ constexpr absl::Duration c(b); // Copy construction (again) >+ >+ absl::Duration d; >+ d = c; // Assignment >+} >+ >+TEST(Duration, Factories) { >+ constexpr absl::Duration zero = absl::ZeroDuration(); >+ constexpr absl::Duration nano = absl::Nanoseconds(1); >+ constexpr absl::Duration micro = absl::Microseconds(1); >+ constexpr absl::Duration milli = absl::Milliseconds(1); >+ constexpr absl::Duration sec = absl::Seconds(1); >+ constexpr absl::Duration min = absl::Minutes(1); >+ constexpr absl::Duration hour = absl::Hours(1); >+ >+ EXPECT_EQ(zero, absl::Duration()); >+ EXPECT_EQ(zero, absl::Seconds(0)); >+ EXPECT_EQ(nano, absl::Nanoseconds(1)); >+ EXPECT_EQ(micro, absl::Nanoseconds(1000)); >+ EXPECT_EQ(milli, absl::Microseconds(1000)); >+ EXPECT_EQ(sec, absl::Milliseconds(1000)); >+ EXPECT_EQ(min, absl::Seconds(60)); >+ EXPECT_EQ(hour, absl::Minutes(60)); >+ >+ // Tests factory limits >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+ EXPECT_GT(inf, absl::Seconds(kint64max)); >+ EXPECT_LT(-inf, absl::Seconds(kint64min)); >+ EXPECT_LT(-inf, absl::Seconds(-kint64max)); >+ >+ EXPECT_EQ(inf, absl::Minutes(kint64max)); >+ EXPECT_EQ(-inf, absl::Minutes(kint64min)); >+ EXPECT_EQ(-inf, absl::Minutes(-kint64max)); >+ EXPECT_GT(inf, absl::Minutes(kint64max / 60)); >+ EXPECT_LT(-inf, absl::Minutes(kint64min / 60)); >+ EXPECT_LT(-inf, absl::Minutes(-kint64max / 60)); >+ >+ EXPECT_EQ(inf, absl::Hours(kint64max)); >+ EXPECT_EQ(-inf, absl::Hours(kint64min)); >+ EXPECT_EQ(-inf, absl::Hours(-kint64max)); >+ EXPECT_GT(inf, absl::Hours(kint64max / 3600)); >+ EXPECT_LT(-inf, absl::Hours(kint64min / 3600)); >+ EXPECT_LT(-inf, absl::Hours(-kint64max / 3600)); >+} >+ >+TEST(Duration, ToConversion) { >+#define TEST_DURATION_CONVERSION(UNIT) \ >+ do { \ >+ const absl::Duration d = absl::UNIT(1.5); \ >+ constexpr absl::Duration z = absl::ZeroDuration(); \ >+ constexpr absl::Duration inf = absl::InfiniteDuration(); \ >+ constexpr double dbl_inf = std::numeric_limits<double>::infinity(); \ >+ EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf)); \ >+ EXPECT_EQ(-1, absl::ToInt64##UNIT(-d)); \ >+ EXPECT_EQ(0, absl::ToInt64##UNIT(z)); \ >+ EXPECT_EQ(1, absl::ToInt64##UNIT(d)); \ >+ EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf)); \ >+ EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf)); \ >+ EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d)); \ >+ EXPECT_EQ(0, absl::ToDouble##UNIT(z)); \ >+ EXPECT_EQ(1.5, absl::ToDouble##UNIT(d)); \ >+ EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf)); \ >+ } while (0) >+ >+ TEST_DURATION_CONVERSION(Nanoseconds); >+ TEST_DURATION_CONVERSION(Microseconds); >+ TEST_DURATION_CONVERSION(Milliseconds); >+ TEST_DURATION_CONVERSION(Seconds); >+ TEST_DURATION_CONVERSION(Minutes); >+ TEST_DURATION_CONVERSION(Hours); >+ >+#undef TEST_DURATION_CONVERSION >+} >+ >+template <int64_t N> >+void TestToConversion() { >+ constexpr absl::Duration nano = absl::Nanoseconds(N); >+ EXPECT_EQ(N, absl::ToInt64Nanoseconds(nano)); >+ EXPECT_EQ(0, absl::ToInt64Microseconds(nano)); >+ EXPECT_EQ(0, absl::ToInt64Milliseconds(nano)); >+ EXPECT_EQ(0, absl::ToInt64Seconds(nano)); >+ EXPECT_EQ(0, absl::ToInt64Minutes(nano)); >+ EXPECT_EQ(0, absl::ToInt64Hours(nano)); >+ const absl::Duration micro = absl::Microseconds(N); >+ EXPECT_EQ(N * 1000, absl::ToInt64Nanoseconds(micro)); >+ EXPECT_EQ(N, absl::ToInt64Microseconds(micro)); >+ EXPECT_EQ(0, absl::ToInt64Milliseconds(micro)); >+ EXPECT_EQ(0, absl::ToInt64Seconds(micro)); >+ EXPECT_EQ(0, absl::ToInt64Minutes(micro)); >+ EXPECT_EQ(0, absl::ToInt64Hours(micro)); >+ const absl::Duration milli = absl::Milliseconds(N); >+ EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Nanoseconds(milli)); >+ EXPECT_EQ(N * 1000, absl::ToInt64Microseconds(milli)); >+ EXPECT_EQ(N, absl::ToInt64Milliseconds(milli)); >+ EXPECT_EQ(0, absl::ToInt64Seconds(milli)); >+ EXPECT_EQ(0, absl::ToInt64Minutes(milli)); >+ EXPECT_EQ(0, absl::ToInt64Hours(milli)); >+ const absl::Duration sec = absl::Seconds(N); >+ EXPECT_EQ(N * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec)); >+ EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Microseconds(sec)); >+ EXPECT_EQ(N * 1000, absl::ToInt64Milliseconds(sec)); >+ EXPECT_EQ(N, absl::ToInt64Seconds(sec)); >+ EXPECT_EQ(0, absl::ToInt64Minutes(sec)); >+ EXPECT_EQ(0, absl::ToInt64Hours(sec)); >+ const absl::Duration min = absl::Minutes(N); >+ EXPECT_EQ(N * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min)); >+ EXPECT_EQ(N * 60 * 1000 * 1000, absl::ToInt64Microseconds(min)); >+ EXPECT_EQ(N * 60 * 1000, absl::ToInt64Milliseconds(min)); >+ EXPECT_EQ(N * 60, absl::ToInt64Seconds(min)); >+ EXPECT_EQ(N, absl::ToInt64Minutes(min)); >+ EXPECT_EQ(0, absl::ToInt64Hours(min)); >+ const absl::Duration hour = absl::Hours(N); >+ EXPECT_EQ(N * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour)); >+ EXPECT_EQ(N * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour)); >+ EXPECT_EQ(N * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour)); >+ EXPECT_EQ(N * 60 * 60, absl::ToInt64Seconds(hour)); >+ EXPECT_EQ(N * 60, absl::ToInt64Minutes(hour)); >+ EXPECT_EQ(N, absl::ToInt64Hours(hour)); >+} >+ >+TEST(Duration, ToConversionDeprecated) { >+ TestToConversion<43>(); >+ TestToConversion<1>(); >+ TestToConversion<0>(); >+ TestToConversion<-1>(); >+ TestToConversion<-43>(); >+} >+ >+template <int64_t N> >+void TestFromChronoBasicEquality() { >+ using std::chrono::nanoseconds; >+ using std::chrono::microseconds; >+ using std::chrono::milliseconds; >+ using std::chrono::seconds; >+ using std::chrono::minutes; >+ using std::chrono::hours; >+ >+ static_assert(absl::Nanoseconds(N) == absl::FromChrono(nanoseconds(N)), ""); >+ static_assert(absl::Microseconds(N) == absl::FromChrono(microseconds(N)), ""); >+ static_assert(absl::Milliseconds(N) == absl::FromChrono(milliseconds(N)), ""); >+ static_assert(absl::Seconds(N) == absl::FromChrono(seconds(N)), ""); >+ static_assert(absl::Minutes(N) == absl::FromChrono(minutes(N)), ""); >+ static_assert(absl::Hours(N) == absl::FromChrono(hours(N)), ""); >+} >+ >+TEST(Duration, FromChrono) { >+ TestFromChronoBasicEquality<-123>(); >+ TestFromChronoBasicEquality<-1>(); >+ TestFromChronoBasicEquality<0>(); >+ TestFromChronoBasicEquality<1>(); >+ TestFromChronoBasicEquality<123>(); >+ >+ // Minutes (might, depending on the platform) saturate at +inf. >+ const auto chrono_minutes_max = std::chrono::minutes::max(); >+ const auto minutes_max = absl::FromChrono(chrono_minutes_max); >+ const int64_t minutes_max_count = chrono_minutes_max.count(); >+ if (minutes_max_count > kint64max / 60) { >+ EXPECT_EQ(absl::InfiniteDuration(), minutes_max); >+ } else { >+ EXPECT_EQ(absl::Minutes(minutes_max_count), minutes_max); >+ } >+ >+ // Minutes (might, depending on the platform) saturate at -inf. >+ const auto chrono_minutes_min = std::chrono::minutes::min(); >+ const auto minutes_min = absl::FromChrono(chrono_minutes_min); >+ const int64_t minutes_min_count = chrono_minutes_min.count(); >+ if (minutes_min_count < kint64min / 60) { >+ EXPECT_EQ(-absl::InfiniteDuration(), minutes_min); >+ } else { >+ EXPECT_EQ(absl::Minutes(minutes_min_count), minutes_min); >+ } >+ >+ // Hours (might, depending on the platform) saturate at +inf. >+ const auto chrono_hours_max = std::chrono::hours::max(); >+ const auto hours_max = absl::FromChrono(chrono_hours_max); >+ const int64_t hours_max_count = chrono_hours_max.count(); >+ if (hours_max_count > kint64max / 3600) { >+ EXPECT_EQ(absl::InfiniteDuration(), hours_max); >+ } else { >+ EXPECT_EQ(absl::Hours(hours_max_count), hours_max); >+ } >+ >+ // Hours (might, depending on the platform) saturate at -inf. >+ const auto chrono_hours_min = std::chrono::hours::min(); >+ const auto hours_min = absl::FromChrono(chrono_hours_min); >+ const int64_t hours_min_count = chrono_hours_min.count(); >+ if (hours_min_count < kint64min / 3600) { >+ EXPECT_EQ(-absl::InfiniteDuration(), hours_min); >+ } else { >+ EXPECT_EQ(absl::Hours(hours_min_count), hours_min); >+ } >+} >+ >+template <int64_t N> >+void TestToChrono() { >+ using std::chrono::nanoseconds; >+ using std::chrono::microseconds; >+ using std::chrono::milliseconds; >+ using std::chrono::seconds; >+ using std::chrono::minutes; >+ using std::chrono::hours; >+ >+ EXPECT_EQ(nanoseconds(N), absl::ToChronoNanoseconds(absl::Nanoseconds(N))); >+ EXPECT_EQ(microseconds(N), absl::ToChronoMicroseconds(absl::Microseconds(N))); >+ EXPECT_EQ(milliseconds(N), absl::ToChronoMilliseconds(absl::Milliseconds(N))); >+ EXPECT_EQ(seconds(N), absl::ToChronoSeconds(absl::Seconds(N))); >+ >+ constexpr auto absl_minutes = absl::Minutes(N); >+ auto chrono_minutes = minutes(N); >+ if (absl_minutes == -absl::InfiniteDuration()) { >+ chrono_minutes = minutes::min(); >+ } else if (absl_minutes == absl::InfiniteDuration()) { >+ chrono_minutes = minutes::max(); >+ } >+ EXPECT_EQ(chrono_minutes, absl::ToChronoMinutes(absl_minutes)); >+ >+ constexpr auto absl_hours = absl::Hours(N); >+ auto chrono_hours = hours(N); >+ if (absl_hours == -absl::InfiniteDuration()) { >+ chrono_hours = hours::min(); >+ } else if (absl_hours == absl::InfiniteDuration()) { >+ chrono_hours = hours::max(); >+ } >+ EXPECT_EQ(chrono_hours, absl::ToChronoHours(absl_hours)); >+} >+ >+TEST(Duration, ToChrono) { >+ using std::chrono::nanoseconds; >+ using std::chrono::microseconds; >+ using std::chrono::milliseconds; >+ using std::chrono::seconds; >+ using std::chrono::minutes; >+ using std::chrono::hours; >+ >+ TestToChrono<kint64min>(); >+ TestToChrono<-1>(); >+ TestToChrono<0>(); >+ TestToChrono<1>(); >+ TestToChrono<kint64max>(); >+ >+ // Verify truncation toward zero. >+ const auto tick = absl::Nanoseconds(1) / 4; >+ EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(tick)); >+ EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(-tick)); >+ EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(tick)); >+ EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(-tick)); >+ EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(tick)); >+ EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(-tick)); >+ EXPECT_EQ(seconds(0), absl::ToChronoSeconds(tick)); >+ EXPECT_EQ(seconds(0), absl::ToChronoSeconds(-tick)); >+ EXPECT_EQ(minutes(0), absl::ToChronoMinutes(tick)); >+ EXPECT_EQ(minutes(0), absl::ToChronoMinutes(-tick)); >+ EXPECT_EQ(hours(0), absl::ToChronoHours(tick)); >+ EXPECT_EQ(hours(0), absl::ToChronoHours(-tick)); >+ >+ // Verifies +/- infinity saturation at max/min. >+ constexpr auto inf = absl::InfiniteDuration(); >+ EXPECT_EQ(nanoseconds::min(), absl::ToChronoNanoseconds(-inf)); >+ EXPECT_EQ(nanoseconds::max(), absl::ToChronoNanoseconds(inf)); >+ EXPECT_EQ(microseconds::min(), absl::ToChronoMicroseconds(-inf)); >+ EXPECT_EQ(microseconds::max(), absl::ToChronoMicroseconds(inf)); >+ EXPECT_EQ(milliseconds::min(), absl::ToChronoMilliseconds(-inf)); >+ EXPECT_EQ(milliseconds::max(), absl::ToChronoMilliseconds(inf)); >+ EXPECT_EQ(seconds::min(), absl::ToChronoSeconds(-inf)); >+ EXPECT_EQ(seconds::max(), absl::ToChronoSeconds(inf)); >+ EXPECT_EQ(minutes::min(), absl::ToChronoMinutes(-inf)); >+ EXPECT_EQ(minutes::max(), absl::ToChronoMinutes(inf)); >+ EXPECT_EQ(hours::min(), absl::ToChronoHours(-inf)); >+ EXPECT_EQ(hours::max(), absl::ToChronoHours(inf)); >+} >+ >+TEST(Duration, FactoryOverloads) { >+ enum E { kOne = 1 }; >+#define TEST_FACTORY_OVERLOADS(NAME) \ >+ EXPECT_EQ(1, NAME(kOne) / NAME(kOne)); \ >+ EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<int64_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<uint8_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \ >+ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \ >+ EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \ >+ EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \ >+ EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<double>(1.5)), NAME(1))); >+ >+ TEST_FACTORY_OVERLOADS(absl::Nanoseconds); >+ TEST_FACTORY_OVERLOADS(absl::Microseconds); >+ TEST_FACTORY_OVERLOADS(absl::Milliseconds); >+ TEST_FACTORY_OVERLOADS(absl::Seconds); >+ TEST_FACTORY_OVERLOADS(absl::Minutes); >+ TEST_FACTORY_OVERLOADS(absl::Hours); >+ >+#undef TEST_FACTORY_OVERLOADS >+ >+ EXPECT_EQ(absl::Milliseconds(1500), absl::Seconds(1.5)); >+ EXPECT_LT(absl::Nanoseconds(1), absl::Nanoseconds(1.5)); >+ EXPECT_GT(absl::Nanoseconds(2), absl::Nanoseconds(1.5)); >+ >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Nanoseconds(dbl_inf)); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Microseconds(dbl_inf)); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Milliseconds(dbl_inf)); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Seconds(dbl_inf)); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Minutes(dbl_inf)); >+ EXPECT_EQ(absl::InfiniteDuration(), absl::Hours(dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Nanoseconds(-dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Microseconds(-dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Milliseconds(-dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Seconds(-dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Minutes(-dbl_inf)); >+ EXPECT_EQ(-absl::InfiniteDuration(), absl::Hours(-dbl_inf)); >+} >+ >+TEST(Duration, InfinityExamples) { >+ // These examples are used in the documentation in time.h. They are >+ // written so that they can be copy-n-pasted easily. >+ >+ constexpr absl::Duration inf = absl::InfiniteDuration(); >+ constexpr absl::Duration d = absl::Seconds(1); // Any finite duration >+ >+ EXPECT_TRUE(inf == inf + inf); >+ EXPECT_TRUE(inf == inf + d); >+ EXPECT_TRUE(inf == inf - inf); >+ EXPECT_TRUE(-inf == d - inf); >+ >+ EXPECT_TRUE(inf == d * 1e100); >+ EXPECT_TRUE(0 == d / inf); // NOLINT(readability/check) >+ >+ // Division by zero returns infinity, or kint64min/MAX where necessary. >+ EXPECT_TRUE(inf == d / 0); >+ EXPECT_TRUE(kint64max == d / absl::ZeroDuration()); >+} >+ >+TEST(Duration, InfinityComparison) { >+ const absl::Duration inf = absl::InfiniteDuration(); >+ const absl::Duration any_dur = absl::Seconds(1); >+ >+ // Equality >+ EXPECT_EQ(inf, inf); >+ EXPECT_EQ(-inf, -inf); >+ EXPECT_NE(inf, -inf); >+ EXPECT_NE(any_dur, inf); >+ EXPECT_NE(any_dur, -inf); >+ >+ // Relational >+ EXPECT_GT(inf, any_dur); >+ EXPECT_LT(-inf, any_dur); >+ EXPECT_LT(-inf, inf); >+ EXPECT_GT(inf, -inf); >+} >+ >+TEST(Duration, InfinityAddition) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration sec_min = absl::Seconds(kint64min); >+ const absl::Duration any_dur = absl::Seconds(1); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+ // Addition >+ EXPECT_EQ(inf, inf + inf); >+ EXPECT_EQ(inf, inf + -inf); >+ EXPECT_EQ(-inf, -inf + inf); >+ EXPECT_EQ(-inf, -inf + -inf); >+ >+ EXPECT_EQ(inf, inf + any_dur); >+ EXPECT_EQ(inf, any_dur + inf); >+ EXPECT_EQ(-inf, -inf + any_dur); >+ EXPECT_EQ(-inf, any_dur + -inf); >+ >+ // Interesting case >+ absl::Duration almost_inf = sec_max + absl::Nanoseconds(999999999); >+ EXPECT_GT(inf, almost_inf); >+ almost_inf += -absl::Nanoseconds(999999999); >+ EXPECT_GT(inf, almost_inf); >+ >+ // Addition overflow/underflow >+ EXPECT_EQ(inf, sec_max + absl::Seconds(1)); >+ EXPECT_EQ(inf, sec_max + sec_max); >+ EXPECT_EQ(-inf, sec_min + -absl::Seconds(1)); >+ EXPECT_EQ(-inf, sec_min + -sec_max); >+ >+ // For reference: IEEE 754 behavior >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ EXPECT_TRUE(std::isinf(dbl_inf + dbl_inf)); >+ EXPECT_TRUE(std::isnan(dbl_inf + -dbl_inf)); // We return inf >+ EXPECT_TRUE(std::isnan(-dbl_inf + dbl_inf)); // We return inf >+ EXPECT_TRUE(std::isinf(-dbl_inf + -dbl_inf)); >+} >+ >+TEST(Duration, InfinitySubtraction) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration sec_min = absl::Seconds(kint64min); >+ const absl::Duration any_dur = absl::Seconds(1); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+ // Subtraction >+ EXPECT_EQ(inf, inf - inf); >+ EXPECT_EQ(inf, inf - -inf); >+ EXPECT_EQ(-inf, -inf - inf); >+ EXPECT_EQ(-inf, -inf - -inf); >+ >+ EXPECT_EQ(inf, inf - any_dur); >+ EXPECT_EQ(-inf, any_dur - inf); >+ EXPECT_EQ(-inf, -inf - any_dur); >+ EXPECT_EQ(inf, any_dur - -inf); >+ >+ // Subtraction overflow/underflow >+ EXPECT_EQ(inf, sec_max - -absl::Seconds(1)); >+ EXPECT_EQ(inf, sec_max - -sec_max); >+ EXPECT_EQ(-inf, sec_min - absl::Seconds(1)); >+ EXPECT_EQ(-inf, sec_min - sec_max); >+ >+ // Interesting case >+ absl::Duration almost_neg_inf = sec_min; >+ EXPECT_LT(-inf, almost_neg_inf); >+ almost_neg_inf -= -absl::Nanoseconds(1); >+ EXPECT_LT(-inf, almost_neg_inf); >+ >+ // For reference: IEEE 754 behavior >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ EXPECT_TRUE(std::isnan(dbl_inf - dbl_inf)); // We return inf >+ EXPECT_TRUE(std::isinf(dbl_inf - -dbl_inf)); >+ EXPECT_TRUE(std::isinf(-dbl_inf - dbl_inf)); >+ EXPECT_TRUE(std::isnan(-dbl_inf - -dbl_inf)); // We return inf >+} >+ >+TEST(Duration, InfinityMultiplication) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration sec_min = absl::Seconds(kint64min); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+#define TEST_INF_MUL_WITH_TYPE(T) \ >+ EXPECT_EQ(inf, inf * static_cast<T>(2)); \ >+ EXPECT_EQ(-inf, inf * static_cast<T>(-2)); \ >+ EXPECT_EQ(-inf, -inf * static_cast<T>(2)); \ >+ EXPECT_EQ(inf, -inf * static_cast<T>(-2)); \ >+ EXPECT_EQ(inf, inf * static_cast<T>(0)); \ >+ EXPECT_EQ(-inf, -inf * static_cast<T>(0)); \ >+ EXPECT_EQ(inf, sec_max * static_cast<T>(2)); \ >+ EXPECT_EQ(inf, sec_min * static_cast<T>(-2)); \ >+ EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3)); \ >+ EXPECT_EQ(-inf, sec_max * static_cast<T>(-2)); \ >+ EXPECT_EQ(-inf, sec_min * static_cast<T>(2)); \ >+ EXPECT_EQ(-inf, (sec_min / static_cast<T>(2)) * static_cast<T>(3)); >+ >+ TEST_INF_MUL_WITH_TYPE(int64_t); // NOLINT(readability/function) >+ TEST_INF_MUL_WITH_TYPE(double); // NOLINT(readability/function) >+ >+#undef TEST_INF_MUL_WITH_TYPE >+ >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ EXPECT_EQ(inf, inf * dbl_inf); >+ EXPECT_EQ(-inf, -inf * dbl_inf); >+ EXPECT_EQ(-inf, inf * -dbl_inf); >+ EXPECT_EQ(inf, -inf * -dbl_inf); >+ >+ const absl::Duration any_dur = absl::Seconds(1); >+ EXPECT_EQ(inf, any_dur * dbl_inf); >+ EXPECT_EQ(-inf, -any_dur * dbl_inf); >+ EXPECT_EQ(-inf, any_dur * -dbl_inf); >+ EXPECT_EQ(inf, -any_dur * -dbl_inf); >+ >+ // Fixed-point multiplication will produce a finite value, whereas floating >+ // point fuzziness will overflow to inf. >+ EXPECT_NE(absl::InfiniteDuration(), absl::Seconds(1) * kint64max); >+ EXPECT_EQ(inf, absl::Seconds(1) * static_cast<double>(kint64max)); >+ EXPECT_NE(-absl::InfiniteDuration(), absl::Seconds(1) * kint64min); >+ EXPECT_EQ(-inf, absl::Seconds(1) * static_cast<double>(kint64min)); >+ >+ // Note that sec_max * or / by 1.0 overflows to inf due to the 53-bit >+ // limitations of double. >+ EXPECT_NE(inf, sec_max); >+ EXPECT_NE(inf, sec_max / 1); >+ EXPECT_EQ(inf, sec_max / 1.0); >+ EXPECT_NE(inf, sec_max * 1); >+ EXPECT_EQ(inf, sec_max * 1.0); >+} >+ >+TEST(Duration, InfinityDivision) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration sec_min = absl::Seconds(kint64min); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+ // Division of Duration by a double >+#define TEST_INF_DIV_WITH_TYPE(T) \ >+ EXPECT_EQ(inf, inf / static_cast<T>(2)); \ >+ EXPECT_EQ(-inf, inf / static_cast<T>(-2)); \ >+ EXPECT_EQ(-inf, -inf / static_cast<T>(2)); \ >+ EXPECT_EQ(inf, -inf / static_cast<T>(-2)); >+ >+ TEST_INF_DIV_WITH_TYPE(int64_t); // NOLINT(readability/function) >+ TEST_INF_DIV_WITH_TYPE(double); // NOLINT(readability/function) >+ >+#undef TEST_INF_DIV_WITH_TYPE >+ >+ // Division of Duration by a double overflow/underflow >+ EXPECT_EQ(inf, sec_max / 0.5); >+ EXPECT_EQ(inf, sec_min / -0.5); >+ EXPECT_EQ(inf, ((sec_max / 0.5) + absl::Seconds(1)) / 0.5); >+ EXPECT_EQ(-inf, sec_max / -0.5); >+ EXPECT_EQ(-inf, sec_min / 0.5); >+ EXPECT_EQ(-inf, ((sec_min / 0.5) - absl::Seconds(1)) / 0.5); >+ >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ EXPECT_EQ(inf, inf / dbl_inf); >+ EXPECT_EQ(-inf, inf / -dbl_inf); >+ EXPECT_EQ(-inf, -inf / dbl_inf); >+ EXPECT_EQ(inf, -inf / -dbl_inf); >+ >+ const absl::Duration any_dur = absl::Seconds(1); >+ EXPECT_EQ(absl::ZeroDuration(), any_dur / dbl_inf); >+ EXPECT_EQ(absl::ZeroDuration(), any_dur / -dbl_inf); >+ EXPECT_EQ(absl::ZeroDuration(), -any_dur / dbl_inf); >+ EXPECT_EQ(absl::ZeroDuration(), -any_dur / -dbl_inf); >+} >+ >+TEST(Duration, InfinityModulus) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration any_dur = absl::Seconds(1); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ >+ EXPECT_EQ(inf, inf % inf); >+ EXPECT_EQ(inf, inf % -inf); >+ EXPECT_EQ(-inf, -inf % -inf); >+ EXPECT_EQ(-inf, -inf % inf); >+ >+ EXPECT_EQ(any_dur, any_dur % inf); >+ EXPECT_EQ(any_dur, any_dur % -inf); >+ EXPECT_EQ(-any_dur, -any_dur % inf); >+ EXPECT_EQ(-any_dur, -any_dur % -inf); >+ >+ EXPECT_EQ(inf, inf % -any_dur); >+ EXPECT_EQ(inf, inf % any_dur); >+ EXPECT_EQ(-inf, -inf % -any_dur); >+ EXPECT_EQ(-inf, -inf % any_dur); >+ >+ // Remainder isn't affected by overflow. >+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Seconds(1)); >+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Milliseconds(1)); >+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Microseconds(1)); >+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1)); >+ EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1) / 4); >+} >+ >+TEST(Duration, InfinityIDiv) { >+ const absl::Duration sec_max = absl::Seconds(kint64max); >+ const absl::Duration any_dur = absl::Seconds(1); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ >+ // IDivDuration (int64_t return value + a remainer) >+ absl::Duration rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64max, absl::IDivDuration(inf, inf, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -inf, &rem)); >+ EXPECT_EQ(-inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64max, absl::IDivDuration(inf, any_dur, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(0, absl::IDivDuration(any_dur, inf, &rem)); >+ EXPECT_EQ(any_dur, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -any_dur, &rem)); >+ EXPECT_EQ(-inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(0, absl::IDivDuration(-any_dur, -inf, &rem)); >+ EXPECT_EQ(-any_dur, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64min, absl::IDivDuration(-inf, inf, &rem)); >+ EXPECT_EQ(-inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64min, absl::IDivDuration(inf, -inf, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64min, absl::IDivDuration(-inf, any_dur, &rem)); >+ EXPECT_EQ(-inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(0, absl::IDivDuration(-any_dur, inf, &rem)); >+ EXPECT_EQ(-any_dur, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(kint64min, absl::IDivDuration(inf, -any_dur, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = absl::ZeroDuration(); >+ EXPECT_EQ(0, absl::IDivDuration(any_dur, -inf, &rem)); >+ EXPECT_EQ(any_dur, rem); >+ >+ // IDivDuration overflow/underflow >+ rem = any_dur; >+ EXPECT_EQ(kint64max, >+ absl::IDivDuration(sec_max, absl::Nanoseconds(1) / 4, &rem)); >+ EXPECT_EQ(sec_max - absl::Nanoseconds(kint64max) / 4, rem); >+ >+ rem = any_dur; >+ EXPECT_EQ(kint64max, >+ absl::IDivDuration(sec_max, absl::Milliseconds(1), &rem)); >+ EXPECT_EQ(sec_max - absl::Milliseconds(kint64max), rem); >+ >+ rem = any_dur; >+ EXPECT_EQ(kint64max, >+ absl::IDivDuration(-sec_max, -absl::Milliseconds(1), &rem)); >+ EXPECT_EQ(-sec_max + absl::Milliseconds(kint64max), rem); >+ >+ rem = any_dur; >+ EXPECT_EQ(kint64min, >+ absl::IDivDuration(-sec_max, absl::Milliseconds(1), &rem)); >+ EXPECT_EQ(-sec_max - absl::Milliseconds(kint64min), rem); >+ >+ rem = any_dur; >+ EXPECT_EQ(kint64min, >+ absl::IDivDuration(sec_max, -absl::Milliseconds(1), &rem)); >+ EXPECT_EQ(sec_max + absl::Milliseconds(kint64min), rem); >+ >+ // >+ // operator/(Duration, Duration) is a wrapper for IDivDuration(). >+ // >+ >+ // IEEE 754 says inf / inf should be nan, but int64_t doesn't have >+ // nan so we'll return kint64max/kint64min instead. >+ EXPECT_TRUE(std::isnan(dbl_inf / dbl_inf)); >+ EXPECT_EQ(kint64max, inf / inf); >+ EXPECT_EQ(kint64max, -inf / -inf); >+ EXPECT_EQ(kint64min, -inf / inf); >+ EXPECT_EQ(kint64min, inf / -inf); >+ >+ EXPECT_TRUE(std::isinf(dbl_inf / 2.0)); >+ EXPECT_EQ(kint64max, inf / any_dur); >+ EXPECT_EQ(kint64max, -inf / -any_dur); >+ EXPECT_EQ(kint64min, -inf / any_dur); >+ EXPECT_EQ(kint64min, inf / -any_dur); >+ >+ EXPECT_EQ(0.0, 2.0 / dbl_inf); >+ EXPECT_EQ(0, any_dur / inf); >+ EXPECT_EQ(0, any_dur / -inf); >+ EXPECT_EQ(0, -any_dur / inf); >+ EXPECT_EQ(0, -any_dur / -inf); >+ EXPECT_EQ(0, absl::ZeroDuration() / inf); >+ >+ // Division of Duration by a Duration overflow/underflow >+ EXPECT_EQ(kint64max, sec_max / absl::Milliseconds(1)); >+ EXPECT_EQ(kint64max, -sec_max / -absl::Milliseconds(1)); >+ EXPECT_EQ(kint64min, -sec_max / absl::Milliseconds(1)); >+ EXPECT_EQ(kint64min, sec_max / -absl::Milliseconds(1)); >+} >+ >+TEST(Duration, InfinityFDiv) { >+ const absl::Duration any_dur = absl::Seconds(1); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, inf)); >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -inf)); >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, any_dur)); >+ EXPECT_EQ(0.0, absl::FDivDuration(any_dur, inf)); >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -any_dur)); >+ EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, -inf)); >+ >+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, inf)); >+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -inf)); >+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, any_dur)); >+ EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, inf)); >+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -any_dur)); >+ EXPECT_EQ(0.0, absl::FDivDuration(any_dur, -inf)); >+} >+ >+TEST(Duration, DivisionByZero) { >+ const absl::Duration zero = absl::ZeroDuration(); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ const absl::Duration any_dur = absl::Seconds(1); >+ const double dbl_inf = std::numeric_limits<double>::infinity(); >+ const double dbl_denorm = std::numeric_limits<double>::denorm_min(); >+ >+ // IEEE 754 behavior >+ double z = 0.0, two = 2.0; >+ EXPECT_TRUE(std::isinf(two / z)); >+ EXPECT_TRUE(std::isnan(z / z)); // We'll return inf >+ >+ // Operator/(Duration, double) >+ EXPECT_EQ(inf, zero / 0.0); >+ EXPECT_EQ(-inf, zero / -0.0); >+ EXPECT_EQ(inf, any_dur / 0.0); >+ EXPECT_EQ(-inf, any_dur / -0.0); >+ EXPECT_EQ(-inf, -any_dur / 0.0); >+ EXPECT_EQ(inf, -any_dur / -0.0); >+ >+ // Tests dividing by a number very close to, but not quite zero. >+ EXPECT_EQ(zero, zero / dbl_denorm); >+ EXPECT_EQ(zero, zero / -dbl_denorm); >+ EXPECT_EQ(inf, any_dur / dbl_denorm); >+ EXPECT_EQ(-inf, any_dur / -dbl_denorm); >+ EXPECT_EQ(-inf, -any_dur / dbl_denorm); >+ EXPECT_EQ(inf, -any_dur / -dbl_denorm); >+ >+ // IDiv >+ absl::Duration rem = zero; >+ EXPECT_EQ(kint64max, absl::IDivDuration(zero, zero, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = zero; >+ EXPECT_EQ(kint64max, absl::IDivDuration(any_dur, zero, &rem)); >+ EXPECT_EQ(inf, rem); >+ >+ rem = zero; >+ EXPECT_EQ(kint64min, absl::IDivDuration(-any_dur, zero, &rem)); >+ EXPECT_EQ(-inf, rem); >+ >+ // Operator/(Duration, Duration) >+ EXPECT_EQ(kint64max, zero / zero); >+ EXPECT_EQ(kint64max, any_dur / zero); >+ EXPECT_EQ(kint64min, -any_dur / zero); >+ >+ // FDiv >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(zero, zero)); >+ EXPECT_EQ(dbl_inf, absl::FDivDuration(any_dur, zero)); >+ EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero)); >+} >+ >+TEST(Duration, Range) { >+ const absl::Duration range = ApproxYears(100 * 1e9); >+ const absl::Duration range_future = range; >+ const absl::Duration range_past = -range; >+ >+ EXPECT_LT(range_future, absl::InfiniteDuration()); >+ EXPECT_GT(range_past, -absl::InfiniteDuration()); >+ >+ const absl::Duration full_range = range_future - range_past; >+ EXPECT_GT(full_range, absl::ZeroDuration()); >+ EXPECT_LT(full_range, absl::InfiniteDuration()); >+ >+ const absl::Duration neg_full_range = range_past - range_future; >+ EXPECT_LT(neg_full_range, absl::ZeroDuration()); >+ EXPECT_GT(neg_full_range, -absl::InfiniteDuration()); >+ >+ EXPECT_LT(neg_full_range, full_range); >+ EXPECT_EQ(neg_full_range, -full_range); >+} >+ >+TEST(Duration, RelationalOperators) { >+#define TEST_REL_OPS(UNIT) \ >+ static_assert(UNIT(2) == UNIT(2), ""); \ >+ static_assert(UNIT(1) != UNIT(2), ""); \ >+ static_assert(UNIT(1) < UNIT(2), ""); \ >+ static_assert(UNIT(3) > UNIT(2), ""); \ >+ static_assert(UNIT(1) <= UNIT(2), ""); \ >+ static_assert(UNIT(2) <= UNIT(2), ""); \ >+ static_assert(UNIT(3) >= UNIT(2), ""); \ >+ static_assert(UNIT(2) >= UNIT(2), ""); >+ >+ TEST_REL_OPS(absl::Nanoseconds); >+ TEST_REL_OPS(absl::Microseconds); >+ TEST_REL_OPS(absl::Milliseconds); >+ TEST_REL_OPS(absl::Seconds); >+ TEST_REL_OPS(absl::Minutes); >+ TEST_REL_OPS(absl::Hours); >+ >+#undef TEST_REL_OPS >+} >+ >+TEST(Duration, Addition) { >+#define TEST_ADD_OPS(UNIT) \ >+ do { \ >+ EXPECT_EQ(UNIT(2), UNIT(1) + UNIT(1)); \ >+ EXPECT_EQ(UNIT(1), UNIT(2) - UNIT(1)); \ >+ EXPECT_EQ(UNIT(0), UNIT(2) - UNIT(2)); \ >+ EXPECT_EQ(UNIT(-1), UNIT(1) - UNIT(2)); \ >+ EXPECT_EQ(UNIT(-2), UNIT(0) - UNIT(2)); \ >+ EXPECT_EQ(UNIT(-2), UNIT(1) - UNIT(3)); \ >+ absl::Duration a = UNIT(1); \ >+ a += UNIT(1); \ >+ EXPECT_EQ(UNIT(2), a); \ >+ a -= UNIT(1); \ >+ EXPECT_EQ(UNIT(1), a); \ >+ } while (0) >+ >+ TEST_ADD_OPS(absl::Nanoseconds); >+ TEST_ADD_OPS(absl::Microseconds); >+ TEST_ADD_OPS(absl::Milliseconds); >+ TEST_ADD_OPS(absl::Seconds); >+ TEST_ADD_OPS(absl::Minutes); >+ TEST_ADD_OPS(absl::Hours); >+ >+#undef TEST_ADD_OPS >+ >+ EXPECT_EQ(absl::Seconds(2), absl::Seconds(3) - 2 * absl::Milliseconds(500)); >+ EXPECT_EQ(absl::Seconds(2) + absl::Milliseconds(500), >+ absl::Seconds(3) - absl::Milliseconds(500)); >+ >+ EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(998), >+ absl::Milliseconds(999) + absl::Milliseconds(999)); >+ >+ EXPECT_EQ(absl::Milliseconds(-1), >+ absl::Milliseconds(998) - absl::Milliseconds(999)); >+ >+ // Tests fractions of a nanoseconds. These are implementation details only. >+ EXPECT_GT(absl::Nanoseconds(1), absl::Nanoseconds(1) / 2); >+ EXPECT_EQ(absl::Nanoseconds(1), >+ absl::Nanoseconds(1) / 2 + absl::Nanoseconds(1) / 2); >+ EXPECT_GT(absl::Nanoseconds(1) / 4, absl::Nanoseconds(0)); >+ EXPECT_EQ(absl::Nanoseconds(1) / 8, absl::Nanoseconds(0)); >+ >+ // Tests subtraction that will cause wrap around of the rep_lo_ bits. >+ absl::Duration d_7_5 = absl::Seconds(7) + absl::Milliseconds(500); >+ absl::Duration d_3_7 = absl::Seconds(3) + absl::Milliseconds(700); >+ absl::Duration ans_3_8 = absl::Seconds(3) + absl::Milliseconds(800); >+ EXPECT_EQ(ans_3_8, d_7_5 - d_3_7); >+ >+ // Subtracting min_duration >+ absl::Duration min_dur = absl::Seconds(kint64min); >+ EXPECT_EQ(absl::Seconds(0), min_dur - min_dur); >+ EXPECT_EQ(absl::Seconds(kint64max), absl::Seconds(-1) - min_dur); >+} >+ >+TEST(Duration, Negation) { >+ // By storing negations of various values in constexpr variables we >+ // verify that the initializers are constant expressions. >+ constexpr absl::Duration negated_zero_duration = -absl::ZeroDuration(); >+ EXPECT_EQ(negated_zero_duration, absl::ZeroDuration()); >+ >+ constexpr absl::Duration negated_infinite_duration = >+ -absl::InfiniteDuration(); >+ EXPECT_NE(negated_infinite_duration, absl::InfiniteDuration()); >+ EXPECT_EQ(-negated_infinite_duration, absl::InfiniteDuration()); >+ >+ // The public APIs to check if a duration is infinite depend on using >+ // -InfiniteDuration(), but we're trying to test operator- here, so we >+ // need to use the lower-level internal query IsInfiniteDuration. >+ EXPECT_TRUE( >+ absl::time_internal::IsInfiniteDuration(negated_infinite_duration)); >+ >+ // The largest Duration is kint64max seconds and kTicksPerSecond - 1 ticks. >+ // Using the absl::time_internal::MakeDuration API is the cleanest way to >+ // construct that Duration. >+ constexpr absl::Duration max_duration = absl::time_internal::MakeDuration( >+ kint64max, absl::time_internal::kTicksPerSecond - 1); >+ constexpr absl::Duration negated_max_duration = -max_duration; >+ // The largest negatable value is one tick above the minimum representable; >+ // it's the negation of max_duration. >+ constexpr absl::Duration nearly_min_duration = >+ absl::time_internal::MakeDuration(kint64min, int64_t{1}); >+ constexpr absl::Duration negated_nearly_min_duration = -nearly_min_duration; >+ >+ EXPECT_EQ(negated_max_duration, nearly_min_duration); >+ EXPECT_EQ(negated_nearly_min_duration, max_duration); >+ EXPECT_EQ(-(-max_duration), max_duration); >+ >+ constexpr absl::Duration min_duration = >+ absl::time_internal::MakeDuration(kint64min); >+ constexpr absl::Duration negated_min_duration = -min_duration; >+ EXPECT_EQ(negated_min_duration, absl::InfiniteDuration()); >+} >+ >+TEST(Duration, AbsoluteValue) { >+ EXPECT_EQ(absl::ZeroDuration(), AbsDuration(absl::ZeroDuration())); >+ EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(1))); >+ EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(-1))); >+ >+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(absl::InfiniteDuration())); >+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(-absl::InfiniteDuration())); >+ >+ absl::Duration max_dur = >+ absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4); >+ EXPECT_EQ(max_dur, AbsDuration(max_dur)); >+ >+ absl::Duration min_dur = absl::Seconds(kint64min); >+ EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(min_dur)); >+ EXPECT_EQ(max_dur, AbsDuration(min_dur + absl::Nanoseconds(1) / 4)); >+} >+ >+TEST(Duration, Multiplication) { >+#define TEST_MUL_OPS(UNIT) \ >+ do { \ >+ EXPECT_EQ(UNIT(5), UNIT(2) * 2.5); \ >+ EXPECT_EQ(UNIT(2), UNIT(5) / 2.5); \ >+ EXPECT_EQ(UNIT(-5), UNIT(-2) * 2.5); \ >+ EXPECT_EQ(UNIT(-5), -UNIT(2) * 2.5); \ >+ EXPECT_EQ(UNIT(-5), UNIT(2) * -2.5); \ >+ EXPECT_EQ(UNIT(-2), UNIT(-5) / 2.5); \ >+ EXPECT_EQ(UNIT(-2), -UNIT(5) / 2.5); \ >+ EXPECT_EQ(UNIT(-2), UNIT(5) / -2.5); \ >+ EXPECT_EQ(UNIT(2), UNIT(11) % UNIT(3)); \ >+ absl::Duration a = UNIT(2); \ >+ a *= 2.5; \ >+ EXPECT_EQ(UNIT(5), a); \ >+ a /= 2.5; \ >+ EXPECT_EQ(UNIT(2), a); \ >+ a %= UNIT(1); \ >+ EXPECT_EQ(UNIT(0), a); \ >+ absl::Duration big = UNIT(1000000000); \ >+ big *= 3; \ >+ big /= 3; \ >+ EXPECT_EQ(UNIT(1000000000), big); \ >+ EXPECT_EQ(-UNIT(2), -UNIT(2)); \ >+ EXPECT_EQ(-UNIT(2), UNIT(2) * -1); \ >+ EXPECT_EQ(-UNIT(2), -1 * UNIT(2)); \ >+ EXPECT_EQ(-UNIT(-2), UNIT(2)); \ >+ EXPECT_EQ(2, UNIT(2) / UNIT(1)); \ >+ absl::Duration rem; \ >+ EXPECT_EQ(2, absl::IDivDuration(UNIT(2), UNIT(1), &rem)); \ >+ EXPECT_EQ(2.0, absl::FDivDuration(UNIT(2), UNIT(1))); \ >+ } while (0) >+ >+ TEST_MUL_OPS(absl::Nanoseconds); >+ TEST_MUL_OPS(absl::Microseconds); >+ TEST_MUL_OPS(absl::Milliseconds); >+ TEST_MUL_OPS(absl::Seconds); >+ TEST_MUL_OPS(absl::Minutes); >+ TEST_MUL_OPS(absl::Hours); >+ >+#undef TEST_MUL_OPS >+ >+ // Ensures that multiplication and division by 1 with a maxed-out durations >+ // doesn't lose precision. >+ absl::Duration max_dur = >+ absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4); >+ absl::Duration min_dur = absl::Seconds(kint64min); >+ EXPECT_EQ(max_dur, max_dur * 1); >+ EXPECT_EQ(max_dur, max_dur / 1); >+ EXPECT_EQ(min_dur, min_dur * 1); >+ EXPECT_EQ(min_dur, min_dur / 1); >+ >+ // Tests division on a Duration with a large number of significant digits. >+ // Tests when the digits span hi and lo as well as only in hi. >+ absl::Duration sigfigs = absl::Seconds(2000000000) + absl::Nanoseconds(3); >+ EXPECT_EQ(absl::Seconds(666666666) + absl::Nanoseconds(666666667) + >+ absl::Nanoseconds(1) / 2, >+ sigfigs / 3); >+ sigfigs = absl::Seconds(7000000000LL); >+ EXPECT_EQ(absl::Seconds(2333333333) + absl::Nanoseconds(333333333) + >+ absl::Nanoseconds(1) / 4, >+ sigfigs / 3); >+ >+ EXPECT_EQ(absl::Seconds(7) + absl::Milliseconds(500), absl::Seconds(3) * 2.5); >+ EXPECT_EQ(absl::Seconds(8) * -1 + absl::Milliseconds(300), >+ (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5); >+ EXPECT_EQ(-absl::Seconds(8) + absl::Milliseconds(300), >+ (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5); >+ EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(875), >+ (absl::Seconds(7) + absl::Milliseconds(500)) / 4); >+ EXPECT_EQ(absl::Seconds(30), >+ (absl::Seconds(7) + absl::Milliseconds(500)) / 0.25); >+ EXPECT_EQ(absl::Seconds(3), >+ (absl::Seconds(7) + absl::Milliseconds(500)) / 2.5); >+ >+ // Tests division remainder. >+ EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(7) % absl::Nanoseconds(1)); >+ EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(0) % absl::Nanoseconds(10)); >+ EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(7) % absl::Nanoseconds(5)); >+ EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(2) % absl::Nanoseconds(5)); >+ >+ EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(10) % absl::Nanoseconds(3)); >+ EXPECT_EQ(absl::Nanoseconds(1), >+ absl::Nanoseconds(10) % absl::Nanoseconds(-3)); >+ EXPECT_EQ(absl::Nanoseconds(-1), >+ absl::Nanoseconds(-10) % absl::Nanoseconds(3)); >+ EXPECT_EQ(absl::Nanoseconds(-1), >+ absl::Nanoseconds(-10) % absl::Nanoseconds(-3)); >+ >+ EXPECT_EQ(absl::Milliseconds(100), >+ absl::Seconds(1) % absl::Milliseconds(300)); >+ EXPECT_EQ( >+ absl::Milliseconds(300), >+ (absl::Seconds(3) + absl::Milliseconds(800)) % absl::Milliseconds(500)); >+ >+ EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(1) % absl::Seconds(1)); >+ EXPECT_EQ(absl::Nanoseconds(-1), absl::Nanoseconds(-1) % absl::Seconds(1)); >+ EXPECT_EQ(0, absl::Nanoseconds(-1) / absl::Seconds(1)); // Actual -1e-9 >+ >+ // Tests identity a = (a/b)*b + a%b >+#define TEST_MOD_IDENTITY(a, b) \ >+ EXPECT_EQ((a), ((a) / (b))*(b) + ((a)%(b))) >+ >+ TEST_MOD_IDENTITY(absl::Seconds(0), absl::Seconds(2)); >+ TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(1)); >+ TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(2)); >+ TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(1)); >+ >+ TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(1)); >+ TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(-1)); >+ TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(-1)); >+ >+ TEST_MOD_IDENTITY(absl::Nanoseconds(0), absl::Nanoseconds(2)); >+ TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(1)); >+ TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(2)); >+ TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(1)); >+ >+ TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(1)); >+ TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(-1)); >+ TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(-1)); >+ >+ // Mixed seconds + subseconds >+ absl::Duration mixed_a = absl::Seconds(1) + absl::Nanoseconds(2); >+ absl::Duration mixed_b = absl::Seconds(1) + absl::Nanoseconds(3); >+ >+ TEST_MOD_IDENTITY(absl::Seconds(0), mixed_a); >+ TEST_MOD_IDENTITY(mixed_a, mixed_a); >+ TEST_MOD_IDENTITY(mixed_a, mixed_b); >+ TEST_MOD_IDENTITY(mixed_b, mixed_a); >+ >+ TEST_MOD_IDENTITY(-mixed_a, mixed_b); >+ TEST_MOD_IDENTITY(mixed_a, -mixed_b); >+ TEST_MOD_IDENTITY(-mixed_a, -mixed_b); >+ >+#undef TEST_MOD_IDENTITY >+} >+ >+TEST(Duration, Truncation) { >+ const absl::Duration d = absl::Nanoseconds(1234567890); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ for (int unit_sign : {1, -1}) { // sign shouldn't matter >+ EXPECT_EQ(absl::Nanoseconds(1234567890), >+ Trunc(d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(1234567), >+ Trunc(d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(1234), >+ Trunc(d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(1), Trunc(d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(inf, Trunc(inf, unit_sign * absl::Seconds(1))); >+ >+ EXPECT_EQ(absl::Nanoseconds(-1234567890), >+ Trunc(-d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(-1234567), >+ Trunc(-d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(-1234), >+ Trunc(-d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(-1), Trunc(-d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(-inf, Trunc(-inf, unit_sign * absl::Seconds(1))); >+ } >+} >+ >+TEST(Duration, Flooring) { >+ const absl::Duration d = absl::Nanoseconds(1234567890); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ for (int unit_sign : {1, -1}) { // sign shouldn't matter >+ EXPECT_EQ(absl::Nanoseconds(1234567890), >+ absl::Floor(d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(1234567), >+ absl::Floor(d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(1234), >+ absl::Floor(d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(1), absl::Floor(d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(inf, absl::Floor(inf, unit_sign * absl::Seconds(1))); >+ >+ EXPECT_EQ(absl::Nanoseconds(-1234567890), >+ absl::Floor(-d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(-1234568), >+ absl::Floor(-d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(-1235), >+ absl::Floor(-d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(-2), absl::Floor(-d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(-inf, absl::Floor(-inf, unit_sign * absl::Seconds(1))); >+ } >+} >+ >+TEST(Duration, Ceiling) { >+ const absl::Duration d = absl::Nanoseconds(1234567890); >+ const absl::Duration inf = absl::InfiniteDuration(); >+ for (int unit_sign : {1, -1}) { // // sign shouldn't matter >+ EXPECT_EQ(absl::Nanoseconds(1234567890), >+ absl::Ceil(d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(1234568), >+ absl::Ceil(d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(1235), >+ absl::Ceil(d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(2), absl::Ceil(d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(inf, absl::Ceil(inf, unit_sign * absl::Seconds(1))); >+ >+ EXPECT_EQ(absl::Nanoseconds(-1234567890), >+ absl::Ceil(-d, unit_sign * absl::Nanoseconds(1))); >+ EXPECT_EQ(absl::Microseconds(-1234567), >+ absl::Ceil(-d, unit_sign * absl::Microseconds(1))); >+ EXPECT_EQ(absl::Milliseconds(-1234), >+ absl::Ceil(-d, unit_sign * absl::Milliseconds(1))); >+ EXPECT_EQ(absl::Seconds(-1), absl::Ceil(-d, unit_sign * absl::Seconds(1))); >+ EXPECT_EQ(-inf, absl::Ceil(-inf, unit_sign * absl::Seconds(1))); >+ } >+} >+ >+TEST(Duration, RoundTripUnits) { >+ const int kRange = 100000; >+ >+#define ROUND_TRIP_UNIT(U, LOW, HIGH) \ >+ do { \ >+ for (int64_t i = LOW; i < HIGH; ++i) { \ >+ absl::Duration d = absl::U(i); \ >+ if (d == absl::InfiniteDuration()) \ >+ EXPECT_EQ(kint64max, d / absl::U(1)); \ >+ else if (d == -absl::InfiniteDuration()) \ >+ EXPECT_EQ(kint64min, d / absl::U(1)); \ >+ else \ >+ EXPECT_EQ(i, absl::U(i) / absl::U(1)); \ >+ } \ >+ } while (0) >+ >+ ROUND_TRIP_UNIT(Nanoseconds, kint64min, kint64min + kRange); >+ ROUND_TRIP_UNIT(Nanoseconds, -kRange, kRange); >+ ROUND_TRIP_UNIT(Nanoseconds, kint64max - kRange, kint64max); >+ >+ ROUND_TRIP_UNIT(Microseconds, kint64min, kint64min + kRange); >+ ROUND_TRIP_UNIT(Microseconds, -kRange, kRange); >+ ROUND_TRIP_UNIT(Microseconds, kint64max - kRange, kint64max); >+ >+ ROUND_TRIP_UNIT(Milliseconds, kint64min, kint64min + kRange); >+ ROUND_TRIP_UNIT(Milliseconds, -kRange, kRange); >+ ROUND_TRIP_UNIT(Milliseconds, kint64max - kRange, kint64max); >+ >+ ROUND_TRIP_UNIT(Seconds, kint64min, kint64min + kRange); >+ ROUND_TRIP_UNIT(Seconds, -kRange, kRange); >+ ROUND_TRIP_UNIT(Seconds, kint64max - kRange, kint64max); >+ >+ ROUND_TRIP_UNIT(Minutes, kint64min / 60, kint64min / 60 + kRange); >+ ROUND_TRIP_UNIT(Minutes, -kRange, kRange); >+ ROUND_TRIP_UNIT(Minutes, kint64max / 60 - kRange, kint64max / 60); >+ >+ ROUND_TRIP_UNIT(Hours, kint64min / 3600, kint64min / 3600 + kRange); >+ ROUND_TRIP_UNIT(Hours, -kRange, kRange); >+ ROUND_TRIP_UNIT(Hours, kint64max / 3600 - kRange, kint64max / 3600); >+ >+#undef ROUND_TRIP_UNIT >+} >+ >+TEST(Duration, TruncConversions) { >+ // Tests ToTimespec()/DurationFromTimespec() >+ const struct { >+ absl::Duration d; >+ timespec ts; >+ } to_ts[] = { >+ {absl::Seconds(1) + absl::Nanoseconds(1), {1, 1}}, >+ {absl::Seconds(1) + absl::Nanoseconds(1) / 2, {1, 0}}, >+ {absl::Seconds(1) + absl::Nanoseconds(0), {1, 0}}, >+ {absl::Seconds(0) + absl::Nanoseconds(0), {0, 0}}, >+ {absl::Seconds(0) - absl::Nanoseconds(1) / 2, {0, 0}}, >+ {absl::Seconds(0) - absl::Nanoseconds(1), {-1, 999999999}}, >+ {absl::Seconds(-1) + absl::Nanoseconds(1), {-1, 1}}, >+ {absl::Seconds(-1) + absl::Nanoseconds(1) / 2, {-1, 1}}, >+ {absl::Seconds(-1) + absl::Nanoseconds(0), {-1, 0}}, >+ {absl::Seconds(-1) - absl::Nanoseconds(1) / 2, {-1, 0}}, >+ }; >+ for (const auto& test : to_ts) { >+ EXPECT_THAT(absl::ToTimespec(test.d), TimespecMatcher(test.ts)); >+ } >+ const struct { >+ timespec ts; >+ absl::Duration d; >+ } from_ts[] = { >+ {{1, 1}, absl::Seconds(1) + absl::Nanoseconds(1)}, >+ {{1, 0}, absl::Seconds(1) + absl::Nanoseconds(0)}, >+ {{0, 0}, absl::Seconds(0) + absl::Nanoseconds(0)}, >+ {{0, -1}, absl::Seconds(0) - absl::Nanoseconds(1)}, >+ {{-1, 999999999}, absl::Seconds(0) - absl::Nanoseconds(1)}, >+ {{-1, 1}, absl::Seconds(-1) + absl::Nanoseconds(1)}, >+ {{-1, 0}, absl::Seconds(-1) + absl::Nanoseconds(0)}, >+ {{-1, -1}, absl::Seconds(-1) - absl::Nanoseconds(1)}, >+ {{-2, 999999999}, absl::Seconds(-1) - absl::Nanoseconds(1)}, >+ }; >+ for (const auto& test : from_ts) { >+ EXPECT_EQ(test.d, absl::DurationFromTimespec(test.ts)); >+ } >+ >+ // Tests ToTimeval()/DurationFromTimeval() (same as timespec above) >+ const struct { >+ absl::Duration d; >+ timeval tv; >+ } to_tv[] = { >+ {absl::Seconds(1) + absl::Microseconds(1), {1, 1}}, >+ {absl::Seconds(1) + absl::Microseconds(1) / 2, {1, 0}}, >+ {absl::Seconds(1) + absl::Microseconds(0), {1, 0}}, >+ {absl::Seconds(0) + absl::Microseconds(0), {0, 0}}, >+ {absl::Seconds(0) - absl::Microseconds(1) / 2, {0, 0}}, >+ {absl::Seconds(0) - absl::Microseconds(1), {-1, 999999}}, >+ {absl::Seconds(-1) + absl::Microseconds(1), {-1, 1}}, >+ {absl::Seconds(-1) + absl::Microseconds(1) / 2, {-1, 1}}, >+ {absl::Seconds(-1) + absl::Microseconds(0), {-1, 0}}, >+ {absl::Seconds(-1) - absl::Microseconds(1) / 2, {-1, 0}}, >+ }; >+ for (const auto& test : to_tv) { >+ EXPECT_THAT(absl::ToTimeval(test.d), TimevalMatcher(test.tv)); >+ } >+ const struct { >+ timeval tv; >+ absl::Duration d; >+ } from_tv[] = { >+ {{1, 1}, absl::Seconds(1) + absl::Microseconds(1)}, >+ {{1, 0}, absl::Seconds(1) + absl::Microseconds(0)}, >+ {{0, 0}, absl::Seconds(0) + absl::Microseconds(0)}, >+ {{0, -1}, absl::Seconds(0) - absl::Microseconds(1)}, >+ {{-1, 999999}, absl::Seconds(0) - absl::Microseconds(1)}, >+ {{-1, 1}, absl::Seconds(-1) + absl::Microseconds(1)}, >+ {{-1, 0}, absl::Seconds(-1) + absl::Microseconds(0)}, >+ {{-1, -1}, absl::Seconds(-1) - absl::Microseconds(1)}, >+ {{-2, 999999}, absl::Seconds(-1) - absl::Microseconds(1)}, >+ }; >+ for (const auto& test : from_tv) { >+ EXPECT_EQ(test.d, absl::DurationFromTimeval(test.tv)); >+ } >+} >+ >+TEST(Duration, SmallConversions) { >+ // Special tests for conversions of small durations. >+ >+ EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0)); >+ // TODO(bww): Is the next one OK? >+ EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0.124999999e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.125e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.250e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.375e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.500e-9)); >+ EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.625e-9)); >+ EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.750e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(0.875e-9)); >+ EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(1.000e-9)); >+ >+ EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(-0.124999999e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.125e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.250e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.375e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.500e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.625e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.750e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-0.875e-9)); >+ EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-1.000e-9)); >+ >+ timespec ts; >+ ts.tv_sec = 0; >+ ts.tv_nsec = 0; >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(0)), TimespecMatcher(ts)); >+ // TODO(bww): Are the next three OK? >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(1) / 4), TimespecMatcher(ts)); >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(2) / 4), TimespecMatcher(ts)); >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(3) / 4), TimespecMatcher(ts)); >+ ts.tv_nsec = 1; >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(4) / 4), TimespecMatcher(ts)); >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(5) / 4), TimespecMatcher(ts)); >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(6) / 4), TimespecMatcher(ts)); >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(7) / 4), TimespecMatcher(ts)); >+ ts.tv_nsec = 2; >+ EXPECT_THAT(ToTimespec(absl::Nanoseconds(8) / 4), TimespecMatcher(ts)); >+ >+ timeval tv; >+ tv.tv_sec = 0; >+ tv.tv_usec = 0; >+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(0)), TimevalMatcher(tv)); >+ // TODO(bww): Is the next one OK? >+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(999)), TimevalMatcher(tv)); >+ tv.tv_usec = 1; >+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(1000)), TimevalMatcher(tv)); >+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(1999)), TimevalMatcher(tv)); >+ tv.tv_usec = 2; >+ EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv)); >+} >+ >+void VerifySameAsMul(double time_as_seconds, int* const misses) { >+ auto direct_seconds = absl::Seconds(time_as_seconds); >+ auto mul_by_one_second = time_as_seconds * absl::Seconds(1); >+ if (direct_seconds != mul_by_one_second) { >+ if (*misses > 10) return; >+ ASSERT_LE(++(*misses), 10) << "Too many errors, not reporting more."; >+ EXPECT_EQ(direct_seconds, mul_by_one_second) >+ << "given double time_as_seconds = " << std::setprecision(17) >+ << time_as_seconds; >+ } >+} >+ >+// For a variety of interesting durations, we find the exact point >+// where one double converts to that duration, and the very next double >+// converts to the next duration. For both of those points, verify that >+// Seconds(point) returns the same duration as point * Seconds(1.0) >+TEST(Duration, ToDoubleSecondsCheckEdgeCases) { >+ constexpr uint32_t kTicksPerSecond = absl::time_internal::kTicksPerSecond; >+ constexpr auto duration_tick = absl::time_internal::MakeDuration(0, 1u); >+ int misses = 0; >+ for (int64_t seconds = 0; seconds < 99; ++seconds) { >+ uint32_t tick_vals[] = {0, +999, +999999, +999999999, kTicksPerSecond - 1, >+ 0, 1000, 1000000, 1000000000, kTicksPerSecond, >+ 1, 1001, 1000001, 1000000001, kTicksPerSecond + 1, >+ 2, 1002, 1000002, 1000000002, kTicksPerSecond + 2, >+ 3, 1003, 1000003, 1000000003, kTicksPerSecond + 3, >+ 4, 1004, 1000004, 1000000004, kTicksPerSecond + 4, >+ 5, 6, 7, 8, 9}; >+ for (uint32_t ticks : tick_vals) { >+ absl::Duration s_plus_t = absl::Seconds(seconds) + ticks * duration_tick; >+ for (absl::Duration d : {s_plus_t, -s_plus_t}) { >+ absl::Duration after_d = d + duration_tick; >+ EXPECT_NE(d, after_d); >+ EXPECT_EQ(after_d - d, duration_tick); >+ >+ double low_edge = ToDoubleSeconds(d); >+ EXPECT_EQ(d, absl::Seconds(low_edge)); >+ >+ double high_edge = ToDoubleSeconds(after_d); >+ EXPECT_EQ(after_d, absl::Seconds(high_edge)); >+ >+ for (;;) { >+ double midpoint = low_edge + (high_edge - low_edge) / 2; >+ if (midpoint == low_edge || midpoint == high_edge) break; >+ absl::Duration mid_duration = absl::Seconds(midpoint); >+ if (mid_duration == d) { >+ low_edge = midpoint; >+ } else { >+ EXPECT_EQ(mid_duration, after_d); >+ high_edge = midpoint; >+ } >+ } >+ // Now low_edge is the highest double that converts to Duration d, >+ // and high_edge is the lowest double that converts to Duration after_d. >+ VerifySameAsMul(low_edge, &misses); >+ VerifySameAsMul(high_edge, &misses); >+ } >+ } >+ } >+} >+ >+TEST(Duration, ToDoubleSecondsCheckRandom) { >+ std::random_device rd; >+ std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}); >+ std::mt19937_64 gen(seed); >+ // We want doubles distributed from 1/8ns up to 2^63, where >+ // as many values are tested from 1ns to 2ns as from 1sec to 2sec, >+ // so even distribute along a log-scale of those values, and >+ // exponentiate before using them. (9.223377e+18 is just slightly >+ // out of bounds for absl::Duration.) >+ std::uniform_real_distribution<double> uniform(std::log(0.125e-9), >+ std::log(9.223377e+18)); >+ int misses = 0; >+ for (int i = 0; i < 1000000; ++i) { >+ double d = std::exp(uniform(gen)); >+ VerifySameAsMul(d, &misses); >+ VerifySameAsMul(-d, &misses); >+ } >+} >+ >+TEST(Duration, ConversionSaturation) { >+ absl::Duration d; >+ >+ const auto max_timeval_sec = >+ std::numeric_limits<decltype(timeval::tv_sec)>::max(); >+ const auto min_timeval_sec = >+ std::numeric_limits<decltype(timeval::tv_sec)>::min(); >+ timeval tv; >+ tv.tv_sec = max_timeval_sec; >+ tv.tv_usec = 999998; >+ d = absl::DurationFromTimeval(tv); >+ tv = ToTimeval(d); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999998, tv.tv_usec); >+ d += absl::Microseconds(1); >+ tv = ToTimeval(d); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999999, tv.tv_usec); >+ d += absl::Microseconds(1); // no effect >+ tv = ToTimeval(d); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999999, tv.tv_usec); >+ >+ tv.tv_sec = min_timeval_sec; >+ tv.tv_usec = 1; >+ d = absl::DurationFromTimeval(tv); >+ tv = ToTimeval(d); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(1, tv.tv_usec); >+ d -= absl::Microseconds(1); >+ tv = ToTimeval(d); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(0, tv.tv_usec); >+ d -= absl::Microseconds(1); // no effect >+ tv = ToTimeval(d); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(0, tv.tv_usec); >+ >+ const auto max_timespec_sec = >+ std::numeric_limits<decltype(timespec::tv_sec)>::max(); >+ const auto min_timespec_sec = >+ std::numeric_limits<decltype(timespec::tv_sec)>::min(); >+ timespec ts; >+ ts.tv_sec = max_timespec_sec; >+ ts.tv_nsec = 999999998; >+ d = absl::DurationFromTimespec(ts); >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999998, ts.tv_nsec); >+ d += absl::Nanoseconds(1); >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999999, ts.tv_nsec); >+ d += absl::Nanoseconds(1); // no effect >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999999, ts.tv_nsec); >+ >+ ts.tv_sec = min_timespec_sec; >+ ts.tv_nsec = 1; >+ d = absl::DurationFromTimespec(ts); >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(1, ts.tv_nsec); >+ d -= absl::Nanoseconds(1); >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(0, ts.tv_nsec); >+ d -= absl::Nanoseconds(1); // no effect >+ ts = absl::ToTimespec(d); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(0, ts.tv_nsec); >+} >+ >+TEST(Duration, FormatDuration) { >+ // Example from Go's docs. >+ EXPECT_EQ("72h3m0.5s", >+ absl::FormatDuration(absl::Hours(72) + absl::Minutes(3) + >+ absl::Milliseconds(500))); >+ // Go's largest time: 2540400h10m10.000000000s >+ EXPECT_EQ("2540400h10m10s", >+ absl::FormatDuration(absl::Hours(2540400) + absl::Minutes(10) + >+ absl::Seconds(10))); >+ >+ EXPECT_EQ("0", absl::FormatDuration(absl::ZeroDuration())); >+ EXPECT_EQ("0", absl::FormatDuration(absl::Seconds(0))); >+ EXPECT_EQ("0", absl::FormatDuration(absl::Nanoseconds(0))); >+ >+ EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1))); >+ EXPECT_EQ("1us", absl::FormatDuration(absl::Microseconds(1))); >+ EXPECT_EQ("1ms", absl::FormatDuration(absl::Milliseconds(1))); >+ EXPECT_EQ("1s", absl::FormatDuration(absl::Seconds(1))); >+ EXPECT_EQ("1m", absl::FormatDuration(absl::Minutes(1))); >+ EXPECT_EQ("1h", absl::FormatDuration(absl::Hours(1))); >+ >+ EXPECT_EQ("1h1m", absl::FormatDuration(absl::Hours(1) + absl::Minutes(1))); >+ EXPECT_EQ("1h1s", absl::FormatDuration(absl::Hours(1) + absl::Seconds(1))); >+ EXPECT_EQ("1m1s", absl::FormatDuration(absl::Minutes(1) + absl::Seconds(1))); >+ >+ EXPECT_EQ("1h0.25s", >+ absl::FormatDuration(absl::Hours(1) + absl::Milliseconds(250))); >+ EXPECT_EQ("1m0.25s", >+ absl::FormatDuration(absl::Minutes(1) + absl::Milliseconds(250))); >+ EXPECT_EQ("1h1m0.25s", >+ absl::FormatDuration(absl::Hours(1) + absl::Minutes(1) + >+ absl::Milliseconds(250))); >+ EXPECT_EQ("1h0.0005s", >+ absl::FormatDuration(absl::Hours(1) + absl::Microseconds(500))); >+ EXPECT_EQ("1h0.0000005s", >+ absl::FormatDuration(absl::Hours(1) + absl::Nanoseconds(500))); >+ >+ // Subsecond special case. >+ EXPECT_EQ("1.5ns", absl::FormatDuration(absl::Nanoseconds(1) + >+ absl::Nanoseconds(1) / 2)); >+ EXPECT_EQ("1.25ns", absl::FormatDuration(absl::Nanoseconds(1) + >+ absl::Nanoseconds(1) / 4)); >+ EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1) + >+ absl::Nanoseconds(1) / 9)); >+ EXPECT_EQ("1.2us", absl::FormatDuration(absl::Microseconds(1) + >+ absl::Nanoseconds(200))); >+ EXPECT_EQ("1.2ms", absl::FormatDuration(absl::Milliseconds(1) + >+ absl::Microseconds(200))); >+ EXPECT_EQ("1.0002ms", absl::FormatDuration(absl::Milliseconds(1) + >+ absl::Nanoseconds(200))); >+ EXPECT_EQ("1.00001ms", absl::FormatDuration(absl::Milliseconds(1) + >+ absl::Nanoseconds(10))); >+ EXPECT_EQ("1.000001ms", >+ absl::FormatDuration(absl::Milliseconds(1) + absl::Nanoseconds(1))); >+ >+ // Negative durations. >+ EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1))); >+ EXPECT_EQ("-1us", absl::FormatDuration(absl::Microseconds(-1))); >+ EXPECT_EQ("-1ms", absl::FormatDuration(absl::Milliseconds(-1))); >+ EXPECT_EQ("-1s", absl::FormatDuration(absl::Seconds(-1))); >+ EXPECT_EQ("-1m", absl::FormatDuration(absl::Minutes(-1))); >+ EXPECT_EQ("-1h", absl::FormatDuration(absl::Hours(-1))); >+ >+ EXPECT_EQ("-1h1m", >+ absl::FormatDuration(-(absl::Hours(1) + absl::Minutes(1)))); >+ EXPECT_EQ("-1h1s", >+ absl::FormatDuration(-(absl::Hours(1) + absl::Seconds(1)))); >+ EXPECT_EQ("-1m1s", >+ absl::FormatDuration(-(absl::Minutes(1) + absl::Seconds(1)))); >+ >+ EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1))); >+ EXPECT_EQ("-1.2us", absl::FormatDuration( >+ -(absl::Microseconds(1) + absl::Nanoseconds(200)))); >+ EXPECT_EQ("-1.2ms", absl::FormatDuration( >+ -(absl::Milliseconds(1) + absl::Microseconds(200)))); >+ EXPECT_EQ("-1.0002ms", absl::FormatDuration(-(absl::Milliseconds(1) + >+ absl::Nanoseconds(200)))); >+ EXPECT_EQ("-1.00001ms", absl::FormatDuration(-(absl::Milliseconds(1) + >+ absl::Nanoseconds(10)))); >+ EXPECT_EQ("-1.000001ms", absl::FormatDuration(-(absl::Milliseconds(1) + >+ absl::Nanoseconds(1)))); >+ >+ // >+ // Interesting corner cases. >+ // >+ >+ const absl::Duration qns = absl::Nanoseconds(1) / 4; >+ const absl::Duration max_dur = >+ absl::Seconds(kint64max) + (absl::Seconds(1) - qns); >+ const absl::Duration min_dur = absl::Seconds(kint64min); >+ >+ EXPECT_EQ("0.25ns", absl::FormatDuration(qns)); >+ EXPECT_EQ("-0.25ns", absl::FormatDuration(-qns)); >+ EXPECT_EQ("2562047788015215h30m7.99999999975s", >+ absl::FormatDuration(max_dur)); >+ EXPECT_EQ("-2562047788015215h30m8s", absl::FormatDuration(min_dur)); >+ >+ // Tests printing full precision from units that print using FDivDuration >+ EXPECT_EQ("55.00000000025s", absl::FormatDuration(absl::Seconds(55) + qns)); >+ EXPECT_EQ("55.00000025ms", >+ absl::FormatDuration(absl::Milliseconds(55) + qns)); >+ EXPECT_EQ("55.00025us", absl::FormatDuration(absl::Microseconds(55) + qns)); >+ EXPECT_EQ("55.25ns", absl::FormatDuration(absl::Nanoseconds(55) + qns)); >+ >+ // Formatting infinity >+ EXPECT_EQ("inf", absl::FormatDuration(absl::InfiniteDuration())); >+ EXPECT_EQ("-inf", absl::FormatDuration(-absl::InfiniteDuration())); >+ >+ // Formatting approximately +/- 100 billion years >+ const absl::Duration huge_range = ApproxYears(100000000000); >+ EXPECT_EQ("876000000000000h", absl::FormatDuration(huge_range)); >+ EXPECT_EQ("-876000000000000h", absl::FormatDuration(-huge_range)); >+ >+ EXPECT_EQ("876000000000000h0.999999999s", >+ absl::FormatDuration(huge_range + >+ (absl::Seconds(1) - absl::Nanoseconds(1)))); >+ EXPECT_EQ("876000000000000h0.9999999995s", >+ absl::FormatDuration( >+ huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 2))); >+ EXPECT_EQ("876000000000000h0.99999999975s", >+ absl::FormatDuration( >+ huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 4))); >+ >+ EXPECT_EQ("-876000000000000h0.999999999s", >+ absl::FormatDuration(-huge_range - >+ (absl::Seconds(1) - absl::Nanoseconds(1)))); >+ EXPECT_EQ("-876000000000000h0.9999999995s", >+ absl::FormatDuration( >+ -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 2))); >+ EXPECT_EQ("-876000000000000h0.99999999975s", >+ absl::FormatDuration( >+ -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 4))); >+} >+ >+TEST(Duration, ParseDuration) { >+ absl::Duration d; >+ >+ // No specified unit. Should only work for zero and infinity. >+ EXPECT_TRUE(absl::ParseDuration("0", &d)); >+ EXPECT_EQ(absl::ZeroDuration(), d); >+ EXPECT_TRUE(absl::ParseDuration("+0", &d)); >+ EXPECT_EQ(absl::ZeroDuration(), d); >+ EXPECT_TRUE(absl::ParseDuration("-0", &d)); >+ EXPECT_EQ(absl::ZeroDuration(), d); >+ >+ EXPECT_TRUE(absl::ParseDuration("inf", &d)); >+ EXPECT_EQ(absl::InfiniteDuration(), d); >+ EXPECT_TRUE(absl::ParseDuration("+inf", &d)); >+ EXPECT_EQ(absl::InfiniteDuration(), d); >+ EXPECT_TRUE(absl::ParseDuration("-inf", &d)); >+ EXPECT_EQ(-absl::InfiniteDuration(), d); >+ EXPECT_FALSE(absl::ParseDuration("infBlah", &d)); >+ >+ // Illegal input forms. >+ EXPECT_FALSE(absl::ParseDuration("", &d)); >+ EXPECT_FALSE(absl::ParseDuration("0.0", &d)); >+ EXPECT_FALSE(absl::ParseDuration(".0", &d)); >+ EXPECT_FALSE(absl::ParseDuration(".", &d)); >+ EXPECT_FALSE(absl::ParseDuration("01", &d)); >+ EXPECT_FALSE(absl::ParseDuration("1", &d)); >+ EXPECT_FALSE(absl::ParseDuration("-1", &d)); >+ EXPECT_FALSE(absl::ParseDuration("2", &d)); >+ EXPECT_FALSE(absl::ParseDuration("2 s", &d)); >+ EXPECT_FALSE(absl::ParseDuration(".s", &d)); >+ EXPECT_FALSE(absl::ParseDuration("-.s", &d)); >+ EXPECT_FALSE(absl::ParseDuration("s", &d)); >+ EXPECT_FALSE(absl::ParseDuration(" 2s", &d)); >+ EXPECT_FALSE(absl::ParseDuration("2s ", &d)); >+ EXPECT_FALSE(absl::ParseDuration(" 2s ", &d)); >+ EXPECT_FALSE(absl::ParseDuration("2mt", &d)); >+ EXPECT_FALSE(absl::ParseDuration("1e3s", &d)); >+ >+ // One unit type. >+ EXPECT_TRUE(absl::ParseDuration("1ns", &d)); >+ EXPECT_EQ(absl::Nanoseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1us", &d)); >+ EXPECT_EQ(absl::Microseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1ms", &d)); >+ EXPECT_EQ(absl::Milliseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1s", &d)); >+ EXPECT_EQ(absl::Seconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("2m", &d)); >+ EXPECT_EQ(absl::Minutes(2), d); >+ EXPECT_TRUE(absl::ParseDuration("2h", &d)); >+ EXPECT_EQ(absl::Hours(2), d); >+ >+ // Huge counts of a unit. >+ EXPECT_TRUE(absl::ParseDuration("9223372036854775807us", &d)); >+ EXPECT_EQ(absl::Microseconds(9223372036854775807), d); >+ EXPECT_TRUE(absl::ParseDuration("-9223372036854775807us", &d)); >+ EXPECT_EQ(absl::Microseconds(-9223372036854775807), d); >+ >+ // Multiple units. >+ EXPECT_TRUE(absl::ParseDuration("2h3m4s", &d)); >+ EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4), d); >+ EXPECT_TRUE(absl::ParseDuration("3m4s5us", &d)); >+ EXPECT_EQ(absl::Minutes(3) + absl::Seconds(4) + absl::Microseconds(5), d); >+ EXPECT_TRUE(absl::ParseDuration("2h3m4s5ms6us7ns", &d)); >+ EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4) + >+ absl::Milliseconds(5) + absl::Microseconds(6) + >+ absl::Nanoseconds(7), >+ d); >+ >+ // Multiple units out of order. >+ EXPECT_TRUE(absl::ParseDuration("2us3m4s5h", &d)); >+ EXPECT_EQ(absl::Hours(5) + absl::Minutes(3) + absl::Seconds(4) + >+ absl::Microseconds(2), >+ d); >+ >+ // Fractional values of units. >+ EXPECT_TRUE(absl::ParseDuration("1.5ns", &d)); >+ EXPECT_EQ(1.5 * absl::Nanoseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1.5us", &d)); >+ EXPECT_EQ(1.5 * absl::Microseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1.5ms", &d)); >+ EXPECT_EQ(1.5 * absl::Milliseconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1.5s", &d)); >+ EXPECT_EQ(1.5 * absl::Seconds(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1.5m", &d)); >+ EXPECT_EQ(1.5 * absl::Minutes(1), d); >+ EXPECT_TRUE(absl::ParseDuration("1.5h", &d)); >+ EXPECT_EQ(1.5 * absl::Hours(1), d); >+ >+ // Huge fractional counts of a unit. >+ EXPECT_TRUE(absl::ParseDuration("0.4294967295s", &d)); >+ EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d); >+ EXPECT_TRUE(absl::ParseDuration("0.429496729501234567890123456789s", &d)); >+ EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d); >+ >+ // Negative durations. >+ EXPECT_TRUE(absl::ParseDuration("-1s", &d)); >+ EXPECT_EQ(absl::Seconds(-1), d); >+ EXPECT_TRUE(absl::ParseDuration("-1m", &d)); >+ EXPECT_EQ(absl::Minutes(-1), d); >+ EXPECT_TRUE(absl::ParseDuration("-1h", &d)); >+ EXPECT_EQ(absl::Hours(-1), d); >+ >+ EXPECT_TRUE(absl::ParseDuration("-1h2s", &d)); >+ EXPECT_EQ(-(absl::Hours(1) + absl::Seconds(2)), d); >+ EXPECT_FALSE(absl::ParseDuration("1h-2s", &d)); >+ EXPECT_FALSE(absl::ParseDuration("-1h-2s", &d)); >+ EXPECT_FALSE(absl::ParseDuration("-1h -2s", &d)); >+} >+ >+TEST(Duration, FormatParseRoundTrip) { >+#define TEST_PARSE_ROUNDTRIP(d) \ >+ do { \ >+ std::string s = absl::FormatDuration(d); \ >+ absl::Duration dur; \ >+ EXPECT_TRUE(absl::ParseDuration(s, &dur)); \ >+ EXPECT_EQ(d, dur); \ >+ } while (0) >+ >+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Microseconds(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Milliseconds(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Seconds(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Minutes(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Hours(1)); >+ TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(2)); >+ >+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(-1)); >+ TEST_PARSE_ROUNDTRIP(absl::Microseconds(-1)); >+ TEST_PARSE_ROUNDTRIP(absl::Milliseconds(-1)); >+ TEST_PARSE_ROUNDTRIP(absl::Seconds(-1)); >+ TEST_PARSE_ROUNDTRIP(absl::Minutes(-1)); >+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1)); >+ >+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(2)); >+ TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(-2)); >+ TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(-2)); >+ >+ TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1) + >+ absl::Nanoseconds(1) / 4); // 1.25ns >+ >+ const absl::Duration huge_range = ApproxYears(100000000000); >+ TEST_PARSE_ROUNDTRIP(huge_range); >+ TEST_PARSE_ROUNDTRIP(huge_range + (absl::Seconds(1) - absl::Nanoseconds(1))); >+ >+#undef TEST_PARSE_ROUNDTRIP >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format.cc >new file mode 100644 >index 00000000000..e98e60a372b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format.cc >@@ -0,0 +1,139 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <string.h> >+#include <cctype> >+#include <cstdint> >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+#include "absl/time/time.h" >+ >+namespace cctz = absl::time_internal::cctz; >+ >+namespace absl { >+ >+extern const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; >+extern const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; >+ >+extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z"; >+extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z"; >+ >+namespace { >+ >+const char kInfiniteFutureStr[] = "infinite-future"; >+const char kInfinitePastStr[] = "infinite-past"; >+ >+struct cctz_parts { >+ cctz::time_point<cctz::seconds> sec; >+ cctz::detail::femtoseconds fem; >+}; >+ >+inline cctz::time_point<cctz::seconds> unix_epoch() { >+ return std::chrono::time_point_cast<cctz::seconds>( >+ std::chrono::system_clock::from_time_t(0)); >+} >+ >+// Splits a Time into seconds and femtoseconds, which can be used with CCTZ. >+// Requires that 't' is finite. See duration.cc for details about rep_hi and >+// rep_lo. >+cctz_parts Split(absl::Time t) { >+ const auto d = time_internal::ToUnixDuration(t); >+ const int64_t rep_hi = time_internal::GetRepHi(d); >+ const int64_t rep_lo = time_internal::GetRepLo(d); >+ const auto sec = unix_epoch() + cctz::seconds(rep_hi); >+ const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4)); >+ return {sec, fem}; >+} >+ >+// Joins the given seconds and femtoseconds into a Time. See duration.cc for >+// details about rep_hi and rep_lo. >+absl::Time Join(const cctz_parts& parts) { >+ const int64_t rep_hi = (parts.sec - unix_epoch()).count(); >+ const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4); >+ const auto d = time_internal::MakeDuration(rep_hi, rep_lo); >+ return time_internal::FromUnixDuration(d); >+} >+ >+} // namespace >+ >+std::string FormatTime(const std::string& format, absl::Time t, absl::TimeZone tz) { >+ if (t == absl::InfiniteFuture()) return kInfiniteFutureStr; >+ if (t == absl::InfinitePast()) return kInfinitePastStr; >+ const auto parts = Split(t); >+ return cctz::detail::format(format, parts.sec, parts.fem, >+ cctz::time_zone(tz)); >+} >+ >+std::string FormatTime(absl::Time t, absl::TimeZone tz) { >+ return FormatTime(RFC3339_full, t, tz); >+} >+ >+std::string FormatTime(absl::Time t) { >+ return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone()); >+} >+ >+bool ParseTime(const std::string& format, const std::string& input, absl::Time* time, >+ std::string* err) { >+ return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err); >+} >+ >+// If the input std::string does not contain an explicit UTC offset, interpret >+// the fields with respect to the given TimeZone. >+bool ParseTime(const std::string& format, const std::string& input, absl::TimeZone tz, >+ absl::Time* time, std::string* err) { >+ const char* data = input.c_str(); >+ while (std::isspace(*data)) ++data; >+ >+ size_t inf_size = strlen(kInfiniteFutureStr); >+ if (strncmp(data, kInfiniteFutureStr, inf_size) == 0) { >+ const char* new_data = data + inf_size; >+ while (std::isspace(*new_data)) ++new_data; >+ if (*new_data == '\0') { >+ *time = InfiniteFuture(); >+ return true; >+ } >+ } >+ >+ inf_size = strlen(kInfinitePastStr); >+ if (strncmp(data, kInfinitePastStr, inf_size) == 0) { >+ const char* new_data = data + inf_size; >+ while (std::isspace(*new_data)) ++new_data; >+ if (*new_data == '\0') { >+ *time = InfinitePast(); >+ return true; >+ } >+ } >+ >+ std::string error; >+ cctz_parts parts; >+ const bool b = cctz::detail::parse(format, input, cctz::time_zone(tz), >+ &parts.sec, &parts.fem, &error); >+ if (b) { >+ *time = Join(parts); >+ } else if (err != nullptr) { >+ *err = error; >+ } >+ return b; >+} >+ >+// Functions required to support absl::Time flags. >+bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) { >+ return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error); >+} >+ >+std::string UnparseFlag(absl::Time t) { >+ return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone()); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_benchmark.cc >new file mode 100644 >index 00000000000..ee53d71c685 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_benchmark.cc >@@ -0,0 +1,63 @@ >+// Copyright 2018 The Abseil Authors. >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstddef> >+#include <string> >+ >+#include "absl/time/internal/test_util.h" >+#include "absl/time/time.h" >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+namespace { >+const char* const kFormats[] = { >+ absl::RFC1123_full, // 0 >+ absl::RFC1123_no_wday, // 1 >+ absl::RFC3339_full, // 2 >+ absl::RFC3339_sec, // 3 >+ "%Y-%m-%dT%H:%M:%S", // 4 >+ "%Y-%m-%d", // 5 >+}; >+const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); >+} // namespace >+ >+void BM_Format_FormatTime(benchmark::State& state) { >+ const std::string fmt = kFormats[state.range(0)]; >+ state.SetLabel(fmt); >+ const absl::TimeZone lax = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ const absl::Time t = >+ absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length()); >+ } >+} >+BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1); >+ >+void BM_Format_ParseTime(benchmark::State& state) { >+ const std::string fmt = kFormats[state.range(0)]; >+ state.SetLabel(fmt); >+ const absl::TimeZone lax = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ absl::Time t = >+ absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1); >+ const std::string when = absl::FormatTime(fmt, t, lax); >+ std::string err; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ParseTime(fmt, when, lax, &t, &err)); >+ } >+} >+BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_test.cc >new file mode 100644 >index 00000000000..7c84c33f1eb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/format_test.cc >@@ -0,0 +1,434 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <cstdint> >+#include <limits> >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/time/internal/test_util.h" >+#include "absl/time/time.h" >+ >+using testing::HasSubstr; >+ >+namespace { >+ >+// A helper that tests the given format specifier by itself, and with leading >+// and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu"). >+void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, const std::string& fmt, >+ const std::string& ans) { >+ EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz)); >+ EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz)); >+ EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz)); >+ EXPECT_EQ("xxx " + ans + " yyy", >+ absl::FormatTime("xxx " + fmt + " yyy", t, tz)); >+} >+ >+// >+// Testing FormatTime() >+// >+ >+TEST(FormatTime, Basics) { >+ absl::TimeZone tz = absl::UTCTimeZone(); >+ absl::Time t = absl::FromTimeT(0); >+ >+ // Starts with a couple basic edge cases. >+ EXPECT_EQ("", absl::FormatTime("", t, tz)); >+ EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); >+ EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); >+ EXPECT_EQ("xxx", absl::FormatTime("xxx", t, tz)); >+ std::string big(128, 'x'); >+ EXPECT_EQ(big, absl::FormatTime(big, t, tz)); >+ // Cause the 1024-byte buffer to grow. >+ std::string bigger(100000, 'x'); >+ EXPECT_EQ(bigger, absl::FormatTime(bigger, t, tz)); >+ >+ t += absl::Hours(13) + absl::Minutes(4) + absl::Seconds(5); >+ t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); >+ EXPECT_EQ("1970-01-01", absl::FormatTime("%Y-%m-%d", t, tz)); >+ EXPECT_EQ("13:04:05", absl::FormatTime("%H:%M:%S", t, tz)); >+ EXPECT_EQ("13:04:05.006", absl::FormatTime("%H:%M:%E3S", t, tz)); >+ EXPECT_EQ("13:04:05.006007", absl::FormatTime("%H:%M:%E6S", t, tz)); >+ EXPECT_EQ("13:04:05.006007008", absl::FormatTime("%H:%M:%E9S", t, tz)); >+} >+ >+TEST(FormatTime, LocaleSpecific) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ absl::Time t = absl::FromTimeT(0); >+ >+ TestFormatSpecifier(t, tz, "%a", "Thu"); >+ TestFormatSpecifier(t, tz, "%A", "Thursday"); >+ TestFormatSpecifier(t, tz, "%b", "Jan"); >+ TestFormatSpecifier(t, tz, "%B", "January"); >+ >+ // %c should at least produce the numeric year and time-of-day. >+ const std::string s = >+ absl::FormatTime("%c", absl::FromTimeT(0), absl::UTCTimeZone()); >+ EXPECT_THAT(s, HasSubstr("1970")); >+ EXPECT_THAT(s, HasSubstr("00:00:00")); >+ >+ TestFormatSpecifier(t, tz, "%p", "AM"); >+ TestFormatSpecifier(t, tz, "%x", "01/01/70"); >+ TestFormatSpecifier(t, tz, "%X", "00:00:00"); >+} >+ >+TEST(FormatTime, ExtendedSeconds) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ >+ // No subseconds. >+ absl::Time t = absl::FromTimeT(0) + absl::Seconds(5); >+ EXPECT_EQ("05", absl::FormatTime("%E*S", t, tz)); >+ EXPECT_EQ("05.000000000000000", absl::FormatTime("%E15S", t, tz)); >+ >+ // With subseconds. >+ t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); >+ EXPECT_EQ("05.006007008", absl::FormatTime("%E*S", t, tz)); >+ EXPECT_EQ("05", absl::FormatTime("%E0S", t, tz)); >+ EXPECT_EQ("05.006007008000000", absl::FormatTime("%E15S", t, tz)); >+ >+ // Times before the Unix epoch. >+ t = absl::FromUnixMicros(-1); >+ EXPECT_EQ("1969-12-31 23:59:59.999999", >+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); >+ >+ // Here is a "%E*S" case we got wrong for a while. While the first >+ // instant below is correctly rendered as "...:07.333304", the second >+ // one used to appear as "...:07.33330499999999999". >+ t = absl::FromUnixMicros(1395024427333304); >+ EXPECT_EQ("2014-03-17 02:47:07.333304", >+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); >+ t += absl::Microseconds(1); >+ EXPECT_EQ("2014-03-17 02:47:07.333305", >+ absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); >+} >+ >+TEST(FormatTime, RFC1123FormatPadsYear) { // locale specific >+ absl::TimeZone tz = absl::UTCTimeZone(); >+ >+ // A year of 77 should be padded to 0077. >+ absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz); >+ EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000", >+ absl::FormatTime(absl::RFC1123_full, t, tz)); >+ EXPECT_EQ("28 Jun 0077 09:08:07 +0000", >+ absl::FormatTime(absl::RFC1123_no_wday, t, tz)); >+} >+ >+TEST(FormatTime, InfiniteTime) { >+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ >+ // The format and timezone are ignored. >+ EXPECT_EQ("infinite-future", >+ absl::FormatTime("%H:%M blah", absl::InfiniteFuture(), tz)); >+ EXPECT_EQ("infinite-past", >+ absl::FormatTime("%H:%M blah", absl::InfinitePast(), tz)); >+} >+ >+// >+// Testing ParseTime() >+// >+ >+TEST(ParseTime, Basics) { >+ absl::Time t = absl::FromTimeT(1234567890); >+ std::string err; >+ >+ // Simple edge cases. >+ EXPECT_TRUE(absl::ParseTime("", "", &t, &err)) << err; >+ EXPECT_EQ(absl::UnixEpoch(), t); // everything defaulted >+ EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; >+ EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; >+ EXPECT_TRUE(absl::ParseTime("x", "x", &t, &err)) << err; >+ EXPECT_TRUE(absl::ParseTime("xxx", "xxx", &t, &err)) << err; >+ >+ EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", >+ "2013-06-28 19:08:09 -0800", &t, &err)) >+ << err; >+ absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60)); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false); >+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); >+} >+ >+TEST(ParseTime, NullErrorString) { >+ absl::Time t; >+ EXPECT_FALSE(absl::ParseTime("%Q", "invalid format", &t, nullptr)); >+ EXPECT_FALSE(absl::ParseTime("%H", "12 trailing data", &t, nullptr)); >+ EXPECT_FALSE( >+ absl::ParseTime("%H out of range", "42 out of range", &t, nullptr)); >+} >+ >+TEST(ParseTime, WithTimeZone) { >+ const absl::TimeZone tz = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ absl::Time t; >+ std::string e; >+ >+ // We can parse a std::string without a UTC offset if we supply a timezone. >+ EXPECT_TRUE( >+ absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e)) >+ << e; >+ absl::Time::Breakdown bd = t.In(tz); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true); >+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); >+ >+ // But the timezone is ignored when a UTC offset is present. >+ EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", >+ "2013-06-28 19:08:09 +0800", tz, &t, &e)) >+ << e; >+ bd = t.In(absl::FixedTimeZone(8 * 60 * 60)); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false); >+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); >+} >+ >+TEST(ParseTime, ErrorCases) { >+ absl::Time t = absl::FromTimeT(0); >+ std::string err; >+ >+ EXPECT_FALSE(absl::ParseTime("%S", "123", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ >+ // Can't parse an illegal format specifier. >+ err.clear(); >+ EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err; >+ // Exact contents of "err" are platform-dependent because of >+ // differences in the strptime implementation between OSX and Linux. >+ EXPECT_FALSE(err.empty()); >+ >+ // Fails because of trailing, unparsed data "blah". >+ EXPECT_FALSE(absl::ParseTime("%m-%d", "2-3 blah", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ >+ // Feb 31 requires normalization. >+ EXPECT_FALSE(absl::ParseTime("%m-%d", "2-31", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Out-of-range")); >+ >+ // Check that we cannot have spaces in UTC offsets. >+ EXPECT_TRUE(absl::ParseTime("%z", "-0203", &t, &err)) << err; >+ EXPECT_FALSE(absl::ParseTime("%z", "- 2 3", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_TRUE(absl::ParseTime("%Ez", "-02:03", &t, &err)) << err; >+ EXPECT_FALSE(absl::ParseTime("%Ez", "- 2: 3", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ >+ // Check that we reject other malformed UTC offsets. >+ EXPECT_FALSE(absl::ParseTime("%Ez", "+-08:00", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%Ez", "-+08:00", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ >+ // Check that we do not accept "-0" in fields that allow zero. >+ EXPECT_FALSE(absl::ParseTime("%Y", "-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%E4Y", "-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%H", "-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%M", "-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%S", "-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%z", "+-000", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%Ez", "+-0:00", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ EXPECT_FALSE(absl::ParseTime("%z", "-00-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ EXPECT_FALSE(absl::ParseTime("%Ez", "-00:-0", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+} >+ >+TEST(ParseTime, ExtendedSeconds) { >+ std::string err; >+ absl::Time t; >+ >+ // Here is a "%E*S" case we got wrong for a while. The fractional >+ // part of the first instant is less than 2^31 and was correctly >+ // parsed, while the second (and any subsecond field >=2^31) failed. >+ t = absl::UnixEpoch(); >+ EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483647", &t, &err)) << err; >+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + >+ absl::Nanoseconds(1) / 2, >+ t); >+ t = absl::UnixEpoch(); >+ EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483648", &t, &err)) << err; >+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + >+ absl::Nanoseconds(3) / 4, >+ t); >+ >+ // We should also be able to specify long strings of digits far >+ // beyond the current resolution and have them convert the same way. >+ t = absl::UnixEpoch(); >+ EXPECT_TRUE(absl::ParseTime( >+ "%E*S", "0.214748364801234567890123456789012345678901234567890123456789", >+ &t, &err)) >+ << err; >+ EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + >+ absl::Nanoseconds(3) / 4, >+ t); >+} >+ >+TEST(ParseTime, ExtendedOffsetErrors) { >+ std::string err; >+ absl::Time t; >+ >+ // %z against +-HHMM. >+ EXPECT_FALSE(absl::ParseTime("%z", "-123", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ >+ // %z against +-HH. >+ EXPECT_FALSE(absl::ParseTime("%z", "-1", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+ >+ // %Ez against +-HH:MM. >+ EXPECT_FALSE(absl::ParseTime("%Ez", "-12:3", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ >+ // %Ez against +-HHMM. >+ EXPECT_FALSE(absl::ParseTime("%Ez", "-123", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Illegal trailing data")); >+ >+ // %Ez against +-HH. >+ EXPECT_FALSE(absl::ParseTime("%Ez", "-1", &t, &err)) << err; >+ EXPECT_THAT(err, HasSubstr("Failed to parse")); >+} >+ >+TEST(ParseTime, InfiniteTime) { >+ absl::Time t; >+ std::string err; >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future", &t, &err)); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ >+ // Surrounding whitespace. >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future", &t, &err)); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future ", &t, &err)); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future ", &t, &err)); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past", &t, &err)); >+ EXPECT_EQ(absl::InfinitePast(), t); >+ >+ // Surrounding whitespace. >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past", &t, &err)); >+ EXPECT_EQ(absl::InfinitePast(), t); >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past ", &t, &err)); >+ EXPECT_EQ(absl::InfinitePast(), t); >+ EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past ", &t, &err)); >+ EXPECT_EQ(absl::InfinitePast(), t); >+ >+ // "infinite-future" as literal std::string >+ absl::TimeZone tz = absl::UTCTimeZone(); >+ EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04", >+ &t, &err)); >+ EXPECT_NE(absl::InfiniteFuture(), t); >+ EXPECT_EQ(3, t.In(tz).hour); >+ EXPECT_EQ(4, t.In(tz).minute); >+ >+ // "infinite-past" as literal std::string >+ EXPECT_TRUE( >+ absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err)); >+ EXPECT_NE(absl::InfinitePast(), t); >+ EXPECT_EQ(3, t.In(tz).hour); >+ EXPECT_EQ(4, t.In(tz).minute); >+ >+ // The input doesn't match the format. >+ EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err)); >+ EXPECT_FALSE(absl::ParseTime("infinite-past %H:%M", "03:04", &t, &err)); >+} >+ >+TEST(ParseTime, FailsOnUnrepresentableTime) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::Time t; >+ EXPECT_FALSE( >+ absl::ParseTime("%Y-%m-%d", "-292277022657-01-27", utc, &t, nullptr)); >+ EXPECT_TRUE( >+ absl::ParseTime("%Y-%m-%d", "-292277022657-01-28", utc, &t, nullptr)); >+ EXPECT_TRUE( >+ absl::ParseTime("%Y-%m-%d", "292277026596-12-04", utc, &t, nullptr)); >+ EXPECT_FALSE( >+ absl::ParseTime("%Y-%m-%d", "292277026596-12-05", utc, &t, nullptr)); >+} >+ >+// >+// Roundtrip test for FormatTime()/ParseTime(). >+// >+ >+TEST(FormatParse, RoundTrip) { >+ const absl::TimeZone gst = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst); >+ const absl::Duration subseconds = absl::Nanoseconds(654321); >+ std::string err; >+ >+ // RFC3339, which renders subseconds. >+ { >+ absl::Time out; >+ const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst); >+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) >+ << s << ": " << err; >+ EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez >+ } >+ >+ // RFC1123, which only does whole seconds. >+ { >+ absl::Time out; >+ const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst); >+ EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err)) >+ << s << ": " << err; >+ EXPECT_EQ(in, out); // RFC1123_full includes %z >+ } >+ >+ // `absl::FormatTime()` falls back to strftime() for "%c", which appears to >+ // work. On Windows, `absl::ParseTime()` falls back to std::get_time() which >+ // appears to fail on "%c" (or at least on the "%c" text produced by >+ // `strftime()`). This makes it fail the round-trip test. >+#ifndef _MSC_VER >+ // Even though we don't know what %c will produce, it should roundtrip, >+ // but only in the 0-offset timezone. >+ { >+ absl::Time out; >+ const std::string s = absl::FormatTime("%c", in, absl::UTCTimeZone()); >+ EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err; >+ EXPECT_EQ(in, out); >+ } >+#endif // _MSC_VER >+} >+ >+TEST(FormatParse, RoundTripDistantFuture) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ const absl::Time in = >+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); >+ std::string err; >+ >+ absl::Time out; >+ const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); >+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) >+ << s << ": " << err; >+ EXPECT_EQ(in, out); >+} >+ >+TEST(FormatParse, RoundTripDistantPast) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ const absl::Time in = >+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::min()); >+ std::string err; >+ >+ absl::Time out; >+ const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); >+ EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) >+ << s << ": " << err; >+ EXPECT_EQ(in, out); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel >new file mode 100644 >index 00000000000..9f1ba21cf7e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.bazel >@@ -0,0 +1,140 @@ >+# Copyright 2016 Google Inc. All Rights Reserved. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+ >+licenses(["notice"]) # Apache License >+ >+### libraries >+ >+cc_library( >+ name = "includes", >+ textual_hdrs = [ >+ "include/cctz/civil_time.h", >+ "include/cctz/civil_time_detail.h", >+ "include/cctz/time_zone.h", >+ ], >+ visibility = ["//absl/time:__pkg__"], >+) >+ >+cc_library( >+ name = "civil_time", >+ srcs = ["src/civil_time_detail.cc"], >+ hdrs = [ >+ "include/cctz/civil_time.h", >+ ], >+ textual_hdrs = ["include/cctz/civil_time_detail.h"], >+ visibility = ["//visibility:public"], >+) >+ >+cc_library( >+ name = "time_zone", >+ srcs = [ >+ "src/time_zone_fixed.cc", >+ "src/time_zone_fixed.h", >+ "src/time_zone_format.cc", >+ "src/time_zone_if.cc", >+ "src/time_zone_if.h", >+ "src/time_zone_impl.cc", >+ "src/time_zone_impl.h", >+ "src/time_zone_info.cc", >+ "src/time_zone_info.h", >+ "src/time_zone_libc.cc", >+ "src/time_zone_libc.h", >+ "src/time_zone_lookup.cc", >+ "src/time_zone_posix.cc", >+ "src/time_zone_posix.h", >+ "src/tzfile.h", >+ "src/zone_info_source.cc", >+ ], >+ hdrs = [ >+ "include/cctz/time_zone.h", >+ "include/cctz/zone_info_source.h", >+ ], >+ visibility = ["//visibility:public"], >+ deps = [":civil_time"], >+) >+ >+### tests >+ >+cc_test( >+ name = "civil_time_test", >+ size = "small", >+ srcs = ["src/civil_time_test.cc"], >+ deps = [ >+ ":civil_time", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "time_zone_format_test", >+ size = "small", >+ srcs = ["src/time_zone_format_test.cc"], >+ data = [":zoneinfo"], >+ tags = [ >+ "no_test_android_arm", >+ "no_test_android_arm64", >+ "no_test_android_x86", >+ ], >+ deps = [ >+ ":civil_time", >+ ":time_zone", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "time_zone_lookup_test", >+ size = "small", >+ srcs = ["src/time_zone_lookup_test.cc"], >+ data = [":zoneinfo"], >+ tags = [ >+ "no_test_android_arm", >+ "no_test_android_arm64", >+ "no_test_android_x86", >+ ], >+ deps = [ >+ ":civil_time", >+ ":time_zone", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+### benchmarks >+ >+cc_test( >+ name = "cctz_benchmark", >+ srcs = [ >+ "src/cctz_benchmark.cc", >+ "src/time_zone_if.h", >+ "src/time_zone_impl.h", >+ "src/time_zone_info.h", >+ "src/tzfile.h", >+ ], >+ linkstatic = 1, >+ tags = ["benchmark"], >+ deps = [ >+ ":civil_time", >+ ":time_zone", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+### examples >+ >+### binaries >+ >+filegroup( >+ name = "zoneinfo", >+ srcs = glob(["testdata/zoneinfo/**"]), >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.gn >new file mode 100644 >index 00000000000..86417e7ce3c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/BUILD.gn >@@ -0,0 +1,72 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("includes") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ "//build/config/compiler:no_chromium_code" ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "include/cctz/civil_time.h", >+ "include/cctz/civil_time_detail.h", >+ "include/cctz/time_zone.h", >+ ] >+ visibility = [] >+ visibility += [ "../time:*" ] >+} >+ >+source_set("civil_time") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ "//build/config/compiler:no_chromium_code" ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "src/civil_time_detail.cc", >+ ] >+ public = [ >+ "include/cctz/civil_time.h", >+ "include/cctz/civil_time_detail.h", >+ ] >+} >+ >+source_set("time_zone") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ "//build/config/compiler:no_chromium_code" ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "src/time_zone_fixed.cc", >+ "src/time_zone_fixed.h", >+ "src/time_zone_format.cc", >+ "src/time_zone_if.cc", >+ "src/time_zone_if.h", >+ "src/time_zone_impl.cc", >+ "src/time_zone_impl.h", >+ "src/time_zone_info.cc", >+ "src/time_zone_info.h", >+ "src/time_zone_libc.cc", >+ "src/time_zone_libc.h", >+ "src/time_zone_lookup.cc", >+ "src/time_zone_posix.cc", >+ "src/time_zone_posix.h", >+ "src/tzfile.h", >+ "src/zone_info_source.cc", >+ ] >+ public = [ >+ "include/cctz/time_zone.h", >+ "include/cctz/zone_info_source.h", >+ ] >+ deps = [ >+ ":civil_time", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time.h >new file mode 100644 >index 00000000000..898222b4c7a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time.h >@@ -0,0 +1,329 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// The term "civil time" refers to the legally recognized human-scale time >+// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil >+// time follows the Gregorian Calendar and is a time-zone-independent concept. >+// A "date" is perhaps the most common example of a civil time (represented in >+// this library as cctz::civil_day). This library provides six classes and a >+// handful of functions that help with rounding, iterating, and arithmetic on >+// civil times while avoiding complications like daylight-saving time (DST). >+// >+// The following six classes form the core of this civil-time library: >+// >+// * civil_second >+// * civil_minute >+// * civil_hour >+// * civil_day >+// * civil_month >+// * civil_year >+// >+// Each class is a simple value type with the same interface for construction >+// and the same six accessors for each of the civil fields (year, month, day, >+// hour, minute, and second, aka YMDHMS). These classes differ only in their >+// alignment, which is indicated by the type name and specifies the field on >+// which arithmetic operates. >+// >+// Each class can be constructed by passing up to six optional integer >+// arguments representing the YMDHMS fields (in that order) to the >+// constructor. Omitted fields are assigned their minimum valid value. Hours, >+// minutes, and seconds will be set to 0, month and day will be set to 1, and >+// since there is no minimum valid year, it will be set to 1970. So, a >+// default-constructed civil-time object will have YMDHMS fields representing >+// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g., >+// October 32 -> November 1) so that all civil-time objects represent valid >+// values. >+// >+// Each civil-time class is aligned to the civil-time field indicated in the >+// class's name after normalization. Alignment is performed by setting all the >+// inferior fields to their minimum valid value (as described above). The >+// following are examples of how each of the six types would align the fields >+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the >+// std::string format used here is not important; it's just a shorthand way of >+// showing the six YMDHMS fields.) >+// >+// civil_second 2015-11-22 12:34:56 >+// civil_minute 2015-11-22 12:34:00 >+// civil_hour 2015-11-22 12:00:00 >+// civil_day 2015-11-22 00:00:00 >+// civil_month 2015-11-01 00:00:00 >+// civil_year 2015-01-01 00:00:00 >+// >+// Each civil-time type performs arithmetic on the field to which it is >+// aligned. This means that adding 1 to a civil_day increments the day field >+// (normalizing as necessary), and subtracting 7 from a civil_month operates >+// on the month field (normalizing as necessary). All arithmetic produces a >+// valid civil time. Difference requires two similarly aligned civil-time >+// objects and returns the scalar answer in units of the objects' alignment. >+// For example, the difference between two civil_hour objects will give an >+// answer in units of civil hours. >+// >+// In addition to the six civil-time types just described, there are >+// a handful of helper functions and algorithms for performing common >+// calculations. These are described below. >+// >+// Note: In C++14 and later, this library is usable in a constexpr context. >+// >+// CONSTRUCTION: >+// >+// Each of the civil-time types can be constructed in two ways: by directly >+// passing to the constructor up to six (optional) integers representing the >+// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned >+// civil-time type. >+// >+// civil_day default_value; // 1970-01-01 00:00:00 >+// >+// civil_day a(2015, 2, 3); // 2015-02-03 00:00:00 >+// civil_day b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 >+// civil_day c(2015); // 2015-01-01 00:00:00 >+// >+// civil_second ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 >+// civil_minute mm(ss); // 2015-02-03 04:05:00 >+// civil_hour hh(mm); // 2015-02-03 04:00:00 >+// civil_day d(hh); // 2015-02-03 00:00:00 >+// civil_month m(d); // 2015-02-01 00:00:00 >+// civil_year y(m); // 2015-01-01 00:00:00 >+// >+// m = civil_month(y); // 2015-01-01 00:00:00 >+// d = civil_day(m); // 2015-01-01 00:00:00 >+// hh = civil_hour(d); // 2015-01-01 00:00:00 >+// mm = civil_minute(hh); // 2015-01-01 00:00:00 >+// ss = civil_second(mm); // 2015-01-01 00:00:00 >+// >+// ALIGNMENT CONVERSION: >+// >+// The alignment of a civil-time object cannot change, but the object may be >+// used to construct a new object with a different alignment. This is referred >+// to as "realigning". When realigning to a type with the same or more >+// precision (e.g., civil_day -> civil_second), the conversion may be >+// performed implicitly since no information is lost. However, if information >+// could be discarded (e.g., civil_second -> civil_day), the conversion must >+// be explicit at the call site. >+// >+// void fun(const civil_day& day); >+// >+// civil_second cs; >+// fun(cs); // Won't compile because data may be discarded >+// fun(civil_day(cs)); // OK: explicit conversion >+// >+// civil_day cd; >+// fun(cd); // OK: no conversion needed >+// >+// civil_month cm; >+// fun(cm); // OK: implicit conversion to civil_day >+// >+// NORMALIZATION: >+// >+// Integer arguments passed to the constructor may be out-of-range, in which >+// case they are normalized to produce a valid civil-time object. This enables >+// natural arithmetic on constructor arguments without worrying about the >+// field's range. Normalization guarantees that there are no invalid >+// civil-time objects. >+// >+// civil_day d(2016, 10, 32); // Out-of-range day; normalized to 2016-11-01 >+// >+// Note: If normalization is undesired, you can signal an error by comparing >+// the constructor arguments to the normalized values returned by the YMDHMS >+// properties. >+// >+// PROPERTIES: >+// >+// All civil-time types have accessors for all six of the civil-time fields: >+// year, month, day, hour, minute, and second. Recall that fields inferior to >+// the type's aligment will be set to their minimum valid value. >+// >+// civil_day d(2015, 6, 28); >+// // d.year() == 2015 >+// // d.month() == 6 >+// // d.day() == 28 >+// // d.hour() == 0 >+// // d.minute() == 0 >+// // d.second() == 0 >+// >+// COMPARISON: >+// >+// Comparison always considers all six YMDHMS fields, regardless of the type's >+// alignment. Comparison between differently aligned civil-time types is >+// allowed. >+// >+// civil_day feb_3(2015, 2, 3); // 2015-02-03 00:00:00 >+// civil_day mar_4(2015, 3, 4); // 2015-03-04 00:00:00 >+// // feb_3 < mar_4 >+// // civil_year(feb_3) == civil_year(mar_4) >+// >+// civil_second feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 >+// // feb_3 < feb_3_noon >+// // feb_3 == civil_day(feb_3_noon) >+// >+// // Iterates all the days of February 2015. >+// for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) { >+// // ... >+// } >+// >+// STREAMING: >+// >+// Each civil-time type may be sent to an output stream using operator<<(). >+// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields >+// inferior to the type's alignment are omitted. >+// >+// civil_second cs(2015, 2, 3, 4, 5, 6); >+// std::cout << cs << "\n"; // Outputs: 2015-02-03T04:05:06 >+// >+// civil_day cd(cs); >+// std::cout << cd << "\n"; // Outputs: 2015-02-03 >+// >+// civil_year cy(cs); >+// std::cout << cy << "\n"; // Outputs: 2015 >+// >+// ARITHMETIC: >+// >+// Civil-time types support natural arithmetic operators such as addition, >+// subtraction, and difference. Arithmetic operates on the civil-time field >+// indicated in the type's name. Difference requires arguments with the same >+// alignment and returns the answer in units of the alignment. >+// >+// civil_day a(2015, 2, 3); >+// ++a; // 2015-02-04 00:00:00 >+// --a; // 2015-02-03 00:00:00 >+// civil_day b = a + 1; // 2015-02-04 00:00:00 >+// civil_day c = 1 + b; // 2015-02-05 00:00:00 >+// int n = c - a; // n = 2 (civil days) >+// int m = c - civil_month(c); // Won't compile: different types. >+// >+// EXAMPLE: Adding a month to January 31. >+// >+// One of the classic questions that arises when considering a civil-time >+// library (or a date library or a date/time library) is this: "What happens >+// when you add a month to January 31?" This is an interesting question >+// because there could be a number of possible answers: >+// >+// 1. March 3 (or 2 if a leap year). This may make sense if the operation >+// wants the equivalent of February 31. >+// 2. February 28 (or 29 if a leap year). This may make sense if the operation >+// wants the last day of January to go to the last day of February. >+// 3. Error. The caller may get some error, an exception, an invalid date >+// object, or maybe false is returned. This may make sense because there is >+// no single unambiguously correct answer to the question. >+// >+// Practically speaking, any answer that is not what the programmer intended >+// is the wrong answer. >+// >+// This civil-time library avoids the problem by making it impossible to ask >+// ambiguous questions. All civil-time objects are aligned to a particular >+// civil-field boundary (such as aligned to a year, month, day, hour, minute, >+// or second), and arithmetic operates on the field to which the object is >+// aligned. This means that in order to "add a month" the object must first be >+// aligned to a month boundary, which is equivalent to the first day of that >+// month. >+// >+// Of course, there are ways to compute an answer the question at hand using >+// this civil-time library, but they require the programmer to be explicit >+// about the answer they expect. To illustrate, let's see how to compute all >+// three of the above possible answers to the question of "Jan 31 plus 1 >+// month": >+// >+// const civil_day d(2015, 1, 31); >+// >+// // Answer 1: >+// // Add 1 to the month field in the constructor, and rely on normalization. >+// const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day()); >+// // ans_normalized == 2015-03-03 (aka Feb 31) >+// >+// // Answer 2: >+// // Add 1 to month field, capping to the end of next month. >+// const auto next_month = civil_month(d) + 1; >+// const auto last_day_of_next_month = civil_day(next_month + 1) - 1; >+// const auto ans_capped = std::min(ans_normalized, last_day_of_next_month); >+// // ans_capped == 2015-02-28 >+// >+// // Answer 3: >+// // Signal an error if the normalized answer is not in next month. >+// if (civil_month(ans_normalized) != next_month) { >+// // error, month overflow >+// } >+// >+using civil_year = detail::civil_year; >+using civil_month = detail::civil_month; >+using civil_day = detail::civil_day; >+using civil_hour = detail::civil_hour; >+using civil_minute = detail::civil_minute; >+using civil_second = detail::civil_second; >+ >+// An enum class with members monday, tuesday, wednesday, thursday, friday, >+// saturday, and sunday. These enum values may be sent to an output stream >+// using operator<<(). The result is the full weekday name in English with a >+// leading capital letter. >+// >+// weekday wd = weekday::thursday; >+// std::cout << wd << "\n"; // Outputs: Thursday >+// >+using detail::weekday; >+ >+// Returns the weekday for the given civil_day. >+// >+// civil_day a(2015, 8, 13); >+// weekday wd = get_weekday(a); // wd == weekday::thursday >+// >+using detail::get_weekday; >+ >+// Returns the civil_day that strictly follows or precedes the given >+// civil_day, and that falls on the given weekday. >+// >+// For example, given: >+// >+// August 2015 >+// Su Mo Tu We Th Fr Sa >+// 1 >+// 2 3 4 5 6 7 8 >+// 9 10 11 12 13 14 15 >+// 16 17 18 19 20 21 22 >+// 23 24 25 26 27 28 29 >+// 30 31 >+// >+// civil_day a(2015, 8, 13); // get_weekday(a) == weekday::thursday >+// civil_day b = next_weekday(a, weekday::thursday); // b = 2015-08-20 >+// civil_day c = prev_weekday(a, weekday::thursday); // c = 2015-08-06 >+// >+// civil_day d = ... >+// // Gets the following Thursday if d is not already Thursday >+// civil_day thurs1 = prev_weekday(d, weekday::thursday) + 7; >+// // Gets the previous Thursday if d is not already Thursday >+// civil_day thurs2 = next_weekday(d, weekday::thursday) - 7; >+// >+using detail::next_weekday; >+using detail::prev_weekday; >+ >+// Returns the day-of-year for the given civil_day. >+// >+// civil_day a(2015, 1, 1); >+// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1 >+// civil_day b(2015, 12, 31); >+// int yd_dec_31 = get_yearday(b); // yd_dec_31 = 365 >+// >+using detail::get_yearday; >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h >new file mode 100644 >index 00000000000..2362a4f4fbc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h >@@ -0,0 +1,560 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ >+ >+#include <cstdint> >+#include <limits> >+#include <ostream> >+#include <type_traits> >+ >+// Disable constexpr support unless we are in C++14 mode. >+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 >+#define CONSTEXPR_D constexpr // data >+#define CONSTEXPR_F constexpr // function >+#define CONSTEXPR_M constexpr // member >+#else >+#define CONSTEXPR_D const >+#define CONSTEXPR_F inline >+#define CONSTEXPR_M >+#endif >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// Support years that at least span the range of 64-bit time_t values. >+using year_t = std::int_fast64_t; >+ >+// Type alias that indicates an argument is not normalized (e.g., the >+// constructor parameters and operands/results of addition/subtraction). >+using diff_t = std::int_fast64_t; >+ >+namespace detail { >+ >+// Type aliases that indicate normalized argument values. >+using month_t = std::int_fast8_t; // [1:12] >+using day_t = std::int_fast8_t; // [1:31] >+using hour_t = std::int_fast8_t; // [0:23] >+using minute_t = std::int_fast8_t; // [0:59] >+using second_t = std::int_fast8_t; // [0:59] >+ >+// Normalized civil-time fields: Y-M-D HH:MM:SS. >+struct fields { >+ CONSTEXPR_M fields(year_t year, month_t month, day_t day, >+ hour_t hour, minute_t minute, second_t second) >+ : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {} >+ std::int_least64_t y; >+ std::int_least8_t m; >+ std::int_least8_t d; >+ std::int_least8_t hh; >+ std::int_least8_t mm; >+ std::int_least8_t ss; >+}; >+ >+struct second_tag {}; >+struct minute_tag : second_tag {}; >+struct hour_tag : minute_tag {}; >+struct day_tag : hour_tag {}; >+struct month_tag : day_tag {}; >+struct year_tag : month_tag {}; >+ >+//////////////////////////////////////////////////////////////////////// >+ >+// Field normalization (without avoidable overflow). >+ >+namespace impl { >+ >+CONSTEXPR_F bool is_leap_year(year_t y) noexcept { >+ return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); >+} >+CONSTEXPR_F int year_index(year_t y, month_t m) noexcept { >+ return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400; >+} >+CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept { >+ const int yi = year_index(y, m); >+ return 36524 + (yi == 0 || yi > 300); >+} >+CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept { >+ const int yi = year_index(y, m); >+ return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96); >+} >+CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept { >+ return is_leap_year(y + (m > 2)) ? 366 : 365; >+} >+CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept { >+ CONSTEXPR_D int k_days_per_month[1 + 12] = { >+ -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year >+ }; >+ return k_days_per_month[m] + (m == 2 && is_leap_year(y)); >+} >+ >+CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, >+ hour_t hh, minute_t mm, second_t ss) noexcept { >+ y += (cd / 146097) * 400; >+ cd %= 146097; >+ if (cd < 0) { >+ y -= 400; >+ cd += 146097; >+ } >+ y += (d / 146097) * 400; >+ d = d % 146097 + cd; >+ if (d > 0) { >+ if (d > 146097) { >+ y += 400; >+ d -= 146097; >+ } >+ } else { >+ if (d > -365) { >+ // We often hit the previous year when stepping a civil time backwards, >+ // so special case it to avoid counting up by 100/4/1-year chunks. >+ y -= 1; >+ d += days_per_year(y, m); >+ } else { >+ y -= 400; >+ d += 146097; >+ } >+ } >+ if (d > 365) { >+ for (int n = days_per_century(y, m); d > n; n = days_per_century(y, m)) { >+ d -= n; >+ y += 100; >+ } >+ for (int n = days_per_4years(y, m); d > n; n = days_per_4years(y, m)) { >+ d -= n; >+ y += 4; >+ } >+ for (int n = days_per_year(y, m); d > n; n = days_per_year(y, m)) { >+ d -= n; >+ ++y; >+ } >+ } >+ if (d > 28) { >+ for (int n = days_per_month(y, m); d > n; n = days_per_month(y, m)) { >+ d -= n; >+ if (++m > 12) { >+ ++y; >+ m = 1; >+ } >+ } >+ } >+ return fields(y, m, static_cast<day_t>(d), hh, mm, ss); >+} >+CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, >+ hour_t hh, minute_t mm, second_t ss) noexcept { >+ if (m != 12) { >+ y += m / 12; >+ m %= 12; >+ if (m <= 0) { >+ y -= 1; >+ m += 12; >+ } >+ } >+ return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss); >+} >+CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, >+ diff_t hh, minute_t mm, second_t ss) noexcept { >+ cd += hh / 24; >+ hh %= 24; >+ if (hh < 0) { >+ cd -= 1; >+ hh += 24; >+ } >+ return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss); >+} >+CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch, >+ diff_t mm, second_t ss) noexcept { >+ ch += mm / 60; >+ mm %= 60; >+ if (mm < 0) { >+ ch -= 1; >+ mm += 60; >+ } >+ return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24, >+ static_cast<minute_t>(mm), ss); >+} >+CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm, >+ diff_t ss) noexcept { >+ // Optimization for when (non-constexpr) fields are already normalized. >+ if (0 <= ss && ss < 60) { >+ const second_t nss = static_cast<second_t>(ss); >+ if (0 <= mm && mm < 60) { >+ const minute_t nmm = static_cast<minute_t>(mm); >+ if (0 <= hh && hh < 24) { >+ const hour_t nhh = static_cast<hour_t>(hh); >+ if (1 <= d && d <= 28 && 1 <= m && m <= 12) { >+ const day_t nd = static_cast<day_t>(d); >+ const month_t nm = static_cast<month_t>(m); >+ return fields(y, nm, nd, nhh, nmm, nss); >+ } >+ return n_mon(y, m, d, 0, nhh, nmm, nss); >+ } >+ return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss); >+ } >+ return n_min(y, m, d, hh, mm / 60, mm % 60, nss); >+ } >+ diff_t cm = ss / 60; >+ ss %= 60; >+ if (ss < 0) { >+ cm -= 1; >+ ss += 60; >+ } >+ return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60, >+ static_cast<second_t>(ss)); >+} >+ >+} // namespace impl >+ >+//////////////////////////////////////////////////////////////////////// >+ >+// Increments the indicated (normalized) field by "n". >+CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept { >+ return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60); >+} >+CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept { >+ return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss); >+} >+CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept { >+ return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss); >+} >+CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept { >+ return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss); >+} >+CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept { >+ return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss); >+} >+CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept { >+ return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss); >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+namespace impl { >+ >+// Returns (v * f + a) but avoiding intermediate overflow when possible. >+CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept { >+ return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f; >+} >+ >+// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01. >+// Probably overflows for years outside [-292277022656:292277026595]. >+CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept { >+ const diff_t eyear = (m <= 2) ? y - 1 : y; >+ const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400; >+ const diff_t yoe = eyear - era * 400; >+ const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; >+ const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; >+ return era * 146097 + doe - 719468; >+} >+ >+// Returns the difference in days between two normalized Y-M-D tuples. >+// ymd_ord() will encounter integer overflow given extreme year values, >+// yet the difference between two such extreme values may actually be >+// small, so we take a little care to avoid overflow when possible by >+// exploiting the 146097-day cycle. >+CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, >+ year_t y2, month_t m2, day_t d2) noexcept { >+ const diff_t a_c4_off = y1 % 400; >+ const diff_t b_c4_off = y2 % 400; >+ diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off); >+ diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2); >+ if (c4_diff > 0 && delta < 0) { >+ delta += 2 * 146097; >+ c4_diff -= 2 * 400; >+ } else if (c4_diff < 0 && delta > 0) { >+ delta -= 2 * 146097; >+ c4_diff += 2 * 400; >+ } >+ return (c4_diff / 400 * 146097) + delta; >+} >+ >+} // namespace impl >+ >+// Returns the difference between fields structs using the indicated unit. >+CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept { >+ return f1.y - f2.y; >+} >+CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept { >+ return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m)); >+} >+CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept { >+ return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d); >+} >+CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept { >+ return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh)); >+} >+CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept { >+ return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm)); >+} >+CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept { >+ return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss); >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+// Aligns the (normalized) fields struct to the indicated field. >+CONSTEXPR_F fields align(second_tag, fields f) noexcept { >+ return f; >+} >+CONSTEXPR_F fields align(minute_tag, fields f) noexcept { >+ return fields{f.y, f.m, f.d, f.hh, f.mm, 0}; >+} >+CONSTEXPR_F fields align(hour_tag, fields f) noexcept { >+ return fields{f.y, f.m, f.d, f.hh, 0, 0}; >+} >+CONSTEXPR_F fields align(day_tag, fields f) noexcept { >+ return fields{f.y, f.m, f.d, 0, 0, 0}; >+} >+CONSTEXPR_F fields align(month_tag, fields f) noexcept { >+ return fields{f.y, f.m, 1, 0, 0, 0}; >+} >+CONSTEXPR_F fields align(year_tag, fields f) noexcept { >+ return fields{f.y, 1, 1, 0, 0, 0}; >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+template <typename T> >+class civil_time { >+ public: >+ explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1, >+ diff_t hh = 0, diff_t mm = 0, >+ diff_t ss = 0) noexcept >+ : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {} >+ >+ CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {} >+ civil_time(const civil_time&) = default; >+ civil_time& operator=(const civil_time&) = default; >+ >+ // Conversion between civil times of different alignment. Conversion to >+ // a more precise alignment is allowed implicitly (e.g., day -> hour), >+ // but conversion where information is discarded must be explicit >+ // (e.g., second -> minute). >+ template <typename U, typename S> >+ using preserves_data = >+ typename std::enable_if<std::is_base_of<U, S>::value>::type; >+ template <typename U> >+ CONSTEXPR_M civil_time(const civil_time<U>& ct, >+ preserves_data<T, U>* = nullptr) noexcept >+ : civil_time(ct.f_) {} >+ template <typename U> >+ explicit CONSTEXPR_M civil_time(const civil_time<U>& ct, >+ preserves_data<U, T>* = nullptr) noexcept >+ : civil_time(ct.f_) {} >+ >+ // Factories for the maximum/minimum representable civil_time. >+ static civil_time max() { >+ const auto max_year = std::numeric_limits<std::int_least64_t>::max(); >+ return civil_time(max_year, 12, 31, 23, 59, 59); >+ } >+ static civil_time min() { >+ const auto min_year = std::numeric_limits<std::int_least64_t>::min(); >+ return civil_time(min_year, 1, 1, 0, 0, 0); >+ } >+ >+ // Field accessors. Note: All but year() return an int. >+ CONSTEXPR_M year_t year() const noexcept { return f_.y; } >+ CONSTEXPR_M int month() const noexcept { return f_.m; } >+ CONSTEXPR_M int day() const noexcept { return f_.d; } >+ CONSTEXPR_M int hour() const noexcept { return f_.hh; } >+ CONSTEXPR_M int minute() const noexcept { return f_.mm; } >+ CONSTEXPR_M int second() const noexcept { return f_.ss; } >+ >+ // Assigning arithmetic. >+ CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept { >+ f_ = step(T{}, f_, n); >+ return *this; >+ } >+ CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept { >+ if (n != std::numeric_limits<diff_t>::min()) { >+ f_ = step(T{}, f_, -n); >+ } else { >+ f_ = step(T{}, step(T{}, f_, -(n + 1)), 1); >+ } >+ return *this; >+ } >+ CONSTEXPR_M civil_time& operator++() noexcept { >+ return *this += 1; >+ } >+ CONSTEXPR_M civil_time operator++(int) noexcept { >+ const civil_time a = *this; >+ ++*this; >+ return a; >+ } >+ CONSTEXPR_M civil_time& operator--() noexcept { >+ return *this -= 1; >+ } >+ CONSTEXPR_M civil_time operator--(int) noexcept { >+ const civil_time a = *this; >+ --*this; >+ return a; >+ } >+ >+ // Binary arithmetic operators. >+ friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept { >+ return a += n; >+ } >+ friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept { >+ return a += n; >+ } >+ friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept { >+ return a -= n; >+ } >+ friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept { >+ return difference(T{}, lhs.f_, rhs.f_); >+ } >+ >+ private: >+ // All instantiations of this template are allowed to call the following >+ // private constructor and access the private fields member. >+ template <typename U> >+ friend class civil_time; >+ >+ // The designated constructor that all others eventually call. >+ explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {} >+ >+ fields f_; >+}; >+ >+// Disallows difference between differently aligned types. >+// auto n = civil_day(...) - civil_hour(...); // would be confusing. >+template <typename T, typename U> >+CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete; >+ >+using civil_year = civil_time<year_tag>; >+using civil_month = civil_time<month_tag>; >+using civil_day = civil_time<day_tag>; >+using civil_hour = civil_time<hour_tag>; >+using civil_minute = civil_time<minute_tag>; >+using civil_second = civil_time<second_tag>; >+ >+//////////////////////////////////////////////////////////////////////// >+ >+// Relational operators that work with differently aligned objects. >+// Always compares all six fields. >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator<(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return (lhs.year() < rhs.year() || >+ (lhs.year() == rhs.year() && >+ (lhs.month() < rhs.month() || >+ (lhs.month() == rhs.month() && >+ (lhs.day() < rhs.day() || >+ (lhs.day() == rhs.day() && >+ (lhs.hour() < rhs.hour() || >+ (lhs.hour() == rhs.hour() && >+ (lhs.minute() < rhs.minute() || >+ (lhs.minute() == rhs.minute() && >+ (lhs.second() < rhs.second()))))))))))); >+} >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return !(rhs < lhs); >+} >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return !(lhs < rhs); >+} >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator>(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return rhs < lhs; >+} >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator==(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return lhs.year() == rhs.year() && lhs.month() == rhs.month() && >+ lhs.day() == rhs.day() && lhs.hour() == rhs.hour() && >+ lhs.minute() == rhs.minute() && lhs.second() == rhs.second(); >+} >+template <typename T1, typename T2> >+CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs, >+ const civil_time<T2>& rhs) noexcept { >+ return !(lhs == rhs); >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+enum class weekday { >+ monday, >+ tuesday, >+ wednesday, >+ thursday, >+ friday, >+ saturday, >+ sunday, >+}; >+ >+CONSTEXPR_F weekday get_weekday(const civil_day& cd) noexcept { >+ CONSTEXPR_D weekday k_weekday_by_sun_off[7] = { >+ weekday::sunday, weekday::monday, weekday::tuesday, >+ weekday::wednesday, weekday::thursday, weekday::friday, >+ weekday::saturday, >+ }; >+ CONSTEXPR_D int k_weekday_offsets[1 + 12] = { >+ -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4, >+ }; >+ year_t wd = cd.year() - (cd.month() < 3); >+ if (wd >= 0) { >+ wd += wd / 4 - wd / 100 + wd / 400; >+ } else { >+ wd += (wd - 3) / 4 - (wd - 99) / 100 + (wd - 399) / 400; >+ } >+ wd += k_weekday_offsets[cd.month()] + cd.day(); >+ return k_weekday_by_sun_off[(wd % 7 + 7) % 7]; >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept { >+ do { cd += 1; } while (get_weekday(cd) != wd); >+ return cd; >+} >+ >+CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept { >+ do { cd -= 1; } while (get_weekday(cd) != wd); >+ return cd; >+} >+ >+CONSTEXPR_F int get_yearday(const civil_day& cd) noexcept { >+ CONSTEXPR_D int k_month_offsets[1 + 12] = { >+ -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, >+ }; >+ const int feb29 = (cd.month() > 2 && impl::is_leap_year(cd.year())); >+ return k_month_offsets[cd.month()] + feb29 + cd.day(); >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+std::ostream& operator<<(std::ostream& os, const civil_year& y); >+std::ostream& operator<<(std::ostream& os, const civil_month& m); >+std::ostream& operator<<(std::ostream& os, const civil_day& d); >+std::ostream& operator<<(std::ostream& os, const civil_hour& h); >+std::ostream& operator<<(std::ostream& os, const civil_minute& m); >+std::ostream& operator<<(std::ostream& os, const civil_second& s); >+std::ostream& operator<<(std::ostream& os, weekday wd); >+ >+} // namespace detail >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#undef CONSTEXPR_M >+#undef CONSTEXPR_F >+#undef CONSTEXPR_D >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h >new file mode 100644 >index 00000000000..0b9764ea72a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/time_zone.h >@@ -0,0 +1,380 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// A library for translating between absolute times (represented by >+// std::chrono::time_points of the std::chrono::system_clock) and civil >+// times (represented by cctz::civil_second) using the rules defined by >+// a time zone (cctz::time_zone). >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ >+ >+#include <chrono> >+#include <cstdint> >+#include <string> >+#include <utility> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// Convenience aliases. Not intended as public API points. >+template <typename D> >+using time_point = std::chrono::time_point<std::chrono::system_clock, D>; >+using seconds = std::chrono::duration<std::int_fast64_t>; >+using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead. >+ >+namespace detail { >+template <typename D> >+inline std::pair<time_point<seconds>, D> >+split_seconds(const time_point<D>& tp) { >+ auto sec = std::chrono::time_point_cast<seconds>(tp); >+ auto sub = tp - sec; >+ if (sub.count() < 0) { >+ sec -= seconds(1); >+ sub += seconds(1); >+ } >+ return {sec, std::chrono::duration_cast<D>(sub)}; >+} >+inline std::pair<time_point<seconds>, seconds> >+split_seconds(const time_point<seconds>& tp) { >+ return {tp, seconds::zero()}; >+} >+} // namespace detail >+ >+// cctz::time_zone is an opaque, small, value-type class representing a >+// geo-political region within which particular rules are used for mapping >+// between absolute and civil times. Time zones are named using the TZ >+// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles" >+// or "Australia/Sydney". Time zones are created from factory functions such >+// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ >+// identifiers. >+// >+// Example: >+// cctz::time_zone utc = cctz::utc_time_zone(); >+// cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8)); >+// cctz::time_zone loc = cctz::local_time_zone(); >+// cctz::time_zone lax; >+// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } >+// >+// See also: >+// - http://www.iana.org/time-zones >+// - http://en.wikipedia.org/wiki/Zoneinfo >+class time_zone { >+ public: >+ time_zone() : time_zone(nullptr) {} // Equivalent to UTC >+ time_zone(const time_zone&) = default; >+ time_zone& operator=(const time_zone&) = default; >+ >+ std::string name() const; >+ >+ // An absolute_lookup represents the civil time (cctz::civil_second) within >+ // this time_zone at the given absolute time (time_point). There are >+ // additionally a few other fields that may be useful when working with >+ // older APIs, such as std::tm. >+ // >+ // Example: >+ // const cctz::time_zone tz = ... >+ // const auto tp = std::chrono::system_clock::now(); >+ // const cctz::time_zone::absolute_lookup al = tz.lookup(tp); >+ struct absolute_lookup { >+ civil_second cs; >+ // Note: The following fields exist for backward compatibility with older >+ // APIs. Accessing these fields directly is a sign of imprudent logic in >+ // the calling code. Modern time-related code should only access this data >+ // indirectly by way of cctz::format(). >+ int offset; // civil seconds east of UTC >+ bool is_dst; // is offset non-standard? >+ const char* abbr; // time-zone abbreviation (e.g., "PST") >+ }; >+ absolute_lookup lookup(const time_point<seconds>& tp) const; >+ template <typename D> >+ absolute_lookup lookup(const time_point<D>& tp) const { >+ return lookup(detail::split_seconds(tp).first); >+ } >+ >+ // A civil_lookup represents the absolute time(s) (time_point) that >+ // correspond to the given civil time (cctz::civil_second) within this >+ // time_zone. Usually the given civil time represents a unique instant >+ // in time, in which case the conversion is unambiguous. However, >+ // within this time zone, the given civil time may be skipped (e.g., >+ // during a positive UTC offset shift), or repeated (e.g., during a >+ // negative UTC offset shift). To account for these possibilities, >+ // civil_lookup is richer than just a single time_point. >+ // >+ // In all cases the civil_lookup::kind enum will indicate the nature >+ // of the given civil-time argument, and the pre, trans, and post >+ // members will give the absolute time answers using the pre-transition >+ // offset, the transition point itself, and the post-transition offset, >+ // respectively (all three times are equal if kind == UNIQUE). If any >+ // of these three absolute times is outside the representable range of a >+ // time_point<seconds> the field is set to its maximum/minimum value. >+ // >+ // Example: >+ // cctz::time_zone lax; >+ // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } >+ // >+ // // A unique civil time. >+ // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0)); >+ // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE >+ // // jan01.pre is 2011/01/01 00:00:00 -0800 >+ // // jan01.trans is 2011/01/01 00:00:00 -0800 >+ // // jan01.post is 2011/01/01 00:00:00 -0800 >+ // >+ // // A Spring DST transition, when there is a gap in civil time. >+ // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0)); >+ // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED >+ // // mar13.pre is 2011/03/13 03:15:00 -0700 >+ // // mar13.trans is 2011/03/13 03:00:00 -0700 >+ // // mar13.post is 2011/03/13 01:15:00 -0800 >+ // >+ // // A Fall DST transition, when civil times are repeated. >+ // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0)); >+ // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED >+ // // nov06.pre is 2011/11/06 01:15:00 -0700 >+ // // nov06.trans is 2011/11/06 01:00:00 -0800 >+ // // nov06.post is 2011/11/06 01:15:00 -0800 >+ struct civil_lookup { >+ enum civil_kind { >+ UNIQUE, // the civil time was singular (pre == trans == post) >+ SKIPPED, // the civil time did not exist (pre >= trans > post) >+ REPEATED, // the civil time was ambiguous (pre < trans <= post) >+ } kind; >+ time_point<seconds> pre; // uses the pre-transition offset >+ time_point<seconds> trans; // instant of civil-offset change >+ time_point<seconds> post; // uses the post-transition offset >+ }; >+ civil_lookup lookup(const civil_second& cs) const; >+ >+ // Finds the time of the next/previous offset change in this time zone. >+ // >+ // By definition, next_transition(tp, &trans) returns false when tp has >+ // its maximum value, and prev_transition(tp, &trans) returns false >+ // when tp has its minimum value. If the zone has no transitions, the >+ // result will also be false no matter what the argument. >+ // >+ // Otherwise, when tp has its minimum value, next_transition(tp, &trans) >+ // returns true and sets trans to the first recorded transition. Chains >+ // of calls to next_transition()/prev_transition() will eventually return >+ // false, but it is unspecified exactly when next_transition(tp, &trans) >+ // jumps to false, or what time is set by prev_transition(tp, &trans) for >+ // a very distant tp. >+ // >+ // Note: Enumeration of time-zone transitions is for informational purposes >+ // only. Modern time-related code should not care about when offset changes >+ // occur. >+ // >+ // Example: >+ // cctz::time_zone nyc; >+ // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... } >+ // const auto now = std::chrono::system_clock::now(); >+ // auto tp = cctz::time_point<cctz::seconds>::min(); >+ // cctz::time_zone::civil_transition trans; >+ // while (tp <= now && nyc.next_transition(tp, &trans)) { >+ // // transition: trans.from -> trans.to >+ // tp = nyc.lookup(trans.to).trans; >+ // } >+ struct civil_transition { >+ civil_second from; // the civil time we jump from >+ civil_second to; // the civil time we jump to >+ }; >+ bool next_transition(const time_point<seconds>& tp, >+ civil_transition* trans) const; >+ template <typename D> >+ bool next_transition(const time_point<D>& tp, >+ civil_transition* trans) const { >+ return next_transition(detail::split_seconds(tp).first, trans); >+ } >+ bool prev_transition(const time_point<seconds>& tp, >+ civil_transition* trans) const; >+ template <typename D> >+ bool prev_transition(const time_point<D>& tp, >+ civil_transition* trans) const { >+ return prev_transition(detail::split_seconds(tp).first, trans); >+ } >+ >+ // version() and description() provide additional information about the >+ // time zone. The content of each of the returned strings is unspecified, >+ // however, when the IANA Time Zone Database is the underlying data source >+ // the version() std::string will be in the familar form (e.g, "2018e") or >+ // empty when unavailable. >+ // >+ // Note: These functions are for informational or testing purposes only. >+ std::string version() const; // empty when unknown >+ std::string description() const; >+ >+ // Relational operators. >+ friend bool operator==(time_zone lhs, time_zone rhs) { >+ return &lhs.effective_impl() == &rhs.effective_impl(); >+ } >+ friend bool operator!=(time_zone lhs, time_zone rhs) { >+ return !(lhs == rhs); >+ } >+ >+ class Impl; >+ >+ private: >+ explicit time_zone(const Impl* impl) : impl_(impl) {} >+ const Impl& effective_impl() const; // handles implicit UTC >+ const Impl* impl_; >+}; >+ >+// Loads the named time zone. May perform I/O on the initial load. >+// If the name is invalid, or some other kind of error occurs, returns >+// false and "*tz" is set to the UTC time zone. >+bool load_time_zone(const std::string& name, time_zone* tz); >+ >+// Returns a time_zone representing UTC. Cannot fail. >+time_zone utc_time_zone(); >+ >+// Returns a time zone that is a fixed offset (seconds east) from UTC. >+// Note: If the absolute value of the offset is greater than 24 hours >+// you'll get UTC (i.e., zero offset) instead. >+time_zone fixed_time_zone(const seconds& offset); >+ >+// Returns a time zone representing the local time zone. Falls back to UTC. >+// Note: local_time_zone.name() may only be something like "localtime". >+time_zone local_time_zone(); >+ >+// Returns the civil time (cctz::civil_second) within the given time zone at >+// the given absolute time (time_point). Since the additional fields provided >+// by the time_zone::absolute_lookup struct should rarely be needed in modern >+// code, this convert() function is simpler and should be preferred. >+template <typename D> >+inline civil_second convert(const time_point<D>& tp, const time_zone& tz) { >+ return tz.lookup(tp).cs; >+} >+ >+// Returns the absolute time (time_point) that corresponds to the given civil >+// time within the given time zone. If the civil time is not unique (i.e., if >+// it was either repeated or non-existent), then the returned time_point is >+// the best estimate that preserves relative order. That is, this function >+// guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz). >+inline time_point<seconds> convert(const civil_second& cs, >+ const time_zone& tz) { >+ const time_zone::civil_lookup cl = tz.lookup(cs); >+ if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans; >+ return cl.pre; >+} >+ >+namespace detail { >+using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>; >+std::string format(const std::string&, const time_point<seconds>&, >+ const femtoseconds&, const time_zone&); >+bool parse(const std::string&, const std::string&, const time_zone&, >+ time_point<seconds>*, femtoseconds*, std::string* err = nullptr); >+} // namespace detail >+ >+// Formats the given time_point in the given cctz::time_zone according to >+// the provided format std::string. Uses strftime()-like formatting options, >+// with the following extensions: >+// >+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) >+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) >+// - %E#S - Seconds with # digits of fractional precision >+// - %E*S - Seconds with full fractional precision (a literal '*') >+// - %E#f - Fractional seconds with # digits of precision >+// - %E*f - Fractional seconds with full precision (a literal '*') >+// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) >+// >+// Note that %E0S behaves like %S, and %E0f produces no characters. In >+// contrast %E*f always produces at least one digit, which may be '0'. >+// >+// Note that %Y produces as many characters as it takes to fully render the >+// year. A year outside of [-999:9999] when formatted with %E4Y will produce >+// more than four characters, just like %Y. >+// >+// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z) >+// so that the resulting std::string uniquely identifies an absolute time. >+// >+// Example: >+// cctz::time_zone lax; >+// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } >+// auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax); >+// std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05" >+// f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000" >+template <typename D> >+inline std::string format(const std::string& fmt, const time_point<D>& tp, >+ const time_zone& tz) { >+ const auto p = detail::split_seconds(tp); >+ const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second); >+ return detail::format(fmt, p.first, n, tz); >+} >+ >+// Parses an input std::string according to the provided format std::string and >+// returns the corresponding time_point. Uses strftime()-like formatting >+// options, with the same extensions as cctz::format(), but with the >+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez >+// and %E*z also accept the same inputs. >+// >+// %Y consumes as many numeric characters as it can, so the matching data >+// should always be terminated with a non-numeric. %E4Y always consumes >+// exactly four characters, including any sign. >+// >+// Unspecified fields are taken from the default date and time of ... >+// >+// "1970-01-01 00:00:00.0 +0000" >+// >+// For example, parsing a std::string of "15:45" (%H:%M) will return a time_point >+// that represents "1970-01-01 15:45:00.0 +0000". >+// >+// Note that parse() returns time instants, so it makes most sense to parse >+// fully-specified date/time strings that include a UTC offset (%z, %Ez, or >+// %E*z). >+// >+// Note also that parse() only heeds the fields year, month, day, hour, >+// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a >+// or %A), while parsed for syntactic validity, are ignored in the conversion. >+// >+// Date and time fields that are out-of-range will be treated as errors rather >+// than normalizing them like cctz::civil_second() would do. For example, it >+// is an error to parse the date "Oct 32, 2013" because 32 is out of range. >+// >+// A second of ":60" is normalized to ":00" of the following minute with >+// fractional seconds discarded. The following table shows how the given >+// seconds and subseconds will be parsed: >+// >+// "59.x" -> 59.x // exact >+// "60.x" -> 00.0 // normalized >+// "00.x" -> 00.x // exact >+// >+// Errors are indicated by returning false. >+// >+// Example: >+// const cctz::time_zone tz = ... >+// std::chrono::system_clock::time_point tp; >+// if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) { >+// ... >+// } >+template <typename D> >+inline bool parse(const std::string& fmt, const std::string& input, >+ const time_zone& tz, time_point<D>* tpp) { >+ time_point<seconds> sec; >+ detail::femtoseconds fs; >+ const bool b = detail::parse(fmt, input, tz, &sec, &fs); >+ if (b) { >+ // TODO: Return false if unrepresentable as a time_point<D>. >+ *tpp = std::chrono::time_point_cast<D>(sec); >+ *tpp += std::chrono::duration_cast<D>(fs); >+ } >+ return b; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h >new file mode 100644 >index 00000000000..20a76979370 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h >@@ -0,0 +1,96 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ >+ >+#include <cstddef> >+#include <functional> >+#include <memory> >+#include <string> >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// A stdio-like interface for providing zoneinfo data for a particular zone. >+class ZoneInfoSource { >+ public: >+ virtual ~ZoneInfoSource(); >+ >+ virtual std::size_t Read(void* ptr, std::size_t size) = 0; // like fread() >+ virtual int Skip(std::size_t offset) = 0; // like fseek() >+ >+ // Until the zoneinfo data supports versioning information, we provide >+ // a way for a ZoneInfoSource to indicate it out-of-band. The default >+ // implementation returns an empty std::string. >+ virtual std::string Version() const; >+}; >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+namespace absl { >+namespace time_internal { >+namespace cctz_extension { >+ >+// A function-pointer type for a factory that returns a ZoneInfoSource >+// given the name of a time zone and a fallback factory. Returns null >+// when the data for the named zone cannot be found. >+using ZoneInfoSourceFactory = >+ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)( >+ const std::string&, >+ const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>( >+ const std::string&)>&); >+ >+// The user can control the mapping of zone names to zoneinfo data by >+// providing a definition for cctz_extension::zone_info_source_factory. >+// For example, given functions my_factory() and my_other_factory() that >+// can return a ZoneInfoSource for a named zone, we could inject them into >+// cctz::load_time_zone() with: >+// >+// namespace cctz_extension { >+// namespace { >+// std::unique_ptr<cctz::ZoneInfoSource> CustomFactory( >+// const std::string& name, >+// const std::function<std::unique_ptr<cctz::ZoneInfoSource>( >+// const std::string& name)>& fallback_factory) { >+// if (auto zip = my_factory(name)) return zip; >+// if (auto zip = fallback_factory(name)) return zip; >+// if (auto zip = my_other_factory(name)) return zip; >+// return nullptr; >+// } >+// } // namespace >+// ZoneInfoSourceFactory zone_info_source_factory = CustomFactory; >+// } // namespace cctz_extension >+// >+// This might be used, say, to use zoneinfo data embedded in the program, >+// or read from a (possibly compressed) file archive, or both. >+// >+// cctz_extension::zone_info_source_factory() will be called: >+// (1) from the same thread as the cctz::load_time_zone() call, >+// (2) only once for any zone name, and >+// (3) serially (i.e., no concurrent execution). >+// >+// The fallback factory obtains zoneinfo data by reading files in ${TZDIR}, >+// and it is used automatically when no zone_info_source_factory definition >+// is linked into the program. >+extern ZoneInfoSourceFactory zone_info_source_factory; >+ >+} // namespace cctz_extension >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc >new file mode 100644 >index 00000000000..c97df78c09c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/cctz_benchmark.cc >@@ -0,0 +1,980 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <algorithm> >+#include <cassert> >+#include <chrono> >+#include <ctime> >+#include <random> >+#include <string> >+#include <vector> >+ >+#include "benchmark/benchmark.h" >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+#include "time_zone_impl.h" >+ >+namespace { >+ >+namespace cctz = absl::time_internal::cctz; >+ >+void BM_Difference_Days(benchmark::State& state) { >+ const cctz::civil_day c(2014, 8, 22); >+ const cctz::civil_day epoch(1970, 1, 1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(c - epoch); >+ } >+} >+BENCHMARK(BM_Difference_Days); >+ >+void BM_Step_Days(benchmark::State& state) { >+ const cctz::civil_day kStart(2014, 8, 22); >+ cctz::civil_day c = kStart; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(++c); >+ } >+} >+BENCHMARK(BM_Step_Days); >+ >+const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; >+const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; >+ >+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; >+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; >+ >+// A list of known time-zone names. >+// TODO: Refactor with src/time_zone_lookup_test.cc. >+const char* const kTimeZoneNames[] = { >+ "Africa/Abidjan", >+ "Africa/Accra", >+ "Africa/Addis_Ababa", >+ "Africa/Algiers", >+ "Africa/Asmara", >+ "Africa/Asmera", >+ "Africa/Bamako", >+ "Africa/Bangui", >+ "Africa/Banjul", >+ "Africa/Bissau", >+ "Africa/Blantyre", >+ "Africa/Brazzaville", >+ "Africa/Bujumbura", >+ "Africa/Cairo", >+ "Africa/Casablanca", >+ "Africa/Ceuta", >+ "Africa/Conakry", >+ "Africa/Dakar", >+ "Africa/Dar_es_Salaam", >+ "Africa/Djibouti", >+ "Africa/Douala", >+ "Africa/El_Aaiun", >+ "Africa/Freetown", >+ "Africa/Gaborone", >+ "Africa/Harare", >+ "Africa/Johannesburg", >+ "Africa/Juba", >+ "Africa/Kampala", >+ "Africa/Khartoum", >+ "Africa/Kigali", >+ "Africa/Kinshasa", >+ "Africa/Lagos", >+ "Africa/Libreville", >+ "Africa/Lome", >+ "Africa/Luanda", >+ "Africa/Lubumbashi", >+ "Africa/Lusaka", >+ "Africa/Malabo", >+ "Africa/Maputo", >+ "Africa/Maseru", >+ "Africa/Mbabane", >+ "Africa/Mogadishu", >+ "Africa/Monrovia", >+ "Africa/Nairobi", >+ "Africa/Ndjamena", >+ "Africa/Niamey", >+ "Africa/Nouakchott", >+ "Africa/Ouagadougou", >+ "Africa/Porto-Novo", >+ "Africa/Sao_Tome", >+ "Africa/Timbuktu", >+ "Africa/Tripoli", >+ "Africa/Tunis", >+ "Africa/Windhoek", >+ "America/Adak", >+ "America/Anchorage", >+ "America/Anguilla", >+ "America/Antigua", >+ "America/Araguaina", >+ "America/Argentina/Buenos_Aires", >+ "America/Argentina/Catamarca", >+ "America/Argentina/ComodRivadavia", >+ "America/Argentina/Cordoba", >+ "America/Argentina/Jujuy", >+ "America/Argentina/La_Rioja", >+ "America/Argentina/Mendoza", >+ "America/Argentina/Rio_Gallegos", >+ "America/Argentina/Salta", >+ "America/Argentina/San_Juan", >+ "America/Argentina/San_Luis", >+ "America/Argentina/Tucuman", >+ "America/Argentina/Ushuaia", >+ "America/Aruba", >+ "America/Asuncion", >+ "America/Atikokan", >+ "America/Atka", >+ "America/Bahia", >+ "America/Bahia_Banderas", >+ "America/Barbados", >+ "America/Belem", >+ "America/Belize", >+ "America/Blanc-Sablon", >+ "America/Boa_Vista", >+ "America/Bogota", >+ "America/Boise", >+ "America/Buenos_Aires", >+ "America/Cambridge_Bay", >+ "America/Campo_Grande", >+ "America/Cancun", >+ "America/Caracas", >+ "America/Catamarca", >+ "America/Cayenne", >+ "America/Cayman", >+ "America/Chicago", >+ "America/Chihuahua", >+ "America/Coral_Harbour", >+ "America/Cordoba", >+ "America/Costa_Rica", >+ "America/Creston", >+ "America/Cuiaba", >+ "America/Curacao", >+ "America/Danmarkshavn", >+ "America/Dawson", >+ "America/Dawson_Creek", >+ "America/Denver", >+ "America/Detroit", >+ "America/Dominica", >+ "America/Edmonton", >+ "America/Eirunepe", >+ "America/El_Salvador", >+ "America/Ensenada", >+ "America/Fort_Nelson", >+ "America/Fort_Wayne", >+ "America/Fortaleza", >+ "America/Glace_Bay", >+ "America/Godthab", >+ "America/Goose_Bay", >+ "America/Grand_Turk", >+ "America/Grenada", >+ "America/Guadeloupe", >+ "America/Guatemala", >+ "America/Guayaquil", >+ "America/Guyana", >+ "America/Halifax", >+ "America/Havana", >+ "America/Hermosillo", >+ "America/Indiana/Indianapolis", >+ "America/Indiana/Knox", >+ "America/Indiana/Marengo", >+ "America/Indiana/Petersburg", >+ "America/Indiana/Tell_City", >+ "America/Indiana/Vevay", >+ "America/Indiana/Vincennes", >+ "America/Indiana/Winamac", >+ "America/Indianapolis", >+ "America/Inuvik", >+ "America/Iqaluit", >+ "America/Jamaica", >+ "America/Jujuy", >+ "America/Juneau", >+ "America/Kentucky/Louisville", >+ "America/Kentucky/Monticello", >+ "America/Knox_IN", >+ "America/Kralendijk", >+ "America/La_Paz", >+ "America/Lima", >+ "America/Los_Angeles", >+ "America/Louisville", >+ "America/Lower_Princes", >+ "America/Maceio", >+ "America/Managua", >+ "America/Manaus", >+ "America/Marigot", >+ "America/Martinique", >+ "America/Matamoros", >+ "America/Mazatlan", >+ "America/Mendoza", >+ "America/Menominee", >+ "America/Merida", >+ "America/Metlakatla", >+ "America/Mexico_City", >+ "America/Miquelon", >+ "America/Moncton", >+ "America/Monterrey", >+ "America/Montevideo", >+ "America/Montreal", >+ "America/Montserrat", >+ "America/Nassau", >+ "America/New_York", >+ "America/Nipigon", >+ "America/Nome", >+ "America/Noronha", >+ "America/North_Dakota/Beulah", >+ "America/North_Dakota/Center", >+ "America/North_Dakota/New_Salem", >+ "America/Ojinaga", >+ "America/Panama", >+ "America/Pangnirtung", >+ "America/Paramaribo", >+ "America/Phoenix", >+ "America/Port-au-Prince", >+ "America/Port_of_Spain", >+ "America/Porto_Acre", >+ "America/Porto_Velho", >+ "America/Puerto_Rico", >+ "America/Punta_Arenas", >+ "America/Rainy_River", >+ "America/Rankin_Inlet", >+ "America/Recife", >+ "America/Regina", >+ "America/Resolute", >+ "America/Rio_Branco", >+ "America/Rosario", >+ "America/Santa_Isabel", >+ "America/Santarem", >+ "America/Santiago", >+ "America/Santo_Domingo", >+ "America/Sao_Paulo", >+ "America/Scoresbysund", >+ "America/Shiprock", >+ "America/Sitka", >+ "America/St_Barthelemy", >+ "America/St_Johns", >+ "America/St_Kitts", >+ "America/St_Lucia", >+ "America/St_Thomas", >+ "America/St_Vincent", >+ "America/Swift_Current", >+ "America/Tegucigalpa", >+ "America/Thule", >+ "America/Thunder_Bay", >+ "America/Tijuana", >+ "America/Toronto", >+ "America/Tortola", >+ "America/Vancouver", >+ "America/Virgin", >+ "America/Whitehorse", >+ "America/Winnipeg", >+ "America/Yakutat", >+ "America/Yellowknife", >+ "Antarctica/Casey", >+ "Antarctica/Davis", >+ "Antarctica/DumontDUrville", >+ "Antarctica/Macquarie", >+ "Antarctica/Mawson", >+ "Antarctica/McMurdo", >+ "Antarctica/Palmer", >+ "Antarctica/Rothera", >+ "Antarctica/South_Pole", >+ "Antarctica/Syowa", >+ "Antarctica/Troll", >+ "Antarctica/Vostok", >+ "Arctic/Longyearbyen", >+ "Asia/Aden", >+ "Asia/Almaty", >+ "Asia/Amman", >+ "Asia/Anadyr", >+ "Asia/Aqtau", >+ "Asia/Aqtobe", >+ "Asia/Ashgabat", >+ "Asia/Ashkhabad", >+ "Asia/Atyrau", >+ "Asia/Baghdad", >+ "Asia/Bahrain", >+ "Asia/Baku", >+ "Asia/Bangkok", >+ "Asia/Barnaul", >+ "Asia/Beirut", >+ "Asia/Bishkek", >+ "Asia/Brunei", >+ "Asia/Calcutta", >+ "Asia/Chita", >+ "Asia/Choibalsan", >+ "Asia/Chongqing", >+ "Asia/Chungking", >+ "Asia/Colombo", >+ "Asia/Dacca", >+ "Asia/Damascus", >+ "Asia/Dhaka", >+ "Asia/Dili", >+ "Asia/Dubai", >+ "Asia/Dushanbe", >+ "Asia/Famagusta", >+ "Asia/Gaza", >+ "Asia/Harbin", >+ "Asia/Hebron", >+ "Asia/Ho_Chi_Minh", >+ "Asia/Hong_Kong", >+ "Asia/Hovd", >+ "Asia/Irkutsk", >+ "Asia/Istanbul", >+ "Asia/Jakarta", >+ "Asia/Jayapura", >+ "Asia/Jerusalem", >+ "Asia/Kabul", >+ "Asia/Kamchatka", >+ "Asia/Karachi", >+ "Asia/Kashgar", >+ "Asia/Kathmandu", >+ "Asia/Katmandu", >+ "Asia/Khandyga", >+ "Asia/Kolkata", >+ "Asia/Krasnoyarsk", >+ "Asia/Kuala_Lumpur", >+ "Asia/Kuching", >+ "Asia/Kuwait", >+ "Asia/Macao", >+ "Asia/Macau", >+ "Asia/Magadan", >+ "Asia/Makassar", >+ "Asia/Manila", >+ "Asia/Muscat", >+ "Asia/Nicosia", >+ "Asia/Novokuznetsk", >+ "Asia/Novosibirsk", >+ "Asia/Omsk", >+ "Asia/Oral", >+ "Asia/Phnom_Penh", >+ "Asia/Pontianak", >+ "Asia/Pyongyang", >+ "Asia/Qatar", >+ "Asia/Qyzylorda", >+ "Asia/Rangoon", >+ "Asia/Riyadh", >+ "Asia/Saigon", >+ "Asia/Sakhalin", >+ "Asia/Samarkand", >+ "Asia/Seoul", >+ "Asia/Shanghai", >+ "Asia/Singapore", >+ "Asia/Srednekolymsk", >+ "Asia/Taipei", >+ "Asia/Tashkent", >+ "Asia/Tbilisi", >+ "Asia/Tehran", >+ "Asia/Tel_Aviv", >+ "Asia/Thimbu", >+ "Asia/Thimphu", >+ "Asia/Tokyo", >+ "Asia/Tomsk", >+ "Asia/Ujung_Pandang", >+ "Asia/Ulaanbaatar", >+ "Asia/Ulan_Bator", >+ "Asia/Urumqi", >+ "Asia/Ust-Nera", >+ "Asia/Vientiane", >+ "Asia/Vladivostok", >+ "Asia/Yakutsk", >+ "Asia/Yangon", >+ "Asia/Yekaterinburg", >+ "Asia/Yerevan", >+ "Atlantic/Azores", >+ "Atlantic/Bermuda", >+ "Atlantic/Canary", >+ "Atlantic/Cape_Verde", >+ "Atlantic/Faeroe", >+ "Atlantic/Faroe", >+ "Atlantic/Jan_Mayen", >+ "Atlantic/Madeira", >+ "Atlantic/Reykjavik", >+ "Atlantic/South_Georgia", >+ "Atlantic/St_Helena", >+ "Atlantic/Stanley", >+ "Australia/ACT", >+ "Australia/Adelaide", >+ "Australia/Brisbane", >+ "Australia/Broken_Hill", >+ "Australia/Canberra", >+ "Australia/Currie", >+ "Australia/Darwin", >+ "Australia/Eucla", >+ "Australia/Hobart", >+ "Australia/LHI", >+ "Australia/Lindeman", >+ "Australia/Lord_Howe", >+ "Australia/Melbourne", >+ "Australia/NSW", >+ "Australia/North", >+ "Australia/Perth", >+ "Australia/Queensland", >+ "Australia/South", >+ "Australia/Sydney", >+ "Australia/Tasmania", >+ "Australia/Victoria", >+ "Australia/West", >+ "Australia/Yancowinna", >+ "Brazil/Acre", >+ "Brazil/DeNoronha", >+ "Brazil/East", >+ "Brazil/West", >+ "CET", >+ "CST6CDT", >+ "Canada/Atlantic", >+ "Canada/Central", >+ "Canada/Eastern", >+ "Canada/Mountain", >+ "Canada/Newfoundland", >+ "Canada/Pacific", >+ "Canada/Saskatchewan", >+ "Canada/Yukon", >+ "Chile/Continental", >+ "Chile/EasterIsland", >+ "Cuba", >+ "EET", >+ "EST", >+ "EST5EDT", >+ "Egypt", >+ "Eire", >+ "Etc/GMT", >+ "Etc/GMT+0", >+ "Etc/GMT+1", >+ "Etc/GMT+10", >+ "Etc/GMT+11", >+ "Etc/GMT+12", >+ "Etc/GMT+2", >+ "Etc/GMT+3", >+ "Etc/GMT+4", >+ "Etc/GMT+5", >+ "Etc/GMT+6", >+ "Etc/GMT+7", >+ "Etc/GMT+8", >+ "Etc/GMT+9", >+ "Etc/GMT-0", >+ "Etc/GMT-1", >+ "Etc/GMT-10", >+ "Etc/GMT-11", >+ "Etc/GMT-12", >+ "Etc/GMT-13", >+ "Etc/GMT-14", >+ "Etc/GMT-2", >+ "Etc/GMT-3", >+ "Etc/GMT-4", >+ "Etc/GMT-5", >+ "Etc/GMT-6", >+ "Etc/GMT-7", >+ "Etc/GMT-8", >+ "Etc/GMT-9", >+ "Etc/GMT0", >+ "Etc/Greenwich", >+ "Etc/UCT", >+ "Etc/UTC", >+ "Etc/Universal", >+ "Etc/Zulu", >+ "Europe/Amsterdam", >+ "Europe/Andorra", >+ "Europe/Astrakhan", >+ "Europe/Athens", >+ "Europe/Belfast", >+ "Europe/Belgrade", >+ "Europe/Berlin", >+ "Europe/Bratislava", >+ "Europe/Brussels", >+ "Europe/Bucharest", >+ "Europe/Budapest", >+ "Europe/Busingen", >+ "Europe/Chisinau", >+ "Europe/Copenhagen", >+ "Europe/Dublin", >+ "Europe/Gibraltar", >+ "Europe/Guernsey", >+ "Europe/Helsinki", >+ "Europe/Isle_of_Man", >+ "Europe/Istanbul", >+ "Europe/Jersey", >+ "Europe/Kaliningrad", >+ "Europe/Kiev", >+ "Europe/Kirov", >+ "Europe/Lisbon", >+ "Europe/Ljubljana", >+ "Europe/London", >+ "Europe/Luxembourg", >+ "Europe/Madrid", >+ "Europe/Malta", >+ "Europe/Mariehamn", >+ "Europe/Minsk", >+ "Europe/Monaco", >+ "Europe/Moscow", >+ "Europe/Nicosia", >+ "Europe/Oslo", >+ "Europe/Paris", >+ "Europe/Podgorica", >+ "Europe/Prague", >+ "Europe/Riga", >+ "Europe/Rome", >+ "Europe/Samara", >+ "Europe/San_Marino", >+ "Europe/Sarajevo", >+ "Europe/Saratov", >+ "Europe/Simferopol", >+ "Europe/Skopje", >+ "Europe/Sofia", >+ "Europe/Stockholm", >+ "Europe/Tallinn", >+ "Europe/Tirane", >+ "Europe/Tiraspol", >+ "Europe/Ulyanovsk", >+ "Europe/Uzhgorod", >+ "Europe/Vaduz", >+ "Europe/Vatican", >+ "Europe/Vienna", >+ "Europe/Vilnius", >+ "Europe/Volgograd", >+ "Europe/Warsaw", >+ "Europe/Zagreb", >+ "Europe/Zaporozhye", >+ "Europe/Zurich", >+ "GB", >+ "GB-Eire", >+ "GMT", >+ "GMT+0", >+ "GMT-0", >+ "GMT0", >+ "Greenwich", >+ "HST", >+ "Hongkong", >+ "Iceland", >+ "Indian/Antananarivo", >+ "Indian/Chagos", >+ "Indian/Christmas", >+ "Indian/Cocos", >+ "Indian/Comoro", >+ "Indian/Kerguelen", >+ "Indian/Mahe", >+ "Indian/Maldives", >+ "Indian/Mauritius", >+ "Indian/Mayotte", >+ "Indian/Reunion", >+ "Iran", >+ "Israel", >+ "Jamaica", >+ "Japan", >+ "Kwajalein", >+ "Libya", >+ "MET", >+ "MST", >+ "MST7MDT", >+ "Mexico/BajaNorte", >+ "Mexico/BajaSur", >+ "Mexico/General", >+ "NZ", >+ "NZ-CHAT", >+ "Navajo", >+ "PRC", >+ "PST8PDT", >+ "Pacific/Apia", >+ "Pacific/Auckland", >+ "Pacific/Bougainville", >+ "Pacific/Chatham", >+ "Pacific/Chuuk", >+ "Pacific/Easter", >+ "Pacific/Efate", >+ "Pacific/Enderbury", >+ "Pacific/Fakaofo", >+ "Pacific/Fiji", >+ "Pacific/Funafuti", >+ "Pacific/Galapagos", >+ "Pacific/Gambier", >+ "Pacific/Guadalcanal", >+ "Pacific/Guam", >+ "Pacific/Honolulu", >+ "Pacific/Johnston", >+ "Pacific/Kiritimati", >+ "Pacific/Kosrae", >+ "Pacific/Kwajalein", >+ "Pacific/Majuro", >+ "Pacific/Marquesas", >+ "Pacific/Midway", >+ "Pacific/Nauru", >+ "Pacific/Niue", >+ "Pacific/Norfolk", >+ "Pacific/Noumea", >+ "Pacific/Pago_Pago", >+ "Pacific/Palau", >+ "Pacific/Pitcairn", >+ "Pacific/Pohnpei", >+ "Pacific/Ponape", >+ "Pacific/Port_Moresby", >+ "Pacific/Rarotonga", >+ "Pacific/Saipan", >+ "Pacific/Samoa", >+ "Pacific/Tahiti", >+ "Pacific/Tarawa", >+ "Pacific/Tongatapu", >+ "Pacific/Truk", >+ "Pacific/Wake", >+ "Pacific/Wallis", >+ "Pacific/Yap", >+ "Poland", >+ "Portugal", >+ "ROC", >+ "ROK", >+ "Singapore", >+ "Turkey", >+ "UCT", >+ "US/Alaska", >+ "US/Aleutian", >+ "US/Arizona", >+ "US/Central", >+ "US/East-Indiana", >+ "US/Eastern", >+ "US/Hawaii", >+ "US/Indiana-Starke", >+ "US/Michigan", >+ "US/Mountain", >+ "US/Pacific", >+ "US/Samoa", >+ "UTC", >+ "Universal", >+ "W-SU", >+ "WET", >+ "Zulu", >+ nullptr >+}; >+ >+std::vector<std::string> AllTimeZoneNames() { >+ std::vector<std::string> names; >+ for (const char* const* namep = kTimeZoneNames; *namep != nullptr; ++namep) { >+ names.push_back(std::string("file:") + *namep); >+ } >+ assert(!names.empty()); >+ >+ std::mt19937 urbg(42); // a UniformRandomBitGenerator with fixed seed >+ std::shuffle(names.begin(), names.end(), urbg); >+ return names; >+} >+ >+cctz::time_zone TestTimeZone() { >+ cctz::time_zone tz; >+ cctz::load_time_zone("America/Los_Angeles", &tz); >+ return tz; >+} >+ >+void BM_Zone_LoadUTCTimeZoneFirst(benchmark::State& state) { >+ cctz::time_zone tz; >+ cctz::load_time_zone("UTC", &tz); // in case we're first >+ cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadUTCTimeZoneFirst); >+ >+void BM_Zone_LoadUTCTimeZoneLast(benchmark::State& state) { >+ cctz::time_zone tz; >+ for (const auto& name : AllTimeZoneNames()) { >+ cctz::load_time_zone(name, &tz); // prime cache >+ } >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadUTCTimeZoneLast); >+ >+void BM_Zone_LoadTimeZoneFirst(benchmark::State& state) { >+ cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first >+ const std::string name = "file:America/Los_Angeles"; >+ while (state.KeepRunning()) { >+ state.PauseTiming(); >+ cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); >+ state.ResumeTiming(); >+ benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadTimeZoneFirst); >+ >+void BM_Zone_LoadTimeZoneCached(benchmark::State& state) { >+ cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first >+ cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); >+ const std::string name = "file:America/Los_Angeles"; >+ cctz::load_time_zone(name, &tz); // prime cache >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadTimeZoneCached); >+ >+void BM_Zone_LoadLocalTimeZoneCached(benchmark::State& state) { >+ cctz::utc_time_zone(); // in case we're first >+ cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); >+ cctz::local_time_zone(); // prime cache >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::local_time_zone()); >+ } >+} >+BENCHMARK(BM_Zone_LoadLocalTimeZoneCached); >+ >+void BM_Zone_LoadAllTimeZonesFirst(benchmark::State& state) { >+ cctz::time_zone tz; >+ const std::vector<std::string> names = AllTimeZoneNames(); >+ for (auto index = names.size(); state.KeepRunning(); ++index) { >+ if (index == names.size()) { >+ index = 0; >+ } >+ if (index == 0) { >+ state.PauseTiming(); >+ cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); >+ state.ResumeTiming(); >+ } >+ benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadAllTimeZonesFirst); >+ >+void BM_Zone_LoadAllTimeZonesCached(benchmark::State& state) { >+ cctz::time_zone tz; >+ const std::vector<std::string> names = AllTimeZoneNames(); >+ for (const auto& name : names) { >+ cctz::load_time_zone(name, &tz); // prime cache >+ } >+ for (auto index = names.size(); state.KeepRunning(); ++index) { >+ if (index == names.size()) { >+ index = 0; >+ } >+ benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); >+ } >+} >+BENCHMARK(BM_Zone_LoadAllTimeZonesCached); >+ >+void BM_Zone_TimeZoneEqualityImplicit(benchmark::State& state) { >+ cctz::time_zone tz; // implicit UTC >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(tz == tz); >+ } >+} >+BENCHMARK(BM_Zone_TimeZoneEqualityImplicit); >+ >+void BM_Zone_TimeZoneEqualityExplicit(benchmark::State& state) { >+ cctz::time_zone tz = cctz::utc_time_zone(); // explicit UTC >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(tz == tz); >+ } >+} >+BENCHMARK(BM_Zone_TimeZoneEqualityExplicit); >+ >+void BM_Zone_UTCTimeZone(benchmark::State& state) { >+ cctz::time_zone tz; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::utc_time_zone()); >+ } >+} >+BENCHMARK(BM_Zone_UTCTimeZone); >+ >+// In each "ToDateTime" benchmark we switch between two instants >+// separated by at least one transition in order to defeat any >+// internal caching of previous results (e.g., see local_time_hint_). >+// >+// The "UTC" variants use UTC instead of the Google/local time zone. >+ >+void BM_Time_ToDateTime_CCTZ(benchmark::State& state) { >+ const cctz::time_zone tz = TestTimeZone(); >+ std::chrono::system_clock::time_point tp = >+ std::chrono::system_clock::from_time_t(1384569027); >+ std::chrono::system_clock::time_point tp2 = >+ std::chrono::system_clock::from_time_t(1418962578); >+ while (state.KeepRunning()) { >+ std::swap(tp, tp2); >+ tp += std::chrono::seconds(1); >+ benchmark::DoNotOptimize(cctz::convert(tp, tz)); >+ } >+} >+BENCHMARK(BM_Time_ToDateTime_CCTZ); >+ >+void BM_Time_ToDateTime_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ time_t t = 1384569027; >+ time_t t2 = 1418962578; >+ struct tm tm; >+ while (state.KeepRunning()) { >+ std::swap(t, t2); >+ t += 1; >+#if defined(_WIN32) || defined(_WIN64) >+ benchmark::DoNotOptimize(localtime_s(&tm, &t)); >+#else >+ benchmark::DoNotOptimize(localtime_r(&t, &tm)); >+#endif >+ } >+} >+BENCHMARK(BM_Time_ToDateTime_Libc); >+ >+void BM_Time_ToDateTimeUTC_CCTZ(benchmark::State& state) { >+ const cctz::time_zone tz = cctz::utc_time_zone(); >+ std::chrono::system_clock::time_point tp = >+ std::chrono::system_clock::from_time_t(1384569027); >+ while (state.KeepRunning()) { >+ tp += std::chrono::seconds(1); >+ benchmark::DoNotOptimize(cctz::convert(tp, tz)); >+ } >+} >+BENCHMARK(BM_Time_ToDateTimeUTC_CCTZ); >+ >+void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) { >+ time_t t = 1384569027; >+ struct tm tm; >+ while (state.KeepRunning()) { >+ t += 1; >+#if defined(_WIN32) || defined(_WIN64) >+ benchmark::DoNotOptimize(gmtime_s(&tm, &t)); >+#else >+ benchmark::DoNotOptimize(gmtime_r(&t, &tm)); >+#endif >+ } >+} >+BENCHMARK(BM_Time_ToDateTimeUTC_Libc); >+ >+// In each "FromDateTime" benchmark we switch between two YMDhms >+// values separated by at least one transition in order to defeat any >+// internal caching of previous results (e.g., see time_local_hint_). >+// >+// The "UTC" variants use UTC instead of the Google/local time zone. >+// The "Day0" variants require normalization of the day of month. >+ >+void BM_Time_FromDateTime_CCTZ(benchmark::State& state) { >+ const cctz::time_zone tz = TestTimeZone(); >+ int i = 0; >+ while (state.KeepRunning()) { >+ if ((i++ & 1) == 0) { >+ benchmark::DoNotOptimize( >+ cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); >+ } else { >+ benchmark::DoNotOptimize( >+ cctz::convert(cctz::civil_second(2013, 11, 15, 18, 30, 27), tz)); >+ } >+ } >+} >+BENCHMARK(BM_Time_FromDateTime_CCTZ); >+ >+void BM_Time_FromDateTime_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ int i = 0; >+ while (state.KeepRunning()) { >+ struct tm tm; >+ if ((i++ & 1) == 0) { >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 12 - 1; >+ tm.tm_mday = 18; >+ tm.tm_hour = 20; >+ tm.tm_min = 16; >+ tm.tm_sec = 18; >+ } else { >+ tm.tm_year = 2013 - 1900; >+ tm.tm_mon = 11 - 1; >+ tm.tm_mday = 15; >+ tm.tm_hour = 18; >+ tm.tm_min = 30; >+ tm.tm_sec = 27; >+ } >+ tm.tm_isdst = -1; >+ benchmark::DoNotOptimize(mktime(&tm)); >+ } >+} >+BENCHMARK(BM_Time_FromDateTime_Libc); >+ >+void BM_Time_FromDateTimeUTC_CCTZ(benchmark::State& state) { >+ const cctz::time_zone tz = cctz::utc_time_zone(); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize( >+ cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeUTC_CCTZ); >+ >+// There is no BM_Time_FromDateTimeUTC_Libc. >+ >+void BM_Time_FromDateTimeDay0_CCTZ(benchmark::State& state) { >+ const cctz::time_zone tz = TestTimeZone(); >+ int i = 0; >+ while (state.KeepRunning()) { >+ if ((i++ & 1) == 0) { >+ benchmark::DoNotOptimize( >+ cctz::convert(cctz::civil_second(2014, 12, 0, 20, 16, 18), tz)); >+ } else { >+ benchmark::DoNotOptimize( >+ cctz::convert(cctz::civil_second(2013, 11, 0, 18, 30, 27), tz)); >+ } >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeDay0_CCTZ); >+ >+void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ int i = 0; >+ while (state.KeepRunning()) { >+ struct tm tm; >+ if ((i++ & 1) == 0) { >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 12 - 1; >+ tm.tm_mday = 0; >+ tm.tm_hour = 20; >+ tm.tm_min = 16; >+ tm.tm_sec = 18; >+ } else { >+ tm.tm_year = 2013 - 1900; >+ tm.tm_mon = 11 - 1; >+ tm.tm_mday = 0; >+ tm.tm_hour = 18; >+ tm.tm_min = 30; >+ tm.tm_sec = 27; >+ } >+ tm.tm_isdst = -1; >+ benchmark::DoNotOptimize(mktime(&tm)); >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeDay0_Libc); >+ >+const char* const kFormats[] = { >+ RFC1123_full, // 0 >+ RFC1123_no_wday, // 1 >+ RFC3339_full, // 2 >+ RFC3339_sec, // 3 >+ "%Y-%m-%dT%H:%M:%S", // 4 >+ "%Y-%m-%d", // 5 >+}; >+const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); >+ >+void BM_Format_FormatTime(benchmark::State& state) { >+ const std::string fmt = kFormats[state.range(0)]; >+ state.SetLabel(fmt); >+ const cctz::time_zone tz = TestTimeZone(); >+ const std::chrono::system_clock::time_point tp = >+ cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + >+ std::chrono::microseconds(1); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::format(fmt, tp, tz)); >+ } >+} >+BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1); >+ >+void BM_Format_ParseTime(benchmark::State& state) { >+ const std::string fmt = kFormats[state.range(0)]; >+ state.SetLabel(fmt); >+ const cctz::time_zone tz = TestTimeZone(); >+ std::chrono::system_clock::time_point tp = >+ cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + >+ std::chrono::microseconds(1); >+ const std::string when = cctz::format(fmt, tp, tz); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(cctz::parse(fmt, when, tz, &tp)); >+ } >+} >+BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_detail.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_detail.cc >new file mode 100644 >index 00000000000..780d5c96e8b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_detail.cc >@@ -0,0 +1,90 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h" >+ >+#include <iomanip> >+#include <ostream> >+#include <sstream> >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+namespace detail { >+ >+// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss, >+// while omitting fields inferior to the type's alignment. For example, >+// civil_day is formatted only as YYYY-MM-DD. >+std::ostream& operator<<(std::ostream& os, const civil_year& y) { >+ std::stringstream ss; >+ ss << y.year(); // No padding. >+ return os << ss.str(); >+} >+std::ostream& operator<<(std::ostream& os, const civil_month& m) { >+ std::stringstream ss; >+ ss << civil_year(m) << '-'; >+ ss << std::setfill('0') << std::setw(2) << m.month(); >+ return os << ss.str(); >+} >+std::ostream& operator<<(std::ostream& os, const civil_day& d) { >+ std::stringstream ss; >+ ss << civil_month(d) << '-'; >+ ss << std::setfill('0') << std::setw(2) << d.day(); >+ return os << ss.str(); >+} >+std::ostream& operator<<(std::ostream& os, const civil_hour& h) { >+ std::stringstream ss; >+ ss << civil_day(h) << 'T'; >+ ss << std::setfill('0') << std::setw(2) << h.hour(); >+ return os << ss.str(); >+} >+std::ostream& operator<<(std::ostream& os, const civil_minute& m) { >+ std::stringstream ss; >+ ss << civil_hour(m) << ':'; >+ ss << std::setfill('0') << std::setw(2) << m.minute(); >+ return os << ss.str(); >+} >+std::ostream& operator<<(std::ostream& os, const civil_second& s) { >+ std::stringstream ss; >+ ss << civil_minute(s) << ':'; >+ ss << std::setfill('0') << std::setw(2) << s.second(); >+ return os << ss.str(); >+} >+ >+//////////////////////////////////////////////////////////////////////// >+ >+std::ostream& operator<<(std::ostream& os, weekday wd) { >+ switch (wd) { >+ case weekday::monday: >+ return os << "Monday"; >+ case weekday::tuesday: >+ return os << "Tuesday"; >+ case weekday::wednesday: >+ return os << "Wednesday"; >+ case weekday::thursday: >+ return os << "Thursday"; >+ case weekday::friday: >+ return os << "Friday"; >+ case weekday::saturday: >+ return os << "Saturday"; >+ case weekday::sunday: >+ return os << "Sunday"; >+ } >+ return os; // Should never get here, but -Wreturn-type may warn without this. >+} >+ >+} // namespace detail >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc >new file mode 100644 >index 00000000000..f6648c8f1f2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/civil_time_test.cc >@@ -0,0 +1,1049 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+ >+#include <iomanip> >+#include <limits> >+#include <sstream> >+#include <string> >+#include <type_traits> >+ >+#include "gtest/gtest.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+template <typename T> >+std::string Format(const T& t) { >+ std::stringstream ss; >+ ss << t; >+ return ss.str(); >+} >+ >+} // namespace >+ >+#if __cpp_constexpr >= 201304 || _MSC_VER >= 1910 >+// Construction constexpr tests >+ >+TEST(CivilTime, Normal) { >+ constexpr civil_second css(2016, 1, 28, 17, 14, 12); >+ static_assert(css.second() == 12, "Normal.second"); >+ constexpr civil_minute cmm(2016, 1, 28, 17, 14); >+ static_assert(cmm.minute() == 14, "Normal.minute"); >+ constexpr civil_hour chh(2016, 1, 28, 17); >+ static_assert(chh.hour() == 17, "Normal.hour"); >+ constexpr civil_day cd(2016, 1, 28); >+ static_assert(cd.day() == 28, "Normal.day"); >+ constexpr civil_month cm(2016, 1); >+ static_assert(cm.month() == 1, "Normal.month"); >+ constexpr civil_year cy(2016); >+ static_assert(cy.year() == 2016, "Normal.year"); >+} >+ >+TEST(CivilTime, Conversion) { >+ constexpr civil_year cy(2016); >+ static_assert(cy.year() == 2016, "Conversion.year"); >+ constexpr civil_month cm(cy); >+ static_assert(cm.month() == 1, "Conversion.month"); >+ constexpr civil_day cd(cm); >+ static_assert(cd.day() == 1, "Conversion.day"); >+ constexpr civil_hour chh(cd); >+ static_assert(chh.hour() == 0, "Conversion.hour"); >+ constexpr civil_minute cmm(chh); >+ static_assert(cmm.minute() == 0, "Conversion.minute"); >+ constexpr civil_second css(cmm); >+ static_assert(css.second() == 0, "Conversion.second"); >+} >+ >+// Normalization constexpr tests >+ >+TEST(CivilTime, Normalized) { >+ constexpr civil_second cs(2016, 1, 28, 17, 14, 12); >+ static_assert(cs.year() == 2016, "Normalized.year"); >+ static_assert(cs.month() == 1, "Normalized.month"); >+ static_assert(cs.day() == 28, "Normalized.day"); >+ static_assert(cs.hour() == 17, "Normalized.hour"); >+ static_assert(cs.minute() == 14, "Normalized.minute"); >+ static_assert(cs.second() == 12, "Normalized.second"); >+} >+ >+TEST(CivilTime, SecondOverflow) { >+ constexpr civil_second cs(2016, 1, 28, 17, 14, 121); >+ static_assert(cs.year() == 2016, "SecondOverflow.year"); >+ static_assert(cs.month() == 1, "SecondOverflow.month"); >+ static_assert(cs.day() == 28, "SecondOverflow.day"); >+ static_assert(cs.hour() == 17, "SecondOverflow.hour"); >+ static_assert(cs.minute() == 16, "SecondOverflow.minute"); >+ static_assert(cs.second() == 1, "SecondOverflow.second"); >+} >+ >+TEST(CivilTime, SecondUnderflow) { >+ constexpr civil_second cs(2016, 1, 28, 17, 14, -121); >+ static_assert(cs.year() == 2016, "SecondUnderflow.year"); >+ static_assert(cs.month() == 1, "SecondUnderflow.month"); >+ static_assert(cs.day() == 28, "SecondUnderflow.day"); >+ static_assert(cs.hour() == 17, "SecondUnderflow.hour"); >+ static_assert(cs.minute() == 11, "SecondUnderflow.minute"); >+ static_assert(cs.second() == 59, "SecondUnderflow.second"); >+} >+ >+TEST(CivilTime, MinuteOverflow) { >+ constexpr civil_second cs(2016, 1, 28, 17, 121, 12); >+ static_assert(cs.year() == 2016, "MinuteOverflow.year"); >+ static_assert(cs.month() == 1, "MinuteOverflow.month"); >+ static_assert(cs.day() == 28, "MinuteOverflow.day"); >+ static_assert(cs.hour() == 19, "MinuteOverflow.hour"); >+ static_assert(cs.minute() == 1, "MinuteOverflow.minute"); >+ static_assert(cs.second() == 12, "MinuteOverflow.second"); >+} >+ >+TEST(CivilTime, MinuteUnderflow) { >+ constexpr civil_second cs(2016, 1, 28, 17, -121, 12); >+ static_assert(cs.year() == 2016, "MinuteUnderflow.year"); >+ static_assert(cs.month() == 1, "MinuteUnderflow.month"); >+ static_assert(cs.day() == 28, "MinuteUnderflow.day"); >+ static_assert(cs.hour() == 14, "MinuteUnderflow.hour"); >+ static_assert(cs.minute() == 59, "MinuteUnderflow.minute"); >+ static_assert(cs.second() == 12, "MinuteUnderflow.second"); >+} >+ >+TEST(CivilTime, HourOverflow) { >+ constexpr civil_second cs(2016, 1, 28, 49, 14, 12); >+ static_assert(cs.year() == 2016, "HourOverflow.year"); >+ static_assert(cs.month() == 1, "HourOverflow.month"); >+ static_assert(cs.day() == 30, "HourOverflow.day"); >+ static_assert(cs.hour() == 1, "HourOverflow.hour"); >+ static_assert(cs.minute() == 14, "HourOverflow.minute"); >+ static_assert(cs.second() == 12, "HourOverflow.second"); >+} >+ >+TEST(CivilTime, HourUnderflow) { >+ constexpr civil_second cs(2016, 1, 28, -49, 14, 12); >+ static_assert(cs.year() == 2016, "HourUnderflow.year"); >+ static_assert(cs.month() == 1, "HourUnderflow.month"); >+ static_assert(cs.day() == 25, "HourUnderflow.day"); >+ static_assert(cs.hour() == 23, "HourUnderflow.hour"); >+ static_assert(cs.minute() == 14, "HourUnderflow.minute"); >+ static_assert(cs.second() == 12, "HourUnderflow.second"); >+} >+ >+TEST(CivilTime, MonthOverflow) { >+ constexpr civil_second cs(2016, 25, 28, 17, 14, 12); >+ static_assert(cs.year() == 2018, "MonthOverflow.year"); >+ static_assert(cs.month() == 1, "MonthOverflow.month"); >+ static_assert(cs.day() == 28, "MonthOverflow.day"); >+ static_assert(cs.hour() == 17, "MonthOverflow.hour"); >+ static_assert(cs.minute() == 14, "MonthOverflow.minute"); >+ static_assert(cs.second() == 12, "MonthOverflow.second"); >+} >+ >+TEST(CivilTime, MonthUnderflow) { >+ constexpr civil_second cs(2016, -25, 28, 17, 14, 12); >+ static_assert(cs.year() == 2013, "MonthUnderflow.year"); >+ static_assert(cs.month() == 11, "MonthUnderflow.month"); >+ static_assert(cs.day() == 28, "MonthUnderflow.day"); >+ static_assert(cs.hour() == 17, "MonthUnderflow.hour"); >+ static_assert(cs.minute() == 14, "MonthUnderflow.minute"); >+ static_assert(cs.second() == 12, "MonthUnderflow.second"); >+} >+ >+TEST(CivilTime, C4Overflow) { >+ constexpr civil_second cs(2016, 1, 292195, 17, 14, 12); >+ static_assert(cs.year() == 2816, "C4Overflow.year"); >+ static_assert(cs.month() == 1, "C4Overflow.month"); >+ static_assert(cs.day() == 1, "C4Overflow.day"); >+ static_assert(cs.hour() == 17, "C4Overflow.hour"); >+ static_assert(cs.minute() == 14, "C4Overflow.minute"); >+ static_assert(cs.second() == 12, "C4Overflow.second"); >+} >+ >+TEST(CivilTime, C4Underflow) { >+ constexpr civil_second cs(2016, 1, -292195, 17, 14, 12); >+ static_assert(cs.year() == 1215, "C4Underflow.year"); >+ static_assert(cs.month() == 12, "C4Underflow.month"); >+ static_assert(cs.day() == 30, "C4Underflow.day"); >+ static_assert(cs.hour() == 17, "C4Underflow.hour"); >+ static_assert(cs.minute() == 14, "C4Underflow.minute"); >+ static_assert(cs.second() == 12, "C4Underflow.second"); >+} >+ >+TEST(CivilTime, MixedNormalization) { >+ constexpr civil_second cs(2016, -42, 122, 99, -147, 4949); >+ static_assert(cs.year() == 2012, "MixedNormalization.year"); >+ static_assert(cs.month() == 10, "MixedNormalization.month"); >+ static_assert(cs.day() == 4, "MixedNormalization.day"); >+ static_assert(cs.hour() == 1, "MixedNormalization.hour"); >+ static_assert(cs.minute() == 55, "MixedNormalization.minute"); >+ static_assert(cs.second() == 29, "MixedNormalization.second"); >+} >+ >+// Relational constexpr tests >+ >+TEST(CivilTime, Less) { >+ constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); >+ constexpr civil_second cs2(2016, 1, 28, 17, 14, 13); >+ constexpr bool less = cs1 < cs2; >+ static_assert(less, "Less"); >+} >+ >+// Arithmetic constexpr tests >+ >+TEST(CivilTime, Addition) { >+ constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); >+ constexpr civil_second cs2 = cs1 + 50; >+ static_assert(cs2.year() == 2016, "Addition.year"); >+ static_assert(cs2.month() == 1, "Addition.month"); >+ static_assert(cs2.day() == 28, "Addition.day"); >+ static_assert(cs2.hour() == 17, "Addition.hour"); >+ static_assert(cs2.minute() == 15, "Addition.minute"); >+ static_assert(cs2.second() == 2, "Addition.second"); >+} >+ >+TEST(CivilTime, Subtraction) { >+ constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); >+ constexpr civil_second cs2 = cs1 - 50; >+ static_assert(cs2.year() == 2016, "Subtraction.year"); >+ static_assert(cs2.month() == 1, "Subtraction.month"); >+ static_assert(cs2.day() == 28, "Subtraction.day"); >+ static_assert(cs2.hour() == 17, "Subtraction.hour"); >+ static_assert(cs2.minute() == 13, "Subtraction.minute"); >+ static_assert(cs2.second() == 22, "Subtraction.second"); >+} >+ >+TEST(CivilTime, Difference) { >+ constexpr civil_day cd1(2016, 1, 28); >+ constexpr civil_day cd2(2015, 1, 28); >+ constexpr int diff = cd1 - cd2; >+ static_assert(diff == 365, "Difference"); >+} >+ >+// NOTE: Run this with --copt=-ftrapv to detect overflow problems. >+TEST(CivilTime, DifferenceWithHugeYear) { >+ { >+ constexpr civil_day d1(9223372036854775807, 1, 1); >+ constexpr civil_day d2(9223372036854775807, 12, 31); >+ static_assert(d2 - d1 == 364, "DifferenceWithHugeYear"); >+ } >+ { >+ constexpr civil_day d1(-9223372036854775807 - 1, 1, 1); >+ constexpr civil_day d2(-9223372036854775807 - 1, 12, 31); >+ static_assert(d2 - d1 == 365, "DifferenceWithHugeYear"); >+ } >+ { >+ // Check the limits of the return value at the end of the year range. >+ constexpr civil_day d1(9223372036854775807, 1, 1); >+ constexpr civil_day d2(9198119301927009252, 6, 6); >+ static_assert(d1 - d2 == 9223372036854775807, "DifferenceWithHugeYear"); >+ static_assert((d2 - 1) - d1 == -9223372036854775807 - 1, >+ "DifferenceWithHugeYear"); >+ } >+ { >+ // Check the limits of the return value at the start of the year range. >+ constexpr civil_day d1(-9223372036854775807 - 1, 1, 1); >+ constexpr civil_day d2(-9198119301927009254, 7, 28); >+ static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear"); >+ static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1, >+ "DifferenceWithHugeYear"); >+ } >+ { >+ // Check the limits of the return value from either side of year 0. >+ constexpr civil_day d1(-12626367463883278, 9, 3); >+ constexpr civil_day d2(12626367463883277, 3, 28); >+ static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear"); >+ static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1, >+ "DifferenceWithHugeYear"); >+ } >+} >+ >+// NOTE: Run this with --copt=-ftrapv to detect overflow problems. >+TEST(CivilTime, DifferenceNoIntermediateOverflow) { >+ { >+ // The difference up to the minute field would be below the minimum >+ // diff_t, but the 52 extra seconds brings us back to the minimum. >+ constexpr civil_second s1(-292277022657, 1, 27, 8, 29 - 1, 52); >+ constexpr civil_second s2(1970, 1, 1, 0, 0 - 1, 0); >+ static_assert(s1 - s2 == -9223372036854775807 - 1, >+ "DifferenceNoIntermediateOverflow"); >+ } >+ { >+ // The difference up to the minute field would be above the maximum >+ // diff_t, but the -53 extra seconds brings us back to the maximum. >+ constexpr civil_second s1(292277026596, 12, 4, 15, 30, 7 - 7); >+ constexpr civil_second s2(1970, 1, 1, 0, 0, 0 - 7); >+ static_assert(s1 - s2 == 9223372036854775807, >+ "DifferenceNoIntermediateOverflow"); >+ } >+} >+ >+// Helper constexpr tests >+ >+TEST(CivilTime, WeekDay) { >+ constexpr civil_day cd(2016, 1, 28); >+ constexpr weekday wd = get_weekday(cd); >+ static_assert(wd == weekday::thursday, "Weekday"); >+} >+ >+TEST(CivilTime, NextWeekDay) { >+ constexpr civil_day cd(2016, 1, 28); >+ constexpr civil_day next = next_weekday(cd, weekday::thursday); >+ static_assert(next.year() == 2016, "NextWeekDay.year"); >+ static_assert(next.month() == 2, "NextWeekDay.month"); >+ static_assert(next.day() == 4, "NextWeekDay.day"); >+} >+ >+TEST(CivilTime, PrevWeekDay) { >+ constexpr civil_day cd(2016, 1, 28); >+ constexpr civil_day prev = prev_weekday(cd, weekday::thursday); >+ static_assert(prev.year() == 2016, "PrevWeekDay.year"); >+ static_assert(prev.month() == 1, "PrevWeekDay.month"); >+ static_assert(prev.day() == 21, "PrevWeekDay.day"); >+} >+ >+TEST(CivilTime, YearDay) { >+ constexpr civil_day cd(2016, 1, 28); >+ constexpr int yd = get_yearday(cd); >+ static_assert(yd == 28, "YearDay"); >+} >+#endif // __cpp_constexpr >= 201304 || _MSC_VER >= 1910 >+ >+// The remaining tests do not use constexpr. >+ >+TEST(CivilTime, DefaultConstruction) { >+ civil_second ss; >+ EXPECT_EQ("1970-01-01T00:00:00", Format(ss)); >+ >+ civil_minute mm; >+ EXPECT_EQ("1970-01-01T00:00", Format(mm)); >+ >+ civil_hour hh; >+ EXPECT_EQ("1970-01-01T00", Format(hh)); >+ >+ civil_day d; >+ EXPECT_EQ("1970-01-01", Format(d)); >+ >+ civil_month m; >+ EXPECT_EQ("1970-01", Format(m)); >+ >+ civil_year y; >+ EXPECT_EQ("1970", Format(y)); >+} >+ >+TEST(CivilTime, StructMember) { >+ struct S { >+ civil_day day; >+ }; >+ S s = {}; >+ EXPECT_EQ(civil_day{}, s.day); >+} >+ >+TEST(CivilTime, FieldsConstruction) { >+ EXPECT_EQ("2015-01-02T03:04:05", Format(civil_second(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015-01-02T03:04:00", Format(civil_second(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015-01-02T03:00:00", Format(civil_second(2015, 1, 2, 3))); >+ EXPECT_EQ("2015-01-02T00:00:00", Format(civil_second(2015, 1, 2))); >+ EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015, 1))); >+ EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015))); >+ >+ EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015-01-02T03:00", Format(civil_minute(2015, 1, 2, 3))); >+ EXPECT_EQ("2015-01-02T00:00", Format(civil_minute(2015, 1, 2))); >+ EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015, 1))); >+ EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015))); >+ >+ EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3))); >+ EXPECT_EQ("2015-01-02T00", Format(civil_hour(2015, 1, 2))); >+ EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015, 1))); >+ EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015))); >+ >+ EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3))); >+ EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2))); >+ EXPECT_EQ("2015-01-01", Format(civil_day(2015, 1))); >+ EXPECT_EQ("2015-01-01", Format(civil_day(2015))); >+ >+ EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3))); >+ EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2))); >+ EXPECT_EQ("2015-01", Format(civil_month(2015, 1))); >+ EXPECT_EQ("2015-01", Format(civil_month(2015))); >+ >+ EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4, 5))); >+ EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4))); >+ EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3))); >+ EXPECT_EQ("2015", Format(civil_year(2015, 1, 2))); >+ EXPECT_EQ("2015", Format(civil_year(2015, 1))); >+ EXPECT_EQ("2015", Format(civil_year(2015))); >+} >+ >+TEST(CivilTime, FieldsConstructionLimits) { >+ const int kIntMax = std::numeric_limits<int>::max(); >+ EXPECT_EQ("2038-01-19T03:14:07", >+ Format(civil_second(1970, 1, 1, 0, 0, kIntMax))); >+ EXPECT_EQ("6121-02-11T05:21:07", >+ Format(civil_second(1970, 1, 1, 0, kIntMax, kIntMax))); >+ EXPECT_EQ("251104-11-20T12:21:07", >+ Format(civil_second(1970, 1, 1, kIntMax, kIntMax, kIntMax))); >+ EXPECT_EQ("6130715-05-30T12:21:07", >+ Format(civil_second(1970, 1, kIntMax, kIntMax, kIntMax, kIntMax))); >+ EXPECT_EQ( >+ "185087685-11-26T12:21:07", >+ Format(civil_second(1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax))); >+ >+ const int kIntMin = std::numeric_limits<int>::min(); >+ EXPECT_EQ("1901-12-13T20:45:52", >+ Format(civil_second(1970, 1, 1, 0, 0, kIntMin))); >+ EXPECT_EQ("-2182-11-20T18:37:52", >+ Format(civil_second(1970, 1, 1, 0, kIntMin, kIntMin))); >+ EXPECT_EQ("-247165-02-11T10:37:52", >+ Format(civil_second(1970, 1, 1, kIntMin, kIntMin, kIntMin))); >+ EXPECT_EQ("-6126776-08-01T10:37:52", >+ Format(civil_second(1970, 1, kIntMin, kIntMin, kIntMin, kIntMin))); >+ EXPECT_EQ( >+ "-185083747-10-31T10:37:52", >+ Format(civil_second(1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin))); >+} >+ >+TEST(CivilTime, ImplicitCrossAlignment) { >+ civil_year year(2015); >+ civil_month month = year; >+ civil_day day = month; >+ civil_hour hour = day; >+ civil_minute minute = hour; >+ civil_second second = minute; >+ >+ second = year; >+ EXPECT_EQ(second, year); >+ second = month; >+ EXPECT_EQ(second, month); >+ second = day; >+ EXPECT_EQ(second, day); >+ second = hour; >+ EXPECT_EQ(second, hour); >+ second = minute; >+ EXPECT_EQ(second, minute); >+ >+ minute = year; >+ EXPECT_EQ(minute, year); >+ minute = month; >+ EXPECT_EQ(minute, month); >+ minute = day; >+ EXPECT_EQ(minute, day); >+ minute = hour; >+ EXPECT_EQ(minute, hour); >+ >+ hour = year; >+ EXPECT_EQ(hour, year); >+ hour = month; >+ EXPECT_EQ(hour, month); >+ hour = day; >+ EXPECT_EQ(hour, day); >+ >+ day = year; >+ EXPECT_EQ(day, year); >+ day = month; >+ EXPECT_EQ(day, month); >+ >+ month = year; >+ EXPECT_EQ(month, year); >+ >+ // Ensures unsafe conversions are not allowed. >+ EXPECT_FALSE((std::is_convertible<civil_second, civil_minute>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_second, civil_hour>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_second, civil_day>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_second, civil_month>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_second, civil_year>::value)); >+ >+ EXPECT_FALSE((std::is_convertible<civil_minute, civil_hour>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_minute, civil_day>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_minute, civil_month>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_minute, civil_year>::value)); >+ >+ EXPECT_FALSE((std::is_convertible<civil_hour, civil_day>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_hour, civil_month>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_hour, civil_year>::value)); >+ >+ EXPECT_FALSE((std::is_convertible<civil_day, civil_month>::value)); >+ EXPECT_FALSE((std::is_convertible<civil_day, civil_year>::value)); >+ >+ EXPECT_FALSE((std::is_convertible<civil_month, civil_year>::value)); >+} >+ >+TEST(CivilTime, ExplicitCrossAlignment) { >+ // >+ // Assign from smaller units -> larger units >+ // >+ >+ civil_second second(2015, 1, 2, 3, 4, 5); >+ EXPECT_EQ("2015-01-02T03:04:05", Format(second)); >+ >+ civil_minute minute(second); >+ EXPECT_EQ("2015-01-02T03:04", Format(minute)); >+ >+ civil_hour hour(minute); >+ EXPECT_EQ("2015-01-02T03", Format(hour)); >+ >+ civil_day day(hour); >+ EXPECT_EQ("2015-01-02", Format(day)); >+ >+ civil_month month(day); >+ EXPECT_EQ("2015-01", Format(month)); >+ >+ civil_year year(month); >+ EXPECT_EQ("2015", Format(year)); >+ >+ // >+ // Now assign from larger units -> smaller units >+ // >+ >+ month = civil_month(year); >+ EXPECT_EQ("2015-01", Format(month)); >+ >+ day = civil_day(month); >+ EXPECT_EQ("2015-01-01", Format(day)); >+ >+ hour = civil_hour(day); >+ EXPECT_EQ("2015-01-01T00", Format(hour)); >+ >+ minute = civil_minute(hour); >+ EXPECT_EQ("2015-01-01T00:00", Format(minute)); >+ >+ second = civil_second(minute); >+ EXPECT_EQ("2015-01-01T00:00:00", Format(second)); >+} >+ >+// Metafunction to test whether difference is allowed between two types. >+template <typename T1, typename T2> >+struct HasDifference { >+ template <typename U1, typename U2> >+ static std::false_type test(...); >+ template <typename U1, typename U2> >+ static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>())); >+ static constexpr bool value = decltype(test<T1, T2>(0))::value; >+}; >+ >+TEST(CivilTime, DisallowCrossAlignedDifference) { >+ // Difference is allowed between types with the same alignment. >+ static_assert(HasDifference<civil_second, civil_second>::value, ""); >+ static_assert(HasDifference<civil_minute, civil_minute>::value, ""); >+ static_assert(HasDifference<civil_hour, civil_hour>::value, ""); >+ static_assert(HasDifference<civil_day, civil_day>::value, ""); >+ static_assert(HasDifference<civil_month, civil_month>::value, ""); >+ static_assert(HasDifference<civil_year, civil_year>::value, ""); >+ >+ // Difference is disallowed between types with different alignments. >+ static_assert(!HasDifference<civil_second, civil_minute>::value, ""); >+ static_assert(!HasDifference<civil_second, civil_hour>::value, ""); >+ static_assert(!HasDifference<civil_second, civil_day>::value, ""); >+ static_assert(!HasDifference<civil_second, civil_month>::value, ""); >+ static_assert(!HasDifference<civil_second, civil_year>::value, ""); >+ >+ static_assert(!HasDifference<civil_minute, civil_hour>::value, ""); >+ static_assert(!HasDifference<civil_minute, civil_day>::value, ""); >+ static_assert(!HasDifference<civil_minute, civil_month>::value, ""); >+ static_assert(!HasDifference<civil_minute, civil_year>::value, ""); >+ >+ static_assert(!HasDifference<civil_hour, civil_day>::value, ""); >+ static_assert(!HasDifference<civil_hour, civil_month>::value, ""); >+ static_assert(!HasDifference<civil_hour, civil_year>::value, ""); >+ >+ static_assert(!HasDifference<civil_day, civil_month>::value, ""); >+ static_assert(!HasDifference<civil_day, civil_year>::value, ""); >+ >+ static_assert(!HasDifference<civil_month, civil_year>::value, ""); >+} >+ >+TEST(CivilTime, ValueSemantics) { >+ const civil_hour a(2015, 1, 2, 3); >+ const civil_hour b = a; >+ const civil_hour c(b); >+ civil_hour d; >+ d = c; >+ EXPECT_EQ("2015-01-02T03", Format(d)); >+} >+ >+TEST(CivilTime, Relational) { >+ // Tests that the alignment unit is ignored in comparison. >+ const civil_year year(2014); >+ const civil_month month(year); >+ EXPECT_EQ(year, month); >+ >+#define TEST_RELATIONAL(OLDER, YOUNGER) \ >+ do { \ >+ EXPECT_FALSE(OLDER < OLDER); \ >+ EXPECT_FALSE(OLDER > OLDER); \ >+ EXPECT_TRUE(OLDER >= OLDER); \ >+ EXPECT_TRUE(OLDER <= OLDER); \ >+ EXPECT_FALSE(YOUNGER < YOUNGER); \ >+ EXPECT_FALSE(YOUNGER > YOUNGER); \ >+ EXPECT_TRUE(YOUNGER >= YOUNGER); \ >+ EXPECT_TRUE(YOUNGER <= YOUNGER); \ >+ EXPECT_EQ(OLDER, OLDER); \ >+ EXPECT_NE(OLDER, YOUNGER); \ >+ EXPECT_LT(OLDER, YOUNGER); \ >+ EXPECT_LE(OLDER, YOUNGER); \ >+ EXPECT_GT(YOUNGER, OLDER); \ >+ EXPECT_GE(YOUNGER, OLDER); \ >+ } while (0) >+ >+ // Alignment is ignored in comparison (verified above), so kSecond is used >+ // to test comparison in all field positions. >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), >+ civil_second(2015, 1, 1, 0, 0, 0)); >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), >+ civil_second(2014, 2, 1, 0, 0, 0)); >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), >+ civil_second(2014, 1, 2, 0, 0, 0)); >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), >+ civil_second(2014, 1, 1, 1, 0, 0)); >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 0, 0), >+ civil_second(2014, 1, 1, 1, 1, 0)); >+ TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0), >+ civil_second(2014, 1, 1, 1, 1, 1)); >+ >+ // Tests the relational operators of two different CivilTime types. >+ TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1)); >+ TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2)); >+ >+#undef TEST_RELATIONAL >+} >+ >+TEST(CivilTime, Arithmetic) { >+ civil_second second(2015, 1, 2, 3, 4, 5); >+ EXPECT_EQ("2015-01-02T03:04:06", Format(second += 1)); >+ EXPECT_EQ("2015-01-02T03:04:07", Format(second + 1)); >+ EXPECT_EQ("2015-01-02T03:04:08", Format(2 + second)); >+ EXPECT_EQ("2015-01-02T03:04:05", Format(second - 1)); >+ EXPECT_EQ("2015-01-02T03:04:05", Format(second -= 1)); >+ EXPECT_EQ("2015-01-02T03:04:05", Format(second++)); >+ EXPECT_EQ("2015-01-02T03:04:07", Format(++second)); >+ EXPECT_EQ("2015-01-02T03:04:07", Format(second--)); >+ EXPECT_EQ("2015-01-02T03:04:05", Format(--second)); >+ >+ civil_minute minute(2015, 1, 2, 3, 4); >+ EXPECT_EQ("2015-01-02T03:05", Format(minute += 1)); >+ EXPECT_EQ("2015-01-02T03:06", Format(minute + 1)); >+ EXPECT_EQ("2015-01-02T03:07", Format(2 + minute)); >+ EXPECT_EQ("2015-01-02T03:04", Format(minute - 1)); >+ EXPECT_EQ("2015-01-02T03:04", Format(minute -= 1)); >+ EXPECT_EQ("2015-01-02T03:04", Format(minute++)); >+ EXPECT_EQ("2015-01-02T03:06", Format(++minute)); >+ EXPECT_EQ("2015-01-02T03:06", Format(minute--)); >+ EXPECT_EQ("2015-01-02T03:04", Format(--minute)); >+ >+ civil_hour hour(2015, 1, 2, 3); >+ EXPECT_EQ("2015-01-02T04", Format(hour += 1)); >+ EXPECT_EQ("2015-01-02T05", Format(hour + 1)); >+ EXPECT_EQ("2015-01-02T06", Format(2 + hour)); >+ EXPECT_EQ("2015-01-02T03", Format(hour - 1)); >+ EXPECT_EQ("2015-01-02T03", Format(hour -= 1)); >+ EXPECT_EQ("2015-01-02T03", Format(hour++)); >+ EXPECT_EQ("2015-01-02T05", Format(++hour)); >+ EXPECT_EQ("2015-01-02T05", Format(hour--)); >+ EXPECT_EQ("2015-01-02T03", Format(--hour)); >+ >+ civil_day day(2015, 1, 2); >+ EXPECT_EQ("2015-01-03", Format(day += 1)); >+ EXPECT_EQ("2015-01-04", Format(day + 1)); >+ EXPECT_EQ("2015-01-05", Format(2 + day)); >+ EXPECT_EQ("2015-01-02", Format(day - 1)); >+ EXPECT_EQ("2015-01-02", Format(day -= 1)); >+ EXPECT_EQ("2015-01-02", Format(day++)); >+ EXPECT_EQ("2015-01-04", Format(++day)); >+ EXPECT_EQ("2015-01-04", Format(day--)); >+ EXPECT_EQ("2015-01-02", Format(--day)); >+ >+ civil_month month(2015, 1); >+ EXPECT_EQ("2015-02", Format(month += 1)); >+ EXPECT_EQ("2015-03", Format(month + 1)); >+ EXPECT_EQ("2015-04", Format(2 + month)); >+ EXPECT_EQ("2015-01", Format(month - 1)); >+ EXPECT_EQ("2015-01", Format(month -= 1)); >+ EXPECT_EQ("2015-01", Format(month++)); >+ EXPECT_EQ("2015-03", Format(++month)); >+ EXPECT_EQ("2015-03", Format(month--)); >+ EXPECT_EQ("2015-01", Format(--month)); >+ >+ civil_year year(2015); >+ EXPECT_EQ("2016", Format(year += 1)); >+ EXPECT_EQ("2017", Format(year + 1)); >+ EXPECT_EQ("2018", Format(2 + year)); >+ EXPECT_EQ("2015", Format(year - 1)); >+ EXPECT_EQ("2015", Format(year -= 1)); >+ EXPECT_EQ("2015", Format(year++)); >+ EXPECT_EQ("2017", Format(++year)); >+ EXPECT_EQ("2017", Format(year--)); >+ EXPECT_EQ("2015", Format(--year)); >+} >+ >+TEST(CivilTime, ArithmeticLimits) { >+ const int kIntMax = std::numeric_limits<int>::max(); >+ const int kIntMin = std::numeric_limits<int>::min(); >+ >+ civil_second second(1970, 1, 1, 0, 0, 0); >+ second += kIntMax; >+ EXPECT_EQ("2038-01-19T03:14:07", Format(second)); >+ second -= kIntMax; >+ EXPECT_EQ("1970-01-01T00:00:00", Format(second)); >+ second += kIntMin; >+ EXPECT_EQ("1901-12-13T20:45:52", Format(second)); >+ second -= kIntMin; >+ EXPECT_EQ("1970-01-01T00:00:00", Format(second)); >+ >+ civil_minute minute(1970, 1, 1, 0, 0); >+ minute += kIntMax; >+ EXPECT_EQ("6053-01-23T02:07", Format(minute)); >+ minute -= kIntMax; >+ EXPECT_EQ("1970-01-01T00:00", Format(minute)); >+ minute += kIntMin; >+ EXPECT_EQ("-2114-12-08T21:52", Format(minute)); >+ minute -= kIntMin; >+ EXPECT_EQ("1970-01-01T00:00", Format(minute)); >+ >+ civil_hour hour(1970, 1, 1, 0); >+ hour += kIntMax; >+ EXPECT_EQ("246953-10-09T07", Format(hour)); >+ hour -= kIntMax; >+ EXPECT_EQ("1970-01-01T00", Format(hour)); >+ hour += kIntMin; >+ EXPECT_EQ("-243014-03-24T16", Format(hour)); >+ hour -= kIntMin; >+ EXPECT_EQ("1970-01-01T00", Format(hour)); >+ >+ civil_day day(1970, 1, 1); >+ day += kIntMax; >+ EXPECT_EQ("5881580-07-11", Format(day)); >+ day -= kIntMax; >+ EXPECT_EQ("1970-01-01", Format(day)); >+ day += kIntMin; >+ EXPECT_EQ("-5877641-06-23", Format(day)); >+ day -= kIntMin; >+ EXPECT_EQ("1970-01-01", Format(day)); >+ >+ civil_month month(1970, 1); >+ month += kIntMax; >+ EXPECT_EQ("178958940-08", Format(month)); >+ month -= kIntMax; >+ EXPECT_EQ("1970-01", Format(month)); >+ month += kIntMin; >+ EXPECT_EQ("-178955001-05", Format(month)); >+ month -= kIntMin; >+ EXPECT_EQ("1970-01", Format(month)); >+ >+ civil_year year(0); >+ year += kIntMax; >+ EXPECT_EQ("2147483647", Format(year)); >+ year -= kIntMax; >+ EXPECT_EQ("0", Format(year)); >+ year += kIntMin; >+ EXPECT_EQ("-2147483648", Format(year)); >+ year -= kIntMin; >+ EXPECT_EQ("0", Format(year)); >+} >+ >+TEST(CivilTime, ArithmeticDifference) { >+ civil_second second(2015, 1, 2, 3, 4, 5); >+ EXPECT_EQ(0, second - second); >+ EXPECT_EQ(10, (second + 10) - second); >+ EXPECT_EQ(-10, (second - 10) - second); >+ >+ civil_minute minute(2015, 1, 2, 3, 4); >+ EXPECT_EQ(0, minute - minute); >+ EXPECT_EQ(10, (minute + 10) - minute); >+ EXPECT_EQ(-10, (minute - 10) - minute); >+ >+ civil_hour hour(2015, 1, 2, 3); >+ EXPECT_EQ(0, hour - hour); >+ EXPECT_EQ(10, (hour + 10) - hour); >+ EXPECT_EQ(-10, (hour - 10) - hour); >+ >+ civil_day day(2015, 1, 2); >+ EXPECT_EQ(0, day - day); >+ EXPECT_EQ(10, (day + 10) - day); >+ EXPECT_EQ(-10, (day - 10) - day); >+ >+ civil_month month(2015, 1); >+ EXPECT_EQ(0, month - month); >+ EXPECT_EQ(10, (month + 10) - month); >+ EXPECT_EQ(-10, (month - 10) - month); >+ >+ civil_year year(2015); >+ EXPECT_EQ(0, year - year); >+ EXPECT_EQ(10, (year + 10) - year); >+ EXPECT_EQ(-10, (year - 10) - year); >+} >+ >+TEST(CivilTime, DifferenceLimits) { >+ const int kIntMax = std::numeric_limits<int>::max(); >+ const int kIntMin = std::numeric_limits<int>::min(); >+ >+ // Check day arithmetic at the end of the year range. >+ const civil_day max_day(kIntMax, 12, 31); >+ EXPECT_EQ(1, max_day - (max_day - 1)); >+ EXPECT_EQ(-1, (max_day - 1) - max_day); >+ >+ // Check day arithmetic at the end of the year range. >+ const civil_day min_day(kIntMin, 1, 1); >+ EXPECT_EQ(1, (min_day + 1) - min_day); >+ EXPECT_EQ(-1, min_day - (min_day + 1)); >+ >+ // Check the limits of the return value. >+ const civil_day d1(1970, 1, 1); >+ const civil_day d2(5881580, 7, 11); >+ EXPECT_EQ(kIntMax, d2 - d1); >+ EXPECT_EQ(kIntMin, d1 - (d2 + 1)); >+} >+ >+TEST(CivilTime, Properties) { >+ civil_second ss(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, ss.year()); >+ EXPECT_EQ(2, ss.month()); >+ EXPECT_EQ(3, ss.day()); >+ EXPECT_EQ(4, ss.hour()); >+ EXPECT_EQ(5, ss.minute()); >+ EXPECT_EQ(6, ss.second()); >+ >+ civil_minute mm(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, mm.year()); >+ EXPECT_EQ(2, mm.month()); >+ EXPECT_EQ(3, mm.day()); >+ EXPECT_EQ(4, mm.hour()); >+ EXPECT_EQ(5, mm.minute()); >+ EXPECT_EQ(0, mm.second()); >+ >+ civil_hour hh(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, hh.year()); >+ EXPECT_EQ(2, hh.month()); >+ EXPECT_EQ(3, hh.day()); >+ EXPECT_EQ(4, hh.hour()); >+ EXPECT_EQ(0, hh.minute()); >+ EXPECT_EQ(0, hh.second()); >+ >+ civil_day d(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, d.year()); >+ EXPECT_EQ(2, d.month()); >+ EXPECT_EQ(3, d.day()); >+ EXPECT_EQ(0, d.hour()); >+ EXPECT_EQ(0, d.minute()); >+ EXPECT_EQ(0, d.second()); >+ EXPECT_EQ(weekday::tuesday, get_weekday(d)); >+ EXPECT_EQ(34, get_yearday(d)); >+ >+ civil_month m(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, m.year()); >+ EXPECT_EQ(2, m.month()); >+ EXPECT_EQ(1, m.day()); >+ EXPECT_EQ(0, m.hour()); >+ EXPECT_EQ(0, m.minute()); >+ EXPECT_EQ(0, m.second()); >+ >+ civil_year y(2015, 2, 3, 4, 5, 6); >+ EXPECT_EQ(2015, y.year()); >+ EXPECT_EQ(1, y.month()); >+ EXPECT_EQ(1, y.day()); >+ EXPECT_EQ(0, y.hour()); >+ EXPECT_EQ(0, y.minute()); >+ EXPECT_EQ(0, y.second()); >+} >+ >+TEST(CivilTime, OutputStream) { >+ // Tests formatting of civil_year, which does not pad. >+ EXPECT_EQ("2016", Format(civil_year(2016))); >+ EXPECT_EQ("123", Format(civil_year(123))); >+ EXPECT_EQ("0", Format(civil_year(0))); >+ EXPECT_EQ("-1", Format(civil_year(-1))); >+ >+ // Tests formatting of sub-year types, which pad to 2 digits >+ EXPECT_EQ("2016-02", Format(civil_month(2016, 2))); >+ EXPECT_EQ("2016-02-03", Format(civil_day(2016, 2, 3))); >+ EXPECT_EQ("2016-02-03T04", Format(civil_hour(2016, 2, 3, 4))); >+ EXPECT_EQ("2016-02-03T04:05", Format(civil_minute(2016, 2, 3, 4, 5))); >+ EXPECT_EQ("2016-02-03T04:05:06", Format(civil_second(2016, 2, 3, 4, 5, 6))); >+ >+ // Tests formatting of weekday. >+ EXPECT_EQ("Monday", Format(weekday::monday)); >+ EXPECT_EQ("Tuesday", Format(weekday::tuesday)); >+ EXPECT_EQ("Wednesday", Format(weekday::wednesday)); >+ EXPECT_EQ("Thursday", Format(weekday::thursday)); >+ EXPECT_EQ("Friday", Format(weekday::friday)); >+ EXPECT_EQ("Saturday", Format(weekday::saturday)); >+ EXPECT_EQ("Sunday", Format(weekday::sunday)); >+} >+ >+TEST(CivilTime, OutputStreamLeftFillWidth) { >+ civil_second cs(2016, 2, 3, 4, 5, 6); >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_year(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016.................X..", ss.str()); >+ } >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_month(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016-02..............X..", ss.str()); >+ } >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_day(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016-02-03...........X..", ss.str()); >+ } >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_hour(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016-02-03T04........X..", ss.str()); >+ } >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_minute(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str()); >+ } >+ { >+ std::stringstream ss; >+ ss << std::left << std::setfill('.'); >+ ss << std::setw(3) << 'X'; >+ ss << std::setw(21) << civil_second(cs); >+ ss << std::setw(3) << 'X'; >+ EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str()); >+ } >+} >+ >+TEST(CivilTime, NextPrevWeekday) { >+ // Jan 1, 1970 was a Thursday. >+ const civil_day thursday(1970, 1, 1); >+ EXPECT_EQ(weekday::thursday, get_weekday(thursday)); >+ >+ // Thursday -> Thursday >+ civil_day d = next_weekday(thursday, weekday::thursday); >+ EXPECT_EQ(7, d - thursday) << Format(d); >+ EXPECT_EQ(d - 14, prev_weekday(thursday, weekday::thursday)); >+ >+ // Thursday -> Friday >+ d = next_weekday(thursday, weekday::friday); >+ EXPECT_EQ(1, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::friday)); >+ >+ // Thursday -> Saturday >+ d = next_weekday(thursday, weekday::saturday); >+ EXPECT_EQ(2, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::saturday)); >+ >+ // Thursday -> Sunday >+ d = next_weekday(thursday, weekday::sunday); >+ EXPECT_EQ(3, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::sunday)); >+ >+ // Thursday -> Monday >+ d = next_weekday(thursday, weekday::monday); >+ EXPECT_EQ(4, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::monday)); >+ >+ // Thursday -> Tuesday >+ d = next_weekday(thursday, weekday::tuesday); >+ EXPECT_EQ(5, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::tuesday)); >+ >+ // Thursday -> Wednesday >+ d = next_weekday(thursday, weekday::wednesday); >+ EXPECT_EQ(6, d - thursday) << Format(d); >+ EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday)); >+} >+ >+TEST(CivilTime, NormalizeWithHugeYear) { >+ civil_month c(9223372036854775807, 1); >+ EXPECT_EQ("9223372036854775807-01", Format(c)); >+ c = c - 1; // Causes normalization >+ EXPECT_EQ("9223372036854775806-12", Format(c)); >+ >+ c = civil_month(-9223372036854775807 - 1, 1); >+ EXPECT_EQ("-9223372036854775808-01", Format(c)); >+ c = c + 12; // Causes normalization >+ EXPECT_EQ("-9223372036854775807-01", Format(c)); >+} >+ >+TEST(CivilTime, LeapYears) { >+ // Test data for leap years. >+ const struct { >+ int year; >+ int days; >+ struct { >+ int month; >+ int day; >+ } leap_day; // The date of the day after Feb 28. >+ } kLeapYearTable[]{ >+ {1900, 365, {3, 1}}, >+ {1999, 365, {3, 1}}, >+ {2000, 366, {2, 29}}, // leap year >+ {2001, 365, {3, 1}}, >+ {2002, 365, {3, 1}}, >+ {2003, 365, {3, 1}}, >+ {2004, 366, {2, 29}}, // leap year >+ {2005, 365, {3, 1}}, >+ {2006, 365, {3, 1}}, >+ {2007, 365, {3, 1}}, >+ {2008, 366, {2, 29}}, // leap year >+ {2009, 365, {3, 1}}, >+ {2100, 365, {3, 1}}, >+ }; >+ >+ for (const auto& e : kLeapYearTable) { >+ // Tests incrementing through the leap day. >+ const civil_day feb28(e.year, 2, 28); >+ const civil_day next_day = feb28 + 1; >+ EXPECT_EQ(e.leap_day.month, next_day.month()); >+ EXPECT_EQ(e.leap_day.day, next_day.day()); >+ >+ // Tests difference in days of leap years. >+ const civil_year year(feb28); >+ const civil_year next_year = year + 1; >+ EXPECT_EQ(e.days, civil_day(next_year) - civil_day(year)); >+ } >+} >+ >+TEST(CivilTime, FirstThursdayInMonth) { >+ const civil_day nov1(2014, 11, 1); >+ const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7; >+ EXPECT_EQ("2014-11-06", Format(thursday)); >+ >+ // Bonus: Date of Thanksgiving in the United States >+ // Rule: Fourth Thursday of November >+ const civil_day thanksgiving = thursday + 7 * 3; >+ EXPECT_EQ("2014-11-27", Format(thanksgiving)); >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc >new file mode 100644 >index 00000000000..598b08fde42 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.cc >@@ -0,0 +1,123 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "time_zone_fixed.h" >+ >+#include <algorithm> >+#include <chrono> >+#include <cstdio> >+#include <cstring> >+#include <string> >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+// The prefix used for the internal names of fixed-offset zones. >+const char kFixedOffsetPrefix[] = "Fixed/UTC"; >+ >+int Parse02d(const char* p) { >+ static const char kDigits[] = "0123456789"; >+ if (const char* ap = std::strchr(kDigits, *p)) { >+ int v = static_cast<int>(ap - kDigits); >+ if (const char* bp = std::strchr(kDigits, *++p)) { >+ return (v * 10) + static_cast<int>(bp - kDigits); >+ } >+ } >+ return -1; >+} >+ >+} // namespace >+ >+bool FixedOffsetFromName(const std::string& name, seconds* offset) { >+ if (name.compare(0, std::string::npos, "UTC", 3) == 0) { >+ *offset = seconds::zero(); >+ return true; >+ } >+ >+ const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1; >+ const char* const ep = kFixedOffsetPrefix + prefix_len; >+ if (name.size() != prefix_len + 9) // <prefix>+99:99:99 >+ return false; >+ if (!std::equal(kFixedOffsetPrefix, ep, name.begin())) >+ return false; >+ const char* np = name.data() + prefix_len; >+ if (np[0] != '+' && np[0] != '-') >+ return false; >+ if (np[3] != ':' || np[6] != ':') // see note below about large offsets >+ return false; >+ >+ int hours = Parse02d(np + 1); >+ if (hours == -1) return false; >+ int mins = Parse02d(np + 4); >+ if (mins == -1) return false; >+ int secs = Parse02d(np + 7); >+ if (secs == -1) return false; >+ >+ secs += ((hours * 60) + mins) * 60; >+ if (secs > 24 * 60 * 60) return false; // outside supported offset range >+ *offset = seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west >+ return true; >+} >+ >+std::string FixedOffsetToName(const seconds& offset) { >+ if (offset == seconds::zero()) return "UTC"; >+ if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) { >+ // We don't support fixed-offset zones more than 24 hours >+ // away from UTC to avoid complications in rendering such >+ // offsets and to (somewhat) limit the total number of zones. >+ return "UTC"; >+ } >+ int seconds = static_cast<int>(offset.count()); >+ const char sign = (seconds < 0 ? '-' : '+'); >+ int minutes = seconds / 60; >+ seconds %= 60; >+ if (sign == '-') { >+ if (seconds > 0) { >+ seconds -= 60; >+ minutes += 1; >+ } >+ seconds = -seconds; >+ minutes = -minutes; >+ } >+ int hours = minutes / 60; >+ minutes %= 60; >+ char buf[sizeof(kFixedOffsetPrefix) + sizeof("-24:00:00")]; >+ snprintf(buf, sizeof(buf), "%s%c%02d:%02d:%02d", >+ kFixedOffsetPrefix, sign, hours, minutes, seconds); >+ return buf; >+} >+ >+std::string FixedOffsetToAbbr(const seconds& offset) { >+ std::string abbr = FixedOffsetToName(offset); >+ const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1; >+ if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99 >+ abbr.erase(0, prefix_len); // +99:99:99 >+ abbr.erase(6, 1); // +99:9999 >+ abbr.erase(3, 1); // +999999 >+ if (abbr[5] == '0' && abbr[6] == '0') { // +999900 >+ abbr.erase(5, 2); // +9999 >+ if (abbr[3] == '0' && abbr[4] == '0') { // +9900 >+ abbr.erase(3, 2); // +99 >+ } >+ } >+ } >+ return abbr; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.h >new file mode 100644 >index 00000000000..489b857d5df >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_fixed.h >@@ -0,0 +1,49 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ >+ >+#include <string> >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// Helper functions for dealing with the names and abbreviations >+// of time zones that are a fixed offset (seconds east) from UTC. >+// FixedOffsetFromName() extracts the offset from a valid fixed-offset >+// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate >+// the canonical zone name and abbreviation respectively for the given >+// offset. >+// >+// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>". >+// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the >+// optional pieces are omitted when their values are zero. (Note that >+// the sign is the opposite of that used in a POSIX TZ specification.) >+// >+// Note: FixedOffsetFromName() fails on syntax errors or when the parsed >+// offset exceeds 24 hours. FixedOffsetToName() and FixedOffsetToAbbr() >+// both produce "UTC" when the argument offset exceeds 24 hours. >+bool FixedOffsetFromName(const std::string& name, seconds* offset); >+std::string FixedOffsetToName(const seconds& offset); >+std::string FixedOffsetToAbbr(const seconds& offset); >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc >new file mode 100644 >index 00000000000..1b023848efa >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format.cc >@@ -0,0 +1,851 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#if !defined(HAS_STRPTIME) >+# if !defined(_MSC_VER) >+# define HAS_STRPTIME 1 // assume everyone has strptime() except windows >+# endif >+#endif >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+#include <cctype> >+#include <chrono> >+#include <cstddef> >+#include <cstdint> >+#include <cstring> >+#include <ctime> >+#include <limits> >+#include <string> >+#include <vector> >+#if !HAS_STRPTIME >+#include <iomanip> >+#include <sstream> >+#endif >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "time_zone_if.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+namespace detail { >+ >+namespace { >+ >+#if !HAS_STRPTIME >+// Build a strptime() using C++11's std::get_time(). >+char* strptime(const char* s, const char* fmt, std::tm* tm) { >+ std::istringstream input(s); >+ input >> std::get_time(tm, fmt); >+ if (input.fail()) return nullptr; >+ return const_cast<char*>(s) + >+ (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg())); >+} >+#endif >+ >+std::tm ToTM(const time_zone::absolute_lookup& al) { >+ std::tm tm{}; >+ tm.tm_sec = al.cs.second(); >+ tm.tm_min = al.cs.minute(); >+ tm.tm_hour = al.cs.hour(); >+ tm.tm_mday = al.cs.day(); >+ tm.tm_mon = al.cs.month() - 1; >+ >+ // Saturate tm.tm_year is cases of over/underflow. >+ if (al.cs.year() < std::numeric_limits<int>::min() + 1900) { >+ tm.tm_year = std::numeric_limits<int>::min(); >+ } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) { >+ tm.tm_year = std::numeric_limits<int>::max(); >+ } else { >+ tm.tm_year = static_cast<int>(al.cs.year() - 1900); >+ } >+ >+ switch (get_weekday(civil_day(al.cs))) { >+ case weekday::sunday: >+ tm.tm_wday = 0; >+ break; >+ case weekday::monday: >+ tm.tm_wday = 1; >+ break; >+ case weekday::tuesday: >+ tm.tm_wday = 2; >+ break; >+ case weekday::wednesday: >+ tm.tm_wday = 3; >+ break; >+ case weekday::thursday: >+ tm.tm_wday = 4; >+ break; >+ case weekday::friday: >+ tm.tm_wday = 5; >+ break; >+ case weekday::saturday: >+ tm.tm_wday = 6; >+ break; >+ } >+ tm.tm_yday = get_yearday(civil_day(al.cs)) - 1; >+ tm.tm_isdst = al.is_dst ? 1 : 0; >+ return tm; >+} >+ >+const char kDigits[] = "0123456789"; >+ >+// Formats a 64-bit integer in the given field width. Note that it is up >+// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure >+// that there is sufficient space before ep to hold the conversion. >+char* Format64(char* ep, int width, std::int_fast64_t v) { >+ bool neg = false; >+ if (v < 0) { >+ --width; >+ neg = true; >+ if (v == std::numeric_limits<std::int_fast64_t>::min()) { >+ // Avoid negating minimum value. >+ std::int_fast64_t last_digit = -(v % 10); >+ v /= 10; >+ if (last_digit < 0) { >+ ++v; >+ last_digit += 10; >+ } >+ --width; >+ *--ep = kDigits[last_digit]; >+ } >+ v = -v; >+ } >+ do { >+ --width; >+ *--ep = kDigits[v % 10]; >+ } while (v /= 10); >+ while (--width >= 0) *--ep = '0'; // zero pad >+ if (neg) *--ep = '-'; >+ return ep; >+} >+ >+// Formats [0 .. 99] as %02d. >+char* Format02d(char* ep, int v) { >+ *--ep = kDigits[v % 10]; >+ *--ep = kDigits[(v / 10) % 10]; >+ return ep; >+} >+ >+// Formats a UTC offset, like +00:00. >+char* FormatOffset(char* ep, int offset, const char* mode) { >+ // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and >+ // generate a "negative zero" when we're formatting a zero offset >+ // as the result of a failed load_time_zone(). >+ char sign = '+'; >+ if (offset < 0) { >+ offset = -offset; // bounded by 24h so no overflow >+ sign = '-'; >+ } >+ char sep = mode[0]; >+ if (sep != '\0' && mode[1] == '*') { >+ ep = Format02d(ep, offset % 60); >+ *--ep = sep; >+ } >+ int minutes = offset / 60; >+ ep = Format02d(ep, minutes % 60); >+ if (sep != '\0') *--ep = sep; >+ ep = Format02d(ep, minutes / 60); >+ *--ep = sign; >+ return ep; >+} >+ >+// Formats a std::tm using strftime(3). >+void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) { >+ // strftime(3) returns the number of characters placed in the output >+ // array (which may be 0 characters). It also returns 0 to indicate >+ // an error, like the array wasn't large enough. To accommodate this, >+ // the following code grows the buffer size from 2x the format std::string >+ // length up to 32x. >+ for (std::size_t i = 2; i != 32; i *= 2) { >+ std::size_t buf_size = fmt.size() * i; >+ std::vector<char> buf(buf_size); >+ if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) { >+ out->append(&buf[0], len); >+ return; >+ } >+ } >+} >+ >+// Used for %E#S/%E#f specifiers and for data values in parse(). >+template <typename T> >+const char* ParseInt(const char* dp, int width, T min, T max, T* vp) { >+ if (dp != nullptr) { >+ const T kmin = std::numeric_limits<T>::min(); >+ bool erange = false; >+ bool neg = false; >+ T value = 0; >+ if (*dp == '-') { >+ neg = true; >+ if (width <= 0 || --width != 0) { >+ ++dp; >+ } else { >+ dp = nullptr; // width was 1 >+ } >+ } >+ if (const char* const bp = dp) { >+ while (const char* cp = strchr(kDigits, *dp)) { >+ int d = static_cast<int>(cp - kDigits); >+ if (d >= 10) break; >+ if (value < kmin / 10) { >+ erange = true; >+ break; >+ } >+ value *= 10; >+ if (value < kmin + d) { >+ erange = true; >+ break; >+ } >+ value -= d; >+ dp += 1; >+ if (width > 0 && --width == 0) break; >+ } >+ if (dp != bp && !erange && (neg || value != kmin)) { >+ if (!neg || value != 0) { >+ if (!neg) value = -value; // make positive >+ if (min <= value && value <= max) { >+ *vp = value; >+ } else { >+ dp = nullptr; >+ } >+ } else { >+ dp = nullptr; >+ } >+ } else { >+ dp = nullptr; >+ } >+ } >+ } >+ return dp; >+} >+ >+// The number of base-10 digits that can be represented by a signed 64-bit >+// integer. That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1). >+const int kDigits10_64 = 18; >+ >+// 10^n for everything that can be represented by a signed 64-bit integer. >+const std::int_fast64_t kExp10[kDigits10_64 + 1] = { >+ 1, >+ 10, >+ 100, >+ 1000, >+ 10000, >+ 100000, >+ 1000000, >+ 10000000, >+ 100000000, >+ 1000000000, >+ 10000000000, >+ 100000000000, >+ 1000000000000, >+ 10000000000000, >+ 100000000000000, >+ 1000000000000000, >+ 10000000000000000, >+ 100000000000000000, >+ 1000000000000000000, >+}; >+ >+} // namespace >+ >+// Uses strftime(3) to format the given Time. The following extended format >+// specifiers are also supported: >+// >+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) >+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) >+// - %E#S - Seconds with # digits of fractional precision >+// - %E*S - Seconds with full fractional precision (a literal '*') >+// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) >+// >+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are >+// handled internally for performance reasons. strftime(3) is slow due to >+// a POSIX requirement to respect changes to ${TZ}. >+// >+// The TZ/GNU %s extension is handled internally because strftime() has >+// to use mktime() to generate it, and that assumes the local time zone. >+// >+// We also handle the %z and %Z specifiers to accommodate platforms that do >+// not support the tm_gmtoff and tm_zone extensions to std::tm. >+// >+// Requires that zero() <= fs < seconds(1). >+std::string format(const std::string& format, const time_point<seconds>& tp, >+ const detail::femtoseconds& fs, const time_zone& tz) { >+ std::string result; >+ result.reserve(format.size()); // A reasonable guess for the result size. >+ const time_zone::absolute_lookup al = tz.lookup(tp); >+ const std::tm tm = ToTM(al); >+ >+ // Scratch buffer for internal conversions. >+ char buf[3 + kDigits10_64]; // enough for longest conversion >+ char* const ep = buf + sizeof(buf); >+ char* bp; // works back from ep >+ >+ // Maintain three, disjoint subsequences that span format. >+ // [format.begin() ... pending) : already formatted into result >+ // [pending ... cur) : formatting pending, but no special cases >+ // [cur ... format.end()) : unexamined >+ // Initially, everything is in the unexamined part. >+ const char* pending = format.c_str(); // NUL terminated >+ const char* cur = pending; >+ const char* end = pending + format.length(); >+ >+ while (cur != end) { // while something is unexamined >+ // Moves cur to the next percent sign. >+ const char* start = cur; >+ while (cur != end && *cur != '%') ++cur; >+ >+ // If the new pending text is all ordinary, copy it out. >+ if (cur != start && pending == start) { >+ result.append(pending, static_cast<std::size_t>(cur - pending)); >+ pending = start = cur; >+ } >+ >+ // Span the sequential percent signs. >+ const char* percent = cur; >+ while (cur != end && *cur == '%') ++cur; >+ >+ // If the new pending text is all percents, copy out one >+ // percent for every matched pair, then skip those pairs. >+ if (cur != start && pending == start) { >+ std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2; >+ result.append(pending, escaped); >+ pending += escaped * 2; >+ // Also copy out a single trailing percent. >+ if (pending != cur && cur == end) { >+ result.push_back(*pending++); >+ } >+ } >+ >+ // Loop unless we have an unescaped percent. >+ if (cur == end || (cur - percent) % 2 == 0) continue; >+ >+ // Simple specifiers that we handle ourselves. >+ if (strchr("YmdeHMSzZs%", *cur)) { >+ if (cur - 1 != pending) { >+ FormatTM(&result, std::string(pending, cur - 1), tm); >+ } >+ switch (*cur) { >+ case 'Y': >+ // This avoids the tm.tm_year overflow problem for %Y, however >+ // tm.tm_year will still be used by other specifiers like %D. >+ bp = Format64(ep, 0, al.cs.year()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'm': >+ bp = Format02d(ep, al.cs.month()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'd': >+ case 'e': >+ bp = Format02d(ep, al.cs.day()); >+ if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'H': >+ bp = Format02d(ep, al.cs.hour()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'M': >+ bp = Format02d(ep, al.cs.minute()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'S': >+ bp = Format02d(ep, al.cs.second()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'z': >+ bp = FormatOffset(ep, al.offset, ""); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case 'Z': >+ result.append(al.abbr); >+ break; >+ case 's': >+ bp = Format64(ep, 0, ToUnixSeconds(tp)); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ break; >+ case '%': >+ result.push_back('%'); >+ break; >+ } >+ pending = ++cur; >+ continue; >+ } >+ >+ // Loop if there is no E modifier. >+ if (*cur != 'E' || ++cur == end) continue; >+ >+ // Format our extensions. >+ if (*cur == 'z') { >+ // Formats %Ez. >+ if (cur - 2 != pending) { >+ FormatTM(&result, std::string(pending, cur - 2), tm); >+ } >+ bp = FormatOffset(ep, al.offset, ":"); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ pending = ++cur; >+ } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') { >+ // Formats %E*z. >+ if (cur - 2 != pending) { >+ FormatTM(&result, std::string(pending, cur - 2), tm); >+ } >+ bp = FormatOffset(ep, al.offset, ":*"); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ pending = cur += 2; >+ } else if (*cur == '*' && cur + 1 != end && >+ (*(cur + 1) == 'S' || *(cur + 1) == 'f')) { >+ // Formats %E*S or %E*F. >+ if (cur - 2 != pending) { >+ FormatTM(&result, std::string(pending, cur - 2), tm); >+ } >+ char* cp = ep; >+ bp = Format64(cp, 15, fs.count()); >+ while (cp != bp && cp[-1] == '0') --cp; >+ switch (*(cur + 1)) { >+ case 'S': >+ if (cp != bp) *--bp = '.'; >+ bp = Format02d(bp, al.cs.second()); >+ break; >+ case 'f': >+ if (cp == bp) *--bp = '0'; >+ break; >+ } >+ result.append(bp, static_cast<std::size_t>(cp - bp)); >+ pending = cur += 2; >+ } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') { >+ // Formats %E4Y. >+ if (cur - 2 != pending) { >+ FormatTM(&result, std::string(pending, cur - 2), tm); >+ } >+ bp = Format64(ep, 4, al.cs.year()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ pending = cur += 2; >+ } else if (std::isdigit(*cur)) { >+ // Possibly found %E#S or %E#f. >+ int n = 0; >+ if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) { >+ if (*np == 'S' || *np == 'f') { >+ // Formats %E#S or %E#f. >+ if (cur - 2 != pending) { >+ FormatTM(&result, std::string(pending, cur - 2), tm); >+ } >+ bp = ep; >+ if (n > 0) { >+ if (n > kDigits10_64) n = kDigits10_64; >+ bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15] >+ : fs.count() / kExp10[15 - n]); >+ if (*np == 'S') *--bp = '.'; >+ } >+ if (*np == 'S') bp = Format02d(bp, al.cs.second()); >+ result.append(bp, static_cast<std::size_t>(ep - bp)); >+ pending = cur = ++np; >+ } >+ } >+ } >+ } >+ >+ // Formats any remaining data. >+ if (end != pending) { >+ FormatTM(&result, std::string(pending, end), tm); >+ } >+ >+ return result; >+} >+ >+namespace { >+ >+const char* ParseOffset(const char* dp, const char* mode, int* offset) { >+ if (dp != nullptr) { >+ const char first = *dp++; >+ if (first == '+' || first == '-') { >+ char sep = mode[0]; >+ int hours = 0; >+ int minutes = 0; >+ int seconds = 0; >+ const char* ap = ParseInt(dp, 2, 0, 23, &hours); >+ if (ap != nullptr && ap - dp == 2) { >+ dp = ap; >+ if (sep != '\0' && *ap == sep) ++ap; >+ const char* bp = ParseInt(ap, 2, 0, 59, &minutes); >+ if (bp != nullptr && bp - ap == 2) { >+ dp = bp; >+ if (sep != '\0' && *bp == sep) ++bp; >+ const char* cp = ParseInt(bp, 2, 0, 59, &seconds); >+ if (cp != nullptr && cp - bp == 2) dp = cp; >+ } >+ *offset = ((hours * 60 + minutes) * 60) + seconds; >+ if (first == '-') *offset = -*offset; >+ } else { >+ dp = nullptr; >+ } >+ } else if (first == 'Z') { // Zulu >+ *offset = 0; >+ } else { >+ dp = nullptr; >+ } >+ } >+ return dp; >+} >+ >+const char* ParseZone(const char* dp, std::string* zone) { >+ zone->clear(); >+ if (dp != nullptr) { >+ while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++); >+ if (zone->empty()) dp = nullptr; >+ } >+ return dp; >+} >+ >+const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) { >+ if (dp != nullptr) { >+ std::int_fast64_t v = 0; >+ std::int_fast64_t exp = 0; >+ const char* const bp = dp; >+ while (const char* cp = strchr(kDigits, *dp)) { >+ int d = static_cast<int>(cp - kDigits); >+ if (d >= 10) break; >+ if (exp < 15) { >+ exp += 1; >+ v *= 10; >+ v += d; >+ } >+ ++dp; >+ } >+ if (dp != bp) { >+ v *= kExp10[15 - exp]; >+ *subseconds = detail::femtoseconds(v); >+ } else { >+ dp = nullptr; >+ } >+ } >+ return dp; >+} >+ >+// Parses a std::string into a std::tm using strptime(3). >+const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) { >+ if (dp != nullptr) { >+ dp = strptime(dp, fmt, tm); >+ } >+ return dp; >+} >+ >+} // namespace >+ >+// Uses strptime(3) to parse the given input. Supports the same extended >+// format specifiers as format(), although %E#S and %E*S are treated >+// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept >+// the same inputs. >+// >+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are >+// handled internally so that we can normally avoid strptime() altogether >+// (which is particularly helpful when the native implementation is broken). >+// >+// The TZ/GNU %s extension is handled internally because strptime() has to >+// use localtime_r() to generate it, and that assumes the local time zone. >+// >+// We also handle the %z specifier to accommodate platforms that do not >+// support the tm_gmtoff extension to std::tm. %Z is parsed but ignored. >+bool parse(const std::string& format, const std::string& input, >+ const time_zone& tz, time_point<seconds>* sec, >+ detail::femtoseconds* fs, std::string* err) { >+ // The unparsed input. >+ const char* data = input.c_str(); // NUL terminated >+ >+ // Skips leading whitespace. >+ while (std::isspace(*data)) ++data; >+ >+ const year_t kyearmax = std::numeric_limits<year_t>::max(); >+ const year_t kyearmin = std::numeric_limits<year_t>::min(); >+ >+ // Sets default values for unspecified fields. >+ bool saw_year = false; >+ year_t year = 1970; >+ std::tm tm{}; >+ tm.tm_year = 1970 - 1900; >+ tm.tm_mon = 1 - 1; // Jan >+ tm.tm_mday = 1; >+ tm.tm_hour = 0; >+ tm.tm_min = 0; >+ tm.tm_sec = 0; >+ tm.tm_wday = 4; // Thu >+ tm.tm_yday = 0; >+ tm.tm_isdst = 0; >+ auto subseconds = detail::femtoseconds::zero(); >+ bool saw_offset = false; >+ int offset = 0; // No offset from passed tz. >+ std::string zone = "UTC"; >+ >+ const char* fmt = format.c_str(); // NUL terminated >+ bool twelve_hour = false; >+ bool afternoon = false; >+ >+ bool saw_percent_s = false; >+ std::int_fast64_t percent_s = 0; >+ >+ // Steps through format, one specifier at a time. >+ while (data != nullptr && *fmt != '\0') { >+ if (std::isspace(*fmt)) { >+ while (std::isspace(*data)) ++data; >+ while (std::isspace(*++fmt)) continue; >+ continue; >+ } >+ >+ if (*fmt != '%') { >+ if (*data == *fmt) { >+ ++data; >+ ++fmt; >+ } else { >+ data = nullptr; >+ } >+ continue; >+ } >+ >+ const char* percent = fmt; >+ if (*++fmt == '\0') { >+ data = nullptr; >+ continue; >+ } >+ switch (*fmt++) { >+ case 'Y': >+ // Symmetrically with FormatTime(), directly handing %Y avoids the >+ // tm.tm_year overflow problem. However, tm.tm_year will still be >+ // used by other specifiers like %D. >+ data = ParseInt(data, 0, kyearmin, kyearmax, &year); >+ if (data != nullptr) saw_year = true; >+ continue; >+ case 'm': >+ data = ParseInt(data, 2, 1, 12, &tm.tm_mon); >+ if (data != nullptr) tm.tm_mon -= 1; >+ continue; >+ case 'd': >+ case 'e': >+ data = ParseInt(data, 2, 1, 31, &tm.tm_mday); >+ continue; >+ case 'H': >+ data = ParseInt(data, 2, 0, 23, &tm.tm_hour); >+ twelve_hour = false; >+ continue; >+ case 'M': >+ data = ParseInt(data, 2, 0, 59, &tm.tm_min); >+ continue; >+ case 'S': >+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec); >+ continue; >+ case 'I': >+ case 'l': >+ case 'r': // probably uses %I >+ twelve_hour = true; >+ break; >+ case 'R': // uses %H >+ case 'T': // uses %H >+ case 'c': // probably uses %H >+ case 'X': // probably uses %H >+ twelve_hour = false; >+ break; >+ case 'z': >+ data = ParseOffset(data, "", &offset); >+ if (data != nullptr) saw_offset = true; >+ continue; >+ case 'Z': // ignored; zone abbreviations are ambiguous >+ data = ParseZone(data, &zone); >+ continue; >+ case 's': >+ data = ParseInt(data, 0, >+ std::numeric_limits<std::int_fast64_t>::min(), >+ std::numeric_limits<std::int_fast64_t>::max(), >+ &percent_s); >+ if (data != nullptr) saw_percent_s = true; >+ continue; >+ case '%': >+ data = (*data == '%' ? data + 1 : nullptr); >+ continue; >+ case 'E': >+ if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) { >+ data = ParseOffset(data, ":", &offset); >+ if (data != nullptr) saw_offset = true; >+ fmt += (*fmt == 'z') ? 1 : 2; >+ continue; >+ } >+ if (*fmt == '*' && *(fmt + 1) == 'S') { >+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec); >+ if (data != nullptr && *data == '.') { >+ data = ParseSubSeconds(data + 1, &subseconds); >+ } >+ fmt += 2; >+ continue; >+ } >+ if (*fmt == '*' && *(fmt + 1) == 'f') { >+ if (data != nullptr && std::isdigit(*data)) { >+ data = ParseSubSeconds(data, &subseconds); >+ } >+ fmt += 2; >+ continue; >+ } >+ if (*fmt == '4' && *(fmt + 1) == 'Y') { >+ const char* bp = data; >+ data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year); >+ if (data != nullptr) { >+ if (data - bp == 4) { >+ saw_year = true; >+ } else { >+ data = nullptr; // stopped too soon >+ } >+ } >+ fmt += 2; >+ continue; >+ } >+ if (std::isdigit(*fmt)) { >+ int n = 0; // value ignored >+ if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) { >+ if (*np == 'S') { >+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec); >+ if (data != nullptr && *data == '.') { >+ data = ParseSubSeconds(data + 1, &subseconds); >+ } >+ fmt = ++np; >+ continue; >+ } >+ if (*np == 'f') { >+ if (data != nullptr && std::isdigit(*data)) { >+ data = ParseSubSeconds(data, &subseconds); >+ } >+ fmt = ++np; >+ continue; >+ } >+ } >+ } >+ if (*fmt == 'c') twelve_hour = false; // probably uses %H >+ if (*fmt == 'X') twelve_hour = false; // probably uses %H >+ if (*fmt != '\0') ++fmt; >+ break; >+ case 'O': >+ if (*fmt == 'H') twelve_hour = false; >+ if (*fmt == 'I') twelve_hour = true; >+ if (*fmt != '\0') ++fmt; >+ break; >+ } >+ >+ // Parses the current specifier. >+ const char* orig_data = data; >+ std::string spec(percent, static_cast<std::size_t>(fmt - percent)); >+ data = ParseTM(data, spec.c_str(), &tm); >+ >+ // If we successfully parsed %p we need to remember whether the result >+ // was AM or PM so that we can adjust tm_hour before ConvertDateTime(). >+ // So reparse the input with a known AM hour, and check if it is shifted >+ // to a PM hour. >+ if (spec == "%p" && data != nullptr) { >+ std::string test_input = "1"; >+ test_input.append(orig_data, static_cast<std::size_t>(data - orig_data)); >+ const char* test_data = test_input.c_str(); >+ std::tm tmp{}; >+ ParseTM(test_data, "%I%p", &tmp); >+ afternoon = (tmp.tm_hour == 13); >+ } >+ } >+ >+ // Adjust a 12-hour tm_hour value if it should be in the afternoon. >+ if (twelve_hour && afternoon && tm.tm_hour < 12) { >+ tm.tm_hour += 12; >+ } >+ >+ if (data == nullptr) { >+ if (err != nullptr) *err = "Failed to parse input"; >+ return false; >+ } >+ >+ // Skip any remaining whitespace. >+ while (std::isspace(*data)) ++data; >+ >+ // parse() must consume the entire input std::string. >+ if (*data != '\0') { >+ if (err != nullptr) *err = "Illegal trailing data in input string"; >+ return false; >+ } >+ >+ // If we saw %s then we ignore anything else and return that time. >+ if (saw_percent_s) { >+ *sec = FromUnixSeconds(percent_s); >+ *fs = detail::femtoseconds::zero(); >+ return true; >+ } >+ >+ // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields >+ // in UTC and then shift by that offset. Otherwise we want to interpret >+ // the fields directly in the passed time_zone. >+ time_zone ptz = saw_offset ? utc_time_zone() : tz; >+ >+ // Allows a leap second of 60 to normalize forward to the following ":00". >+ if (tm.tm_sec == 60) { >+ tm.tm_sec -= 1; >+ offset -= 1; >+ subseconds = detail::femtoseconds::zero(); >+ } >+ >+ if (!saw_year) { >+ year = year_t{tm.tm_year}; >+ if (year > kyearmax - 1900) { >+ // Platform-dependent, maybe unreachable. >+ if (err != nullptr) *err = "Out-of-range year"; >+ return false; >+ } >+ year += 1900; >+ } >+ >+ const int month = tm.tm_mon + 1; >+ civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); >+ >+ // parse() should not allow normalization. Due to the restricted field >+ // ranges above (see ParseInt()), the only possibility is for days to roll >+ // into months. That is, parsing "Sep 31" should not produce "Oct 1". >+ if (cs.month() != month || cs.day() != tm.tm_mday) { >+ if (err != nullptr) *err = "Out-of-range field"; >+ return false; >+ } >+ >+ // Accounts for the offset adjustment before converting to absolute time. >+ if ((offset < 0 && cs > civil_second::max() + offset) || >+ (offset > 0 && cs < civil_second::min() + offset)) { >+ if (err != nullptr) *err = "Out-of-range field"; >+ return false; >+ } >+ cs -= offset; >+ >+ const auto tp = ptz.lookup(cs).pre; >+ // Checks for overflow/underflow and returns an error as necessary. >+ if (tp == time_point<seconds>::max()) { >+ const auto al = ptz.lookup(time_point<seconds>::max()); >+ if (cs > al.cs) { >+ if (err != nullptr) *err = "Out-of-range field"; >+ return false; >+ } >+ } >+ if (tp == time_point<seconds>::min()) { >+ const auto al = ptz.lookup(time_point<seconds>::min()); >+ if (cs < al.cs) { >+ if (err != nullptr) *err = "Out-of-range field"; >+ return false; >+ } >+ } >+ >+ *sec = tp; >+ *fs = subseconds; >+ return true; >+} >+ >+} // namespace detail >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc >new file mode 100644 >index 00000000000..a90dda7603a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_format_test.cc >@@ -0,0 +1,1426 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+#include <chrono> >+#include <iomanip> >+#include <sstream> >+#include <string> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+ >+namespace chrono = std::chrono; >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+// This helper is a macro so that failed expectations show up with the >+// correct line numbers. >+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \ >+ do { \ >+ time_zone::absolute_lookup al = tz.lookup(tp); \ >+ EXPECT_EQ(y, al.cs.year()); \ >+ EXPECT_EQ(m, al.cs.month()); \ >+ EXPECT_EQ(d, al.cs.day()); \ >+ EXPECT_EQ(hh, al.cs.hour()); \ >+ EXPECT_EQ(mm, al.cs.minute()); \ >+ EXPECT_EQ(ss, al.cs.second()); \ >+ EXPECT_EQ(off, al.offset); \ >+ EXPECT_TRUE(isdst == al.is_dst); \ >+ EXPECT_STREQ(zone, al.abbr); \ >+ } while (0) >+ >+const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; >+const char RFC3339_sec[] = "%Y-%m-%dT%H:%M:%S%Ez"; >+ >+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; >+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; >+ >+// A helper that tests the given format specifier by itself, and with leading >+// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu"). >+template <typename D> >+void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt, >+ const std::string& ans) { >+ EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt; >+ EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz)); >+ EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz)); >+ EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz)); >+} >+ >+// These tests sometimes run on platforms that have zoneinfo data so old >+// that the transition we are attempting to check does not exist, most >+// notably Android emulators. Fortunately, AndroidZoneInfoSource supports >+// time_zone::version() so, in cases where we've learned that it matters, >+// we can make the check conditionally. >+int VersionCmp(time_zone tz, const std::string& target) { >+ std::string version = tz.version(); >+ if (version.empty() && !target.empty()) return 1; // unknown > known >+ return version.compare(target); >+} >+ >+} // namespace >+ >+// >+// Testing format() >+// >+ >+TEST(Format, TimePointResolution) { >+ const char kFmt[] = "%H:%M:%E*S"; >+ const time_zone utc = utc_time_zone(); >+ const time_point<chrono::nanoseconds> t0 = >+ chrono::system_clock::from_time_t(1420167845) + >+ chrono::milliseconds(123) + chrono::microseconds(456) + >+ chrono::nanoseconds(789); >+ EXPECT_EQ( >+ "03:04:05.123456789", >+ format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc)); >+ EXPECT_EQ( >+ "03:04:05.123456", >+ format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc)); >+ EXPECT_EQ( >+ "03:04:05.123", >+ format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc)); >+ EXPECT_EQ("03:04:05", >+ format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc)); >+ EXPECT_EQ("03:04:05", >+ format(kFmt, chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc)); >+ EXPECT_EQ("03:04:00", >+ format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc)); >+ EXPECT_EQ("03:00:00", >+ format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc)); >+} >+ >+TEST(Format, TimePointExtendedResolution) { >+ const char kFmt[] = "%H:%M:%E*S"; >+ const time_zone utc = utc_time_zone(); >+ const time_point<absl::time_internal::cctz::seconds> tp = >+ chrono::time_point_cast<absl::time_internal::cctz::seconds>( >+ chrono::system_clock::from_time_t(0)) + >+ chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56); >+ >+ EXPECT_EQ( >+ "12:34:56.123456789012345", >+ detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc)); >+ EXPECT_EQ( >+ "12:34:56.012345678901234", >+ detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc)); >+ EXPECT_EQ( >+ "12:34:56.001234567890123", >+ detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc)); >+ EXPECT_EQ( >+ "12:34:56.000123456789012", >+ detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc)); >+ >+ EXPECT_EQ("12:34:56.000000000000123", >+ detail::format(kFmt, tp, detail::femtoseconds(123), utc)); >+ EXPECT_EQ("12:34:56.000000000000012", >+ detail::format(kFmt, tp, detail::femtoseconds(12), utc)); >+ EXPECT_EQ("12:34:56.000000000000001", >+ detail::format(kFmt, tp, detail::femtoseconds(1), utc)); >+} >+ >+TEST(Format, Basics) { >+ time_zone tz = utc_time_zone(); >+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); >+ >+ // Starts with a couple basic edge cases. >+ EXPECT_EQ("", format("", tp, tz)); >+ EXPECT_EQ(" ", format(" ", tp, tz)); >+ EXPECT_EQ(" ", format(" ", tp, tz)); >+ EXPECT_EQ("xxx", format("xxx", tp, tz)); >+ std::string big(128, 'x'); >+ EXPECT_EQ(big, format(big, tp, tz)); >+ // Cause the 1024-byte buffer to grow. >+ std::string bigger(100000, 'x'); >+ EXPECT_EQ(bigger, format(bigger, tp, tz)); >+ >+ tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5); >+ tp += chrono::milliseconds(6) + chrono::microseconds(7) + >+ chrono::nanoseconds(8); >+ EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz)); >+ EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz)); >+ EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz)); >+ EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz)); >+ EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz)); >+} >+ >+TEST(Format, PosixConversions) { >+ const time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ >+ TestFormatSpecifier(tp, tz, "%d", "01"); >+ TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support >+ TestFormatSpecifier(tp, tz, "%H", "00"); >+ TestFormatSpecifier(tp, tz, "%I", "12"); >+ TestFormatSpecifier(tp, tz, "%j", "001"); >+ TestFormatSpecifier(tp, tz, "%m", "01"); >+ TestFormatSpecifier(tp, tz, "%M", "00"); >+ TestFormatSpecifier(tp, tz, "%S", "00"); >+ TestFormatSpecifier(tp, tz, "%U", "00"); >+ TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday >+ TestFormatSpecifier(tp, tz, "%W", "00"); >+ TestFormatSpecifier(tp, tz, "%y", "70"); >+ TestFormatSpecifier(tp, tz, "%Y", "1970"); >+ TestFormatSpecifier(tp, tz, "%z", "+0000"); >+ TestFormatSpecifier(tp, tz, "%Z", "UTC"); >+ TestFormatSpecifier(tp, tz, "%%", "%"); >+ >+#if defined(__linux__) >+ // SU/C99/TZ extensions >+ TestFormatSpecifier(tp, tz, "%C", "19"); >+ TestFormatSpecifier(tp, tz, "%D", "01/01/70"); >+ TestFormatSpecifier(tp, tz, "%F", "1970-01-01"); >+ TestFormatSpecifier(tp, tz, "%g", "70"); >+ TestFormatSpecifier(tp, tz, "%G", "1970"); >+ TestFormatSpecifier(tp, tz, "%k", " 0"); >+ TestFormatSpecifier(tp, tz, "%l", "12"); >+ TestFormatSpecifier(tp, tz, "%n", "\n"); >+ TestFormatSpecifier(tp, tz, "%R", "00:00"); >+ TestFormatSpecifier(tp, tz, "%t", "\t"); >+ TestFormatSpecifier(tp, tz, "%T", "00:00:00"); >+ TestFormatSpecifier(tp, tz, "%u", "4"); // 4=Thursday >+ TestFormatSpecifier(tp, tz, "%V", "01"); >+ TestFormatSpecifier(tp, tz, "%s", "0"); >+#endif >+} >+ >+TEST(Format, LocaleSpecific) { >+ const time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ >+ TestFormatSpecifier(tp, tz, "%a", "Thu"); >+ TestFormatSpecifier(tp, tz, "%A", "Thursday"); >+ TestFormatSpecifier(tp, tz, "%b", "Jan"); >+ TestFormatSpecifier(tp, tz, "%B", "January"); >+ >+ // %c should at least produce the numeric year and time-of-day. >+ const std::string s = format("%c", tp, utc_time_zone()); >+ EXPECT_THAT(s, testing::HasSubstr("1970")); >+ EXPECT_THAT(s, testing::HasSubstr("00:00:00")); >+ >+ TestFormatSpecifier(tp, tz, "%p", "AM"); >+ TestFormatSpecifier(tp, tz, "%x", "01/01/70"); >+ TestFormatSpecifier(tp, tz, "%X", "00:00:00"); >+ >+#if defined(__linux__) >+ // SU/C99/TZ extensions >+ TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b >+ TestFormatSpecifier(tp, tz, "%P", "am"); >+ TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM"); >+ >+ // Modified conversion specifiers %E_ >+ TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970"); >+ TestFormatSpecifier(tp, tz, "%EC", "19"); >+ TestFormatSpecifier(tp, tz, "%Ex", "01/01/70"); >+ TestFormatSpecifier(tp, tz, "%EX", "00:00:00"); >+ TestFormatSpecifier(tp, tz, "%Ey", "70"); >+ TestFormatSpecifier(tp, tz, "%EY", "1970"); >+ >+ // Modified conversion specifiers %O_ >+ TestFormatSpecifier(tp, tz, "%Od", "01"); >+ TestFormatSpecifier(tp, tz, "%Oe", " 1"); >+ TestFormatSpecifier(tp, tz, "%OH", "00"); >+ TestFormatSpecifier(tp, tz, "%OI", "12"); >+ TestFormatSpecifier(tp, tz, "%Om", "01"); >+ TestFormatSpecifier(tp, tz, "%OM", "00"); >+ TestFormatSpecifier(tp, tz, "%OS", "00"); >+ TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday >+ TestFormatSpecifier(tp, tz, "%OU", "00"); >+ TestFormatSpecifier(tp, tz, "%OV", "01"); >+ TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday >+ TestFormatSpecifier(tp, tz, "%OW", "00"); >+ TestFormatSpecifier(tp, tz, "%Oy", "70"); >+#endif >+} >+ >+TEST(Format, Escaping) { >+ const time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ >+ TestFormatSpecifier(tp, tz, "%%", "%"); >+ TestFormatSpecifier(tp, tz, "%%a", "%a"); >+ TestFormatSpecifier(tp, tz, "%%b", "%b"); >+ TestFormatSpecifier(tp, tz, "%%Ea", "%Ea"); >+ TestFormatSpecifier(tp, tz, "%%Es", "%Es"); >+ TestFormatSpecifier(tp, tz, "%%E3S", "%E3S"); >+ TestFormatSpecifier(tp, tz, "%%OS", "%OS"); >+ TestFormatSpecifier(tp, tz, "%%O3S", "%O3S"); >+ >+ // Multiple levels of escaping. >+ TestFormatSpecifier(tp, tz, "%%%Y", "%1970"); >+ TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000"); >+ TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S"); >+} >+ >+TEST(Format, ExtendedSeconds) { >+ const time_zone tz = utc_time_zone(); >+ >+ // No subseconds. >+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); >+ tp += chrono::seconds(5); >+ EXPECT_EQ("05", format("%E*S", tp, tz)); >+ EXPECT_EQ("05", format("%E0S", tp, tz)); >+ EXPECT_EQ("05.0", format("%E1S", tp, tz)); >+ EXPECT_EQ("05.00", format("%E2S", tp, tz)); >+ EXPECT_EQ("05.000", format("%E3S", tp, tz)); >+ EXPECT_EQ("05.0000", format("%E4S", tp, tz)); >+ EXPECT_EQ("05.00000", format("%E5S", tp, tz)); >+ EXPECT_EQ("05.000000", format("%E6S", tp, tz)); >+ EXPECT_EQ("05.0000000", format("%E7S", tp, tz)); >+ EXPECT_EQ("05.00000000", format("%E8S", tp, tz)); >+ EXPECT_EQ("05.000000000", format("%E9S", tp, tz)); >+ EXPECT_EQ("05.0000000000", format("%E10S", tp, tz)); >+ EXPECT_EQ("05.00000000000", format("%E11S", tp, tz)); >+ EXPECT_EQ("05.000000000000", format("%E12S", tp, tz)); >+ EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz)); >+ EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz)); >+ EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz)); >+ >+ // With subseconds. >+ tp += chrono::milliseconds(6) + chrono::microseconds(7) + >+ chrono::nanoseconds(8); >+ EXPECT_EQ("05.006007008", format("%E*S", tp, tz)); >+ EXPECT_EQ("05", format("%E0S", tp, tz)); >+ EXPECT_EQ("05.0", format("%E1S", tp, tz)); >+ EXPECT_EQ("05.00", format("%E2S", tp, tz)); >+ EXPECT_EQ("05.006", format("%E3S", tp, tz)); >+ EXPECT_EQ("05.0060", format("%E4S", tp, tz)); >+ EXPECT_EQ("05.00600", format("%E5S", tp, tz)); >+ EXPECT_EQ("05.006007", format("%E6S", tp, tz)); >+ EXPECT_EQ("05.0060070", format("%E7S", tp, tz)); >+ EXPECT_EQ("05.00600700", format("%E8S", tp, tz)); >+ EXPECT_EQ("05.006007008", format("%E9S", tp, tz)); >+ EXPECT_EQ("05.0060070080", format("%E10S", tp, tz)); >+ EXPECT_EQ("05.00600700800", format("%E11S", tp, tz)); >+ EXPECT_EQ("05.006007008000", format("%E12S", tp, tz)); >+ EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz)); >+ EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz)); >+ EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz)); >+ >+ // Times before the Unix epoch. >+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); >+ EXPECT_EQ("1969-12-31 23:59:59.999999", >+ format("%Y-%m-%d %H:%M:%E*S", tp, tz)); >+ >+ // Here is a "%E*S" case we got wrong for a while. While the first >+ // instant below is correctly rendered as "...:07.333304", the second >+ // one used to appear as "...:07.33330499999999999". >+ tp = chrono::system_clock::from_time_t(0) + >+ chrono::microseconds(1395024427333304); >+ EXPECT_EQ("2014-03-17 02:47:07.333304", >+ format("%Y-%m-%d %H:%M:%E*S", tp, tz)); >+ tp += chrono::microseconds(1); >+ EXPECT_EQ("2014-03-17 02:47:07.333305", >+ format("%Y-%m-%d %H:%M:%E*S", tp, tz)); >+} >+ >+TEST(Format, ExtendedSubeconds) { >+ const time_zone tz = utc_time_zone(); >+ >+ // No subseconds. >+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); >+ tp += chrono::seconds(5); >+ EXPECT_EQ("0", format("%E*f", tp, tz)); >+ EXPECT_EQ("", format("%E0f", tp, tz)); >+ EXPECT_EQ("0", format("%E1f", tp, tz)); >+ EXPECT_EQ("00", format("%E2f", tp, tz)); >+ EXPECT_EQ("000", format("%E3f", tp, tz)); >+ EXPECT_EQ("0000", format("%E4f", tp, tz)); >+ EXPECT_EQ("00000", format("%E5f", tp, tz)); >+ EXPECT_EQ("000000", format("%E6f", tp, tz)); >+ EXPECT_EQ("0000000", format("%E7f", tp, tz)); >+ EXPECT_EQ("00000000", format("%E8f", tp, tz)); >+ EXPECT_EQ("000000000", format("%E9f", tp, tz)); >+ EXPECT_EQ("0000000000", format("%E10f", tp, tz)); >+ EXPECT_EQ("00000000000", format("%E11f", tp, tz)); >+ EXPECT_EQ("000000000000", format("%E12f", tp, tz)); >+ EXPECT_EQ("0000000000000", format("%E13f", tp, tz)); >+ EXPECT_EQ("00000000000000", format("%E14f", tp, tz)); >+ EXPECT_EQ("000000000000000", format("%E15f", tp, tz)); >+ >+ // With subseconds. >+ tp += chrono::milliseconds(6) + chrono::microseconds(7) + >+ chrono::nanoseconds(8); >+ EXPECT_EQ("006007008", format("%E*f", tp, tz)); >+ EXPECT_EQ("", format("%E0f", tp, tz)); >+ EXPECT_EQ("0", format("%E1f", tp, tz)); >+ EXPECT_EQ("00", format("%E2f", tp, tz)); >+ EXPECT_EQ("006", format("%E3f", tp, tz)); >+ EXPECT_EQ("0060", format("%E4f", tp, tz)); >+ EXPECT_EQ("00600", format("%E5f", tp, tz)); >+ EXPECT_EQ("006007", format("%E6f", tp, tz)); >+ EXPECT_EQ("0060070", format("%E7f", tp, tz)); >+ EXPECT_EQ("00600700", format("%E8f", tp, tz)); >+ EXPECT_EQ("006007008", format("%E9f", tp, tz)); >+ EXPECT_EQ("0060070080", format("%E10f", tp, tz)); >+ EXPECT_EQ("00600700800", format("%E11f", tp, tz)); >+ EXPECT_EQ("006007008000", format("%E12f", tp, tz)); >+ EXPECT_EQ("0060070080000", format("%E13f", tp, tz)); >+ EXPECT_EQ("00600700800000", format("%E14f", tp, tz)); >+ EXPECT_EQ("006007008000000", format("%E15f", tp, tz)); >+ >+ // Times before the Unix epoch. >+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); >+ EXPECT_EQ("1969-12-31 23:59:59.999999", >+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); >+ >+ // Here is a "%E*S" case we got wrong for a while. While the first >+ // instant below is correctly rendered as "...:07.333304", the second >+ // one used to appear as "...:07.33330499999999999". >+ tp = chrono::system_clock::from_time_t(0) + >+ chrono::microseconds(1395024427333304); >+ EXPECT_EQ("2014-03-17 02:47:07.333304", >+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); >+ tp += chrono::microseconds(1); >+ EXPECT_EQ("2014-03-17 02:47:07.333305", >+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); >+} >+ >+TEST(Format, CompareExtendSecondsVsSubseconds) { >+ const time_zone tz = utc_time_zone(); >+ >+ // This test case illustrates the differences/similarities between: >+ // fmt_A: %E<prec>S >+ // fmt_B: %S.%E<prec>f >+ auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; }; >+ auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; }; >+ >+ // No subseconds: >+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); >+ tp += chrono::seconds(5); >+ // ... %E*S and %S.%E*f are different. >+ EXPECT_EQ("05", format(fmt_A("*"), tp, tz)); >+ EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz)); >+ // ... %E0S and %S.%E0f are different. >+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); >+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); >+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15]. >+ for (int prec = 1; prec <= 15; ++prec) { >+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); >+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); >+ EXPECT_EQ(a, b) << "prec=" << prec; >+ } >+ >+ // With subseconds: >+ // ... %E*S and %S.%E*f are the same. >+ tp += chrono::milliseconds(6) + chrono::microseconds(7) + >+ chrono::nanoseconds(8); >+ EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz)); >+ EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz)); >+ // ... %E0S and %S.%E0f are different. >+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); >+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); >+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15]. >+ for (int prec = 1; prec <= 15; ++prec) { >+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); >+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); >+ EXPECT_EQ(a, b) << "prec=" << prec; >+ } >+} >+ >+TEST(Format, ExtendedOffset) { >+ auto tp = chrono::system_clock::from_time_t(0); >+ >+ time_zone tz = utc_time_zone(); >+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); >+ >+ EXPECT_TRUE(load_time_zone("America/New_York", &tz)); >+ TestFormatSpecifier(tp, tz, "%Ez", "-05:00"); >+ >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); >+ TestFormatSpecifier(tp, tz, "%Ez", "-08:00"); >+ >+ EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz)); >+ TestFormatSpecifier(tp, tz, "%Ez", "+10:00"); >+ >+ EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz)); >+ // The true offset is -00:44:30 but %z only gives (truncated) minutes. >+ TestFormatSpecifier(tp, tz, "%z", "-0044"); >+ TestFormatSpecifier(tp, tz, "%Ez", "-00:44"); >+} >+ >+TEST(Format, ExtendedSecondOffset) { >+ const time_zone utc = utc_time_zone(); >+ time_point<chrono::seconds> tp; >+ time_zone tz; >+ >+ EXPECT_TRUE(load_time_zone("America/New_York", &tz)); >+ tp = convert(civil_second(1883, 11, 18, 16, 59, 59), utc); >+ if (tz.lookup(tp).offset == -5 * 60 * 60) { >+ // It looks like the tzdata is only 32 bit (probably macOS), >+ // which bottoms out at 1901-12-13T20:45:52+00:00. >+ } else { >+ TestFormatSpecifier(tp, tz, "%E*z", "-04:56:02"); >+ TestFormatSpecifier(tp, tz, "%Ez", "-04:56"); >+ } >+ tp += chrono::seconds(1); >+ TestFormatSpecifier(tp, tz, "%E*z", "-05:00:00"); >+ >+ EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz)); >+ tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc); >+ if (VersionCmp(tz, "2016g") >= 0) { >+ TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19"); >+ TestFormatSpecifier(tp, tz, "%Ez", "+04:31"); >+ } >+ tp += chrono::seconds(1); >+ TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00"); >+} >+ >+TEST(Format, ExtendedYears) { >+ const time_zone utc = utc_time_zone(); >+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators >+ >+ // %E4Y zero-pads the year to produce at least 4 chars, including the sign. >+ auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("00001127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("00011127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("00091127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("00991127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("09991127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("99991127", format(e4y_fmt, tp, utc)); >+ >+ // When the year is outside [-999:9999], more than 4 chars are produced. >+ tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc)); >+ tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc); >+ EXPECT_EQ("100001127", format(e4y_fmt, tp, utc)); >+} >+ >+TEST(Format, RFC3339Format) { >+ time_zone tz; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); >+ >+ time_point<chrono::nanoseconds> tp = >+ convert(civil_second(1977, 6, 28, 9, 8, 7), tz); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::milliseconds(100); >+ EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::milliseconds(20); >+ EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::milliseconds(3); >+ EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::microseconds(400); >+ EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::microseconds(50); >+ EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::microseconds(6); >+ EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::nanoseconds(700); >+ EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::nanoseconds(80); >+ EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+ >+ tp += chrono::nanoseconds(9); >+ EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00", >+ format(RFC3339_full, tp, tz)); >+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); >+} >+ >+TEST(Format, RFC1123Format) { // locale specific >+ time_zone tz; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); >+ >+ auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); >+ EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz)); >+ EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz)); >+} >+ >+// >+// Testing parse() >+// >+ >+TEST(Parse, TimePointResolution) { >+ const char kFmt[] = "%H:%M:%E*S"; >+ const time_zone utc = utc_time_zone(); >+ >+ time_point<chrono::nanoseconds> tp_ns; >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns)); >+ EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns)); >+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc)); >+ >+ time_point<chrono::microseconds> tp_us; >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us)); >+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us)); >+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us)); >+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc)); >+ >+ time_point<chrono::milliseconds> tp_ms; >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms)); >+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms)); >+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms)); >+ EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc)); >+ >+ time_point<chrono::seconds> tp_s; >+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s)); >+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); >+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s)); >+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); >+ >+ time_point<chrono::minutes> tp_m; >+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m)); >+ EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc)); >+ >+ time_point<chrono::hours> tp_h; >+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h)); >+ EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc)); >+} >+ >+TEST(Parse, TimePointExtendedResolution) { >+ const char kFmt[] = "%H:%M:%E*S"; >+ const time_zone utc = utc_time_zone(); >+ >+ time_point<absl::time_internal::cctz::seconds> tp; >+ detail::femtoseconds fs; >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc)); >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc)); >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc)); >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc)); >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc)); >+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs)); >+ EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc)); >+} >+ >+TEST(Parse, Basics) { >+ time_zone tz = utc_time_zone(); >+ time_point<chrono::nanoseconds> tp = >+ chrono::system_clock::from_time_t(1234567890); >+ >+ // Simple edge cases. >+ EXPECT_TRUE(parse("", "", tz, &tp)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted >+ EXPECT_TRUE(parse(" ", " ", tz, &tp)); >+ EXPECT_TRUE(parse(" ", " ", tz, &tp)); >+ EXPECT_TRUE(parse("x", "x", tz, &tp)); >+ EXPECT_TRUE(parse("xxx", "xxx", tz, &tp)); >+ >+ EXPECT_TRUE( >+ parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC"); >+} >+ >+TEST(Parse, WithTimeZone) { >+ time_zone tz; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); >+ time_point<chrono::nanoseconds> tp; >+ >+ // We can parse a std::string without a UTC offset if we supply a timezone. >+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT"); >+ >+ // But the timezone is ignored when a UTC offset is present. >+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800", >+ utc_time_zone(), &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT"); >+ >+ // Check a skipped time (a Spring DST transition). parse() returns >+ // the preferred-offset result, as defined for ConvertDateTime(). >+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp)); >+ ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT"); >+ >+ // Check a repeated time (a Fall DST transition). parse() returns >+ // the preferred-offset result, as defined for ConvertDateTime(). >+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp)); >+ ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT"); >+} >+ >+TEST(Parse, LeapSecond) { >+ time_zone tz; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); >+ time_point<chrono::nanoseconds> tp; >+ >+ // ":59" -> ":59" >+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT"); >+ >+ // ":59.5" -> ":59.5" >+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT"); >+ >+ // ":60" -> ":00" >+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT"); >+ >+ // ":60.5" -> ":00.0" >+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp)); >+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT"); >+ >+ // ":61" -> error >+ EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp)); >+} >+ >+TEST(Parse, ErrorCases) { >+ const time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ >+ // Illegal trailing data. >+ EXPECT_FALSE(parse("%S", "123", tz, &tp)); >+ >+ // Can't parse an illegal format specifier. >+ EXPECT_FALSE(parse("%Q", "x", tz, &tp)); >+ >+ // Fails because of trailing, unparsed data "blah". >+ EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp)); >+ >+ // Trailing whitespace is allowed. >+ EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, utc_time_zone()).month()); >+ EXPECT_EQ(3, convert(tp, utc_time_zone()).day()); >+ >+ // Feb 31 requires normalization. >+ EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp)); >+ >+ // Check that we cannot have spaces in UTC offsets. >+ EXPECT_TRUE(parse("%z", "-0203", tz, &tp)); >+ EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp)); >+ EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp)); >+ EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp)); >+ >+ // Check that we reject other malformed UTC offsets. >+ EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp)); >+ EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp)); >+ >+ // Check that we do not accept "-0" in fields that allow zero. >+ EXPECT_FALSE(parse("%Y", "-0", tz, &tp)); >+ EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp)); >+ EXPECT_FALSE(parse("%H", "-0", tz, &tp)); >+ EXPECT_FALSE(parse("%M", "-0", tz, &tp)); >+ EXPECT_FALSE(parse("%S", "-0", tz, &tp)); >+ EXPECT_FALSE(parse("%z", "+-000", tz, &tp)); >+ EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp)); >+ EXPECT_FALSE(parse("%z", "-00-0", tz, &tp)); >+ EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp)); >+} >+ >+TEST(Parse, PosixConversions) { >+ time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%d", "15", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).day()); >+ >+ // %e is an extension, but is supported internally. >+ tp = reset; >+ EXPECT_TRUE(parse("%e", "15", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%H", "17", tz, &tp)); >+ EXPECT_EQ(17, convert(tp, tz).hour()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%I", "5", tz, &tp)); >+ EXPECT_EQ(5, convert(tp, tz).hour()); >+ >+ // %j is parsed but ignored. >+ EXPECT_TRUE(parse("%j", "32", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%m", "11", tz, &tp)); >+ EXPECT_EQ(11, convert(tp, tz).month()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%M", "33", tz, &tp)); >+ EXPECT_EQ(33, convert(tp, tz).minute()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%S", "55", tz, &tp)); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+ // %U is parsed but ignored. >+ EXPECT_TRUE(parse("%U", "15", tz, &tp)); >+ >+ // %w is parsed but ignored. >+ EXPECT_TRUE(parse("%w", "2", tz, &tp)); >+ >+ // %W is parsed but ignored. >+ EXPECT_TRUE(parse("%W", "22", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%y", "04", tz, &tp)); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Y", "2004", tz, &tp)); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ EXPECT_TRUE(parse("%%", "%", tz, &tp)); >+ >+#if defined(__linux__) >+ // SU/C99/TZ extensions >+ >+ // Because we handle each (non-internal) specifier in a separate call >+ // to strptime(), there is no way to group %C and %y together. So we >+ // just skip the %C/%y case. >+#if 0 >+ tp = reset; >+ EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp)); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+#endif >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, tz).month()); >+ EXPECT_EQ(3, convert(tp, tz).day()); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ EXPECT_TRUE(parse("%n", "\n", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%R", "03:44", tz, &tp)); >+ EXPECT_EQ(3, convert(tp, tz).hour()); >+ EXPECT_EQ(44, convert(tp, tz).minute()); >+ >+ EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp)); >+ EXPECT_EQ(3, convert(tp, tz).hour()); >+ EXPECT_EQ(44, convert(tp, tz).minute()); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%s", "1234567890", tz, &tp)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); >+ >+ // %s conversion, like %z/%Ez, pays no heed to the optional zone. >+ time_zone lax; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax)); >+ tp = reset; >+ EXPECT_TRUE(parse("%s", "1234567890", lax, &tp)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); >+ >+ // This is most important when the time has the same YMDhms >+ // breakdown in the zone as some other time. For example, ... >+ // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT) >+ // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST) >+ tp = reset; >+ EXPECT_TRUE(parse("%s", "1414917000", lax, &tp)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp); >+ tp = reset; >+ EXPECT_TRUE(parse("%s", "1414920600", lax, &tp)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp); >+#endif >+} >+ >+TEST(Parse, LocaleSpecific) { >+ time_zone tz = utc_time_zone(); >+ auto tp = chrono::system_clock::from_time_t(0); >+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); >+ >+ // %a is parsed but ignored. >+ EXPECT_TRUE(parse("%a", "Mon", tz, &tp)); >+ >+ // %A is parsed but ignored. >+ EXPECT_TRUE(parse("%A", "Monday", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%b", "Feb", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, tz).month()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%B", "February", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, tz).month()); >+ >+ // %p is parsed but ignored if it's alone. But it's used with %I. >+ EXPECT_TRUE(parse("%p", "AM", tz, &tp)); >+ tp = reset; >+ EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp)); >+ EXPECT_EQ(17, convert(tp, tz).hour()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp)); >+ if (convert(tp, tz).month() == 2) { >+ EXPECT_EQ(3, convert(tp, tz).day()); >+ } else { >+ EXPECT_EQ(2, convert(tp, tz).day()); >+ EXPECT_EQ(3, convert(tp, tz).month()); >+ } >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).hour()); >+ EXPECT_EQ(44, convert(tp, tz).minute()); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+#if defined(__linux__) >+ // SU/C99/TZ extensions >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%h", "Feb", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp)); >+ EXPECT_EQ(17, convert(tp, tz).hour()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).hour()); >+ EXPECT_EQ(44, convert(tp, tz).minute()); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp)); >+ EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp); >+ >+ // Modified conversion specifiers %E_ >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp)); >+ EXPECT_EQ(2, convert(tp, tz).month()); >+ EXPECT_EQ(3, convert(tp, tz).day()); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).hour()); >+ EXPECT_EQ(44, convert(tp, tz).minute()); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+ // %Ey, the year offset from %EC, doesn't really make sense alone as there >+ // is no way to represent it in tm_year (%EC is not simply the century). >+ // Yet, because we handle each (non-internal) specifier in a separate call >+ // to strptime(), there is no way to group %EC and %Ey either. So we just >+ // skip the %EC and %Ey cases. >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%EY", "2004", tz, &tp)); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+ >+ // Modified conversion specifiers %O_ >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Od", "15", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).day()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Oe", "15", tz, &tp)); >+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%OH", "17", tz, &tp)); >+ EXPECT_EQ(17, convert(tp, tz).hour()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%OI", "5", tz, &tp)); >+ EXPECT_EQ(5, convert(tp, tz).hour()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Om", "11", tz, &tp)); >+ EXPECT_EQ(11, convert(tp, tz).month()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%OM", "33", tz, &tp)); >+ EXPECT_EQ(33, convert(tp, tz).minute()); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%OS", "55", tz, &tp)); >+ EXPECT_EQ(55, convert(tp, tz).second()); >+ >+ // %OU is parsed but ignored. >+ EXPECT_TRUE(parse("%OU", "15", tz, &tp)); >+ >+ // %Ow is parsed but ignored. >+ EXPECT_TRUE(parse("%Ow", "2", tz, &tp)); >+ >+ // %OW is parsed but ignored. >+ EXPECT_TRUE(parse("%OW", "22", tz, &tp)); >+ >+ tp = reset; >+ EXPECT_TRUE(parse("%Oy", "04", tz, &tp)); >+ EXPECT_EQ(2004, convert(tp, tz).year()); >+#endif >+} >+ >+TEST(Parse, ExtendedSeconds) { >+ const time_zone tz = utc_time_zone(); >+ const time_point<chrono::nanoseconds> unix_epoch = >+ chrono::system_clock::from_time_t(0); >+ >+ // All %E<prec>S cases are treated the same as %E*S on input. >+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7", >+ "8", "9", "10", "11", "12", "13", "14", "15"}; >+ for (const std::string& prec : precisions) { >+ const std::string fmt = "%E" + prec + "S"; >+ SCOPED_TRACE(fmt); >+ time_point<chrono::nanoseconds> tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "5", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.0", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.00", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.6", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.60", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.600", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.67", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.670", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "05.678", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp); >+ } >+ >+ // Here is a "%E*S" case we got wrong for a while. The fractional >+ // part of the first instant is less than 2^31 and was correctly >+ // parsed, while the second (and any subsecond field >=2^31) failed. >+ time_point<chrono::nanoseconds> tp = unix_epoch; >+ EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+ >+ // We should also be able to specify long strings of digits far >+ // beyond the current resolution and have them convert the same way. >+ tp = unix_epoch; >+ EXPECT_TRUE(parse( >+ "%E*S", "0.214748364801234567890123456789012345678901234567890123456789", >+ tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+} >+ >+TEST(Parse, ExtendedSecondsScan) { >+ const time_zone tz = utc_time_zone(); >+ time_point<chrono::nanoseconds> tp; >+ for (int ms = 0; ms < 1000; ms += 111) { >+ for (int us = 0; us < 1000; us += 27) { >+ const int micros = ms * 1000 + us; >+ for (int ns = 0; ns < 1000; ns += 9) { >+ const auto expected = chrono::system_clock::from_time_t(0) + >+ chrono::nanoseconds(micros * 1000 + ns); >+ std::ostringstream oss; >+ oss << "0." << std::setfill('0') << std::setw(3); >+ oss << ms << std::setw(3) << us << std::setw(3) << ns; >+ const std::string input = oss.str(); >+ EXPECT_TRUE(parse("%E*S", input, tz, &tp)); >+ EXPECT_EQ(expected, tp) << input; >+ } >+ } >+ } >+} >+ >+TEST(Parse, ExtendedSubeconds) { >+ const time_zone tz = utc_time_zone(); >+ const time_point<chrono::nanoseconds> unix_epoch = >+ chrono::system_clock::from_time_t(0); >+ >+ // All %E<prec>f cases are treated the same as %E*f on input. >+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7", >+ "8", "9", "10", "11", "12", "13", "14", "15"}; >+ for (const std::string& prec : precisions) { >+ const std::string fmt = "%E" + prec + "f"; >+ SCOPED_TRACE(fmt); >+ time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1); >+ EXPECT_TRUE(parse(fmt, "", tz, &tp)); >+ EXPECT_EQ(unix_epoch, tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "6", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "60", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "600", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "67", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "670", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "678", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse(fmt, "6789", tz, &tp)); >+ EXPECT_EQ( >+ unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp); >+ } >+ >+ // Here is a "%E*f" case we got wrong for a while. The fractional >+ // part of the first instant is less than 2^31 and was correctly >+ // parsed, while the second (and any subsecond field >=2^31) failed. >+ time_point<chrono::nanoseconds> tp = unix_epoch; >+ EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+ tp = unix_epoch; >+ EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+ >+ // We should also be able to specify long strings of digits far >+ // beyond the current resolution and have them convert the same way. >+ tp = unix_epoch; >+ EXPECT_TRUE(parse( >+ "%E*f", "214748364801234567890123456789012345678901234567890123456789", >+ tz, &tp)); >+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); >+} >+ >+TEST(Parse, ExtendedSubecondsScan) { >+ time_point<chrono::nanoseconds> tp; >+ const time_zone tz = utc_time_zone(); >+ for (int ms = 0; ms < 1000; ms += 111) { >+ for (int us = 0; us < 1000; us += 27) { >+ const int micros = ms * 1000 + us; >+ for (int ns = 0; ns < 1000; ns += 9) { >+ std::ostringstream oss; >+ oss << std::setfill('0') << std::setw(3) << ms; >+ oss << std::setw(3) << us << std::setw(3) << ns; >+ const std::string nanos = oss.str(); >+ const auto expected = chrono::system_clock::from_time_t(0) + >+ chrono::nanoseconds(micros * 1000 + ns); >+ for (int ps = 0; ps < 1000; ps += 250) { >+ std::ostringstream oss; >+ oss << std::setfill('0') << std::setw(3) << ps; >+ const std::string input = nanos + oss.str() + "999"; >+ EXPECT_TRUE(parse("%E*f", input, tz, &tp)); >+ EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input; >+ } >+ } >+ } >+ } >+} >+ >+TEST(Parse, ExtendedOffset) { >+ const time_zone utc = utc_time_zone(); >+ time_point<absl::time_internal::cctz::seconds> tp; >+ >+ // %z against +-HHMM. >+ EXPECT_TRUE(parse("%z", "+0000", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%z", "-1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); >+ EXPECT_TRUE(parse("%z", "+1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); >+ EXPECT_FALSE(parse("%z", "-123", utc, &tp)); >+ >+ // %z against +-HH. >+ EXPECT_TRUE(parse("%z", "+00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%z", "-12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%z", "+12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); >+ EXPECT_FALSE(parse("%z", "-1", utc, &tp)); >+ >+ // %Ez against +-HH:MM. >+ EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); >+ EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp)); >+ >+ // %Ez against +-HHMM. >+ EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); >+ EXPECT_FALSE(parse("%Ez", "-123", utc, &tp)); >+ >+ // %Ez against +-HH. >+ EXPECT_TRUE(parse("%Ez", "+00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "-12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "+12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); >+ EXPECT_FALSE(parse("%Ez", "-1", utc, &tp)); >+} >+ >+TEST(Parse, ExtendedSecondOffset) { >+ const time_zone utc = utc_time_zone(); >+ time_point<absl::time_internal::cctz::seconds> tp; >+ >+ // %Ez against +-HH:MM:SS. >+ EXPECT_TRUE(parse("%Ez", "+00:00:00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "-12:34:56", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "+12:34:56", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); >+ EXPECT_FALSE(parse("%Ez", "-12:34:5", utc, &tp)); >+ >+ // %Ez against +-HHMMSS. >+ EXPECT_TRUE(parse("%Ez", "+000000", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "-123456", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); >+ EXPECT_TRUE(parse("%Ez", "+123456", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); >+ EXPECT_FALSE(parse("%Ez", "-12345", utc, &tp)); >+ >+ // %E*z against +-HH:MM:SS. >+ EXPECT_TRUE(parse("%E*z", "+00:00:00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "-12:34:56", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "+12:34:56", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); >+ EXPECT_FALSE(parse("%E*z", "-12:34:5", utc, &tp)); >+ >+ // %E*z against +-HHMMSS. >+ EXPECT_TRUE(parse("%E*z", "+000000", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "-123456", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "+123456", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); >+ EXPECT_FALSE(parse("%E*z", "-12345", utc, &tp)); >+ >+ // %E*z against +-HH:MM. >+ EXPECT_TRUE(parse("%E*z", "+00:00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "-12:34", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "+12:34", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); >+ EXPECT_FALSE(parse("%E*z", "-12:3", utc, &tp)); >+ >+ // %E*z against +-HHMM. >+ EXPECT_TRUE(parse("%E*z", "+0000", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "-1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "+1234", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); >+ EXPECT_FALSE(parse("%E*z", "-123", utc, &tp)); >+ >+ // %E*z against +-HH. >+ EXPECT_TRUE(parse("%E*z", "+00", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "-12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); >+ EXPECT_TRUE(parse("%E*z", "+12", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); >+ EXPECT_FALSE(parse("%E*z", "-1", utc, &tp)); >+} >+ >+TEST(Parse, ExtendedYears) { >+ const time_zone utc = utc_time_zone(); >+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators >+ time_point<absl::time_internal::cctz::seconds> tp; >+ >+ // %E4Y consumes exactly four chars, including any sign. >+ EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp); >+ EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp)); >+ EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp); >+ >+ // When the year is outside [-999:9999], the parse fails. >+ EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp)); >+ EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp)); >+} >+ >+TEST(Parse, RFC3339Format) { >+ const time_zone tz = utc_time_zone(); >+ time_point<chrono::nanoseconds> tp; >+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp)); >+ ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC"); >+ >+ // Check that %Ez also accepts "Z" as a synonym for "+00:00". >+ time_point<chrono::nanoseconds> tp2; >+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2)); >+ EXPECT_EQ(tp, tp2); >+} >+ >+TEST(Parse, MaxRange) { >+ const time_zone utc = utc_time_zone(); >+ time_point<absl::time_internal::cctz::seconds> tp; >+ >+ // tests the upper limit using +00:00 offset >+ EXPECT_TRUE( >+ parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp)); >+ EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max()); >+ EXPECT_FALSE( >+ parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp)); >+ >+ // tests the upper limit using -01:00 offset >+ EXPECT_TRUE( >+ parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp)); >+ EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max()); >+ EXPECT_FALSE( >+ parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp)); >+ >+ // tests the lower limit using +00:00 offset >+ EXPECT_TRUE( >+ parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp)); >+ EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min()); >+ EXPECT_FALSE( >+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp)); >+ >+ // tests the lower limit using +01:00 offset >+ EXPECT_TRUE( >+ parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp)); >+ EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min()); >+ EXPECT_FALSE( >+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp)); >+ >+ // tests max/min civil-second overflow >+ EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01", >+ utc, &tp)); >+ EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01", >+ utc, &tp)); >+ >+ // TODO: Add tests that parsing times with fractional seconds overflow >+ // appropriately. This can't be done until cctz::parse() properly detects >+ // overflow when combining the chrono seconds and femto. >+} >+ >+// >+// Roundtrip test for format()/parse(). >+// >+ >+TEST(FormatParse, RoundTrip) { >+ time_zone lax; >+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax)); >+ const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax); >+ const auto subseconds = chrono::nanoseconds(654321); >+ >+ // RFC3339, which renders subseconds. >+ { >+ time_point<chrono::nanoseconds> out; >+ const std::string s = format(RFC3339_full, in + subseconds, lax); >+ EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s; >+ EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez >+ } >+ >+ // RFC1123, which only does whole seconds. >+ { >+ time_point<chrono::nanoseconds> out; >+ const std::string s = format(RFC1123_full, in, lax); >+ EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s; >+ EXPECT_EQ(in, out); // RFC1123_full includes %z >+ } >+ >+#if defined(_WIN32) || defined(_WIN64) >+ // Initial investigations indicate the %c does not roundtrip on Windows. >+ // TODO: Figure out what is going on here (perhaps a locale problem). >+#else >+ // Even though we don't know what %c will produce, it should roundtrip, >+ // but only in the 0-offset timezone. >+ { >+ time_point<chrono::nanoseconds> out; >+ time_zone utc = utc_time_zone(); >+ const std::string s = format("%c", in, utc); >+ EXPECT_TRUE(parse("%c", s, utc, &out)) << s; >+ EXPECT_EQ(in, out); >+ } >+#endif >+} >+ >+TEST(FormatParse, RoundTripDistantFuture) { >+ const time_zone utc = utc_time_zone(); >+ const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::max(); >+ const std::string s = format(RFC3339_full, in, utc); >+ time_point<absl::time_internal::cctz::seconds> out; >+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; >+ EXPECT_EQ(in, out); >+} >+ >+TEST(FormatParse, RoundTripDistantPast) { >+ const time_zone utc = utc_time_zone(); >+ const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::min(); >+ const std::string s = format(RFC3339_full, in, utc); >+ time_point<absl::time_internal::cctz::seconds> out; >+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; >+ EXPECT_EQ(in, out); >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.cc >new file mode 100644 >index 00000000000..380834a172a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.cc >@@ -0,0 +1,41 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "time_zone_if.h" >+#include "time_zone_info.h" >+#include "time_zone_libc.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) { >+ // Support "libc:localtime" and "libc:*" to access the legacy >+ // localtime and UTC support respectively from the C library. >+ if (name.compare(0, 5, "libc:") == 0) { >+ return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5))); >+ } >+ >+ // Otherwise use the "zoneinfo" implementation by default. >+ std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo); >+ if (!tz->Load(name)) tz.reset(); >+ return std::unique_ptr<TimeZoneIf>(tz.release()); >+} >+ >+// Defined out-of-line to avoid emitting a weak vtable in all TUs. >+TimeZoneIf::~TimeZoneIf() {} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.h >new file mode 100644 >index 00000000000..e4bd3866a87 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_if.h >@@ -0,0 +1,72 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ >+ >+#include <chrono> >+#include <cstdint> >+#include <memory> >+#include <string> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// A simple interface used to hide time-zone complexities from time_zone::Impl. >+// Subclasses implement the functions for civil-time conversions in the zone. >+class TimeZoneIf { >+ public: >+ // A factory function for TimeZoneIf implementations. >+ static std::unique_ptr<TimeZoneIf> Load(const std::string& name); >+ >+ virtual ~TimeZoneIf(); >+ >+ virtual time_zone::absolute_lookup BreakTime( >+ const time_point<seconds>& tp) const = 0; >+ virtual time_zone::civil_lookup MakeTime( >+ const civil_second& cs) const = 0; >+ >+ virtual bool NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const = 0; >+ virtual bool PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const = 0; >+ >+ virtual std::string Version() const = 0; >+ virtual std::string Description() const = 0; >+ >+ protected: >+ TimeZoneIf() {} >+}; >+ >+// Convert between time_point<seconds> and a count of seconds since the >+// Unix epoch. We assume that the std::chrono::system_clock and the >+// Unix clock are second aligned, but not that they share an epoch. >+inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) { >+ return (tp - std::chrono::time_point_cast<seconds>( >+ std::chrono::system_clock::from_time_t(0))).count(); >+} >+inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) { >+ return std::chrono::time_point_cast<seconds>( >+ std::chrono::system_clock::from_time_t(0)) + seconds(t); >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.cc >new file mode 100644 >index 00000000000..3062ccd3ceb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.cc >@@ -0,0 +1,108 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "time_zone_impl.h" >+ >+#include <mutex> >+#include <string> >+#include <unordered_map> >+#include <utility> >+ >+#include "time_zone_fixed.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+// time_zone::Impls are linked into a map to support fast lookup by name. >+using TimeZoneImplByName = >+ std::unordered_map<std::string, const time_zone::Impl*>; >+TimeZoneImplByName* time_zone_map = nullptr; >+ >+// Mutual exclusion for time_zone_map. >+std::mutex time_zone_mutex; >+ >+} // namespace >+ >+time_zone time_zone::Impl::UTC() { >+ return time_zone(UTCImpl()); >+} >+ >+bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) { >+ const time_zone::Impl* const utc_impl = UTCImpl(); >+ >+ // First check for UTC (which is never a key in time_zone_map). >+ auto offset = seconds::zero(); >+ if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) { >+ *tz = time_zone(utc_impl); >+ return true; >+ } >+ >+ // Then check, under a shared lock, whether the time zone has already >+ // been loaded. This is the common path. TODO: Move to shared_mutex. >+ { >+ std::lock_guard<std::mutex> lock(time_zone_mutex); >+ if (time_zone_map != nullptr) { >+ TimeZoneImplByName::const_iterator itr = time_zone_map->find(name); >+ if (itr != time_zone_map->end()) { >+ *tz = time_zone(itr->second); >+ return itr->second != utc_impl; >+ } >+ } >+ } >+ >+ // Now check again, under an exclusive lock. >+ std::lock_guard<std::mutex> lock(time_zone_mutex); >+ if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName; >+ const Impl*& impl = (*time_zone_map)[name]; >+ if (impl == nullptr) { >+ // The first thread in loads the new time zone. >+ Impl* new_impl = new Impl(name); >+ new_impl->zone_ = TimeZoneIf::Load(new_impl->name_); >+ if (new_impl->zone_ == nullptr) { >+ delete new_impl; // free the nascent Impl >+ impl = utc_impl; // and fallback to UTC >+ } else { >+ impl = new_impl; // install new time zone >+ } >+ } >+ *tz = time_zone(impl); >+ return impl != utc_impl; >+} >+ >+void time_zone::Impl::ClearTimeZoneMapTestOnly() { >+ std::lock_guard<std::mutex> lock(time_zone_mutex); >+ if (time_zone_map != nullptr) { >+ // Existing time_zone::Impl* entries are in the wild, so we simply >+ // leak them. Future requests will result in reloading the data. >+ time_zone_map->clear(); >+ } >+} >+ >+time_zone::Impl::Impl(const std::string& name) : name_(name) {} >+ >+const time_zone::Impl* time_zone::Impl::UTCImpl() { >+ static Impl* utc_impl = [] { >+ Impl* impl = new Impl("UTC"); >+ impl->zone_ = TimeZoneIf::Load(impl->name_); // never fails >+ return impl; >+ }(); >+ return utc_impl; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.h >new file mode 100644 >index 00000000000..14965ef54bf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_impl.h >@@ -0,0 +1,90 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ >+ >+#include <memory> >+#include <string> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+#include "time_zone_if.h" >+#include "time_zone_info.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// time_zone::Impl is the internal object referenced by a cctz::time_zone. >+class time_zone::Impl { >+ public: >+ // The UTC time zone. Also used for other time zones that fail to load. >+ static time_zone UTC(); >+ >+ // Load a named time zone. Returns false if the name is invalid, or if >+ // some other kind of error occurs. Note that loading "UTC" never fails. >+ static bool LoadTimeZone(const std::string& name, time_zone* tz); >+ >+ // Clears the map of cached time zones. Primarily for use in benchmarks >+ // that gauge the performance of loading/parsing the time-zone data. >+ static void ClearTimeZoneMapTestOnly(); >+ >+ // The primary key is the time-zone ID (e.g., "America/New_York"). >+ const std::string& Name() const { >+ // TODO: It would nice if the zoneinfo data included the zone name. >+ return name_; >+ } >+ >+ // Breaks a time_point down to civil-time components in this time zone. >+ time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const { >+ return zone_->BreakTime(tp); >+ } >+ >+ // Converts the civil-time components in this time zone into a time_point. >+ // That is, the opposite of BreakTime(). The requested civil time may be >+ // ambiguous or illegal due to a change of UTC offset. >+ time_zone::civil_lookup MakeTime(const civil_second& cs) const { >+ return zone_->MakeTime(cs); >+ } >+ >+ // Finds the time of the next/previous offset change in this time zone. >+ bool NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ return zone_->NextTransition(tp, trans); >+ } >+ bool PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ return zone_->PrevTransition(tp, trans); >+ } >+ >+ // Returns an implementation-defined version std::string for this time zone. >+ std::string Version() const { return zone_->Version(); } >+ >+ // Returns an implementation-defined description of this time zone. >+ std::string Description() const { return zone_->Description(); } >+ >+ private: >+ explicit Impl(const std::string& name); >+ static const Impl* UTCImpl(); >+ >+ const std::string name_; >+ std::unique_ptr<TimeZoneIf> zone_; >+}; >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc >new file mode 100644 >index 00000000000..bf73635d4c6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.cc >@@ -0,0 +1,976 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file implements the TimeZoneIf interface using the "zoneinfo" >+// data provided by the IANA Time Zone Database (i.e., the only real game >+// in town). >+// >+// TimeZoneInfo represents the history of UTC-offset changes within a time >+// zone. Most changes are due to daylight-saving rules, but occasionally >+// shifts are made to the time-zone's base offset. The database only attempts >+// to be definitive for times since 1970, so be wary of local-time conversions >+// before that. Also, rule and zone-boundary changes are made at the whim >+// of governments, so the conversion of future times needs to be taken with >+// a grain of salt. >+// >+// For more information see tzfile(5), http://www.iana.org/time-zones, or >+// http://en.wikipedia.org/wiki/Zoneinfo. >+// >+// Note that we assume the proleptic Gregorian calendar and 60-second >+// minutes throughout. >+ >+#include "time_zone_info.h" >+ >+#include <algorithm> >+#include <cassert> >+#include <chrono> >+#include <cstdint> >+#include <cstdio> >+#include <cstdlib> >+#include <cstring> >+#include <functional> >+#include <iostream> >+#include <memory> >+#include <sstream> >+#include <string> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "time_zone_fixed.h" >+#include "time_zone_posix.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+inline bool IsLeap(year_t year) { >+ return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); >+} >+ >+// The number of days in non-leap and leap years respectively. >+const std::int_least32_t kDaysPerYear[2] = {365, 366}; >+ >+// The day offsets of the beginning of each (1-based) month in non-leap and >+// leap years respectively (e.g., 335 days before December in a leap year). >+const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = { >+ {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, >+ {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, >+}; >+ >+// We reject leap-second encoded zoneinfo and so assume 60-second minutes. >+const std::int_least32_t kSecsPerDay = 24 * 60 * 60; >+ >+// 400-year chunks always have 146097 days (20871 weeks). >+const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay; >+ >+// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay. >+const std::int_least32_t kSecsPerYear[2] = { >+ 365 * kSecsPerDay, >+ 366 * kSecsPerDay, >+}; >+ >+// Single-byte, unsigned numeric values are encoded directly. >+inline std::uint_fast8_t Decode8(const char* cp) { >+ return static_cast<std::uint_fast8_t>(*cp) & 0xff; >+} >+ >+// Multi-byte, numeric values are encoded using a MSB first, >+// twos-complement representation. These helpers decode, from >+// the given address, 4-byte and 8-byte values respectively. >+// Note: If int_fastXX_t == intXX_t and this machine is not >+// twos complement, then there will be at least one input value >+// we cannot represent. >+std::int_fast32_t Decode32(const char* cp) { >+ std::uint_fast32_t v = 0; >+ for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++); >+ const std::int_fast32_t s32max = 0x7fffffff; >+ const auto s32maxU = static_cast<std::uint_fast32_t>(s32max); >+ if (v <= s32maxU) return static_cast<std::int_fast32_t>(v); >+ return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1; >+} >+ >+std::int_fast64_t Decode64(const char* cp) { >+ std::uint_fast64_t v = 0; >+ for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++); >+ const std::int_fast64_t s64max = 0x7fffffffffffffff; >+ const auto s64maxU = static_cast<std::uint_fast64_t>(s64max); >+ if (v <= s64maxU) return static_cast<std::int_fast64_t>(v); >+ return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1; >+} >+ >+// Generate a year-relative offset for a PosixTransition. >+std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday, >+ const PosixTransition& pt) { >+ std::int_fast64_t days = 0; >+ switch (pt.date.fmt) { >+ case PosixTransition::J: { >+ days = pt.date.j.day; >+ if (!leap_year || days < kMonthOffsets[1][3]) days -= 1; >+ break; >+ } >+ case PosixTransition::N: { >+ days = pt.date.n.day; >+ break; >+ } >+ case PosixTransition::M: { >+ const bool last_week = (pt.date.m.week == 5); >+ days = kMonthOffsets[leap_year][pt.date.m.month + last_week]; >+ const std::int_fast64_t weekday = (jan1_weekday + days) % 7; >+ if (last_week) { >+ days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1; >+ } else { >+ days += (pt.date.m.weekday + 7 - weekday) % 7; >+ days += (pt.date.m.week - 1) * 7; >+ } >+ break; >+ } >+ } >+ return (days * kSecsPerDay) + pt.time.offset; >+} >+ >+inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) { >+ time_zone::civil_lookup cl; >+ cl.kind = time_zone::civil_lookup::UNIQUE; >+ cl.pre = cl.trans = cl.post = tp; >+ return cl; >+} >+ >+inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) { >+ return MakeUnique(FromUnixSeconds(unix_time)); >+} >+ >+inline time_zone::civil_lookup MakeSkipped(const Transition& tr, >+ const civil_second& cs) { >+ time_zone::civil_lookup cl; >+ cl.kind = time_zone::civil_lookup::SKIPPED; >+ cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec)); >+ cl.trans = FromUnixSeconds(tr.unix_time); >+ cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs)); >+ return cl; >+} >+ >+inline time_zone::civil_lookup MakeRepeated(const Transition& tr, >+ const civil_second& cs) { >+ time_zone::civil_lookup cl; >+ cl.kind = time_zone::civil_lookup::REPEATED; >+ cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs)); >+ cl.trans = FromUnixSeconds(tr.unix_time); >+ cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec)); >+ return cl; >+} >+ >+inline civil_second YearShift(const civil_second& cs, year_t shift) { >+ return civil_second(cs.year() + shift, cs.month(), cs.day(), >+ cs.hour(), cs.minute(), cs.second()); >+} >+ >+} // namespace >+ >+// What (no leap-seconds) UTC+seconds zoneinfo would look like. >+bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { >+ transition_types_.resize(1); >+ TransitionType& tt(transition_types_.back()); >+ tt.utc_offset = static_cast<std::int_least32_t>(offset.count()); >+ tt.is_dst = false; >+ tt.abbr_index = 0; >+ >+ // We temporarily add some redundant, contemporary (2013 through 2023) >+ // transitions for performance reasons. See TimeZoneInfo::LocalTime(). >+ // TODO: Fix the performance issue and remove the extra transitions. >+ transitions_.clear(); >+ transitions_.reserve(12); >+ for (const std::int_fast64_t unix_time : { >+ -(1LL << 59), // BIG_BANG >+ 1356998400LL, // 2013-01-01T00:00:00+00:00 >+ 1388534400LL, // 2014-01-01T00:00:00+00:00 >+ 1420070400LL, // 2015-01-01T00:00:00+00:00 >+ 1451606400LL, // 2016-01-01T00:00:00+00:00 >+ 1483228800LL, // 2017-01-01T00:00:00+00:00 >+ 1514764800LL, // 2018-01-01T00:00:00+00:00 >+ 1546300800LL, // 2019-01-01T00:00:00+00:00 >+ 1577836800LL, // 2020-01-01T00:00:00+00:00 >+ 1609459200LL, // 2021-01-01T00:00:00+00:00 >+ 1640995200LL, // 2022-01-01T00:00:00+00:00 >+ 1672531200LL, // 2023-01-01T00:00:00+00:00 >+ 2147483647LL, // 2^31 - 1 >+ }) { >+ Transition& tr(*transitions_.emplace(transitions_.end())); >+ tr.unix_time = unix_time; >+ tr.type_index = 0; >+ tr.civil_sec = LocalTime(tr.unix_time, tt).cs; >+ tr.prev_civil_sec = tr.civil_sec - 1; >+ } >+ >+ default_transition_type_ = 0; >+ abbreviations_ = FixedOffsetToAbbr(offset); >+ abbreviations_.append(1, '\0'); // add NUL >+ future_spec_.clear(); // never needed for a fixed-offset zone >+ extended_ = false; >+ >+ tt.civil_max = LocalTime(seconds::max().count(), tt).cs; >+ tt.civil_min = LocalTime(seconds::min().count(), tt).cs; >+ >+ transitions_.shrink_to_fit(); >+ return true; >+} >+ >+// Builds the in-memory header using the raw bytes from the file. >+bool TimeZoneInfo::Header::Build(const tzhead& tzh) { >+ std::int_fast32_t v; >+ if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; >+ timecnt = static_cast<std::size_t>(v); >+ if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; >+ typecnt = static_cast<std::size_t>(v); >+ if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; >+ charcnt = static_cast<std::size_t>(v); >+ if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; >+ leapcnt = static_cast<std::size_t>(v); >+ if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; >+ ttisstdcnt = static_cast<std::size_t>(v); >+ if ((v = Decode32(tzh.tzh_ttisgmtcnt)) < 0) return false; >+ ttisgmtcnt = static_cast<std::size_t>(v); >+ return true; >+} >+ >+// How many bytes of data are associated with this header. The result >+// depends upon whether this is a section with 4-byte or 8-byte times. >+std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const { >+ std::size_t len = 0; >+ len += (time_len + 1) * timecnt; // unix_time + type_index >+ len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index >+ len += 1 * charcnt; // abbreviations >+ len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC >+ len += 1 * ttisstdcnt; // UTC/local indicators >+ len += 1 * ttisgmtcnt; // standard/wall indicators >+ return len; >+} >+ >+// Check that the TransitionType has the expected offset/is_dst/abbreviation. >+void TimeZoneInfo::CheckTransition(const std::string& name, >+ const TransitionType& tt, >+ std::int_fast32_t offset, bool is_dst, >+ const std::string& abbr) const { >+ if (tt.utc_offset != offset || tt.is_dst != is_dst || >+ &abbreviations_[tt.abbr_index] != abbr) { >+ std::clog << name << ": Transition" >+ << " offset=" << tt.utc_offset << "/" >+ << (tt.is_dst ? "DST" : "STD") >+ << "/abbr=" << &abbreviations_[tt.abbr_index] >+ << " does not match POSIX spec '" << future_spec_ << "'\n"; >+ } >+} >+ >+// zic(8) can generate no-op transitions when a zone changes rules at an >+// instant when there is actually no discontinuity. So we check whether >+// two transitions have equivalent types (same offset/is_dst/abbr). >+bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, >+ std::uint_fast8_t tt2_index) const { >+ if (tt1_index == tt2_index) return true; >+ const TransitionType& tt1(transition_types_[tt1_index]); >+ const TransitionType& tt2(transition_types_[tt2_index]); >+ if (tt1.is_dst != tt2.is_dst) return false; >+ if (tt1.utc_offset != tt2.utc_offset) return false; >+ if (tt1.abbr_index != tt2.abbr_index) return false; >+ return true; >+} >+ >+// Use the POSIX-TZ-environment-variable-style std::string to handle times >+// in years after the last transition stored in the zoneinfo data. >+void TimeZoneInfo::ExtendTransitions(const std::string& name, >+ const Header& hdr) { >+ extended_ = false; >+ bool extending = !future_spec_.empty(); >+ >+ PosixTimeZone posix; >+ if (extending && !ParsePosixSpec(future_spec_, &posix)) { >+ std::clog << name << ": Failed to parse '" << future_spec_ << "'\n"; >+ extending = false; >+ } >+ >+ if (extending && posix.dst_abbr.empty()) { // std only >+ // The future specification should match the last/default transition, >+ // and that means that handling the future will fall out naturally. >+ std::uint_fast8_t index = default_transition_type_; >+ if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index; >+ const TransitionType& tt(transition_types_[index]); >+ CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr); >+ extending = false; >+ } >+ >+ if (extending && hdr.timecnt < 2) { >+ std::clog << name << ": Too few transitions for POSIX spec\n"; >+ extending = false; >+ } >+ >+ if (!extending) { >+ // Ensure that there is always a transition in the second half of the >+ // time line (the BIG_BANG transition is in the first half) so that the >+ // signed difference between a civil_second and the civil_second of its >+ // previous transition is always representable, without overflow. >+ const Transition& last(transitions_.back()); >+ if (last.unix_time < 0) { >+ const std::uint_fast8_t type_index = last.type_index; >+ Transition& tr(*transitions_.emplace(transitions_.end())); >+ tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00 >+ tr.type_index = type_index; >+ } >+ return; // last transition wins >+ } >+ >+ // Extend the transitions for an additional 400 years using the >+ // future specification. Years beyond those can be handled by >+ // mapping back to a cycle-equivalent year within that range. >+ // zic(8) should probably do this so that we don't have to. >+ // TODO: Reduce the extension by the number of compatible >+ // transitions already in place. >+ transitions_.reserve(hdr.timecnt + 400 * 2 + 1); >+ transitions_.resize(hdr.timecnt + 400 * 2); >+ extended_ = true; >+ >+ // The future specification should match the last two transitions, >+ // and those transitions should have different is_dst flags. Note >+ // that nothing says the UTC offset used by the is_dst transition >+ // must be greater than that used by the !is_dst transition. (See >+ // Europe/Dublin, for example.) >+ const Transition* tr0 = &transitions_[hdr.timecnt - 1]; >+ const Transition* tr1 = &transitions_[hdr.timecnt - 2]; >+ const TransitionType* tt0 = &transition_types_[tr0->type_index]; >+ const TransitionType* tt1 = &transition_types_[tr1->type_index]; >+ const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1); >+ const TransitionType& std(tt0->is_dst ? *tt1 : *tt0); >+ CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr); >+ CheckTransition(name, std, posix.std_offset, false, posix.std_abbr); >+ >+ // Add the transitions to tr1 and back to tr0 for each extra year. >+ last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year(); >+ bool leap_year = IsLeap(last_year_); >+ const civil_day jan1(last_year_, 1, 1); >+ std::int_fast64_t jan1_time = civil_second(jan1) - civil_second(); >+ int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7; >+ Transition* tr = &transitions_[hdr.timecnt]; // next trans to fill >+ if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) { >+ // Add a single extra transition to align to a calendar year. >+ transitions_.resize(transitions_.size() + 1); >+ assert(tr == &transitions_[hdr.timecnt]); // no reallocation >+ const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start); >+ std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1); >+ tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset; >+ tr++->type_index = tr1->type_index; >+ tr0 = &transitions_[hdr.timecnt]; >+ tr1 = &transitions_[hdr.timecnt - 1]; >+ tt0 = &transition_types_[tr0->type_index]; >+ tt1 = &transition_types_[tr1->type_index]; >+ } >+ const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start); >+ const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end); >+ for (const year_t limit = last_year_ + 400; last_year_ < limit;) { >+ last_year_ += 1; // an additional year of generated transitions >+ jan1_time += kSecsPerYear[leap_year]; >+ jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7; >+ leap_year = !leap_year && IsLeap(last_year_); >+ std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1); >+ tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset; >+ tr++->type_index = tr1->type_index; >+ std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0); >+ tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset; >+ tr++->type_index = tr0->type_index; >+ } >+ assert(tr == &transitions_[0] + transitions_.size()); >+} >+ >+bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) { >+ // Read and validate the header. >+ tzhead tzh; >+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) >+ return false; >+ if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) >+ return false; >+ Header hdr; >+ if (!hdr.Build(tzh)) >+ return false; >+ std::size_t time_len = 4; >+ if (tzh.tzh_version[0] != '\0') { >+ // Skip the 4-byte data. >+ if (zip->Skip(hdr.DataLength(time_len)) != 0) >+ return false; >+ // Read and validate the header for the 8-byte data. >+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) >+ return false; >+ if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) >+ return false; >+ if (tzh.tzh_version[0] == '\0') >+ return false; >+ if (!hdr.Build(tzh)) >+ return false; >+ time_len = 8; >+ } >+ if (hdr.typecnt == 0) >+ return false; >+ if (hdr.leapcnt != 0) { >+ // This code assumes 60-second minutes so we do not want >+ // the leap-second encoded zoneinfo. We could reverse the >+ // compensation, but the "right" encoding is rarely used >+ // so currently we simply reject such data. >+ return false; >+ } >+ if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) >+ return false; >+ if (hdr.ttisgmtcnt != 0 && hdr.ttisgmtcnt != hdr.typecnt) >+ return false; >+ >+ // Read the data into a local buffer. >+ std::size_t len = hdr.DataLength(time_len); >+ std::vector<char> tbuf(len); >+ if (zip->Read(tbuf.data(), len) != len) >+ return false; >+ const char* bp = tbuf.data(); >+ >+ // Decode and validate the transitions. >+ transitions_.reserve(hdr.timecnt + 2); // We might add a couple. >+ transitions_.resize(hdr.timecnt); >+ for (std::size_t i = 0; i != hdr.timecnt; ++i) { >+ transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp); >+ bp += time_len; >+ if (i != 0) { >+ // Check that the transitions are ordered by time (as zic guarantees). >+ if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) >+ return false; // out of order >+ } >+ } >+ bool seen_type_0 = false; >+ for (std::size_t i = 0; i != hdr.timecnt; ++i) { >+ transitions_[i].type_index = Decode8(bp++); >+ if (transitions_[i].type_index >= hdr.typecnt) >+ return false; >+ if (transitions_[i].type_index == 0) >+ seen_type_0 = true; >+ } >+ >+ // Decode and validate the transition types. >+ transition_types_.resize(hdr.typecnt); >+ for (std::size_t i = 0; i != hdr.typecnt; ++i) { >+ transition_types_[i].utc_offset = >+ static_cast<std::int_least32_t>(Decode32(bp)); >+ if (transition_types_[i].utc_offset >= kSecsPerDay || >+ transition_types_[i].utc_offset <= -kSecsPerDay) >+ return false; >+ bp += 4; >+ transition_types_[i].is_dst = (Decode8(bp++) != 0); >+ transition_types_[i].abbr_index = Decode8(bp++); >+ if (transition_types_[i].abbr_index >= hdr.charcnt) >+ return false; >+ } >+ >+ // Determine the before-first-transition type. >+ default_transition_type_ = 0; >+ if (seen_type_0 && hdr.timecnt != 0) { >+ std::uint_fast8_t index = 0; >+ if (transition_types_[0].is_dst) { >+ index = transitions_[0].type_index; >+ while (index != 0 && transition_types_[index].is_dst) >+ --index; >+ } >+ while (index != hdr.typecnt && transition_types_[index].is_dst) >+ ++index; >+ if (index != hdr.typecnt) >+ default_transition_type_ = index; >+ } >+ >+ // Copy all the abbreviations. >+ abbreviations_.assign(bp, hdr.charcnt); >+ bp += hdr.charcnt; >+ >+ // Skip the unused portions. We've already dispensed with leap-second >+ // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when >+ // interpreting a POSIX spec that does not include start/end rules, and >+ // that isn't the case here (see "zic -p"). >+ bp += (8 + 4) * hdr.leapcnt; // leap-time + TAI-UTC >+ bp += 1 * hdr.ttisstdcnt; // UTC/local indicators >+ bp += 1 * hdr.ttisgmtcnt; // standard/wall indicators >+ assert(bp == tbuf.data() + tbuf.size()); >+ >+ future_spec_.clear(); >+ if (tzh.tzh_version[0] != '\0') { >+ // Snarf up the NL-enclosed future POSIX spec. Note >+ // that version '3' files utilize an extended format. >+ auto get_char = [](ZoneInfoSource* zip) -> int { >+ unsigned char ch; // all non-EOF results are positive >+ return (zip->Read(&ch, 1) == 1) ? ch : EOF; >+ }; >+ if (get_char(zip) != '\n') >+ return false; >+ for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { >+ if (c == EOF) >+ return false; >+ future_spec_.push_back(static_cast<char>(c)); >+ } >+ } >+ >+ // We don't check for EOF so that we're forwards compatible. >+ >+ // If we did not find version information during the standard loading >+ // process (as of tzh_version '3' that is unsupported), then ask the >+ // ZoneInfoSource for any out-of-bound version std::string it may be privy to. >+ if (version_.empty()) { >+ version_ = zip->Version(); >+ } >+ >+ // Trim redundant transitions. zic may have added these to work around >+ // differences between the glibc and reference implementations (see >+ // zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071). >+ // For us, they just get in the way when we do future_spec_ extension. >+ while (hdr.timecnt > 1) { >+ if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, >+ transitions_[hdr.timecnt - 2].type_index)) { >+ break; >+ } >+ hdr.timecnt -= 1; >+ } >+ transitions_.resize(hdr.timecnt); >+ >+ // Ensure that there is always a transition in the first half of the >+ // time line (the second half is handled in ExtendTransitions()) so that >+ // the signed difference between a civil_second and the civil_second of >+ // its previous transition is always representable, without overflow. >+ // A contemporary zic will usually have already done this for us. >+ if (transitions_.empty() || transitions_.front().unix_time >= 0) { >+ Transition& tr(*transitions_.emplace(transitions_.begin())); >+ tr.unix_time = -(1LL << 59); // see tz/zic.c "BIG_BANG" >+ tr.type_index = default_transition_type_; >+ hdr.timecnt += 1; >+ } >+ >+ // Extend the transitions using the future specification. >+ ExtendTransitions(name, hdr); >+ >+ // Compute the local civil time for each transition and the preceding >+ // second. These will be used for reverse conversions in MakeTime(). >+ const TransitionType* ttp = &transition_types_[default_transition_type_]; >+ for (std::size_t i = 0; i != transitions_.size(); ++i) { >+ Transition& tr(transitions_[i]); >+ tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; >+ ttp = &transition_types_[tr.type_index]; >+ tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; >+ if (i != 0) { >+ // Check that the transitions are ordered by civil time. Essentially >+ // this means that an offset change cannot cross another such change. >+ // No one does this in practice, and we depend on it in MakeTime(). >+ if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) >+ return false; // out of order >+ } >+ } >+ >+ // Compute the maximum/minimum civil times that can be converted to a >+ // time_point<seconds> for each of the zone's transition types. >+ for (auto& tt : transition_types_) { >+ tt.civil_max = LocalTime(seconds::max().count(), tt).cs; >+ tt.civil_min = LocalTime(seconds::min().count(), tt).cs; >+ } >+ >+ transitions_.shrink_to_fit(); >+ return true; >+} >+ >+namespace { >+ >+// fopen(3) adaptor. >+inline FILE* FOpen(const char* path, const char* mode) { >+#if defined(_MSC_VER) >+ FILE* fp; >+ if (fopen_s(&fp, path, mode) != 0) fp = nullptr; >+ return fp; >+#else >+ return fopen(path, mode); // TODO: Enable the close-on-exec flag. >+#endif >+} >+ >+// A stdio(3)-backed implementation of ZoneInfoSource. >+class FileZoneInfoSource : public ZoneInfoSource { >+ public: >+ static std::unique_ptr<ZoneInfoSource> Open(const std::string& name); >+ >+ std::size_t Read(void* ptr, std::size_t size) override { >+ size = std::min(size, len_); >+ std::size_t nread = fread(ptr, 1, size, fp_.get()); >+ len_ -= nread; >+ return nread; >+ } >+ int Skip(std::size_t offset) override { >+ offset = std::min(offset, len_); >+ int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR); >+ if (rc == 0) len_ -= offset; >+ return rc; >+ } >+ std::string Version() const override { >+ // TODO: It would nice if the zoneinfo data included the tzdb version. >+ return std::string(); >+ } >+ >+ protected: >+ explicit FileZoneInfoSource( >+ FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max()) >+ : fp_(fp, fclose), len_(len) {} >+ >+ private: >+ std::unique_ptr<FILE, int(*)(FILE*)> fp_; >+ std::size_t len_; >+}; >+ >+std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open( >+ const std::string& name) { >+ // Use of the "file:" prefix is intended for testing purposes only. >+ if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5)); >+ >+ // Map the time-zone name to a path name. >+ std::string path; >+ if (name.empty() || name[0] != '/') { >+ const char* tzdir = "/usr/share/zoneinfo"; >+ char* tzdir_env = nullptr; >+#if defined(_MSC_VER) >+ _dupenv_s(&tzdir_env, nullptr, "TZDIR"); >+#else >+ tzdir_env = std::getenv("TZDIR"); >+#endif >+ if (tzdir_env && *tzdir_env) tzdir = tzdir_env; >+ path += tzdir; >+ path += '/'; >+#if defined(_MSC_VER) >+ free(tzdir_env); >+#endif >+ } >+ path += name; >+ >+ // Open the zoneinfo file. >+ FILE* fp = FOpen(path.c_str(), "rb"); >+ if (fp == nullptr) return nullptr; >+ std::size_t length = 0; >+ if (fseek(fp, 0, SEEK_END) == 0) { >+ long pos = ftell(fp); >+ if (pos >= 0) { >+ length = static_cast<std::size_t>(pos); >+ } >+ rewind(fp); >+ } >+ return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length)); >+} >+ >+class AndroidZoneInfoSource : public FileZoneInfoSource { >+ public: >+ static std::unique_ptr<ZoneInfoSource> Open(const std::string& name); >+ std::string Version() const override { return version_; } >+ >+ private: >+ explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers) >+ : FileZoneInfoSource(fp, len), version_(vers) {} >+ std::string version_; >+}; >+ >+std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open( >+ const std::string& name) { >+ // Use of the "file:" prefix is intended for testing purposes only. >+ if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5)); >+ >+#if defined(__ANDROID__) >+ // See Android's libc/tzcode/bionic.cpp for additional information. >+ for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata", >+ "/system/usr/share/zoneinfo/tzdata"}) { >+ std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose); >+ if (fp.get() == nullptr) continue; >+ >+ char hbuf[24]; // covers header.zonetab_offset too >+ if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue; >+ if (strncmp(hbuf, "tzdata", 6) != 0) continue; >+ const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : ""; >+ const std::int_fast32_t index_offset = Decode32(hbuf + 12); >+ const std::int_fast32_t data_offset = Decode32(hbuf + 16); >+ if (index_offset < 0 || data_offset < index_offset) continue; >+ if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0) >+ continue; >+ >+ char ebuf[52]; // covers entry.unused too >+ const std::size_t index_size = >+ static_cast<std::size_t>(data_offset - index_offset); >+ const std::size_t zonecnt = index_size / sizeof(ebuf); >+ if (zonecnt * sizeof(ebuf) != index_size) continue; >+ for (std::size_t i = 0; i != zonecnt; ++i) { >+ if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break; >+ const std::int_fast32_t start = data_offset + Decode32(ebuf + 40); >+ const std::int_fast32_t length = Decode32(ebuf + 44); >+ if (start < 0 || length < 0) break; >+ ebuf[40] = '\0'; // ensure zone name is NUL terminated >+ if (strcmp(name.c_str(), ebuf) == 0) { >+ if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break; >+ return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource( >+ fp.release(), static_cast<std::size_t>(length), vers)); >+ } >+ } >+ } >+#endif // __ANDROID__ >+ return nullptr; >+} >+ >+} // namespace >+ >+bool TimeZoneInfo::Load(const std::string& name) { >+ // We can ensure that the loading of UTC or any other fixed-offset >+ // zone never fails because the simple, fixed-offset state can be >+ // internally generated. Note that this depends on our choice to not >+ // accept leap-second encoded ("right") zoneinfo. >+ auto offset = seconds::zero(); >+ if (FixedOffsetFromName(name, &offset)) { >+ return ResetToBuiltinUTC(offset); >+ } >+ >+ // Find and use a ZoneInfoSource to load the named zone. >+ auto zip = cctz_extension::zone_info_source_factory( >+ name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> { >+ if (auto zip = FileZoneInfoSource::Open(name)) return zip; >+ if (auto zip = AndroidZoneInfoSource::Open(name)) return zip; >+ return nullptr; >+ }); >+ return zip != nullptr && Load(name, zip.get()); >+} >+ >+// BreakTime() translation for a particular transition type. >+time_zone::absolute_lookup TimeZoneInfo::LocalTime( >+ std::int_fast64_t unix_time, const TransitionType& tt) const { >+ // A civil time in "+offset" looks like (time+offset) in UTC. >+ // Note: We perform two additions in the civil_second domain to >+ // sidestep the chance of overflow in (unix_time + tt.utc_offset). >+ return {(civil_second() + unix_time) + tt.utc_offset, >+ tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]}; >+} >+ >+// BreakTime() translation for a particular transition. >+time_zone::absolute_lookup TimeZoneInfo::LocalTime( >+ std::int_fast64_t unix_time, const Transition& tr) const { >+ const TransitionType& tt = transition_types_[tr.type_index]; >+ // Note: (unix_time - tr.unix_time) will never overflow as we >+ // have ensured that there is always a "nearby" transition. >+ return {tr.civil_sec + (unix_time - tr.unix_time), // TODO: Optimize. >+ tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]}; >+} >+ >+// MakeTime() translation with a conversion-preserving +N * 400-year shift. >+time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs, >+ year_t c4_shift) const { >+ assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_); >+ time_zone::civil_lookup cl = MakeTime(cs); >+ if (c4_shift > seconds::max().count() / kSecsPer400Years) { >+ cl.pre = cl.trans = cl.post = time_point<seconds>::max(); >+ } else { >+ const auto offset = seconds(c4_shift * kSecsPer400Years); >+ const auto limit = time_point<seconds>::max() - offset; >+ for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) { >+ if (*tp > limit) { >+ *tp = time_point<seconds>::max(); >+ } else { >+ *tp += offset; >+ } >+ } >+ } >+ return cl; >+} >+ >+time_zone::absolute_lookup TimeZoneInfo::BreakTime( >+ const time_point<seconds>& tp) const { >+ std::int_fast64_t unix_time = ToUnixSeconds(tp); >+ const std::size_t timecnt = transitions_.size(); >+ assert(timecnt != 0); // We always add a transition. >+ >+ if (unix_time < transitions_[0].unix_time) { >+ return LocalTime(unix_time, transition_types_[default_transition_type_]); >+ } >+ if (unix_time >= transitions_[timecnt - 1].unix_time) { >+ // After the last transition. If we extended the transitions using >+ // future_spec_, shift back to a supported year using the 400-year >+ // cycle of calendaric equivalence and then compensate accordingly. >+ if (extended_) { >+ const std::int_fast64_t diff = >+ unix_time - transitions_[timecnt - 1].unix_time; >+ const year_t shift = diff / kSecsPer400Years + 1; >+ const auto d = seconds(shift * kSecsPer400Years); >+ time_zone::absolute_lookup al = BreakTime(tp - d); >+ al.cs = YearShift(al.cs, shift * 400); >+ return al; >+ } >+ return LocalTime(unix_time, transitions_[timecnt - 1]); >+ } >+ >+ const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed); >+ if (0 < hint && hint < timecnt) { >+ if (transitions_[hint - 1].unix_time <= unix_time) { >+ if (unix_time < transitions_[hint].unix_time) { >+ return LocalTime(unix_time, transitions_[hint - 1]); >+ } >+ } >+ } >+ >+ const Transition target = {unix_time, 0, civil_second(), civil_second()}; >+ const Transition* begin = &transitions_[0]; >+ const Transition* tr = std::upper_bound(begin, begin + timecnt, target, >+ Transition::ByUnixTime()); >+ local_time_hint_.store(static_cast<std::size_t>(tr - begin), >+ std::memory_order_relaxed); >+ return LocalTime(unix_time, *--tr); >+} >+ >+time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const { >+ const std::size_t timecnt = transitions_.size(); >+ assert(timecnt != 0); // We always add a transition. >+ >+ // Find the first transition after our target civil time. >+ const Transition* tr = nullptr; >+ const Transition* begin = &transitions_[0]; >+ const Transition* end = begin + timecnt; >+ if (cs < begin->civil_sec) { >+ tr = begin; >+ } else if (cs >= transitions_[timecnt - 1].civil_sec) { >+ tr = end; >+ } else { >+ const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed); >+ if (0 < hint && hint < timecnt) { >+ if (transitions_[hint - 1].civil_sec <= cs) { >+ if (cs < transitions_[hint].civil_sec) { >+ tr = begin + hint; >+ } >+ } >+ } >+ if (tr == nullptr) { >+ const Transition target = {0, 0, cs, civil_second()}; >+ tr = std::upper_bound(begin, end, target, Transition::ByCivilTime()); >+ time_local_hint_.store(static_cast<std::size_t>(tr - begin), >+ std::memory_order_relaxed); >+ } >+ } >+ >+ if (tr == begin) { >+ if (tr->prev_civil_sec >= cs) { >+ // Before first transition, so use the default offset. >+ const TransitionType& tt(transition_types_[default_transition_type_]); >+ if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min()); >+ return MakeUnique(cs - (civil_second() + tt.utc_offset)); >+ } >+ // tr->prev_civil_sec < cs < tr->civil_sec >+ return MakeSkipped(*tr, cs); >+ } >+ >+ if (tr == end) { >+ if (cs > (--tr)->prev_civil_sec) { >+ // After the last transition. If we extended the transitions using >+ // future_spec_, shift back to a supported year using the 400-year >+ // cycle of calendaric equivalence and then compensate accordingly. >+ if (extended_ && cs.year() > last_year_) { >+ const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1; >+ return TimeLocal(YearShift(cs, shift * -400), shift); >+ } >+ const TransitionType& tt(transition_types_[tr->type_index]); >+ if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max()); >+ return MakeUnique(tr->unix_time + (cs - tr->civil_sec)); >+ } >+ // tr->civil_sec <= cs <= tr->prev_civil_sec >+ return MakeRepeated(*tr, cs); >+ } >+ >+ if (tr->prev_civil_sec < cs) { >+ // tr->prev_civil_sec < cs < tr->civil_sec >+ return MakeSkipped(*tr, cs); >+ } >+ >+ if (cs <= (--tr)->prev_civil_sec) { >+ // tr->civil_sec <= cs <= tr->prev_civil_sec >+ return MakeRepeated(*tr, cs); >+ } >+ >+ // In between transitions. >+ return MakeUnique(tr->unix_time + (cs - tr->civil_sec)); >+} >+ >+std::string TimeZoneInfo::Version() const { >+ return version_; >+} >+ >+std::string TimeZoneInfo::Description() const { >+ std::ostringstream oss; >+ oss << "#trans=" << transitions_.size(); >+ oss << " #types=" << transition_types_.size(); >+ oss << " spec='" << future_spec_ << "'"; >+ return oss.str(); >+} >+ >+bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ if (transitions_.empty()) return false; >+ const Transition* begin = &transitions_[0]; >+ const Transition* end = begin + transitions_.size(); >+ if (begin->unix_time <= -(1LL << 59)) { >+ // Do not report the BIG_BANG found in recent zoneinfo data as it is >+ // really a sentinel, not a transition. See tz/zic.c. >+ ++begin; >+ } >+ std::int_fast64_t unix_time = ToUnixSeconds(tp); >+ const Transition target = { unix_time }; >+ const Transition* tr = std::upper_bound(begin, end, target, >+ Transition::ByUnixTime()); >+ for (; tr != end; ++tr) { // skip no-op transitions >+ std::uint_fast8_t prev_type_index = >+ (tr == begin) ? default_transition_type_ : tr[-1].type_index; >+ if (!EquivTransitions(prev_type_index, tr[0].type_index)) break; >+ } >+ // When tr == end we return false, ignoring future_spec_. >+ if (tr == end) return false; >+ trans->from = tr->prev_civil_sec + 1; >+ trans->to = tr->civil_sec; >+ return true; >+} >+ >+bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ if (transitions_.empty()) return false; >+ const Transition* begin = &transitions_[0]; >+ const Transition* end = begin + transitions_.size(); >+ if (begin->unix_time <= -(1LL << 59)) { >+ // Do not report the BIG_BANG found in recent zoneinfo data as it is >+ // really a sentinel, not a transition. See tz/zic.c. >+ ++begin; >+ } >+ std::int_fast64_t unix_time = ToUnixSeconds(tp); >+ if (FromUnixSeconds(unix_time) != tp) { >+ if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) { >+ if (end == begin) return false; // Ignore future_spec_. >+ trans->from = (--end)->prev_civil_sec + 1; >+ trans->to = end->civil_sec; >+ return true; >+ } >+ unix_time += 1; // ceils >+ } >+ const Transition target = { unix_time }; >+ const Transition* tr = std::lower_bound(begin, end, target, >+ Transition::ByUnixTime()); >+ for (; tr != begin; --tr) { // skip no-op transitions >+ std::uint_fast8_t prev_type_index = >+ (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index; >+ if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break; >+ } >+ // When tr == end we return the "last" transition, ignoring future_spec_. >+ if (tr == begin) return false; >+ trans->from = (--tr)->prev_civil_sec + 1; >+ trans->to = tr->civil_sec; >+ return true; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.h >new file mode 100644 >index 00000000000..958e9b6bd74 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_info.h >@@ -0,0 +1,136 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ >+ >+#include <atomic> >+#include <cstddef> >+#include <cstdint> >+#include <string> >+#include <vector> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" >+#include "time_zone_if.h" >+#include "tzfile.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// A transition to a new UTC offset. >+struct Transition { >+ std::int_least64_t unix_time; // the instant of this transition >+ std::uint_least8_t type_index; // index of the transition type >+ civil_second civil_sec; // local civil time of transition >+ civil_second prev_civil_sec; // local civil time one second earlier >+ >+ struct ByUnixTime { >+ inline bool operator()(const Transition& lhs, const Transition& rhs) const { >+ return lhs.unix_time < rhs.unix_time; >+ } >+ }; >+ struct ByCivilTime { >+ inline bool operator()(const Transition& lhs, const Transition& rhs) const { >+ return lhs.civil_sec < rhs.civil_sec; >+ } >+ }; >+}; >+ >+// The characteristics of a particular transition. >+struct TransitionType { >+ std::int_least32_t utc_offset; // the new prevailing UTC offset >+ civil_second civil_max; // max convertible civil time for offset >+ civil_second civil_min; // min convertible civil time for offset >+ bool is_dst; // did we move into daylight-saving time >+ std::uint_least8_t abbr_index; // index of the new abbreviation >+}; >+ >+// A time zone backed by the IANA Time Zone Database (zoneinfo). >+class TimeZoneInfo : public TimeZoneIf { >+ public: >+ TimeZoneInfo() = default; >+ TimeZoneInfo(const TimeZoneInfo&) = delete; >+ TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; >+ >+ // Loads the zoneinfo for the given name, returning true if successful. >+ bool Load(const std::string& name); >+ >+ // TimeZoneIf implementations. >+ time_zone::absolute_lookup BreakTime( >+ const time_point<seconds>& tp) const override; >+ time_zone::civil_lookup MakeTime( >+ const civil_second& cs) const override; >+ bool NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const override; >+ bool PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const override; >+ std::string Version() const override; >+ std::string Description() const override; >+ >+ private: >+ struct Header { // counts of: >+ std::size_t timecnt; // transition times >+ std::size_t typecnt; // transition types >+ std::size_t charcnt; // zone abbreviation characters >+ std::size_t leapcnt; // leap seconds (we expect none) >+ std::size_t ttisstdcnt; // UTC/local indicators (unused) >+ std::size_t ttisgmtcnt; // standard/wall indicators (unused) >+ >+ bool Build(const tzhead& tzh); >+ std::size_t DataLength(std::size_t time_len) const; >+ }; >+ >+ void CheckTransition(const std::string& name, const TransitionType& tt, >+ std::int_fast32_t offset, bool is_dst, >+ const std::string& abbr) const; >+ bool EquivTransitions(std::uint_fast8_t tt1_index, >+ std::uint_fast8_t tt2_index) const; >+ void ExtendTransitions(const std::string& name, const Header& hdr); >+ >+ bool ResetToBuiltinUTC(const seconds& offset); >+ bool Load(const std::string& name, ZoneInfoSource* zip); >+ >+ // Helpers for BreakTime() and MakeTime(). >+ time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time, >+ const TransitionType& tt) const; >+ time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time, >+ const Transition& tr) const; >+ time_zone::civil_lookup TimeLocal(const civil_second& cs, >+ year_t c4_shift) const; >+ >+ std::vector<Transition> transitions_; // ordered by unix_time and civil_sec >+ std::vector<TransitionType> transition_types_; // distinct transition types >+ std::uint_fast8_t default_transition_type_; // for before first transition >+ std::string abbreviations_; // all the NUL-terminated abbreviations >+ >+ std::string version_; // the tzdata version if available >+ std::string future_spec_; // for after the last zic transition >+ bool extended_; // future_spec_ was used to generate transitions >+ year_t last_year_; // the final year of the generated transitions >+ >+ // We remember the transitions found during the last BreakTime() and >+ // MakeTime() calls. If the next request is for the same transition we >+ // will avoid re-searching. >+ mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint >+ mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint >+}; >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc >new file mode 100644 >index 00000000000..074c8d0a4a4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc >@@ -0,0 +1,162 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#if defined(_WIN32) || defined(_WIN64) >+#define _CRT_SECURE_NO_WARNINGS 1 >+#endif >+ >+#include "time_zone_libc.h" >+ >+#include <chrono> >+#include <ctime> >+#include <tuple> >+#include <utility> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+// .first is seconds east of UTC; .second is the time-zone abbreviation. >+using OffsetAbbr = std::pair<int, const char*>; >+ >+// Defines a function that can be called as follows: >+// >+// std::tm tm = ...; >+// OffsetAbbr off_abbr = get_offset_abbr(tm); >+// >+#if defined(_WIN32) || defined(_WIN64) >+// Uses the globals: '_timezone', '_dstbias' and '_tzname'. >+OffsetAbbr get_offset_abbr(const std::tm& tm) { >+ const bool is_dst = tm.tm_isdst > 0; >+ const int off = _timezone + (is_dst ? _dstbias : 0); >+ const char* abbr = _tzname[is_dst]; >+ return {off, abbr}; >+} >+#elif defined(__sun) >+// Uses the globals: 'timezone', 'altzone' and 'tzname'. >+OffsetAbbr get_offset_abbr(const std::tm& tm) { >+ const bool is_dst = tm.tm_isdst > 0; >+ const int off = is_dst ? altzone : timezone; >+ const char* abbr = tzname[is_dst]; >+ return {off, abbr}; >+} >+#elif defined(__native_client__) || defined(__myriad2__) || \ >+ defined(__EMSCRIPTEN__) >+// Uses the globals: 'timezone' and 'tzname'. >+OffsetAbbr get_offset_abbr(const std::tm& tm) { >+ const bool is_dst = tm.tm_isdst > 0; >+ const int off = _timezone + (is_dst ? 60 * 60 : 0); >+ const char* abbr = tzname[is_dst]; >+ return {off, abbr}; >+} >+#else >+// >+// Returns an OffsetAbbr using std::tm fields with various spellings. >+// >+#if !defined(tm_gmtoff) && !defined(tm_zone) >+template <typename T> >+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::tm_gmtoff) = nullptr, >+ decltype(&T::tm_zone) = nullptr) { >+ return {tm.tm_gmtoff, tm.tm_zone}; >+} >+#endif // !defined(tm_gmtoff) && !defined(tm_zone) >+#if !defined(__tm_gmtoff) && !defined(__tm_zone) >+template <typename T> >+OffsetAbbr get_offset_abbr(const T& tm, decltype(&T::__tm_gmtoff) = nullptr, >+ decltype(&T::__tm_zone) = nullptr) { >+ return {tm.__tm_gmtoff, tm.__tm_zone}; >+} >+#endif // !defined(__tm_gmtoff) && !defined(__tm_zone) >+#endif >+ >+} // namespace >+ >+TimeZoneLibC::TimeZoneLibC(const std::string& name) >+ : local_(name == "localtime") {} >+ >+time_zone::absolute_lookup TimeZoneLibC::BreakTime( >+ const time_point<seconds>& tp) const { >+ time_zone::absolute_lookup al; >+ std::time_t t = ToUnixSeconds(tp); >+ std::tm tm; >+ if (local_) { >+#if defined(_WIN32) || defined(_WIN64) >+ localtime_s(&tm, &t); >+#else >+ localtime_r(&t, &tm); >+#endif >+ std::tie(al.offset, al.abbr) = get_offset_abbr(tm); >+ } else { >+#if defined(_WIN32) || defined(_WIN64) >+ gmtime_s(&tm, &t); >+#else >+ gmtime_r(&t, &tm); >+#endif >+ al.offset = 0; >+ al.abbr = "UTC"; >+ } >+ al.cs = civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, >+ tm.tm_hour, tm.tm_min, tm.tm_sec); >+ al.is_dst = tm.tm_isdst > 0; >+ return al; >+} >+ >+time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { >+ time_zone::civil_lookup cl; >+ std::time_t t; >+ if (local_) { >+ // Does not handle SKIPPED/AMBIGUOUS or huge years. >+ std::tm tm; >+ tm.tm_year = static_cast<int>(cs.year() - 1900); >+ tm.tm_mon = cs.month() - 1; >+ tm.tm_mday = cs.day(); >+ tm.tm_hour = cs.hour(); >+ tm.tm_min = cs.minute(); >+ tm.tm_sec = cs.second(); >+ tm.tm_isdst = -1; >+ t = std::mktime(&tm); >+ } else { >+ t = cs - civil_second(); >+ } >+ cl.kind = time_zone::civil_lookup::UNIQUE; >+ cl.pre = cl.trans = cl.post = FromUnixSeconds(t); >+ return cl; >+} >+ >+bool TimeZoneLibC::NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ return false; >+} >+ >+bool TimeZoneLibC::PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const { >+ return false; >+} >+ >+std::string TimeZoneLibC::Version() const { >+ return std::string(); // unknown >+} >+ >+std::string TimeZoneLibC::Description() const { >+ return local_ ? "localtime" : "UTC"; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.h >new file mode 100644 >index 00000000000..4e40c61ab24 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.h >@@ -0,0 +1,53 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ >+ >+#include <string> >+ >+#include "time_zone_if.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3), >+// and which therefore only supports UTC and the local time zone. >+// TODO: Add support for fixed offsets from UTC. >+class TimeZoneLibC : public TimeZoneIf { >+ public: >+ explicit TimeZoneLibC(const std::string& name); >+ >+ // TimeZoneIf implementations. >+ time_zone::absolute_lookup BreakTime( >+ const time_point<seconds>& tp) const override; >+ time_zone::civil_lookup MakeTime( >+ const civil_second& cs) const override; >+ bool NextTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const override; >+ bool PrevTransition(const time_point<seconds>& tp, >+ time_zone::civil_transition* trans) const override; >+ std::string Version() const override; >+ std::string Description() const override; >+ >+ private: >+ const bool local_; // localtime or UTC >+}; >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc >new file mode 100644 >index 00000000000..f2d151e4d5e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup.cc >@@ -0,0 +1,168 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+#if defined(__ANDROID__) >+#include <sys/system_properties.h> >+#if __ANDROID_API__ >= 21 >+#include <dlfcn.h> >+#endif >+#endif >+#include <cstdlib> >+#include <cstring> >+#include <string> >+ >+#include "time_zone_fixed.h" >+#include "time_zone_impl.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+#if defined(__ANDROID__) && __ANDROID_API__ >= 21 >+namespace { >+// Android 'L' removes __system_property_get() from the NDK, however >+// it is still a hidden symbol in libc so we use dlsym() to access it. >+// See Chromium's base/sys_info_android.cc for a similar example. >+ >+using property_get_func = int (*)(const char*, char*); >+ >+property_get_func LoadSystemPropertyGet() { >+ int flag = RTLD_LAZY | RTLD_GLOBAL; >+#if defined(RTLD_NOLOAD) >+ flag |= RTLD_NOLOAD; // libc.so should already be resident >+#endif >+ if (void* handle = dlopen("libc.so", flag)) { >+ void* sym = dlsym(handle, "__system_property_get"); >+ dlclose(handle); >+ return reinterpret_cast<property_get_func>(sym); >+ } >+ return nullptr; >+} >+ >+int __system_property_get(const char* name, char* value) { >+ static property_get_func system_property_get = LoadSystemPropertyGet(); >+ return system_property_get ? system_property_get(name, value) : -1; >+} >+ >+} // namespace >+#endif >+ >+std::string time_zone::name() const { >+ return effective_impl().Name(); >+} >+ >+time_zone::absolute_lookup time_zone::lookup( >+ const time_point<seconds>& tp) const { >+ return effective_impl().BreakTime(tp); >+} >+ >+time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const { >+ return effective_impl().MakeTime(cs); >+} >+ >+bool time_zone::next_transition(const time_point<seconds>& tp, >+ civil_transition* trans) const { >+ return effective_impl().NextTransition(tp, trans); >+} >+ >+bool time_zone::prev_transition(const time_point<seconds>& tp, >+ civil_transition* trans) const { >+ return effective_impl().PrevTransition(tp, trans); >+} >+ >+std::string time_zone::version() const { >+ return effective_impl().Version(); >+} >+ >+std::string time_zone::description() const { >+ return effective_impl().Description(); >+} >+ >+const time_zone::Impl& time_zone::effective_impl() const { >+ if (impl_ == nullptr) { >+ // Dereferencing an implicit-UTC time_zone is expected to be >+ // rare, so we don't mind paying a small synchronization cost. >+ return *time_zone::Impl::UTC().impl_; >+ } >+ return *impl_; >+} >+ >+bool load_time_zone(const std::string& name, time_zone* tz) { >+ return time_zone::Impl::LoadTimeZone(name, tz); >+} >+ >+time_zone utc_time_zone() { >+ return time_zone::Impl::UTC(); // avoid name lookup >+} >+ >+time_zone fixed_time_zone(const seconds& offset) { >+ time_zone tz; >+ load_time_zone(FixedOffsetToName(offset), &tz); >+ return tz; >+} >+ >+time_zone local_time_zone() { >+ const char* zone = ":localtime"; >+ >+ // Allow ${TZ} to override to default zone. >+ char* tz_env = nullptr; >+#if defined(_MSC_VER) >+ _dupenv_s(&tz_env, nullptr, "TZ"); >+#else >+ tz_env = std::getenv("TZ"); >+#endif >+#if defined(__ANDROID__) >+ char sysprop[PROP_VALUE_MAX]; >+ if (tz_env == nullptr) >+ if (__system_property_get("persist.sys.timezone", sysprop) > 0) >+ tz_env = sysprop; >+#endif >+ if (tz_env) zone = tz_env; >+ >+ // We only support the "[:]<zone-name>" form. >+ if (*zone == ':') ++zone; >+ >+ // Map "localtime" to a system-specific name, but >+ // allow ${LOCALTIME} to override the default name. >+ char* localtime_env = nullptr; >+ if (strcmp(zone, "localtime") == 0) { >+#if defined(_MSC_VER) >+ // System-specific default is just "localtime". >+ _dupenv_s(&localtime_env, nullptr, "LOCALTIME"); >+#else >+ zone = "/etc/localtime"; // System-specific default. >+ localtime_env = std::getenv("LOCALTIME"); >+#endif >+ if (localtime_env) zone = localtime_env; >+ } >+ >+ const std::string name = zone; >+#if defined(_MSC_VER) >+ free(localtime_env); >+ free(tz_env); >+#endif >+ >+ time_zone tz; >+ load_time_zone(name, &tz); // Falls back to UTC. >+ // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and >+ // arrange for %z to generate "-0000" when we don't know the local >+ // offset because the load_time_zone() failed and we're using UTC. >+ return tz; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc >new file mode 100644 >index 00000000000..551292fb55e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc >@@ -0,0 +1,1331 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+#include <chrono> >+#include <cstddef> >+#include <future> >+#include <string> >+#include <thread> >+#include <vector> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "gtest/gtest.h" >+ >+namespace chrono = std::chrono; >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+// A list of known time-zone names. >+const char* const kTimeZoneNames[] = { >+ "Africa/Abidjan", >+ "Africa/Accra", >+ "Africa/Addis_Ababa", >+ "Africa/Algiers", >+ "Africa/Asmara", >+ "Africa/Asmera", >+ "Africa/Bamako", >+ "Africa/Bangui", >+ "Africa/Banjul", >+ "Africa/Bissau", >+ "Africa/Blantyre", >+ "Africa/Brazzaville", >+ "Africa/Bujumbura", >+ "Africa/Cairo", >+ "Africa/Casablanca", >+ "Africa/Ceuta", >+ "Africa/Conakry", >+ "Africa/Dakar", >+ "Africa/Dar_es_Salaam", >+ "Africa/Djibouti", >+ "Africa/Douala", >+ "Africa/El_Aaiun", >+ "Africa/Freetown", >+ "Africa/Gaborone", >+ "Africa/Harare", >+ "Africa/Johannesburg", >+ "Africa/Juba", >+ "Africa/Kampala", >+ "Africa/Khartoum", >+ "Africa/Kigali", >+ "Africa/Kinshasa", >+ "Africa/Lagos", >+ "Africa/Libreville", >+ "Africa/Lome", >+ "Africa/Luanda", >+ "Africa/Lubumbashi", >+ "Africa/Lusaka", >+ "Africa/Malabo", >+ "Africa/Maputo", >+ "Africa/Maseru", >+ "Africa/Mbabane", >+ "Africa/Mogadishu", >+ "Africa/Monrovia", >+ "Africa/Nairobi", >+ "Africa/Ndjamena", >+ "Africa/Niamey", >+ "Africa/Nouakchott", >+ "Africa/Ouagadougou", >+ "Africa/Porto-Novo", >+ "Africa/Sao_Tome", >+ "Africa/Timbuktu", >+ "Africa/Tripoli", >+ "Africa/Tunis", >+ "Africa/Windhoek", >+ "America/Adak", >+ "America/Anchorage", >+ "America/Anguilla", >+ "America/Antigua", >+ "America/Araguaina", >+ "America/Argentina/Buenos_Aires", >+ "America/Argentina/Catamarca", >+ "America/Argentina/ComodRivadavia", >+ "America/Argentina/Cordoba", >+ "America/Argentina/Jujuy", >+ "America/Argentina/La_Rioja", >+ "America/Argentina/Mendoza", >+ "America/Argentina/Rio_Gallegos", >+ "America/Argentina/Salta", >+ "America/Argentina/San_Juan", >+ "America/Argentina/San_Luis", >+ "America/Argentina/Tucuman", >+ "America/Argentina/Ushuaia", >+ "America/Aruba", >+ "America/Asuncion", >+ "America/Atikokan", >+ "America/Atka", >+ "America/Bahia", >+ "America/Bahia_Banderas", >+ "America/Barbados", >+ "America/Belem", >+ "America/Belize", >+ "America/Blanc-Sablon", >+ "America/Boa_Vista", >+ "America/Bogota", >+ "America/Boise", >+ "America/Buenos_Aires", >+ "America/Cambridge_Bay", >+ "America/Campo_Grande", >+ "America/Cancun", >+ "America/Caracas", >+ "America/Catamarca", >+ "America/Cayenne", >+ "America/Cayman", >+ "America/Chicago", >+ "America/Chihuahua", >+ "America/Coral_Harbour", >+ "America/Cordoba", >+ "America/Costa_Rica", >+ "America/Creston", >+ "America/Cuiaba", >+ "America/Curacao", >+ "America/Danmarkshavn", >+ "America/Dawson", >+ "America/Dawson_Creek", >+ "America/Denver", >+ "America/Detroit", >+ "America/Dominica", >+ "America/Edmonton", >+ "America/Eirunepe", >+ "America/El_Salvador", >+ "America/Ensenada", >+ "America/Fort_Nelson", >+ "America/Fort_Wayne", >+ "America/Fortaleza", >+ "America/Glace_Bay", >+ "America/Godthab", >+ "America/Goose_Bay", >+ "America/Grand_Turk", >+ "America/Grenada", >+ "America/Guadeloupe", >+ "America/Guatemala", >+ "America/Guayaquil", >+ "America/Guyana", >+ "America/Halifax", >+ "America/Havana", >+ "America/Hermosillo", >+ "America/Indiana/Indianapolis", >+ "America/Indiana/Knox", >+ "America/Indiana/Marengo", >+ "America/Indiana/Petersburg", >+ "America/Indiana/Tell_City", >+ "America/Indiana/Vevay", >+ "America/Indiana/Vincennes", >+ "America/Indiana/Winamac", >+ "America/Indianapolis", >+ "America/Inuvik", >+ "America/Iqaluit", >+ "America/Jamaica", >+ "America/Jujuy", >+ "America/Juneau", >+ "America/Kentucky/Louisville", >+ "America/Kentucky/Monticello", >+ "America/Knox_IN", >+ "America/Kralendijk", >+ "America/La_Paz", >+ "America/Lima", >+ "America/Los_Angeles", >+ "America/Louisville", >+ "America/Lower_Princes", >+ "America/Maceio", >+ "America/Managua", >+ "America/Manaus", >+ "America/Marigot", >+ "America/Martinique", >+ "America/Matamoros", >+ "America/Mazatlan", >+ "America/Mendoza", >+ "America/Menominee", >+ "America/Merida", >+ "America/Metlakatla", >+ "America/Mexico_City", >+ "America/Miquelon", >+ "America/Moncton", >+ "America/Monterrey", >+ "America/Montevideo", >+ "America/Montreal", >+ "America/Montserrat", >+ "America/Nassau", >+ "America/New_York", >+ "America/Nipigon", >+ "America/Nome", >+ "America/Noronha", >+ "America/North_Dakota/Beulah", >+ "America/North_Dakota/Center", >+ "America/North_Dakota/New_Salem", >+ "America/Ojinaga", >+ "America/Panama", >+ "America/Pangnirtung", >+ "America/Paramaribo", >+ "America/Phoenix", >+ "America/Port-au-Prince", >+ "America/Port_of_Spain", >+ "America/Porto_Acre", >+ "America/Porto_Velho", >+ "America/Puerto_Rico", >+ "America/Punta_Arenas", >+ "America/Rainy_River", >+ "America/Rankin_Inlet", >+ "America/Recife", >+ "America/Regina", >+ "America/Resolute", >+ "America/Rio_Branco", >+ "America/Rosario", >+ "America/Santa_Isabel", >+ "America/Santarem", >+ "America/Santiago", >+ "America/Santo_Domingo", >+ "America/Sao_Paulo", >+ "America/Scoresbysund", >+ "America/Shiprock", >+ "America/Sitka", >+ "America/St_Barthelemy", >+ "America/St_Johns", >+ "America/St_Kitts", >+ "America/St_Lucia", >+ "America/St_Thomas", >+ "America/St_Vincent", >+ "America/Swift_Current", >+ "America/Tegucigalpa", >+ "America/Thule", >+ "America/Thunder_Bay", >+ "America/Tijuana", >+ "America/Toronto", >+ "America/Tortola", >+ "America/Vancouver", >+ "America/Virgin", >+ "America/Whitehorse", >+ "America/Winnipeg", >+ "America/Yakutat", >+ "America/Yellowknife", >+ "Antarctica/Casey", >+ "Antarctica/Davis", >+ "Antarctica/DumontDUrville", >+ "Antarctica/Macquarie", >+ "Antarctica/Mawson", >+ "Antarctica/McMurdo", >+ "Antarctica/Palmer", >+ "Antarctica/Rothera", >+ "Antarctica/South_Pole", >+ "Antarctica/Syowa", >+ "Antarctica/Troll", >+ "Antarctica/Vostok", >+ "Arctic/Longyearbyen", >+ "Asia/Aden", >+ "Asia/Almaty", >+ "Asia/Amman", >+ "Asia/Anadyr", >+ "Asia/Aqtau", >+ "Asia/Aqtobe", >+ "Asia/Ashgabat", >+ "Asia/Ashkhabad", >+ "Asia/Atyrau", >+ "Asia/Baghdad", >+ "Asia/Bahrain", >+ "Asia/Baku", >+ "Asia/Bangkok", >+ "Asia/Barnaul", >+ "Asia/Beirut", >+ "Asia/Bishkek", >+ "Asia/Brunei", >+ "Asia/Calcutta", >+ "Asia/Chita", >+ "Asia/Choibalsan", >+ "Asia/Chongqing", >+ "Asia/Chungking", >+ "Asia/Colombo", >+ "Asia/Dacca", >+ "Asia/Damascus", >+ "Asia/Dhaka", >+ "Asia/Dili", >+ "Asia/Dubai", >+ "Asia/Dushanbe", >+ "Asia/Famagusta", >+ "Asia/Gaza", >+ "Asia/Harbin", >+ "Asia/Hebron", >+ "Asia/Ho_Chi_Minh", >+ "Asia/Hong_Kong", >+ "Asia/Hovd", >+ "Asia/Irkutsk", >+ "Asia/Istanbul", >+ "Asia/Jakarta", >+ "Asia/Jayapura", >+ "Asia/Jerusalem", >+ "Asia/Kabul", >+ "Asia/Kamchatka", >+ "Asia/Karachi", >+ "Asia/Kashgar", >+ "Asia/Kathmandu", >+ "Asia/Katmandu", >+ "Asia/Khandyga", >+ "Asia/Kolkata", >+ "Asia/Krasnoyarsk", >+ "Asia/Kuala_Lumpur", >+ "Asia/Kuching", >+ "Asia/Kuwait", >+ "Asia/Macao", >+ "Asia/Macau", >+ "Asia/Magadan", >+ "Asia/Makassar", >+ "Asia/Manila", >+ "Asia/Muscat", >+ "Asia/Nicosia", >+ "Asia/Novokuznetsk", >+ "Asia/Novosibirsk", >+ "Asia/Omsk", >+ "Asia/Oral", >+ "Asia/Phnom_Penh", >+ "Asia/Pontianak", >+ "Asia/Pyongyang", >+ "Asia/Qatar", >+ "Asia/Qyzylorda", >+ "Asia/Rangoon", >+ "Asia/Riyadh", >+ "Asia/Saigon", >+ "Asia/Sakhalin", >+ "Asia/Samarkand", >+ "Asia/Seoul", >+ "Asia/Shanghai", >+ "Asia/Singapore", >+ "Asia/Srednekolymsk", >+ "Asia/Taipei", >+ "Asia/Tashkent", >+ "Asia/Tbilisi", >+ "Asia/Tehran", >+ "Asia/Tel_Aviv", >+ "Asia/Thimbu", >+ "Asia/Thimphu", >+ "Asia/Tokyo", >+ "Asia/Tomsk", >+ "Asia/Ujung_Pandang", >+ "Asia/Ulaanbaatar", >+ "Asia/Ulan_Bator", >+ "Asia/Urumqi", >+ "Asia/Ust-Nera", >+ "Asia/Vientiane", >+ "Asia/Vladivostok", >+ "Asia/Yakutsk", >+ "Asia/Yangon", >+ "Asia/Yekaterinburg", >+ "Asia/Yerevan", >+ "Atlantic/Azores", >+ "Atlantic/Bermuda", >+ "Atlantic/Canary", >+ "Atlantic/Cape_Verde", >+ "Atlantic/Faeroe", >+ "Atlantic/Faroe", >+ "Atlantic/Jan_Mayen", >+ "Atlantic/Madeira", >+ "Atlantic/Reykjavik", >+ "Atlantic/South_Georgia", >+ "Atlantic/St_Helena", >+ "Atlantic/Stanley", >+ "Australia/ACT", >+ "Australia/Adelaide", >+ "Australia/Brisbane", >+ "Australia/Broken_Hill", >+ "Australia/Canberra", >+ "Australia/Currie", >+ "Australia/Darwin", >+ "Australia/Eucla", >+ "Australia/Hobart", >+ "Australia/LHI", >+ "Australia/Lindeman", >+ "Australia/Lord_Howe", >+ "Australia/Melbourne", >+ "Australia/NSW", >+ "Australia/North", >+ "Australia/Perth", >+ "Australia/Queensland", >+ "Australia/South", >+ "Australia/Sydney", >+ "Australia/Tasmania", >+ "Australia/Victoria", >+ "Australia/West", >+ "Australia/Yancowinna", >+ "Brazil/Acre", >+ "Brazil/DeNoronha", >+ "Brazil/East", >+ "Brazil/West", >+ "CET", >+ "CST6CDT", >+ "Canada/Atlantic", >+ "Canada/Central", >+ "Canada/Eastern", >+ "Canada/Mountain", >+ "Canada/Newfoundland", >+ "Canada/Pacific", >+ "Canada/Saskatchewan", >+ "Canada/Yukon", >+ "Chile/Continental", >+ "Chile/EasterIsland", >+ "Cuba", >+ "EET", >+ "EST", >+ "EST5EDT", >+ "Egypt", >+ "Eire", >+ "Etc/GMT", >+ "Etc/GMT+0", >+ "Etc/GMT+1", >+ "Etc/GMT+10", >+ "Etc/GMT+11", >+ "Etc/GMT+12", >+ "Etc/GMT+2", >+ "Etc/GMT+3", >+ "Etc/GMT+4", >+ "Etc/GMT+5", >+ "Etc/GMT+6", >+ "Etc/GMT+7", >+ "Etc/GMT+8", >+ "Etc/GMT+9", >+ "Etc/GMT-0", >+ "Etc/GMT-1", >+ "Etc/GMT-10", >+ "Etc/GMT-11", >+ "Etc/GMT-12", >+ "Etc/GMT-13", >+ "Etc/GMT-14", >+ "Etc/GMT-2", >+ "Etc/GMT-3", >+ "Etc/GMT-4", >+ "Etc/GMT-5", >+ "Etc/GMT-6", >+ "Etc/GMT-7", >+ "Etc/GMT-8", >+ "Etc/GMT-9", >+ "Etc/GMT0", >+ "Etc/Greenwich", >+ "Etc/UCT", >+ "Etc/UTC", >+ "Etc/Universal", >+ "Etc/Zulu", >+ "Europe/Amsterdam", >+ "Europe/Andorra", >+ "Europe/Astrakhan", >+ "Europe/Athens", >+ "Europe/Belfast", >+ "Europe/Belgrade", >+ "Europe/Berlin", >+ "Europe/Bratislava", >+ "Europe/Brussels", >+ "Europe/Bucharest", >+ "Europe/Budapest", >+ "Europe/Busingen", >+ "Europe/Chisinau", >+ "Europe/Copenhagen", >+ "Europe/Dublin", >+ "Europe/Gibraltar", >+ "Europe/Guernsey", >+ "Europe/Helsinki", >+ "Europe/Isle_of_Man", >+ "Europe/Istanbul", >+ "Europe/Jersey", >+ "Europe/Kaliningrad", >+ "Europe/Kiev", >+ "Europe/Kirov", >+ "Europe/Lisbon", >+ "Europe/Ljubljana", >+ "Europe/London", >+ "Europe/Luxembourg", >+ "Europe/Madrid", >+ "Europe/Malta", >+ "Europe/Mariehamn", >+ "Europe/Minsk", >+ "Europe/Monaco", >+ "Europe/Moscow", >+ "Europe/Nicosia", >+ "Europe/Oslo", >+ "Europe/Paris", >+ "Europe/Podgorica", >+ "Europe/Prague", >+ "Europe/Riga", >+ "Europe/Rome", >+ "Europe/Samara", >+ "Europe/San_Marino", >+ "Europe/Sarajevo", >+ "Europe/Saratov", >+ "Europe/Simferopol", >+ "Europe/Skopje", >+ "Europe/Sofia", >+ "Europe/Stockholm", >+ "Europe/Tallinn", >+ "Europe/Tirane", >+ "Europe/Tiraspol", >+ "Europe/Ulyanovsk", >+ "Europe/Uzhgorod", >+ "Europe/Vaduz", >+ "Europe/Vatican", >+ "Europe/Vienna", >+ "Europe/Vilnius", >+ "Europe/Volgograd", >+ "Europe/Warsaw", >+ "Europe/Zagreb", >+ "Europe/Zaporozhye", >+ "Europe/Zurich", >+ "GB", >+ "GB-Eire", >+ "GMT", >+ "GMT+0", >+ "GMT-0", >+ "GMT0", >+ "Greenwich", >+ "HST", >+ "Hongkong", >+ "Iceland", >+ "Indian/Antananarivo", >+ "Indian/Chagos", >+ "Indian/Christmas", >+ "Indian/Cocos", >+ "Indian/Comoro", >+ "Indian/Kerguelen", >+ "Indian/Mahe", >+ "Indian/Maldives", >+ "Indian/Mauritius", >+ "Indian/Mayotte", >+ "Indian/Reunion", >+ "Iran", >+ "Israel", >+ "Jamaica", >+ "Japan", >+ "Kwajalein", >+ "Libya", >+ "MET", >+ "MST", >+ "MST7MDT", >+ "Mexico/BajaNorte", >+ "Mexico/BajaSur", >+ "Mexico/General", >+ "NZ", >+ "NZ-CHAT", >+ "Navajo", >+ "PRC", >+ "PST8PDT", >+ "Pacific/Apia", >+ "Pacific/Auckland", >+ "Pacific/Bougainville", >+ "Pacific/Chatham", >+ "Pacific/Chuuk", >+ "Pacific/Easter", >+ "Pacific/Efate", >+ "Pacific/Enderbury", >+ "Pacific/Fakaofo", >+ "Pacific/Fiji", >+ "Pacific/Funafuti", >+ "Pacific/Galapagos", >+ "Pacific/Gambier", >+ "Pacific/Guadalcanal", >+ "Pacific/Guam", >+ "Pacific/Honolulu", >+ "Pacific/Johnston", >+ "Pacific/Kiritimati", >+ "Pacific/Kosrae", >+ "Pacific/Kwajalein", >+ "Pacific/Majuro", >+ "Pacific/Marquesas", >+ "Pacific/Midway", >+ "Pacific/Nauru", >+ "Pacific/Niue", >+ "Pacific/Norfolk", >+ "Pacific/Noumea", >+ "Pacific/Pago_Pago", >+ "Pacific/Palau", >+ "Pacific/Pitcairn", >+ "Pacific/Pohnpei", >+ "Pacific/Ponape", >+ "Pacific/Port_Moresby", >+ "Pacific/Rarotonga", >+ "Pacific/Saipan", >+ "Pacific/Samoa", >+ "Pacific/Tahiti", >+ "Pacific/Tarawa", >+ "Pacific/Tongatapu", >+ "Pacific/Truk", >+ "Pacific/Wake", >+ "Pacific/Wallis", >+ "Pacific/Yap", >+ "Poland", >+ "Portugal", >+ "ROC", >+ "ROK", >+ "Singapore", >+ "Turkey", >+ "UCT", >+ "US/Alaska", >+ "US/Aleutian", >+ "US/Arizona", >+ "US/Central", >+ "US/East-Indiana", >+ "US/Eastern", >+ "US/Hawaii", >+ "US/Indiana-Starke", >+ "US/Michigan", >+ "US/Mountain", >+ "US/Pacific", >+ "US/Samoa", >+ "UTC", >+ "Universal", >+ "W-SU", >+ "WET", >+ "Zulu", >+ nullptr >+}; >+ >+// Helper to return a loaded time zone by value (UTC on error). >+time_zone LoadZone(const std::string& name) { >+ time_zone tz; >+ load_time_zone(name, &tz); >+ return tz; >+} >+ >+// This helper is a macro so that failed expectations show up with the >+// correct line numbers. >+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \ >+ do { \ >+ time_zone::absolute_lookup al = tz.lookup(tp); \ >+ EXPECT_EQ(y, al.cs.year()); \ >+ EXPECT_EQ(m, al.cs.month()); \ >+ EXPECT_EQ(d, al.cs.day()); \ >+ EXPECT_EQ(hh, al.cs.hour()); \ >+ EXPECT_EQ(mm, al.cs.minute()); \ >+ EXPECT_EQ(ss, al.cs.second()); \ >+ EXPECT_EQ(off, al.offset); \ >+ EXPECT_TRUE(isdst == al.is_dst); \ >+ /* EXPECT_STREQ(zone, al.abbr); */ \ >+ } while (0) >+ >+// These tests sometimes run on platforms that have zoneinfo data so old >+// that the transition we are attempting to check does not exist, most >+// notably Android emulators. Fortunately, AndroidZoneInfoSource supports >+// time_zone::version() so, in cases where we've learned that it matters, >+// we can make the check conditionally. >+int VersionCmp(time_zone tz, const std::string& target) { >+ std::string version = tz.version(); >+ if (version.empty() && !target.empty()) return 1; // unknown > known >+ return version.compare(target); >+} >+ >+} // namespace >+ >+TEST(TimeZones, LoadZonesConcurrently) { >+ std::promise<void> ready_promise; >+ std::shared_future<void> ready_future(ready_promise.get_future()); >+ auto load_zones = [ready_future](std::promise<void>* started, >+ std::set<std::string>* failures) { >+ started->set_value(); >+ ready_future.wait(); >+ for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { >+ std::string zone = *np; >+ time_zone tz; >+ if (load_time_zone(zone, &tz)) { >+ EXPECT_EQ(zone, tz.name()); >+ } else { >+ failures->insert(zone); >+ } >+ } >+ }; >+ >+ const std::size_t n_threads = 128; >+ std::vector<std::thread> threads; >+ std::vector<std::set<std::string>> thread_failures(n_threads); >+ for (std::size_t i = 0; i != n_threads; ++i) { >+ std::promise<void> started; >+ threads.emplace_back(load_zones, &started, &thread_failures[i]); >+ started.get_future().wait(); >+ } >+ ready_promise.set_value(); >+ for (auto& thread : threads) { >+ thread.join(); >+ } >+ >+ // Allow a small number of failures to account for skew between >+ // the contents of kTimeZoneNames and the zoneinfo data source. >+#if defined(__ANDROID__) >+ // Cater to the possibility of using an even older zoneinfo data >+ // source when running on Android, where it is difficult to override >+ // the bionic tzdata provided by the test environment. >+ const std::size_t max_failures = 20; >+#else >+ const std::size_t max_failures = 3; >+#endif >+ std::set<std::string> failures; >+ for (const auto& thread_failure : thread_failures) { >+ failures.insert(thread_failure.begin(), thread_failure.end()); >+ } >+ EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures); >+} >+ >+TEST(TimeZone, NamedTimeZones) { >+ const time_zone utc = utc_time_zone(); >+ EXPECT_EQ("UTC", utc.name()); >+ const time_zone nyc = LoadZone("America/New_York"); >+ EXPECT_EQ("America/New_York", nyc.name()); >+ const time_zone syd = LoadZone("Australia/Sydney"); >+ EXPECT_EQ("Australia/Sydney", syd.name()); >+ const time_zone fixed0 = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); >+ EXPECT_EQ("UTC", fixed0.name()); >+ const time_zone fixed_pos = fixed_time_zone( >+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45)); >+ EXPECT_EQ("Fixed/UTC+03:25:45", fixed_pos.name()); >+ const time_zone fixed_neg = fixed_time_zone( >+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56))); >+ EXPECT_EQ("Fixed/UTC-12:34:56", fixed_neg.name()); >+} >+ >+TEST(TimeZone, Failures) { >+ time_zone tz; >+ EXPECT_FALSE(load_time_zone(":America/Los_Angeles", &tz)); >+ >+ tz = LoadZone("America/Los_Angeles"); >+ EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(0), >+ convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC >+ >+ // Ensures that the load still fails on a subsequent attempt. >+ tz = LoadZone("America/Los_Angeles"); >+ EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(0), >+ convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC >+ >+ // Loading an empty std::string timezone should fail. >+ tz = LoadZone("America/Los_Angeles"); >+ EXPECT_FALSE(load_time_zone("", &tz)); >+ EXPECT_EQ(chrono::system_clock::from_time_t(0), >+ convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC >+} >+ >+TEST(TimeZone, Equality) { >+ const time_zone a; >+ const time_zone b; >+ EXPECT_EQ(a, b); >+ EXPECT_EQ(a.name(), b.name()); >+ >+ const time_zone implicit_utc; >+ const time_zone explicit_utc = utc_time_zone(); >+ EXPECT_EQ(implicit_utc, explicit_utc); >+ EXPECT_EQ(implicit_utc.name(), explicit_utc.name()); >+ >+ const time_zone fixed_zero = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); >+ EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name())); >+ EXPECT_EQ(fixed_zero, explicit_utc); >+ >+ const time_zone fixed_utc = LoadZone("Fixed/UTC+00:00:00"); >+ EXPECT_EQ(fixed_utc, LoadZone(fixed_utc.name())); >+ EXPECT_EQ(fixed_utc, explicit_utc); >+ >+ const time_zone fixed_pos = fixed_time_zone( >+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45)); >+ EXPECT_EQ(fixed_pos, LoadZone(fixed_pos.name())); >+ EXPECT_NE(fixed_pos, explicit_utc); >+ const time_zone fixed_neg = fixed_time_zone( >+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56))); >+ EXPECT_EQ(fixed_neg, LoadZone(fixed_neg.name())); >+ EXPECT_NE(fixed_neg, explicit_utc); >+ >+ const time_zone fixed_lim = fixed_time_zone(chrono::hours(24)); >+ EXPECT_EQ(fixed_lim, LoadZone(fixed_lim.name())); >+ EXPECT_NE(fixed_lim, explicit_utc); >+ const time_zone fixed_ovfl = >+ fixed_time_zone(chrono::hours(24) + chrono::seconds(1)); >+ EXPECT_EQ(fixed_ovfl, LoadZone(fixed_ovfl.name())); >+ EXPECT_EQ(fixed_ovfl, explicit_utc); >+ >+ EXPECT_EQ(fixed_time_zone(chrono::seconds(1)), >+ fixed_time_zone(chrono::seconds(1))); >+ >+ const time_zone local = local_time_zone(); >+ EXPECT_EQ(local, LoadZone(local.name())); >+ >+ time_zone la = LoadZone("America/Los_Angeles"); >+ time_zone nyc = LoadZone("America/New_York"); >+ EXPECT_NE(la, nyc); >+} >+ >+TEST(StdChronoTimePoint, TimeTAlignment) { >+ // Ensures that the Unix epoch and the system clock epoch are an integral >+ // number of seconds apart. This simplifies conversions to/from time_t. >+ auto diff = chrono::system_clock::time_point() - >+ chrono::system_clock::from_time_t(0); >+ EXPECT_EQ(chrono::system_clock::time_point::duration::zero(), >+ diff % chrono::seconds(1)); >+} >+ >+TEST(BreakTime, TimePointResolution) { >+ const time_zone utc = utc_time_zone(); >+ const auto t0 = chrono::system_clock::from_time_t(0); >+ >+ ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc, >+ 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+} >+ >+TEST(BreakTime, LocalTimeInUTC) { >+ const time_zone tz = utc_time_zone(); >+ const auto tp = chrono::system_clock::from_time_t(0); >+ ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); >+ EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(BreakTime, LocalTimeInUTCUnaligned) { >+ const time_zone tz = utc_time_zone(); >+ const auto tp = >+ chrono::system_clock::from_time_t(0) - chrono::milliseconds(500); >+ ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC"); >+ EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(BreakTime, LocalTimePosix) { >+ // See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch. >+ const time_zone tz = utc_time_zone(); >+ const auto tp = chrono::system_clock::from_time_t(536457599); >+ ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC"); >+ EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(TimeZoneImpl, LocalTimeInFixed) { >+ const absl::time_internal::cctz::seconds offset = >+ -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47)); >+ const time_zone tz = fixed_time_zone(offset); >+ const auto tp = chrono::system_clock::from_time_t(0); >+ ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false, >+ "-083347"); >+ EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(BreakTime, LocalTimeInNewYork) { >+ const time_zone tz = LoadZone("America/New_York"); >+ const auto tp = chrono::system_clock::from_time_t(45); >+ ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST"); >+ EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(BreakTime, LocalTimeInMTV) { >+ const time_zone tz = LoadZone("America/Los_Angeles"); >+ const auto tp = chrono::system_clock::from_time_t(1380855729); >+ ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT"); >+ EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(BreakTime, LocalTimeInSydney) { >+ const time_zone tz = LoadZone("Australia/Sydney"); >+ const auto tp = chrono::system_clock::from_time_t(90); >+ ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST"); >+ EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(MakeTime, TimePointResolution) { >+ const time_zone utc = utc_time_zone(); >+ const time_point<chrono::nanoseconds> tp_ns = >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc); >+ EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc)); >+ const time_point<chrono::microseconds> tp_us = >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc); >+ EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc)); >+ const time_point<chrono::milliseconds> tp_ms = >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc); >+ EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc)); >+ const time_point<chrono::seconds> tp_s = >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc); >+ EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc)); >+ const time_point<absl::time_internal::cctz::seconds> tp_s64 = >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc); >+ EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc)); >+ >+ // These next two require chrono::time_point_cast because the conversion >+ // from a resolution of seconds (the return value of convert()) to a >+ // coarser resolution requires an explicit cast. >+ const time_point<chrono::minutes> tp_m = >+ chrono::time_point_cast<chrono::minutes>( >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); >+ EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc)); >+ const time_point<chrono::hours> tp_h = >+ chrono::time_point_cast<chrono::hours>( >+ convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); >+ EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc)); >+} >+ >+TEST(MakeTime, Normalization) { >+ const time_zone tz = LoadZone("America/New_York"); >+ const auto tp = convert(civil_second(2009, 2, 13, 18, 31, 30), tz); >+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); >+ >+ // Now requests for the same time_point but with out-of-range fields. >+ EXPECT_EQ(tp, convert(civil_second(2008, 14, 13, 18, 31, 30), tz)); // month >+ EXPECT_EQ(tp, convert(civil_second(2009, 1, 44, 18, 31, 30), tz)); // day >+ EXPECT_EQ(tp, convert(civil_second(2009, 2, 12, 42, 31, 30), tz)); // hour >+ EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 17, 91, 30), tz)); // minute >+ EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second >+} >+ >+// NOTE: Run this with --copt=-ftrapv to detect overflow problems. >+TEST(MakeTime, SysSecondsLimits) { >+ const char RFC3339[] = "%Y-%m-%dT%H:%M:%S%Ez"; >+ const time_zone utc = utc_time_zone(); >+ const time_zone east = fixed_time_zone(chrono::hours(14)); >+ const time_zone west = fixed_time_zone(-chrono::hours(14)); >+ time_point<absl::time_internal::cctz::seconds> tp; >+ >+ // Approach the maximal time_point<cctz::seconds> value from below. >+ tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc); >+ EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc)); >+ tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc); >+ EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second::max(), utc); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ >+ // Checks that we can also get the maximal value for a far-east zone. >+ tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east); >+ EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second::max(), east); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ >+ // Checks that we can also get the maximal value for a far-west zone. >+ tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west); >+ EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ tp = convert(civil_second::max(), west); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); >+ >+ // Approach the minimal time_point<cctz::seconds> value from above. >+ tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc); >+ EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc)); >+ tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc); >+ EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second::min(), utc); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ >+ // Checks that we can also get the minimal value for a far-east zone. >+ tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east); >+ EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second::min(), east); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ >+ // Checks that we can also get the minimal value for a far-west zone. >+ tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west); >+ EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west)); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+ tp = convert(civil_second::min(), west); >+ EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); >+} >+ >+TEST(NextTransition, UTC) { >+ const auto tz = utc_time_zone(); >+ time_zone::civil_transition trans; >+ >+ auto tp = time_point<absl::time_internal::cctz::seconds>::min(); >+ EXPECT_FALSE(tz.next_transition(tp, &trans)); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::max(); >+ EXPECT_FALSE(tz.next_transition(tp, &trans)); >+} >+ >+TEST(PrevTransition, UTC) { >+ const auto tz = utc_time_zone(); >+ time_zone::civil_transition trans; >+ >+ auto tp = time_point<absl::time_internal::cctz::seconds>::max(); >+ EXPECT_FALSE(tz.prev_transition(tp, &trans)); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::min(); >+ EXPECT_FALSE(tz.prev_transition(tp, &trans)); >+} >+ >+TEST(NextTransition, AmericaNewYork) { >+ const auto tz = LoadZone("America/New_York"); >+ time_zone::civil_transition trans; >+ >+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz); >+ EXPECT_TRUE(tz.next_transition(tp, &trans)); >+ EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from); >+ EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::max(); >+ EXPECT_FALSE(tz.next_transition(tp, &trans)); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::min(); >+ EXPECT_TRUE(tz.next_transition(tp, &trans)); >+ if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) { >+ // It looks like the tzdata is only 32 bit (probably macOS), >+ // which bottoms out at 1901-12-13T20:45:52+00:00. >+ EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to); >+ } else { >+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from); >+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to); >+ } >+} >+ >+TEST(PrevTransition, AmericaNewYork) { >+ const auto tz = LoadZone("America/New_York"); >+ time_zone::civil_transition trans; >+ >+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz); >+ EXPECT_TRUE(tz.prev_transition(tp, &trans)); >+ EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from); >+ EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::min(); >+ EXPECT_FALSE(tz.prev_transition(tp, &trans)); >+ >+ tp = time_point<absl::time_internal::cctz::seconds>::max(); >+ EXPECT_TRUE(tz.prev_transition(tp, &trans)); >+ // We have a transition but we don't know which one. >+} >+ >+TEST(TimeZoneEdgeCase, AmericaNewYork) { >+ const time_zone tz = LoadZone("America/New_York"); >+ >+ // Spring 1:59:59 -> 3:00:00 >+ auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -5 * 3600, false, "EST"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -4 * 3600, true, "EDT"); >+ >+ // Fall 1:59:59 -> 1:00:00 >+ tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -4 * 3600, true, "EDT"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -5 * 3600, false, "EST"); >+} >+ >+TEST(TimeZoneEdgeCase, AmericaLosAngeles) { >+ const time_zone tz = LoadZone("America/Los_Angeles"); >+ >+ // Spring 1:59:59 -> 3:00:00 >+ auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -8 * 3600, false, "PST"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -7 * 3600, true, "PDT"); >+ >+ // Fall 1:59:59 -> 1:00:00 >+ tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, true, "PDT"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -8 * 3600, false, "PST"); >+} >+ >+TEST(TimeZoneEdgeCase, ArizonaNoTransition) { >+ const time_zone tz = LoadZone("America/Phoenix"); >+ >+ // No transition in Spring. >+ auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -7 * 3600, false, "MST"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 3, 10, 2, 0, 0, -7 * 3600, false, "MST"); >+ >+ // No transition in Fall. >+ tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, false, "MST"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 11, 3, 2, 0, 0, -7 * 3600, false, "MST"); >+} >+ >+TEST(TimeZoneEdgeCase, AsiaKathmandu) { >+ const time_zone tz = LoadZone("Asia/Kathmandu"); >+ >+ // A non-DST offset change from +0530 to +0545 >+ // >+ // 504901799 == Tue, 31 Dec 1985 23:59:59 +0530 (+0530) >+ // 504901800 == Wed, 1 Jan 1986 00:15:00 +0545 (+0545) >+ auto tp = convert(civil_second(1985, 12, 31, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 1985, 12, 31, 23, 59, 59, 5.5 * 3600, false, "+0530"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "+0545"); >+} >+ >+TEST(TimeZoneEdgeCase, PacificChatham) { >+ const time_zone tz = LoadZone("Pacific/Chatham"); >+ >+ // One-hour DST offset changes, but at atypical values >+ // >+ // 1365256799 == Sun, 7 Apr 2013 03:44:59 +1345 (+1345) >+ // 1365256800 == Sun, 7 Apr 2013 02:45:00 +1245 (+1245) >+ auto tp = convert(civil_second(2013, 4, 7, 3, 44, 59), tz); >+ ExpectTime(tp, tz, 2013, 4, 7, 3, 44, 59, 13.75 * 3600, true, "+1345"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "+1245"); >+ >+ // 1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (+1245) >+ // 1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (+1345) >+ tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz); >+ ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, "+1245"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "+1345"); >+} >+ >+TEST(TimeZoneEdgeCase, AustraliaLordHowe) { >+ const time_zone tz = LoadZone("Australia/Lord_Howe"); >+ >+ // Half-hour DST offset changes >+ // >+ // 1365260399 == Sun, 7 Apr 2013 01:59:59 +1100 (+11) >+ // 1365260400 == Sun, 7 Apr 2013 01:30:00 +1030 (+1030) >+ auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "+11"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "+1030"); >+ >+ // 1380986999 == Sun, 6 Oct 2013 01:59:59 +1030 (+1030) >+ // 1380987000 == Sun, 6 Oct 2013 02:30:00 +1100 (+11) >+ tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "+1030"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "+11"); >+} >+ >+TEST(TimeZoneEdgeCase, PacificApia) { >+ const time_zone tz = LoadZone("Pacific/Apia"); >+ >+ // At the end of December 2011, Samoa jumped forward by one day, >+ // skipping 30 December from the local calendar, when the nation >+ // moved to the west of the International Date Line. >+ // >+ // A one-day, non-DST offset change >+ // >+ // 1325239199 == Thu, 29 Dec 2011 23:59:59 -1000 (-10) >+ // 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14) >+ auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10"); >+ EXPECT_EQ(363, get_yearday(civil_day(convert(tp, tz)))); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14"); >+ EXPECT_EQ(365, get_yearday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(TimeZoneEdgeCase, AfricaCairo) { >+ const time_zone tz = LoadZone("Africa/Cairo"); >+ >+ if (VersionCmp(tz, "2014c") >= 0) { >+ // An interesting case of midnight not existing. >+ // >+ // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET) >+ // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST) >+ auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST"); >+ } >+} >+ >+TEST(TimeZoneEdgeCase, AfricaMonrovia) { >+ const time_zone tz = LoadZone("Africa/Monrovia"); >+ >+ if (VersionCmp(tz, "2017b") >= 0) { >+ // Strange offset change -00:44:30 -> +00:00:00 (non-DST) >+ // >+ // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT) >+ // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT) >+ auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT"); >+ } >+} >+ >+TEST(TimeZoneEdgeCase, AmericaJamaica) { >+ // Jamaica discontinued DST transitions in 1983, and is now at a >+ // constant -0500. This makes it an interesting edge-case target. >+ // Note that the 32-bit times used in a (tzh_version == 0) zoneinfo >+ // file cannot represent the abbreviation-only transition of 1890, >+ // so we ignore the abbreviation by expecting what we received. >+ const time_zone tz = LoadZone("America/Jamaica"); >+ >+ // Before the first transition. >+ if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) { >+ // We avoid the expectations on the -18430 offset below unless we are >+ // certain we have commit 907241e (Fix off-by-1 error for Jamaica and >+ // T&C before 1913) from 2018d. TODO: Remove the "version() not empty" >+ // part when 2018d is generally available from /usr/share/zoneinfo. >+ auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz); >+ ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false, >+ tz.lookup(tp).abbr); >+ >+ // Over the first (abbreviation-change only) transition. >+ // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT) >+ // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT) >+ tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false, >+ tz.lookup(tp).abbr); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT"); >+ } >+ >+ // Over the last (DST) transition. >+ // 436341599 == Sun, 30 Oct 1983 01:59:59 -0400 (EDT) >+ // 436341600 == Sun, 30 Oct 1983 01:00:00 -0500 (EST) >+ auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz); >+ ExpectTime(tp, tz, 1983, 10, 30, 1, 59, 59, -4 * 3600, true, "EDT"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 1983, 10, 30, 1, 0, 0, -5 * 3600, false, "EST"); >+ >+ // After the last transition. >+ tp = convert(civil_second(1983, 12, 31, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 1983, 12, 31, 23, 59, 59, -5 * 3600, false, "EST"); >+} >+ >+TEST(TimeZoneEdgeCase, WET) { >+ // Cover some non-existent times within forward transitions. >+ const time_zone tz = LoadZone("WET"); >+ >+ // Before the first transition. >+ auto tp = convert(civil_second(1977, 1, 1, 0, 0, 0), tz); >+ ExpectTime(tp, tz, 1977, 1, 1, 0, 0, 0, 0, false, "WET"); >+ >+ // Over the first transition. >+ // 228877199 == Sun, 3 Apr 1977 00:59:59 +0000 (WET) >+ // 228877200 == Sun, 3 Apr 1977 02:00:00 +0100 (WEST) >+ tp = convert(civil_second(1977, 4, 3, 0, 59, 59), tz); >+ ExpectTime(tp, tz, 1977, 4, 3, 0, 59, 59, 0, false, "WET"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST"); >+ >+ // A non-existent time within the first transition. >+ time_zone::civil_lookup cl1 = tz.lookup(civil_second(1977, 4, 3, 1, 15, 0)); >+ EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl1.kind); >+ ExpectTime(cl1.pre, tz, 1977, 4, 3, 2, 15, 0, 1 * 3600, true, "WEST"); >+ ExpectTime(cl1.trans, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST"); >+ ExpectTime(cl1.post, tz, 1977, 4, 3, 0, 15, 0, 0 * 3600, false, "WET"); >+ >+ // A non-existent time within the second forward transition. >+ time_zone::civil_lookup cl2 = tz.lookup(civil_second(1978, 4, 2, 1, 15, 0)); >+ EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl2.kind); >+ ExpectTime(cl2.pre, tz, 1978, 4, 2, 2, 15, 0, 1 * 3600, true, "WEST"); >+ ExpectTime(cl2.trans, tz, 1978, 4, 2, 2, 0, 0, 1 * 3600, true, "WEST"); >+ ExpectTime(cl2.post, tz, 1978, 4, 2, 0, 15, 0, 0 * 3600, false, "WET"); >+} >+ >+TEST(TimeZoneEdgeCase, FixedOffsets) { >+ const time_zone gmtm5 = LoadZone("Etc/GMT+5"); // -0500 >+ auto tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtm5); >+ ExpectTime(tp, gmtm5, 1970, 1, 1, 0, 0, 0, -5 * 3600, false, "-05"); >+ EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp); >+ >+ const time_zone gmtp5 = LoadZone("Etc/GMT-5"); // +0500 >+ tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtp5); >+ ExpectTime(tp, gmtp5, 1970, 1, 1, 0, 0, 0, 5 * 3600, false, "+05"); >+ EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp); >+} >+ >+TEST(TimeZoneEdgeCase, NegativeYear) { >+ // Tests transition from year 0 (aka 1BCE) to year -1. >+ const time_zone tz = utc_time_zone(); >+ auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz); >+ ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); >+ EXPECT_EQ(weekday::saturday, get_weekday(civil_day(convert(tp, tz)))); >+ tp -= absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC"); >+ EXPECT_EQ(weekday::friday, get_weekday(civil_day(convert(tp, tz)))); >+} >+ >+TEST(TimeZoneEdgeCase, UTC32bitLimit) { >+ const time_zone tz = utc_time_zone(); >+ >+ // Limits of signed 32-bit time_t >+ // >+ // 2147483647 == Tue, 19 Jan 2038 03:14:07 +0000 (UTC) >+ // 2147483648 == Tue, 19 Jan 2038 03:14:08 +0000 (UTC) >+ auto tp = convert(civil_second(2038, 1, 19, 3, 14, 7), tz); >+ ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 7, 0 * 3600, false, "UTC"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 8, 0 * 3600, false, "UTC"); >+} >+ >+TEST(TimeZoneEdgeCase, UTC5DigitYear) { >+ const time_zone tz = utc_time_zone(); >+ >+ // Rollover to 5-digit year >+ // >+ // 253402300799 == Fri, 31 Dec 9999 23:59:59 +0000 (UTC) >+ // 253402300800 == Sat, 1 Jan 1000 00:00:00 +0000 (UTC) >+ auto tp = convert(civil_second(9999, 12, 31, 23, 59, 59), tz); >+ ExpectTime(tp, tz, 9999, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC"); >+ tp += absl::time_internal::cctz::seconds(1); >+ ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.cc >new file mode 100644 >index 00000000000..75ad8bcba93 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.cc >@@ -0,0 +1,155 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "time_zone_posix.h" >+ >+#include <cstddef> >+#include <cstring> >+#include <limits> >+#include <string> >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+namespace { >+ >+const char kDigits[] = "0123456789"; >+ >+const char* ParseInt(const char* p, int min, int max, int* vp) { >+ int value = 0; >+ const char* op = p; >+ const int kMaxInt = std::numeric_limits<int>::max(); >+ for (; const char* dp = strchr(kDigits, *p); ++p) { >+ int d = static_cast<int>(dp - kDigits); >+ if (d >= 10) break; // '\0' >+ if (value > kMaxInt / 10) return nullptr; >+ value *= 10; >+ if (value > kMaxInt - d) return nullptr; >+ value += d; >+ } >+ if (p == op || value < min || value > max) return nullptr; >+ *vp = value; >+ return p; >+} >+ >+// abbr = <.*?> | [^-+,\d]{3,} >+const char* ParseAbbr(const char* p, std::string* abbr) { >+ const char* op = p; >+ if (*p == '<') { // special zoneinfo <...> form >+ while (*++p != '>') { >+ if (*p == '\0') return nullptr; >+ } >+ abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1); >+ return ++p; >+ } >+ while (*p != '\0') { >+ if (strchr("-+,", *p)) break; >+ if (strchr(kDigits, *p)) break; >+ ++p; >+ } >+ if (p - op < 3) return nullptr; >+ abbr->assign(op, static_cast<std::size_t>(p - op)); >+ return p; >+} >+ >+// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value) >+const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign, >+ std::int_fast32_t* offset) { >+ if (p == nullptr) return nullptr; >+ if (*p == '+' || *p == '-') { >+ if (*p++ == '-') sign = -sign; >+ } >+ int hours = 0; >+ int minutes = 0; >+ int seconds = 0; >+ >+ p = ParseInt(p, min_hour, max_hour, &hours); >+ if (p == nullptr) return nullptr; >+ if (*p == ':') { >+ p = ParseInt(p + 1, 0, 59, &minutes); >+ if (p == nullptr) return nullptr; >+ if (*p == ':') { >+ p = ParseInt(p + 1, 0, 59, &seconds); >+ if (p == nullptr) return nullptr; >+ } >+ } >+ *offset = sign * ((((hours * 60) + minutes) * 60) + seconds); >+ return p; >+} >+ >+// datetime = ( Jn | n | Mm.w.d ) [ / offset ] >+const char* ParseDateTime(const char* p, PosixTransition* res) { >+ if (p != nullptr && *p == ',') { >+ if (*++p == 'M') { >+ int month = 0; >+ if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') { >+ int week = 0; >+ if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') { >+ int weekday = 0; >+ if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) { >+ res->date.fmt = PosixTransition::M; >+ res->date.m.month = static_cast<int_fast8_t>(month); >+ res->date.m.week = static_cast<int_fast8_t>(week); >+ res->date.m.weekday = static_cast<int_fast8_t>(weekday); >+ } >+ } >+ } >+ } else if (*p == 'J') { >+ int day = 0; >+ if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) { >+ res->date.fmt = PosixTransition::J; >+ res->date.j.day = static_cast<int_fast16_t>(day); >+ } >+ } else { >+ int day = 0; >+ if ((p = ParseInt(p, 0, 365, &day)) != nullptr) { >+ res->date.fmt = PosixTransition::N; >+ res->date.j.day = static_cast<int_fast16_t>(day); >+ } >+ } >+ } >+ if (p != nullptr) { >+ res->time.offset = 2 * 60 * 60; // default offset is 02:00:00 >+ if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset); >+ } >+ return p; >+} >+ >+} // namespace >+ >+// spec = std offset [ dst [ offset ] , datetime , datetime ] >+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) { >+ const char* p = spec.c_str(); >+ if (*p == ':') return false; >+ >+ p = ParseAbbr(p, &res->std_abbr); >+ p = ParseOffset(p, 0, 24, -1, &res->std_offset); >+ if (p == nullptr) return false; >+ if (*p == '\0') return true; >+ >+ p = ParseAbbr(p, &res->dst_abbr); >+ if (p == nullptr) return false; >+ res->dst_offset = res->std_offset + (60 * 60); // default >+ if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset); >+ >+ p = ParseDateTime(p, &res->dst_start); >+ p = ParseDateTime(p, &res->dst_end); >+ >+ return p != nullptr && *p == '\0'; >+} >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.h >new file mode 100644 >index 00000000000..6619f27edcf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_posix.h >@@ -0,0 +1,118 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in >+// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html. >+// >+// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0", >+// which would be broken down as ... >+// >+// PosixTimeZone { >+// std_abbr = "PST" >+// std_offset = -28800 >+// dst_abbr = "PDT" >+// dst_offset = -25200 >+// dst_start = PosixTransition { >+// date { >+// m { >+// month = 3 >+// week = 2 >+// weekday = 0 >+// } >+// } >+// time { >+// offset = 7200 >+// } >+// } >+// dst_end = PosixTransition { >+// date { >+// m { >+// month = 11 >+// week = 1 >+// weekday = 0 >+// } >+// } >+// time { >+// offset = 7200 >+// } >+// } >+// } >+ >+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ >+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ >+ >+#include <cstdint> >+#include <string> >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// The date/time of the transition. The date is specified as either: >+// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or >+// (N) the Nth day of the year (0 <= N <= 365), including leap days, or >+// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March). >+// The time, specified as a day offset, identifies the particular moment >+// of the transition, and may be negative or >= 24h, and in which case >+// it would take us to another day, and perhaps week, or even month. >+struct PosixTransition { >+ enum DateFormat { J, N, M }; >+ struct { >+ DateFormat fmt; >+ union { >+ struct { >+ std::int_fast16_t day; // day of non-leap year [1:365] >+ } j; >+ struct { >+ std::int_fast16_t day; // day of year [0:365] >+ } n; >+ struct { >+ std::int_fast8_t month; // month of year [1:12] >+ std::int_fast8_t week; // week of month [1:5] (5==last) >+ std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat >+ } m; >+ }; >+ } date; >+ struct { >+ std::int_fast32_t offset; // seconds before/after 00:00:00 >+ } time; >+}; >+ >+// The entirety of a POSIX-std::string specified time-zone rule. The standard >+// abbreviation and offset are always given. If the time zone includes >+// daylight saving, then the daylight abbrevation is non-empty and the >+// remaining fields are also valid. Note that the start/end transitions >+// are not ordered---in the southern hemisphere the transition to end >+// daylight time occurs first in any particular year. >+struct PosixTimeZone { >+ std::string std_abbr; >+ std::int_fast32_t std_offset; >+ >+ std::string dst_abbr; >+ std::int_fast32_t dst_offset; >+ PosixTransition dst_start; >+ PosixTransition dst_end; >+}; >+ >+// Breaks down a POSIX time-zone specification into its constituent pieces, >+// filling in any missing values (DST offset, or start/end transition times) >+// with the standard-defined defaults. Returns false if the specification >+// could not be parsed (although some fields of *res may have been altered). >+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res); >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h >new file mode 100644 >index 00000000000..90cfc0c4298 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/tzfile.h >@@ -0,0 +1,117 @@ >+#ifndef TZFILE_H >+ >+#define TZFILE_H >+ >+/* >+** This file is in the public domain, so clarified as of >+** 1996-06-05 by Arthur David Olson. >+*/ >+ >+/* >+** This header is for use ONLY with the time conversion code. >+** There is no guarantee that it will remain unchanged, >+** or that it will remain at all. >+** Do NOT copy it to any system include directory. >+** Thank you! >+*/ >+ >+/* >+** Information about time zone files. >+*/ >+ >+#ifndef TZDIR >+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ >+#endif /* !defined TZDIR */ >+ >+#ifndef TZDEFAULT >+#define TZDEFAULT "/etc/localtime" >+#endif /* !defined TZDEFAULT */ >+ >+#ifndef TZDEFRULES >+#define TZDEFRULES "posixrules" >+#endif /* !defined TZDEFRULES */ >+ >+/* >+** Each file begins with. . . >+*/ >+ >+#define TZ_MAGIC "TZif" >+ >+struct tzhead { >+ char tzh_magic[4]; /* TZ_MAGIC */ >+ char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */ >+ char tzh_reserved[15]; /* reserved; must be zero */ >+ char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ >+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ >+ char tzh_leapcnt[4]; /* coded number of leap seconds */ >+ char tzh_timecnt[4]; /* coded number of transition times */ >+ char tzh_typecnt[4]; /* coded number of local time types */ >+ char tzh_charcnt[4]; /* coded number of abbr. chars */ >+}; >+ >+/* >+** . . .followed by. . . >+** >+** tzh_timecnt (char [4])s coded transition times a la time(2) >+** tzh_timecnt (unsigned char)s types of local time starting at above >+** tzh_typecnt repetitions of >+** one (char [4]) coded UT offset in seconds >+** one (unsigned char) used to set tm_isdst >+** one (unsigned char) that's an abbreviation list index >+** tzh_charcnt (char)s '\0'-terminated zone abbreviations >+** tzh_leapcnt repetitions of >+** one (char [4]) coded leap second transition times >+** one (char [4]) total correction after above >+** tzh_ttisstdcnt (char)s indexed by type; if 1, transition >+** time is standard time, if 0, >+** transition time is wall clock time >+** if absent, transition times are >+** assumed to be wall clock time >+** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition >+** time is UT, if 0, >+** transition time is local time >+** if absent, transition times are >+** assumed to be local time >+*/ >+ >+/* >+** If tzh_version is '2' or greater, the above is followed by a second instance >+** of tzhead and a second instance of the data in which each coded transition >+** time uses 8 rather than 4 chars, >+** then a POSIX-TZ-environment-variable-style std::string for use in handling >+** instants after the last transition time stored in the file >+** (with nothing between the newlines if there is no POSIX representation for >+** such instants). >+** >+** If tz_version is '3' or greater, the above is extended as follows. >+** First, the POSIX TZ std::string's hour offset may range from -167 >+** through 167 as compared to the POSIX-required 0 through 24. >+** Second, its DST start time may be January 1 at 00:00 and its stop >+** time December 31 at 24:00 plus the difference between DST and >+** standard time, indicating DST all year. >+*/ >+ >+/* >+** In the current implementation, "tzset()" refuses to deal with files that >+** exceed any of the limits below. >+*/ >+ >+#ifndef TZ_MAX_TIMES >+#define TZ_MAX_TIMES 2000 >+#endif /* !defined TZ_MAX_TIMES */ >+ >+#ifndef TZ_MAX_TYPES >+/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ >+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ >+#endif /* !defined TZ_MAX_TYPES */ >+ >+#ifndef TZ_MAX_CHARS >+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ >+ /* (limited by what unsigned chars can hold) */ >+#endif /* !defined TZ_MAX_CHARS */ >+ >+#ifndef TZ_MAX_LEAPS >+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ >+#endif /* !defined TZ_MAX_LEAPS */ >+ >+#endif /* !defined TZFILE_H */ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc >new file mode 100644 >index 00000000000..bf2d2d2d2b5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/cctz/src/zone_info_source.cc >@@ -0,0 +1,79 @@ >+// Copyright 2016 Google Inc. All Rights Reserved. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" >+ >+namespace absl { >+namespace time_internal { >+namespace cctz { >+ >+// Defined out-of-line to avoid emitting a weak vtable in all TUs. >+ZoneInfoSource::~ZoneInfoSource() {} >+std::string ZoneInfoSource::Version() const { return std::string(); } >+ >+} // namespace cctz >+} // namespace time_internal >+} // namespace absl >+ >+namespace absl { >+namespace time_internal { >+namespace cctz_extension { >+ >+namespace { >+ >+// A default for cctz_extension::zone_info_source_factory, which simply >+// defers to the fallback factory. >+std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory( >+ const std::string& name, >+ const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>( >+ const std::string& name)>& fallback_factory) { >+ return fallback_factory(name); >+} >+ >+} // namespace >+ >+// A "weak" definition for cctz_extension::zone_info_source_factory. >+// The user may override this with their own "strong" definition (see >+// zone_info_source.h). >+#if defined(_MSC_VER) >+extern ZoneInfoSourceFactory zone_info_source_factory; >+extern ZoneInfoSourceFactory default_factory; >+ZoneInfoSourceFactory default_factory = DefaultFactory; >+#if defined(_M_IX86) >+#pragma comment( \ >+ linker, \ >+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZA") >+#elif defined(_M_IA_64) || defined(_M_AMD64) >+#pragma comment( \ >+ linker, \ >+ "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA=?default_factory@cctz_extension@time_internal@absl@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@5@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@absl@@U?$default_delete@VZoneInfoSource@cctz@time_internal@absl@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@5@@ZEA") >+#else >+#error Unsupported MSVC platform >+#endif >+#else // _MSC_VER >+#if !defined(__has_attribute) >+#define __has_attribute(x) 0 >+#endif >+#if __has_attribute(weak) || defined(__GNUC__) >+ZoneInfoSourceFactory zone_info_source_factory >+ __attribute__((weak)) = DefaultFactory; >+#else >+// Make it a "strong" definition if we have no other choice. >+ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory; >+#endif >+#endif // _MSC_VER >+ >+} // namespace cctz_extension >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc >new file mode 100644 >index 00000000000..cf884a10ed9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_chrono.inc >@@ -0,0 +1,29 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include <chrono> >+#include <cstdint> >+ >+namespace absl { >+namespace time_internal { >+ >+static int64_t GetCurrentTimeNanosFromSystem() { >+ return std::chrono::duration_cast<std::chrono::nanoseconds>( >+ std::chrono::system_clock::now() - >+ std::chrono::system_clock::from_time_t(0)) >+ .count(); >+} >+ >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_posix.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_posix.inc >new file mode 100644 >index 00000000000..65474ca6da1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/get_current_time_posix.inc >@@ -0,0 +1,22 @@ >+#include "absl/time/clock.h" >+ >+#include <sys/time.h> >+#include <ctime> >+#include <cstdint> >+ >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+namespace time_internal { >+ >+static int64_t GetCurrentTimeNanosFromSystem() { >+ const int64_t kNanosPerSecond = 1000 * 1000 * 1000; >+ struct timespec ts; >+ ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0, >+ "Failed to read real-time clock."); >+ return (int64_t{ts.tv_sec} * kNanosPerSecond + >+ int64_t{ts.tv_nsec}); >+} >+ >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.cc >new file mode 100644 >index 00000000000..bbbef7da70c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.cc >@@ -0,0 +1,129 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/test_util.h" >+ >+#include <algorithm> >+#include <cstddef> >+#include <cstring> >+ >+#include "absl/base/internal/raw_logging.h" >+#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" >+ >+namespace cctz = absl::time_internal::cctz; >+ >+namespace absl { >+namespace time_internal { >+ >+#if GTEST_USES_SIMPLE_RE >+extern const char kZoneAbbrRE[] = ".*"; // just punt >+#else >+extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?"; >+#endif >+ >+TimeZone LoadTimeZone(const std::string& name) { >+ TimeZone tz; >+ ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str()); >+ return tz; >+} >+ >+} // namespace time_internal >+} // namespace absl >+ >+namespace absl { >+namespace time_internal { >+namespace cctz_extension { >+namespace { >+ >+// Embed the zoneinfo data for time zones used during tests and benchmarks. >+// The data was generated using "xxd -i zoneinfo-file". There is no need >+// to update the data as long as the tests do not depend on recent changes >+// (and the past rules remain the same). >+#include "absl/time/internal/zoneinfo.inc" >+ >+const struct ZoneInfo { >+ const char* name; >+ const char* data; >+ std::size_t length; >+} kZoneInfo[] = { >+ // The three real time zones used by :time_test and :time_benchmark. >+ {"America/Los_Angeles", // >+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, >+ {"America/New_York", // >+ reinterpret_cast<char*>(America_New_York), America_New_York_len}, >+ {"Australia/Sydney", // >+ reinterpret_cast<char*>(Australia_Sydney), Australia_Sydney_len}, >+ >+ // Other zones named in tests but which should fail to load. >+ {"Invalid/TimeZone", nullptr, 0}, >+ {"", nullptr, 0}, >+ >+ // Also allow for loading the local time zone under TZ=US/Pacific. >+ {"US/Pacific", // >+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, >+ >+ // Allows use of the local time zone from a system-specific location. >+#ifdef _MSC_VER >+ {"localtime", // >+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, >+#else >+ {"/etc/localtime", // >+ reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, >+#endif >+}; >+ >+class TestZoneInfoSource : public cctz::ZoneInfoSource { >+ public: >+ TestZoneInfoSource(const char* data, std::size_t size) >+ : data_(data), end_(data + size) {} >+ >+ std::size_t Read(void* ptr, std::size_t size) override { >+ const std::size_t len = std::min<std::size_t>(size, end_ - data_); >+ memcpy(ptr, data_, len); >+ data_ += len; >+ return len; >+ } >+ >+ int Skip(std::size_t offset) override { >+ data_ += std::min<std::size_t>(offset, end_ - data_); >+ return 0; >+ } >+ >+ private: >+ const char* data_; >+ const char* const end_; >+}; >+ >+std::unique_ptr<cctz::ZoneInfoSource> TestFactory( >+ const std::string& name, >+ const std::function<std::unique_ptr<cctz::ZoneInfoSource>( >+ const std::string& name)>& /*fallback_factory*/) { >+ for (const ZoneInfo& zoneinfo : kZoneInfo) { >+ if (name == zoneinfo.name) { >+ if (zoneinfo.data == nullptr) return nullptr; >+ return std::unique_ptr<cctz::ZoneInfoSource>( >+ new TestZoneInfoSource(zoneinfo.data, zoneinfo.length)); >+ } >+ } >+ ABSL_RAW_LOG(FATAL, "Unexpected time zone \"%s\" in test", name.c_str()); >+ return nullptr; >+} >+ >+} // namespace >+ >+ZoneInfoSourceFactory zone_info_source_factory = TestFactory; >+ >+} // namespace cctz_extension >+} // namespace time_internal >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.h >new file mode 100644 >index 00000000000..8fd5fb9fd03 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/test_util.h >@@ -0,0 +1,55 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#ifndef ABSL_TIME_INTERNAL_TEST_UTIL_H_ >+#define ABSL_TIME_INTERNAL_TEST_UTIL_H_ >+ >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/time/time.h" >+ >+// This helper is a macro so that failed expectations show up with the >+// correct line numbers. >+// >+// This is for internal testing of the Base Time library itself. This is not >+// part of a public API. >+#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \ >+ do { \ >+ EXPECT_EQ(y, bd.year); \ >+ EXPECT_EQ(m, bd.month); \ >+ EXPECT_EQ(d, bd.day); \ >+ EXPECT_EQ(h, bd.hour); \ >+ EXPECT_EQ(min, bd.minute); \ >+ EXPECT_EQ(s, bd.second); \ >+ EXPECT_EQ(off, bd.offset); \ >+ EXPECT_EQ(isdst, bd.is_dst); \ >+ EXPECT_THAT(bd.zone_abbr, \ >+ testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \ >+ } while (0) >+ >+namespace absl { >+namespace time_internal { >+ >+// A regular expression that matches all zone abbreviations (%Z). >+extern const char kZoneAbbrRE[]; >+ >+// Loads the named timezone, but dies on any failure. >+absl::TimeZone LoadTimeZone(const std::string& name); >+ >+} // namespace time_internal >+} // namespace absl >+ >+#endif // ABSL_TIME_INTERNAL_TEST_UTIL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/zoneinfo.inc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/zoneinfo.inc >new file mode 100644 >index 00000000000..bfed82990dd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/internal/zoneinfo.inc >@@ -0,0 +1,729 @@ >+unsigned char America_Los_Angeles[] = { >+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, >+ 0x9e, 0xa6, 0x48, 0xa0, 0x9f, 0xbb, 0x15, 0x90, 0xa0, 0x86, 0x2a, 0xa0, >+ 0xa1, 0x9a, 0xf7, 0x90, 0xcb, 0x89, 0x1a, 0xa0, 0xd2, 0x23, 0xf4, 0x70, >+ 0xd2, 0x61, 0x26, 0x10, 0xd6, 0xfe, 0x74, 0x5c, 0xd8, 0x80, 0xad, 0x90, >+ 0xda, 0xfe, 0xc3, 0x90, 0xdb, 0xc0, 0x90, 0x10, 0xdc, 0xde, 0xa5, 0x90, >+ 0xdd, 0xa9, 0xac, 0x90, 0xde, 0xbe, 0x87, 0x90, 0xdf, 0x89, 0x8e, 0x90, >+ 0xe0, 0x9e, 0x69, 0x90, 0xe1, 0x69, 0x70, 0x90, 0xe2, 0x7e, 0x4b, 0x90, >+ 0xe3, 0x49, 0x52, 0x90, 0xe4, 0x5e, 0x2d, 0x90, 0xe5, 0x29, 0x34, 0x90, >+ 0xe6, 0x47, 0x4a, 0x10, 0xe7, 0x12, 0x51, 0x10, 0xe8, 0x27, 0x2c, 0x10, >+ 0xe8, 0xf2, 0x33, 0x10, 0xea, 0x07, 0x0e, 0x10, 0xea, 0xd2, 0x15, 0x10, >+ 0xeb, 0xe6, 0xf0, 0x10, 0xec, 0xb1, 0xf7, 0x10, 0xed, 0xc6, 0xd2, 0x10, >+ 0xee, 0x91, 0xd9, 0x10, 0xef, 0xaf, 0xee, 0x90, 0xf0, 0x71, 0xbb, 0x10, >+ 0xf1, 0x8f, 0xd0, 0x90, 0xf2, 0x7f, 0xc1, 0x90, 0xf3, 0x6f, 0xb2, 0x90, >+ 0xf4, 0x5f, 0xa3, 0x90, 0xf5, 0x4f, 0x94, 0x90, 0xf6, 0x3f, 0x85, 0x90, >+ 0xf7, 0x2f, 0x76, 0x90, 0xf8, 0x28, 0xa2, 0x10, 0xf9, 0x0f, 0x58, 0x90, >+ 0xfa, 0x08, 0x84, 0x10, 0xfa, 0xf8, 0x83, 0x20, 0xfb, 0xe8, 0x66, 0x10, >+ 0xfc, 0xd8, 0x65, 0x20, 0xfd, 0xc8, 0x48, 0x10, 0xfe, 0xb8, 0x47, 0x20, >+ 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0c, 0x10, >+ 0x02, 0x78, 0x0b, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xa0, >+ 0x05, 0x51, 0x0a, 0x90, 0x06, 0x41, 0x09, 0xa0, 0x07, 0x30, 0xec, 0x90, >+ 0x07, 0x8d, 0x43, 0xa0, 0x09, 0x10, 0xce, 0x90, 0x09, 0xad, 0xbf, 0x20, >+ 0x0a, 0xf0, 0xb0, 0x90, 0x0b, 0xe0, 0xaf, 0xa0, 0x0c, 0xd9, 0xcd, 0x10, >+ 0x0d, 0xc0, 0x91, 0xa0, 0x0e, 0xb9, 0xaf, 0x10, 0x0f, 0xa9, 0xae, 0x20, >+ 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, >+ 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, >+ 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, >+ 0x19, 0x09, 0x18, 0x20, 0x1a, 0x02, 0x35, 0x90, 0x1a, 0xf2, 0x34, 0xa0, >+ 0x1b, 0xe2, 0x17, 0x90, 0x1c, 0xd2, 0x16, 0xa0, 0x1d, 0xc1, 0xf9, 0x90, >+ 0x1e, 0xb1, 0xf8, 0xa0, 0x1f, 0xa1, 0xdb, 0x90, 0x20, 0x76, 0x2b, 0x20, >+ 0x21, 0x81, 0xbd, 0x90, 0x22, 0x56, 0x0d, 0x20, 0x23, 0x6a, 0xda, 0x10, >+ 0x24, 0x35, 0xef, 0x20, 0x25, 0x4a, 0xbc, 0x10, 0x26, 0x15, 0xd1, 0x20, >+ 0x27, 0x2a, 0x9e, 0x10, 0x27, 0xfe, 0xed, 0xa0, 0x29, 0x0a, 0x80, 0x10, >+ 0x29, 0xde, 0xcf, 0xa0, 0x2a, 0xea, 0x62, 0x10, 0x2b, 0xbe, 0xb1, 0xa0, >+ 0x2c, 0xd3, 0x7e, 0x90, 0x2d, 0x9e, 0x93, 0xa0, 0x2e, 0xb3, 0x60, 0x90, >+ 0x2f, 0x7e, 0x75, 0xa0, 0x30, 0x93, 0x42, 0x90, 0x31, 0x67, 0x92, 0x20, >+ 0x32, 0x73, 0x24, 0x90, 0x33, 0x47, 0x74, 0x20, 0x34, 0x53, 0x06, 0x90, >+ 0x35, 0x27, 0x56, 0x20, 0x36, 0x32, 0xe8, 0x90, 0x37, 0x07, 0x38, 0x20, >+ 0x38, 0x1c, 0x05, 0x10, 0x38, 0xe7, 0x1a, 0x20, 0x39, 0xfb, 0xe7, 0x10, >+ 0x3a, 0xc6, 0xfc, 0x20, 0x3b, 0xdb, 0xc9, 0x10, 0x3c, 0xb0, 0x18, 0xa0, >+ 0x3d, 0xbb, 0xab, 0x10, 0x3e, 0x8f, 0xfa, 0xa0, 0x3f, 0x9b, 0x8d, 0x10, >+ 0x40, 0x6f, 0xdc, 0xa0, 0x41, 0x84, 0xa9, 0x90, 0x42, 0x4f, 0xbe, 0xa0, >+ 0x43, 0x64, 0x8b, 0x90, 0x44, 0x2f, 0xa0, 0xa0, 0x45, 0x44, 0x6d, 0x90, >+ 0x45, 0xf3, 0xd3, 0x20, 0x47, 0x2d, 0x8a, 0x10, 0x47, 0xd3, 0xb5, 0x20, >+ 0x49, 0x0d, 0x6c, 0x10, 0x49, 0xb3, 0x97, 0x20, 0x4a, 0xed, 0x4e, 0x10, >+ 0x4b, 0x9c, 0xb3, 0xa0, 0x4c, 0xd6, 0x6a, 0x90, 0x4d, 0x7c, 0x95, 0xa0, >+ 0x4e, 0xb6, 0x4c, 0x90, 0x4f, 0x5c, 0x77, 0xa0, 0x50, 0x96, 0x2e, 0x90, >+ 0x51, 0x3c, 0x59, 0xa0, 0x52, 0x76, 0x10, 0x90, 0x53, 0x1c, 0x3b, 0xa0, >+ 0x54, 0x55, 0xf2, 0x90, 0x54, 0xfc, 0x1d, 0xa0, 0x56, 0x35, 0xd4, 0x90, >+ 0x56, 0xe5, 0x3a, 0x20, 0x58, 0x1e, 0xf1, 0x10, 0x58, 0xc5, 0x1c, 0x20, >+ 0x59, 0xfe, 0xd3, 0x10, 0x5a, 0xa4, 0xfe, 0x20, 0x5b, 0xde, 0xb5, 0x10, >+ 0x5c, 0x84, 0xe0, 0x20, 0x5d, 0xbe, 0x97, 0x10, 0x5e, 0x64, 0xc2, 0x20, >+ 0x5f, 0x9e, 0x79, 0x10, 0x60, 0x4d, 0xde, 0xa0, 0x61, 0x87, 0x95, 0x90, >+ 0x62, 0x2d, 0xc0, 0xa0, 0x63, 0x67, 0x77, 0x90, 0x64, 0x0d, 0xa2, 0xa0, >+ 0x65, 0x47, 0x59, 0x90, 0x65, 0xed, 0x84, 0xa0, 0x67, 0x27, 0x3b, 0x90, >+ 0x67, 0xcd, 0x66, 0xa0, 0x69, 0x07, 0x1d, 0x90, 0x69, 0xad, 0x48, 0xa0, >+ 0x6a, 0xe6, 0xff, 0x90, 0x6b, 0x96, 0x65, 0x20, 0x6c, 0xd0, 0x1c, 0x10, >+ 0x6d, 0x76, 0x47, 0x20, 0x6e, 0xaf, 0xfe, 0x10, 0x6f, 0x56, 0x29, 0x20, >+ 0x70, 0x8f, 0xe0, 0x10, 0x71, 0x36, 0x0b, 0x20, 0x72, 0x6f, 0xc2, 0x10, >+ 0x73, 0x15, 0xed, 0x20, 0x74, 0x4f, 0xa4, 0x10, 0x74, 0xff, 0x09, 0xa0, >+ 0x76, 0x38, 0xc0, 0x90, 0x76, 0xde, 0xeb, 0xa0, 0x78, 0x18, 0xa2, 0x90, >+ 0x78, 0xbe, 0xcd, 0xa0, 0x79, 0xf8, 0x84, 0x90, 0x7a, 0x9e, 0xaf, 0xa0, >+ 0x7b, 0xd8, 0x66, 0x90, 0x7c, 0x7e, 0x91, 0xa0, 0x7d, 0xb8, 0x48, 0x90, >+ 0x7e, 0x5e, 0x73, 0xa0, 0x7f, 0x98, 0x2a, 0x90, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, >+ 0x01, 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, >+ 0x01, 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, >+ 0x50, 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, >+ 0x50, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, >+ 0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0xbb, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x04, >+ 0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x48, 0xa0, 0xff, 0xff, >+ 0xff, 0xff, 0x9f, 0xbb, 0x15, 0x90, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, >+ 0x2a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xf7, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xcb, 0x89, 0x1a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x23, >+ 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x61, 0x26, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xd6, 0xfe, 0x74, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x80, >+ 0xad, 0x90, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xc3, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xdb, 0xc0, 0x90, 0x10, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xde, >+ 0xa5, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0xac, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xde, 0xbe, 0x87, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x89, >+ 0x8e, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x69, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xe1, 0x69, 0x70, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x7e, >+ 0x4b, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x52, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xe4, 0x5e, 0x2d, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x29, >+ 0x34, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x4a, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xe7, 0x12, 0x51, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x27, >+ 0x2c, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xf2, 0x33, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xea, 0x07, 0x0e, 0x10, 0xff, 0xff, 0xff, 0xff, 0xea, 0xd2, >+ 0x15, 0x10, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xf0, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xec, 0xb1, 0xf7, 0x10, 0xff, 0xff, 0xff, 0xff, 0xed, 0xc6, >+ 0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xee, 0x91, 0xd9, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xef, 0xaf, 0xee, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x71, >+ 0xbb, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xd0, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xf2, 0x7f, 0xc1, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x6f, >+ 0xb2, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0xa3, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xf5, 0x4f, 0x94, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x3f, >+ 0x85, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x76, 0x90, 0xff, 0xff, >+ 0xff, 0xff, 0xf8, 0x28, 0xa2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0f, >+ 0x58, 0x90, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x84, 0x10, 0xff, 0xff, >+ 0xff, 0xff, 0xfa, 0xf8, 0x83, 0x20, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe8, >+ 0x66, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x65, 0x20, 0xff, 0xff, >+ 0xff, 0xff, 0xfd, 0xc8, 0x48, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb8, >+ 0x47, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, >+ 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0b, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, >+ 0x27, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0a, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x06, 0x41, 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, >+ 0xec, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x43, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x09, 0x10, 0xce, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xad, >+ 0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0xb0, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x0b, 0xe0, 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd9, >+ 0xcd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x91, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x0e, 0xb9, 0xaf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa9, >+ 0xae, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79, >+ 0x73, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x72, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x14, 0x59, 0x55, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49, >+ 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x37, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x17, 0x29, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22, >+ 0x53, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x18, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x1a, 0x02, 0x35, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xf2, >+ 0x34, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe2, 0x17, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x1c, 0xd2, 0x16, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, >+ 0xf9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xf8, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x1f, 0xa1, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76, >+ 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xbd, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x22, 0x56, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6a, >+ 0xda, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xef, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x25, 0x4a, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15, >+ 0xd1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x9e, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x27, 0xfe, 0xed, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0a, >+ 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xcf, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x2a, 0xea, 0x62, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xbe, >+ 0xb1, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x7e, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x2d, 0x9e, 0x93, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb3, >+ 0x60, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x75, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x30, 0x93, 0x42, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67, >+ 0x92, 0x20, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x24, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x33, 0x47, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x34, 0x53, >+ 0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x56, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x36, 0x32, 0xe8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, >+ 0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x05, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x38, 0xe7, 0x1a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xfb, >+ 0xe7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xfc, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x3b, 0xdb, 0xc9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0, >+ 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0xab, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x3e, 0x8f, 0xfa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9b, >+ 0x8d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xdc, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x41, 0x84, 0xa9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4f, >+ 0xbe, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x8b, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x44, 0x2f, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, >+ 0x6d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xd3, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x47, 0x2d, 0x8a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xd3, >+ 0xb5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x6c, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x49, 0xb3, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xed, >+ 0x4e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0xb3, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x4c, 0xd6, 0x6a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x7c, >+ 0x95, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x4c, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x4f, 0x5c, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96, >+ 0x2e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x59, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x52, 0x76, 0x10, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1c, >+ 0x3b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xf2, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x54, 0xfc, 0x1d, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35, >+ 0xd4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x3a, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x58, 0x1e, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc5, >+ 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xd3, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x5a, 0xa4, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xde, >+ 0xb5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xe0, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x5d, 0xbe, 0x97, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x64, >+ 0xc2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x79, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x60, 0x4d, 0xde, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87, >+ 0x95, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0xc0, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x63, 0x67, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0d, >+ 0xa2, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x59, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x65, 0xed, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27, >+ 0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x66, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x69, 0x07, 0x1d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xad, >+ 0x48, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xff, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x6b, 0x96, 0x65, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xd0, >+ 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x47, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x6e, 0xaf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x56, >+ 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xe0, 0x10, 0x00, 0x00, >+ 0x00, 0x00, 0x71, 0x36, 0x0b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, >+ 0xc2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xed, 0x20, 0x00, 0x00, >+ 0x00, 0x00, 0x74, 0x4f, 0xa4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff, >+ 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xc0, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x76, 0xde, 0xeb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18, >+ 0xa2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xcd, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x79, 0xf8, 0x84, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x9e, >+ 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x66, 0x90, 0x00, 0x00, >+ 0x00, 0x00, 0x7c, 0x7e, 0x91, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7d, 0xb8, >+ 0x48, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x73, 0xa0, 0x00, 0x00, >+ 0x00, 0x00, 0x7f, 0x98, 0x2a, 0x90, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, 0x01, >+ 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, 0x01, >+ 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x50, >+ 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, >+ 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, >+ 0x01, 0x0a, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x2c, 0x4d, 0x33, >+ 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31, 0x2e, 0x30, >+ 0x0a >+}; >+unsigned int America_Los_Angeles_len = 2845; >+unsigned char America_New_York[] = { >+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, >+ 0x9e, 0xa6, 0x1e, 0x70, 0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70, >+ 0xa1, 0x9a, 0xcd, 0x60, 0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0, >+ 0xa4, 0x6a, 0xae, 0x70, 0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0, >+ 0xa7, 0x15, 0x89, 0x60, 0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0, >+ 0xaa, 0x13, 0x8e, 0xf0, 0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0, >+ 0xac, 0xbe, 0x69, 0xe0, 0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0, >+ 0xaf, 0xb3, 0x34, 0xf0, 0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70, >+ 0xb2, 0x67, 0x4a, 0x60, 0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60, >+ 0xb5, 0x5c, 0x15, 0x70, 0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70, >+ 0xb8, 0x06, 0xf0, 0x60, 0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60, >+ 0xbb, 0x04, 0xf5, 0xf0, 0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0, >+ 0xbd, 0xaf, 0xd0, 0xe0, 0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0, >+ 0xc0, 0xa4, 0x9b, 0xf0, 0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0, >+ 0xc3, 0x4f, 0x76, 0xe0, 0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0, >+ 0xc6, 0x4d, 0x7c, 0x70, 0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70, >+ 0xc8, 0xf8, 0x57, 0x60, 0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60, >+ 0xcb, 0x88, 0xf0, 0x70, 0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0, >+ 0xd3, 0x75, 0xe4, 0xf0, 0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0, >+ 0xd6, 0x20, 0xbf, 0xe0, 0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0, >+ 0xd9, 0x15, 0x8a, 0xf0, 0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70, >+ 0xdb, 0xc0, 0x65, 0xe0, 0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60, >+ 0xde, 0xbe, 0x6b, 0x70, 0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70, >+ 0xe1, 0x69, 0x46, 0x60, 0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60, >+ 0xe4, 0x5e, 0x11, 0x70, 0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0, >+ 0xe7, 0x37, 0x10, 0xe0, 0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0, >+ 0xea, 0x06, 0xf1, 0xf0, 0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0, >+ 0xec, 0xd6, 0xb6, 0xe0, 0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60, >+ 0xef, 0xaf, 0xd2, 0x70, 0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70, >+ 0xf2, 0x7f, 0x97, 0x60, 0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60, >+ 0xf5, 0x4f, 0x78, 0x70, 0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70, >+ 0xf8, 0x28, 0x77, 0xe0, 0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0, >+ 0xfa, 0xf8, 0x58, 0xf0, 0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0, >+ 0xfd, 0xc8, 0x1d, 0xe0, 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0, >+ 0x00, 0x97, 0xfe, 0xf0, 0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0, >+ 0x03, 0x70, 0xfe, 0x60, 0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60, >+ 0x06, 0x40, 0xdf, 0x70, 0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70, >+ 0x09, 0x10, 0xa4, 0x60, 0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60, >+ 0x0b, 0xe0, 0x85, 0x70, 0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70, >+ 0x0e, 0xb9, 0x84, 0xe0, 0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0, >+ 0x11, 0x89, 0x65, 0xf0, 0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0, >+ 0x14, 0x59, 0x2a, 0xe0, 0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0, >+ 0x17, 0x29, 0x0b, 0xf0, 0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0, >+ 0x1a, 0x02, 0x0b, 0x60, 0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60, >+ 0x1c, 0xd1, 0xec, 0x70, 0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70, >+ 0x1f, 0xa1, 0xb1, 0x60, 0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60, >+ 0x22, 0x55, 0xe2, 0xf0, 0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0, >+ 0x25, 0x4a, 0x91, 0xe0, 0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0, >+ 0x27, 0xfe, 0xc3, 0x70, 0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70, >+ 0x2a, 0xea, 0x37, 0xe0, 0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60, >+ 0x2d, 0x9e, 0x69, 0x70, 0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70, >+ 0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60, >+ 0x33, 0x47, 0x49, 0xf0, 0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0, >+ 0x36, 0x32, 0xbe, 0x60, 0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0, >+ 0x38, 0xe6, 0xef, 0xf0, 0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0, >+ 0x3b, 0xdb, 0x9e, 0xe0, 0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0, >+ 0x3e, 0x8f, 0xd0, 0x70, 0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70, >+ 0x41, 0x84, 0x7f, 0x60, 0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60, >+ 0x44, 0x2f, 0x76, 0x70, 0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0, >+ 0x47, 0x2d, 0x5f, 0xe0, 0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0, >+ 0x49, 0xb3, 0x6c, 0xf0, 0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70, >+ 0x4c, 0xd6, 0x40, 0x60, 0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60, >+ 0x4f, 0x5c, 0x4d, 0x70, 0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70, >+ 0x52, 0x75, 0xe6, 0x60, 0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60, >+ 0x54, 0xfb, 0xf3, 0x70, 0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0, >+ 0x58, 0x1e, 0xc6, 0xe0, 0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0, >+ 0x5a, 0xa4, 0xd3, 0xf0, 0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0, >+ 0x5d, 0xbe, 0x6c, 0xe0, 0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0, >+ 0x60, 0x4d, 0xb4, 0x70, 0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70, >+ 0x63, 0x67, 0x4d, 0x60, 0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60, >+ 0x65, 0xed, 0x5a, 0x70, 0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70, >+ 0x69, 0x06, 0xf3, 0x60, 0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60, >+ 0x6b, 0x96, 0x3a, 0xf0, 0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0, >+ 0x6e, 0xaf, 0xd3, 0xe0, 0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0, >+ 0x71, 0x35, 0xe0, 0xf0, 0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0, >+ 0x74, 0x4f, 0x79, 0xe0, 0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60, >+ 0x76, 0xde, 0xc1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70, >+ 0x79, 0xf8, 0x5a, 0x60, 0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60, >+ 0x7c, 0x7e, 0x67, 0x70, 0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70, >+ 0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x04, >+ 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c, >+ 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x45, 0x44, >+ 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50, >+ 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, >+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90, >+ 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0x9f, 0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xa2, 0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xa5, 0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xa8, 0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xaa, 0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xad, 0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xb0, 0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xb3, 0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xb6, 0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xb9, 0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xbb, 0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xbe, 0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xc1, 0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xc4, 0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xc7, 0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xca, 0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xd2, 0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xd4, 0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xd7, 0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xd9, 0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xdc, 0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xdf, 0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xe2, 0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xe5, 0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xe8, 0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xea, 0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xed, 0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xf0, 0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff, >+ 0xf3, 0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60, >+ 0xff, 0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff, >+ 0xf6, 0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xf9, 0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0, >+ 0xff, 0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xfb, 0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0, >+ 0xff, 0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff, >+ 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x01, 0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x04, 0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x07, 0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x09, 0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x0c, 0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x0f, 0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x12, 0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x15, 0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x18, 0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x1a, 0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x1d, 0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x20, 0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x23, 0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x26, 0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x29, 0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x2b, 0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x2e, 0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x31, 0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x34, 0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x37, 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x39, 0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x3c, 0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x3f, 0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x42, 0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x45, 0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x47, 0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x4a, 0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x4d, 0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x50, 0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x53, 0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x56, 0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x58, 0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x5b, 0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x5e, 0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x61, 0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x64, 0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x67, 0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x69, 0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x6c, 0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x6f, 0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0, >+ 0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00, >+ 0x72, 0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0, >+ 0x00, 0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, >+ 0x74, 0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x78, 0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00, >+ 0x7a, 0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60, >+ 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x7d, 0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70, >+ 0x00, 0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x00, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, >+ 0xff, 0xc7, 0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, >+ 0xff, 0xc7, 0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, >+ 0x4d, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, >+ 0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44, >+ 0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, >+ 0x2e, 0x31, 0x2e, 0x30, 0x0a >+}; >+unsigned int America_New_York_len = 3545; >+unsigned char Australia_Sydney[] = { >+ 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, >+ 0x9c, 0x4e, 0xa6, 0x9c, 0x9c, 0xbc, 0x20, 0xf0, 0xcb, 0x54, 0xb3, 0x00, >+ 0xcb, 0xc7, 0x57, 0x70, 0xcc, 0xb7, 0x56, 0x80, 0xcd, 0xa7, 0x39, 0x70, >+ 0xce, 0xa0, 0x73, 0x00, 0xcf, 0x87, 0x1b, 0x70, 0x03, 0x70, 0x39, 0x80, >+ 0x04, 0x0d, 0x1c, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x05, 0xf6, 0x38, 0x80, >+ 0x07, 0x2f, 0xfd, 0x80, 0x07, 0xd6, 0x1a, 0x80, 0x09, 0x0f, 0xdf, 0x80, >+ 0x09, 0xb5, 0xfc, 0x80, 0x0a, 0xef, 0xc1, 0x80, 0x0b, 0x9f, 0x19, 0x00, >+ 0x0c, 0xd8, 0xde, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x0e, 0xb8, 0xc0, 0x00, >+ 0x0f, 0x5e, 0xdd, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x11, 0x3e, 0xbf, 0x00, >+ 0x12, 0x78, 0x84, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x14, 0x58, 0x66, 0x00, >+ 0x14, 0xfe, 0x83, 0x00, 0x16, 0x38, 0x48, 0x00, 0x17, 0x0c, 0x89, 0x80, >+ 0x18, 0x21, 0x64, 0x80, 0x18, 0xc7, 0x81, 0x80, 0x1a, 0x01, 0x46, 0x80, >+ 0x1a, 0xa7, 0x63, 0x80, 0x1b, 0xe1, 0x28, 0x80, 0x1c, 0x87, 0x45, 0x80, >+ 0x1d, 0xc1, 0x0a, 0x80, 0x1e, 0x79, 0x9c, 0x80, 0x1f, 0x97, 0xb2, 0x00, >+ 0x20, 0x59, 0x7e, 0x80, 0x21, 0x80, 0xce, 0x80, 0x22, 0x42, 0x9b, 0x00, >+ 0x23, 0x69, 0xeb, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x25, 0x49, 0xcd, 0x00, >+ 0x25, 0xef, 0xea, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x27, 0xcf, 0xcc, 0x00, >+ 0x29, 0x09, 0x91, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x2a, 0xe9, 0x73, 0x00, >+ 0x2b, 0x98, 0xca, 0x80, 0x2c, 0xd2, 0x8f, 0x80, 0x2d, 0x78, 0xac, 0x80, >+ 0x2e, 0xb2, 0x71, 0x80, 0x2f, 0x58, 0x8e, 0x80, 0x30, 0x92, 0x53, 0x80, >+ 0x31, 0x5d, 0x5a, 0x80, 0x32, 0x72, 0x35, 0x80, 0x33, 0x3d, 0x3c, 0x80, >+ 0x34, 0x52, 0x17, 0x80, 0x35, 0x1d, 0x1e, 0x80, 0x36, 0x31, 0xf9, 0x80, >+ 0x36, 0xfd, 0x00, 0x80, 0x38, 0x1b, 0x16, 0x00, 0x38, 0xdc, 0xe2, 0x80, >+ 0x39, 0xa7, 0xe9, 0x80, 0x3a, 0xbc, 0xc4, 0x80, 0x3b, 0xda, 0xda, 0x00, >+ 0x3c, 0xa5, 0xe1, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x3e, 0x85, 0xc3, 0x00, >+ 0x3f, 0x9a, 0x9e, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x41, 0x83, 0xba, 0x80, >+ 0x42, 0x45, 0x87, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x44, 0x2e, 0xa3, 0x80, >+ 0x45, 0x43, 0x7e, 0x80, 0x46, 0x05, 0x4b, 0x00, 0x47, 0x23, 0x60, 0x80, >+ 0x47, 0xf7, 0xa2, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x49, 0xd7, 0x84, 0x00, >+ 0x4a, 0xc7, 0x75, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x4c, 0xa7, 0x57, 0x00, >+ 0x4d, 0x97, 0x48, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x4f, 0x77, 0x2a, 0x00, >+ 0x50, 0x70, 0x55, 0x80, 0x51, 0x60, 0x46, 0x80, 0x52, 0x50, 0x37, 0x80, >+ 0x53, 0x40, 0x28, 0x80, 0x54, 0x30, 0x19, 0x80, 0x55, 0x20, 0x0a, 0x80, >+ 0x56, 0x0f, 0xfb, 0x80, 0x56, 0xff, 0xec, 0x80, 0x57, 0xef, 0xdd, 0x80, >+ 0x58, 0xdf, 0xce, 0x80, 0x59, 0xcf, 0xbf, 0x80, 0x5a, 0xbf, 0xb0, 0x80, >+ 0x5b, 0xb8, 0xdc, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x5d, 0x98, 0xbe, 0x00, >+ 0x5e, 0x88, 0xaf, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x60, 0x68, 0x91, 0x00, >+ 0x61, 0x58, 0x82, 0x00, 0x62, 0x48, 0x73, 0x00, 0x63, 0x38, 0x64, 0x00, >+ 0x64, 0x28, 0x55, 0x00, 0x65, 0x18, 0x46, 0x00, 0x66, 0x11, 0x71, 0x80, >+ 0x67, 0x01, 0x62, 0x80, 0x67, 0xf1, 0x53, 0x80, 0x68, 0xe1, 0x44, 0x80, >+ 0x69, 0xd1, 0x35, 0x80, 0x6a, 0xc1, 0x26, 0x80, 0x6b, 0xb1, 0x17, 0x80, >+ 0x6c, 0xa1, 0x08, 0x80, 0x6d, 0x90, 0xf9, 0x80, 0x6e, 0x80, 0xea, 0x80, >+ 0x6f, 0x70, 0xdb, 0x80, 0x70, 0x6a, 0x07, 0x00, 0x71, 0x59, 0xf8, 0x00, >+ 0x72, 0x49, 0xe9, 0x00, 0x73, 0x39, 0xda, 0x00, 0x74, 0x29, 0xcb, 0x00, >+ 0x75, 0x19, 0xbc, 0x00, 0x76, 0x09, 0xad, 0x00, 0x76, 0xf9, 0x9e, 0x00, >+ 0x77, 0xe9, 0x8f, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x79, 0xc9, 0x71, 0x00, >+ 0x7a, 0xb9, 0x62, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x7c, 0xa2, 0x7e, 0x80, >+ 0x7d, 0x92, 0x6f, 0x80, 0x7e, 0x82, 0x60, 0x80, 0x7f, 0x72, 0x51, 0x80, >+ 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, >+ 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00, >+ 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00, >+ 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00, >+ 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x45, 0x44, 0x54, >+ 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, >+ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, >+ 0x73, 0x16, 0x7f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x4e, 0xa6, 0x9c, >+ 0xff, 0xff, 0xff, 0xff, 0x9c, 0xbc, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff, >+ 0xcb, 0x54, 0xb3, 0x00, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xc7, 0x57, 0x70, >+ 0xff, 0xff, 0xff, 0xff, 0xcc, 0xb7, 0x56, 0x80, 0xff, 0xff, 0xff, 0xff, >+ 0xcd, 0xa7, 0x39, 0x70, 0xff, 0xff, 0xff, 0xff, 0xce, 0xa0, 0x73, 0x00, >+ 0xff, 0xff, 0xff, 0xff, 0xcf, 0x87, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, >+ 0x03, 0x70, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x1c, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x05, 0xf6, 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2f, 0xfd, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x07, 0xd6, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x09, 0x0f, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb5, 0xfc, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0xef, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x0b, 0x9f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd8, 0xde, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x0e, 0xb8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xdd, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x11, 0x3e, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x78, 0x84, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x14, 0x58, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xfe, 0x83, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x16, 0x38, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x17, 0x0c, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x21, 0x64, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x18, 0xc7, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x1a, 0x01, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xa7, 0x63, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x1c, 0x87, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, 0x0a, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x79, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x1f, 0x97, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x7e, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x22, 0x42, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0xeb, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x25, 0x49, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xef, 0xea, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x27, 0xcf, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x09, 0x91, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x2a, 0xe9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x98, 0xca, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd2, 0x8f, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x2d, 0x78, 0xac, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb2, 0x71, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x2f, 0x58, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x30, 0x92, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5d, 0x5a, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x33, 0x3d, 0x3c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x17, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x36, 0x31, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x36, 0xfd, 0x00, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x38, 0xdc, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa7, 0xe9, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x3a, 0xbc, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x3b, 0xda, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa5, 0xe1, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x3e, 0x85, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9a, 0x9e, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x41, 0x83, 0xba, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x87, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x44, 0x2e, 0xa3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0x7e, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x47, 0x23, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0xf7, 0xa2, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x49, 0xd7, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xc7, 0x75, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x4c, 0xa7, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x97, 0x48, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x4f, 0x77, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x70, 0x55, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x51, 0x60, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x52, 0x50, 0x37, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x40, 0x28, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x54, 0x30, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x55, 0x20, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0x0f, 0xfb, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x56, 0xff, 0xec, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x57, 0xef, 0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x58, 0xdf, 0xce, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x59, 0xcf, 0xbf, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x5a, 0xbf, 0xb0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xb8, 0xdc, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x5d, 0x98, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x88, 0xaf, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x60, 0x68, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x58, 0x82, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x62, 0x48, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x63, 0x38, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x55, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x65, 0x18, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x66, 0x11, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x62, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x67, 0xf1, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x68, 0xe1, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xd1, 0x35, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x6a, 0xc1, 0x26, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x6b, 0xb1, 0x17, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xa1, 0x08, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x6d, 0x90, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x6e, 0x80, 0xea, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0xdb, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x70, 0x6a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x71, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x49, 0xe9, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x73, 0x39, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x74, 0x29, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x19, 0xbc, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x76, 0x09, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x76, 0xf9, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xe9, 0x8f, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x79, 0xc9, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xb9, 0x62, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x7c, 0xa2, 0x7e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x92, 0x6f, 0x80, >+ 0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, >+ 0x7f, 0x72, 0x51, 0x80, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, >+ 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, >+ 0x03, 0x04, 0x03, 0x00, 0x00, 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, >+ 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, >+ 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, >+ 0x00, 0x41, 0x45, 0x44, 0x54, 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, >+ 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x45, >+ 0x53, 0x54, 0x2d, 0x31, 0x30, 0x41, 0x45, 0x44, 0x54, 0x2c, 0x4d, 0x31, >+ 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x4d, 0x34, 0x2e, 0x31, 0x2e, 0x30, >+ 0x2f, 0x33, 0x0a >+}; >+unsigned int Australia_Sydney_len = 2223; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.cc >new file mode 100644 >index 00000000000..71fd8ee6e74 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.cc >@@ -0,0 +1,384 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// The implementation of the absl::Time class, which is declared in >+// //absl/time.h. >+// >+// The representation for an absl::Time is an absl::Duration offset from the >+// epoch. We use the traditional Unix epoch (1970-01-01 00:00:00 +0000) >+// for convenience, but this is not exposed in the API and could be changed. >+// >+// NOTE: To keep type verbosity to a minimum, the following variable naming >+// conventions are used throughout this file. >+// >+// cz: A cctz::time_zone >+// tz: An absl::TimeZone >+// cl: A cctz::time_zone::civil_lookup >+// al: A cctz::time_zone::absolute_lookup >+// cd: A cctz::civil_day >+// cs: A cctz::civil_second >+// bd: An absl::Time::Breakdown >+ >+#include "absl/time/time.h" >+ >+#include <cstring> >+#include <ctime> >+#include <limits> >+ >+#include "absl/time/internal/cctz/include/cctz/civil_time.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+namespace cctz = absl::time_internal::cctz; >+namespace absl { >+ >+namespace { >+ >+inline cctz::time_point<cctz::seconds> unix_epoch() { >+ return std::chrono::time_point_cast<cctz::seconds>( >+ std::chrono::system_clock::from_time_t(0)); >+} >+ >+// Floors d to the next unit boundary closer to negative infinity. >+inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { >+ absl::Duration rem; >+ int64_t q = absl::IDivDuration(d, unit, &rem); >+ return (q > 0 || >+ rem >= ZeroDuration() || >+ q == std::numeric_limits<int64_t>::min()) ? q : q - 1; >+} >+ >+inline absl::Time::Breakdown InfiniteFutureBreakdown() { >+ absl::Time::Breakdown bd; >+ bd.year = std::numeric_limits<int64_t>::max(); >+ bd.month = 12; >+ bd.day = 31; >+ bd.hour = 23; >+ bd.minute = 59; >+ bd.second = 59; >+ bd.subsecond = absl::InfiniteDuration(); >+ bd.weekday = 4; >+ bd.yearday = 365; >+ bd.offset = 0; >+ bd.is_dst = false; >+ bd.zone_abbr = "-00"; >+ return bd; >+} >+ >+inline Time::Breakdown InfinitePastBreakdown() { >+ Time::Breakdown bd; >+ bd.year = std::numeric_limits<int64_t>::min(); >+ bd.month = 1; >+ bd.day = 1; >+ bd.hour = 0; >+ bd.minute = 0; >+ bd.second = 0; >+ bd.subsecond = -absl::InfiniteDuration(); >+ bd.weekday = 7; >+ bd.yearday = 1; >+ bd.offset = 0; >+ bd.is_dst = false; >+ bd.zone_abbr = "-00"; >+ return bd; >+} >+ >+inline absl::TimeConversion InfiniteFutureTimeConversion() { >+ absl::TimeConversion tc; >+ tc.pre = tc.trans = tc.post = absl::InfiniteFuture(); >+ tc.kind = absl::TimeConversion::UNIQUE; >+ tc.normalized = true; >+ return tc; >+} >+ >+inline TimeConversion InfinitePastTimeConversion() { >+ absl::TimeConversion tc; >+ tc.pre = tc.trans = tc.post = absl::InfinitePast(); >+ tc.kind = absl::TimeConversion::UNIQUE; >+ tc.normalized = true; >+ return tc; >+} >+ >+// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as >+// necessary. If sec is min/max, then consult cs+tz to check for overlow. >+Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec, >+ const cctz::civil_second& cs, >+ const cctz::time_zone& tz, >+ bool* normalized = nullptr) { >+ const auto max = cctz::time_point<cctz::seconds>::max(); >+ const auto min = cctz::time_point<cctz::seconds>::min(); >+ if (sec == max) { >+ const auto al = tz.lookup(max); >+ if (cs > al.cs) { >+ if (normalized) *normalized = true; >+ return absl::InfiniteFuture(); >+ } >+ } >+ if (sec == min) { >+ const auto al = tz.lookup(min); >+ if (cs < al.cs) { >+ if (normalized) *normalized = true; >+ return absl::InfinitePast(); >+ } >+ } >+ const auto hi = (sec - unix_epoch()).count(); >+ return time_internal::FromUnixDuration(time_internal::MakeDuration(hi)); >+} >+ >+inline absl::TimeConversion::Kind MapKind( >+ const cctz::time_zone::civil_lookup::civil_kind& kind) { >+ switch (kind) { >+ case cctz::time_zone::civil_lookup::UNIQUE: >+ return absl::TimeConversion::UNIQUE; >+ case cctz::time_zone::civil_lookup::SKIPPED: >+ return absl::TimeConversion::SKIPPED; >+ case cctz::time_zone::civil_lookup::REPEATED: >+ return absl::TimeConversion::REPEATED; >+ } >+ return absl::TimeConversion::UNIQUE; >+} >+ >+// Returns Mon=1..Sun=7. >+inline int MapWeekday(const cctz::weekday& wd) { >+ switch (wd) { >+ case cctz::weekday::monday: >+ return 1; >+ case cctz::weekday::tuesday: >+ return 2; >+ case cctz::weekday::wednesday: >+ return 3; >+ case cctz::weekday::thursday: >+ return 4; >+ case cctz::weekday::friday: >+ return 5; >+ case cctz::weekday::saturday: >+ return 6; >+ case cctz::weekday::sunday: >+ return 7; >+ } >+ return 1; >+} >+ >+} // namespace >+ >+absl::Time::Breakdown Time::In(absl::TimeZone tz) const { >+ if (*this == absl::InfiniteFuture()) return absl::InfiniteFutureBreakdown(); >+ if (*this == absl::InfinitePast()) return absl::InfinitePastBreakdown(); >+ >+ const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_)); >+ const auto al = cctz::time_zone(tz).lookup(tp); >+ const auto cs = al.cs; >+ const auto cd = cctz::civil_day(cs); >+ >+ absl::Time::Breakdown bd; >+ bd.year = cs.year(); >+ bd.month = cs.month(); >+ bd.day = cs.day(); >+ bd.hour = cs.hour(); >+ bd.minute = cs.minute(); >+ bd.second = cs.second(); >+ bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_)); >+ bd.weekday = MapWeekday(get_weekday(cd)); >+ bd.yearday = get_yearday(cd); >+ bd.offset = al.offset; >+ bd.is_dst = al.is_dst; >+ bd.zone_abbr = al.abbr; >+ return bd; >+} >+ >+absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) { >+ const auto cz = cctz::time_zone(tz); >+ const auto cs = >+ cctz::civil_second(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, >+ tm.tm_hour, tm.tm_min, tm.tm_sec); >+ const auto cl = cz.lookup(cs); >+ const auto tp = tm.tm_isdst == 0 ? cl.post : cl.pre; >+ return MakeTimeWithOverflow(tp, cs, cz); >+} >+ >+struct tm ToTM(absl::Time t, absl::TimeZone tz) { >+ const absl::Time::Breakdown bd = t.In(tz); >+ struct tm tm; >+ std::memset(&tm, 0, sizeof(tm)); >+ tm.tm_sec = bd.second; >+ tm.tm_min = bd.minute; >+ tm.tm_hour = bd.hour; >+ tm.tm_mday = bd.day; >+ tm.tm_mon = bd.month - 1; >+ >+ // Saturates tm.tm_year in cases of over/underflow, accounting for the fact >+ // that tm.tm_year is years since 1900. >+ if (bd.year < std::numeric_limits<int>::min() + 1900) { >+ tm.tm_year = std::numeric_limits<int>::min(); >+ } else if (bd.year > std::numeric_limits<int>::max()) { >+ tm.tm_year = std::numeric_limits<int>::max() - 1900; >+ } else { >+ tm.tm_year = static_cast<int>(bd.year - 1900); >+ } >+ >+ tm.tm_wday = bd.weekday % 7; >+ tm.tm_yday = bd.yearday - 1; >+ tm.tm_isdst = bd.is_dst ? 1 : 0; >+ >+ return tm; >+} >+ >+// >+// Factory functions. >+// >+ >+absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, >+ int min, int sec, TimeZone tz) { >+ // Avoids years that are too extreme for civil_second to normalize. >+ if (year > 300000000000) return InfiniteFutureTimeConversion(); >+ if (year < -300000000000) return InfinitePastTimeConversion(); >+ const auto cz = cctz::time_zone(tz); >+ const auto cs = cctz::civil_second(year, mon, day, hour, min, sec); >+ absl::TimeConversion tc; >+ tc.normalized = year != cs.year() || mon != cs.month() || day != cs.day() || >+ hour != cs.hour() || min != cs.minute() || sec != cs.second(); >+ const auto cl = cz.lookup(cs); >+ // Converts the civil_lookup struct to a TimeConversion. >+ tc.pre = MakeTimeWithOverflow(cl.pre, cs, cz, &tc.normalized); >+ tc.trans = MakeTimeWithOverflow(cl.trans, cs, cz, &tc.normalized); >+ tc.post = MakeTimeWithOverflow(cl.post, cs, cz, &tc.normalized); >+ tc.kind = MapKind(cl.kind); >+ return tc; >+} >+ >+absl::Time FromDateTime(int64_t year, int mon, int day, int hour, int min, >+ int sec, TimeZone tz) { >+ if (year > 300000000000) return InfiniteFuture(); >+ if (year < -300000000000) return InfinitePast(); >+ const auto cz = cctz::time_zone(tz); >+ const auto cs = cctz::civil_second(year, mon, day, hour, min, sec); >+ const auto cl = cz.lookup(cs); >+ return MakeTimeWithOverflow(cl.pre, cs, cz); >+} >+ >+absl::Time TimeFromTimespec(timespec ts) { >+ return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts)); >+} >+ >+absl::Time TimeFromTimeval(timeval tv) { >+ return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv)); >+} >+ >+absl::Time FromUDate(double udate) { >+ return time_internal::FromUnixDuration(absl::Milliseconds(udate)); >+} >+ >+absl::Time FromUniversal(int64_t universal) { >+ return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal); >+} >+ >+// >+// Conversion to other time types. >+// >+ >+int64_t ToUnixNanos(Time t) { >+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && >+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) { >+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * >+ 1000 * 1000 * 1000) + >+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4); >+ } >+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1)); >+} >+ >+int64_t ToUnixMicros(Time t) { >+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && >+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) { >+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * >+ 1000 * 1000) + >+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000); >+ } >+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1)); >+} >+ >+int64_t ToUnixMillis(Time t) { >+ if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && >+ time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) { >+ return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) + >+ (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / >+ (4000 * 1000)); >+ } >+ return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1)); >+} >+ >+int64_t ToUnixSeconds(Time t) { >+ return time_internal::GetRepHi(time_internal::ToUnixDuration(t)); >+} >+ >+time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; } >+ >+timespec ToTimespec(Time t) { >+ timespec ts; >+ absl::Duration d = time_internal::ToUnixDuration(t); >+ if (!time_internal::IsInfiniteDuration(d)) { >+ ts.tv_sec = time_internal::GetRepHi(d); >+ if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing >+ ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor >+ return ts; >+ } >+ } >+ if (d >= absl::ZeroDuration()) { >+ ts.tv_sec = std::numeric_limits<time_t>::max(); >+ ts.tv_nsec = 1000 * 1000 * 1000 - 1; >+ } else { >+ ts.tv_sec = std::numeric_limits<time_t>::min(); >+ ts.tv_nsec = 0; >+ } >+ return ts; >+} >+ >+timeval ToTimeval(Time t) { >+ timeval tv; >+ timespec ts = absl::ToTimespec(t); >+ tv.tv_sec = ts.tv_sec; >+ if (tv.tv_sec != ts.tv_sec) { // narrowing >+ if (ts.tv_sec < 0) { >+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min(); >+ tv.tv_usec = 0; >+ } else { >+ tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max(); >+ tv.tv_usec = 1000 * 1000 - 1; >+ } >+ return tv; >+ } >+ tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t >+ return tv; >+} >+ >+double ToUDate(Time t) { >+ return absl::FDivDuration(time_internal::ToUnixDuration(t), >+ absl::Milliseconds(1)); >+} >+ >+int64_t ToUniversal(absl::Time t) { >+ return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100)); >+} >+ >+Time FromChrono(const std::chrono::system_clock::time_point& tp) { >+ return time_internal::FromUnixDuration(time_internal::FromChrono( >+ tp - std::chrono::system_clock::from_time_t(0))); >+} >+ >+std::chrono::system_clock::time_point ToChronoTime(absl::Time t) { >+ using D = std::chrono::system_clock::duration; >+ auto d = time_internal::ToUnixDuration(t); >+ if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1})); >+ return std::chrono::system_clock::from_time_t(0) + >+ time_internal::ToChronoDuration<D>(d); >+} >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.h >new file mode 100644 >index 00000000000..c41cb89c5ef >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time.h >@@ -0,0 +1,1349 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// File: time.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines abstractions for computing with absolute points >+// in time, durations of time, and formatting and parsing time within a given >+// time zone. The following abstractions are defined: >+// >+// * `absl::Time` defines an absolute, specific instance in time >+// * `absl::Duration` defines a signed, fixed-length span of time >+// * `absl::TimeZone` defines geopolitical time zone regions (as collected >+// within the IANA Time Zone database (https://www.iana.org/time-zones)). >+// >+// Example: >+// >+// absl::TimeZone nyc; >+// >+// // LoadTimeZone may fail so it's always better to check for success. >+// if (!absl::LoadTimeZone("America/New_York", &nyc)) { >+// // handle error case >+// } >+// >+// // My flight leaves NYC on Jan 2, 2017 at 03:04:05 >+// absl::Time takeoff = absl::FromDateTime(2017, 1, 2, 3, 4, 5, nyc); >+// absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35); >+// absl::Time landing = takeoff + flight_duration; >+// >+// absl::TimeZone syd; >+// if (!absl::LoadTimeZone("Australia/Sydney", &syd)) { >+// // handle error case >+// } >+// std::string s = absl::FormatTime( >+// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S", >+// landing, syd); >+// >+#ifndef ABSL_TIME_TIME_H_ >+#define ABSL_TIME_TIME_H_ >+ >+#if !defined(_MSC_VER) >+#include <sys/time.h> >+#else >+#include <winsock2.h> >+#endif >+#include <chrono> // NOLINT(build/c++11) >+#include <cstdint> >+#include <ctime> >+#include <ostream> >+#include <string> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/base/port.h" // Needed for string vs std::string >+#include "absl/strings/string_view.h" >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+namespace absl { >+ >+class Duration; // Defined below >+class Time; // Defined below >+class TimeZone; // Defined below >+ >+namespace time_internal { >+int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem); >+constexpr Time FromUnixDuration(Duration d); >+constexpr Duration ToUnixDuration(Time t); >+constexpr int64_t GetRepHi(Duration d); >+constexpr uint32_t GetRepLo(Duration d); >+constexpr Duration MakeDuration(int64_t hi, uint32_t lo); >+constexpr Duration MakeDuration(int64_t hi, int64_t lo); >+inline Duration MakePosDoubleDuration(double n); >+constexpr int64_t kTicksPerNanosecond = 4; >+constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond; >+template <std::intmax_t N> >+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>); >+constexpr Duration FromInt64(int64_t v, std::ratio<60>); >+constexpr Duration FromInt64(int64_t v, std::ratio<3600>); >+template <typename T> >+using EnableIfIntegral = typename std::enable_if< >+ std::is_integral<T>::value || std::is_enum<T>::value, int>::type; >+template <typename T> >+using EnableIfFloat = >+ typename std::enable_if<std::is_floating_point<T>::value, int>::type; >+} // namespace time_internal >+ >+// Duration >+// >+// The `absl::Duration` class represents a signed, fixed-length span of time. >+// A `Duration` is generated using a unit-specific factory function, or is >+// the result of subtracting one `absl::Time` from another. Durations behave >+// like unit-safe integers and they support all the natural integer-like >+// arithmetic operations. Arithmetic overflows and saturates at +/- infinity. >+// `Duration` should be passed by value rather than const reference. >+// >+// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`, >+// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for >+// creation of constexpr `Duration` values >+// >+// Examples: >+// >+// constexpr absl::Duration ten_ns = absl::Nanoseconds(10); >+// constexpr absl::Duration min = absl::Minutes(1); >+// constexpr absl::Duration hour = absl::Hours(1); >+// absl::Duration dur = 60 * min; // dur == hour >+// absl::Duration half_sec = absl::Milliseconds(500); >+// absl::Duration quarter_sec = 0.25 * absl::Seconds(1); >+// >+// `Duration` values can be easily converted to an integral number of units >+// using the division operator. >+// >+// Example: >+// >+// constexpr absl::Duration dur = absl::Milliseconds(1500); >+// int64_t ns = dur / absl::Nanoseconds(1); // ns == 1500000000 >+// int64_t ms = dur / absl::Milliseconds(1); // ms == 1500 >+// int64_t sec = dur / absl::Seconds(1); // sec == 1 (subseconds truncated) >+// int64_t min = dur / absl::Minutes(1); // min == 0 >+// >+// See the `IDivDuration()` and `FDivDuration()` functions below for details on >+// how to access the fractional parts of the quotient. >+// >+// Alternatively, conversions can be performed using helpers such as >+// `ToInt64Microseconds()` and `ToDoubleSeconds()`. >+class Duration { >+ public: >+ // Value semantics. >+ constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration >+ >+ // Compound assignment operators. >+ Duration& operator+=(Duration d); >+ Duration& operator-=(Duration d); >+ Duration& operator*=(int64_t r); >+ Duration& operator*=(double r); >+ Duration& operator/=(int64_t r); >+ Duration& operator/=(double r); >+ Duration& operator%=(Duration rhs); >+ >+ // Overloads that forward to either the int64_t or double overloads above. >+ template <typename T> >+ Duration& operator*=(T r) { >+ int64_t x = r; >+ return *this *= x; >+ } >+ template <typename T> >+ Duration& operator/=(T r) { >+ int64_t x = r; >+ return *this /= x; >+ } >+ Duration& operator*=(float r) { return *this *= static_cast<double>(r); } >+ Duration& operator/=(float r) { return *this /= static_cast<double>(r); } >+ >+ private: >+ friend constexpr int64_t time_internal::GetRepHi(Duration d); >+ friend constexpr uint32_t time_internal::GetRepLo(Duration d); >+ friend constexpr Duration time_internal::MakeDuration(int64_t hi, >+ uint32_t lo); >+ constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {} >+ int64_t rep_hi_; >+ uint32_t rep_lo_; >+}; >+ >+// Relational Operators >+constexpr bool operator<(Duration lhs, Duration rhs); >+constexpr bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; } >+constexpr bool operator>=(Duration lhs, Duration rhs) { return !(lhs < rhs); } >+constexpr bool operator<=(Duration lhs, Duration rhs) { return !(rhs < lhs); } >+constexpr bool operator==(Duration lhs, Duration rhs); >+constexpr bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); } >+ >+// Additive Operators >+constexpr Duration operator-(Duration d); >+inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; } >+inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; } >+ >+// Multiplicative Operators >+template <typename T> >+Duration operator*(Duration lhs, T rhs) { >+ return lhs *= rhs; >+} >+template <typename T> >+Duration operator*(T lhs, Duration rhs) { >+ return rhs *= lhs; >+} >+template <typename T> >+Duration operator/(Duration lhs, T rhs) { >+ return lhs /= rhs; >+} >+inline int64_t operator/(Duration lhs, Duration rhs) { >+ return time_internal::IDivDuration(true, lhs, rhs, >+ &lhs); // trunc towards zero >+} >+inline Duration operator%(Duration lhs, Duration rhs) { return lhs %= rhs; } >+ >+// IDivDuration() >+// >+// Divides a numerator `Duration` by a denominator `Duration`, returning the >+// quotient and remainder. The remainder always has the same sign as the >+// numerator. The returned quotient and remainder respect the identity: >+// >+// numerator = denominator * quotient + remainder >+// >+// Returned quotients are capped to the range of `int64_t`, with the difference >+// spilling into the remainder to uphold the above identity. This means that the >+// remainder returned could differ from the remainder returned by >+// `Duration::operator%` for huge quotients. >+// >+// See also the notes on `InfiniteDuration()` below regarding the behavior of >+// division involving zero and infinite durations. >+// >+// Example: >+// >+// constexpr absl::Duration a = >+// absl::Seconds(std::numeric_limits<int64_t>::max()); // big >+// constexpr absl::Duration b = absl::Nanoseconds(1); // small >+// >+// absl::Duration rem = a % b; >+// // rem == absl::ZeroDuration() >+// >+// // Here, q would overflow int64_t, so rem accounts for the difference. >+// int64_t q = absl::IDivDuration(a, b, &rem); >+// // q == std::numeric_limits<int64_t>::max(), rem == a - b * q >+inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) { >+ return time_internal::IDivDuration(true, num, den, >+ rem); // trunc towards zero >+} >+ >+// FDivDuration() >+// >+// Divides a `Duration` numerator into a fractional number of units of a >+// `Duration` denominator. >+// >+// See also the notes on `InfiniteDuration()` below regarding the behavior of >+// division involving zero and infinite durations. >+// >+// Example: >+// >+// double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1)); >+// // d == 1.5 >+double FDivDuration(Duration num, Duration den); >+ >+// ZeroDuration() >+// >+// Returns a zero-length duration. This function behaves just like the default >+// constructor, but the name helps make the semantics clear at call sites. >+constexpr Duration ZeroDuration() { return Duration(); } >+ >+// AbsDuration() >+// >+// Returns the absolute value of a duration. >+inline Duration AbsDuration(Duration d) { >+ return (d < ZeroDuration()) ? -d : d; >+} >+ >+// Trunc() >+// >+// Truncates a duration (toward zero) to a multiple of a non-zero unit. >+// >+// Example: >+// >+// absl::Duration d = absl::Nanoseconds(123456789); >+// absl::Duration a = absl::Trunc(d, absl::Microseconds(1)); // 123456us >+Duration Trunc(Duration d, Duration unit); >+ >+// Floor() >+// >+// Floors a duration using the passed duration unit to its largest value not >+// greater than the duration. >+// >+// Example: >+// >+// absl::Duration d = absl::Nanoseconds(123456789); >+// absl::Duration b = absl::Floor(d, absl::Microseconds(1)); // 123456us >+Duration Floor(Duration d, Duration unit); >+ >+// Ceil() >+// >+// Returns the ceiling of a duration using the passed duration unit to its >+// smallest value not less than the duration. >+// >+// Example: >+// >+// absl::Duration d = absl::Nanoseconds(123456789); >+// absl::Duration c = absl::Ceil(d, absl::Microseconds(1)); // 123457us >+Duration Ceil(Duration d, Duration unit); >+ >+// InfiniteDuration() >+// >+// Returns an infinite `Duration`. To get a `Duration` representing negative >+// infinity, use `-InfiniteDuration()`. >+// >+// Duration arithmetic overflows to +/- infinity and saturates. In general, >+// arithmetic with `Duration` infinities is similar to IEEE 754 infinities >+// except where IEEE 754 NaN would be involved, in which case +/- >+// `InfiniteDuration()` is used in place of a "nan" Duration. >+// >+// Examples: >+// >+// constexpr absl::Duration inf = absl::InfiniteDuration(); >+// const absl::Duration d = ... any finite duration ... >+// >+// inf == inf + inf >+// inf == inf + d >+// inf == inf - inf >+// -inf == d - inf >+// >+// inf == d * 1e100 >+// inf == inf / 2 >+// 0 == d / inf >+// INT64_MAX == inf / d >+// >+// // Division by zero returns infinity, or INT64_MIN/MAX where appropriate. >+// inf == d / 0 >+// INT64_MAX == d / absl::ZeroDuration() >+// >+// The examples involving the `/` operator above also apply to `IDivDuration()` >+// and `FDivDuration()`. >+constexpr Duration InfiniteDuration(); >+ >+// Nanoseconds() >+// Microseconds() >+// Milliseconds() >+// Seconds() >+// Minutes() >+// Hours() >+// >+// Factory functions for constructing `Duration` values from an integral number >+// of the unit indicated by the factory function's name. >+// >+// Note: no "Days()" factory function exists because "a day" is ambiguous. Civil >+// days are not always 24 hours long, and a 24-hour duration often does not >+// correspond with a civil day. If a 24-hour duration is needed, use >+// `absl::Hours(24)`. >+// >+// >+// Example: >+// >+// absl::Duration a = absl::Seconds(60); >+// absl::Duration b = absl::Minutes(1); // b == a >+constexpr Duration Nanoseconds(int64_t n); >+constexpr Duration Microseconds(int64_t n); >+constexpr Duration Milliseconds(int64_t n); >+constexpr Duration Seconds(int64_t n); >+constexpr Duration Minutes(int64_t n); >+constexpr Duration Hours(int64_t n); >+ >+// Factory overloads for constructing `Duration` values from a floating-point >+// number of the unit indicated by the factory function's name. These functions >+// exist for convenience, but they are not as efficient as the integral >+// factories, which should be preferred. >+// >+// Example: >+// auto a = absl::Seconds(1.5); // OK >+// auto b = absl::Milliseconds(1500); // BETTER >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Nanoseconds(T n) { >+ return n * Nanoseconds(1); >+} >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Microseconds(T n) { >+ return n * Microseconds(1); >+} >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Milliseconds(T n) { >+ return n * Milliseconds(1); >+} >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Seconds(T n) { >+ if (n >= 0) { >+ if (n >= std::numeric_limits<int64_t>::max()) return InfiniteDuration(); >+ return time_internal::MakePosDoubleDuration(n); >+ } else { >+ if (n <= std::numeric_limits<int64_t>::min()) return -InfiniteDuration(); >+ return -time_internal::MakePosDoubleDuration(-n); >+ } >+} >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Minutes(T n) { >+ return n * Minutes(1); >+} >+template <typename T, time_internal::EnableIfFloat<T> = 0> >+Duration Hours(T n) { >+ return n * Hours(1); >+} >+ >+// ToInt64Nanoseconds() >+// ToInt64Microseconds() >+// ToInt64Milliseconds() >+// ToInt64Seconds() >+// ToInt64Minutes() >+// ToInt64Hours() >+// >+// Helper functions that convert a Duration to an integral count of the >+// indicated unit. These functions are shorthand for the `IDivDuration()` >+// function above; see its documentation for details about overflow, etc. >+// >+// Example: >+// >+// absl::Duration d = absl::Milliseconds(1500); >+// int64_t isec = absl::ToInt64Seconds(d); // isec == 1 >+int64_t ToInt64Nanoseconds(Duration d); >+int64_t ToInt64Microseconds(Duration d); >+int64_t ToInt64Milliseconds(Duration d); >+int64_t ToInt64Seconds(Duration d); >+int64_t ToInt64Minutes(Duration d); >+int64_t ToInt64Hours(Duration d); >+ >+// ToDoubleNanoSeconds() >+// ToDoubleMicroseconds() >+// ToDoubleMilliseconds() >+// ToDoubleSeconds() >+// ToDoubleMinutes() >+// ToDoubleHours() >+// >+// Helper functions that convert a Duration to a floating point count of the >+// indicated unit. These functions are shorthand for the `FDivDuration()` >+// function above; see its documentation for details about overflow, etc. >+// >+// Example: >+// >+// absl::Duration d = absl::Milliseconds(1500); >+// double dsec = absl::ToDoubleSeconds(d); // dsec == 1.5 >+double ToDoubleNanoseconds(Duration d); >+double ToDoubleMicroseconds(Duration d); >+double ToDoubleMilliseconds(Duration d); >+double ToDoubleSeconds(Duration d); >+double ToDoubleMinutes(Duration d); >+double ToDoubleHours(Duration d); >+ >+// FromChrono() >+// >+// Converts any of the pre-defined std::chrono durations to an absl::Duration. >+// >+// Example: >+// >+// std::chrono::milliseconds ms(123); >+// absl::Duration d = absl::FromChrono(ms); >+constexpr Duration FromChrono(const std::chrono::nanoseconds& d); >+constexpr Duration FromChrono(const std::chrono::microseconds& d); >+constexpr Duration FromChrono(const std::chrono::milliseconds& d); >+constexpr Duration FromChrono(const std::chrono::seconds& d); >+constexpr Duration FromChrono(const std::chrono::minutes& d); >+constexpr Duration FromChrono(const std::chrono::hours& d); >+ >+// ToChronoNanoseconds() >+// ToChronoMicroseconds() >+// ToChronoMilliseconds() >+// ToChronoSeconds() >+// ToChronoMinutes() >+// ToChronoHours() >+// >+// Converts an absl::Duration to any of the pre-defined std::chrono durations. >+// If overflow would occur, the returned value will saturate at the min/max >+// chrono duration value instead. >+// >+// Example: >+// >+// absl::Duration d = absl::Microseconds(123); >+// auto x = absl::ToChronoMicroseconds(d); >+// auto y = absl::ToChronoNanoseconds(d); // x == y >+// auto z = absl::ToChronoSeconds(absl::InfiniteDuration()); >+// // z == std::chrono::seconds::max() >+std::chrono::nanoseconds ToChronoNanoseconds(Duration d); >+std::chrono::microseconds ToChronoMicroseconds(Duration d); >+std::chrono::milliseconds ToChronoMilliseconds(Duration d); >+std::chrono::seconds ToChronoSeconds(Duration d); >+std::chrono::minutes ToChronoMinutes(Duration d); >+std::chrono::hours ToChronoHours(Duration d); >+ >+// FormatDuration() >+// >+// Returns a std::string representing the duration in the form "72h3m0.5s". >+// Returns "inf" or "-inf" for +/- `InfiniteDuration()`. >+std::string FormatDuration(Duration d); >+ >+// Output stream operator. >+inline std::ostream& operator<<(std::ostream& os, Duration d) { >+ return os << FormatDuration(d); >+} >+ >+// ParseDuration() >+// >+// Parses a duration std::string consisting of a possibly signed sequence of >+// decimal numbers, each with an optional fractional part and a unit >+// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h". >+// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as >+// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`. >+bool ParseDuration(const std::string& dur_string, Duration* d); >+ >+// Support for flag values of type Duration. Duration flags must be specified >+// in a format that is valid input for absl::ParseDuration(). >+bool ParseFlag(const std::string& text, Duration* dst, std::string* error); >+std::string UnparseFlag(Duration d); >+ >+// Time >+// >+// An `absl::Time` represents a specific instant in time. Arithmetic operators >+// are provided for naturally expressing time calculations. Instances are >+// created using `absl::Now()` and the `absl::From*()` factory functions that >+// accept the gamut of other time representations. Formatting and parsing >+// functions are provided for conversion to and from strings. `absl::Time` >+// should be passed by value rather than const reference. >+// >+// `absl::Time` assumes there are 60 seconds in a minute, which means the >+// underlying time scales must be "smeared" to eliminate leap seconds. >+// See https://developers.google.com/time/smear. >+// >+// Even though `absl::Time` supports a wide range of timestamps, exercise >+// caution when using values in the distant past. `absl::Time` uses the >+// Proleptic Gregorian calendar, which extends the Gregorian calendar backward >+// to dates before its introduction in 1582. >+// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar >+// for more information. Use the ICU calendar classes to convert a date in >+// some other calendar (http://userguide.icu-project.org/datetime/calendar). >+// >+// Similarly, standardized time zones are a reasonably recent innovation, with >+// the Greenwich prime meridian being established in 1884. The TZ database >+// itself does not profess accurate offsets for timestamps prior to 1970. The >+// breakdown of future timestamps is subject to the whim of regional >+// governments. >+// >+// The `absl::Time` class represents an instant in time as a count of clock >+// ticks of some granularity (resolution) from some starting point (epoch). >+// >+// >+// `absl::Time` uses a resolution that is high enough to avoid loss in >+// precision, and a range that is wide enough to avoid overflow, when >+// converting between tick counts in most Google time scales (i.e., precision >+// of at least one nanosecond, and range +/-100 billion years). Conversions >+// between the time scales are performed by truncating (towards negative >+// infinity) to the nearest representable point. >+// >+// Examples: >+// >+// absl::Time t1 = ...; >+// absl::Time t2 = t1 + absl::Minutes(2); >+// absl::Duration d = t2 - t1; // == absl::Minutes(2) >+// absl::Time::Breakdown bd = t1.In(absl::LocalTimeZone()); >+// >+class Time { >+ public: >+ // Value semantics. >+ >+ // Returns the Unix epoch. However, those reading your code may not know >+ // or expect the Unix epoch as the default value, so make your code more >+ // readable by explicitly initializing all instances before use. >+ // >+ // Example: >+ // absl::Time t = absl::UnixEpoch(); >+ // absl::Time t = absl::Now(); >+ // absl::Time t = absl::TimeFromTimeval(tv); >+ // absl::Time t = absl::InfinitePast(); >+ constexpr Time() {} >+ >+ // Assignment operators. >+ Time& operator+=(Duration d) { >+ rep_ += d; >+ return *this; >+ } >+ Time& operator-=(Duration d) { >+ rep_ -= d; >+ return *this; >+ } >+ >+ // Time::Breakdown >+ // >+ // The calendar and wall-clock (aka "civil time") components of an >+ // `absl::Time` in a certain `absl::TimeZone`. This struct is not >+ // intended to represent an instant in time. So, rather than passing >+ // a `Time::Breakdown` to a function, pass an `absl::Time` and an >+ // `absl::TimeZone`. >+ struct Breakdown { >+ int64_t year; // year (e.g., 2013) >+ int month; // month of year [1:12] >+ int day; // day of month [1:31] >+ int hour; // hour of day [0:23] >+ int minute; // minute of hour [0:59] >+ int second; // second of minute [0:59] >+ Duration subsecond; // [Seconds(0):Seconds(1)) if finite >+ int weekday; // 1==Mon, ..., 7=Sun >+ int yearday; // day of year [1:366] >+ >+ // Note: The following fields exist for backward compatibility >+ // with older APIs. Accessing these fields directly is a sign of >+ // imprudent logic in the calling code. Modern time-related code >+ // should only access this data indirectly by way of FormatTime(). >+ // These fields are undefined for InfiniteFuture() and InfinitePast(). >+ int offset; // seconds east of UTC >+ bool is_dst; // is offset non-standard? >+ const char* zone_abbr; // time-zone abbreviation (e.g., "PST") >+ }; >+ >+ // Time::In() >+ // >+ // Returns the breakdown of this instant in the given TimeZone. >+ Breakdown In(TimeZone tz) const; >+ >+ private: >+ friend constexpr Time time_internal::FromUnixDuration(Duration d); >+ friend constexpr Duration time_internal::ToUnixDuration(Time t); >+ friend constexpr bool operator<(Time lhs, Time rhs); >+ friend constexpr bool operator==(Time lhs, Time rhs); >+ friend Duration operator-(Time lhs, Time rhs); >+ friend constexpr Time UniversalEpoch(); >+ friend constexpr Time InfiniteFuture(); >+ friend constexpr Time InfinitePast(); >+ constexpr explicit Time(Duration rep) : rep_(rep) {} >+ Duration rep_; >+}; >+ >+// Relational Operators >+constexpr bool operator<(Time lhs, Time rhs) { return lhs.rep_ < rhs.rep_; } >+constexpr bool operator>(Time lhs, Time rhs) { return rhs < lhs; } >+constexpr bool operator>=(Time lhs, Time rhs) { return !(lhs < rhs); } >+constexpr bool operator<=(Time lhs, Time rhs) { return !(rhs < lhs); } >+constexpr bool operator==(Time lhs, Time rhs) { return lhs.rep_ == rhs.rep_; } >+constexpr bool operator!=(Time lhs, Time rhs) { return !(lhs == rhs); } >+ >+// Additive Operators >+inline Time operator+(Time lhs, Duration rhs) { return lhs += rhs; } >+inline Time operator+(Duration lhs, Time rhs) { return rhs += lhs; } >+inline Time operator-(Time lhs, Duration rhs) { return lhs -= rhs; } >+inline Duration operator-(Time lhs, Time rhs) { return lhs.rep_ - rhs.rep_; } >+ >+// UnixEpoch() >+// >+// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000". >+constexpr Time UnixEpoch() { return Time(); } >+ >+// UniversalEpoch() >+// >+// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the >+// epoch of the ICU Universal Time Scale. >+constexpr Time UniversalEpoch() { >+ // 719162 is the number of days from 0001-01-01 to 1970-01-01, >+ // assuming the Gregorian calendar. >+ return Time(time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, 0U)); >+} >+ >+// InfiniteFuture() >+// >+// Returns an `absl::Time` that is infinitely far in the future. >+constexpr Time InfiniteFuture() { >+ return Time( >+ time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U)); >+} >+ >+// InfinitePast() >+// >+// Returns an `absl::Time` that is infinitely far in the past. >+constexpr Time InfinitePast() { >+ return Time( >+ time_internal::MakeDuration(std::numeric_limits<int64_t>::min(), ~0U)); >+} >+ >+// TimeConversion >+// >+// An `absl::TimeConversion` represents the conversion of year, month, day, >+// hour, minute, and second values (i.e., a civil time), in a particular >+// `absl::TimeZone`, to a time instant (an absolute time), as returned by >+// `absl::ConvertDateTime()`. (Subseconds must be handled separately.) >+// >+// It is possible, though, for a caller to try to convert values that >+// do not represent an actual or unique instant in time (due to a shift >+// in UTC offset in the `absl::TimeZone`, which results in a discontinuity in >+// the civil-time components). For example, a daylight-saving-time >+// transition skips or repeats civil times---in the United States, March >+// 13, 2011 02:15 never occurred, while November 6, 2011 01:15 occurred >+// twice---so requests for such times are not well-defined. >+// >+// To account for these possibilities, `absl::TimeConversion` is richer >+// than just a single `absl::Time`. When the civil time is skipped or >+// repeated, `absl::ConvertDateTime()` returns times calculated using the >+// pre-transition and post-transition UTC offsets, plus the transition >+// time itself. >+// >+// Examples: >+// >+// absl::TimeZone lax; >+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... } >+// >+// // A unique civil time >+// absl::TimeConversion jan01 = >+// absl::ConvertDateTime(2011, 1, 1, 0, 0, 0, lax); >+// // jan01.kind == TimeConversion::UNIQUE >+// // jan01.pre is 2011/01/01 00:00:00 -0800 >+// // jan01.trans is 2011/01/01 00:00:00 -0800 >+// // jan01.post is 2011/01/01 00:00:00 -0800 >+// >+// // A Spring DST transition, when there is a gap in civil time >+// absl::TimeConversion mar13 = >+// absl::ConvertDateTime(2011, 3, 13, 2, 15, 0, lax); >+// // mar13.kind == TimeConversion::SKIPPED >+// // mar13.pre is 2011/03/13 03:15:00 -0700 >+// // mar13.trans is 2011/03/13 03:00:00 -0700 >+// // mar13.post is 2011/03/13 01:15:00 -0800 >+// >+// // A Fall DST transition, when civil times are repeated >+// absl::TimeConversion nov06 = >+// absl::ConvertDateTime(2011, 11, 6, 1, 15, 0, lax); >+// // nov06.kind == TimeConversion::REPEATED >+// // nov06.pre is 2011/11/06 01:15:00 -0700 >+// // nov06.trans is 2011/11/06 01:00:00 -0800 >+// // nov06.post is 2011/11/06 01:15:00 -0800 >+// >+// The input month, day, hour, minute, and second values can also be >+// outside of their valid ranges, in which case they will be "normalized" >+// during the conversion. >+// >+// Example: >+// >+// // "October 32" normalizes to "November 1". >+// absl::TimeZone tz = absl::LocalTimeZone(); >+// absl::TimeConversion tc = >+// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, tz); >+// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true >+// // tc.pre.In(tz).month == 11 && tc.pre.In(tz).day == 1 >+struct TimeConversion { >+ Time pre; // time calculated using the pre-transition offset >+ Time trans; // when the civil-time discontinuity occurred >+ Time post; // time calculated using the post-transition offset >+ >+ enum Kind { >+ UNIQUE, // the civil time was singular (pre == trans == post) >+ SKIPPED, // the civil time did not exist >+ REPEATED, // the civil time was ambiguous >+ }; >+ Kind kind; >+ >+ bool normalized; // input values were outside their valid ranges >+}; >+ >+// ConvertDateTime() >+// >+// The full generality of a civil time to absl::Time conversion. >+TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, >+ int min, int sec, TimeZone tz); >+ >+// FromDateTime() >+// >+// A convenience wrapper for `absl::ConvertDateTime()` that simply returns the >+// "pre" `absl::Time`. That is, the unique result, or the instant that >+// is correct using the pre-transition offset (as if the transition >+// never happened). This is typically the answer that humans expected when >+// faced with non-unique times, such as near daylight-saving time transitions. >+// >+// Example: >+// >+// absl::TimeZone seattle; >+// if (!absl::LoadTimeZone("America/Los_Angeles", &seattle)) { ... } >+// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, seattle); >+Time FromDateTime(int64_t year, int mon, int day, int hour, int min, int sec, >+ TimeZone tz); >+ >+// FromTM() >+// >+// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and >+// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) >+// for a description of the expected values of the tm fields. IFF the indicated >+// time instant is not unique (see `absl::ConvertDateTime()` above), the >+// `tm_isdst` field is consulted to select the desired instant (`tm_isdst` > 0 >+// means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 means use the default >+// like `absl::FromDateTime()`). >+Time FromTM(const struct tm& tm, TimeZone tz); >+ >+// ToTM() >+// >+// Converts the given `absl::Time` to a struct tm using the given time zone. >+// See ctime(3) for a description of the values of the tm fields. >+struct tm ToTM(Time t, TimeZone tz); >+ >+// FromUnixNanos() >+// FromUnixMicros() >+// FromUnixMillis() >+// FromUnixSeconds() >+// FromTimeT() >+// FromUDate() >+// FromUniversal() >+// >+// Creates an `absl::Time` from a variety of other representations. >+constexpr Time FromUnixNanos(int64_t ns); >+constexpr Time FromUnixMicros(int64_t us); >+constexpr Time FromUnixMillis(int64_t ms); >+constexpr Time FromUnixSeconds(int64_t s); >+constexpr Time FromTimeT(time_t t); >+Time FromUDate(double udate); >+Time FromUniversal(int64_t universal); >+ >+// ToUnixNanos() >+// ToUnixMicros() >+// ToUnixMillis() >+// ToUnixSeconds() >+// ToTimeT() >+// ToUDate() >+// ToUniversal() >+// >+// Converts an `absl::Time` to a variety of other representations. Note that >+// these operations round down toward negative infinity where necessary to >+// adjust to the resolution of the result type. Beware of possible time_t >+// over/underflow in ToTime{T,val,spec}() on 32-bit platforms. >+int64_t ToUnixNanos(Time t); >+int64_t ToUnixMicros(Time t); >+int64_t ToUnixMillis(Time t); >+int64_t ToUnixSeconds(Time t); >+time_t ToTimeT(Time t); >+double ToUDate(Time t); >+int64_t ToUniversal(Time t); >+ >+// DurationFromTimespec() >+// DurationFromTimeval() >+// ToTimespec() >+// ToTimeval() >+// TimeFromTimespec() >+// TimeFromTimeval() >+// ToTimespec() >+// ToTimeval() >+// >+// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2) >+// and select(2)), while others use them as a Time (e.g. clock_gettime(2) >+// and gettimeofday(2)), so conversion functions are provided for both cases. >+// The "to timespec/val" direction is easily handled via overloading, but >+// for "from timespec/val" the desired type is part of the function name. >+Duration DurationFromTimespec(timespec ts); >+Duration DurationFromTimeval(timeval tv); >+timespec ToTimespec(Duration d); >+timeval ToTimeval(Duration d); >+Time TimeFromTimespec(timespec ts); >+Time TimeFromTimeval(timeval tv); >+timespec ToTimespec(Time t); >+timeval ToTimeval(Time t); >+ >+// FromChrono() >+// >+// Converts a std::chrono::system_clock::time_point to an absl::Time. >+// >+// Example: >+// >+// auto tp = std::chrono::system_clock::from_time_t(123); >+// absl::Time t = absl::FromChrono(tp); >+// // t == absl::FromTimeT(123) >+Time FromChrono(const std::chrono::system_clock::time_point& tp); >+ >+// ToChronoTime() >+// >+// Converts an absl::Time to a std::chrono::system_clock::time_point. If >+// overflow would occur, the returned value will saturate at the min/max time >+// point value instead. >+// >+// Example: >+// >+// absl::Time t = absl::FromTimeT(123); >+// auto tp = absl::ToChronoTime(t); >+// // tp == std::chrono::system_clock::from_time_t(123); >+std::chrono::system_clock::time_point ToChronoTime(Time); >+ >+// RFC3339_full >+// RFC3339_sec >+// >+// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings, >+// with trailing zeros trimmed or with fractional seconds omitted altogether. >+// >+// Note that RFC3339_sec[] matches an ISO 8601 extended format for date >+// and time with UTC offset. >+extern const char RFC3339_full[]; // %Y-%m-%dT%H:%M:%E*S%Ez >+extern const char RFC3339_sec[]; // %Y-%m-%dT%H:%M:%S%Ez >+ >+// RFC1123_full >+// RFC1123_no_wday >+// >+// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. >+extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z >+extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z >+ >+// FormatTime() >+// >+// Formats the given `absl::Time` in the `absl::TimeZone` according to the >+// provided format std::string. Uses strftime()-like formatting options, with >+// the following extensions: >+// >+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) >+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) >+// - %E#S - Seconds with # digits of fractional precision >+// - %E*S - Seconds with full fractional precision (a literal '*') >+// - %E#f - Fractional seconds with # digits of precision >+// - %E*f - Fractional seconds with full precision (a literal '*') >+// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) >+// >+// Note that %E0S behaves like %S, and %E0f produces no characters. In >+// contrast %E*f always produces at least one digit, which may be '0'. >+// >+// Note that %Y produces as many characters as it takes to fully render the >+// year. A year outside of [-999:9999] when formatted with %E4Y will produce >+// more than four characters, just like %Y. >+// >+// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z) >+// so that the result uniquely identifies a time instant. >+// >+// Example: >+// >+// absl::TimeZone lax; >+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... } >+// absl::Time t = absl::FromDateTime(2013, 1, 2, 3, 4, 5, lax); >+// >+// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05" >+// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000" >+// >+// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned >+// std::string will be exactly "infinite-future". If the given `absl::Time` is >+// `absl::InfinitePast()`, the returned std::string will be exactly "infinite-past". >+// In both cases the given format std::string and `absl::TimeZone` are ignored. >+// >+std::string FormatTime(const std::string& format, Time t, TimeZone tz); >+ >+// Convenience functions that format the given time using the RFC3339_full >+// format. The first overload uses the provided TimeZone, while the second >+// uses LocalTimeZone(). >+std::string FormatTime(Time t, TimeZone tz); >+std::string FormatTime(Time t); >+ >+// Output stream operator. >+inline std::ostream& operator<<(std::ostream& os, Time t) { >+ return os << FormatTime(t); >+} >+ >+// ParseTime() >+// >+// Parses an input std::string according to the provided format std::string and >+// returns the corresponding `absl::Time`. Uses strftime()-like formatting >+// options, with the same extensions as FormatTime(), but with the >+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez >+// and %E*z also accept the same inputs. >+// >+// %Y consumes as many numeric characters as it can, so the matching data >+// should always be terminated with a non-numeric. %E4Y always consumes >+// exactly four characters, including any sign. >+// >+// Unspecified fields are taken from the default date and time of ... >+// >+// "1970-01-01 00:00:00.0 +0000" >+// >+// For example, parsing a std::string of "15:45" (%H:%M) will return an absl::Time >+// that represents "1970-01-01 15:45:00.0 +0000". >+// >+// Note that since ParseTime() returns time instants, it makes the most sense >+// to parse fully-specified date/time strings that include a UTC offset (%z, >+// %Ez, or %E*z). >+// >+// Note also that `absl::ParseTime()` only heeds the fields year, month, day, >+// hour, minute, (fractional) second, and UTC offset. Other fields, like >+// weekday (%a or %A), while parsed for syntactic validity, are ignored >+// in the conversion. >+// >+// Date and time fields that are out-of-range will be treated as errors >+// rather than normalizing them like `absl::FromDateTime()` does. For example, >+// it is an error to parse the date "Oct 32, 2013" because 32 is out of range. >+// >+// A leap second of ":60" is normalized to ":00" of the following minute >+// with fractional seconds discarded. The following table shows how the >+// given seconds and subseconds will be parsed: >+// >+// "59.x" -> 59.x // exact >+// "60.x" -> 00.0 // normalized >+// "00.x" -> 00.x // exact >+// >+// Errors are indicated by returning false and assigning an error message >+// to the "err" out param if it is non-null. >+// >+// Note: If the input std::string is exactly "infinite-future", the returned >+// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned. >+// If the input std::string is "infinite-past", the returned `absl::Time` will be >+// `absl::InfinitePast()` and `true` will be returned. >+// >+bool ParseTime(const std::string& format, const std::string& input, Time* time, >+ std::string* err); >+ >+// Like ParseTime() above, but if the format std::string does not contain a UTC >+// offset specification (%z/%Ez/%E*z) then the input is interpreted in the >+// given TimeZone. This means that the input, by itself, does not identify a >+// unique instant. Being time-zone dependent, it also admits the possibility >+// of ambiguity or non-existence, in which case the "pre" time (as defined >+// for ConvertDateTime()) is returned. For these reasons we recommend that >+// all date/time strings include a UTC offset so they're context independent. >+bool ParseTime(const std::string& format, const std::string& input, TimeZone tz, >+ Time* time, std::string* err); >+ >+// Support for flag values of type Time. Time flags must be specified in a >+// format that matches absl::RFC3339_full. For example: >+// >+// --start_time=2016-01-02T03:04:05.678+08:00 >+// >+// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required. >+// >+// Additionally, if you'd like to specify a time as a count of >+// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag >+// and add that duration to absl::UnixEpoch() to get an absl::Time. >+bool ParseFlag(const std::string& text, Time* t, std::string* error); >+std::string UnparseFlag(Time t); >+ >+// TimeZone >+// >+// The `absl::TimeZone` is an opaque, small, value-type class representing a >+// geo-political region within which particular rules are used for converting >+// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone` >+// values are named using the TZ identifiers from the IANA Time Zone Database, >+// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values >+// are created from factory functions such as `absl::LoadTimeZone()`. Note: >+// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by >+// value rather than const reference. >+// >+// For more on the fundamental concepts of time zones, absolute times, and civil >+// times, see https://github.com/google/cctz#fundamental-concepts >+// >+// Examples: >+// >+// absl::TimeZone utc = absl::UTCTimeZone(); >+// absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60); >+// absl::TimeZone loc = absl::LocalTimeZone(); >+// absl::TimeZone lax; >+// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { ... } >+// >+// See also: >+// - https://github.com/google/cctz >+// - http://www.iana.org/time-zones >+// - http://en.wikipedia.org/wiki/Zoneinfo >+class TimeZone { >+ public: >+ explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {} >+ TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit. >+ TimeZone(const TimeZone&) = default; >+ TimeZone& operator=(const TimeZone&) = default; >+ >+ explicit operator time_internal::cctz::time_zone() const { return cz_; } >+ >+ std::string name() const { return cz_.name(); } >+ >+ private: >+ friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; } >+ friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; } >+ friend std::ostream& operator<<(std::ostream& os, TimeZone tz) { >+ return os << tz.name(); >+ } >+ >+ time_internal::cctz::time_zone cz_; >+}; >+ >+// LoadTimeZone() >+// >+// Loads the named zone. May perform I/O on the initial load of the named >+// zone. If the name is invalid, or some other kind of error occurs, returns >+// `false` and `*tz` is set to the UTC time zone. >+inline bool LoadTimeZone(const std::string& name, TimeZone* tz) { >+ if (name == "localtime") { >+ *tz = TimeZone(time_internal::cctz::local_time_zone()); >+ return true; >+ } >+ time_internal::cctz::time_zone cz; >+ const bool b = time_internal::cctz::load_time_zone(name, &cz); >+ *tz = TimeZone(cz); >+ return b; >+} >+ >+// FixedTimeZone() >+// >+// Returns a TimeZone that is a fixed offset (seconds east) from UTC. >+// Note: If the absolute value of the offset is greater than 24 hours >+// you'll get UTC (i.e., no offset) instead. >+inline TimeZone FixedTimeZone(int seconds) { >+ return TimeZone( >+ time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds))); >+} >+ >+// UTCTimeZone() >+// >+// Convenience method returning the UTC time zone. >+inline TimeZone UTCTimeZone() { >+ return TimeZone(time_internal::cctz::utc_time_zone()); >+} >+ >+// LocalTimeZone() >+// >+// Convenience method returning the local time zone, or UTC if there is >+// no configured local zone. Warning: Be wary of using LocalTimeZone(), >+// and particularly so in a server process, as the zone configured for the >+// local machine should be irrelevant. Prefer an explicit zone name. >+inline TimeZone LocalTimeZone() { >+ return TimeZone(time_internal::cctz::local_time_zone()); >+} >+ >+// ============================================================================ >+// Implementation Details Follow >+// ============================================================================ >+ >+namespace time_internal { >+ >+// Creates a Duration with a given representation. >+// REQUIRES: hi,lo is a valid representation of a Duration as specified >+// in time/duration.cc. >+constexpr Duration MakeDuration(int64_t hi, uint32_t lo = 0) { >+ return Duration(hi, lo); >+} >+ >+constexpr Duration MakeDuration(int64_t hi, int64_t lo) { >+ return MakeDuration(hi, static_cast<uint32_t>(lo)); >+} >+ >+// Make a Duration value from a floating-point number, as long as that number >+// is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as >+// it's positive and can be converted to int64_t without risk of UB. >+inline Duration MakePosDoubleDuration(double n) { >+ const int64_t int_secs = static_cast<int64_t>(n); >+ const uint32_t ticks = >+ static_cast<uint32_t>((n - int_secs) * kTicksPerSecond + 0.5); >+ return ticks < kTicksPerSecond >+ ? MakeDuration(int_secs, ticks) >+ : MakeDuration(int_secs + 1, ticks - kTicksPerSecond); >+} >+ >+// Creates a normalized Duration from an almost-normalized (sec,ticks) >+// pair. sec may be positive or negative. ticks must be in the range >+// -kTicksPerSecond < *ticks < kTicksPerSecond. If ticks is negative it >+// will be normalized to a positive value in the resulting Duration. >+constexpr Duration MakeNormalizedDuration(int64_t sec, int64_t ticks) { >+ return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond) >+ : MakeDuration(sec, ticks); >+} >+// Provide access to the Duration representation. >+constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; } >+constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; } >+constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; } >+ >+// Returns an infinite Duration with the opposite sign. >+// REQUIRES: IsInfiniteDuration(d) >+constexpr Duration OppositeInfinity(Duration d) { >+ return GetRepHi(d) < 0 >+ ? MakeDuration(std::numeric_limits<int64_t>::max(), ~0U) >+ : MakeDuration(std::numeric_limits<int64_t>::min(), ~0U); >+} >+ >+// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow. >+constexpr int64_t NegateAndSubtractOne(int64_t n) { >+ // Note: Good compilers will optimize this expression to ~n when using >+ // a two's-complement representation (which is required for int64_t). >+ return (n < 0) ? -(n + 1) : (-n) - 1; >+} >+ >+// Map between a Time and a Duration since the Unix epoch. Note that these >+// functions depend on the above mentioned choice of the Unix epoch for the >+// Time representation (and both need to be Time friends). Without this >+// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively. >+constexpr Time FromUnixDuration(Duration d) { return Time(d); } >+constexpr Duration ToUnixDuration(Time t) { return t.rep_; } >+ >+template <std::intmax_t N> >+constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) { >+ static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio"); >+ // Subsecond ratios cannot overflow. >+ return MakeNormalizedDuration( >+ v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N); >+} >+constexpr Duration FromInt64(int64_t v, std::ratio<60>) { >+ return (v <= std::numeric_limits<int64_t>::max() / 60 && >+ v >= std::numeric_limits<int64_t>::min() / 60) >+ ? MakeDuration(v * 60) >+ : v > 0 ? InfiniteDuration() : -InfiniteDuration(); >+} >+constexpr Duration FromInt64(int64_t v, std::ratio<3600>) { >+ return (v <= std::numeric_limits<int64_t>::max() / 3600 && >+ v >= std::numeric_limits<int64_t>::min() / 3600) >+ ? MakeDuration(v * 3600) >+ : v > 0 ? InfiniteDuration() : -InfiniteDuration(); >+} >+ >+// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is >+// valid. That is, if a T can be assigned to an int64_t without narrowing. >+template <typename T> >+constexpr auto IsValidRep64(int) >+ -> decltype(int64_t{std::declval<T>()}, bool()) { >+ return true; >+} >+template <typename T> >+constexpr auto IsValidRep64(char) -> bool { >+ return false; >+} >+ >+// Converts a std::chrono::duration to an absl::Duration. >+template <typename Rep, typename Period> >+constexpr Duration FromChrono(const std::chrono::duration<Rep, Period>& d) { >+ static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); >+ return FromInt64(int64_t{d.count()}, Period{}); >+} >+ >+template <typename Ratio> >+int64_t ToInt64(Duration d, Ratio) { >+ // Note: This may be used on MSVC, which may have a system_clock period of >+ // std::ratio<1, 10 * 1000 * 1000> >+ return ToInt64Seconds(d * Ratio::den / Ratio::num); >+} >+// Fastpath implementations for the 6 common duration units. >+inline int64_t ToInt64(Duration d, std::nano) { >+ return ToInt64Nanoseconds(d); >+} >+inline int64_t ToInt64(Duration d, std::micro) { >+ return ToInt64Microseconds(d); >+} >+inline int64_t ToInt64(Duration d, std::milli) { >+ return ToInt64Milliseconds(d); >+} >+inline int64_t ToInt64(Duration d, std::ratio<1>) { >+ return ToInt64Seconds(d); >+} >+inline int64_t ToInt64(Duration d, std::ratio<60>) { >+ return ToInt64Minutes(d); >+} >+inline int64_t ToInt64(Duration d, std::ratio<3600>) { >+ return ToInt64Hours(d); >+} >+ >+// Converts an absl::Duration to a chrono duration of type T. >+template <typename T> >+T ToChronoDuration(Duration d) { >+ using Rep = typename T::rep; >+ using Period = typename T::period; >+ static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); >+ if (time_internal::IsInfiniteDuration(d)) >+ return d < ZeroDuration() ? T::min() : T::max(); >+ const auto v = ToInt64(d, Period{}); >+ if (v > std::numeric_limits<Rep>::max()) return T::max(); >+ if (v < std::numeric_limits<Rep>::min()) return T::min(); >+ return T{v}; >+} >+ >+} // namespace time_internal >+constexpr Duration Nanoseconds(int64_t n) { >+ return time_internal::FromInt64(n, std::nano{}); >+} >+constexpr Duration Microseconds(int64_t n) { >+ return time_internal::FromInt64(n, std::micro{}); >+} >+constexpr Duration Milliseconds(int64_t n) { >+ return time_internal::FromInt64(n, std::milli{}); >+} >+constexpr Duration Seconds(int64_t n) { >+ return time_internal::FromInt64(n, std::ratio<1>{}); >+} >+constexpr Duration Minutes(int64_t n) { >+ return time_internal::FromInt64(n, std::ratio<60>{}); >+} >+constexpr Duration Hours(int64_t n) { >+ return time_internal::FromInt64(n, std::ratio<3600>{}); >+} >+ >+constexpr bool operator<(Duration lhs, Duration rhs) { >+ return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) >+ ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) >+ : time_internal::GetRepHi(lhs) == std::numeric_limits<int64_t>::min() >+ ? time_internal::GetRepLo(lhs) + 1 < >+ time_internal::GetRepLo(rhs) + 1 >+ : time_internal::GetRepLo(lhs) < >+ time_internal::GetRepLo(rhs); >+} >+ >+constexpr bool operator==(Duration lhs, Duration rhs) { >+ return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) && >+ time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs); >+} >+ >+constexpr Duration operator-(Duration d) { >+ // This is a little interesting because of the special cases. >+ // >+ // If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're >+ // dealing with an integral number of seconds, and the only special case is >+ // the maximum negative finite duration, which can't be negated. >+ // >+ // Infinities stay infinite, and just change direction. >+ // >+ // Finally we're in the case where rep_lo_ is non-zero, and we can borrow >+ // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1 >+ // is safe). >+ return time_internal::GetRepLo(d) == 0 >+ ? time_internal::GetRepHi(d) == std::numeric_limits<int64_t>::min() >+ ? InfiniteDuration() >+ : time_internal::MakeDuration(-time_internal::GetRepHi(d)) >+ : time_internal::IsInfiniteDuration(d) >+ ? time_internal::OppositeInfinity(d) >+ : time_internal::MakeDuration( >+ time_internal::NegateAndSubtractOne( >+ time_internal::GetRepHi(d)), >+ time_internal::kTicksPerSecond - >+ time_internal::GetRepLo(d)); >+} >+ >+constexpr Duration InfiniteDuration() { >+ return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U); >+} >+ >+constexpr Duration FromChrono(const std::chrono::nanoseconds& d) { >+ return time_internal::FromChrono(d); >+} >+constexpr Duration FromChrono(const std::chrono::microseconds& d) { >+ return time_internal::FromChrono(d); >+} >+constexpr Duration FromChrono(const std::chrono::milliseconds& d) { >+ return time_internal::FromChrono(d); >+} >+constexpr Duration FromChrono(const std::chrono::seconds& d) { >+ return time_internal::FromChrono(d); >+} >+constexpr Duration FromChrono(const std::chrono::minutes& d) { >+ return time_internal::FromChrono(d); >+} >+constexpr Duration FromChrono(const std::chrono::hours& d) { >+ return time_internal::FromChrono(d); >+} >+ >+constexpr Time FromUnixNanos(int64_t ns) { >+ return time_internal::FromUnixDuration(Nanoseconds(ns)); >+} >+ >+constexpr Time FromUnixMicros(int64_t us) { >+ return time_internal::FromUnixDuration(Microseconds(us)); >+} >+ >+constexpr Time FromUnixMillis(int64_t ms) { >+ return time_internal::FromUnixDuration(Milliseconds(ms)); >+} >+ >+constexpr Time FromUnixSeconds(int64_t s) { >+ return time_internal::FromUnixDuration(Seconds(s)); >+} >+ >+constexpr Time FromTimeT(time_t t) { >+ return time_internal::FromUnixDuration(Seconds(t)); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_TIME_TIME_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_benchmark.cc >new file mode 100644 >index 00000000000..e1009946cd5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_benchmark.cc >@@ -0,0 +1,316 @@ >+// Copyright 2018 The Abseil Authors. >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/time.h" >+ >+#if !defined(_WIN32) >+#include <sys/time.h> >+#endif // _WIN32 >+#include <algorithm> >+#include <cmath> >+#include <cstddef> >+#include <cstring> >+#include <ctime> >+#include <memory> >+#include <string> >+ >+#include "absl/time/clock.h" >+#include "absl/time/internal/test_util.h" >+#include "benchmark/benchmark.h" >+ >+namespace { >+ >+// >+// Addition/Subtraction of a duration >+// >+ >+void BM_Time_Arithmetic(benchmark::State& state) { >+ const absl::Duration nano = absl::Nanoseconds(1); >+ const absl::Duration sec = absl::Seconds(1); >+ absl::Time t = absl::UnixEpoch(); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(t += nano); >+ benchmark::DoNotOptimize(t -= sec); >+ } >+} >+BENCHMARK(BM_Time_Arithmetic); >+ >+// >+// Time difference >+// >+ >+void BM_Time_Difference(benchmark::State& state) { >+ absl::Time start = absl::Now(); >+ absl::Time end = start + absl::Nanoseconds(1); >+ absl::Duration diff; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(diff += end - start); >+ } >+} >+BENCHMARK(BM_Time_Difference); >+ >+// >+// ToDateTime >+// >+// In each "ToDateTime" benchmark we switch between two instants >+// separated by at least one transition in order to defeat any >+// internal caching of previous results (e.g., see local_time_hint_). >+// >+// The "UTC" variants use UTC instead of the Google/local time zone. >+// >+ >+void BM_Time_ToDateTime_Absl(benchmark::State& state) { >+ const absl::TimeZone tz = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ absl::Time t = absl::FromUnixSeconds(1384569027); >+ absl::Time t2 = absl::FromUnixSeconds(1418962578); >+ while (state.KeepRunning()) { >+ std::swap(t, t2); >+ t += absl::Seconds(1); >+ benchmark::DoNotOptimize(t.In(tz)); >+ } >+} >+BENCHMARK(BM_Time_ToDateTime_Absl); >+ >+void BM_Time_ToDateTime_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ time_t t = 1384569027; >+ time_t t2 = 1418962578; >+ while (state.KeepRunning()) { >+ std::swap(t, t2); >+ t += 1; >+ struct tm tm; >+#if !defined(_WIN32) >+ benchmark::DoNotOptimize(localtime_r(&t, &tm)); >+#else // _WIN32 >+ benchmark::DoNotOptimize(localtime_s(&tm, &t)); >+#endif // _WIN32 >+ } >+} >+BENCHMARK(BM_Time_ToDateTime_Libc); >+ >+void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ absl::Time t = absl::FromUnixSeconds(1384569027); >+ while (state.KeepRunning()) { >+ t += absl::Seconds(1); >+ benchmark::DoNotOptimize(t.In(tz)); >+ } >+} >+BENCHMARK(BM_Time_ToDateTimeUTC_Absl); >+ >+void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) { >+ time_t t = 1384569027; >+ while (state.KeepRunning()) { >+ t += 1; >+ struct tm tm; >+#if !defined(_WIN32) >+ benchmark::DoNotOptimize(gmtime_r(&t, &tm)); >+#else // _WIN32 >+ benchmark::DoNotOptimize(gmtime_s(&tm, &t)); >+#endif // _WIN32 >+ } >+} >+BENCHMARK(BM_Time_ToDateTimeUTC_Libc); >+ >+// >+// FromUnixMicros >+// >+ >+void BM_Time_FromUnixMicros(benchmark::State& state) { >+ int i = 0; >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::FromUnixMicros(i)); >+ ++i; >+ } >+} >+BENCHMARK(BM_Time_FromUnixMicros); >+ >+void BM_Time_ToUnixNanos(benchmark::State& state) { >+ const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(ToUnixNanos(t)); >+ } >+} >+BENCHMARK(BM_Time_ToUnixNanos); >+ >+void BM_Time_ToUnixMicros(benchmark::State& state) { >+ const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(ToUnixMicros(t)); >+ } >+} >+BENCHMARK(BM_Time_ToUnixMicros); >+ >+void BM_Time_ToUnixMillis(benchmark::State& state) { >+ const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(ToUnixMillis(t)); >+ } >+} >+BENCHMARK(BM_Time_ToUnixMillis); >+ >+void BM_Time_ToUnixSeconds(benchmark::State& state) { >+ const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToUnixSeconds(t)); >+ } >+} >+BENCHMARK(BM_Time_ToUnixSeconds); >+ >+// >+// FromDateTime >+// >+// In each "FromDateTime" benchmark we switch between two YMDhms >+// values separated by at least one transition in order to defeat any >+// internal caching of previous results (e.g., see time_local_hint_). >+// >+// The "UTC" variants use UTC instead of the Google/local time zone. >+// The "Day0" variants require normalization of the day of month. >+// >+ >+void BM_Time_FromDateTime_Absl(benchmark::State& state) { >+ const absl::TimeZone tz = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ int i = 0; >+ while (state.KeepRunning()) { >+ if ((i & 1) == 0) { >+ absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz); >+ } else { >+ absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz); >+ } >+ ++i; >+ } >+} >+BENCHMARK(BM_Time_FromDateTime_Absl); >+ >+void BM_Time_FromDateTime_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ int i = 0; >+ while (state.KeepRunning()) { >+ struct tm tm; >+ if ((i & 1) == 0) { >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 12 - 1; >+ tm.tm_mday = 18; >+ tm.tm_hour = 20; >+ tm.tm_min = 16; >+ tm.tm_sec = 18; >+ } else { >+ tm.tm_year = 2013 - 1900; >+ tm.tm_mon = 11 - 1; >+ tm.tm_mday = 15; >+ tm.tm_hour = 18; >+ tm.tm_min = 30; >+ tm.tm_sec = 27; >+ } >+ tm.tm_isdst = -1; >+ mktime(&tm); >+ ++i; >+ } >+} >+BENCHMARK(BM_Time_FromDateTime_Libc); >+ >+void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) { >+ const absl::TimeZone tz = absl::UTCTimeZone(); >+ while (state.KeepRunning()) { >+ FromDateTime(2014, 12, 18, 20, 16, 18, tz); >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeUTC_Absl); >+ >+void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) { >+ const absl::TimeZone tz = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ int i = 0; >+ while (state.KeepRunning()) { >+ if ((i & 1) == 0) { >+ absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz); >+ } else { >+ absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz); >+ } >+ ++i; >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeDay0_Absl); >+ >+void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) { >+ // No timezone support, so just use localtime. >+ int i = 0; >+ while (state.KeepRunning()) { >+ struct tm tm; >+ if ((i & 1) == 0) { >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 12 - 1; >+ tm.tm_mday = 0; >+ tm.tm_hour = 20; >+ tm.tm_min = 16; >+ tm.tm_sec = 18; >+ } else { >+ tm.tm_year = 2013 - 1900; >+ tm.tm_mon = 11 - 1; >+ tm.tm_mday = 0; >+ tm.tm_hour = 18; >+ tm.tm_min = 30; >+ tm.tm_sec = 27; >+ } >+ tm.tm_isdst = -1; >+ mktime(&tm); >+ ++i; >+ } >+} >+BENCHMARK(BM_Time_FromDateTimeDay0_Libc); >+ >+// >+// To/FromTimespec >+// >+ >+void BM_Time_ToTimespec(benchmark::State& state) { >+ absl::Time now = absl::Now(); >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::ToTimespec(now)); >+ } >+} >+BENCHMARK(BM_Time_ToTimespec); >+ >+void BM_Time_FromTimespec(benchmark::State& state) { >+ timespec ts = absl::ToTimespec(absl::Now()); >+ while (state.KeepRunning()) { >+ if (++ts.tv_nsec == 1000 * 1000 * 1000) { >+ ++ts.tv_sec; >+ ts.tv_nsec = 0; >+ } >+ benchmark::DoNotOptimize(absl::TimeFromTimespec(ts)); >+ } >+} >+BENCHMARK(BM_Time_FromTimespec); >+ >+// >+// Comparison with InfiniteFuture/Past >+// >+ >+void BM_Time_InfiniteFuture(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::InfiniteFuture()); >+ } >+} >+BENCHMARK(BM_Time_InfiniteFuture); >+ >+void BM_Time_InfinitePast(benchmark::State& state) { >+ while (state.KeepRunning()) { >+ benchmark::DoNotOptimize(absl::InfinitePast()); >+ } >+} >+BENCHMARK(BM_Time_InfinitePast); >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_norm_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_norm_test.cc >new file mode 100644 >index 00000000000..4436242e412 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_norm_test.cc >@@ -0,0 +1,306 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// This file contains tests for FromDateTime() normalization, which is >+// time-zone independent so we just use UTC throughout. >+ >+#include <cstdint> >+#include <limits> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/time/internal/test_util.h" >+#include "absl/time/time.h" >+ >+namespace { >+ >+TEST(TimeNormCase, SimpleOverflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = >+ absl::ConvertDateTime(2013, 11, 15, 16, 32, 59 + 1, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 33, 0, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 59 + 1, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 17, 0, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 23 + 1, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 16, 0, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 30 + 1, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 1, 16, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 12 + 1, 15, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 15, 16, 32, 14, 0, false); >+} >+ >+TEST(TimeNormCase, SimpleUnderflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = ConvertDateTime(2013, 11, 15, 16, 32, 0 - 1, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 16, 31, 59, 0, false); >+ >+ tc = ConvertDateTime(2013, 11, 15, 16, 0 - 1, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 15, 15, 59, 14, 0, false); >+ >+ tc = ConvertDateTime(2013, 11, 15, 0 - 1, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 14, 23, 32, 14, 0, false); >+ >+ tc = ConvertDateTime(2013, 11, 1 - 1, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 10, 31, 16, 32, 14, 0, false); >+ >+ tc = ConvertDateTime(2013, 1 - 1, 15, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 12, 15, 16, 32, 14, 0, false); >+} >+ >+TEST(TimeNormCase, MultipleOverflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::TimeConversion tc = ConvertDateTime(2013, 12, 31, 23, 59, 59 + 1, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2014, 1, 1, 0, 0, 0, 0, false); >+} >+ >+TEST(TimeNormCase, MultipleUnderflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::TimeConversion tc = absl::ConvertDateTime(2014, 1, 1, 0, 0, 0 - 1, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 12, 31, 23, 59, 59, 0, false); >+} >+ >+TEST(TimeNormCase, OverflowLimits) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::TimeConversion tc; >+ absl::Time::Breakdown bd; >+ >+ const int kintmax = std::numeric_limits<int>::max(); >+ tc = absl::ConvertDateTime(0, kintmax, kintmax, kintmax, kintmax, kintmax, >+ utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 185085715, 11, 27, 12, 21, 7, 0, false); >+ >+ const int kintmin = std::numeric_limits<int>::min(); >+ tc = absl::ConvertDateTime(0, kintmin, kintmin, kintmin, kintmin, kintmin, >+ utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, -185085717, 10, 31, 10, 37, 52, 0, false); >+ >+ const int64_t max_year = std::numeric_limits<int64_t>::max(); >+ tc = absl::ConvertDateTime(max_year, 12, 31, 23, 59, 59, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ EXPECT_EQ(absl::InfiniteFuture(), tc.pre); >+ >+ const int64_t min_year = std::numeric_limits<int64_t>::min(); >+ tc = absl::ConvertDateTime(min_year, 1, 1, 0, 0, 0, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ EXPECT_EQ(absl::InfinitePast(), tc.pre); >+} >+ >+TEST(TimeNormCase, ComplexOverflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = >+ ConvertDateTime(2013, 11, 15, 16, 32, 14 + 123456789, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 10, 14, 14, 5, 23, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 + 1234567, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2016, 3, 22, 0, 39, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16 + 123456, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2027, 12, 16, 16, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15 + 1234, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2017, 4, 2, 16, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11 + 123, 15, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2024, 2, 15, 16, 32, 14, 0, false); >+} >+ >+TEST(TimeNormCase, ComplexUnderflow) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = >+ absl::ConvertDateTime(1999, 3, 0, 0, 0, 0, utc); // year 400 >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 2, 28, 0, 0, 0, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32, 14 - 123456789, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2009, 12, 17, 18, 59, 5, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16, 32 - 1234567, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2011, 7, 12, 8, 25, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15, 16 - 123456, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1999, 10, 16, 16, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11, 15 - 1234, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2010, 6, 30, 16, 32, 14, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11 - 123, 15, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2003, 8, 15, 16, 32, 14, 0, false); >+} >+ >+TEST(TimeNormCase, Mishmash) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = >+ absl::ConvertDateTime(2013, 11 - 123, 15 + 1234, 16 - 123456, >+ 32 + 1234567, 14 - 123456789, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1991, 5, 9, 3, 6, 5, 0, false); >+ >+ tc = absl::ConvertDateTime(2013, 11 + 123, 15 - 1234, 16 + 123456, >+ 32 - 1234567, 14 + 123456789, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2036, 5, 24, 5, 58, 23, 0, false); >+ >+ // Here is a normalization case we got wrong for a while. Because the >+ // day is converted to "1" within a 400-year (146097-day) period, we >+ // didn't need to roll the month and so we didn't mark it as normalized. >+ tc = absl::ConvertDateTime(2013, 11, -146097 + 1, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1613, 11, 1, 16, 32, 14, 0, false); >+ >+ // Even though the month overflow compensates for the day underflow, >+ // this should still be marked as normalized. >+ tc = absl::ConvertDateTime(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 11, 1, 16, 32, 14, 0, false); >+} >+ >+TEST(TimeNormCase, LeapYears) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ absl::TimeConversion tc = >+ absl::ConvertDateTime(2013, 2, 28 + 1, 0, 0, 0, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ absl::Time::Breakdown bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 3, 1, 0, 0, 0, 0, false); >+ >+ tc = absl::ConvertDateTime(2012, 2, 28 + 1, 0, 0, 0, utc); >+ EXPECT_FALSE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2012, 2, 29, 0, 0, 0, 0, false); >+ >+ tc = absl::ConvertDateTime(2000, 2, 28 + 1, 0, 0, 0, utc); >+ EXPECT_FALSE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 2000, 2, 29, 0, 0, 0, 0, false); >+ >+ tc = absl::ConvertDateTime(1900, 2, 28 + 1, 0, 0, 0, utc); >+ EXPECT_TRUE(tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ bd = tc.pre.In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1900, 3, 1, 0, 0, 0, 0, false); >+} >+ >+// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31) >+// and check that they normalize to the expected time. 146097 days span >+// the 400-year Gregorian cycle used during normalization. >+TEST(TimeNormCase, AllTheDays) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::Time exp_time = absl::UnixEpoch(); >+ >+ for (int day = 1; day <= 146097; ++day) { >+ absl::TimeConversion tc = absl::ConvertDateTime(1970, 1, day, 0, 0, 0, utc); >+ EXPECT_EQ(day > 31, tc.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, tc.kind); >+ EXPECT_EQ(exp_time, tc.pre); >+ exp_time += absl::Hours(24); >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_test.cc >new file mode 100644 >index 00000000000..4f8f58a6ef3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_test.cc >@@ -0,0 +1,1088 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/time.h" >+ >+#include <chrono> // NOLINT(build/c++11) >+#include <cstring> >+#include <ctime> >+#include <iomanip> >+#include <limits> >+#include <string> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/time/clock.h" >+#include "absl/time/internal/test_util.h" >+ >+namespace { >+ >+// A gMock matcher to match timespec values. Use this matcher like: >+// timespec ts1, ts2; >+// EXPECT_THAT(ts1, TimespecMatcher(ts2)); >+MATCHER_P(TimespecMatcher, ts, "") { >+ if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) >+ return true; >+ *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} "; >+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}"; >+ return false; >+} >+ >+// A gMock matcher to match timeval values. Use this matcher like: >+// timeval tv1, tv2; >+// EXPECT_THAT(tv1, TimevalMatcher(tv2)); >+MATCHER_P(TimevalMatcher, tv, "") { >+ if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) >+ return true; >+ *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} "; >+ *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}"; >+ return false; >+} >+ >+TEST(Time, ConstExpr) { >+ constexpr absl::Time t0 = absl::UnixEpoch(); >+ static_assert(t0 == absl::Time(), "UnixEpoch"); >+ constexpr absl::Time t1 = absl::InfiniteFuture(); >+ static_assert(t1 != absl::Time(), "InfiniteFuture"); >+ constexpr absl::Time t2 = absl::InfinitePast(); >+ static_assert(t2 != absl::Time(), "InfinitePast"); >+ constexpr absl::Time t3 = absl::FromUnixNanos(0); >+ static_assert(t3 == absl::Time(), "FromUnixNanos"); >+ constexpr absl::Time t4 = absl::FromUnixMicros(0); >+ static_assert(t4 == absl::Time(), "FromUnixMicros"); >+ constexpr absl::Time t5 = absl::FromUnixMillis(0); >+ static_assert(t5 == absl::Time(), "FromUnixMillis"); >+ constexpr absl::Time t6 = absl::FromUnixSeconds(0); >+ static_assert(t6 == absl::Time(), "FromUnixSeconds"); >+ constexpr absl::Time t7 = absl::FromTimeT(0); >+ static_assert(t7 == absl::Time(), "FromTimeT"); >+} >+ >+TEST(Time, ValueSemantics) { >+ absl::Time a; // Default construction >+ absl::Time b = a; // Copy construction >+ EXPECT_EQ(a, b); >+ absl::Time c(a); // Copy construction (again) >+ EXPECT_EQ(a, b); >+ EXPECT_EQ(a, c); >+ EXPECT_EQ(b, c); >+ b = c; // Assignment >+ EXPECT_EQ(a, b); >+ EXPECT_EQ(a, c); >+ EXPECT_EQ(b, c); >+} >+ >+TEST(Time, UnixEpoch) { >+ absl::Time::Breakdown bd = absl::UnixEpoch().In(absl::UTCTimeZone()); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1970, 1, 1, 0, 0, 0, 0, false); >+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); >+ EXPECT_EQ(4, bd.weekday); // Thursday >+} >+ >+TEST(Time, Breakdown) { >+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/New_York"); >+ absl::Time t = absl::UnixEpoch(); >+ >+ // The Unix epoch as seen in NYC. >+ absl::Time::Breakdown bd = t.In(tz); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 19, 0, 0, -18000, false); >+ EXPECT_EQ(absl::ZeroDuration(), bd.subsecond); >+ EXPECT_EQ(3, bd.weekday); // Wednesday >+ >+ // Just before the epoch. >+ t -= absl::Nanoseconds(1); >+ bd = t.In(tz); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1969, 12, 31, 18, 59, 59, -18000, false); >+ EXPECT_EQ(absl::Nanoseconds(999999999), bd.subsecond); >+ EXPECT_EQ(3, bd.weekday); // Wednesday >+ >+ // Some time later. >+ t += absl::Hours(24) * 2735; >+ t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) + >+ absl::Nanoseconds(9); >+ bd = t.In(tz); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 1977, 6, 28, 14, 30, 15, -14400, true); >+ EXPECT_EQ(8, bd.subsecond / absl::Nanoseconds(1)); >+ EXPECT_EQ(2, bd.weekday); // Tuesday >+} >+ >+TEST(Time, AdditiveOperators) { >+ const absl::Duration d = absl::Nanoseconds(1); >+ const absl::Time t0; >+ const absl::Time t1 = t0 + d; >+ >+ EXPECT_EQ(d, t1 - t0); >+ EXPECT_EQ(-d, t0 - t1); >+ EXPECT_EQ(t0, t1 - d); >+ >+ absl::Time t(t0); >+ EXPECT_EQ(t0, t); >+ t += d; >+ EXPECT_EQ(t0 + d, t); >+ EXPECT_EQ(d, t - t0); >+ t -= d; >+ EXPECT_EQ(t0, t); >+ >+ // Tests overflow between subseconds and seconds. >+ t = absl::UnixEpoch(); >+ t += absl::Milliseconds(500); >+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t); >+ t += absl::Milliseconds(600); >+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(1100), t); >+ t -= absl::Milliseconds(600); >+ EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t); >+ t -= absl::Milliseconds(500); >+ EXPECT_EQ(absl::UnixEpoch(), t); >+} >+ >+TEST(Time, RelationalOperators) { >+ constexpr absl::Time t1 = absl::FromUnixNanos(0); >+ constexpr absl::Time t2 = absl::FromUnixNanos(1); >+ constexpr absl::Time t3 = absl::FromUnixNanos(2); >+ >+ static_assert(absl::Time() == t1, ""); >+ static_assert(t1 == t1, ""); >+ static_assert(t2 == t2, ""); >+ static_assert(t3 == t3, ""); >+ >+ static_assert(t1 < t2, ""); >+ static_assert(t2 < t3, ""); >+ static_assert(t1 < t3, ""); >+ >+ static_assert(t1 <= t1, ""); >+ static_assert(t1 <= t2, ""); >+ static_assert(t2 <= t2, ""); >+ static_assert(t2 <= t3, ""); >+ static_assert(t3 <= t3, ""); >+ static_assert(t1 <= t3, ""); >+ >+ static_assert(t2 > t1, ""); >+ static_assert(t3 > t2, ""); >+ static_assert(t3 > t1, ""); >+ >+ static_assert(t2 >= t2, ""); >+ static_assert(t2 >= t1, ""); >+ static_assert(t3 >= t3, ""); >+ static_assert(t3 >= t2, ""); >+ static_assert(t1 >= t1, ""); >+ static_assert(t3 >= t1, ""); >+} >+ >+TEST(Time, Infinity) { >+ constexpr absl::Time ifuture = absl::InfiniteFuture(); >+ constexpr absl::Time ipast = absl::InfinitePast(); >+ >+ static_assert(ifuture == ifuture, ""); >+ static_assert(ipast == ipast, ""); >+ static_assert(ipast < ifuture, ""); >+ static_assert(ifuture > ipast, ""); >+ >+ // Arithmetic saturates >+ EXPECT_EQ(ifuture, ifuture + absl::Seconds(1)); >+ EXPECT_EQ(ifuture, ifuture - absl::Seconds(1)); >+ EXPECT_EQ(ipast, ipast + absl::Seconds(1)); >+ EXPECT_EQ(ipast, ipast - absl::Seconds(1)); >+ >+ EXPECT_EQ(absl::InfiniteDuration(), ifuture - ifuture); >+ EXPECT_EQ(absl::InfiniteDuration(), ifuture - ipast); >+ EXPECT_EQ(-absl::InfiniteDuration(), ipast - ifuture); >+ EXPECT_EQ(-absl::InfiniteDuration(), ipast - ipast); >+ >+ constexpr absl::Time t = absl::UnixEpoch(); // Any finite time. >+ static_assert(t < ifuture, ""); >+ static_assert(t > ipast, ""); >+} >+ >+TEST(Time, FloorConversion) { >+#define TEST_FLOOR_CONVERSION(TO, FROM) \ >+ EXPECT_EQ(1, TO(FROM(1001))); \ >+ EXPECT_EQ(1, TO(FROM(1000))); \ >+ EXPECT_EQ(0, TO(FROM(999))); \ >+ EXPECT_EQ(0, TO(FROM(1))); \ >+ EXPECT_EQ(0, TO(FROM(0))); \ >+ EXPECT_EQ(-1, TO(FROM(-1))); \ >+ EXPECT_EQ(-1, TO(FROM(-999))); \ >+ EXPECT_EQ(-1, TO(FROM(-1000))); \ >+ EXPECT_EQ(-2, TO(FROM(-1001))); >+ >+ TEST_FLOOR_CONVERSION(absl::ToUnixMicros, absl::FromUnixNanos); >+ TEST_FLOOR_CONVERSION(absl::ToUnixMillis, absl::FromUnixMicros); >+ TEST_FLOOR_CONVERSION(absl::ToUnixSeconds, absl::FromUnixMillis); >+ TEST_FLOOR_CONVERSION(absl::ToTimeT, absl::FromUnixMillis); >+ >+#undef TEST_FLOOR_CONVERSION >+ >+ // Tests ToUnixNanos. >+ EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(3) / 2)); >+ EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1))); >+ EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1) / 2)); >+ EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(0))); >+ EXPECT_EQ(-1, >+ absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1) / 2)); >+ EXPECT_EQ(-1, absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1))); >+ EXPECT_EQ(-2, >+ absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(3) / 2)); >+ >+ // Tests ToUniversal, which uses a different epoch than the tests above. >+ EXPECT_EQ(1, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(101))); >+ EXPECT_EQ(1, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(100))); >+ EXPECT_EQ(0, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(99))); >+ EXPECT_EQ(0, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(1))); >+ EXPECT_EQ(0, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(0))); >+ EXPECT_EQ(-1, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-1))); >+ EXPECT_EQ(-1, >+ absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-99))); >+ EXPECT_EQ( >+ -1, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-100))); >+ EXPECT_EQ( >+ -2, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-101))); >+ >+ // Tests ToTimespec()/TimeFromTimespec() >+ const struct { >+ absl::Time t; >+ timespec ts; >+ } to_ts[] = { >+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(1), {1, 1}}, >+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(1) / 2, {1, 0}}, >+ {absl::FromUnixSeconds(1) + absl::Nanoseconds(0), {1, 0}}, >+ {absl::FromUnixSeconds(0) + absl::Nanoseconds(0), {0, 0}}, >+ {absl::FromUnixSeconds(0) - absl::Nanoseconds(1) / 2, {-1, 999999999}}, >+ {absl::FromUnixSeconds(0) - absl::Nanoseconds(1), {-1, 999999999}}, >+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1), {-1, 1}}, >+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1) / 2, {-1, 0}}, >+ {absl::FromUnixSeconds(-1) + absl::Nanoseconds(0), {-1, 0}}, >+ {absl::FromUnixSeconds(-1) - absl::Nanoseconds(1) / 2, {-2, 999999999}}, >+ }; >+ for (const auto& test : to_ts) { >+ EXPECT_THAT(absl::ToTimespec(test.t), TimespecMatcher(test.ts)); >+ } >+ const struct { >+ timespec ts; >+ absl::Time t; >+ } from_ts[] = { >+ {{1, 1}, absl::FromUnixSeconds(1) + absl::Nanoseconds(1)}, >+ {{1, 0}, absl::FromUnixSeconds(1) + absl::Nanoseconds(0)}, >+ {{0, 0}, absl::FromUnixSeconds(0) + absl::Nanoseconds(0)}, >+ {{0, -1}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)}, >+ {{-1, 999999999}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)}, >+ {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(1)}, >+ {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(0)}, >+ {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)}, >+ {{-2, 999999999}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)}, >+ }; >+ for (const auto& test : from_ts) { >+ EXPECT_EQ(test.t, absl::TimeFromTimespec(test.ts)); >+ } >+ >+ // Tests ToTimeval()/TimeFromTimeval() (same as timespec above) >+ const struct { >+ absl::Time t; >+ timeval tv; >+ } to_tv[] = { >+ {absl::FromUnixSeconds(1) + absl::Microseconds(1), {1, 1}}, >+ {absl::FromUnixSeconds(1) + absl::Microseconds(1) / 2, {1, 0}}, >+ {absl::FromUnixSeconds(1) + absl::Microseconds(0), {1, 0}}, >+ {absl::FromUnixSeconds(0) + absl::Microseconds(0), {0, 0}}, >+ {absl::FromUnixSeconds(0) - absl::Microseconds(1) / 2, {-1, 999999}}, >+ {absl::FromUnixSeconds(0) - absl::Microseconds(1), {-1, 999999}}, >+ {absl::FromUnixSeconds(-1) + absl::Microseconds(1), {-1, 1}}, >+ {absl::FromUnixSeconds(-1) + absl::Microseconds(1) / 2, {-1, 0}}, >+ {absl::FromUnixSeconds(-1) + absl::Microseconds(0), {-1, 0}}, >+ {absl::FromUnixSeconds(-1) - absl::Microseconds(1) / 2, {-2, 999999}}, >+ }; >+ for (const auto& test : to_tv) { >+ EXPECT_THAT(ToTimeval(test.t), TimevalMatcher(test.tv)); >+ } >+ const struct { >+ timeval tv; >+ absl::Time t; >+ } from_tv[] = { >+ {{1, 1}, absl::FromUnixSeconds(1) + absl::Microseconds(1)}, >+ {{1, 0}, absl::FromUnixSeconds(1) + absl::Microseconds(0)}, >+ {{0, 0}, absl::FromUnixSeconds(0) + absl::Microseconds(0)}, >+ {{0, -1}, absl::FromUnixSeconds(0) - absl::Microseconds(1)}, >+ {{-1, 999999}, absl::FromUnixSeconds(0) - absl::Microseconds(1)}, >+ {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Microseconds(1)}, >+ {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Microseconds(0)}, >+ {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)}, >+ {{-2, 999999}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)}, >+ }; >+ for (const auto& test : from_tv) { >+ EXPECT_EQ(test.t, absl::TimeFromTimeval(test.tv)); >+ } >+ >+ // Tests flooring near negative infinity. >+ const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1; >+ EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1))); >+ EXPECT_EQ(std::numeric_limits<int64_t>::min(), >+ absl::ToUnixSeconds( >+ absl::FromUnixSeconds(min_plus_1) - absl::Nanoseconds(1) / 2)); >+ >+ // Tests flooring near positive infinity. >+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), >+ absl::ToUnixSeconds(absl::FromUnixSeconds( >+ std::numeric_limits<int64_t>::max()) + absl::Nanoseconds(1) / 2)); >+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), >+ absl::ToUnixSeconds( >+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()))); >+ EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1, >+ absl::ToUnixSeconds(absl::FromUnixSeconds( >+ std::numeric_limits<int64_t>::max()) - absl::Nanoseconds(1) / 2)); >+} >+ >+TEST(Time, RoundtripConversion) { >+#define TEST_CONVERSION_ROUND_TRIP(SOURCE, FROM, TO, MATCHER) \ >+ EXPECT_THAT(TO(FROM(SOURCE)), MATCHER(SOURCE)) >+ >+ // FromUnixNanos() and ToUnixNanos() >+ int64_t now_ns = absl::GetCurrentTimeNanos(); >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixNanos, absl::ToUnixNanos, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixNanos, absl::ToUnixNanos, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixNanos, absl::ToUnixNanos, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_ns, absl::FromUnixNanos, absl::ToUnixNanos, >+ testing::Eq) >+ << now_ns; >+ >+ // FromUnixMicros() and ToUnixMicros() >+ int64_t now_us = absl::GetCurrentTimeNanos() / 1000; >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMicros, absl::ToUnixMicros, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMicros, absl::ToUnixMicros, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMicros, absl::ToUnixMicros, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_us, absl::FromUnixMicros, absl::ToUnixMicros, >+ testing::Eq) >+ << now_us; >+ >+ // FromUnixMillis() and ToUnixMillis() >+ int64_t now_ms = absl::GetCurrentTimeNanos() / 1000000; >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMillis, absl::ToUnixMillis, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMillis, absl::ToUnixMillis, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMillis, absl::ToUnixMillis, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_ms, absl::FromUnixMillis, absl::ToUnixMillis, >+ testing::Eq) >+ << now_ms; >+ >+ // FromUnixSeconds() and ToUnixSeconds() >+ int64_t now_s = std::time(nullptr); >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixSeconds, absl::ToUnixSeconds, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixSeconds, absl::ToUnixSeconds, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixSeconds, absl::ToUnixSeconds, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_s, absl::FromUnixSeconds, absl::ToUnixSeconds, >+ testing::Eq) >+ << now_s; >+ >+ // FromTimeT() and ToTimeT() >+ time_t now_time_t = std::time(nullptr); >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromTimeT, absl::ToTimeT, testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromTimeT, absl::ToTimeT, testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromTimeT, absl::ToTimeT, testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_time_t, absl::FromTimeT, absl::ToTimeT, >+ testing::Eq) >+ << now_time_t; >+ >+ // TimeFromTimeval() and ToTimeval() >+ timeval tv; >+ tv.tv_sec = -1; >+ tv.tv_usec = 0; >+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, >+ TimevalMatcher); >+ tv.tv_sec = -1; >+ tv.tv_usec = 999999; >+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, >+ TimevalMatcher); >+ tv.tv_sec = 0; >+ tv.tv_usec = 0; >+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, >+ TimevalMatcher); >+ tv.tv_sec = 0; >+ tv.tv_usec = 1; >+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, >+ TimevalMatcher); >+ tv.tv_sec = 1; >+ tv.tv_usec = 0; >+ TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, >+ TimevalMatcher); >+ >+ // TimeFromTimespec() and ToTimespec() >+ timespec ts; >+ ts.tv_sec = -1; >+ ts.tv_nsec = 0; >+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, >+ TimespecMatcher); >+ ts.tv_sec = -1; >+ ts.tv_nsec = 999999999; >+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, >+ TimespecMatcher); >+ ts.tv_sec = 0; >+ ts.tv_nsec = 0; >+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, >+ TimespecMatcher); >+ ts.tv_sec = 0; >+ ts.tv_nsec = 1; >+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, >+ TimespecMatcher); >+ ts.tv_sec = 1; >+ ts.tv_nsec = 0; >+ TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, >+ TimespecMatcher); >+ >+ // FromUDate() and ToUDate() >+ double now_ud = absl::GetCurrentTimeNanos() / 1000000; >+ TEST_CONVERSION_ROUND_TRIP(-1.5, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(-0.5, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(0.5, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(1.5, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq); >+ TEST_CONVERSION_ROUND_TRIP(now_ud, absl::FromUDate, absl::ToUDate, >+ testing::DoubleEq) >+ << std::fixed << std::setprecision(17) << now_ud; >+ >+ // FromUniversal() and ToUniversal() >+ int64_t now_uni = ((719162LL * (24 * 60 * 60)) * (1000 * 1000 * 10)) + >+ (absl::GetCurrentTimeNanos() / 100); >+ TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUniversal, absl::ToUniversal, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(0, absl::FromUniversal, absl::ToUniversal, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(1, absl::FromUniversal, absl::ToUniversal, >+ testing::Eq); >+ TEST_CONVERSION_ROUND_TRIP(now_uni, absl::FromUniversal, absl::ToUniversal, >+ testing::Eq) >+ << now_uni; >+ >+#undef TEST_CONVERSION_ROUND_TRIP >+} >+ >+template <typename Duration> >+std::chrono::system_clock::time_point MakeChronoUnixTime(const Duration& d) { >+ return std::chrono::system_clock::from_time_t(0) + d; >+} >+ >+TEST(Time, FromChrono) { >+ EXPECT_EQ(absl::FromTimeT(-1), >+ absl::FromChrono(std::chrono::system_clock::from_time_t(-1))); >+ EXPECT_EQ(absl::FromTimeT(0), >+ absl::FromChrono(std::chrono::system_clock::from_time_t(0))); >+ EXPECT_EQ(absl::FromTimeT(1), >+ absl::FromChrono(std::chrono::system_clock::from_time_t(1))); >+ >+ EXPECT_EQ( >+ absl::FromUnixMillis(-1), >+ absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(-1)))); >+ EXPECT_EQ(absl::FromUnixMillis(0), >+ absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(0)))); >+ EXPECT_EQ(absl::FromUnixMillis(1), >+ absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(1)))); >+ >+ // Chrono doesn't define exactly its range and precision (neither does >+ // absl::Time), so let's simply test +/- ~100 years to make sure things work. >+ const auto century_sec = 60 * 60 * 24 * 365 * int64_t{100}; >+ const auto century = std::chrono::seconds(century_sec); >+ const auto chrono_future = MakeChronoUnixTime(century); >+ const auto chrono_past = MakeChronoUnixTime(-century); >+ EXPECT_EQ(absl::FromUnixSeconds(century_sec), >+ absl::FromChrono(chrono_future)); >+ EXPECT_EQ(absl::FromUnixSeconds(-century_sec), absl::FromChrono(chrono_past)); >+ >+ // Roundtrip them both back to chrono. >+ EXPECT_EQ(chrono_future, >+ absl::ToChronoTime(absl::FromUnixSeconds(century_sec))); >+ EXPECT_EQ(chrono_past, >+ absl::ToChronoTime(absl::FromUnixSeconds(-century_sec))); >+} >+ >+TEST(Time, ToChronoTime) { >+ EXPECT_EQ(std::chrono::system_clock::from_time_t(-1), >+ absl::ToChronoTime(absl::FromTimeT(-1))); >+ EXPECT_EQ(std::chrono::system_clock::from_time_t(0), >+ absl::ToChronoTime(absl::FromTimeT(0))); >+ EXPECT_EQ(std::chrono::system_clock::from_time_t(1), >+ absl::ToChronoTime(absl::FromTimeT(1))); >+ >+ EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(-1)), >+ absl::ToChronoTime(absl::FromUnixMillis(-1))); >+ EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(0)), >+ absl::ToChronoTime(absl::FromUnixMillis(0))); >+ EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(1)), >+ absl::ToChronoTime(absl::FromUnixMillis(1))); >+ >+ // Time before the Unix epoch should floor, not trunc. >+ const auto tick = absl::Nanoseconds(1) / 4; >+ EXPECT_EQ(std::chrono::system_clock::from_time_t(0) - >+ std::chrono::system_clock::duration(1), >+ absl::ToChronoTime(absl::UnixEpoch() - tick)); >+} >+ >+TEST(Time, ConvertDateTime) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ const absl::TimeZone goog = >+ absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ const absl::TimeZone nyc = >+ absl::time_internal::LoadTimeZone("America/New_York"); >+ const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; >+ >+ // A simple case of normalization. >+ absl::TimeConversion oct32 = ConvertDateTime(2013, 10, 32, 8, 30, 0, goog); >+ EXPECT_TRUE(oct32.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, oct32.kind); >+ absl::TimeConversion nov01 = ConvertDateTime(2013, 11, 1, 8, 30, 0, goog); >+ EXPECT_FALSE(nov01.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, nov01.kind); >+ EXPECT_EQ(oct32.pre, nov01.pre); >+ EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0700 (PDT)", >+ absl::FormatTime(fmt, nov01.pre, goog)); >+ >+ // A Spring DST transition, when there is a gap in civil time >+ // and we prefer the later of the possible interpretations of a >+ // non-existent time. >+ absl::TimeConversion mar13 = ConvertDateTime(2011, 3, 13, 2, 15, 0, nyc); >+ EXPECT_FALSE(mar13.normalized); >+ EXPECT_EQ(absl::TimeConversion::SKIPPED, mar13.kind); >+ EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)", >+ absl::FormatTime(fmt, mar13.pre, nyc)); >+ EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)", >+ absl::FormatTime(fmt, mar13.trans, nyc)); >+ EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)", >+ absl::FormatTime(fmt, mar13.post, nyc)); >+ EXPECT_EQ(mar13.pre, absl::FromDateTime(2011, 3, 13, 2, 15, 0, nyc)); >+ >+ // A Fall DST transition, when civil times are repeated and >+ // we prefer the earlier of the possible interpretations of an >+ // ambiguous time. >+ absl::TimeConversion nov06 = ConvertDateTime(2011, 11, 6, 1, 15, 0, nyc); >+ EXPECT_FALSE(nov06.normalized); >+ EXPECT_EQ(absl::TimeConversion::REPEATED, nov06.kind); >+ EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0400 (EDT)", >+ absl::FormatTime(fmt, nov06.pre, nyc)); >+ EXPECT_EQ("Sun, 6 Nov 2011 01:00:00 -0500 (EST)", >+ absl::FormatTime(fmt, nov06.trans, nyc)); >+ EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0500 (EST)", >+ absl::FormatTime(fmt, nov06.post, nyc)); >+ EXPECT_EQ(nov06.pre, absl::FromDateTime(2011, 11, 6, 1, 15, 0, nyc)); >+ >+ // Check that (time_t) -1 is handled correctly. >+ absl::TimeConversion minus1 = ConvertDateTime(1969, 12, 31, 18, 59, 59, nyc); >+ EXPECT_FALSE(minus1.normalized); >+ EXPECT_EQ(absl::TimeConversion::UNIQUE, minus1.kind); >+ EXPECT_EQ(-1, absl::ToTimeT(minus1.pre)); >+ EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)", >+ absl::FormatTime(fmt, minus1.pre, nyc)); >+ EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)", >+ absl::FormatTime(fmt, minus1.pre, utc)); >+} >+ >+// FromDateTime(year, mon, day, hour, min, sec, UTCTimeZone()) has >+// a specialized fastpath implementation which we exercise here. >+TEST(Time, FromDateTimeUTC) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; >+ const int kMax = std::numeric_limits<int>::max(); >+ const int kMin = std::numeric_limits<int>::min(); >+ absl::Time t; >+ >+ // 292091940881 is the last positive year to use the fastpath. >+ t = absl::FromDateTime(292091940881, kMax, kMax, kMax, kMax, kMax, utc); >+ EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ t = absl::FromDateTime(292091940882, kMax, kMax, kMax, kMax, kMax, utc); >+ EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow >+ t = absl::FromDateTime( >+ std::numeric_limits<int64_t>::max(), kMax, kMax, kMax, kMax, kMax, utc); >+ EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow >+ >+ // -292091936940 is the last negative year to use the fastpath. >+ t = absl::FromDateTime(-292091936940, kMin, kMin, kMin, kMin, kMin, utc); >+ EXPECT_EQ("Fri, 1 Nov -292277022657 10:37:52 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ t = absl::FromDateTime(-292091936941, kMin, kMin, kMin, kMin, kMin, utc); >+ EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no underflow >+ t = absl::FromDateTime( >+ std::numeric_limits<int64_t>::min(), kMin, kMin, kMin, kMin, kMin, utc); >+ EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no overflow >+ >+ // Check that we're counting leap years correctly. >+ t = absl::FromDateTime(1900, 2, 28, 23, 59, 59, utc); >+ EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ t = absl::FromDateTime(1900, 3, 1, 0, 0, 0, utc); >+ EXPECT_EQ("Thu, 1 Mar 1900 00:00:00 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ t = absl::FromDateTime(2000, 2, 29, 23, 59, 59, utc); >+ EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ t = absl::FromDateTime(2000, 3, 1, 0, 0, 0, utc); >+ EXPECT_EQ("Wed, 1 Mar 2000 00:00:00 +0000 (UTC)", >+ absl::FormatTime(fmt, t, utc)); >+ >+ // Check normalization. >+ const std::string ymdhms = "%Y-%m-%d %H:%M:%S"; >+ t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc); >+ EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc); >+ EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc); >+ EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc); >+ EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc); >+ EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc); >+ EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc); >+ EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc); >+ EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc); >+ EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc); >+ EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc); >+ EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); >+ t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc); >+ EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc)); >+} >+ >+TEST(Time, ToTM) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ >+ // Compares the results of ToTM() to gmtime_r() for lots of times over the >+ // course of a few days. >+ const absl::Time start = absl::FromDateTime(2014, 1, 2, 3, 4, 5, utc); >+ const absl::Time end = absl::FromDateTime(2014, 1, 5, 3, 4, 5, utc); >+ for (absl::Time t = start; t < end; t += absl::Seconds(30)) { >+ const struct tm tm_bt = ToTM(t, utc); >+ const time_t tt = absl::ToTimeT(t); >+ struct tm tm_lc; >+#ifdef _WIN32 >+ gmtime_s(&tm_lc, &tt); >+#else >+ gmtime_r(&tt, &tm_lc); >+#endif >+ EXPECT_EQ(tm_lc.tm_year, tm_bt.tm_year); >+ EXPECT_EQ(tm_lc.tm_mon, tm_bt.tm_mon); >+ EXPECT_EQ(tm_lc.tm_mday, tm_bt.tm_mday); >+ EXPECT_EQ(tm_lc.tm_hour, tm_bt.tm_hour); >+ EXPECT_EQ(tm_lc.tm_min, tm_bt.tm_min); >+ EXPECT_EQ(tm_lc.tm_sec, tm_bt.tm_sec); >+ EXPECT_EQ(tm_lc.tm_wday, tm_bt.tm_wday); >+ EXPECT_EQ(tm_lc.tm_yday, tm_bt.tm_yday); >+ EXPECT_EQ(tm_lc.tm_isdst, tm_bt.tm_isdst); >+ >+ ASSERT_FALSE(HasFailure()); >+ } >+ >+ // Checks that the tm_isdst field is correct when in standard time. >+ const absl::TimeZone nyc = >+ absl::time_internal::LoadTimeZone("America/New_York"); >+ absl::Time t = absl::FromDateTime(2014, 3, 1, 0, 0, 0, nyc); >+ struct tm tm = ToTM(t, nyc); >+ EXPECT_FALSE(tm.tm_isdst); >+ >+ // Checks that the tm_isdst field is correct when in daylight time. >+ t = absl::FromDateTime(2014, 4, 1, 0, 0, 0, nyc); >+ tm = ToTM(t, nyc); >+ EXPECT_TRUE(tm.tm_isdst); >+ >+ // Checks overflow. >+ tm = ToTM(absl::InfiniteFuture(), nyc); >+ EXPECT_EQ(std::numeric_limits<int>::max() - 1900, tm.tm_year); >+ EXPECT_EQ(11, tm.tm_mon); >+ EXPECT_EQ(31, tm.tm_mday); >+ EXPECT_EQ(23, tm.tm_hour); >+ EXPECT_EQ(59, tm.tm_min); >+ EXPECT_EQ(59, tm.tm_sec); >+ EXPECT_EQ(4, tm.tm_wday); >+ EXPECT_EQ(364, tm.tm_yday); >+ EXPECT_FALSE(tm.tm_isdst); >+ >+ // Checks underflow. >+ tm = ToTM(absl::InfinitePast(), nyc); >+ EXPECT_EQ(std::numeric_limits<int>::min(), tm.tm_year); >+ EXPECT_EQ(0, tm.tm_mon); >+ EXPECT_EQ(1, tm.tm_mday); >+ EXPECT_EQ(0, tm.tm_hour); >+ EXPECT_EQ(0, tm.tm_min); >+ EXPECT_EQ(0, tm.tm_sec); >+ EXPECT_EQ(0, tm.tm_wday); >+ EXPECT_EQ(0, tm.tm_yday); >+ EXPECT_FALSE(tm.tm_isdst); >+} >+ >+TEST(Time, FromTM) { >+ const absl::TimeZone nyc = >+ absl::time_internal::LoadTimeZone("America/New_York"); >+ >+ // Verifies that tm_isdst doesn't affect anything when the time is unique. >+ struct tm tm; >+ std::memset(&tm, 0, sizeof(tm)); >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 6 - 1; >+ tm.tm_mday = 28; >+ tm.tm_hour = 1; >+ tm.tm_min = 2; >+ tm.tm_sec = 3; >+ tm.tm_isdst = -1; >+ absl::Time t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST >+ tm.tm_isdst = 0; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST >+ tm.tm_isdst = 1; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST >+ >+ // Adjusts tm to refer to an ambiguous time. >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 11 - 1; >+ tm.tm_mday = 2; >+ tm.tm_hour = 1; >+ tm.tm_min = 30; >+ tm.tm_sec = 42; >+ tm.tm_isdst = -1; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST >+ tm.tm_isdst = 0; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-11-02T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD >+ tm.tm_isdst = 1; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST >+ >+ // Adjusts tm to refer to a skipped time. >+ tm.tm_year = 2014 - 1900; >+ tm.tm_mon = 3 - 1; >+ tm.tm_mday = 9; >+ tm.tm_hour = 2; >+ tm.tm_min = 30; >+ tm.tm_sec = 42; >+ tm.tm_isdst = -1; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST >+ tm.tm_isdst = 0; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-03-09T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD >+ tm.tm_isdst = 1; >+ t = FromTM(tm, nyc); >+ EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST >+} >+ >+TEST(Time, TMRoundTrip) { >+ const absl::TimeZone nyc = >+ absl::time_internal::LoadTimeZone("America/New_York"); >+ >+ // Test round-tripping across a skipped transition >+ absl::Time start = absl::FromDateTime(2014, 3, 9, 0, 0, 0, nyc); >+ absl::Time end = absl::FromDateTime(2014, 3, 9, 4, 0, 0, nyc); >+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) { >+ struct tm tm = ToTM(t, nyc); >+ absl::Time rt = FromTM(tm, nyc); >+ EXPECT_EQ(rt, t); >+ } >+ >+ // Test round-tripping across an ambiguous transition >+ start = absl::FromDateTime(2014, 11, 2, 0, 0, 0, nyc); >+ end = absl::FromDateTime(2014, 11, 2, 4, 0, 0, nyc); >+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) { >+ struct tm tm = ToTM(t, nyc); >+ absl::Time rt = FromTM(tm, nyc); >+ EXPECT_EQ(rt, t); >+ } >+ >+ // Test round-tripping of unique instants crossing a day boundary >+ start = absl::FromDateTime(2014, 6, 27, 22, 0, 0, nyc); >+ end = absl::FromDateTime(2014, 6, 28, 4, 0, 0, nyc); >+ for (absl::Time t = start; t < end; t += absl::Minutes(1)) { >+ struct tm tm = ToTM(t, nyc); >+ absl::Time rt = FromTM(tm, nyc); >+ EXPECT_EQ(rt, t); >+ } >+} >+ >+TEST(Time, Range) { >+ // The API's documented range is +/- 100 billion years. >+ const absl::Duration range = absl::Hours(24) * 365.2425 * 100000000000; >+ >+ // Arithmetic and comparison still works at +/-range around base values. >+ absl::Time bases[2] = {absl::UnixEpoch(), absl::Now()}; >+ for (const auto base : bases) { >+ absl::Time bottom = base - range; >+ EXPECT_GT(bottom, bottom - absl::Nanoseconds(1)); >+ EXPECT_LT(bottom, bottom + absl::Nanoseconds(1)); >+ absl::Time top = base + range; >+ EXPECT_GT(top, top - absl::Nanoseconds(1)); >+ EXPECT_LT(top, top + absl::Nanoseconds(1)); >+ absl::Duration full_range = 2 * range; >+ EXPECT_EQ(full_range, top - bottom); >+ EXPECT_EQ(-full_range, bottom - top); >+ } >+} >+ >+TEST(Time, Limits) { >+ // It is an implementation detail that Time().rep_ == ZeroDuration(), >+ // and that the resolution of a Duration is 1/4 of a nanosecond. >+ const absl::Time zero; >+ const absl::Time max = >+ zero + absl::Seconds(std::numeric_limits<int64_t>::max()) + >+ absl::Nanoseconds(999999999) + absl::Nanoseconds(3) / 4; >+ const absl::Time min = >+ zero + absl::Seconds(std::numeric_limits<int64_t>::min()); >+ >+ // Some simple max/min bounds checks. >+ EXPECT_LT(max, absl::InfiniteFuture()); >+ EXPECT_GT(min, absl::InfinitePast()); >+ EXPECT_LT(zero, max); >+ EXPECT_GT(zero, min); >+ EXPECT_GE(absl::UnixEpoch(), min); >+ EXPECT_LT(absl::UnixEpoch(), max); >+ >+ // Check sign of Time differences. >+ EXPECT_LT(absl::ZeroDuration(), max - zero); >+ EXPECT_LT(absl::ZeroDuration(), >+ zero - absl::Nanoseconds(1) / 4 - min); // avoid zero - min >+ >+ // Arithmetic works at max - 0.25ns and min + 0.25ns. >+ EXPECT_GT(max, max - absl::Nanoseconds(1) / 4); >+ EXPECT_LT(min, min + absl::Nanoseconds(1) / 4); >+} >+ >+TEST(Time, ConversionSaturation) { >+ const absl::TimeZone utc = absl::UTCTimeZone(); >+ absl::Time t; >+ >+ const auto max_time_t = std::numeric_limits<time_t>::max(); >+ const auto min_time_t = std::numeric_limits<time_t>::min(); >+ time_t tt = max_time_t - 1; >+ t = absl::FromTimeT(tt); >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(max_time_t - 1, tt); >+ t += absl::Seconds(1); >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(max_time_t, tt); >+ t += absl::Seconds(1); // no effect >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(max_time_t, tt); >+ >+ tt = min_time_t + 1; >+ t = absl::FromTimeT(tt); >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(min_time_t + 1, tt); >+ t -= absl::Seconds(1); >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(min_time_t, tt); >+ t -= absl::Seconds(1); // no effect >+ tt = absl::ToTimeT(t); >+ EXPECT_EQ(min_time_t, tt); >+ >+ const auto max_timeval_sec = >+ std::numeric_limits<decltype(timeval::tv_sec)>::max(); >+ const auto min_timeval_sec = >+ std::numeric_limits<decltype(timeval::tv_sec)>::min(); >+ timeval tv; >+ tv.tv_sec = max_timeval_sec; >+ tv.tv_usec = 999998; >+ t = absl::TimeFromTimeval(tv); >+ tv = ToTimeval(t); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999998, tv.tv_usec); >+ t += absl::Microseconds(1); >+ tv = ToTimeval(t); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999999, tv.tv_usec); >+ t += absl::Microseconds(1); // no effect >+ tv = ToTimeval(t); >+ EXPECT_EQ(max_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(999999, tv.tv_usec); >+ >+ tv.tv_sec = min_timeval_sec; >+ tv.tv_usec = 1; >+ t = absl::TimeFromTimeval(tv); >+ tv = ToTimeval(t); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(1, tv.tv_usec); >+ t -= absl::Microseconds(1); >+ tv = ToTimeval(t); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(0, tv.tv_usec); >+ t -= absl::Microseconds(1); // no effect >+ tv = ToTimeval(t); >+ EXPECT_EQ(min_timeval_sec, tv.tv_sec); >+ EXPECT_EQ(0, tv.tv_usec); >+ >+ const auto max_timespec_sec = >+ std::numeric_limits<decltype(timespec::tv_sec)>::max(); >+ const auto min_timespec_sec = >+ std::numeric_limits<decltype(timespec::tv_sec)>::min(); >+ timespec ts; >+ ts.tv_sec = max_timespec_sec; >+ ts.tv_nsec = 999999998; >+ t = absl::TimeFromTimespec(ts); >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999998, ts.tv_nsec); >+ t += absl::Nanoseconds(1); >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999999, ts.tv_nsec); >+ t += absl::Nanoseconds(1); // no effect >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(max_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(999999999, ts.tv_nsec); >+ >+ ts.tv_sec = min_timespec_sec; >+ ts.tv_nsec = 1; >+ t = absl::TimeFromTimespec(ts); >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(1, ts.tv_nsec); >+ t -= absl::Nanoseconds(1); >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(0, ts.tv_nsec); >+ t -= absl::Nanoseconds(1); // no effect >+ ts = absl::ToTimespec(t); >+ EXPECT_EQ(min_timespec_sec, ts.tv_sec); >+ EXPECT_EQ(0, ts.tv_nsec); >+ >+ // Checks how Time::In() saturates on infinities. >+ absl::Time::Breakdown bd = absl::InfiniteFuture().In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::max(), 12, 31, 23, >+ 59, 59, 0, false); >+ EXPECT_EQ(absl::InfiniteDuration(), bd.subsecond); >+ EXPECT_EQ(4, bd.weekday); // Thursday >+ EXPECT_EQ(365, bd.yearday); >+ EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() >+ bd = absl::InfinitePast().In(utc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, >+ 0, 0, false); >+ EXPECT_EQ(-absl::InfiniteDuration(), bd.subsecond); >+ EXPECT_EQ(7, bd.weekday); // Sunday >+ EXPECT_EQ(1, bd.yearday); >+ EXPECT_STREQ("-00", bd.zone_abbr); // artifact of absl::Time::In() >+ >+ // Approach the maximal Time value from below. >+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 6, utc); >+ EXPECT_EQ("292277026596-12-04T15:30:06+00:00", >+ absl::FormatTime(absl::RFC3339_full, t, utc)); >+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 7, utc); >+ EXPECT_EQ("292277026596-12-04T15:30:07+00:00", >+ absl::FormatTime(absl::RFC3339_full, t, utc)); >+ EXPECT_EQ( >+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); >+ >+ // Checks that we can also get the maximal Time value for a far-east zone. >+ const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); >+ t = absl::FromDateTime(292277026596, 12, 5, 5, 30, 7, plus14); >+ EXPECT_EQ("292277026596-12-05T05:30:07+14:00", >+ absl::FormatTime(absl::RFC3339_full, t, plus14)); >+ EXPECT_EQ( >+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t); >+ >+ // One second later should push us to infinity. >+ t = absl::FromDateTime(292277026596, 12, 4, 15, 30, 8, utc); >+ EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc)); >+ >+ // Approach the minimal Time value from above. >+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 53, utc); >+ EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", >+ absl::FormatTime(absl::RFC3339_full, t, utc)); >+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 52, utc); >+ EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", >+ absl::FormatTime(absl::RFC3339_full, t, utc)); >+ EXPECT_EQ( >+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); >+ >+ // Checks that we can also get the minimal Time value for a far-west zone. >+ const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); >+ t = absl::FromDateTime(-292277022657, 1, 26, 20, 29, 52, minus12); >+ EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", >+ absl::FormatTime(absl::RFC3339_full, t, minus12)); >+ EXPECT_EQ( >+ absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t); >+ >+ // One second before should push us to -infinity. >+ t = absl::FromDateTime(-292277022657, 1, 27, 8, 29, 51, utc); >+ EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc)); >+} >+ >+// In zones with POSIX-style recurring rules we use special logic to >+// handle conversions in the distant future. Here we check the limits >+// of those conversions, particularly with respect to integer overflow. >+TEST(Time, ExtendedConversionSaturation) { >+ const absl::TimeZone syd = >+ absl::time_internal::LoadTimeZone("Australia/Sydney"); >+ const absl::TimeZone nyc = >+ absl::time_internal::LoadTimeZone("America/New_York"); >+ const absl::Time max = >+ absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); >+ absl::Time::Breakdown bd; >+ absl::Time t; >+ >+ // The maximal time converted in each zone. >+ bd = max.In(syd); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 5, 2, 30, 7, 39600, true); >+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 7, syd); >+ EXPECT_EQ(max, t); >+ bd = max.In(nyc); >+ ABSL_INTERNAL_EXPECT_TIME(bd, 292277026596, 12, 4, 10, 30, 7, -18000, false); >+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 7, nyc); >+ EXPECT_EQ(max, t); >+ >+ // One second later should push us to infinity. >+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 8, syd); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 8, nyc); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ >+ // And we should stick there. >+ t = absl::FromDateTime(292277026596, 12, 5, 2, 30, 9, syd); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ t = absl::FromDateTime(292277026596, 12, 4, 10, 30, 9, nyc); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ >+ // All the way up to a saturated date/time, without overflow. >+ t = absl::FromDateTime( >+ std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, syd); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+ t = absl::FromDateTime( >+ std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, nyc); >+ EXPECT_EQ(absl::InfiniteFuture(), t); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_zone_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_zone_test.cc >new file mode 100644 >index 00000000000..43d91904044 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/time/time_zone_test.cc >@@ -0,0 +1,97 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/time/internal/cctz/include/cctz/time_zone.h" >+ >+#include "gtest/gtest.h" >+#include "absl/time/internal/test_util.h" >+#include "absl/time/time.h" >+ >+namespace cctz = absl::time_internal::cctz; >+ >+namespace { >+ >+TEST(TimeZone, ValueSemantics) { >+ absl::TimeZone tz; >+ absl::TimeZone tz2 = tz; // Copy-construct >+ EXPECT_EQ(tz, tz2); >+ tz2 = tz; // Copy-assign >+ EXPECT_EQ(tz, tz2); >+} >+ >+TEST(TimeZone, Equality) { >+ absl::TimeZone a, b; >+ EXPECT_EQ(a, b); >+ EXPECT_EQ(a.name(), b.name()); >+ >+ absl::TimeZone implicit_utc; >+ absl::TimeZone explicit_utc = absl::UTCTimeZone(); >+ EXPECT_EQ(implicit_utc, explicit_utc); >+ EXPECT_EQ(implicit_utc.name(), explicit_utc.name()); >+ >+ absl::TimeZone la = absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); >+ EXPECT_NE(la, nyc); >+} >+ >+TEST(TimeZone, CCTZConversion) { >+ const cctz::time_zone cz = cctz::utc_time_zone(); >+ const absl::TimeZone tz(cz); >+ EXPECT_EQ(cz, cctz::time_zone(tz)); >+} >+ >+TEST(TimeZone, DefaultTimeZones) { >+ absl::TimeZone tz; >+ EXPECT_EQ("UTC", absl::TimeZone().name()); >+ EXPECT_EQ("UTC", absl::UTCTimeZone().name()); >+} >+ >+TEST(TimeZone, FixedTimeZone) { >+ const absl::TimeZone tz = absl::FixedTimeZone(123); >+ const cctz::time_zone cz = cctz::fixed_time_zone(cctz::seconds(123)); >+ EXPECT_EQ(tz, absl::TimeZone(cz)); >+} >+ >+TEST(TimeZone, LocalTimeZone) { >+ const absl::TimeZone local_tz = absl::LocalTimeZone(); >+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("localtime"); >+ EXPECT_EQ(tz, local_tz); >+} >+ >+TEST(TimeZone, NamedTimeZones) { >+ absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); >+ EXPECT_EQ("America/New_York", nyc.name()); >+ absl::TimeZone syd = absl::time_internal::LoadTimeZone("Australia/Sydney"); >+ EXPECT_EQ("Australia/Sydney", syd.name()); >+ absl::TimeZone fixed = absl::FixedTimeZone((((3 * 60) + 25) * 60) + 45); >+ EXPECT_EQ("Fixed/UTC+03:25:45", fixed.name()); >+} >+ >+TEST(TimeZone, Failures) { >+ absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz)); >+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC >+ >+ // Ensures that the load still fails on a subsequent attempt. >+ tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz)); >+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC >+ >+ // Loading an empty std::string timezone should fail. >+ tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); >+ EXPECT_FALSE(LoadTimeZone("", &tz)); >+ EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.bazel >new file mode 100644 >index 00000000000..096c119e638 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.bazel >@@ -0,0 +1,280 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+ "ABSL_EXCEPTIONS_FLAG", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "any", >+ hdrs = ["any.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":bad_any_cast", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ "//absl/utility", >+ ], >+) >+ >+cc_library( >+ name = "bad_any_cast", >+ hdrs = ["bad_any_cast.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":bad_any_cast_impl", >+ "//absl/base:config", >+ ], >+) >+ >+cc_library( >+ name = "bad_any_cast_impl", >+ srcs = [ >+ "bad_any_cast.cc", >+ "bad_any_cast.h", >+ ], >+ copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS, >+ visibility = ["//visibility:private"], >+ deps = [ >+ "//absl/base", >+ "//absl/base:config", >+ ], >+) >+ >+cc_test( >+ name = "any_test", >+ size = "small", >+ srcs = [ >+ "any_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":any", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/base:exception_testing", >+ "//absl/container:test_instance_tracker", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "any_test_noexceptions", >+ size = "small", >+ srcs = [ >+ "any_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":any", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/base:exception_testing", >+ "//absl/container:test_instance_tracker", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "any_exception_safety_test", >+ srcs = ["any_exception_safety_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":any", >+ "//absl/base:exception_safety_testing", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "span", >+ hdrs = ["span.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/algorithm", >+ "//absl/base:core_headers", >+ "//absl/base:throw_delegate", >+ "//absl/meta:type_traits", >+ ], >+) >+ >+cc_test( >+ name = "span_test", >+ size = "small", >+ srcs = ["span_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":span", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/base:exception_testing", >+ "//absl/container:fixed_array", >+ "//absl/container:inlined_vector", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "span_test_noexceptions", >+ size = "small", >+ srcs = ["span_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":span", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/base:exception_testing", >+ "//absl/container:fixed_array", >+ "//absl/container:inlined_vector", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "optional", >+ srcs = ["optional.cc"], >+ hdrs = ["optional.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":bad_optional_access", >+ "//absl/base:config", >+ "//absl/memory", >+ "//absl/meta:type_traits", >+ "//absl/utility", >+ ], >+) >+ >+cc_library( >+ name = "bad_optional_access", >+ srcs = ["bad_optional_access.cc"], >+ hdrs = ["bad_optional_access.h"], >+ copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ "//absl/base", >+ "//absl/base:config", >+ ], >+) >+ >+cc_library( >+ name = "bad_variant_access", >+ srcs = ["bad_variant_access.cc"], >+ hdrs = ["bad_variant_access.h"], >+ copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base", >+ "//absl/base:config", >+ ], >+) >+ >+cc_test( >+ name = "optional_test", >+ size = "small", >+ srcs = [ >+ "optional_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":optional", >+ "//absl/base", >+ "//absl/base:config", >+ "//absl/meta:type_traits", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "optional_exception_safety_test", >+ srcs = [ >+ "optional_exception_safety_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":optional", >+ "//absl/base:exception_safety_testing", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_library( >+ name = "variant", >+ srcs = ["internal/variant.h"], >+ hdrs = ["variant.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ ":bad_variant_access", >+ "//absl/base:base_internal", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/meta:type_traits", >+ "//absl/utility", >+ ], >+) >+ >+cc_test( >+ name = "variant_test", >+ size = "small", >+ srcs = ["variant_test.cc"], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":variant", >+ "//absl/base:config", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "//absl/meta:type_traits", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >+ >+cc_test( >+ name = "variant_benchmark", >+ srcs = [ >+ "variant_benchmark.cc", >+ ], >+ copts = ABSL_TEST_COPTS, >+ tags = ["benchmark"], >+ deps = [ >+ ":variant", >+ "//absl/utility", >+ "@com_github_google_benchmark//:benchmark_main", >+ ], >+) >+ >+cc_test( >+ name = "variant_exception_safety_test", >+ size = "small", >+ srcs = [ >+ "variant_exception_safety_test.cc", >+ ], >+ copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, >+ deps = [ >+ ":variant", >+ "//absl/base:exception_safety_testing", >+ "//absl/memory", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.gn >new file mode 100644 >index 00000000000..fd7e89dee34 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/BUILD.gn >@@ -0,0 +1,172 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("any") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "any.h", >+ ] >+ deps = [ >+ ":bad_any_cast", >+ "../base:config", >+ "../base:core_headers", >+ "../meta:type_traits", >+ "../utility", >+ ] >+} >+ >+source_set("bad_any_cast") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "bad_any_cast.h", >+ ] >+ deps = [ >+ ":bad_any_cast_impl", >+ "../base:config", >+ ] >+} >+ >+source_set("bad_any_cast_impl") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "bad_any_cast.cc", >+ ] >+ public = [ >+ "bad_any_cast.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:config", >+ ] >+ visibility = [] >+ visibility += [ ":*" ] >+} >+ >+source_set("span") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "span.h", >+ ] >+ deps = [ >+ "../algorithm", >+ "../base:core_headers", >+ "../base:throw_delegate", >+ "../meta:type_traits", >+ ] >+} >+ >+source_set("optional") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "optional.cc", >+ ] >+ public = [ >+ "optional.h", >+ ] >+ deps = [ >+ ":bad_optional_access", >+ "../base:config", >+ "../memory", >+ "../meta:type_traits", >+ "../utility", >+ ] >+} >+ >+source_set("bad_optional_access") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "bad_optional_access.cc", >+ ] >+ public = [ >+ "bad_optional_access.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:config", >+ ] >+} >+ >+source_set("bad_variant_access") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "bad_variant_access.cc", >+ ] >+ public = [ >+ "bad_variant_access.h", >+ ] >+ deps = [ >+ "../base", >+ "../base:config", >+ ] >+} >+ >+source_set("variant") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ sources = [ >+ "internal/variant.h", >+ ] >+ public = [ >+ "variant.h", >+ ] >+ deps = [ >+ ":bad_variant_access", >+ "../base:base_internal", >+ "../base:config", >+ "../base:core_headers", >+ "../meta:type_traits", >+ "../utility", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/CMakeLists.txt >new file mode 100644 >index 00000000000..2f2e3a77808 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/CMakeLists.txt >@@ -0,0 +1,228 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+list(APPEND TYPES_PUBLIC_HEADERS >+ "any.h" >+ "bad_any_cast.h" >+ "bad_optional_access.h" >+ "optional.h" >+ "span.h" >+ "variant.h" >+) >+ >+ >+# any library >+absl_header_library( >+ TARGET >+ absl_any >+ PUBLIC_LIBRARIES >+ absl::bad_any_cast >+ absl::base >+ absl::meta >+ absl::utility >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+ EXPORT_NAME >+ any >+) >+ >+# span library >+absl_header_library( >+ TARGET >+ absl_span >+ PUBLIC_LIBRARIES >+ absl::utility >+ EXPORT_NAME >+ span >+) >+ >+ >+# bad_any_cast library >+list(APPEND BAD_ANY_CAST_SRC >+ "bad_any_cast.cc" >+ ${TYPES_PUBLIC_HEADERS} >+) >+ >+absl_library( >+ TARGET >+ absl_bad_any_cast >+ SOURCES >+ ${BAD_ANY_CAST_SRC} >+ PUBLIC_LIBRARIES >+ EXPORT_NAME >+ bad_any_cast >+) >+ >+ >+# optional library >+list(APPEND OPTIONAL_SRC >+ "optional.cc" >+) >+ >+absl_library( >+ TARGET >+ absl_optional >+ SOURCES >+ ${OPTIONAL_SRC} >+ PUBLIC_LIBRARIES >+ absl::bad_optional_access >+ absl::base >+ absl::memory >+ absl::meta >+ absl::utility >+ EXPORT_NAME >+ optional >+) >+ >+ >+set(BAD_OPTIONAL_ACCESS_SRC "bad_optional_access.cc") >+set(BAD_OPTIONAL_ACCESS_LIBRARIES absl::base) >+ >+absl_library( >+ TARGET >+ absl_bad_optional_access >+ SOURCES >+ ${BAD_OPTIONAL_ACCESS_SRC} >+ PUBLIC_LIBRARIES >+ ${BAD_OPTIONAL_ACCESS_PUBLIC_LIBRARIES} >+ EXPORT_NAME >+ bad_optional_access >+) >+ >+# variant library >+absl_library( >+ TARGET >+ absl_variant >+ SOURCES >+ "bad_variant_access.h" "bad_variant_access.cc" "variant.h" "internal/variant.h" >+ PUBLIC_LIBRARIES >+ absl::base absl::meta absl::utility >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+ EXPORT_NAME >+ variant >+) >+ >+# >+## TESTS >+# >+ >+ >+# test any_test >+set(ANY_TEST_SRC "any_test.cc") >+set(ANY_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::any absl::bad_any_cast test_instance_tracker_lib) >+ >+absl_test( >+ TARGET >+ any_test >+ SOURCES >+ ${ANY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ANY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+# test any_test_noexceptions >+absl_test( >+ TARGET >+ any_test_noexceptions >+ SOURCES >+ ${ANY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ANY_TEST_PUBLIC_LIBRARIES} >+) >+ >+# test any_exception_safety_test >+set(ANY_EXCEPTION_SAFETY_TEST_SRC "any_exception_safety_test.cc") >+set(ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES >+ absl::any >+ absl::base >+ absl_base_internal_exception_safety_testing >+) >+ >+absl_test( >+ TARGET >+ any_exception_safety_test >+ SOURCES >+ ${ANY_EXCEPTION_SAFETY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${ANY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+# test span_test >+set(SPAN_TEST_SRC "span_test.cc") >+set(SPAN_TEST_PUBLIC_LIBRARIES absl::base absl::strings absl::throw_delegate absl::span test_instance_tracker_lib) >+ >+absl_test( >+ TARGET >+ span_test >+ SOURCES >+ ${SPAN_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${SPAN_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >+ >+ >+# test span_test_noexceptions >+absl_test( >+ TARGET >+ span_test_noexceptions >+ SOURCES >+ ${SPAN_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${SPAN_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+ >+# test optional_test >+set(OPTIONAL_TEST_SRC "optional_test.cc") >+set(OPTIONAL_TEST_PUBLIC_LIBRARIES absl::base absl::throw_delegate absl::optional absl_bad_optional_access) >+ >+absl_test( >+ TARGET >+ optional_test >+ SOURCES >+ ${OPTIONAL_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${OPTIONAL_TEST_PUBLIC_LIBRARIES} >+) >+ >+ >+# test optional_exception_safety_test >+set(OPTIONAL_EXCEPTION_SAFETY_TEST_SRC "optional_exception_safety_test.cc") >+set(OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES >+ absl::optional >+ absl_base_internal_exception_safety_testing >+) >+ >+absl_test( >+ TARGET >+ optional_exception_safety_test >+ SOURCES >+ ${OPTIONAL_EXCEPTION_SAFETY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${OPTIONAL_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} >+ PRIVATE_COMPILE_FLAGS >+ ${ABSL_EXCEPTIONS_FLAG} >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any.h >new file mode 100644 >index 00000000000..a973c6dab7e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any.h >@@ -0,0 +1,539 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// any.h >+// ----------------------------------------------------------------------------- >+// >+// This header file define the `absl::any` type for holding a type-safe value >+// of any type. The 'absl::any` type is useful for providing a way to hold >+// something that is, as yet, unspecified. Such unspecified types >+// traditionally are passed between API boundaries until they are later cast to >+// their "destination" types. To cast to such a destination type, use >+// `absl::any_cast()`. Note that when casting an `absl::any`, you must cast it >+// to an explicit type; implicit conversions will throw. >+// >+// Example: >+// >+// auto a = absl::any(65); >+// absl::any_cast<int>(a); // 65 >+// absl::any_cast<char>(a); // throws absl::bad_any_cast >+// absl::any_cast<std::string>(a); // throws absl::bad_any_cast >+// >+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction >+// and is designed to be a drop-in replacement for code compliant with C++17. >+// >+// Traditionally, the behavior of casting to a temporary unspecified type has >+// been accomplished with the `void *` paradigm, where the pointer was to some >+// other unspecified type. `absl::any` provides an "owning" version of `void *` >+// that avoids issues of pointer management. >+// >+// Note: just as in the case of `void *`, use of `absl::any` (and its C++17 >+// version `std::any`) is a code smell indicating that your API might not be >+// constructed correctly. We have seen that most uses of `any` are unwarranted, >+// and `absl::any`, like `std::any`, is difficult to use properly. Before using >+// this abstraction, make sure that you should not instead be rewriting your >+// code to be more specific. >+// >+// Abseil expects to release an `absl::variant` type shortly (a C++11 compatible >+// version of the C++17 `std::variant), which is generally preferred for use >+// over `absl::any`. >+#ifndef ABSL_TYPES_ANY_H_ >+#define ABSL_TYPES_ANY_H_ >+ >+#include "absl/base/config.h" >+#include "absl/utility/utility.h" >+ >+#ifdef ABSL_HAVE_STD_ANY >+ >+#include <any> >+ >+namespace absl { >+using std::any; >+using std::any_cast; >+using std::bad_any_cast; >+using std::make_any; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_ANY >+ >+#include <algorithm> >+#include <cstddef> >+#include <initializer_list> >+#include <memory> >+#include <stdexcept> >+#include <type_traits> >+#include <typeinfo> >+#include <utility> >+ >+#include "absl/base/macros.h" >+#include "absl/meta/type_traits.h" >+#include "absl/types/bad_any_cast.h" >+ >+// NOTE: This macro is an implementation detail that is undefined at the bottom >+// of the file. It is not intended for expansion directly from user code. >+#ifdef ABSL_ANY_DETAIL_HAS_RTTI >+#error ABSL_ANY_DETAIL_HAS_RTTI cannot be directly set >+#elif !defined(__GNUC__) || defined(__GXX_RTTI) >+#define ABSL_ANY_DETAIL_HAS_RTTI 1 >+#endif // !defined(__GNUC__) || defined(__GXX_RTTI) >+ >+namespace absl { >+ >+namespace any_internal { >+ >+template <typename Type> >+struct TypeTag { >+ constexpr static char dummy_var = 0; >+}; >+ >+template <typename Type> >+constexpr char TypeTag<Type>::dummy_var; >+ >+// FastTypeId<Type>() evaluates at compile/link-time to a unique pointer for the >+// passed in type. These are meant to be good match for keys into maps or >+// straight up comparisons. >+template<typename Type> >+constexpr inline const void* FastTypeId() { >+ return &TypeTag<Type>::dummy_var; >+} >+ >+} // namespace any_internal >+ >+class any; >+ >+// swap() >+// >+// Swaps two `absl::any` values. Equivalent to `x.swap(y) where `x` and `y` are >+// `absl::any` types. >+void swap(any& x, any& y) noexcept; >+ >+// make_any() >+// >+// Constructs an `absl::any` of type `T` with the given arguments. >+template <typename T, typename... Args> >+any make_any(Args&&... args); >+ >+// Overload of `absl::make_any()` for constructing an `absl::any` type from an >+// initializer list. >+template <typename T, typename U, typename... Args> >+any make_any(std::initializer_list<U> il, Args&&... args); >+ >+// any_cast() >+// >+// Statically casts the value of a `const absl::any` type to the given type. >+// This function will throw `absl::bad_any_cast` if the stored value type of the >+// `absl::any` does not match the cast. >+// >+// `any_cast()` can also be used to get a reference to the internal storage iff >+// a reference type is passed as its `ValueType`: >+// >+// Example: >+// >+// absl::any my_any = std::vector<int>(); >+// absl::any_cast<std::vector<int>&>(my_any).push_back(42); >+template <typename ValueType> >+ValueType any_cast(const any& operand); >+ >+// Overload of `any_cast()` to statically cast the value of a non-const >+// `absl::any` type to the given type. This function will throw >+// `absl::bad_any_cast` if the stored value type of the `absl::any` does not >+// match the cast. >+template <typename ValueType> >+ValueType any_cast(any& operand); // NOLINT(runtime/references) >+ >+// Overload of `any_cast()` to statically cast the rvalue of an `absl::any` >+// type. This function will throw `absl::bad_any_cast` if the stored value type >+// of the `absl::any` does not match the cast. >+template <typename ValueType> >+ValueType any_cast(any&& operand); >+ >+// Overload of `any_cast()` to statically cast the value of a const pointer >+// `absl::any` type to the given pointer type, or `nullptr` if the stored value >+// type of the `absl::any` does not match the cast. >+template <typename ValueType> >+const ValueType* any_cast(const any* operand) noexcept; >+ >+// Overload of `any_cast()` to statically cast the value of a pointer >+// `absl::any` type to the given pointer type, or `nullptr` if the stored value >+// type of the `absl::any` does not match the cast. >+template <typename ValueType> >+ValueType* any_cast(any* operand) noexcept; >+ >+// ----------------------------------------------------------------------------- >+// absl::any >+// ----------------------------------------------------------------------------- >+// >+// An `absl::any` object provides the facility to either store an instance of a >+// type, known as the "contained object", or no value. An `absl::any` is used to >+// store values of types that are unknown at compile time. The `absl::any` >+// object, when containing a value, must contain a value type; storing a >+// reference type is neither desired nor supported. >+// >+// An `absl::any` can only store a type that is copy-constructable; move-only >+// types are not allowed within an `any` object. >+// >+// Example: >+// >+// auto a = absl::any(65); // Literal, copyable >+// auto b = absl::any(std::vector<int>()); // Default-initialized, copyable >+// std::unique_ptr<Foo> my_foo; >+// auto c = absl::any(std::move(my_foo)); // Error, not copy-constructable >+// >+// Note that `absl::any` makes use of decayed types (`absl::decay_t` in this >+// context) to remove const-volatile qualifiers (known as "cv qualifiers"), >+// decay functions to function pointers, etc. We essentially "decay" a given >+// type into its essential type. >+// >+// `absl::any` makes use of decayed types when determining the basic type `T` of >+// the value to store in the any's contained object. In the documentation below, >+// we explicitly denote this by using the phrase "a decayed type of `T`". >+// >+// Example: >+// >+// const int a = 4; >+// absl::any foo(a); // Decay ensures we store an "int", not a "const int&". >+// >+// void my_function() {} >+// absl::any bar(my_function); // Decay ensures we store a function pointer. >+// >+// `absl::any` is a C++11 compatible version of the C++17 `std::any` abstraction >+// and is designed to be a drop-in replacement for code compliant with C++17. >+class any { >+ private: >+ template <typename T> >+ struct IsInPlaceType; >+ >+ public: >+ // Constructors >+ >+ // Constructs an empty `absl::any` object (`any::has_value()` will return >+ // `false`). >+ constexpr any() noexcept; >+ >+ // Copy constructs an `absl::any` object with a "contained object" of the >+ // passed type of `other` (or an empty `absl::any` if `other.has_value()` is >+ // `false`. >+ any(const any& other) >+ : obj_(other.has_value() ? other.obj_->Clone() >+ : std::unique_ptr<ObjInterface>()) {} >+ >+ // Move constructs an `absl::any` object with a "contained object" of the >+ // passed type of `other` (or an empty `absl::any` if `other.has_value()` is >+ // `false`). >+ any(any&& other) noexcept = default; >+ >+ // Constructs an `absl::any` object with a "contained object" of the decayed >+ // type of `T`, which is initialized via `std::forward<T>(value)`. >+ // >+ // This constructor will not participate in overload resolution if the >+ // decayed type of `T` is not copy-constructible. >+ template < >+ typename T, typename VT = absl::decay_t<T>, >+ absl::enable_if_t<!absl::disjunction< >+ std::is_same<any, VT>, IsInPlaceType<VT>, >+ absl::negation<std::is_copy_constructible<VT> > >::value>* = nullptr> >+ any(T&& value) : obj_(new Obj<VT>(in_place, std::forward<T>(value))) {} >+ >+ // Constructs an `absl::any` object with a "contained object" of the decayed >+ // type of `T`, which is initialized via `std::forward<T>(value)`. >+ template <typename T, typename... Args, typename VT = absl::decay_t<T>, >+ absl::enable_if_t<absl::conjunction< >+ std::is_copy_constructible<VT>, >+ std::is_constructible<VT, Args...>>::value>* = nullptr> >+ explicit any(in_place_type_t<T> /*tag*/, Args&&... args) >+ : obj_(new Obj<VT>(in_place, std::forward<Args>(args)...)) {} >+ >+ // Constructs an `absl::any` object with a "contained object" of the passed >+ // type `VT` as a decayed type of `T`. `VT` is initialized as if >+ // direct-non-list-initializing an object of type `VT` with the arguments >+ // `initializer_list, std::forward<Args>(args)...`. >+ template < >+ typename T, typename U, typename... Args, typename VT = absl::decay_t<T>, >+ absl::enable_if_t< >+ absl::conjunction<std::is_copy_constructible<VT>, >+ std::is_constructible<VT, std::initializer_list<U>&, >+ Args...>>::value>* = nullptr> >+ explicit any(in_place_type_t<T> /*tag*/, std::initializer_list<U> ilist, >+ Args&&... args) >+ : obj_(new Obj<VT>(in_place, ilist, std::forward<Args>(args)...)) {} >+ >+ // Assignment operators >+ >+ // Copy assigns an `absl::any` object with a "contained object" of the >+ // passed type. >+ any& operator=(const any& rhs) { >+ any(rhs).swap(*this); >+ return *this; >+ } >+ >+ // Move assigns an `absl::any` object with a "contained object" of the >+ // passed type. `rhs` is left in a valid but otherwise unspecified state. >+ any& operator=(any&& rhs) noexcept { >+ any(std::move(rhs)).swap(*this); >+ return *this; >+ } >+ >+ // Assigns an `absl::any` object with a "contained object" of the passed type. >+ template <typename T, typename VT = absl::decay_t<T>, >+ absl::enable_if_t<absl::conjunction< >+ absl::negation<std::is_same<VT, any>>, >+ std::is_copy_constructible<VT>>::value>* = nullptr> >+ any& operator=(T&& rhs) { >+ any tmp(in_place_type_t<VT>(), std::forward<T>(rhs)); >+ tmp.swap(*this); >+ return *this; >+ } >+ >+ // Modifiers >+ >+ // any::emplace() >+ // >+ // Emplaces a value within an `absl::any` object by calling `any::reset()`, >+ // initializing the contained value as if direct-non-list-initializing an >+ // object of type `VT` with the arguments `std::forward<Args>(args)...`, and >+ // returning a reference to the new contained value. >+ // >+ // Note: If an exception is thrown during the call to `VT`'s constructor, >+ // `*this` does not contain a value, and any previously contained value has >+ // been destroyed. >+ template < >+ typename T, typename... Args, typename VT = absl::decay_t<T>, >+ absl::enable_if_t<std::is_copy_constructible<VT>::value && >+ std::is_constructible<VT, Args...>::value>* = nullptr> >+ VT& emplace(Args&&... args) { >+ reset(); // NOTE: reset() is required here even in the world of exceptions. >+ Obj<VT>* const object_ptr = >+ new Obj<VT>(in_place, std::forward<Args>(args)...); >+ obj_ = std::unique_ptr<ObjInterface>(object_ptr); >+ return object_ptr->value; >+ } >+ >+ // Overload of `any::emplace()` to emplace a value within an `absl::any` >+ // object by calling `any::reset()`, initializing the contained value as if >+ // direct-non-list-initializing an object of type `VT` with the arguments >+ // `initializer_list, std::forward<Args>(args)...`, and returning a reference >+ // to the new contained value. >+ // >+ // Note: If an exception is thrown during the call to `VT`'s constructor, >+ // `*this` does not contain a value, and any previously contained value has >+ // been destroyed. The function shall not participate in overload resolution >+ // unless `is_copy_constructible_v<VT>` is `true` and >+ // `is_constructible_v<VT, initializer_list<U>&, Args...>` is `true`. >+ template < >+ typename T, typename U, typename... Args, typename VT = absl::decay_t<T>, >+ absl::enable_if_t<std::is_copy_constructible<VT>::value && >+ std::is_constructible<VT, std::initializer_list<U>&, >+ Args...>::value>* = nullptr> >+ VT& emplace(std::initializer_list<U> ilist, Args&&... args) { >+ reset(); // NOTE: reset() is required here even in the world of exceptions. >+ Obj<VT>* const object_ptr = >+ new Obj<VT>(in_place, ilist, std::forward<Args>(args)...); >+ obj_ = std::unique_ptr<ObjInterface>(object_ptr); >+ return object_ptr->value; >+ } >+ >+ // any::reset() >+ // >+ // Resets the state of the `absl::any` object, destroying the contained object >+ // if present. >+ void reset() noexcept { obj_ = nullptr; } >+ >+ // any::swap() >+ // >+ // Swaps the passed value and the value of this `absl::any` object. >+ void swap(any& other) noexcept { obj_.swap(other.obj_); } >+ >+ // Observers >+ >+ // any::has_value() >+ // >+ // Returns `true` if the `any` object has a contained value, otherwise >+ // returns `false`. >+ bool has_value() const noexcept { return obj_ != nullptr; } >+ >+#if ABSL_ANY_DETAIL_HAS_RTTI >+ // Returns: typeid(T) if *this has a contained object of type T, otherwise >+ // typeid(void). >+ const std::type_info& type() const noexcept { >+ if (has_value()) { >+ return obj_->Type(); >+ } >+ >+ return typeid(void); >+ } >+#endif // ABSL_ANY_DETAIL_HAS_RTTI >+ >+ private: >+ // Tagged type-erased abstraction for holding a cloneable object. >+ class ObjInterface { >+ public: >+ virtual ~ObjInterface() = default; >+ virtual std::unique_ptr<ObjInterface> Clone() const = 0; >+ virtual const void* ObjTypeId() const noexcept = 0; >+#if ABSL_ANY_DETAIL_HAS_RTTI >+ virtual const std::type_info& Type() const noexcept = 0; >+#endif // ABSL_ANY_DETAIL_HAS_RTTI >+ }; >+ >+ // Hold a value of some queryable type, with an ability to Clone it. >+ template <typename T> >+ class Obj : public ObjInterface { >+ public: >+ template <typename... Args> >+ explicit Obj(in_place_t /*tag*/, Args&&... args) >+ : value(std::forward<Args>(args)...) {} >+ >+ std::unique_ptr<ObjInterface> Clone() const final { >+ return std::unique_ptr<ObjInterface>(new Obj(in_place, value)); >+ } >+ >+ const void* ObjTypeId() const noexcept final { return IdForType<T>(); } >+ >+#if ABSL_ANY_DETAIL_HAS_RTTI >+ const std::type_info& Type() const noexcept final { return typeid(T); } >+#endif // ABSL_ANY_DETAIL_HAS_RTTI >+ >+ T value; >+ }; >+ >+ std::unique_ptr<ObjInterface> CloneObj() const { >+ if (!obj_) return nullptr; >+ return obj_->Clone(); >+ } >+ >+ template <typename T> >+ constexpr static const void* IdForType() { >+ // Note: This type dance is to make the behavior consistent with typeid. >+ using NormalizedType = >+ typename std::remove_cv<typename std::remove_reference<T>::type>::type; >+ >+ return any_internal::FastTypeId<NormalizedType>(); >+ } >+ >+ const void* GetObjTypeId() const { >+ return obj_ ? obj_->ObjTypeId() : any_internal::FastTypeId<void>(); >+ } >+ >+ // `absl::any` nonmember functions // >+ >+ // Description at the declaration site (top of file). >+ template <typename ValueType> >+ friend ValueType any_cast(const any& operand); >+ >+ // Description at the declaration site (top of file). >+ template <typename ValueType> >+ friend ValueType any_cast(any& operand); // NOLINT(runtime/references) >+ >+ // Description at the declaration site (top of file). >+ template <typename T> >+ friend const T* any_cast(const any* operand) noexcept; >+ >+ // Description at the declaration site (top of file). >+ template <typename T> >+ friend T* any_cast(any* operand) noexcept; >+ >+ std::unique_ptr<ObjInterface> obj_; >+}; >+ >+// ----------------------------------------------------------------------------- >+// Implementation Details >+// ----------------------------------------------------------------------------- >+ >+constexpr any::any() noexcept = default; >+ >+template <typename T> >+struct any::IsInPlaceType : std::false_type {}; >+ >+template <typename T> >+struct any::IsInPlaceType<in_place_type_t<T>> : std::true_type {}; >+ >+inline void swap(any& x, any& y) noexcept { x.swap(y); } >+ >+// Description at the declaration site (top of file). >+template <typename T, typename... Args> >+any make_any(Args&&... args) { >+ return any(in_place_type_t<T>(), std::forward<Args>(args)...); >+} >+ >+// Description at the declaration site (top of file). >+template <typename T, typename U, typename... Args> >+any make_any(std::initializer_list<U> il, Args&&... args) { >+ return any(in_place_type_t<T>(), il, std::forward<Args>(args)...); >+} >+ >+// Description at the declaration site (top of file). >+template <typename ValueType> >+ValueType any_cast(const any& operand) { >+ using U = typename std::remove_cv< >+ typename std::remove_reference<ValueType>::type>::type; >+ static_assert(std::is_constructible<ValueType, const U&>::value, >+ "Invalid ValueType"); >+ auto* const result = (any_cast<U>)(&operand); >+ if (result == nullptr) { >+ any_internal::ThrowBadAnyCast(); >+ } >+ return static_cast<ValueType>(*result); >+} >+ >+// Description at the declaration site (top of file). >+template <typename ValueType> >+ValueType any_cast(any& operand) { // NOLINT(runtime/references) >+ using U = typename std::remove_cv< >+ typename std::remove_reference<ValueType>::type>::type; >+ static_assert(std::is_constructible<ValueType, U&>::value, >+ "Invalid ValueType"); >+ auto* result = (any_cast<U>)(&operand); >+ if (result == nullptr) { >+ any_internal::ThrowBadAnyCast(); >+ } >+ return static_cast<ValueType>(*result); >+} >+ >+// Description at the declaration site (top of file). >+template <typename ValueType> >+ValueType any_cast(any&& operand) { >+ using U = typename std::remove_cv< >+ typename std::remove_reference<ValueType>::type>::type; >+ static_assert(std::is_constructible<ValueType, U>::value, >+ "Invalid ValueType"); >+ return static_cast<ValueType>(std::move((any_cast<U&>)(operand))); >+} >+ >+// Description at the declaration site (top of file). >+template <typename T> >+const T* any_cast(const any* operand) noexcept { >+ return operand && operand->GetObjTypeId() == any::IdForType<T>() >+ ? std::addressof( >+ static_cast<const any::Obj<T>*>(operand->obj_.get())->value) >+ : nullptr; >+} >+ >+// Description at the declaration site (top of file). >+template <typename T> >+T* any_cast(any* operand) noexcept { >+ return operand && operand->GetObjTypeId() == any::IdForType<T>() >+ ? std::addressof( >+ static_cast<any::Obj<T>*>(operand->obj_.get())->value) >+ : nullptr; >+} >+ >+} // namespace absl >+ >+#undef ABSL_ANY_DETAIL_HAS_RTTI >+ >+#endif // ABSL_HAVE_STD_ANY >+ >+#endif // ABSL_TYPES_ANY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc >new file mode 100644 >index 00000000000..36955f6c5c3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_exception_safety_test.cc >@@ -0,0 +1,167 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/any.h" >+ >+#include <typeinfo> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_safety_testing.h" >+ >+using Thrower = testing::ThrowingValue<>; >+using NoThrowMoveThrower = >+ testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; >+using ThrowerList = std::initializer_list<Thrower>; >+using ThrowerVec = std::vector<Thrower>; >+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>; >+using ThrowingThrowerVec = std::vector<Thrower, ThrowingAlloc>; >+ >+namespace { >+ >+testing::AssertionResult AnyInvariants(absl::any* a) { >+ using testing::AssertionFailure; >+ using testing::AssertionSuccess; >+ >+ if (a->has_value()) { >+ if (a->type() == typeid(void)) { >+ return AssertionFailure() >+ << "A non-empty any should not have type `void`"; >+ } >+ } else { >+ if (a->type() != typeid(void)) { >+ return AssertionFailure() >+ << "An empty any should have type void, but has type " >+ << a->type().name(); >+ } >+ } >+ >+ // Make sure that reset() changes any to a valid state. >+ a->reset(); >+ if (a->has_value()) { >+ return AssertionFailure() << "A reset `any` should be valueless"; >+ } >+ if (a->type() != typeid(void)) { >+ return AssertionFailure() << "A reset `any` should have type() of `void`, " >+ "but instead has type " >+ << a->type().name(); >+ } >+ try { >+ auto unused = absl::any_cast<Thrower>(*a); >+ static_cast<void>(unused); >+ return AssertionFailure() >+ << "A reset `any` should not be able to be any_cast"; >+ } catch (absl::bad_any_cast) { >+ } catch (...) { >+ return AssertionFailure() >+ << "Unexpected exception thrown from absl::any_cast"; >+ } >+ return AssertionSuccess(); >+} >+ >+testing::AssertionResult AnyIsEmpty(absl::any* a) { >+ if (!a->has_value()) { >+ return testing::AssertionSuccess(); >+ } >+ return testing::AssertionFailure() >+ << "a should be empty, but instead has value " >+ << absl::any_cast<Thrower>(*a).Get(); >+} >+ >+TEST(AnyExceptionSafety, Ctors) { >+ Thrower val(1); >+ testing::TestThrowingCtor<absl::any>(val); >+ >+ Thrower copy(val); >+ testing::TestThrowingCtor<absl::any>(copy); >+ >+ testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<Thrower>(), 1); >+ >+ testing::TestThrowingCtor<absl::any>(absl::in_place_type_t<ThrowerVec>(), >+ ThrowerList{val}); >+ >+ testing::TestThrowingCtor<absl::any, >+ absl::in_place_type_t<ThrowingThrowerVec>, >+ ThrowerList, ThrowingAlloc>( >+ absl::in_place_type_t<ThrowingThrowerVec>(), {val}, ThrowingAlloc()); >+} >+ >+TEST(AnyExceptionSafety, Assignment) { >+ auto original = >+ absl::any(absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor); >+ auto any_is_strong = [original](absl::any* ap) { >+ return testing::AssertionResult(ap->has_value() && >+ absl::any_cast<Thrower>(original) == >+ absl::any_cast<Thrower>(*ap)); >+ }; >+ auto any_strong_tester = testing::MakeExceptionSafetyTester() >+ .WithInitialValue(original) >+ .WithInvariants(AnyInvariants, any_is_strong); >+ >+ Thrower val(2); >+ absl::any any_val(val); >+ NoThrowMoveThrower mv_val(2); >+ >+ auto assign_any = [&any_val](absl::any* ap) { *ap = any_val; }; >+ auto assign_val = [&val](absl::any* ap) { *ap = val; }; >+ auto move = [&val](absl::any* ap) { *ap = std::move(val); }; >+ auto move_movable = [&mv_val](absl::any* ap) { *ap = std::move(mv_val); }; >+ >+ EXPECT_TRUE(any_strong_tester.Test(assign_any)); >+ EXPECT_TRUE(any_strong_tester.Test(assign_val)); >+ EXPECT_TRUE(any_strong_tester.Test(move)); >+ EXPECT_TRUE(any_strong_tester.Test(move_movable)); >+ >+ auto empty_any_is_strong = [](absl::any* ap) { >+ return testing::AssertionResult{!ap->has_value()}; >+ }; >+ auto strong_empty_any_tester = >+ testing::MakeExceptionSafetyTester() >+ .WithInitialValue(absl::any{}) >+ .WithInvariants(AnyInvariants, empty_any_is_strong); >+ >+ EXPECT_TRUE(strong_empty_any_tester.Test(assign_any)); >+ EXPECT_TRUE(strong_empty_any_tester.Test(assign_val)); >+ EXPECT_TRUE(strong_empty_any_tester.Test(move)); >+} >+// libstdc++ std::any fails this test >+#if !defined(ABSL_HAVE_STD_ANY) >+TEST(AnyExceptionSafety, Emplace) { >+ auto initial_val = >+ absl::any{absl::in_place_type_t<Thrower>(), 1, testing::nothrow_ctor}; >+ auto one_tester = testing::MakeExceptionSafetyTester() >+ .WithInitialValue(initial_val) >+ .WithInvariants(AnyInvariants, AnyIsEmpty); >+ >+ auto emp_thrower = [](absl::any* ap) { ap->emplace<Thrower>(2); }; >+ auto emp_throwervec = [](absl::any* ap) { >+ std::initializer_list<Thrower> il{Thrower(2, testing::nothrow_ctor)}; >+ ap->emplace<ThrowerVec>(il); >+ }; >+ auto emp_movethrower = [](absl::any* ap) { >+ ap->emplace<NoThrowMoveThrower>(2); >+ }; >+ >+ EXPECT_TRUE(one_tester.Test(emp_thrower)); >+ EXPECT_TRUE(one_tester.Test(emp_throwervec)); >+ EXPECT_TRUE(one_tester.Test(emp_movethrower)); >+ >+ auto empty_tester = one_tester.WithInitialValue(absl::any{}); >+ >+ EXPECT_TRUE(empty_tester.Test(emp_thrower)); >+ EXPECT_TRUE(empty_tester.Test(emp_throwervec)); >+} >+#endif // ABSL_HAVE_STD_ANY >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_test.cc >new file mode 100644 >index 00000000000..115e78df7af >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/any_test.cc >@@ -0,0 +1,724 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/any.h" >+ >+#include <initializer_list> >+#include <type_traits> >+#include <utility> >+#include <vector> >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/exception_testing.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/container/internal/test_instance_tracker.h" >+ >+namespace { >+using absl::test_internal::CopyableOnlyInstance; >+using absl::test_internal::InstanceTracker; >+ >+template <typename T> >+const T& AsConst(const T& t) { >+ return t; >+} >+ >+struct MoveOnly { >+ MoveOnly() = default; >+ explicit MoveOnly(int value) : value(value) {} >+ MoveOnly(MoveOnly&&) = default; >+ MoveOnly& operator=(MoveOnly&&) = default; >+ >+ int value = 0; >+}; >+ >+struct CopyOnly { >+ CopyOnly() = default; >+ explicit CopyOnly(int value) : value(value) {} >+ CopyOnly(CopyOnly&&) = delete; >+ CopyOnly& operator=(CopyOnly&&) = delete; >+ CopyOnly(const CopyOnly&) = default; >+ CopyOnly& operator=(const CopyOnly&) = default; >+ >+ int value = 0; >+}; >+ >+struct MoveOnlyWithListConstructor { >+ MoveOnlyWithListConstructor() = default; >+ explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/, >+ int value) >+ : value(value) {} >+ MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default; >+ MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) = >+ default; >+ >+ int value = 0; >+}; >+ >+struct IntMoveOnlyCopyOnly { >+ IntMoveOnlyCopyOnly(int value, MoveOnly /*move_only*/, CopyOnly /*copy_only*/) >+ : value(value) {} >+ >+ int value; >+}; >+ >+struct ListMoveOnlyCopyOnly { >+ ListMoveOnlyCopyOnly(std::initializer_list<int> ilist, MoveOnly /*move_only*/, >+ CopyOnly /*copy_only*/) >+ : values(ilist) {} >+ >+ std::vector<int> values; >+}; >+ >+using FunctionType = void(); >+void FunctionToEmplace() {} >+ >+using ArrayType = int[2]; >+using DecayedArray = absl::decay_t<ArrayType>; >+ >+TEST(AnyTest, Noexcept) { >+ static_assert(std::is_nothrow_default_constructible<absl::any>(), ""); >+ static_assert(std::is_nothrow_move_constructible<absl::any>(), ""); >+ static_assert(std::is_nothrow_move_assignable<absl::any>(), ""); >+ static_assert(noexcept(std::declval<absl::any&>().has_value()), ""); >+ static_assert(noexcept(std::declval<absl::any&>().type()), ""); >+ static_assert(noexcept(absl::any_cast<int>(std::declval<absl::any*>())), ""); >+ static_assert( >+ noexcept(std::declval<absl::any&>().swap(std::declval<absl::any&>())), >+ ""); >+ >+ using std::swap; >+ static_assert( >+ noexcept(swap(std::declval<absl::any&>(), std::declval<absl::any&>())), >+ ""); >+} >+ >+TEST(AnyTest, HasValue) { >+ absl::any o; >+ EXPECT_FALSE(o.has_value()); >+ o.emplace<int>(); >+ EXPECT_TRUE(o.has_value()); >+ o.reset(); >+ EXPECT_FALSE(o.has_value()); >+} >+ >+TEST(AnyTest, Type) { >+ absl::any o; >+ EXPECT_EQ(typeid(void), o.type()); >+ o.emplace<int>(5); >+ EXPECT_EQ(typeid(int), o.type()); >+ o.emplace<float>(5.f); >+ EXPECT_EQ(typeid(float), o.type()); >+ o.reset(); >+ EXPECT_EQ(typeid(void), o.type()); >+} >+ >+TEST(AnyTest, EmptyPointerCast) { >+ // pointer-to-unqualified overload >+ { >+ absl::any o; >+ EXPECT_EQ(nullptr, absl::any_cast<int>(&o)); >+ o.emplace<int>(); >+ EXPECT_NE(nullptr, absl::any_cast<int>(&o)); >+ o.reset(); >+ EXPECT_EQ(nullptr, absl::any_cast<int>(&o)); >+ } >+ >+ // pointer-to-const overload >+ { >+ absl::any o; >+ EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o))); >+ o.emplace<int>(); >+ EXPECT_NE(nullptr, absl::any_cast<int>(&AsConst(o))); >+ o.reset(); >+ EXPECT_EQ(nullptr, absl::any_cast<int>(&AsConst(o))); >+ } >+} >+ >+TEST(AnyTest, InPlaceConstruction) { >+ const CopyOnly copy_only{}; >+ absl::any o(absl::in_place_type_t<IntMoveOnlyCopyOnly>(), 5, MoveOnly(), >+ copy_only); >+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(5, v.value); >+} >+ >+TEST(AnyTest, InPlaceConstructionWithCV) { >+ const CopyOnly copy_only{}; >+ absl::any o(absl::in_place_type_t<const volatile IntMoveOnlyCopyOnly>(), 5, >+ MoveOnly(), copy_only); >+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(5, v.value); >+} >+ >+TEST(AnyTest, InPlaceConstructionWithFunction) { >+ absl::any o(absl::in_place_type_t<FunctionType>(), FunctionToEmplace); >+ FunctionType*& construction_result = absl::any_cast<FunctionType*&>(o); >+ EXPECT_EQ(&FunctionToEmplace, construction_result); >+} >+ >+TEST(AnyTest, InPlaceConstructionWithArray) { >+ ArrayType ar = {5, 42}; >+ absl::any o(absl::in_place_type_t<ArrayType>(), ar); >+ DecayedArray& construction_result = absl::any_cast<DecayedArray&>(o); >+ EXPECT_EQ(&ar[0], construction_result); >+} >+ >+TEST(AnyTest, InPlaceConstructionIlist) { >+ const CopyOnly copy_only{}; >+ absl::any o(absl::in_place_type_t<ListMoveOnlyCopyOnly>(), {1, 2, 3, 4}, >+ MoveOnly(), copy_only); >+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); >+ std::vector<int> expected_values = {1, 2, 3, 4}; >+ EXPECT_EQ(expected_values, v.values); >+} >+ >+TEST(AnyTest, InPlaceConstructionIlistWithCV) { >+ const CopyOnly copy_only{}; >+ absl::any o(absl::in_place_type_t<const volatile ListMoveOnlyCopyOnly>(), >+ {1, 2, 3, 4}, MoveOnly(), copy_only); >+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); >+ std::vector<int> expected_values = {1, 2, 3, 4}; >+ EXPECT_EQ(expected_values, v.values); >+} >+ >+TEST(AnyTest, InPlaceNoArgs) { >+ absl::any o(absl::in_place_type_t<int>{}); >+ EXPECT_EQ(0, absl::any_cast<int&>(o)); >+} >+ >+template <typename Enabler, typename T, typename... Args> >+struct CanEmplaceAnyImpl : std::false_type {}; >+ >+template <typename T, typename... Args> >+struct CanEmplaceAnyImpl< >+ absl::void_t<decltype( >+ std::declval<absl::any&>().emplace<T>(std::declval<Args>()...))>, >+ T, Args...> : std::true_type {}; >+ >+template <typename T, typename... Args> >+using CanEmplaceAny = CanEmplaceAnyImpl<void, T, Args...>; >+ >+TEST(AnyTest, Emplace) { >+ const CopyOnly copy_only{}; >+ absl::any o; >+ EXPECT_TRUE((std::is_same<decltype(o.emplace<IntMoveOnlyCopyOnly>( >+ 5, MoveOnly(), copy_only)), >+ IntMoveOnlyCopyOnly&>::value)); >+ IntMoveOnlyCopyOnly& emplace_result = >+ o.emplace<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only); >+ EXPECT_EQ(5, emplace_result.value); >+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(5, v.value); >+ EXPECT_EQ(&emplace_result, &v); >+ >+ static_assert(!CanEmplaceAny<int, int, int>::value, ""); >+ static_assert(!CanEmplaceAny<MoveOnly, MoveOnly>::value, ""); >+} >+ >+TEST(AnyTest, EmplaceWithCV) { >+ const CopyOnly copy_only{}; >+ absl::any o; >+ EXPECT_TRUE( >+ (std::is_same<decltype(o.emplace<const volatile IntMoveOnlyCopyOnly>( >+ 5, MoveOnly(), copy_only)), >+ IntMoveOnlyCopyOnly&>::value)); >+ IntMoveOnlyCopyOnly& emplace_result = >+ o.emplace<const volatile IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only); >+ EXPECT_EQ(5, emplace_result.value); >+ IntMoveOnlyCopyOnly& v = absl::any_cast<IntMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(5, v.value); >+ EXPECT_EQ(&emplace_result, &v); >+} >+ >+TEST(AnyTest, EmplaceWithFunction) { >+ absl::any o; >+ EXPECT_TRUE( >+ (std::is_same<decltype(o.emplace<FunctionType>(FunctionToEmplace)), >+ FunctionType*&>::value)); >+ FunctionType*& emplace_result = o.emplace<FunctionType>(FunctionToEmplace); >+ EXPECT_EQ(&FunctionToEmplace, emplace_result); >+} >+ >+TEST(AnyTest, EmplaceWithArray) { >+ absl::any o; >+ ArrayType ar = {5, 42}; >+ EXPECT_TRUE( >+ (std::is_same<decltype(o.emplace<ArrayType>(ar)), DecayedArray&>::value)); >+ DecayedArray& emplace_result = o.emplace<ArrayType>(ar); >+ EXPECT_EQ(&ar[0], emplace_result); >+} >+ >+TEST(AnyTest, EmplaceIlist) { >+ const CopyOnly copy_only{}; >+ absl::any o; >+ EXPECT_TRUE((std::is_same<decltype(o.emplace<ListMoveOnlyCopyOnly>( >+ {1, 2, 3, 4}, MoveOnly(), copy_only)), >+ ListMoveOnlyCopyOnly&>::value)); >+ ListMoveOnlyCopyOnly& emplace_result = >+ o.emplace<ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), copy_only); >+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(&v, &emplace_result); >+ std::vector<int> expected_values = {1, 2, 3, 4}; >+ EXPECT_EQ(expected_values, v.values); >+ >+ static_assert(!CanEmplaceAny<int, std::initializer_list<int>>::value, ""); >+ static_assert(!CanEmplaceAny<MoveOnlyWithListConstructor, >+ std::initializer_list<int>, int>::value, >+ ""); >+} >+ >+TEST(AnyTest, EmplaceIlistWithCV) { >+ const CopyOnly copy_only{}; >+ absl::any o; >+ EXPECT_TRUE( >+ (std::is_same<decltype(o.emplace<const volatile ListMoveOnlyCopyOnly>( >+ {1, 2, 3, 4}, MoveOnly(), copy_only)), >+ ListMoveOnlyCopyOnly&>::value)); >+ ListMoveOnlyCopyOnly& emplace_result = >+ o.emplace<const volatile ListMoveOnlyCopyOnly>({1, 2, 3, 4}, MoveOnly(), >+ copy_only); >+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); >+ EXPECT_EQ(&v, &emplace_result); >+ std::vector<int> expected_values = {1, 2, 3, 4}; >+ EXPECT_EQ(expected_values, v.values); >+} >+ >+TEST(AnyTest, EmplaceNoArgs) { >+ absl::any o; >+ o.emplace<int>(); >+ EXPECT_EQ(0, absl::any_cast<int>(o)); >+} >+ >+TEST(AnyTest, ConversionConstruction) { >+ { >+ absl::any o = 5; >+ EXPECT_EQ(5, absl::any_cast<int>(o)); >+ } >+ >+ { >+ const CopyOnly copy_only(5); >+ absl::any o = copy_only; >+ EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value); >+ } >+ >+ static_assert(!std::is_convertible<MoveOnly, absl::any>::value, ""); >+} >+ >+TEST(AnyTest, ConversionAssignment) { >+ { >+ absl::any o; >+ o = 5; >+ EXPECT_EQ(5, absl::any_cast<int>(o)); >+ } >+ >+ { >+ const CopyOnly copy_only(5); >+ absl::any o; >+ o = copy_only; >+ EXPECT_EQ(5, absl::any_cast<CopyOnly&>(o).value); >+ } >+ >+ static_assert(!std::is_assignable<MoveOnly, absl::any>::value, ""); >+} >+ >+// Suppress MSVC warnings. >+// 4521: multiple copy constructors specified >+// We wrote multiple of them to test that the correct overloads are selected. >+#ifdef _MSC_VER >+#pragma warning( push ) >+#pragma warning( disable : 4521) >+#endif >+ >+// Weird type for testing, only used to make sure we "properly" perfect-forward >+// when being placed into an absl::any (use the l-value constructor if given an >+// l-value rather than use the copy constructor). >+struct WeirdConstructor42 { >+ explicit WeirdConstructor42(int value) : value(value) {} >+ >+ // Copy-constructor >+ WeirdConstructor42(const WeirdConstructor42& other) : value(other.value) {} >+ >+ // L-value "weird" constructor (used when given an l-value) >+ WeirdConstructor42( >+ WeirdConstructor42& /*other*/) // NOLINT(runtime/references) >+ : value(42) {} >+ >+ int value; >+}; >+#ifdef _MSC_VER >+#pragma warning( pop ) >+#endif >+ >+TEST(AnyTest, WeirdConversionConstruction) { >+ { >+ const WeirdConstructor42 source(5); >+ absl::any o = source; // Actual copy >+ EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value); >+ } >+ >+ { >+ WeirdConstructor42 source(5); >+ absl::any o = source; // Weird "conversion" >+ EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value); >+ } >+} >+ >+TEST(AnyTest, WeirdConversionAssignment) { >+ { >+ const WeirdConstructor42 source(5); >+ absl::any o; >+ o = source; // Actual copy >+ EXPECT_EQ(5, absl::any_cast<WeirdConstructor42&>(o).value); >+ } >+ >+ { >+ WeirdConstructor42 source(5); >+ absl::any o; >+ o = source; // Weird "conversion" >+ EXPECT_EQ(42, absl::any_cast<WeirdConstructor42&>(o).value); >+ } >+} >+ >+struct Value {}; >+ >+TEST(AnyTest, AnyCastValue) { >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<int>(o)); >+ EXPECT_EQ(5, absl::any_cast<int>(AsConst(o))); >+ static_assert( >+ std::is_same<decltype(absl::any_cast<Value>(o)), Value>::value, ""); >+ } >+ >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<const int>(o)); >+ EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o))); >+ static_assert(std::is_same<decltype(absl::any_cast<const Value>(o)), >+ const Value>::value, >+ ""); >+ } >+} >+ >+TEST(AnyTest, AnyCastReference) { >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<int&>(o)); >+ EXPECT_EQ(5, absl::any_cast<const int&>(AsConst(o))); >+ static_assert( >+ std::is_same<decltype(absl::any_cast<Value&>(o)), Value&>::value, ""); >+ } >+ >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<const int>(o)); >+ EXPECT_EQ(5, absl::any_cast<const int>(AsConst(o))); >+ static_assert(std::is_same<decltype(absl::any_cast<const Value&>(o)), >+ const Value&>::value, >+ ""); >+ } >+ >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<int&&>(std::move(o))); >+ static_assert(std::is_same<decltype(absl::any_cast<Value&&>(std::move(o))), >+ Value&&>::value, >+ ""); >+ } >+ >+ { >+ absl::any o; >+ o.emplace<int>(5); >+ EXPECT_EQ(5, absl::any_cast<const int>(std::move(o))); >+ static_assert( >+ std::is_same<decltype(absl::any_cast<const Value&&>(std::move(o))), >+ const Value&&>::value, >+ ""); >+ } >+} >+ >+TEST(AnyTest, AnyCastPointer) { >+ { >+ absl::any o; >+ EXPECT_EQ(nullptr, absl::any_cast<char>(&o)); >+ o.emplace<int>(5); >+ EXPECT_EQ(nullptr, absl::any_cast<char>(&o)); >+ o.emplace<char>('a'); >+ EXPECT_EQ('a', *absl::any_cast<char>(&o)); >+ static_assert( >+ std::is_same<decltype(absl::any_cast<Value>(&o)), Value*>::value, ""); >+ } >+ >+ { >+ absl::any o; >+ EXPECT_EQ(nullptr, absl::any_cast<const char>(&o)); >+ o.emplace<int>(5); >+ EXPECT_EQ(nullptr, absl::any_cast<const char>(&o)); >+ o.emplace<char>('a'); >+ EXPECT_EQ('a', *absl::any_cast<const char>(&o)); >+ static_assert(std::is_same<decltype(absl::any_cast<const Value>(&o)), >+ const Value*>::value, >+ ""); >+ } >+} >+ >+TEST(AnyTest, MakeAny) { >+ const CopyOnly copy_only{}; >+ auto o = absl::make_any<IntMoveOnlyCopyOnly>(5, MoveOnly(), copy_only); >+ static_assert(std::is_same<decltype(o), absl::any>::value, ""); >+ EXPECT_EQ(5, absl::any_cast<IntMoveOnlyCopyOnly&>(o).value); >+} >+ >+TEST(AnyTest, MakeAnyIList) { >+ const CopyOnly copy_only{}; >+ auto o = >+ absl::make_any<ListMoveOnlyCopyOnly>({1, 2, 3}, MoveOnly(), copy_only); >+ static_assert(std::is_same<decltype(o), absl::any>::value, ""); >+ ListMoveOnlyCopyOnly& v = absl::any_cast<ListMoveOnlyCopyOnly&>(o); >+ std::vector<int> expected_values = {1, 2, 3}; >+ EXPECT_EQ(expected_values, v.values); >+} >+ >+// Test the use of copy constructor and operator= >+TEST(AnyTest, Copy) { >+ InstanceTracker tracker_raii; >+ >+ { >+ absl::any o(absl::in_place_type_t<CopyableOnlyInstance>{}, 123); >+ CopyableOnlyInstance* f1 = absl::any_cast<CopyableOnlyInstance>(&o); >+ >+ absl::any o2(o); >+ const CopyableOnlyInstance* f2 = absl::any_cast<CopyableOnlyInstance>(&o2); >+ EXPECT_EQ(123, f2->value()); >+ EXPECT_NE(f1, f2); >+ >+ absl::any o3; >+ o3 = o2; >+ const CopyableOnlyInstance* f3 = absl::any_cast<CopyableOnlyInstance>(&o3); >+ EXPECT_EQ(123, f3->value()); >+ EXPECT_NE(f2, f3); >+ >+ const absl::any o4(4); >+ // copy construct from const lvalue ref. >+ absl::any o5 = o4; >+ EXPECT_EQ(4, absl::any_cast<int>(o4)); >+ EXPECT_EQ(4, absl::any_cast<int>(o5)); >+ >+ // Copy construct from const rvalue ref. >+ absl::any o6 = std::move(o4); // NOLINT >+ EXPECT_EQ(4, absl::any_cast<int>(o4)); >+ EXPECT_EQ(4, absl::any_cast<int>(o6)); >+ } >+} >+ >+TEST(AnyTest, Move) { >+ InstanceTracker tracker_raii; >+ >+ absl::any any1; >+ any1.emplace<CopyableOnlyInstance>(5); >+ >+ // This is a copy, so copy count increases to 1. >+ absl::any any2 = any1; >+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any1).value()); >+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any2).value()); >+ EXPECT_EQ(1, tracker_raii.copies()); >+ >+ // This isn't a copy, so copy count doesn't increase. >+ absl::any any3 = std::move(any2); >+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any3).value()); >+ EXPECT_EQ(1, tracker_raii.copies()); >+ >+ absl::any any4; >+ any4 = std::move(any3); >+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(any4).value()); >+ EXPECT_EQ(1, tracker_raii.copies()); >+ >+ absl::any tmp4(4); >+ absl::any o4(std::move(tmp4)); // move construct >+ EXPECT_EQ(4, absl::any_cast<int>(o4)); >+ o4 = *&o4; // self assign >+ EXPECT_EQ(4, absl::any_cast<int>(o4)); >+ EXPECT_TRUE(o4.has_value()); >+ >+ absl::any o5; >+ absl::any tmp5(5); >+ o5 = std::move(tmp5); // move assign >+ EXPECT_EQ(5, absl::any_cast<int>(o5)); >+} >+ >+// Reset the ObjectOwner with an object of a different type >+TEST(AnyTest, Reset) { >+ absl::any o; >+ o.emplace<int>(); >+ >+ o.reset(); >+ EXPECT_FALSE(o.has_value()); >+ >+ o.emplace<char>(); >+ EXPECT_TRUE(o.has_value()); >+} >+ >+TEST(AnyTest, ConversionConstructionCausesOneCopy) { >+ InstanceTracker tracker_raii; >+ CopyableOnlyInstance counter(5); >+ absl::any o(counter); >+ EXPECT_EQ(5, absl::any_cast<CopyableOnlyInstance&>(o).value()); >+ EXPECT_EQ(1, tracker_raii.copies()); >+} >+ >+////////////////////////////////// >+// Tests for Exception Behavior // >+////////////////////////////////// >+ >+#if defined(ABSL_HAVE_STD_ANY) >+ >+// If using a std `any` implementation, we can't check for a specific message. >+#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \ >+ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \ >+ "") >+ >+#else >+ >+// If using the absl `any` implementation, we can rely on a specific message. >+#define ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(...) \ >+ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), absl::bad_any_cast, \ >+ "Bad any cast") >+ >+#endif // defined(ABSL_HAVE_STD_ANY) >+ >+TEST(AnyTest, ThrowBadAlloc) { >+ { >+ absl::any a; >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int&&>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&&>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(absl::any{})); >+ >+ // const absl::any operand >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int&>(AsConst(a))); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<int>(AsConst(a))); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const int>(AsConst(a))); >+ } >+ >+ { >+ absl::any a(absl::in_place_type_t<int>{}); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float&&>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST( >+ absl::any_cast<const float&&>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(a)); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(absl::any{})); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(absl::any{})); >+ >+ // const absl::any operand >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float&>(AsConst(a))); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<float>(AsConst(a))); >+ ABSL_ANY_TEST_EXPECT_BAD_ANY_CAST(absl::any_cast<const float>(AsConst(a))); >+ } >+} >+ >+class BadCopy {}; >+ >+struct BadCopyable { >+ BadCopyable() = default; >+ BadCopyable(BadCopyable&&) = default; >+ BadCopyable(const BadCopyable&) { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw BadCopy(); >+#else >+ ABSL_RAW_LOG(FATAL, "Bad copy"); >+#endif >+ } >+}; >+ >+#define ABSL_ANY_TEST_EXPECT_BAD_COPY(...) \ >+ ABSL_BASE_INTERNAL_EXPECT_FAIL((__VA_ARGS__), BadCopy, "Bad copy") >+ >+// Test the guarantees regarding exceptions in copy/assign. >+TEST(AnyTest, FailedCopy) { >+ { >+ const BadCopyable bad{}; >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{bad}); >+ } >+ >+ { >+ absl::any src(absl::in_place_type_t<BadCopyable>{}); >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(absl::any{src}); >+ } >+ >+ { >+ BadCopyable bad; >+ absl::any target; >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad); >+ } >+ >+ { >+ BadCopyable bad; >+ absl::any target(absl::in_place_type_t<BadCopyable>{}); >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = bad); >+ EXPECT_TRUE(target.has_value()); >+ } >+ >+ { >+ absl::any src(absl::in_place_type_t<BadCopyable>{}); >+ absl::any target; >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); >+ EXPECT_FALSE(target.has_value()); >+ } >+ >+ { >+ absl::any src(absl::in_place_type_t<BadCopyable>{}); >+ absl::any target(absl::in_place_type_t<BadCopyable>{}); >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target = src); >+ EXPECT_TRUE(target.has_value()); >+ } >+} >+ >+// Test the guarantees regarding exceptions in emplace. >+TEST(AnyTest, FailedEmplace) { >+ { >+ BadCopyable bad; >+ absl::any target; >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad)); >+ } >+ >+ { >+ BadCopyable bad; >+ absl::any target(absl::in_place_type_t<int>{}); >+ ABSL_ANY_TEST_EXPECT_BAD_COPY(target.emplace<BadCopyable>(bad)); >+#if defined(ABSL_HAVE_STD_ANY) && defined(__GLIBCXX__) >+ // libstdc++ std::any::emplace() implementation (as of 7.2) has a bug: if an >+ // exception is thrown, *this contains a value. >+#define ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG 1 >+#endif >+#if defined(ABSL_HAVE_EXCEPTIONS) && \ >+ !defined(ABSL_GLIBCXX_ANY_EMPLACE_EXCEPTION_BUG) >+ EXPECT_FALSE(target.has_value()); >+#endif >+ } >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.cc >new file mode 100644 >index 00000000000..2e2fd29a337 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.cc >@@ -0,0 +1,44 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/bad_any_cast.h" >+ >+#ifndef ABSL_HAVE_STD_ANY >+ >+#include <cstdlib> >+ >+#include "absl/base/config.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+bad_any_cast::~bad_any_cast() = default; >+ >+const char* bad_any_cast::what() const noexcept { return "Bad any cast"; } >+ >+namespace any_internal { >+ >+void ThrowBadAnyCast() { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw bad_any_cast(); >+#else >+ ABSL_RAW_LOG(FATAL, "Bad any cast"); >+ std::abort(); >+#endif >+} >+ >+} // namespace any_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_ANY >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.h >new file mode 100644 >index 00000000000..603901324af >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_any_cast.h >@@ -0,0 +1,71 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// bad_any_cast.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines the `absl::bad_any_cast` type. >+ >+#ifndef ABSL_TYPES_BAD_ANY_CAST_H_ >+#define ABSL_TYPES_BAD_ANY_CAST_H_ >+ >+#include <typeinfo> >+ >+#include "absl/base/config.h" >+ >+#ifdef ABSL_HAVE_STD_ANY >+ >+#include <any> >+ >+namespace absl { >+using std::bad_any_cast; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_ANY >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// bad_any_cast >+// ----------------------------------------------------------------------------- >+// >+// An `absl::bad_any_cast` type is an exception type that is thrown when >+// failing to successfully cast the return value of an `absl::any` object. >+// >+// Example: >+// >+// auto a = absl::any(65); >+// absl::any_cast<int>(a); // 65 >+// try { >+// absl::any_cast<char>(a); >+// } catch(const absl::bad_any_cast& e) { >+// std::cout << "Bad any cast: " << e.what() << '\n'; >+// } >+class bad_any_cast : public std::bad_cast { >+ public: >+ ~bad_any_cast() override; >+ const char* what() const noexcept override; >+}; >+ >+namespace any_internal { >+ >+[[noreturn]] void ThrowBadAnyCast(); >+ >+} // namespace any_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_ANY >+ >+#endif // ABSL_TYPES_BAD_ANY_CAST_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.cc >new file mode 100644 >index 00000000000..558707760e9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.cc >@@ -0,0 +1,46 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/bad_optional_access.h" >+ >+#ifndef ABSL_HAVE_STD_OPTIONAL >+ >+#include <cstdlib> >+ >+#include "absl/base/config.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+bad_optional_access::~bad_optional_access() = default; >+ >+const char* bad_optional_access::what() const noexcept { >+ return "optional has no value"; >+} >+ >+namespace optional_internal { >+ >+void throw_bad_optional_access() { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw bad_optional_access(); >+#else >+ ABSL_RAW_LOG(FATAL, "Bad optional access"); >+ abort(); >+#endif >+} >+ >+} // namespace optional_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_OPTIONAL >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.h >new file mode 100644 >index 00000000000..c6c27460a76 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_optional_access.h >@@ -0,0 +1,74 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// bad_optional_access.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines the `absl::bad_optional_access` type. >+ >+#ifndef ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_ >+#define ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_ >+ >+#include <stdexcept> >+ >+#include "absl/base/config.h" >+ >+#ifdef ABSL_HAVE_STD_OPTIONAL >+ >+#include <optional> >+ >+namespace absl { >+using std::bad_optional_access; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_OPTIONAL >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// bad_optional_access >+// ----------------------------------------------------------------------------- >+// >+// An `absl::bad_optional_access` type is an exception type that is thrown when >+// attempting to access an `absl::optional` object that does not contain a >+// value. >+// >+// Example: >+// >+// absl::optional<int> o; >+// >+// try { >+// int n = o.value(); >+// } catch(const absl::bad_optional_access& e) { >+// std::cout << "Bad optional access: " << e.what() << '\n'; >+// } >+class bad_optional_access : public std::exception { >+ public: >+ bad_optional_access() = default; >+ ~bad_optional_access() override; >+ const char* what() const noexcept override; >+}; >+ >+namespace optional_internal { >+ >+// throw delegator >+[[noreturn]] void throw_bad_optional_access(); >+ >+} // namespace optional_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_OPTIONAL >+ >+#endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.cc >new file mode 100644 >index 00000000000..d27d7756179 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.cc >@@ -0,0 +1,62 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/bad_variant_access.h" >+ >+#ifndef ABSL_HAVE_STD_VARIANT >+ >+#include <cstdlib> >+#include <stdexcept> >+ >+#include "absl/base/config.h" >+#include "absl/base/internal/raw_logging.h" >+ >+namespace absl { >+ >+////////////////////////// >+// [variant.bad.access] // >+////////////////////////// >+ >+bad_variant_access::~bad_variant_access() = default; >+ >+const char* bad_variant_access::what() const noexcept { >+ return "Bad variant access"; >+} >+ >+namespace variant_internal { >+ >+void ThrowBadVariantAccess() { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw bad_variant_access(); >+#else >+ ABSL_RAW_LOG(FATAL, "Bad variant access"); >+ abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn. >+#endif >+} >+ >+void Rethrow() { >+#ifdef ABSL_HAVE_EXCEPTIONS >+ throw; >+#else >+ ABSL_RAW_LOG(FATAL, >+ "Internal error in absl::variant implementation. Attempted to " >+ "rethrow an exception when building with exceptions disabled."); >+ abort(); // TODO(calabrese) Remove once RAW_LOG FATAL is noreturn. >+#endif >+} >+ >+} // namespace variant_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_VARIANT >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.h >new file mode 100644 >index 00000000000..e7355a5a74c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/bad_variant_access.h >@@ -0,0 +1,78 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// bad_variant_access.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines the `absl::bad_variant_access` type. >+ >+#ifndef ABSL_TYPES_BAD_VARIANT_ACCESS_H_ >+#define ABSL_TYPES_BAD_VARIANT_ACCESS_H_ >+ >+#include <stdexcept> >+ >+#include "absl/base/config.h" >+ >+#ifdef ABSL_HAVE_STD_VARIANT >+ >+#include <variant> >+ >+namespace absl { >+using std::bad_variant_access; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_VARIANT >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// bad_variant_access >+// ----------------------------------------------------------------------------- >+// >+// An `absl::bad_variant_access` type is an exception type that is thrown in >+// the following cases: >+// >+// * Calling `absl::get(absl::variant) with an index or type that does not >+// match the currently selected alternative type >+// * Calling `absl::visit on an `absl::variant` that is in the >+// `variant::valueless_by_exception` state. >+// >+// Example: >+// >+// absl::variant<int, std::string> v; >+// v = 1; >+// try { >+// absl::get<std::string>(v); >+// } catch(const absl::bad_variant_access& e) { >+// std::cout << "Bad variant access: " << e.what() << '\n'; >+// } >+class bad_variant_access : public std::exception { >+ public: >+ bad_variant_access() noexcept = default; >+ ~bad_variant_access() override; >+ const char* what() const noexcept override; >+}; >+ >+namespace variant_internal { >+ >+[[noreturn]] void ThrowBadVariantAccess(); >+[[noreturn]] void Rethrow(); >+ >+} // namespace variant_internal >+} // namespace absl >+ >+#endif // ABSL_HAVE_STD_VARIANT >+ >+#endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/internal/variant.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/internal/variant.h >new file mode 100644 >index 00000000000..7708e67cb14 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/internal/variant.h >@@ -0,0 +1,1615 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// Implementation details of absl/types/variant.h, pulled into a >+// separate file to avoid cluttering the top of the API header with >+// implementation details. >+ >+#ifndef ABSL_TYPES_variant_internal_H_ >+#define ABSL_TYPES_variant_internal_H_ >+ >+#include <cassert> >+#include <cstddef> >+#include <cstdlib> >+#include <memory> >+#include <stdexcept> >+#include <tuple> >+#include <type_traits> >+ >+#include "absl/base/config.h" >+#include "absl/base/internal/identity.h" >+#include "absl/base/internal/inline_variable.h" >+#include "absl/base/internal/invoke.h" >+#include "absl/base/macros.h" >+#include "absl/base/optimization.h" >+#include "absl/meta/type_traits.h" >+#include "absl/types/bad_variant_access.h" >+#include "absl/utility/utility.h" >+ >+namespace absl { >+ >+template <class... Types> >+class variant; >+ >+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); >+ >+template <class T> >+struct variant_size; >+ >+template <std::size_t I, class T> >+struct variant_alternative; >+ >+namespace variant_internal { >+ >+// NOTE: See specializations below for details. >+template <std::size_t I, class T> >+struct VariantAlternativeSfinae {}; >+ >+// Requires: I < variant_size_v<T>. >+// >+// Value: The Ith type of Types... >+template <std::size_t I, class T0, class... Tn> >+struct VariantAlternativeSfinae<I, variant<T0, Tn...>> >+ : VariantAlternativeSfinae<I - 1, variant<Tn...>> {}; >+ >+// Value: T0 >+template <class T0, class... Ts> >+struct VariantAlternativeSfinae<0, variant<T0, Ts...>> { >+ using type = T0; >+}; >+ >+template <std::size_t I, class T> >+using VariantAlternativeSfinaeT = typename VariantAlternativeSfinae<I, T>::type; >+ >+// NOTE: Requires T to be a reference type. >+template <class T, class U> >+struct GiveQualsTo; >+ >+template <class T, class U> >+struct GiveQualsTo<T&, U> { >+ using type = U&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<T&&, U> { >+ using type = U&&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<const T&, U> { >+ using type = const U&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<const T&&, U> { >+ using type = const U&&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<volatile T&, U> { >+ using type = volatile U&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<volatile T&&, U> { >+ using type = volatile U&&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<volatile const T&, U> { >+ using type = volatile const U&; >+}; >+ >+template <class T, class U> >+struct GiveQualsTo<volatile const T&&, U> { >+ using type = volatile const U&&; >+}; >+ >+template <class T, class U> >+using GiveQualsToT = typename GiveQualsTo<T, U>::type; >+ >+// Convenience alias, since size_t integral_constant is used a lot in this file. >+template <std::size_t I> >+using SizeT = std::integral_constant<std::size_t, I>; >+ >+using NPos = SizeT<variant_npos>; >+ >+template <class Variant, class T, class = void> >+struct IndexOfConstructedType {}; >+ >+template <std::size_t I, class Variant> >+struct VariantAccessResultImpl; >+ >+template <std::size_t I, template <class...> class Variantemplate, class... T> >+struct VariantAccessResultImpl<I, Variantemplate<T...>&> { >+ using type = typename absl::variant_alternative<I, variant<T...>>::type&; >+}; >+ >+template <std::size_t I, template <class...> class Variantemplate, class... T> >+struct VariantAccessResultImpl<I, const Variantemplate<T...>&> { >+ using type = >+ const typename absl::variant_alternative<I, variant<T...>>::type&; >+}; >+ >+template <std::size_t I, template <class...> class Variantemplate, class... T> >+struct VariantAccessResultImpl<I, Variantemplate<T...>&&> { >+ using type = typename absl::variant_alternative<I, variant<T...>>::type&&; >+}; >+ >+template <std::size_t I, template <class...> class Variantemplate, class... T> >+struct VariantAccessResultImpl<I, const Variantemplate<T...>&&> { >+ using type = >+ const typename absl::variant_alternative<I, variant<T...>>::type&&; >+}; >+ >+template <std::size_t I, class Variant> >+using VariantAccessResult = >+ typename VariantAccessResultImpl<I, Variant&&>::type; >+ >+// NOTE: This is used instead of std::array to reduce instantiation overhead. >+template <class T, std::size_t Size> >+struct SimpleArray { >+ static_assert(Size != 0, ""); >+ T value[Size]; >+}; >+ >+template <class T> >+struct AccessedType { >+ using type = T; >+}; >+ >+template <class T> >+using AccessedTypeT = typename AccessedType<T>::type; >+ >+template <class T, std::size_t Size> >+struct AccessedType<SimpleArray<T, Size>> { >+ using type = AccessedTypeT<T>; >+}; >+ >+template <class T> >+constexpr T AccessSimpleArray(const T& value) { >+ return value; >+} >+ >+template <class T, std::size_t Size, class... SizeT> >+constexpr AccessedTypeT<T> AccessSimpleArray(const SimpleArray<T, Size>& table, >+ std::size_t head_index, >+ SizeT... tail_indices) { >+ return AccessSimpleArray(table.value[head_index], tail_indices...); >+} >+ >+// Note: Intentionally is an alias. >+template <class T> >+using AlwaysZero = SizeT<0>; >+ >+template <class Op, class... Vs> >+struct VisitIndicesResultImpl { >+ using type = absl::result_of_t<Op(AlwaysZero<Vs>...)>; >+}; >+ >+template <class Op, class... Vs> >+using VisitIndicesResultT = typename VisitIndicesResultImpl<Op, Vs...>::type; >+ >+template <class ReturnType, class FunctionObject, class EndIndices, >+ std::size_t... BoundIndices> >+struct MakeVisitationMatrix; >+ >+template <class ReturnType, class FunctionObject, std::size_t... Indices> >+constexpr ReturnType call_with_indices(FunctionObject&& function) { >+ static_assert( >+ std::is_same<ReturnType, decltype(std::declval<FunctionObject>()( >+ SizeT<Indices>()...))>::value, >+ "Not all visitation overloads have the same return type."); >+ return absl::forward<FunctionObject>(function)(SizeT<Indices>()...); >+} >+ >+template <class ReturnType, class FunctionObject, std::size_t... BoundIndices> >+struct MakeVisitationMatrix<ReturnType, FunctionObject, index_sequence<>, >+ BoundIndices...> { >+ using ResultType = ReturnType (*)(FunctionObject&&); >+ static constexpr ResultType Run() { >+ return &call_with_indices<ReturnType, FunctionObject, >+ (BoundIndices - 1)...>; >+ } >+}; >+ >+template <class ReturnType, class FunctionObject, class EndIndices, >+ class CurrIndices, std::size_t... BoundIndices> >+struct MakeVisitationMatrixImpl; >+ >+template <class ReturnType, class FunctionObject, std::size_t... EndIndices, >+ std::size_t... CurrIndices, std::size_t... BoundIndices> >+struct MakeVisitationMatrixImpl< >+ ReturnType, FunctionObject, index_sequence<EndIndices...>, >+ index_sequence<CurrIndices...>, BoundIndices...> { >+ using ResultType = SimpleArray< >+ typename MakeVisitationMatrix<ReturnType, FunctionObject, >+ index_sequence<EndIndices...>>::ResultType, >+ sizeof...(CurrIndices)>; >+ >+ static constexpr ResultType Run() { >+ return {{MakeVisitationMatrix<ReturnType, FunctionObject, >+ index_sequence<EndIndices...>, >+ BoundIndices..., CurrIndices>::Run()...}}; >+ } >+}; >+ >+template <class ReturnType, class FunctionObject, std::size_t HeadEndIndex, >+ std::size_t... TailEndIndices, std::size_t... BoundIndices> >+struct MakeVisitationMatrix<ReturnType, FunctionObject, >+ index_sequence<HeadEndIndex, TailEndIndices...>, >+ BoundIndices...> >+ : MakeVisitationMatrixImpl< >+ ReturnType, FunctionObject, index_sequence<TailEndIndices...>, >+ absl::make_index_sequence<HeadEndIndex>, BoundIndices...> {}; >+ >+struct UnreachableSwitchCase { >+ template <class Op> >+ [[noreturn]] static VisitIndicesResultT<Op, std::size_t> Run( >+ Op&& /*ignored*/) { >+#if ABSL_HAVE_BUILTIN(__builtin_unreachable) || \ >+ (defined(__GNUC__) && !defined(__clang__)) >+ __builtin_unreachable(); >+#elif defined(_MSC_VER) >+ __assume(false); >+#else >+ // Try to use assert of false being identified as an unreachable intrinsic. >+ // NOTE: We use assert directly to increase chances of exploiting an assume >+ // intrinsic. >+ assert(false); // NOLINT >+ >+ // Hack to silence potential no return warning -- cause an infinite loop. >+ return Run(absl::forward<Op>(op)); >+#endif // Checks for __builtin_unreachable >+ } >+}; >+ >+template <class Op, std::size_t I> >+struct ReachableSwitchCase { >+ static VisitIndicesResultT<Op, std::size_t> Run(Op&& op) { >+ return absl::base_internal::Invoke(absl::forward<Op>(op), SizeT<I>()); >+ } >+}; >+ >+// The number 33 is just a guess at a reasonable maximum to our switch. It is >+// not based on any analysis. The reason it is a power of 2 plus 1 instead of a >+// power of 2 is because the number was picked to correspond to a power of 2 >+// amount of "normal" alternatives, plus one for the possibility of the user >+// providing "monostate" in addition to the more natural alternatives. >+ABSL_INTERNAL_INLINE_CONSTEXPR(std::size_t, MaxUnrolledVisitCases, 33); >+ >+// Note: The default-definition is for unreachable cases. >+template <bool IsReachable> >+struct PickCaseImpl { >+ template <class Op, std::size_t I> >+ using Apply = UnreachableSwitchCase; >+}; >+ >+template <> >+struct PickCaseImpl</*IsReachable =*/true> { >+ template <class Op, std::size_t I> >+ using Apply = ReachableSwitchCase<Op, I>; >+}; >+ >+// Note: This form of dance with template aliases is to make sure that we >+// instantiate a number of templates proportional to the number of variant >+// alternatives rather than a number of templates proportional to our >+// maximum unrolled amount of visitation cases (aliases are effectively >+// "free" whereas other template instantiations are costly). >+template <class Op, std::size_t I, std::size_t EndIndex> >+using PickCase = typename PickCaseImpl<(I < EndIndex)>::template Apply<Op, I>; >+ >+template <class ReturnType> >+[[noreturn]] ReturnType TypedThrowBadVariantAccess() { >+ absl::variant_internal::ThrowBadVariantAccess(); >+} >+ >+// Given N variant sizes, determine the number of cases there would need to be >+// in a single switch-statement that would cover every possibility in the >+// corresponding N-ary visit operation. >+template <std::size_t... NumAlternatives> >+struct NumCasesOfSwitch; >+ >+template <std::size_t HeadNumAlternatives, std::size_t... TailNumAlternatives> >+struct NumCasesOfSwitch<HeadNumAlternatives, TailNumAlternatives...> { >+ static constexpr std::size_t value = >+ (HeadNumAlternatives + 1) * >+ NumCasesOfSwitch<TailNumAlternatives...>::value; >+}; >+ >+template <> >+struct NumCasesOfSwitch<> { >+ static constexpr std::size_t value = 1; >+}; >+ >+// A switch statement optimizes better than the table of function pointers. >+template <std::size_t EndIndex> >+struct VisitIndicesSwitch { >+ static_assert(EndIndex <= MaxUnrolledVisitCases, >+ "Maximum unrolled switch size exceeded."); >+ >+ template <class Op> >+ static VisitIndicesResultT<Op, std::size_t> Run(Op&& op, std::size_t i) { >+ switch (i) { >+ case 0: >+ return PickCase<Op, 0, EndIndex>::Run(absl::forward<Op>(op)); >+ case 1: >+ return PickCase<Op, 1, EndIndex>::Run(absl::forward<Op>(op)); >+ case 2: >+ return PickCase<Op, 2, EndIndex>::Run(absl::forward<Op>(op)); >+ case 3: >+ return PickCase<Op, 3, EndIndex>::Run(absl::forward<Op>(op)); >+ case 4: >+ return PickCase<Op, 4, EndIndex>::Run(absl::forward<Op>(op)); >+ case 5: >+ return PickCase<Op, 5, EndIndex>::Run(absl::forward<Op>(op)); >+ case 6: >+ return PickCase<Op, 6, EndIndex>::Run(absl::forward<Op>(op)); >+ case 7: >+ return PickCase<Op, 7, EndIndex>::Run(absl::forward<Op>(op)); >+ case 8: >+ return PickCase<Op, 8, EndIndex>::Run(absl::forward<Op>(op)); >+ case 9: >+ return PickCase<Op, 9, EndIndex>::Run(absl::forward<Op>(op)); >+ case 10: >+ return PickCase<Op, 10, EndIndex>::Run(absl::forward<Op>(op)); >+ case 11: >+ return PickCase<Op, 11, EndIndex>::Run(absl::forward<Op>(op)); >+ case 12: >+ return PickCase<Op, 12, EndIndex>::Run(absl::forward<Op>(op)); >+ case 13: >+ return PickCase<Op, 13, EndIndex>::Run(absl::forward<Op>(op)); >+ case 14: >+ return PickCase<Op, 14, EndIndex>::Run(absl::forward<Op>(op)); >+ case 15: >+ return PickCase<Op, 15, EndIndex>::Run(absl::forward<Op>(op)); >+ case 16: >+ return PickCase<Op, 16, EndIndex>::Run(absl::forward<Op>(op)); >+ case 17: >+ return PickCase<Op, 17, EndIndex>::Run(absl::forward<Op>(op)); >+ case 18: >+ return PickCase<Op, 18, EndIndex>::Run(absl::forward<Op>(op)); >+ case 19: >+ return PickCase<Op, 19, EndIndex>::Run(absl::forward<Op>(op)); >+ case 20: >+ return PickCase<Op, 20, EndIndex>::Run(absl::forward<Op>(op)); >+ case 21: >+ return PickCase<Op, 21, EndIndex>::Run(absl::forward<Op>(op)); >+ case 22: >+ return PickCase<Op, 22, EndIndex>::Run(absl::forward<Op>(op)); >+ case 23: >+ return PickCase<Op, 23, EndIndex>::Run(absl::forward<Op>(op)); >+ case 24: >+ return PickCase<Op, 24, EndIndex>::Run(absl::forward<Op>(op)); >+ case 25: >+ return PickCase<Op, 25, EndIndex>::Run(absl::forward<Op>(op)); >+ case 26: >+ return PickCase<Op, 26, EndIndex>::Run(absl::forward<Op>(op)); >+ case 27: >+ return PickCase<Op, 27, EndIndex>::Run(absl::forward<Op>(op)); >+ case 28: >+ return PickCase<Op, 28, EndIndex>::Run(absl::forward<Op>(op)); >+ case 29: >+ return PickCase<Op, 29, EndIndex>::Run(absl::forward<Op>(op)); >+ case 30: >+ return PickCase<Op, 30, EndIndex>::Run(absl::forward<Op>(op)); >+ case 31: >+ return PickCase<Op, 31, EndIndex>::Run(absl::forward<Op>(op)); >+ case 32: >+ return PickCase<Op, 32, EndIndex>::Run(absl::forward<Op>(op)); >+ default: >+ ABSL_ASSERT(i == variant_npos); >+ return absl::base_internal::Invoke(absl::forward<Op>(op), NPos()); >+ } >+ } >+}; >+ >+template <std::size_t... EndIndices> >+struct VisitIndicesFallback { >+ template <class Op, class... SizeT> >+ static VisitIndicesResultT<Op, SizeT...> Run(Op&& op, SizeT... indices) { >+ return AccessSimpleArray( >+ MakeVisitationMatrix<VisitIndicesResultT<Op, SizeT...>, Op, >+ index_sequence<(EndIndices + 1)...>>::Run(), >+ (indices + 1)...)(absl::forward<Op>(op)); >+ } >+}; >+ >+// Take an N-dimensional series of indices and convert them into a single index >+// without loss of information. The purpose of this is to be able to convert an >+// N-ary visit operation into a single switch statement. >+template <std::size_t...> >+struct FlattenIndices; >+ >+template <std::size_t HeadSize, std::size_t... TailSize> >+struct FlattenIndices<HeadSize, TailSize...> { >+ template<class... SizeType> >+ static constexpr std::size_t Run(std::size_t head, SizeType... tail) { >+ return head + HeadSize * FlattenIndices<TailSize...>::Run(tail...); >+ } >+}; >+ >+template <> >+struct FlattenIndices<> { >+ static constexpr std::size_t Run() { return 0; } >+}; >+ >+// Take a single "flattened" index (flattened by FlattenIndices) and determine >+// the value of the index of one of the logically represented dimensions. >+template <std::size_t I, std::size_t IndexToGet, std::size_t HeadSize, >+ std::size_t... TailSize> >+struct UnflattenIndex { >+ static constexpr std::size_t value = >+ UnflattenIndex<I / HeadSize, IndexToGet - 1, TailSize...>::value; >+}; >+ >+template <std::size_t I, std::size_t HeadSize, std::size_t... TailSize> >+struct UnflattenIndex<I, 0, HeadSize, TailSize...> { >+ static constexpr std::size_t value = (I % HeadSize); >+}; >+ >+// The backend for converting an N-ary visit operation into a unary visit. >+template <class IndexSequence, std::size_t... EndIndices> >+struct VisitIndicesVariadicImpl; >+ >+template <std::size_t... N, std::size_t... EndIndices> >+struct VisitIndicesVariadicImpl<absl::index_sequence<N...>, EndIndices...> { >+ // A type that can take an N-ary function object and converts it to a unary >+ // function object that takes a single, flattened index, and "unflattens" it >+ // into its individual dimensions when forwarding to the wrapped object. >+ template <class Op> >+ struct FlattenedOp { >+ template <std::size_t I> >+ VisitIndicesResultT<Op, decltype(EndIndices)...> operator()( >+ SizeT<I> /*index*/) && { >+ return base_internal::Invoke( >+ absl::forward<Op>(op), >+ SizeT<UnflattenIndex<I, N, (EndIndices + 1)...>::value - >+ std::size_t{1}>()...); >+ } >+ >+ Op&& op; >+ }; >+ >+ template <class Op, class... SizeType> >+ static VisitIndicesResultT<Op, decltype(EndIndices)...> Run( >+ Op&& op, SizeType... i) { >+ return VisitIndicesSwitch<NumCasesOfSwitch<EndIndices...>::value>::Run( >+ FlattenedOp<Op>{absl::forward<Op>(op)}, >+ FlattenIndices<(EndIndices + std::size_t{1})...>::Run( >+ (i + std::size_t{1})...)); >+ } >+}; >+ >+template <std::size_t... EndIndices> >+struct VisitIndicesVariadic >+ : VisitIndicesVariadicImpl<absl::make_index_sequence<sizeof...(EndIndices)>, >+ EndIndices...> {}; >+ >+// This implementation will flatten N-ary visit operations into a single switch >+// statement when the number of cases would be less than our maximum specified >+// switch-statement size. >+// TODO(calabrese) >+// Based on benchmarks, determine whether the function table approach actually >+// does optimize better than a chain of switch statements and possibly update >+// the implementation accordingly. Also consider increasing the maximum switch >+// size. >+template <std::size_t... EndIndices> >+struct VisitIndices >+ : absl::conditional_t<(NumCasesOfSwitch<EndIndices...>::value <= >+ MaxUnrolledVisitCases), >+ VisitIndicesVariadic<EndIndices...>, >+ VisitIndicesFallback<EndIndices...>> {}; >+ >+template <std::size_t EndIndex> >+struct VisitIndices<EndIndex> >+ : absl::conditional_t<(EndIndex <= MaxUnrolledVisitCases), >+ VisitIndicesSwitch<EndIndex>, >+ VisitIndicesFallback<EndIndex>> {}; >+ >+// Suppress bogus warning on MSVC: MSVC complains that the `reinterpret_cast` >+// below is returning the address of a temporary or local object. >+#ifdef _MSC_VER >+#pragma warning(push) >+#pragma warning(disable : 4172) >+#endif // _MSC_VER >+ >+// TODO(calabrese) std::launder >+// TODO(calabrese) constexpr >+// NOTE: DO NOT REMOVE the `inline` keyword as it is necessary to work around a >+// MSVC bug. See https://github.com/abseil/abseil-cpp/issues/129 for details. >+template <class Self, std::size_t I> >+inline VariantAccessResult<I, Self> AccessUnion(Self&& self, SizeT<I> /*i*/) { >+ return reinterpret_cast<VariantAccessResult<I, Self>>(self); >+} >+ >+#ifdef _MSC_VER >+#pragma warning(pop) >+#endif // _MSC_VER >+ >+template <class T> >+void DeducedDestroy(T& self) { // NOLINT >+ self.~T(); >+} >+ >+// NOTE: This type exists as a single entity for variant and its bases to >+// befriend. It contains helper functionality that manipulates the state of the >+// variant, such as the implementation of things like assignment and emplace >+// operations. >+struct VariantCoreAccess { >+ template <class VariantType> >+ static typename VariantType::Variant& Derived(VariantType& self) { // NOLINT >+ return static_cast<typename VariantType::Variant&>(self); >+ } >+ >+ template <class VariantType> >+ static const typename VariantType::Variant& Derived( >+ const VariantType& self) { // NOLINT >+ return static_cast<const typename VariantType::Variant&>(self); >+ } >+ >+ template <class VariantType> >+ static void Destroy(VariantType& self) { // NOLINT >+ Derived(self).destroy(); >+ self.index_ = absl::variant_npos; >+ } >+ >+ template <class Variant> >+ static void SetIndex(Variant& self, std::size_t i) { // NOLINT >+ self.index_ = i; >+ } >+ >+ template <class Variant> >+ static void InitFrom(Variant& self, Variant&& other) { // NOLINT >+ VisitIndices<absl::variant_size<Variant>::value>::Run( >+ InitFromVisitor<Variant, Variant&&>{&self, >+ std::forward<Variant>(other)}, >+ other.index()); >+ self.index_ = other.index(); >+ } >+ >+ // Access a variant alternative, assuming the index is correct. >+ template <std::size_t I, class Variant> >+ static VariantAccessResult<I, Variant> Access(Variant&& self) { >+ // This cast instead of invocation of AccessUnion with an rvalue is a >+ // workaround for msvc. Without this there is a runtime failure when dealing >+ // with rvalues. >+ // TODO(calabrese) Reduce test case and find a simpler workaround. >+ return static_cast<VariantAccessResult<I, Variant>>( >+ variant_internal::AccessUnion(self.state_, SizeT<I>())); >+ } >+ >+ // Access a variant alternative, throwing if the index is incorrect. >+ template <std::size_t I, class Variant> >+ static VariantAccessResult<I, Variant> CheckedAccess(Variant&& self) { >+ if (ABSL_PREDICT_FALSE(self.index_ != I)) { >+ TypedThrowBadVariantAccess<VariantAccessResult<I, Variant>>(); >+ } >+ >+ return Access<I>(absl::forward<Variant>(self)); >+ } >+ >+ // The implementation of the move-assignment operation for a variant. >+ template <class VType> >+ struct MoveAssignVisitor { >+ using DerivedType = typename VType::Variant; >+ template <std::size_t NewIndex> >+ void operator()(SizeT<NewIndex> /*new_i*/) const { >+ if (left->index_ == NewIndex) { >+ Access<NewIndex>(*left) = std::move(Access<NewIndex>(*right)); >+ } else { >+ Derived(*left).template emplace<NewIndex>( >+ std::move(Access<NewIndex>(*right))); >+ } >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const { >+ Destroy(*left); >+ } >+ >+ VType* left; >+ VType* right; >+ }; >+ >+ template <class VType> >+ static MoveAssignVisitor<VType> MakeMoveAssignVisitor(VType* left, >+ VType* other) { >+ return {left, other}; >+ } >+ >+ // The implementation of the assignment operation for a variant. >+ template <class VType> >+ struct CopyAssignVisitor { >+ using DerivedType = typename VType::Variant; >+ template <std::size_t NewIndex> >+ void operator()(SizeT<NewIndex> /*new_i*/) const { >+ using New = >+ typename absl::variant_alternative<NewIndex, DerivedType>::type; >+ >+ if (left->index_ == NewIndex) { >+ Access<NewIndex>(*left) = Access<NewIndex>(*right); >+ } else if (std::is_nothrow_copy_constructible<New>::value || >+ !std::is_nothrow_move_constructible<New>::value) { >+ Derived(*left).template emplace<NewIndex>(Access<NewIndex>(*right)); >+ } else { >+ Derived(*left) = DerivedType(Derived(*right)); >+ } >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const { >+ Destroy(*left); >+ } >+ >+ VType* left; >+ const VType* right; >+ }; >+ >+ template <class VType> >+ static CopyAssignVisitor<VType> MakeCopyAssignVisitor(VType* left, >+ const VType& other) { >+ return {left, &other}; >+ } >+ >+ // The implementation of conversion-assignment operations for variant. >+ template <class Left, class QualifiedNew> >+ struct ConversionAssignVisitor { >+ using NewIndex = >+ variant_internal::IndexOfConstructedType<Left, QualifiedNew>; >+ >+ void operator()(SizeT<NewIndex::value> /*old_i*/ >+ ) const { >+ Access<NewIndex::value>(*left) = absl::forward<QualifiedNew>(other); >+ } >+ >+ template <std::size_t OldIndex> >+ void operator()(SizeT<OldIndex> /*old_i*/ >+ ) const { >+ using New = >+ typename absl::variant_alternative<NewIndex::value, Left>::type; >+ if (std::is_nothrow_constructible<New, QualifiedNew>::value || >+ !std::is_nothrow_move_constructible<New>::value) { >+ left->template emplace<NewIndex::value>( >+ absl::forward<QualifiedNew>(other)); >+ } else { >+ // the standard says "equivalent to >+ // operator=(variant(std::forward<T>(t)))", but we use `emplace` here >+ // because the variant's move assignment operator could be deleted. >+ left->template emplace<NewIndex::value>( >+ New(absl::forward<QualifiedNew>(other))); >+ } >+ } >+ >+ Left* left; >+ QualifiedNew&& other; >+ }; >+ >+ template <class Left, class QualifiedNew> >+ static ConversionAssignVisitor<Left, QualifiedNew> >+ MakeConversionAssignVisitor(Left* left, QualifiedNew&& qual) { >+ return {left, absl::forward<QualifiedNew>(qual)}; >+ } >+ >+ // Backend for operations for `emplace()` which destructs `*self` then >+ // construct a new alternative with `Args...`. >+ template <std::size_t NewIndex, class Self, class... Args> >+ static typename absl::variant_alternative<NewIndex, Self>::type& Replace( >+ Self* self, Args&&... args) { >+ Destroy(*self); >+ using New = typename absl::variant_alternative<NewIndex, Self>::type; >+ New* const result = ::new (static_cast<void*>(&self->state_)) >+ New(absl::forward<Args>(args)...); >+ self->index_ = NewIndex; >+ return *result; >+ } >+ >+ template <class LeftVariant, class QualifiedRightVariant> >+ struct InitFromVisitor { >+ template <std::size_t NewIndex> >+ void operator()(SizeT<NewIndex> /*new_i*/) const { >+ using Alternative = >+ typename variant_alternative<NewIndex, LeftVariant>::type; >+ ::new (static_cast<void*>(&left->state_)) Alternative( >+ Access<NewIndex>(std::forward<QualifiedRightVariant>(right))); >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*new_i*/) const { >+ // This space intentionally left blank. >+ } >+ LeftVariant* left; >+ QualifiedRightVariant&& right; >+ }; >+}; >+ >+template <class Expected, class... T> >+struct IndexOfImpl; >+ >+template <class Expected> >+struct IndexOfImpl<Expected> { >+ using IndexFromEnd = SizeT<0>; >+ using MatchedIndexFromEnd = IndexFromEnd; >+ using MultipleMatches = std::false_type; >+}; >+ >+template <class Expected, class Head, class... Tail> >+struct IndexOfImpl<Expected, Head, Tail...> : IndexOfImpl<Expected, Tail...> { >+ using IndexFromEnd = >+ SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>; >+}; >+ >+template <class Expected, class... Tail> >+struct IndexOfImpl<Expected, Expected, Tail...> >+ : IndexOfImpl<Expected, Tail...> { >+ using IndexFromEnd = >+ SizeT<IndexOfImpl<Expected, Tail...>::IndexFromEnd::value + 1>; >+ using MatchedIndexFromEnd = IndexFromEnd; >+ using MultipleMatches = std::integral_constant< >+ bool, IndexOfImpl<Expected, Tail...>::MatchedIndexFromEnd::value != 0>; >+}; >+ >+template <class Expected, class... Types> >+struct IndexOfMeta { >+ using Results = IndexOfImpl<Expected, Types...>; >+ static_assert(!Results::MultipleMatches::value, >+ "Attempted to access a variant by specifying a type that " >+ "matches more than one alternative."); >+ static_assert(Results::MatchedIndexFromEnd::value != 0, >+ "Attempted to access a variant by specifying a type that does " >+ "not match any alternative."); >+ using type = SizeT<sizeof...(Types) - Results::MatchedIndexFromEnd::value>; >+}; >+ >+template <class Expected, class... Types> >+using IndexOf = typename IndexOfMeta<Expected, Types...>::type; >+ >+template <class Variant, class T, std::size_t CurrIndex> >+struct UnambiguousIndexOfImpl; >+ >+// Terminating case encountered once we've checked all of the alternatives >+template <class T, std::size_t CurrIndex> >+struct UnambiguousIndexOfImpl<variant<>, T, CurrIndex> : SizeT<CurrIndex> {}; >+ >+// Case where T is not Head >+template <class Head, class... Tail, class T, std::size_t CurrIndex> >+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, T, CurrIndex> >+ : UnambiguousIndexOfImpl<variant<Tail...>, T, CurrIndex + 1>::type {}; >+ >+// Case where T is Head >+template <class Head, class... Tail, std::size_t CurrIndex> >+struct UnambiguousIndexOfImpl<variant<Head, Tail...>, Head, CurrIndex> >+ : SizeT<UnambiguousIndexOfImpl<variant<Tail...>, Head, 0>::value == >+ sizeof...(Tail) >+ ? CurrIndex >+ : CurrIndex + sizeof...(Tail) + 1> {}; >+ >+template <class Variant, class T> >+struct UnambiguousIndexOf; >+ >+struct NoMatch { >+ struct type {}; >+}; >+ >+template <class... Alts, class T> >+struct UnambiguousIndexOf<variant<Alts...>, T> >+ : std::conditional<UnambiguousIndexOfImpl<variant<Alts...>, T, 0>::value != >+ sizeof...(Alts), >+ UnambiguousIndexOfImpl<variant<Alts...>, T, 0>, >+ NoMatch>::type::type {}; >+ >+template <class T, std::size_t /*Dummy*/> >+using UnambiguousTypeOfImpl = T; >+ >+template <class Variant, class T> >+using UnambiguousTypeOfT = >+ UnambiguousTypeOfImpl<T, UnambiguousIndexOf<Variant, T>::value>; >+ >+template <class H, class... T> >+class VariantStateBase; >+ >+// This is an implementation of the "imaginary function" that is described in >+// [variant.ctor] >+// It is used in order to determine which alternative to construct during >+// initialization from some type T. >+template <class Variant, std::size_t I = 0> >+struct ImaginaryFun; >+ >+template <std::size_t I> >+struct ImaginaryFun<variant<>, I> { >+ static void Run() = delete; >+}; >+ >+template <class H, class... T, std::size_t I> >+struct ImaginaryFun<variant<H, T...>, I> : ImaginaryFun<variant<T...>, I + 1> { >+ using ImaginaryFun<variant<T...>, I + 1>::Run; >+ >+ // NOTE: const& and && are used instead of by-value due to lack of guaranteed >+ // move elision of C++17. This may have other minor differences, but tests >+ // pass. >+ static SizeT<I> Run(const H&); >+ static SizeT<I> Run(H&&); >+}; >+ >+// The following metafunctions are used in constructor and assignment >+// constraints. >+template <class Self, class T> >+struct IsNeitherSelfNorInPlace : std::true_type {}; >+ >+template <class Self> >+struct IsNeitherSelfNorInPlace<Self, Self> : std::false_type {}; >+ >+template <class Self, class T> >+struct IsNeitherSelfNorInPlace<Self, in_place_type_t<T>> : std::false_type {}; >+ >+template <class Self, std::size_t I> >+struct IsNeitherSelfNorInPlace<Self, in_place_index_t<I>> : std::false_type {}; >+ >+template <class Variant, class T, class = void> >+struct ConversionIsPossibleImpl : std::false_type {}; >+ >+template <class Variant, class T> >+struct ConversionIsPossibleImpl< >+ Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>> >+ : std::true_type {}; >+ >+template <class Variant, class T> >+struct ConversionIsPossible : ConversionIsPossibleImpl<Variant, T>::type {}; >+ >+template <class Variant, class T> >+struct IndexOfConstructedType< >+ Variant, T, void_t<decltype(ImaginaryFun<Variant>::Run(std::declval<T>()))>> >+ : decltype(ImaginaryFun<Variant>::Run(std::declval<T>())) {}; >+ >+template <std::size_t... Is> >+struct ContainsVariantNPos >+ : absl::negation<std::is_same< // NOLINT >+ absl::integer_sequence<bool, 0 <= Is...>, >+ absl::integer_sequence<bool, Is != absl::variant_npos...>>> {}; >+ >+template <class Op, class... QualifiedVariants> >+using RawVisitResult = >+ absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>; >+ >+// NOTE: The spec requires that all return-paths yield the same type and is not >+// SFINAE-friendly, so we can deduce the return type by examining the first >+// result. If it's not callable, then we get an error, but are compliant and >+// fast to compile. >+// TODO(calabrese) Possibly rewrite in a way that yields better compile errors >+// at the cost of longer compile-times. >+template <class Op, class... QualifiedVariants> >+struct VisitResultImpl { >+ using type = >+ absl::result_of_t<Op(VariantAccessResult<0, QualifiedVariants>...)>; >+}; >+ >+// Done in two steps intentionally so that we don't cause substitution to fail. >+template <class Op, class... QualifiedVariants> >+using VisitResult = typename VisitResultImpl<Op, QualifiedVariants...>::type; >+ >+template <class Op, class... QualifiedVariants> >+struct PerformVisitation { >+ using ReturnType = VisitResult<Op, QualifiedVariants...>; >+ >+ template <std::size_t... Is> >+ constexpr ReturnType operator()(SizeT<Is>... indices) const { >+ return Run(typename ContainsVariantNPos<Is...>::type{}, >+ absl::index_sequence_for<QualifiedVariants...>(), indices...); >+ } >+ >+ template <std::size_t... TupIs, std::size_t... Is> >+ constexpr ReturnType Run(std::false_type /*has_valueless*/, >+ index_sequence<TupIs...>, SizeT<Is>...) const { >+ return absl::base_internal::Invoke( >+ absl::forward<Op>(op), >+ VariantCoreAccess::Access<Is>( >+ absl::forward<QualifiedVariants>(std::get<TupIs>(variant_tup)))...); >+ } >+ >+ template <std::size_t... TupIs, std::size_t... Is> >+ [[noreturn]] ReturnType Run(std::true_type /*has_valueless*/, >+ index_sequence<TupIs...>, SizeT<Is>...) const { >+ absl::variant_internal::ThrowBadVariantAccess(); >+ } >+ >+ // TODO(calabrese) Avoid using a tuple, which causes lots of instantiations >+ // Attempts using lambda variadic captures fail on current GCC. >+ std::tuple<QualifiedVariants&&...> variant_tup; >+ Op&& op; >+}; >+ >+template <class... T> >+union Union; >+ >+// We want to allow for variant<> to be trivial. For that, we need the default >+// constructor to be trivial, which means we can't define it ourselves. >+// Instead, we use a non-default constructor that takes NoopConstructorTag >+// that doesn't affect the triviality of the types. >+struct NoopConstructorTag {}; >+ >+template <std::size_t I> >+struct EmplaceTag {}; >+ >+template <> >+union Union<> { >+ constexpr explicit Union(NoopConstructorTag) noexcept {} >+}; >+ >+// Suppress bogus warning on MSVC: MSVC complains that Union<T...> has a defined >+// deleted destructor from the `std::is_destructible` check below. >+#ifdef _MSC_VER >+#pragma warning(push) >+#pragma warning(disable : 4624) >+#endif // _MSC_VER >+ >+template <class Head, class... Tail> >+union Union<Head, Tail...> { >+ using TailUnion = Union<Tail...>; >+ >+ explicit constexpr Union(NoopConstructorTag /*tag*/) noexcept >+ : tail(NoopConstructorTag()) {} >+ >+ template <class... P> >+ explicit constexpr Union(EmplaceTag<0>, P&&... args) >+ : head(absl::forward<P>(args)...) {} >+ >+ template <std::size_t I, class... P> >+ explicit constexpr Union(EmplaceTag<I>, P&&... args) >+ : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {} >+ >+ Head head; >+ TailUnion tail; >+}; >+ >+#ifdef _MSC_VER >+#pragma warning(pop) >+#endif // _MSC_VER >+ >+// TODO(calabrese) Just contain a Union in this union (certain configs fail). >+template <class... T> >+union DestructibleUnionImpl; >+ >+template <> >+union DestructibleUnionImpl<> { >+ constexpr explicit DestructibleUnionImpl(NoopConstructorTag) noexcept {} >+}; >+ >+template <class Head, class... Tail> >+union DestructibleUnionImpl<Head, Tail...> { >+ using TailUnion = DestructibleUnionImpl<Tail...>; >+ >+ explicit constexpr DestructibleUnionImpl(NoopConstructorTag /*tag*/) noexcept >+ : tail(NoopConstructorTag()) {} >+ >+ template <class... P> >+ explicit constexpr DestructibleUnionImpl(EmplaceTag<0>, P&&... args) >+ : head(absl::forward<P>(args)...) {} >+ >+ template <std::size_t I, class... P> >+ explicit constexpr DestructibleUnionImpl(EmplaceTag<I>, P&&... args) >+ : tail(EmplaceTag<I - 1>{}, absl::forward<P>(args)...) {} >+ >+ ~DestructibleUnionImpl() {} >+ >+ Head head; >+ TailUnion tail; >+}; >+ >+// This union type is destructible even if one or more T are not trivially >+// destructible. In the case that all T are trivially destructible, then so is >+// this resultant type. >+template <class... T> >+using DestructibleUnion = >+ absl::conditional_t<std::is_destructible<Union<T...>>::value, Union<T...>, >+ DestructibleUnionImpl<T...>>; >+ >+// Deepest base, containing the actual union and the discriminator >+template <class H, class... T> >+class VariantStateBase { >+ protected: >+ using Variant = variant<H, T...>; >+ >+ template <class LazyH = H, >+ class ConstructibleH = absl::enable_if_t< >+ std::is_default_constructible<LazyH>::value, LazyH>> >+ constexpr VariantStateBase() noexcept( >+ std::is_nothrow_default_constructible<ConstructibleH>::value) >+ : state_(EmplaceTag<0>()), index_(0) {} >+ >+ template <std::size_t I, class... P> >+ explicit constexpr VariantStateBase(EmplaceTag<I> tag, P&&... args) >+ : state_(tag, absl::forward<P>(args)...), index_(I) {} >+ >+ explicit constexpr VariantStateBase(NoopConstructorTag) >+ : state_(NoopConstructorTag()), index_(variant_npos) {} >+ >+ void destroy() {} // Does nothing (shadowed in child if non-trivial) >+ >+ DestructibleUnion<H, T...> state_; >+ std::size_t index_; >+}; >+ >+using absl::internal::identity; >+ >+// OverloadSet::Overload() is a unary function which is overloaded to >+// take any of the element types of the variant, by reference-to-const. >+// The return type of the overload on T is identity<T>, so that you >+// can statically determine which overload was called. >+// >+// Overload() is not defined, so it can only be called in unevaluated >+// contexts. >+template <typename... Ts> >+struct OverloadSet; >+ >+template <typename T, typename... Ts> >+struct OverloadSet<T, Ts...> : OverloadSet<Ts...> { >+ using Base = OverloadSet<Ts...>; >+ static identity<T> Overload(const T&); >+ using Base::Overload; >+}; >+ >+template <> >+struct OverloadSet<> { >+ // For any case not handled above. >+ static void Overload(...); >+}; >+ >+template <class T> >+using LessThanResult = decltype(std::declval<T>() < std::declval<T>()); >+ >+template <class T> >+using GreaterThanResult = decltype(std::declval<T>() > std::declval<T>()); >+ >+template <class T> >+using LessThanOrEqualResult = decltype(std::declval<T>() <= std::declval<T>()); >+ >+template <class T> >+using GreaterThanOrEqualResult = >+ decltype(std::declval<T>() >= std::declval<T>()); >+ >+template <class T> >+using EqualResult = decltype(std::declval<T>() == std::declval<T>()); >+ >+template <class T> >+using NotEqualResult = decltype(std::declval<T>() != std::declval<T>()); >+ >+using type_traits_internal::is_detected_convertible; >+ >+template <class... T> >+using RequireAllHaveEqualT = absl::enable_if_t< >+ absl::conjunction<is_detected_convertible<bool, EqualResult, T>...>::value, >+ bool>; >+ >+template <class... T> >+using RequireAllHaveNotEqualT = >+ absl::enable_if_t<absl::conjunction<is_detected_convertible< >+ bool, NotEqualResult, T>...>::value, >+ bool>; >+ >+template <class... T> >+using RequireAllHaveLessThanT = >+ absl::enable_if_t<absl::conjunction<is_detected_convertible< >+ bool, LessThanResult, T>...>::value, >+ bool>; >+ >+template <class... T> >+using RequireAllHaveLessThanOrEqualT = >+ absl::enable_if_t<absl::conjunction<is_detected_convertible< >+ bool, LessThanOrEqualResult, T>...>::value, >+ bool>; >+ >+template <class... T> >+using RequireAllHaveGreaterThanOrEqualT = >+ absl::enable_if_t<absl::conjunction<is_detected_convertible< >+ bool, GreaterThanOrEqualResult, T>...>::value, >+ bool>; >+ >+template <class... T> >+using RequireAllHaveGreaterThanT = >+ absl::enable_if_t<absl::conjunction<is_detected_convertible< >+ bool, GreaterThanResult, T>...>::value, >+ bool>; >+ >+// Helper template containing implementations details of variant that can't go >+// in the private section. For convenience, this takes the variant type as a >+// single template parameter. >+template <typename T> >+struct VariantHelper; >+ >+template <typename... Ts> >+struct VariantHelper<variant<Ts...>> { >+ // Type metafunction which returns the element type selected if >+ // OverloadSet::Overload() is well-formed when called with argument type U. >+ template <typename U> >+ using BestMatch = decltype( >+ variant_internal::OverloadSet<Ts...>::Overload(std::declval<U>())); >+ >+ // Type metafunction which returns true if OverloadSet::Overload() is >+ // well-formed when called with argument type U. >+ // CanAccept can't be just an alias because there is a MSVC bug on parameter >+ // pack expansion involving decltype. >+ template <typename U> >+ struct CanAccept : >+ std::integral_constant<bool, !std::is_void<BestMatch<U>>::value> {}; >+ >+ // Type metafunction which returns true if Other is an instantiation of >+ // variant, and variants's converting constructor from Other will be >+ // well-formed. We will use this to remove constructors that would be >+ // ill-formed from the overload set. >+ template <typename Other> >+ struct CanConvertFrom; >+ >+ template <typename... Us> >+ struct CanConvertFrom<variant<Us...>> >+ : public absl::conjunction<CanAccept<Us>...> {}; >+}; >+ >+// A type with nontrivial copy ctor and trivial move ctor. >+struct TrivialMoveOnly { >+ TrivialMoveOnly(TrivialMoveOnly&&) = default; >+}; >+ >+// Trait class to detect whether a type is trivially move constructible. >+// A union's defaulted copy/move constructor is deleted if any variant member's >+// copy/move constructor is nontrivial. >+template <typename T> >+struct IsTriviallyMoveConstructible: >+ std::is_move_constructible<Union<T, TrivialMoveOnly>> {}; >+ >+// To guarantee triviality of all special-member functions that can be trivial, >+// we use a chain of conditional bases for each one. >+// The order of inheritance of bases from child to base are logically: >+// >+// variant >+// VariantCopyAssignBase >+// VariantMoveAssignBase >+// VariantCopyBase >+// VariantMoveBase >+// VariantStateBaseDestructor >+// VariantStateBase >+// >+// Note that there is a separate branch at each base that is dependent on >+// whether or not that corresponding special-member-function can be trivial in >+// the resultant variant type. >+ >+template <class... T> >+class VariantStateBaseDestructorNontrivial; >+ >+template <class... T> >+class VariantMoveBaseNontrivial; >+ >+template <class... T> >+class VariantCopyBaseNontrivial; >+ >+template <class... T> >+class VariantMoveAssignBaseNontrivial; >+ >+template <class... T> >+class VariantCopyAssignBaseNontrivial; >+ >+// Base that is dependent on whether or not the destructor can be trivial. >+template <class... T> >+using VariantStateBaseDestructor = >+ absl::conditional_t<std::is_destructible<Union<T...>>::value, >+ VariantStateBase<T...>, >+ VariantStateBaseDestructorNontrivial<T...>>; >+ >+// Base that is dependent on whether or not the move-constructor can be >+// implicitly generated by the compiler (trivial or deleted). >+// Previously we were using `std::is_move_constructible<Union<T...>>` to check >+// whether all Ts have trivial move constructor, but it ran into a GCC bug: >+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84866 >+// So we have to use a different approach (i.e. `HasTrivialMoveConstructor`) to >+// work around the bug. >+template <class... T> >+using VariantMoveBase = absl::conditional_t< >+ absl::disjunction< >+ absl::negation<absl::conjunction<std::is_move_constructible<T>...>>, >+ absl::conjunction<IsTriviallyMoveConstructible<T>...>>::value, >+ VariantStateBaseDestructor<T...>, VariantMoveBaseNontrivial<T...>>; >+ >+// Base that is dependent on whether or not the copy-constructor can be trivial. >+template <class... T> >+using VariantCopyBase = absl::conditional_t< >+ absl::disjunction< >+ absl::negation<absl::conjunction<std::is_copy_constructible<T>...>>, >+ std::is_copy_constructible<Union<T...>>>::value, >+ VariantMoveBase<T...>, VariantCopyBaseNontrivial<T...>>; >+ >+// Base that is dependent on whether or not the move-assign can be trivial. >+template <class... T> >+using VariantMoveAssignBase = absl::conditional_t< >+ absl::disjunction<absl::conjunction<std::is_move_assignable<Union<T...>>, >+ std::is_move_constructible<Union<T...>>, >+ std::is_destructible<Union<T...>>>, >+ absl::negation<absl::conjunction< >+ std::is_move_constructible<T>..., >+ std::is_move_assignable<T>...>>>::value, >+ VariantCopyBase<T...>, VariantMoveAssignBaseNontrivial<T...>>; >+ >+// Base that is dependent on whether or not the copy-assign can be trivial. >+template <class... T> >+using VariantCopyAssignBase = absl::conditional_t< >+ absl::disjunction<absl::conjunction<std::is_copy_assignable<Union<T...>>, >+ std::is_copy_constructible<Union<T...>>, >+ std::is_destructible<Union<T...>>>, >+ absl::negation<absl::conjunction< >+ std::is_copy_constructible<T>..., >+ std::is_copy_assignable<T>...>>>::value, >+ VariantMoveAssignBase<T...>, VariantCopyAssignBaseNontrivial<T...>>; >+ >+template <class... T> >+using VariantBase = VariantCopyAssignBase<T...>; >+ >+template <class... T> >+class VariantStateBaseDestructorNontrivial : protected VariantStateBase<T...> { >+ private: >+ using Base = VariantStateBase<T...>; >+ >+ protected: >+ using Base::Base; >+ >+ VariantStateBaseDestructorNontrivial() = default; >+ VariantStateBaseDestructorNontrivial(VariantStateBaseDestructorNontrivial&&) = >+ default; >+ VariantStateBaseDestructorNontrivial( >+ const VariantStateBaseDestructorNontrivial&) = default; >+ VariantStateBaseDestructorNontrivial& operator=( >+ VariantStateBaseDestructorNontrivial&&) = default; >+ VariantStateBaseDestructorNontrivial& operator=( >+ const VariantStateBaseDestructorNontrivial&) = default; >+ >+ struct Destroyer { >+ template <std::size_t I> >+ void operator()(SizeT<I> i) const { >+ using Alternative = >+ typename absl::variant_alternative<I, variant<T...>>::type; >+ variant_internal::AccessUnion(self->state_, i).~Alternative(); >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*i*/) const { >+ // This space intentionally left blank >+ } >+ >+ VariantStateBaseDestructorNontrivial* self; >+ }; >+ >+ void destroy() { VisitIndices<sizeof...(T)>::Run(Destroyer{this}, index_); } >+ >+ ~VariantStateBaseDestructorNontrivial() { destroy(); } >+ >+ protected: >+ using Base::index_; >+ using Base::state_; >+}; >+ >+template <class... T> >+class VariantMoveBaseNontrivial : protected VariantStateBaseDestructor<T...> { >+ private: >+ using Base = VariantStateBaseDestructor<T...>; >+ >+ protected: >+ using Base::Base; >+ >+ struct Construct { >+ template <std::size_t I> >+ void operator()(SizeT<I> i) const { >+ using Alternative = >+ typename absl::variant_alternative<I, variant<T...>>::type; >+ ::new (static_cast<void*>(&self->state_)) Alternative( >+ variant_internal::AccessUnion(absl::move(other->state_), i)); >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*i*/) const {} >+ >+ VariantMoveBaseNontrivial* self; >+ VariantMoveBaseNontrivial* other; >+ }; >+ >+ VariantMoveBaseNontrivial() = default; >+ VariantMoveBaseNontrivial(VariantMoveBaseNontrivial&& other) noexcept( >+ absl::conjunction<std::is_nothrow_move_constructible<T>...>::value) >+ : Base(NoopConstructorTag()) { >+ VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_); >+ index_ = other.index_; >+ } >+ >+ VariantMoveBaseNontrivial(VariantMoveBaseNontrivial const&) = default; >+ >+ VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial&&) = default; >+ VariantMoveBaseNontrivial& operator=(VariantMoveBaseNontrivial const&) = >+ default; >+ >+ protected: >+ using Base::index_; >+ using Base::state_; >+}; >+ >+template <class... T> >+class VariantCopyBaseNontrivial : protected VariantMoveBase<T...> { >+ private: >+ using Base = VariantMoveBase<T...>; >+ >+ protected: >+ using Base::Base; >+ >+ VariantCopyBaseNontrivial() = default; >+ VariantCopyBaseNontrivial(VariantCopyBaseNontrivial&&) = default; >+ >+ struct Construct { >+ template <std::size_t I> >+ void operator()(SizeT<I> i) const { >+ using Alternative = >+ typename absl::variant_alternative<I, variant<T...>>::type; >+ ::new (static_cast<void*>(&self->state_)) >+ Alternative(variant_internal::AccessUnion(other->state_, i)); >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*i*/) const {} >+ >+ VariantCopyBaseNontrivial* self; >+ const VariantCopyBaseNontrivial* other; >+ }; >+ >+ VariantCopyBaseNontrivial(VariantCopyBaseNontrivial const& other) >+ : Base(NoopConstructorTag()) { >+ VisitIndices<sizeof...(T)>::Run(Construct{this, &other}, other.index_); >+ index_ = other.index_; >+ } >+ >+ VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial&&) = default; >+ VariantCopyBaseNontrivial& operator=(VariantCopyBaseNontrivial const&) = >+ default; >+ >+ protected: >+ using Base::index_; >+ using Base::state_; >+}; >+ >+template <class... T> >+class VariantMoveAssignBaseNontrivial : protected VariantCopyBase<T...> { >+ friend struct VariantCoreAccess; >+ >+ private: >+ using Base = VariantCopyBase<T...>; >+ >+ protected: >+ using Base::Base; >+ >+ VariantMoveAssignBaseNontrivial() = default; >+ VariantMoveAssignBaseNontrivial(VariantMoveAssignBaseNontrivial&&) = default; >+ VariantMoveAssignBaseNontrivial(const VariantMoveAssignBaseNontrivial&) = >+ default; >+ VariantMoveAssignBaseNontrivial& operator=( >+ VariantMoveAssignBaseNontrivial const&) = default; >+ >+ VariantMoveAssignBaseNontrivial& >+ operator=(VariantMoveAssignBaseNontrivial&& other) noexcept( >+ absl::conjunction<std::is_nothrow_move_constructible<T>..., >+ std::is_nothrow_move_assignable<T>...>::value) { >+ VisitIndices<sizeof...(T)>::Run( >+ VariantCoreAccess::MakeMoveAssignVisitor(this, &other), other.index_); >+ return *this; >+ } >+ >+ protected: >+ using Base::index_; >+ using Base::state_; >+}; >+ >+template <class... T> >+class VariantCopyAssignBaseNontrivial : protected VariantMoveAssignBase<T...> { >+ friend struct VariantCoreAccess; >+ >+ private: >+ using Base = VariantMoveAssignBase<T...>; >+ >+ protected: >+ using Base::Base; >+ >+ VariantCopyAssignBaseNontrivial() = default; >+ VariantCopyAssignBaseNontrivial(VariantCopyAssignBaseNontrivial&&) = default; >+ VariantCopyAssignBaseNontrivial(const VariantCopyAssignBaseNontrivial&) = >+ default; >+ VariantCopyAssignBaseNontrivial& operator=( >+ VariantCopyAssignBaseNontrivial&&) = default; >+ >+ VariantCopyAssignBaseNontrivial& operator=( >+ const VariantCopyAssignBaseNontrivial& other) { >+ VisitIndices<sizeof...(T)>::Run( >+ VariantCoreAccess::MakeCopyAssignVisitor(this, other), other.index_); >+ return *this; >+ } >+ >+ protected: >+ using Base::index_; >+ using Base::state_; >+}; >+ >+//////////////////////////////////////// >+// Visitors for Comparison Operations // >+//////////////////////////////////////// >+ >+template <class... Types> >+struct EqualsOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return true; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) == VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+template <class... Types> >+struct NotEqualsOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return false; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) != VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+template <class... Types> >+struct LessThanOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return false; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) < VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+template <class... Types> >+struct GreaterThanOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return false; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) > VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+template <class... Types> >+struct LessThanOrEqualsOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return true; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) <= VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+template <class... Types> >+struct GreaterThanOrEqualsOp { >+ const variant<Types...>* v; >+ const variant<Types...>* w; >+ >+ constexpr bool operator()(SizeT<absl::variant_npos> /*v_i*/) const { >+ return true; >+ } >+ >+ template <std::size_t I> >+ constexpr bool operator()(SizeT<I> /*v_i*/) const { >+ return VariantCoreAccess::Access<I>(*v) >= VariantCoreAccess::Access<I>(*w); >+ } >+}; >+ >+// Precondition: v.index() == w.index(); >+template <class... Types> >+struct SwapSameIndex { >+ variant<Types...>* v; >+ variant<Types...>* w; >+ template <std::size_t I> >+ void operator()(SizeT<I>) const { >+ using std::swap; >+ swap(VariantCoreAccess::Access<I>(*v), VariantCoreAccess::Access<I>(*w)); >+ } >+ >+ void operator()(SizeT<variant_npos>) const {} >+}; >+ >+// TODO(calabrese) do this from a different namespace for proper adl usage >+template <class... Types> >+struct Swap { >+ variant<Types...>* v; >+ variant<Types...>* w; >+ >+ void generic_swap() const { >+ variant<Types...> tmp(std::move(*w)); >+ VariantCoreAccess::Destroy(*w); >+ VariantCoreAccess::InitFrom(*w, std::move(*v)); >+ VariantCoreAccess::Destroy(*v); >+ VariantCoreAccess::InitFrom(*v, std::move(tmp)); >+ } >+ >+ void operator()(SizeT<absl::variant_npos> /*w_i*/) const { >+ if (!v->valueless_by_exception()) { >+ generic_swap(); >+ } >+ } >+ >+ template <std::size_t Wi> >+ void operator()(SizeT<Wi> /*w_i*/) { >+ if (v->index() == Wi) { >+ VisitIndices<sizeof...(Types)>::Run(SwapSameIndex<Types...>{v, w}, Wi); >+ } else { >+ generic_swap(); >+ } >+ } >+}; >+ >+template <typename Variant, typename = void, typename... Ts> >+struct VariantHashBase { >+ VariantHashBase() = delete; >+ VariantHashBase(const VariantHashBase&) = delete; >+ VariantHashBase(VariantHashBase&&) = delete; >+ VariantHashBase& operator=(const VariantHashBase&) = delete; >+ VariantHashBase& operator=(VariantHashBase&&) = delete; >+}; >+ >+struct VariantHashVisitor { >+ template <typename T> >+ size_t operator()(const T& t) { >+ return std::hash<T>{}(t); >+ } >+}; >+ >+template <typename Variant, typename... Ts> >+struct VariantHashBase<Variant, >+ absl::enable_if_t<absl::conjunction< >+ type_traits_internal::IsHashEnabled<Ts>...>::value>, >+ Ts...> { >+ using argument_type = Variant; >+ using result_type = size_t; >+ size_t operator()(const Variant& var) const { >+ if (var.valueless_by_exception()) { >+ return 239799884; >+ } >+ size_t result = VisitIndices<variant_size<Variant>::value>::Run( >+ PerformVisitation<VariantHashVisitor, const Variant&>{ >+ std::forward_as_tuple(var), VariantHashVisitor{}}, >+ var.index()); >+ // Combine the index and the hash result in order to distinguish >+ // std::variant<int, int> holding the same value as different alternative. >+ return result ^ var.index(); >+ } >+}; >+ >+} // namespace variant_internal >+} // namespace absl >+ >+#endif // ABSL_TYPES_variant_internal_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.cc >new file mode 100644 >index 00000000000..ef272904199 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.cc >@@ -0,0 +1,24 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/optional.h" >+ >+#ifndef ABSL_HAVE_STD_OPTIONAL >+namespace absl { >+ >+nullopt_t::init_t nullopt_t::init; >+extern const nullopt_t nullopt{nullopt_t::init}; >+ >+} // namespace absl >+#endif // ABSL_HAVE_STD_OPTIONAL >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.h >new file mode 100644 >index 00000000000..c837cddeef4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional.h >@@ -0,0 +1,1141 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// optional.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines the `absl::optional` type for holding a value which >+// may or may not be present. This type is useful for providing value semantics >+// for operations that may either wish to return or hold "something-or-nothing". >+// >+// Example: >+// >+// // A common way to signal operation failure is to provide an output >+// // parameter and a bool return type: >+// bool AcquireResource(const Input&, Resource * out); >+// >+// // Providing an absl::optional return type provides a cleaner API: >+// absl::optional<Resource> AcquireResource(const Input&); >+// >+// `absl::optional` is a C++11 compatible version of the C++17 `std::optional` >+// abstraction and is designed to be a drop-in replacement for code compliant >+// with C++17. >+#ifndef ABSL_TYPES_OPTIONAL_H_ >+#define ABSL_TYPES_OPTIONAL_H_ >+ >+#include "absl/base/config.h" >+#include "absl/utility/utility.h" >+ >+#ifdef ABSL_HAVE_STD_OPTIONAL >+ >+#include <optional> >+ >+namespace absl { >+using std::bad_optional_access; >+using std::optional; >+using std::make_optional; >+using std::nullopt_t; >+using std::nullopt; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_OPTIONAL >+ >+#include <cassert> >+#include <functional> >+#include <initializer_list> >+#include <new> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "absl/meta/type_traits.h" >+#include "absl/types/bad_optional_access.h" >+ >+// ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS >+// >+// Inheriting constructors is supported in GCC 4.8+, Clang 3.3+ and MSVC 2015. >+// __cpp_inheriting_constructors is a predefined macro and a recommended way to >+// check for this language feature, but GCC doesn't support it until 5.0 and >+// Clang doesn't support it until 3.6. >+// Also, MSVC 2015 has a bug: it doesn't inherit the constexpr template >+// constructor. For example, the following code won't work on MSVC 2015 Update3: >+// struct Base { >+// int t; >+// template <typename T> >+// constexpr Base(T t_) : t(t_) {} >+// }; >+// struct Foo : Base { >+// using Base::Base; >+// } >+// constexpr Foo foo(0); // doesn't work on MSVC 2015 >+#if defined(__clang__) >+#if __has_feature(cxx_inheriting_constructors) >+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 >+#endif >+#elif (defined(__GNUC__) && \ >+ (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \ >+ (__cpp_inheriting_constructors >= 200802) || \ >+ (defined(_MSC_VER) && _MSC_VER >= 1910) >+#define ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1 >+#endif >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// absl::optional >+// ----------------------------------------------------------------------------- >+// >+// A value of type `absl::optional<T>` holds either a value of `T` or an >+// "empty" value. When it holds a value of `T`, it stores it as a direct >+// sub-object, so `sizeof(optional<T>)` is approximately >+// `sizeof(T) + sizeof(bool)`. >+// >+// This implementation is based on the specification in the latest draft of the >+// C++17 `std::optional` specification as of May 2017, section 20.6. >+// >+// Differences between `absl::optional<T>` and `std::optional<T>` include: >+// >+// * `constexpr` is not used for non-const member functions. >+// (dependency on some differences between C++11 and C++14.) >+// * `absl::nullopt` and `absl::in_place` are not declared `constexpr`. We >+// need the inline variable support in C++17 for external linkage. >+// * Throws `absl::bad_optional_access` instead of >+// `std::bad_optional_access`. >+// * `optional::swap()` and `absl::swap()` relies on >+// `std::is_(nothrow_)swappable()`, which has been introduced in C++17. >+// As a workaround, we assume `is_swappable()` is always `true` >+// and `is_nothrow_swappable()` is the same as `std::is_trivial()`. >+// * `make_optional()` cannot be declared `constexpr` due to the absence of >+// guaranteed copy elision. >+// * The move constructor's `noexcept` specification is stronger, i.e. if the >+// default allocator is non-throwing (via setting >+// `ABSL_ALLOCATOR_NOTHROW`), it evaluates to `noexcept(true)`, because >+// we assume >+// a) move constructors should only throw due to allocation failure and >+// b) if T's move constructor allocates, it uses the same allocation >+// function as the default allocator. >+template <typename T> >+class optional; >+ >+// nullopt_t >+// >+// Class type for `absl::nullopt` used to indicate an `absl::optional<T>` type >+// that does not contain a value. >+struct nullopt_t { >+ struct init_t {}; >+ static init_t init; >+ >+ // It must not be default-constructible to avoid ambiguity for opt = {}. >+ // Note the non-const reference, which is to eliminate ambiguity for code >+ // like: >+ // >+ // struct S { int value; }; >+ // >+ // void Test() { >+ // optional<S> opt; >+ // opt = {{}}; >+ // } >+ explicit constexpr nullopt_t(init_t& /*unused*/) {} >+}; >+ >+// nullopt >+// >+// A tag constant of type `absl::nullopt_t` used to indicate an empty >+// `absl::optional` in certain functions, such as construction or assignment. >+extern const nullopt_t nullopt; >+ >+namespace optional_internal { >+ >+struct empty_struct {}; >+// This class stores the data in optional<T>. >+// It is specialized based on whether T is trivially destructible. >+// This is the specialization for non trivially destructible type. >+template <typename T, bool = std::is_trivially_destructible<T>::value> >+class optional_data_dtor_base { >+ struct dummy_type { >+ static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); >+ // Use an array to avoid GCC 6 placement-new warning. >+ empty_struct data[sizeof(T) / sizeof(empty_struct)]; >+ }; >+ >+ protected: >+ // Whether there is data or not. >+ bool engaged_; >+ // Data storage >+ union { >+ dummy_type dummy_; >+ T data_; >+ }; >+ >+ void destruct() noexcept { >+ if (engaged_) { >+ data_.~T(); >+ engaged_ = false; >+ } >+ } >+ >+ // dummy_ must be initialized for constexpr constructor. >+ constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} >+ >+ template <typename... Args> >+ constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) >+ : engaged_(true), data_(absl::forward<Args>(args)...) {} >+ >+ ~optional_data_dtor_base() { destruct(); } >+}; >+ >+// Specialization for trivially destructible type. >+template <typename T> >+class optional_data_dtor_base<T, true> { >+ struct dummy_type { >+ static_assert(sizeof(T) % sizeof(empty_struct) == 0, ""); >+ // Use array to avoid GCC 6 placement-new warning. >+ empty_struct data[sizeof(T) / sizeof(empty_struct)]; >+ }; >+ >+ protected: >+ // Whether there is data or not. >+ bool engaged_; >+ // Data storage >+ union { >+ dummy_type dummy_; >+ T data_; >+ }; >+ void destruct() noexcept { engaged_ = false; } >+ >+ // dummy_ must be initialized for constexpr constructor. >+ constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {} >+ >+ template <typename... Args> >+ constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args) >+ : engaged_(true), data_(absl::forward<Args>(args)...) {} >+}; >+ >+template <typename T> >+class optional_data_base : public optional_data_dtor_base<T> { >+ protected: >+ using base = optional_data_dtor_base<T>; >+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS >+ using base::base; >+#else >+ optional_data_base() = default; >+ >+ template <typename... Args> >+ constexpr explicit optional_data_base(in_place_t t, Args&&... args) >+ : base(t, absl::forward<Args>(args)...) {} >+#endif >+ >+ template <typename... Args> >+ void construct(Args&&... args) { >+ // Use dummy_'s address to work around casting cv-qualified T* to void*. >+ ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...); >+ this->engaged_ = true; >+ } >+ >+ template <typename U> >+ void assign(U&& u) { >+ if (this->engaged_) { >+ this->data_ = std::forward<U>(u); >+ } else { >+ construct(std::forward<U>(u)); >+ } >+ } >+}; >+ >+// TODO(absl-team): Add another class using >+// std::is_trivially_move_constructible trait when available to match >+// http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that >+// have trivial move but nontrivial copy. >+// Also, we should be checking is_trivially_copyable here, which is not >+// supported now, so we use is_trivially_* traits instead. >+template <typename T, bool = absl::is_trivially_copy_constructible<T>::value&& >+ absl::is_trivially_copy_assignable< >+ typename std::remove_cv<T>::type>::value&& >+ std::is_trivially_destructible<T>::value> >+class optional_data; >+ >+// Trivially copyable types >+template <typename T> >+class optional_data<T, true> : public optional_data_base<T> { >+ protected: >+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS >+ using optional_data_base<T>::optional_data_base; >+#else >+ optional_data() = default; >+ >+ template <typename... Args> >+ constexpr explicit optional_data(in_place_t t, Args&&... args) >+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {} >+#endif >+}; >+ >+template <typename T> >+class optional_data<T, false> : public optional_data_base<T> { >+ protected: >+#if ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS >+ using optional_data_base<T>::optional_data_base; >+#else >+ template <typename... Args> >+ constexpr explicit optional_data(in_place_t t, Args&&... args) >+ : optional_data_base<T>(t, absl::forward<Args>(args)...) {} >+#endif >+ >+ optional_data() = default; >+ >+ optional_data(const optional_data& rhs) { >+ if (rhs.engaged_) { >+ this->construct(rhs.data_); >+ } >+ } >+ >+ optional_data(optional_data&& rhs) noexcept( >+ absl::default_allocator_is_nothrow::value || >+ std::is_nothrow_move_constructible<T>::value) { >+ if (rhs.engaged_) { >+ this->construct(std::move(rhs.data_)); >+ } >+ } >+ >+ optional_data& operator=(const optional_data& rhs) { >+ if (rhs.engaged_) { >+ this->assign(rhs.data_); >+ } else { >+ this->destruct(); >+ } >+ return *this; >+ } >+ >+ optional_data& operator=(optional_data&& rhs) noexcept( >+ std::is_nothrow_move_assignable<T>::value&& >+ std::is_nothrow_move_constructible<T>::value) { >+ if (rhs.engaged_) { >+ this->assign(std::move(rhs.data_)); >+ } else { >+ this->destruct(); >+ } >+ return *this; >+ } >+}; >+ >+// Ordered by level of restriction, from low to high. >+// Copyable implies movable. >+enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 }; >+ >+// Base class for enabling/disabling copy/move constructor. >+template <copy_traits> >+class optional_ctor_base; >+ >+template <> >+class optional_ctor_base<copy_traits::copyable> { >+ public: >+ constexpr optional_ctor_base() = default; >+ optional_ctor_base(const optional_ctor_base&) = default; >+ optional_ctor_base(optional_ctor_base&&) = default; >+ optional_ctor_base& operator=(const optional_ctor_base&) = default; >+ optional_ctor_base& operator=(optional_ctor_base&&) = default; >+}; >+ >+template <> >+class optional_ctor_base<copy_traits::movable> { >+ public: >+ constexpr optional_ctor_base() = default; >+ optional_ctor_base(const optional_ctor_base&) = delete; >+ optional_ctor_base(optional_ctor_base&&) = default; >+ optional_ctor_base& operator=(const optional_ctor_base&) = default; >+ optional_ctor_base& operator=(optional_ctor_base&&) = default; >+}; >+ >+template <> >+class optional_ctor_base<copy_traits::non_movable> { >+ public: >+ constexpr optional_ctor_base() = default; >+ optional_ctor_base(const optional_ctor_base&) = delete; >+ optional_ctor_base(optional_ctor_base&&) = delete; >+ optional_ctor_base& operator=(const optional_ctor_base&) = default; >+ optional_ctor_base& operator=(optional_ctor_base&&) = default; >+}; >+ >+// Base class for enabling/disabling copy/move assignment. >+template <copy_traits> >+class optional_assign_base; >+ >+template <> >+class optional_assign_base<copy_traits::copyable> { >+ public: >+ constexpr optional_assign_base() = default; >+ optional_assign_base(const optional_assign_base&) = default; >+ optional_assign_base(optional_assign_base&&) = default; >+ optional_assign_base& operator=(const optional_assign_base&) = default; >+ optional_assign_base& operator=(optional_assign_base&&) = default; >+}; >+ >+template <> >+class optional_assign_base<copy_traits::movable> { >+ public: >+ constexpr optional_assign_base() = default; >+ optional_assign_base(const optional_assign_base&) = default; >+ optional_assign_base(optional_assign_base&&) = default; >+ optional_assign_base& operator=(const optional_assign_base&) = delete; >+ optional_assign_base& operator=(optional_assign_base&&) = default; >+}; >+ >+template <> >+class optional_assign_base<copy_traits::non_movable> { >+ public: >+ constexpr optional_assign_base() = default; >+ optional_assign_base(const optional_assign_base&) = default; >+ optional_assign_base(optional_assign_base&&) = default; >+ optional_assign_base& operator=(const optional_assign_base&) = delete; >+ optional_assign_base& operator=(optional_assign_base&&) = delete; >+}; >+ >+template <typename T> >+constexpr copy_traits get_ctor_copy_traits() { >+ return std::is_copy_constructible<T>::value >+ ? copy_traits::copyable >+ : std::is_move_constructible<T>::value ? copy_traits::movable >+ : copy_traits::non_movable; >+} >+ >+template <typename T> >+constexpr copy_traits get_assign_copy_traits() { >+ return std::is_copy_assignable<T>::value && >+ std::is_copy_constructible<T>::value >+ ? copy_traits::copyable >+ : std::is_move_assignable<T>::value && >+ std::is_move_constructible<T>::value >+ ? copy_traits::movable >+ : copy_traits::non_movable; >+} >+ >+// Whether T is constructible or convertible from optional<U>. >+template <typename T, typename U> >+struct is_constructible_convertible_from_optional >+ : std::integral_constant< >+ bool, std::is_constructible<T, optional<U>&>::value || >+ std::is_constructible<T, optional<U>&&>::value || >+ std::is_constructible<T, const optional<U>&>::value || >+ std::is_constructible<T, const optional<U>&&>::value || >+ std::is_convertible<optional<U>&, T>::value || >+ std::is_convertible<optional<U>&&, T>::value || >+ std::is_convertible<const optional<U>&, T>::value || >+ std::is_convertible<const optional<U>&&, T>::value> {}; >+ >+// Whether T is constructible or convertible or assignable from optional<U>. >+template <typename T, typename U> >+struct is_constructible_convertible_assignable_from_optional >+ : std::integral_constant< >+ bool, is_constructible_convertible_from_optional<T, U>::value || >+ std::is_assignable<T&, optional<U>&>::value || >+ std::is_assignable<T&, optional<U>&&>::value || >+ std::is_assignable<T&, const optional<U>&>::value || >+ std::is_assignable<T&, const optional<U>&&>::value> {}; >+ >+// Helper function used by [optional.relops], [optional.comp_with_t], >+// for checking whether an expression is convertible to bool. >+bool convertible_to_bool(bool); >+ >+// Base class for std::hash<absl::optional<T>>: >+// If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to >+// compute the hash; Otherwise, it is disabled. >+// Reference N4659 23.14.15 [unord.hash]. >+template <typename T, typename = size_t> >+struct optional_hash_base { >+ optional_hash_base() = delete; >+ optional_hash_base(const optional_hash_base&) = delete; >+ optional_hash_base(optional_hash_base&&) = delete; >+ optional_hash_base& operator=(const optional_hash_base&) = delete; >+ optional_hash_base& operator=(optional_hash_base&&) = delete; >+}; >+ >+template <typename T> >+struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( >+ std::declval<absl::remove_const_t<T> >()))> { >+ using argument_type = absl::optional<T>; >+ using result_type = size_t; >+ size_t operator()(const absl::optional<T>& opt) const { >+ if (opt) { >+ return std::hash<absl::remove_const_t<T> >()(*opt); >+ } else { >+ return static_cast<size_t>(0x297814aaad196e6dULL); >+ } >+ } >+}; >+ >+} // namespace optional_internal >+ >+// ----------------------------------------------------------------------------- >+// absl::optional class definition >+// ----------------------------------------------------------------------------- >+ >+template <typename T> >+class optional : private optional_internal::optional_data<T>, >+ private optional_internal::optional_ctor_base< >+ optional_internal::get_ctor_copy_traits<T>()>, >+ private optional_internal::optional_assign_base< >+ optional_internal::get_assign_copy_traits<T>()> { >+ using data_base = optional_internal::optional_data<T>; >+ >+ public: >+ typedef T value_type; >+ >+ // Constructors >+ >+ // Constructs an `optional` holding an empty value, NOT a default constructed >+ // `T`. >+ constexpr optional() noexcept {} >+ >+ // Constructs an `optional` initialized with `nullopt` to hold an empty value. >+ constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit) >+ >+ // Copy constructor, standard semantics >+ optional(const optional& src) = default; >+ >+ // Move constructor, standard semantics >+ optional(optional&& src) = default; >+ >+ // Constructs a non-empty `optional` direct-initialized value of type `T` from >+ // the arguments `std::forward<Args>(args)...` within the `optional`. >+ // (The `in_place_t` is a tag used to indicate that the contained object >+ // should be constructed in-place.) >+ // >+ // TODO(absl-team): Add std::is_constructible<T, Args&&...> SFINAE. >+ template <typename... Args> >+ constexpr explicit optional(in_place_t, Args&&... args) >+ : data_base(in_place_t(), absl::forward<Args>(args)...) {} >+ >+ // Constructs a non-empty `optional` direct-initialized value of type `T` from >+ // the arguments of an initializer_list and `std::forward<Args>(args)...`. >+ // (The `in_place_t` is a tag used to indicate that the contained object >+ // should be constructed in-place.) >+ template <typename U, typename... Args, >+ typename = typename std::enable_if<std::is_constructible< >+ T, std::initializer_list<U>&, Args&&...>::value>::type> >+ constexpr explicit optional(in_place_t, std::initializer_list<U> il, >+ Args&&... args) >+ : data_base(in_place_t(), il, absl::forward<Args>(args)...) { >+ } >+ >+ // Value constructor (implicit) >+ template < >+ typename U = T, >+ typename std::enable_if< >+ absl::conjunction<absl::negation<std::is_same< >+ in_place_t, typename std::decay<U>::type> >, >+ absl::negation<std::is_same< >+ optional<T>, typename std::decay<U>::type> >, >+ std::is_convertible<U&&, T>, >+ std::is_constructible<T, U&&> >::value, >+ bool>::type = false> >+ constexpr optional(U&& v) : data_base(in_place_t(), absl::forward<U>(v)) {} >+ >+ // Value constructor (explicit) >+ template < >+ typename U = T, >+ typename std::enable_if< >+ absl::conjunction<absl::negation<std::is_same< >+ in_place_t, typename std::decay<U>::type>>, >+ absl::negation<std::is_same< >+ optional<T>, typename std::decay<U>::type>>, >+ absl::negation<std::is_convertible<U&&, T>>, >+ std::is_constructible<T, U&&>>::value, >+ bool>::type = false> >+ explicit constexpr optional(U&& v) >+ : data_base(in_place_t(), absl::forward<U>(v)) {} >+ >+ // Converting copy constructor (implicit) >+ template <typename U, >+ typename std::enable_if< >+ absl::conjunction< >+ absl::negation<std::is_same<T, U> >, >+ std::is_constructible<T, const U&>, >+ absl::negation< >+ optional_internal:: >+ is_constructible_convertible_from_optional<T, U> >, >+ std::is_convertible<const U&, T> >::value, >+ bool>::type = false> >+ optional(const optional<U>& rhs) { >+ if (rhs) { >+ this->construct(*rhs); >+ } >+ } >+ >+ // Converting copy constructor (explicit) >+ template <typename U, >+ typename std::enable_if< >+ absl::conjunction< >+ absl::negation<std::is_same<T, U>>, >+ std::is_constructible<T, const U&>, >+ absl::negation< >+ optional_internal:: >+ is_constructible_convertible_from_optional<T, U>>, >+ absl::negation<std::is_convertible<const U&, T>>>::value, >+ bool>::type = false> >+ explicit optional(const optional<U>& rhs) { >+ if (rhs) { >+ this->construct(*rhs); >+ } >+ } >+ >+ // Converting move constructor (implicit) >+ template <typename U, >+ typename std::enable_if< >+ absl::conjunction< >+ absl::negation<std::is_same<T, U> >, >+ std::is_constructible<T, U&&>, >+ absl::negation< >+ optional_internal:: >+ is_constructible_convertible_from_optional<T, U> >, >+ std::is_convertible<U&&, T> >::value, >+ bool>::type = false> >+ optional(optional<U>&& rhs) { >+ if (rhs) { >+ this->construct(std::move(*rhs)); >+ } >+ } >+ >+ // Converting move constructor (explicit) >+ template < >+ typename U, >+ typename std::enable_if< >+ absl::conjunction< >+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>, >+ absl::negation< >+ optional_internal::is_constructible_convertible_from_optional< >+ T, U>>, >+ absl::negation<std::is_convertible<U&&, T>>>::value, >+ bool>::type = false> >+ explicit optional(optional<U>&& rhs) { >+ if (rhs) { >+ this->construct(std::move(*rhs)); >+ } >+ } >+ >+ // Destructor. Trivial if `T` is trivially destructible. >+ ~optional() = default; >+ >+ // Assignment Operators >+ >+ // Assignment from `nullopt` >+ // >+ // Example: >+ // >+ // struct S { int value; }; >+ // optional<S> opt = absl::nullopt; // Could also use opt = { }; >+ optional& operator=(nullopt_t) noexcept { >+ this->destruct(); >+ return *this; >+ } >+ >+ // Copy assignment operator, standard semantics >+ optional& operator=(const optional& src) = default; >+ >+ // Move assignment operator, standard semantics >+ optional& operator=(optional&& src) = default; >+ >+ // Value assignment operators >+ template < >+ typename U = T, >+ typename = typename std::enable_if<absl::conjunction< >+ absl::negation< >+ std::is_same<optional<T>, typename std::decay<U>::type>>, >+ absl::negation< >+ absl::conjunction<std::is_scalar<T>, >+ std::is_same<T, typename std::decay<U>::type>>>, >+ std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type> >+ optional& operator=(U&& v) { >+ this->assign(std::forward<U>(v)); >+ return *this; >+ } >+ >+ template < >+ typename U, >+ typename = typename std::enable_if<absl::conjunction< >+ absl::negation<std::is_same<T, U>>, >+ std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>, >+ absl::negation< >+ optional_internal:: >+ is_constructible_convertible_assignable_from_optional< >+ T, U>>>::value>::type> >+ optional& operator=(const optional<U>& rhs) { >+ if (rhs) { >+ this->assign(*rhs); >+ } else { >+ this->destruct(); >+ } >+ return *this; >+ } >+ >+ template <typename U, >+ typename = typename std::enable_if<absl::conjunction< >+ absl::negation<std::is_same<T, U>>, std::is_constructible<T, U>, >+ std::is_assignable<T&, U>, >+ absl::negation< >+ optional_internal:: >+ is_constructible_convertible_assignable_from_optional< >+ T, U>>>::value>::type> >+ optional& operator=(optional<U>&& rhs) { >+ if (rhs) { >+ this->assign(std::move(*rhs)); >+ } else { >+ this->destruct(); >+ } >+ return *this; >+ } >+ >+ // Modifiers >+ >+ // optional::reset() >+ // >+ // Destroys the inner `T` value of an `absl::optional` if one is present. >+ void reset() noexcept { this->destruct(); } >+ >+ // optional::emplace() >+ // >+ // (Re)constructs the underlying `T` in-place with the given forwarded >+ // arguments. >+ // >+ // Example: >+ // >+ // optional<Foo> opt; >+ // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3) >+ // >+ // If the optional is non-empty, and the `args` refer to subobjects of the >+ // current object, then behaviour is undefined, because the current object >+ // will be destructed before the new object is constructed with `args`. >+ template <typename... Args, >+ typename = typename std::enable_if< >+ std::is_constructible<T, Args&&...>::value>::type> >+ T& emplace(Args&&... args) { >+ this->destruct(); >+ this->construct(std::forward<Args>(args)...); >+ return reference(); >+ } >+ >+ // Emplace reconstruction overload for an initializer list and the given >+ // forwarded arguments. >+ // >+ // Example: >+ // >+ // struct Foo { >+ // Foo(std::initializer_list<int>); >+ // }; >+ // >+ // optional<Foo> opt; >+ // opt.emplace({1,2,3}); // Constructs Foo({1,2,3}) >+ template <typename U, typename... Args, >+ typename = typename std::enable_if<std::is_constructible< >+ T, std::initializer_list<U>&, Args&&...>::value>::type> >+ T& emplace(std::initializer_list<U> il, Args&&... args) { >+ this->destruct(); >+ this->construct(il, std::forward<Args>(args)...); >+ return reference(); >+ } >+ >+ // Swaps >+ >+ // Swap, standard semantics >+ void swap(optional& rhs) noexcept( >+ std::is_nothrow_move_constructible<T>::value&& >+ std::is_trivial<T>::value) { >+ if (*this) { >+ if (rhs) { >+ using std::swap; >+ swap(**this, *rhs); >+ } else { >+ rhs.construct(std::move(**this)); >+ this->destruct(); >+ } >+ } else { >+ if (rhs) { >+ this->construct(std::move(*rhs)); >+ rhs.destruct(); >+ } else { >+ // No effect (swap(disengaged, disengaged)). >+ } >+ } >+ } >+ >+ // Observers >+ >+ // optional::operator->() >+ // >+ // Accesses the underlying `T` value's member `m` of an `optional`. If the >+ // `optional` is empty, behavior is undefined. >+ // >+ // If you need myOpt->foo in constexpr, use (*myOpt).foo instead. >+ const T* operator->() const { >+ assert(this->engaged_); >+ return std::addressof(this->data_); >+ } >+ T* operator->() { >+ assert(this->engaged_); >+ return std::addressof(this->data_); >+ } >+ >+ // optional::operator*() >+ // >+ // Accesses the underlying `T` value of an `optional`. If the `optional` is >+ // empty, behavior is undefined. >+ constexpr const T& operator*() const & { return reference(); } >+ T& operator*() & { >+ assert(this->engaged_); >+ return reference(); >+ } >+ constexpr const T&& operator*() const && { >+ return absl::move(reference()); >+ } >+ T&& operator*() && { >+ assert(this->engaged_); >+ return std::move(reference()); >+ } >+ >+ // optional::operator bool() >+ // >+ // Returns false if and only if the `optional` is empty. >+ // >+ // if (opt) { >+ // // do something with opt.value(); >+ // } else { >+ // // opt is empty. >+ // } >+ // >+ constexpr explicit operator bool() const noexcept { return this->engaged_; } >+ >+ // optional::has_value() >+ // >+ // Determines whether the `optional` contains a value. Returns `false` if and >+ // only if `*this` is empty. >+ constexpr bool has_value() const noexcept { return this->engaged_; } >+ >+// Suppress bogus warning on MSVC: MSVC complains call to reference() after >+// throw_bad_optional_access() is unreachable. >+#ifdef _MSC_VER >+#pragma warning(push) >+#pragma warning(disable : 4702) >+#endif // _MSC_VER >+ // optional::value() >+ // >+ // Returns a reference to an `optional`s underlying value. The constness >+ // and lvalue/rvalue-ness of the `optional` is preserved to the view of >+ // the `T` sub-object. Throws `absl::bad_optional_access` when the `optional` >+ // is empty. >+ constexpr const T& value() const & { >+ return static_cast<bool>(*this) >+ ? reference() >+ : (optional_internal::throw_bad_optional_access(), reference()); >+ } >+ T& value() & { >+ return static_cast<bool>(*this) >+ ? reference() >+ : (optional_internal::throw_bad_optional_access(), reference()); >+ } >+ T&& value() && { // NOLINT(build/c++11) >+ return std::move( >+ static_cast<bool>(*this) >+ ? reference() >+ : (optional_internal::throw_bad_optional_access(), reference())); >+ } >+ constexpr const T&& value() const && { // NOLINT(build/c++11) >+ return absl::move( >+ static_cast<bool>(*this) >+ ? reference() >+ : (optional_internal::throw_bad_optional_access(), reference())); >+ } >+#ifdef _MSC_VER >+#pragma warning(pop) >+#endif // _MSC_VER >+ >+ // optional::value_or() >+ // >+ // Returns either the value of `T` or a passed default `v` if the `optional` >+ // is empty. >+ template <typename U> >+ constexpr T value_or(U&& v) const& { >+ static_assert(std::is_copy_constructible<value_type>::value, >+ "optional<T>::value_or: T must by copy constructible"); >+ static_assert(std::is_convertible<U&&, value_type>::value, >+ "optional<T>::value_or: U must be convertible to T"); >+ return static_cast<bool>(*this) >+ ? **this >+ : static_cast<T>(absl::forward<U>(v)); >+ } >+ template <typename U> >+ T value_or(U&& v) && { // NOLINT(build/c++11) >+ static_assert(std::is_move_constructible<value_type>::value, >+ "optional<T>::value_or: T must by copy constructible"); >+ static_assert(std::is_convertible<U&&, value_type>::value, >+ "optional<T>::value_or: U must be convertible to T"); >+ return static_cast<bool>(*this) ? std::move(**this) >+ : static_cast<T>(std::forward<U>(v)); >+ } >+ >+ private: >+ // Private accessors for internal storage viewed as reference to T. >+ constexpr const T& reference() const { return this->data_; } >+ T& reference() { return this->data_; } >+ >+ // T constraint checks. You can't have an optional of nullopt_t, in_place_t >+ // or a reference. >+ static_assert( >+ !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value, >+ "optional<nullopt_t> is not allowed."); >+ static_assert( >+ !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value, >+ "optional<in_place_t> is not allowed."); >+ static_assert(!std::is_reference<T>::value, >+ "optional<reference> is not allowed."); >+}; >+ >+// Non-member functions >+ >+// swap() >+// >+// Performs a swap between two `absl::optional` objects, using standard >+// semantics. >+// >+// NOTE: we assume `is_swappable()` is always `true`. A compile error will >+// result if this is not the case. >+template <typename T, >+ typename std::enable_if<std::is_move_constructible<T>::value, >+ bool>::type = false> >+void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) { >+ a.swap(b); >+} >+ >+// make_optional() >+// >+// Creates a non-empty `optional<T>` where the type of `T` is deduced. An >+// `absl::optional` can also be explicitly instantiated with >+// `make_optional<T>(v)`. >+// >+// Note: `make_optional()` constructions may be declared `constexpr` for >+// trivially copyable types `T`. Non-trivial types require copy elision >+// support in C++17 for `make_optional` to support `constexpr` on such >+// non-trivial types. >+// >+// Example: >+// >+// constexpr absl::optional<int> opt = absl::make_optional(1); >+// static_assert(opt.value() == 1, ""); >+template <typename T> >+constexpr optional<typename std::decay<T>::type> make_optional(T&& v) { >+ return optional<typename std::decay<T>::type>(absl::forward<T>(v)); >+} >+ >+template <typename T, typename... Args> >+constexpr optional<T> make_optional(Args&&... args) { >+ return optional<T>(in_place_t(), absl::forward<Args>(args)...); >+} >+ >+template <typename T, typename U, typename... Args> >+constexpr optional<T> make_optional(std::initializer_list<U> il, >+ Args&&... args) { >+ return optional<T>(in_place_t(), il, >+ absl::forward<Args>(args)...); >+} >+ >+// Relational operators [optional.relops] >+ >+// Empty optionals are considered equal to each other and less than non-empty >+// optionals. Supports relations between optional<T> and optional<U>, between >+// optional<T> and U, and between optional<T> and nullopt. >+// >+// Note: We're careful to support T having non-bool relationals. >+ >+// Requires: The expression, e.g. "*x == *y" shall be well-formed and its result >+// shall be convertible to bool. >+// The C++17 (N4606) "Returns:" statements are translated into >+// code in an obvious way here, and the original text retained as function docs. >+// Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true; >+// otherwise *x == *y. >+template <typename T, typename U> >+constexpr auto operator==(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x == *y)) { >+ return static_cast<bool>(x) != static_cast<bool>(y) >+ ? false >+ : static_cast<bool>(x) == false ? true >+ : static_cast<bool>(*x == *y); >+} >+ >+// Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false; >+// otherwise *x != *y. >+template <typename T, typename U> >+constexpr auto operator!=(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x != *y)) { >+ return static_cast<bool>(x) != static_cast<bool>(y) >+ ? true >+ : static_cast<bool>(x) == false ? false >+ : static_cast<bool>(*x != *y); >+} >+// Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y. >+template <typename T, typename U> >+constexpr auto operator<(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x < *y)) { >+ return !y ? false : !x ? true : static_cast<bool>(*x < *y); >+} >+// Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y. >+template <typename T, typename U> >+constexpr auto operator>(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x > *y)) { >+ return !x ? false : !y ? true : static_cast<bool>(*x > *y); >+} >+// Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y. >+template <typename T, typename U> >+constexpr auto operator<=(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x <= *y)) { >+ return !x ? true : !y ? false : static_cast<bool>(*x <= *y); >+} >+// Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y. >+template <typename T, typename U> >+constexpr auto operator>=(const optional<T>& x, const optional<U>& y) >+ -> decltype(optional_internal::convertible_to_bool(*x >= *y)) { >+ return !y ? true : !x ? false : static_cast<bool>(*x >= *y); >+} >+ >+// Comparison with nullopt [optional.nullops] >+// The C++17 (N4606) "Returns:" statements are used directly here. >+template <typename T> >+constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept { >+ return !x; >+} >+template <typename T> >+constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept { >+ return !x; >+} >+template <typename T> >+constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept { >+ return static_cast<bool>(x); >+} >+template <typename T> >+constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept { >+ return static_cast<bool>(x); >+} >+template <typename T> >+constexpr bool operator<(const optional<T>&, nullopt_t) noexcept { >+ return false; >+} >+template <typename T> >+constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept { >+ return static_cast<bool>(x); >+} >+template <typename T> >+constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept { >+ return !x; >+} >+template <typename T> >+constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept { >+ return true; >+} >+template <typename T> >+constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept { >+ return static_cast<bool>(x); >+} >+template <typename T> >+constexpr bool operator>(nullopt_t, const optional<T>&) noexcept { >+ return false; >+} >+template <typename T> >+constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept { >+ return true; >+} >+template <typename T> >+constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept { >+ return !x; >+} >+ >+// Comparison with T [optional.comp_with_t] >+ >+// Requires: The expression, e.g. "*x == v" shall be well-formed and its result >+// shall be convertible to bool. >+// The C++17 (N4606) "Equivalent to:" statements are used directly here. >+template <typename T, typename U> >+constexpr auto operator==(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x == v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false; >+} >+template <typename T, typename U> >+constexpr auto operator==(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v == *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false; >+} >+template <typename T, typename U> >+constexpr auto operator!=(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x != v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true; >+} >+template <typename T, typename U> >+constexpr auto operator!=(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v != *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true; >+} >+template <typename T, typename U> >+constexpr auto operator<(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x < v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true; >+} >+template <typename T, typename U> >+constexpr auto operator<(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v < *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false; >+} >+template <typename T, typename U> >+constexpr auto operator<=(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x <= v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true; >+} >+template <typename T, typename U> >+constexpr auto operator<=(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v <= *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false; >+} >+template <typename T, typename U> >+constexpr auto operator>(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x > v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false; >+} >+template <typename T, typename U> >+constexpr auto operator>(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v > *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true; >+} >+template <typename T, typename U> >+constexpr auto operator>=(const optional<T>& x, const U& v) >+ -> decltype(optional_internal::convertible_to_bool(*x >= v)) { >+ return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false; >+} >+template <typename T, typename U> >+constexpr auto operator>=(const U& v, const optional<T>& x) >+ -> decltype(optional_internal::convertible_to_bool(v >= *x)) { >+ return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true; >+} >+ >+} // namespace absl >+ >+namespace std { >+ >+// std::hash specialization for absl::optional. >+template <typename T> >+struct hash<absl::optional<T> > >+ : absl::optional_internal::optional_hash_base<T> {}; >+ >+} // namespace std >+ >+#undef ABSL_OPTIONAL_USE_INHERITING_CONSTRUCTORS >+#undef ABSL_MSVC_CONSTEXPR_BUG_IN_UNION_LIKE_CLASS >+ >+#endif // ABSL_HAVE_STD_OPTIONAL >+ >+#endif // ABSL_TYPES_OPTIONAL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_exception_safety_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_exception_safety_test.cc >new file mode 100644 >index 00000000000..d2ef04b8d1b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_exception_safety_test.cc >@@ -0,0 +1,282 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/optional.h" >+ >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_safety_testing.h" >+ >+namespace absl { >+ >+namespace { >+ >+using ::testing::AssertionFailure; >+using ::testing::AssertionResult; >+using ::testing::AssertionSuccess; >+using ::testing::MakeExceptionSafetyTester; >+ >+using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>; >+using Optional = absl::optional<Thrower>; >+ >+using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; >+using MoveOptional = absl::optional<MoveThrower>; >+ >+constexpr int kInitialInteger = 5; >+constexpr int kUpdatedInteger = 10; >+ >+template <typename OptionalT> >+bool ValueThrowsBadOptionalAccess(const OptionalT& optional) try { >+ return (static_cast<void>(optional.value()), false); >+} catch (absl::bad_optional_access) { >+ return true; >+} >+ >+template <typename OptionalT> >+AssertionResult CheckInvariants(OptionalT* optional_ptr) { >+ // Check the current state post-throw for validity >+ auto& optional = *optional_ptr; >+ >+ if (optional.has_value() && ValueThrowsBadOptionalAccess(optional)) { >+ return AssertionFailure() >+ << "Optional with value should not throw bad_optional_access when " >+ "accessing the value."; >+ } >+ if (!optional.has_value() && !ValueThrowsBadOptionalAccess(optional)) { >+ return AssertionFailure() >+ << "Optional without a value should throw bad_optional_access when " >+ "accessing the value."; >+ } >+ >+ // Reset to a known state >+ optional.reset(); >+ >+ // Confirm that the known post-reset state is valid >+ if (optional.has_value()) { >+ return AssertionFailure() >+ << "Optional should not contain a value after being reset."; >+ } >+ if (!ValueThrowsBadOptionalAccess(optional)) { >+ return AssertionFailure() << "Optional should throw bad_optional_access " >+ "when accessing the value after being reset."; >+ } >+ >+ return AssertionSuccess(); >+} >+ >+template <typename OptionalT> >+AssertionResult CheckDisengaged(OptionalT* optional_ptr) { >+ auto& optional = *optional_ptr; >+ >+ if (optional.has_value()) { >+ return AssertionFailure() >+ << "Expected optional to not contain a value but a value was found."; >+ } >+ >+ return AssertionSuccess(); >+} >+ >+template <typename OptionalT> >+AssertionResult CheckEngaged(OptionalT* optional_ptr) { >+ auto& optional = *optional_ptr; >+ >+ if (!optional.has_value()) { >+ return AssertionFailure() >+ << "Expected optional to contain a value but no value was found."; >+ } >+ >+ return AssertionSuccess(); >+} >+ >+TEST(OptionalExceptionSafety, ThrowingConstructors) { >+ auto thrower_nonempty = Optional(Thrower(kInitialInteger)); >+ testing::TestThrowingCtor<Optional>(thrower_nonempty); >+ >+ auto integer_nonempty = absl::optional<int>(kInitialInteger); >+ testing::TestThrowingCtor<Optional>(integer_nonempty); >+ testing::TestThrowingCtor<Optional>(std::move(integer_nonempty)); // NOLINT >+ >+ testing::TestThrowingCtor<Optional>(kInitialInteger); >+ using ThrowerVec = std::vector<Thrower, testing::ThrowingAllocator<Thrower>>; >+ testing::TestThrowingCtor<absl::optional<ThrowerVec>>( >+ absl::in_place, >+ std::initializer_list<Thrower>{Thrower(), Thrower(), Thrower()}, >+ testing::ThrowingAllocator<Thrower>()); >+} >+ >+TEST(OptionalExceptionSafety, NothrowConstructors) { >+ // This constructor is marked noexcept. If it throws, the program will >+ // terminate. >+ testing::TestThrowingCtor<MoveOptional>(MoveOptional(kUpdatedInteger)); >+} >+ >+TEST(OptionalExceptionSafety, Emplace) { >+ // Test the basic guarantee plus test the result of optional::has_value() >+ // is false in all cases >+ auto disengaged_test = MakeExceptionSafetyTester().WithInvariants( >+ CheckInvariants<Optional>, CheckDisengaged<Optional>); >+ auto disengaged_test_empty = disengaged_test.WithInitialValue(Optional()); >+ auto disengaged_test_nonempty = >+ disengaged_test.WithInitialValue(Optional(kInitialInteger)); >+ >+ auto emplace_thrower_directly = [](Optional* optional_ptr) { >+ optional_ptr->emplace(kUpdatedInteger); >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_directly)); >+ EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_directly)); >+ >+ auto emplace_thrower_copy = [](Optional* optional_ptr) { >+ auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); >+ optional_ptr->emplace(thrower); >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(emplace_thrower_copy)); >+ EXPECT_TRUE(disengaged_test_nonempty.Test(emplace_thrower_copy)); >+} >+ >+TEST(OptionalExceptionSafety, EverythingThrowsSwap) { >+ // Test the basic guarantee plus test the result of optional::has_value() >+ // remains the same >+ auto test = >+ MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); >+ auto disengaged_test_empty = test.WithInitialValue(Optional()) >+ .WithInvariants(CheckDisengaged<Optional>); >+ auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) >+ .WithInvariants(CheckEngaged<Optional>); >+ >+ auto swap_empty = [](Optional* optional_ptr) { >+ auto empty = Optional(); >+ optional_ptr->swap(empty); >+ }; >+ EXPECT_TRUE(engaged_test_nonempty.Test(swap_empty)); >+ >+ auto swap_nonempty = [](Optional* optional_ptr) { >+ auto nonempty = >+ Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); >+ optional_ptr->swap(nonempty); >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(swap_nonempty)); >+ EXPECT_TRUE(engaged_test_nonempty.Test(swap_nonempty)); >+} >+ >+TEST(OptionalExceptionSafety, NoThrowMoveSwap) { >+ // Tests the nothrow guarantee for optional of T with non-throwing move >+ { >+ auto empty = MoveOptional(); >+ auto nonempty = MoveOptional(kInitialInteger); >+ EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); })); >+ } >+ { >+ auto nonempty = MoveOptional(kUpdatedInteger); >+ auto empty = MoveOptional(); >+ EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); })); >+ } >+ { >+ auto nonempty_from = MoveOptional(kUpdatedInteger); >+ auto nonempty_to = MoveOptional(kInitialInteger); >+ EXPECT_TRUE( >+ testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); })); >+ } >+} >+ >+TEST(OptionalExceptionSafety, CopyAssign) { >+ // Test the basic guarantee plus test the result of optional::has_value() >+ // remains the same >+ auto test = >+ MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); >+ auto disengaged_test_empty = test.WithInitialValue(Optional()) >+ .WithInvariants(CheckDisengaged<Optional>); >+ auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) >+ .WithInvariants(CheckEngaged<Optional>); >+ >+ auto copyassign_nonempty = [](Optional* optional_ptr) { >+ auto nonempty = >+ Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); >+ *optional_ptr = nonempty; >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(copyassign_nonempty)); >+ EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_nonempty)); >+ >+ auto copyassign_thrower = [](Optional* optional_ptr) { >+ auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); >+ *optional_ptr = thrower; >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(copyassign_thrower)); >+ EXPECT_TRUE(engaged_test_nonempty.Test(copyassign_thrower)); >+} >+ >+TEST(OptionalExceptionSafety, MoveAssign) { >+ // Test the basic guarantee plus test the result of optional::has_value() >+ // remains the same >+ auto test = >+ MakeExceptionSafetyTester().WithInvariants(CheckInvariants<Optional>); >+ auto disengaged_test_empty = test.WithInitialValue(Optional()) >+ .WithInvariants(CheckDisengaged<Optional>); >+ auto engaged_test_nonempty = test.WithInitialValue(Optional(kInitialInteger)) >+ .WithInvariants(CheckEngaged<Optional>); >+ >+ auto moveassign_empty = [](Optional* optional_ptr) { >+ auto empty = Optional(); >+ *optional_ptr = std::move(empty); >+ }; >+ EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_empty)); >+ >+ auto moveassign_nonempty = [](Optional* optional_ptr) { >+ auto nonempty = >+ Optional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor); >+ *optional_ptr = std::move(nonempty); >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(moveassign_nonempty)); >+ EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_nonempty)); >+ >+ auto moveassign_thrower = [](Optional* optional_ptr) { >+ auto thrower = Thrower(kUpdatedInteger, testing::nothrow_ctor); >+ *optional_ptr = std::move(thrower); >+ }; >+ EXPECT_TRUE(disengaged_test_empty.Test(moveassign_thrower)); >+ EXPECT_TRUE(engaged_test_nonempty.Test(moveassign_thrower)); >+} >+ >+TEST(OptionalExceptionSafety, NothrowMoveAssign) { >+ // Tests the nothrow guarantee for optional of T with non-throwing move >+ { >+ auto empty = MoveOptional(); >+ auto nonempty = MoveOptional(kInitialInteger); >+ EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); })); >+ } >+ { >+ auto nonempty = MoveOptional(kInitialInteger); >+ auto empty = MoveOptional(); >+ EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); })); >+ } >+ { >+ auto nonempty_from = MoveOptional(kUpdatedInteger); >+ auto nonempty_to = MoveOptional(kInitialInteger); >+ EXPECT_TRUE(testing::TestNothrowOp( >+ [&]() { nonempty_to = std::move(nonempty_from); })); >+ } >+ { >+ auto thrower = MoveThrower(kUpdatedInteger); >+ auto empty = MoveOptional(); >+ EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); })); >+ } >+ { >+ auto thrower = MoveThrower(kUpdatedInteger); >+ auto nonempty = MoveOptional(kInitialInteger); >+ EXPECT_TRUE( >+ testing::TestNothrowOp([&]() { nonempty = std::move(thrower); })); >+ } >+} >+ >+} // namespace >+ >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_test.cc >new file mode 100644 >index 00000000000..179bfd66d2f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/optional_test.cc >@@ -0,0 +1,1625 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/optional.h" >+ >+#include <string> >+#include <type_traits> >+#include <utility> >+ >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/raw_logging.h" >+#include "absl/meta/type_traits.h" >+#include "absl/strings/string_view.h" >+ >+struct Hashable {}; >+ >+namespace std { >+template <> >+struct hash<Hashable> { >+ size_t operator()(const Hashable&) { return 0; } >+}; >+} // namespace std >+ >+struct NonHashable {}; >+ >+namespace { >+ >+std::string TypeQuals(std::string&) { return "&"; } >+std::string TypeQuals(std::string&&) { return "&&"; } >+std::string TypeQuals(const std::string&) { return "c&"; } >+std::string TypeQuals(const std::string&&) { return "c&&"; } >+ >+struct StructorListener { >+ int construct0 = 0; >+ int construct1 = 0; >+ int construct2 = 0; >+ int listinit = 0; >+ int copy = 0; >+ int move = 0; >+ int copy_assign = 0; >+ int move_assign = 0; >+ int destruct = 0; >+ int volatile_copy = 0; >+ int volatile_move = 0; >+ int volatile_copy_assign = 0; >+ int volatile_move_assign = 0; >+}; >+ >+// Suppress MSVC warnings. >+// 4521: multiple copy constructors specified >+// 4522: multiple assignment operators specified >+// We wrote multiple of them to test that the correct overloads are selected. >+#ifdef _MSC_VER >+#pragma warning( push ) >+#pragma warning( disable : 4521) >+#pragma warning( disable : 4522) >+#endif >+struct Listenable { >+ static StructorListener* listener; >+ >+ Listenable() { ++listener->construct0; } >+ explicit Listenable(int /*unused*/) { ++listener->construct1; } >+ Listenable(int /*unused*/, int /*unused*/) { ++listener->construct2; } >+ Listenable(std::initializer_list<int> /*unused*/) { ++listener->listinit; } >+ Listenable(const Listenable& /*unused*/) { ++listener->copy; } >+ Listenable(const volatile Listenable& /*unused*/) { >+ ++listener->volatile_copy; >+ } >+ Listenable(volatile Listenable&& /*unused*/) { ++listener->volatile_move; } >+ Listenable(Listenable&& /*unused*/) { ++listener->move; } >+ Listenable& operator=(const Listenable& /*unused*/) { >+ ++listener->copy_assign; >+ return *this; >+ } >+ Listenable& operator=(Listenable&& /*unused*/) { >+ ++listener->move_assign; >+ return *this; >+ } >+ // use void return type instead of volatile T& to work around GCC warning >+ // when the assignment's returned reference is ignored. >+ void operator=(const volatile Listenable& /*unused*/) volatile { >+ ++listener->volatile_copy_assign; >+ } >+ void operator=(volatile Listenable&& /*unused*/) volatile { >+ ++listener->volatile_move_assign; >+ } >+ ~Listenable() { ++listener->destruct; } >+}; >+#ifdef _MSC_VER >+#pragma warning( pop ) >+#endif >+ >+StructorListener* Listenable::listener = nullptr; >+ >+// ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST is defined to 1 when the standard >+// library implementation doesn't marked initializer_list's default constructor >+// constexpr. The C++11 standard doesn't specify constexpr on it, but C++14 >+// added it. However, libstdc++ 4.7 marked it constexpr. >+#if defined(_LIBCPP_VERSION) && \ >+ (_LIBCPP_STD_VER <= 11 || defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)) >+#define ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST 1 >+#endif >+ >+struct ConstexprType { >+ enum CtorTypes { >+ kCtorDefault, >+ kCtorInt, >+ kCtorInitializerList, >+ kCtorConstChar >+ }; >+ constexpr ConstexprType() : x(kCtorDefault) {} >+ constexpr explicit ConstexprType(int i) : x(kCtorInt) {} >+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST >+ constexpr ConstexprType(std::initializer_list<int> il) >+ : x(kCtorInitializerList) {} >+#endif >+ constexpr ConstexprType(const char*) // NOLINT(runtime/explicit) >+ : x(kCtorConstChar) {} >+ int x; >+}; >+ >+struct Copyable { >+ Copyable() {} >+ Copyable(const Copyable&) {} >+ Copyable& operator=(const Copyable&) { return *this; } >+}; >+ >+struct MoveableThrow { >+ MoveableThrow() {} >+ MoveableThrow(MoveableThrow&&) {} >+ MoveableThrow& operator=(MoveableThrow&&) { return *this; } >+}; >+ >+struct MoveableNoThrow { >+ MoveableNoThrow() {} >+ MoveableNoThrow(MoveableNoThrow&&) noexcept {} >+ MoveableNoThrow& operator=(MoveableNoThrow&&) noexcept { return *this; } >+}; >+ >+struct NonMovable { >+ NonMovable() {} >+ NonMovable(const NonMovable&) = delete; >+ NonMovable& operator=(const NonMovable&) = delete; >+ NonMovable(NonMovable&&) = delete; >+ NonMovable& operator=(NonMovable&&) = delete; >+}; >+ >+TEST(optionalTest, DefaultConstructor) { >+ absl::optional<int> empty; >+ EXPECT_FALSE(empty); >+ constexpr absl::optional<int> cempty; >+ static_assert(!cempty.has_value(), ""); >+ EXPECT_TRUE( >+ std::is_nothrow_default_constructible<absl::optional<int>>::value); >+} >+ >+TEST(optionalTest, nulloptConstructor) { >+ absl::optional<int> empty(absl::nullopt); >+ EXPECT_FALSE(empty); >+ >+#ifdef ABSL_HAVE_STD_OPTIONAL >+ constexpr absl::optional<int> cempty{absl::nullopt}; >+#else >+ // Creating a temporary absl::nullopt_t object instead of using absl::nullopt >+ // because absl::nullopt cannot be constexpr and have external linkage at the >+ // same time. >+ constexpr absl::optional<int> cempty{absl::nullopt_t(absl::nullopt_t::init)}; >+#endif >+ static_assert(!cempty.has_value(), ""); >+ EXPECT_TRUE((std::is_nothrow_constructible<absl::optional<int>, >+ absl::nullopt_t>::value)); >+} >+ >+TEST(optionalTest, CopyConstructor) { >+ { >+ absl::optional<int> empty, opt42 = 42; >+ absl::optional<int> empty_copy(empty); >+ EXPECT_FALSE(empty_copy); >+ absl::optional<int> opt42_copy(opt42); >+ EXPECT_TRUE(opt42_copy); >+ EXPECT_EQ(42, *opt42_copy); >+ } >+ { >+ absl::optional<const int> empty, opt42 = 42; >+ absl::optional<const int> empty_copy(empty); >+ EXPECT_FALSE(empty_copy); >+ absl::optional<const int> opt42_copy(opt42); >+ EXPECT_TRUE(opt42_copy); >+ EXPECT_EQ(42, *opt42_copy); >+ } >+ { >+ absl::optional<volatile int> empty, opt42 = 42; >+ absl::optional<volatile int> empty_copy(empty); >+ EXPECT_FALSE(empty_copy); >+ absl::optional<volatile int> opt42_copy(opt42); >+ EXPECT_TRUE(opt42_copy); >+ EXPECT_EQ(42, *opt42_copy); >+ } >+ // test copyablility >+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<int>>::value); >+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<Copyable>>::value); >+ EXPECT_FALSE( >+ std::is_copy_constructible<absl::optional<MoveableThrow>>::value); >+ EXPECT_FALSE( >+ std::is_copy_constructible<absl::optional<MoveableNoThrow>>::value); >+ EXPECT_FALSE(std::is_copy_constructible<absl::optional<NonMovable>>::value); >+ >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<absl::optional<Copyable>>::value); >+#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(__GLIBCXX__) >+ // libstdc++ std::optional implementation (as of 7.2) has a bug: when T is >+ // trivially copyable, optional<T> is not trivially copyable (due to one of >+ // its base class is unconditionally nontrivial). >+#define ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG 1 >+#endif >+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG >+ EXPECT_TRUE( >+ absl::is_trivially_copy_constructible<absl::optional<int>>::value); >+ EXPECT_TRUE( >+ absl::is_trivially_copy_constructible<absl::optional<const int>>::value); >+#ifndef _MSC_VER >+ // See defect report "Trivial copy/move constructor for class with volatile >+ // member" at >+ // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#2094 >+ // A class with non-static data member of volatile-qualified type should still >+ // have a trivial copy constructor if the data member is trivial. >+ // Also a cv-qualified scalar type should be trivially copyable. >+ EXPECT_TRUE(absl::is_trivially_copy_constructible< >+ absl::optional<volatile int>>::value); >+#endif // _MSC_VER >+#endif // ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG >+ >+ // constexpr copy constructor for trivially copyable types >+ { >+ constexpr absl::optional<int> o1; >+ constexpr absl::optional<int> o2 = o1; >+ static_assert(!o2, ""); >+ } >+ { >+ constexpr absl::optional<int> o1 = 42; >+ constexpr absl::optional<int> o2 = o1; >+ static_assert(o2, ""); >+ static_assert(*o2 == 42, ""); >+ } >+ { >+ struct TrivialCopyable { >+ constexpr TrivialCopyable() : x(0) {} >+ constexpr explicit TrivialCopyable(int i) : x(i) {} >+ int x; >+ }; >+ constexpr absl::optional<TrivialCopyable> o1(42); >+ constexpr absl::optional<TrivialCopyable> o2 = o1; >+ static_assert(o2, ""); >+ static_assert((*o2).x == 42, ""); >+#ifndef ABSL_GLIBCXX_OPTIONAL_TRIVIALITY_BUG >+ EXPECT_TRUE(absl::is_trivially_copy_constructible< >+ absl::optional<TrivialCopyable>>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible< >+ absl::optional<const TrivialCopyable>>::value); >+#endif >+ // When testing with VS 2017 15.3, there seems to be a bug in MSVC >+ // std::optional when T is volatile-qualified. So skipping this test. >+ // Bug report: >+ // https://connect.microsoft.com/VisualStudio/feedback/details/3142534 >+#if defined(ABSL_HAVE_STD_OPTIONAL) && defined(_MSC_VER) && _MSC_VER >= 1911 >+#define ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG 1 >+#endif >+#ifndef ABSL_MSVC_OPTIONAL_VOLATILE_COPY_BUG >+ EXPECT_FALSE(std::is_copy_constructible< >+ absl::optional<volatile TrivialCopyable>>::value); >+#endif >+ } >+} >+ >+TEST(optionalTest, MoveConstructor) { >+ absl::optional<int> empty, opt42 = 42; >+ absl::optional<int> empty_move(std::move(empty)); >+ EXPECT_FALSE(empty_move); >+ absl::optional<int> opt42_move(std::move(opt42)); >+ EXPECT_TRUE(opt42_move); >+ EXPECT_EQ(42, opt42_move); >+ // test movability >+ EXPECT_TRUE(std::is_move_constructible<absl::optional<int>>::value); >+ EXPECT_TRUE(std::is_move_constructible<absl::optional<Copyable>>::value); >+ EXPECT_TRUE(std::is_move_constructible<absl::optional<MoveableThrow>>::value); >+ EXPECT_TRUE( >+ std::is_move_constructible<absl::optional<MoveableNoThrow>>::value); >+ EXPECT_FALSE(std::is_move_constructible<absl::optional<NonMovable>>::value); >+ // test noexcept >+ EXPECT_TRUE(std::is_nothrow_move_constructible<absl::optional<int>>::value); >+#ifndef ABSL_HAVE_STD_OPTIONAL >+ EXPECT_EQ( >+ absl::default_allocator_is_nothrow::value, >+ std::is_nothrow_move_constructible<absl::optional<MoveableThrow>>::value); >+#endif >+ EXPECT_TRUE(std::is_nothrow_move_constructible< >+ absl::optional<MoveableNoThrow>>::value); >+} >+ >+TEST(optionalTest, Destructor) { >+ struct Trivial {}; >+ >+ struct NonTrivial { >+ NonTrivial(const NonTrivial&) {} >+ NonTrivial& operator=(const NonTrivial&) { return *this; } >+ ~NonTrivial() {} >+ }; >+ >+ EXPECT_TRUE(std::is_trivially_destructible<absl::optional<int>>::value); >+ EXPECT_TRUE(std::is_trivially_destructible<absl::optional<Trivial>>::value); >+ EXPECT_FALSE( >+ std::is_trivially_destructible<absl::optional<NonTrivial>>::value); >+} >+ >+TEST(optionalTest, InPlaceConstructor) { >+ constexpr absl::optional<ConstexprType> opt0{absl::in_place_t()}; >+ static_assert(opt0, ""); >+ static_assert((*opt0).x == ConstexprType::kCtorDefault, ""); >+ constexpr absl::optional<ConstexprType> opt1{absl::in_place_t(), 1}; >+ static_assert(opt1, ""); >+ static_assert((*opt1).x == ConstexprType::kCtorInt, ""); >+#ifndef ABSL_HAVE_NO_CONSTEXPR_INITIALIZER_LIST >+ constexpr absl::optional<ConstexprType> opt2{absl::in_place_t(), {1, 2}}; >+ static_assert(opt2, ""); >+ static_assert((*opt2).x == ConstexprType::kCtorInitializerList, ""); >+#endif >+ >+ // TODO(absl-team): uncomment these when std::is_constructible<T, Args&&...> >+ // SFINAE is added to optional::optional(absl::in_place_t, Args&&...). >+ // struct I { >+ // I(absl::in_place_t); >+ // }; >+ >+ // EXPECT_FALSE((std::is_constructible<absl::optional<I>, >+ // absl::in_place_t>::value)); >+ // EXPECT_FALSE((std::is_constructible<absl::optional<I>, const >+ // absl::in_place_t&>::value)); >+} >+ >+// template<U=T> optional(U&&); >+TEST(optionalTest, ValueConstructor) { >+ constexpr absl::optional<int> opt0(0); >+ static_assert(opt0, ""); >+ static_assert(*opt0 == 0, ""); >+ EXPECT_TRUE((std::is_convertible<int, absl::optional<int>>::value)); >+ // Copy initialization ( = "abc") won't work due to optional(optional&&) >+ // is not constexpr. Use list initialization instead. This invokes >+ // absl::optional<ConstexprType>::absl::optional<U>(U&&), with U = const char >+ // (&) [4], which direct-initializes the ConstexprType value held by the >+ // optional via ConstexprType::ConstexprType(const char*). >+ constexpr absl::optional<ConstexprType> opt1 = {"abc"}; >+ static_assert(opt1, ""); >+ static_assert(ConstexprType::kCtorConstChar == (*opt1).x, ""); >+ EXPECT_TRUE( >+ (std::is_convertible<const char*, absl::optional<ConstexprType>>::value)); >+ // direct initialization >+ constexpr absl::optional<ConstexprType> opt2{2}; >+ static_assert(opt2, ""); >+ static_assert(ConstexprType::kCtorInt == (*opt2).x, ""); >+ EXPECT_FALSE( >+ (std::is_convertible<int, absl::optional<ConstexprType>>::value)); >+ >+ // this invokes absl::optional<int>::optional(int&&) >+ // NOTE: this has different behavior than assignment, e.g. >+ // "opt3 = {};" clears the optional rather than setting the value to 0 >+ // According to C++17 standard N4659 [over.ics.list] 16.3.3.1.5, (9.2)- "if >+ // the initializer list has no elements, the implicit conversion is the >+ // identity conversion", so `optional(int&&)` should be a better match than >+ // `optional(optional&&)` which is a user-defined conversion. >+ // Note: GCC 7 has a bug with this overload selection when compiled with >+ // `-std=c++17`. >+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 7 && \ >+ __cplusplus == 201703L >+#define ABSL_GCC7_OVER_ICS_LIST_BUG 1 >+#endif >+#ifndef ABSL_GCC7_OVER_ICS_LIST_BUG >+ constexpr absl::optional<int> opt3({}); >+ static_assert(opt3, ""); >+ static_assert(*opt3 == 0, ""); >+#endif >+ >+ // this invokes the move constructor with a default constructed optional >+ // because non-template function is a better match than template function. >+ absl::optional<ConstexprType> opt4({}); >+ EXPECT_FALSE(opt4); >+} >+ >+struct Implicit {}; >+ >+struct Explicit {}; >+ >+struct Convert { >+ Convert(const Implicit&) // NOLINT(runtime/explicit) >+ : implicit(true), move(false) {} >+ Convert(Implicit&&) // NOLINT(runtime/explicit) >+ : implicit(true), move(true) {} >+ explicit Convert(const Explicit&) : implicit(false), move(false) {} >+ explicit Convert(Explicit&&) : implicit(false), move(true) {} >+ >+ bool implicit; >+ bool move; >+}; >+ >+struct ConvertFromOptional { >+ ConvertFromOptional(const Implicit&) // NOLINT(runtime/explicit) >+ : implicit(true), move(false), from_optional(false) {} >+ ConvertFromOptional(Implicit&&) // NOLINT(runtime/explicit) >+ : implicit(true), move(true), from_optional(false) {} >+ ConvertFromOptional( >+ const absl::optional<Implicit>&) // NOLINT(runtime/explicit) >+ : implicit(true), move(false), from_optional(true) {} >+ ConvertFromOptional(absl::optional<Implicit>&&) // NOLINT(runtime/explicit) >+ : implicit(true), move(true), from_optional(true) {} >+ explicit ConvertFromOptional(const Explicit&) >+ : implicit(false), move(false), from_optional(false) {} >+ explicit ConvertFromOptional(Explicit&&) >+ : implicit(false), move(true), from_optional(false) {} >+ explicit ConvertFromOptional(const absl::optional<Explicit>&) >+ : implicit(false), move(false), from_optional(true) {} >+ explicit ConvertFromOptional(absl::optional<Explicit>&&) >+ : implicit(false), move(true), from_optional(true) {} >+ >+ bool implicit; >+ bool move; >+ bool from_optional; >+}; >+ >+TEST(optionalTest, ConvertingConstructor) { >+ absl::optional<Implicit> i_empty; >+ absl::optional<Implicit> i(absl::in_place); >+ absl::optional<Explicit> e_empty; >+ absl::optional<Explicit> e(absl::in_place); >+ { >+ // implicitly constructing absl::optional<Convert> from >+ // absl::optional<Implicit> >+ absl::optional<Convert> empty = i_empty; >+ EXPECT_FALSE(empty); >+ absl::optional<Convert> opt_copy = i; >+ EXPECT_TRUE(opt_copy); >+ EXPECT_TRUE(opt_copy->implicit); >+ EXPECT_FALSE(opt_copy->move); >+ absl::optional<Convert> opt_move = absl::optional<Implicit>(absl::in_place); >+ EXPECT_TRUE(opt_move); >+ EXPECT_TRUE(opt_move->implicit); >+ EXPECT_TRUE(opt_move->move); >+ } >+ { >+ // explicitly constructing absl::optional<Convert> from >+ // absl::optional<Explicit> >+ absl::optional<Convert> empty(e_empty); >+ EXPECT_FALSE(empty); >+ absl::optional<Convert> opt_copy(e); >+ EXPECT_TRUE(opt_copy); >+ EXPECT_FALSE(opt_copy->implicit); >+ EXPECT_FALSE(opt_copy->move); >+ EXPECT_FALSE((std::is_convertible<const absl::optional<Explicit>&, >+ absl::optional<Convert>>::value)); >+ absl::optional<Convert> opt_move{absl::optional<Explicit>(absl::in_place)}; >+ EXPECT_TRUE(opt_move); >+ EXPECT_FALSE(opt_move->implicit); >+ EXPECT_TRUE(opt_move->move); >+ EXPECT_FALSE((std::is_convertible<absl::optional<Explicit>&&, >+ absl::optional<Convert>>::value)); >+ } >+ { >+ // implicitly constructing absl::optional<ConvertFromOptional> from >+ // absl::optional<Implicit> via >+ // ConvertFromOptional(absl::optional<Implicit>&&) check that >+ // ConvertFromOptional(Implicit&&) is NOT called >+ static_assert( >+ std::is_convertible<absl::optional<Implicit>, >+ absl::optional<ConvertFromOptional>>::value, >+ ""); >+ absl::optional<ConvertFromOptional> opt0 = i_empty; >+ EXPECT_TRUE(opt0); >+ EXPECT_TRUE(opt0->implicit); >+ EXPECT_FALSE(opt0->move); >+ EXPECT_TRUE(opt0->from_optional); >+ absl::optional<ConvertFromOptional> opt1 = absl::optional<Implicit>(); >+ EXPECT_TRUE(opt1); >+ EXPECT_TRUE(opt1->implicit); >+ EXPECT_TRUE(opt1->move); >+ EXPECT_TRUE(opt1->from_optional); >+ } >+ { >+ // implicitly constructing absl::optional<ConvertFromOptional> from >+ // absl::optional<Explicit> via >+ // ConvertFromOptional(absl::optional<Explicit>&&) check that >+ // ConvertFromOptional(Explicit&&) is NOT called >+ absl::optional<ConvertFromOptional> opt0(e_empty); >+ EXPECT_TRUE(opt0); >+ EXPECT_FALSE(opt0->implicit); >+ EXPECT_FALSE(opt0->move); >+ EXPECT_TRUE(opt0->from_optional); >+ EXPECT_FALSE( >+ (std::is_convertible<const absl::optional<Explicit>&, >+ absl::optional<ConvertFromOptional>>::value)); >+ absl::optional<ConvertFromOptional> opt1{absl::optional<Explicit>()}; >+ EXPECT_TRUE(opt1); >+ EXPECT_FALSE(opt1->implicit); >+ EXPECT_TRUE(opt1->move); >+ EXPECT_TRUE(opt1->from_optional); >+ EXPECT_FALSE( >+ (std::is_convertible<absl::optional<Explicit>&&, >+ absl::optional<ConvertFromOptional>>::value)); >+ } >+} >+ >+TEST(optionalTest, StructorBasic) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ { >+ absl::optional<Listenable> empty; >+ EXPECT_FALSE(empty); >+ absl::optional<Listenable> opt0(absl::in_place); >+ EXPECT_TRUE(opt0); >+ absl::optional<Listenable> opt1(absl::in_place, 1); >+ EXPECT_TRUE(opt1); >+ absl::optional<Listenable> opt2(absl::in_place, 1, 2); >+ EXPECT_TRUE(opt2); >+ } >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.construct1); >+ EXPECT_EQ(1, listener.construct2); >+ EXPECT_EQ(3, listener.destruct); >+} >+ >+TEST(optionalTest, CopyMoveStructor) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> original(absl::in_place); >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(0, listener.copy); >+ EXPECT_EQ(0, listener.move); >+ absl::optional<Listenable> copy(original); >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.copy); >+ EXPECT_EQ(0, listener.move); >+ absl::optional<Listenable> move(std::move(original)); >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.copy); >+ EXPECT_EQ(1, listener.move); >+} >+ >+TEST(optionalTest, ListInit) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> listinit1(absl::in_place, {1}); >+ absl::optional<Listenable> listinit2(absl::in_place, {1, 2}); >+ EXPECT_EQ(2, listener.listinit); >+} >+ >+TEST(optionalTest, AssignFromNullopt) { >+ absl::optional<int> opt(1); >+ opt = absl::nullopt; >+ EXPECT_FALSE(opt); >+ >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> opt1(absl::in_place); >+ opt1 = absl::nullopt; >+ EXPECT_FALSE(opt1); >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.destruct); >+ >+ EXPECT_TRUE(( >+ std::is_nothrow_assignable<absl::optional<int>, absl::nullopt_t>::value)); >+ EXPECT_TRUE((std::is_nothrow_assignable<absl::optional<Listenable>, >+ absl::nullopt_t>::value)); >+} >+ >+TEST(optionalTest, CopyAssignment) { >+ const absl::optional<int> empty, opt1 = 1, opt2 = 2; >+ absl::optional<int> empty_to_opt1, opt1_to_opt2, opt2_to_empty; >+ >+ EXPECT_FALSE(empty_to_opt1); >+ empty_to_opt1 = empty; >+ EXPECT_FALSE(empty_to_opt1); >+ empty_to_opt1 = opt1; >+ EXPECT_TRUE(empty_to_opt1); >+ EXPECT_EQ(1, empty_to_opt1.value()); >+ >+ EXPECT_FALSE(opt1_to_opt2); >+ opt1_to_opt2 = opt1; >+ EXPECT_TRUE(opt1_to_opt2); >+ EXPECT_EQ(1, opt1_to_opt2.value()); >+ opt1_to_opt2 = opt2; >+ EXPECT_TRUE(opt1_to_opt2); >+ EXPECT_EQ(2, opt1_to_opt2.value()); >+ >+ EXPECT_FALSE(opt2_to_empty); >+ opt2_to_empty = opt2; >+ EXPECT_TRUE(opt2_to_empty); >+ EXPECT_EQ(2, opt2_to_empty.value()); >+ opt2_to_empty = empty; >+ EXPECT_FALSE(opt2_to_empty); >+ >+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<const int>>::value); >+ EXPECT_TRUE(std::is_copy_assignable<absl::optional<Copyable>>::value); >+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableThrow>>::value); >+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<MoveableNoThrow>>::value); >+ EXPECT_FALSE(std::is_copy_assignable<absl::optional<NonMovable>>::value); >+ >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<int>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<volatile int>::value); >+ >+ struct Trivial { >+ int i; >+ }; >+ struct NonTrivial { >+ NonTrivial& operator=(const NonTrivial&) { return *this; } >+ int i; >+ }; >+ >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<Trivial>::value); >+ EXPECT_FALSE(std::is_copy_assignable<const Trivial>::value); >+ EXPECT_FALSE(std::is_copy_assignable<volatile Trivial>::value); >+ EXPECT_TRUE(std::is_copy_assignable<NonTrivial>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<NonTrivial>::value); >+ >+ // std::optional doesn't support volatile nontrivial types. >+#ifndef ABSL_HAVE_STD_OPTIONAL >+ { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ absl::optional<volatile Listenable> empty, set(absl::in_place); >+ EXPECT_EQ(1, listener.construct0); >+ absl::optional<volatile Listenable> empty_to_empty, empty_to_set, >+ set_to_empty(absl::in_place), set_to_set(absl::in_place); >+ EXPECT_EQ(3, listener.construct0); >+ empty_to_empty = empty; // no effect >+ empty_to_set = set; // copy construct >+ set_to_empty = empty; // destruct >+ set_to_set = set; // copy assign >+ EXPECT_EQ(1, listener.volatile_copy); >+ EXPECT_EQ(0, listener.volatile_move); >+ EXPECT_EQ(1, listener.destruct); >+ EXPECT_EQ(1, listener.volatile_copy_assign); >+ } >+#endif // ABSL_HAVE_STD_OPTIONAL >+} >+ >+TEST(optionalTest, MoveAssignment) { >+ { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ absl::optional<Listenable> empty1, empty2, set1(absl::in_place), >+ set2(absl::in_place); >+ EXPECT_EQ(2, listener.construct0); >+ absl::optional<Listenable> empty_to_empty, empty_to_set, >+ set_to_empty(absl::in_place), set_to_set(absl::in_place); >+ EXPECT_EQ(4, listener.construct0); >+ empty_to_empty = std::move(empty1); >+ empty_to_set = std::move(set1); >+ set_to_empty = std::move(empty2); >+ set_to_set = std::move(set2); >+ EXPECT_EQ(0, listener.copy); >+ EXPECT_EQ(1, listener.move); >+ EXPECT_EQ(1, listener.destruct); >+ EXPECT_EQ(1, listener.move_assign); >+ } >+ // std::optional doesn't support volatile nontrivial types. >+#ifndef ABSL_HAVE_STD_OPTIONAL >+ { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ absl::optional<volatile Listenable> empty1, empty2, set1(absl::in_place), >+ set2(absl::in_place); >+ EXPECT_EQ(2, listener.construct0); >+ absl::optional<volatile Listenable> empty_to_empty, empty_to_set, >+ set_to_empty(absl::in_place), set_to_set(absl::in_place); >+ EXPECT_EQ(4, listener.construct0); >+ empty_to_empty = std::move(empty1); // no effect >+ empty_to_set = std::move(set1); // move construct >+ set_to_empty = std::move(empty2); // destruct >+ set_to_set = std::move(set2); // move assign >+ EXPECT_EQ(0, listener.volatile_copy); >+ EXPECT_EQ(1, listener.volatile_move); >+ EXPECT_EQ(1, listener.destruct); >+ EXPECT_EQ(1, listener.volatile_move_assign); >+ } >+#endif // ABSL_HAVE_STD_OPTIONAL >+ EXPECT_FALSE(std::is_move_assignable<absl::optional<const int>>::value); >+ EXPECT_TRUE(std::is_move_assignable<absl::optional<Copyable>>::value); >+ EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableThrow>>::value); >+ EXPECT_TRUE(std::is_move_assignable<absl::optional<MoveableNoThrow>>::value); >+ EXPECT_FALSE(std::is_move_assignable<absl::optional<NonMovable>>::value); >+ >+ EXPECT_FALSE( >+ std::is_nothrow_move_assignable<absl::optional<MoveableThrow>>::value); >+ EXPECT_TRUE( >+ std::is_nothrow_move_assignable<absl::optional<MoveableNoThrow>>::value); >+} >+ >+struct NoConvertToOptional { >+ // disable implicit conversion from const NoConvertToOptional& >+ // to absl::optional<NoConvertToOptional>. >+ NoConvertToOptional(const NoConvertToOptional&) = delete; >+}; >+ >+struct CopyConvert { >+ CopyConvert(const NoConvertToOptional&); >+ CopyConvert& operator=(const CopyConvert&) = delete; >+ CopyConvert& operator=(const NoConvertToOptional&); >+}; >+ >+struct CopyConvertFromOptional { >+ CopyConvertFromOptional(const NoConvertToOptional&); >+ CopyConvertFromOptional(const absl::optional<NoConvertToOptional>&); >+ CopyConvertFromOptional& operator=(const CopyConvertFromOptional&) = delete; >+ CopyConvertFromOptional& operator=(const NoConvertToOptional&); >+ CopyConvertFromOptional& operator=( >+ const absl::optional<NoConvertToOptional>&); >+}; >+ >+struct MoveConvert { >+ MoveConvert(NoConvertToOptional&&); >+ MoveConvert& operator=(const MoveConvert&) = delete; >+ MoveConvert& operator=(NoConvertToOptional&&); >+}; >+ >+struct MoveConvertFromOptional { >+ MoveConvertFromOptional(NoConvertToOptional&&); >+ MoveConvertFromOptional(absl::optional<NoConvertToOptional>&&); >+ MoveConvertFromOptional& operator=(const MoveConvertFromOptional&) = delete; >+ MoveConvertFromOptional& operator=(NoConvertToOptional&&); >+ MoveConvertFromOptional& operator=(absl::optional<NoConvertToOptional>&&); >+}; >+ >+// template <typename U = T> absl::optional<T>& operator=(U&& v); >+TEST(optionalTest, ValueAssignment) { >+ absl::optional<int> opt; >+ EXPECT_FALSE(opt); >+ opt = 42; >+ EXPECT_TRUE(opt); >+ EXPECT_EQ(42, opt.value()); >+ opt = absl::nullopt; >+ EXPECT_FALSE(opt); >+ opt = 42; >+ EXPECT_TRUE(opt); >+ EXPECT_EQ(42, opt.value()); >+ opt = 43; >+ EXPECT_TRUE(opt); >+ EXPECT_EQ(43, opt.value()); >+ opt = {}; // this should clear optional >+ EXPECT_FALSE(opt); >+ >+ opt = {44}; >+ EXPECT_TRUE(opt); >+ EXPECT_EQ(44, opt.value()); >+ >+ // U = const NoConvertToOptional& >+ EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvert>&, >+ const NoConvertToOptional&>::value)); >+ // U = const absl::optional<NoConvertToOptional>& >+ EXPECT_TRUE((std::is_assignable<absl::optional<CopyConvertFromOptional>&, >+ const NoConvertToOptional&>::value)); >+ // U = const NoConvertToOptional& triggers SFINAE because >+ // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false >+ EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvert>&, >+ const NoConvertToOptional&>::value)); >+ // U = NoConvertToOptional >+ EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvert>&, >+ NoConvertToOptional&&>::value)); >+ // U = const NoConvertToOptional& triggers SFINAE because >+ // std::is_constructible_v<MoveConvertFromOptional, const >+ // NoConvertToOptional&> is false >+ EXPECT_FALSE((std::is_assignable<absl::optional<MoveConvertFromOptional>&, >+ const NoConvertToOptional&>::value)); >+ // U = NoConvertToOptional >+ EXPECT_TRUE((std::is_assignable<absl::optional<MoveConvertFromOptional>&, >+ NoConvertToOptional&&>::value)); >+ // U = const absl::optional<NoConvertToOptional>& >+ EXPECT_TRUE( >+ (std::is_assignable<absl::optional<CopyConvertFromOptional>&, >+ const absl::optional<NoConvertToOptional>&>::value)); >+ // U = absl::optional<NoConvertToOptional> >+ EXPECT_TRUE( >+ (std::is_assignable<absl::optional<MoveConvertFromOptional>&, >+ absl::optional<NoConvertToOptional>&&>::value)); >+} >+ >+// template <typename U> absl::optional<T>& operator=(const absl::optional<U>& >+// rhs); template <typename U> absl::optional<T>& operator=(absl::optional<U>&& >+// rhs); >+TEST(optionalTest, ConvertingAssignment) { >+ absl::optional<int> opt_i; >+ absl::optional<char> opt_c('c'); >+ opt_i = opt_c; >+ EXPECT_TRUE(opt_i); >+ EXPECT_EQ(*opt_c, *opt_i); >+ opt_i = absl::optional<char>(); >+ EXPECT_FALSE(opt_i); >+ opt_i = absl::optional<char>('d'); >+ EXPECT_TRUE(opt_i); >+ EXPECT_EQ('d', *opt_i); >+ >+ absl::optional<std::string> opt_str; >+ absl::optional<const char*> opt_cstr("abc"); >+ opt_str = opt_cstr; >+ EXPECT_TRUE(opt_str); >+ EXPECT_EQ(std::string("abc"), *opt_str); >+ opt_str = absl::optional<const char*>(); >+ EXPECT_FALSE(opt_str); >+ opt_str = absl::optional<const char*>("def"); >+ EXPECT_TRUE(opt_str); >+ EXPECT_EQ(std::string("def"), *opt_str); >+ >+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional >+ EXPECT_TRUE( >+ (std::is_assignable<absl::optional<CopyConvert>, >+ const absl::optional<NoConvertToOptional>&>::value)); >+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional >+ // triggers SFINAE because >+ // std::is_constructible_v<MoveConvert, const NoConvertToOptional&> is false >+ EXPECT_FALSE( >+ (std::is_assignable<absl::optional<MoveConvert>&, >+ const absl::optional<NoConvertToOptional>&>::value)); >+ // operator=(absl::optional<U>&&) with U = NoConvertToOptional >+ EXPECT_TRUE( >+ (std::is_assignable<absl::optional<MoveConvert>&, >+ absl::optional<NoConvertToOptional>&&>::value)); >+ // operator=(const absl::optional<U>&) with U = NoConvertToOptional triggers >+ // SFINAE because std::is_constructible_v<MoveConvertFromOptional, const >+ // NoConvertToOptional&> is false. operator=(U&&) with U = const >+ // absl::optional<NoConverToOptional>& triggers SFINAE because >+ // std::is_constructible<MoveConvertFromOptional, >+ // absl::optional<NoConvertToOptional>&&> is true. >+ EXPECT_FALSE( >+ (std::is_assignable<absl::optional<MoveConvertFromOptional>&, >+ const absl::optional<NoConvertToOptional>&>::value)); >+} >+ >+TEST(optionalTest, ResetAndHasValue) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> opt; >+ EXPECT_FALSE(opt); >+ EXPECT_FALSE(opt.has_value()); >+ opt.emplace(); >+ EXPECT_TRUE(opt); >+ EXPECT_TRUE(opt.has_value()); >+ opt.reset(); >+ EXPECT_FALSE(opt); >+ EXPECT_FALSE(opt.has_value()); >+ EXPECT_EQ(1, listener.destruct); >+ opt.reset(); >+ EXPECT_FALSE(opt); >+ EXPECT_FALSE(opt.has_value()); >+ >+ constexpr absl::optional<int> empty; >+ static_assert(!empty.has_value(), ""); >+ constexpr absl::optional<int> nonempty(1); >+ static_assert(nonempty.has_value(), ""); >+} >+ >+TEST(optionalTest, Emplace) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> opt; >+ EXPECT_FALSE(opt); >+ opt.emplace(1); >+ EXPECT_TRUE(opt); >+ opt.emplace(1, 2); >+ EXPECT_EQ(1, listener.construct1); >+ EXPECT_EQ(1, listener.construct2); >+ EXPECT_EQ(1, listener.destruct); >+ >+ absl::optional<std::string> o; >+ EXPECT_TRUE((std::is_same<std::string&, decltype(o.emplace("abc"))>::value)); >+ std::string& ref = o.emplace("abc"); >+ EXPECT_EQ(&ref, &o.value()); >+} >+ >+TEST(optionalTest, ListEmplace) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ absl::optional<Listenable> opt; >+ EXPECT_FALSE(opt); >+ opt.emplace({1}); >+ EXPECT_TRUE(opt); >+ opt.emplace({1, 2}); >+ EXPECT_EQ(2, listener.listinit); >+ EXPECT_EQ(1, listener.destruct); >+ >+ absl::optional<Listenable> o; >+ EXPECT_TRUE((std::is_same<Listenable&, decltype(o.emplace({1}))>::value)); >+ Listenable& ref = o.emplace({1}); >+ EXPECT_EQ(&ref, &o.value()); >+} >+ >+TEST(optionalTest, Swap) { >+ absl::optional<int> opt_empty, opt1 = 1, opt2 = 2; >+ EXPECT_FALSE(opt_empty); >+ EXPECT_TRUE(opt1); >+ EXPECT_EQ(1, opt1.value()); >+ EXPECT_TRUE(opt2); >+ EXPECT_EQ(2, opt2.value()); >+ swap(opt_empty, opt1); >+ EXPECT_FALSE(opt1); >+ EXPECT_TRUE(opt_empty); >+ EXPECT_EQ(1, opt_empty.value()); >+ EXPECT_TRUE(opt2); >+ EXPECT_EQ(2, opt2.value()); >+ swap(opt_empty, opt1); >+ EXPECT_FALSE(opt_empty); >+ EXPECT_TRUE(opt1); >+ EXPECT_EQ(1, opt1.value()); >+ EXPECT_TRUE(opt2); >+ EXPECT_EQ(2, opt2.value()); >+ swap(opt1, opt2); >+ EXPECT_FALSE(opt_empty); >+ EXPECT_TRUE(opt1); >+ EXPECT_EQ(2, opt1.value()); >+ EXPECT_TRUE(opt2); >+ EXPECT_EQ(1, opt2.value()); >+ >+ EXPECT_TRUE(noexcept(opt1.swap(opt2))); >+ EXPECT_TRUE(noexcept(swap(opt1, opt2))); >+} >+ >+template <int v> >+struct DeletedOpAddr { >+ constexpr static const int value = v; >+ constexpr DeletedOpAddr() = default; >+ constexpr const DeletedOpAddr<v>* operator&() const = delete; // NOLINT >+ DeletedOpAddr<v>* operator&() = delete; // NOLINT >+}; >+ >+// The static_assert featuring a constexpr call to operator->() is commented out >+// to document the fact that the current implementation of absl::optional<T> >+// expects such usecases to be malformed and not compile. >+TEST(optionalTest, OperatorAddr) { >+ constexpr const int v = -1; >+ { // constexpr >+ constexpr const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{}); >+ static_assert(opt.has_value(), ""); >+ // static_assert(opt->value == v, ""); >+ static_assert((*opt).value == v, ""); >+ } >+ { // non-constexpr >+ const absl::optional<DeletedOpAddr<v>> opt(absl::in_place_t{}); >+ EXPECT_TRUE(opt.has_value()); >+ EXPECT_TRUE(opt->value == v); >+ EXPECT_TRUE((*opt).value == v); >+ } >+} >+ >+TEST(optionalTest, PointerStuff) { >+ absl::optional<std::string> opt(absl::in_place, "foo"); >+ EXPECT_EQ("foo", *opt); >+ const auto& opt_const = opt; >+ EXPECT_EQ("foo", *opt_const); >+ EXPECT_EQ(opt->size(), 3); >+ EXPECT_EQ(opt_const->size(), 3); >+ >+ constexpr absl::optional<ConstexprType> opt1(1); >+ static_assert((*opt1).x == ConstexprType::kCtorInt, ""); >+} >+ >+// gcc has a bug pre 4.9.1 where it doesn't do correct overload resolution >+// when overloads are const-qualified and *this is an raluve. >+// Skip that test to make the build green again when using the old compiler. >+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59296 is fixed in 4.9.1. >+#if defined(__GNUC__) && !defined(__clang__) >+#define GCC_VERSION (__GNUC__ * 10000 \ >+ + __GNUC_MINOR__ * 100 \ >+ + __GNUC_PATCHLEVEL__) >+#if GCC_VERSION < 40901 >+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG >+#endif >+#endif >+ >+// MSVC has a bug with "cv-qualifiers in class construction", fixed in 2017. See >+// https://docs.microsoft.com/en-us/cpp/cpp-conformance-improvements-2017#bug-fixes >+// The compiler some incorrectly ingores the cv-qualifier when generating a >+// class object via a constructor call. For example: >+// >+// class optional { >+// constexpr T&& value() &&; >+// constexpr const T&& value() const &&; >+// } >+// >+// using COI = const absl::optional<int>; >+// static_assert(2 == COI(2).value(), ""); // const && >+// >+// This should invoke the "const &&" overload but since it ignores the const >+// qualifier it finds the "&&" overload the best candidate. >+#if defined(_MSC_VER) && _MSC_VER < 1910 >+#define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG >+#endif >+ >+TEST(optionalTest, Value) { >+ using O = absl::optional<std::string>; >+ using CO = const absl::optional<std::string>; >+ using OC = absl::optional<const std::string>; >+ O lvalue(absl::in_place, "lvalue"); >+ CO clvalue(absl::in_place, "clvalue"); >+ OC lvalue_c(absl::in_place, "lvalue_c"); >+ EXPECT_EQ("lvalue", lvalue.value()); >+ EXPECT_EQ("clvalue", clvalue.value()); >+ EXPECT_EQ("lvalue_c", lvalue_c.value()); >+ EXPECT_EQ("xvalue", O(absl::in_place, "xvalue").value()); >+ EXPECT_EQ("xvalue_c", OC(absl::in_place, "xvalue_c").value()); >+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG >+ EXPECT_EQ("cxvalue", CO(absl::in_place, "cxvalue").value()); >+#endif >+ EXPECT_EQ("&", TypeQuals(lvalue.value())); >+ EXPECT_EQ("c&", TypeQuals(clvalue.value())); >+ EXPECT_EQ("c&", TypeQuals(lvalue_c.value())); >+ EXPECT_EQ("&&", TypeQuals(O(absl::in_place, "xvalue").value())); >+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \ >+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) >+ EXPECT_EQ("c&&", TypeQuals(CO(absl::in_place, "cxvalue").value())); >+#endif >+ EXPECT_EQ("c&&", TypeQuals(OC(absl::in_place, "xvalue_c").value())); >+ >+ // test on volatile type >+ using OV = absl::optional<volatile int>; >+ OV lvalue_v(absl::in_place, 42); >+ EXPECT_EQ(42, lvalue_v.value()); >+ EXPECT_EQ(42, OV(42).value()); >+ EXPECT_TRUE((std::is_same<volatile int&, decltype(lvalue_v.value())>::value)); >+ EXPECT_TRUE((std::is_same<volatile int&&, decltype(OV(42).value())>::value)); >+ >+ // test exception throw on value() >+ absl::optional<int> empty; >+#ifdef ABSL_HAVE_EXCEPTIONS >+ EXPECT_THROW(empty.value(), absl::bad_optional_access); >+#else >+ EXPECT_DEATH(empty.value(), "Bad optional access"); >+#endif >+ >+ // test constexpr value() >+ constexpr absl::optional<int> o1(1); >+ static_assert(1 == o1.value(), ""); // const & >+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \ >+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) >+ using COI = const absl::optional<int>; >+ static_assert(2 == COI(2).value(), ""); // const && >+#endif >+} >+ >+TEST(optionalTest, DerefOperator) { >+ using O = absl::optional<std::string>; >+ using CO = const absl::optional<std::string>; >+ using OC = absl::optional<const std::string>; >+ O lvalue(absl::in_place, "lvalue"); >+ CO clvalue(absl::in_place, "clvalue"); >+ OC lvalue_c(absl::in_place, "lvalue_c"); >+ EXPECT_EQ("lvalue", *lvalue); >+ EXPECT_EQ("clvalue", *clvalue); >+ EXPECT_EQ("lvalue_c", *lvalue_c); >+ EXPECT_EQ("xvalue", *O(absl::in_place, "xvalue")); >+ EXPECT_EQ("xvalue_c", *OC(absl::in_place, "xvalue_c")); >+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG >+ EXPECT_EQ("cxvalue", *CO(absl::in_place, "cxvalue")); >+#endif >+ EXPECT_EQ("&", TypeQuals(*lvalue)); >+ EXPECT_EQ("c&", TypeQuals(*clvalue)); >+ EXPECT_EQ("&&", TypeQuals(*O(absl::in_place, "xvalue"))); >+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \ >+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) >+ EXPECT_EQ("c&&", TypeQuals(*CO(absl::in_place, "cxvalue"))); >+#endif >+ EXPECT_EQ("c&&", TypeQuals(*OC(absl::in_place, "xvalue_c"))); >+ >+ // test on volatile type >+ using OV = absl::optional<volatile int>; >+ OV lvalue_v(absl::in_place, 42); >+ EXPECT_EQ(42, *lvalue_v); >+ EXPECT_EQ(42, *OV(42)); >+ EXPECT_TRUE((std::is_same<volatile int&, decltype(*lvalue_v)>::value)); >+ EXPECT_TRUE((std::is_same<volatile int&&, decltype(*OV(42))>::value)); >+ >+ constexpr absl::optional<int> opt1(1); >+ static_assert(*opt1 == 1, ""); >+#if !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG) && \ >+ !defined(ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG) >+ using COI = const absl::optional<int>; >+ static_assert(*COI(2) == 2, ""); >+#endif >+} >+ >+TEST(optionalTest, ValueOr) { >+ absl::optional<double> opt_empty, opt_set = 1.2; >+ EXPECT_EQ(42.0, opt_empty.value_or(42)); >+ EXPECT_EQ(1.2, opt_set.value_or(42)); >+ EXPECT_EQ(42.0, absl::optional<double>().value_or(42)); >+ EXPECT_EQ(1.2, absl::optional<double>(1.2).value_or(42)); >+ >+ constexpr absl::optional<double> copt_empty, copt_set = {1.2}; >+ static_assert(42.0 == copt_empty.value_or(42), ""); >+ static_assert(1.2 == copt_set.value_or(42), ""); >+#ifndef ABSL_SKIP_OVERLOAD_TEST_DUE_TO_MSVC_BUG >+ using COD = const absl::optional<double>; >+ static_assert(42.0 == COD().value_or(42), ""); >+ static_assert(1.2 == COD(1.2).value_or(42), ""); >+#endif >+} >+ >+// make_optional cannot be constexpr until C++17 >+TEST(optionalTest, make_optional) { >+ auto opt_int = absl::make_optional(42); >+ EXPECT_TRUE((std::is_same<decltype(opt_int), absl::optional<int>>::value)); >+ EXPECT_EQ(42, opt_int); >+ >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ absl::optional<Listenable> opt0 = absl::make_optional<Listenable>(); >+ EXPECT_EQ(1, listener.construct0); >+ absl::optional<Listenable> opt1 = absl::make_optional<Listenable>(1); >+ EXPECT_EQ(1, listener.construct1); >+ absl::optional<Listenable> opt2 = absl::make_optional<Listenable>(1, 2); >+ EXPECT_EQ(1, listener.construct2); >+ absl::optional<Listenable> opt3 = absl::make_optional<Listenable>({1}); >+ absl::optional<Listenable> opt4 = absl::make_optional<Listenable>({1, 2}); >+ EXPECT_EQ(2, listener.listinit); >+ >+ // Constexpr tests on trivially copyable types >+ // optional<T> has trivial copy/move ctors when T is trivially copyable. >+ // For nontrivial types with constexpr constructors, we need copy elision in >+ // C++17 for make_optional to be constexpr. >+ { >+ constexpr absl::optional<int> c_opt = absl::make_optional(42); >+ static_assert(c_opt.value() == 42, ""); >+ } >+ { >+ struct TrivialCopyable { >+ constexpr TrivialCopyable() : x(0) {} >+ constexpr explicit TrivialCopyable(int i) : x(i) {} >+ int x; >+ }; >+ >+ constexpr TrivialCopyable v; >+ constexpr absl::optional<TrivialCopyable> c_opt0 = absl::make_optional(v); >+ static_assert((*c_opt0).x == 0, ""); >+ constexpr absl::optional<TrivialCopyable> c_opt1 = >+ absl::make_optional<TrivialCopyable>(); >+ static_assert((*c_opt1).x == 0, ""); >+ constexpr absl::optional<TrivialCopyable> c_opt2 = >+ absl::make_optional<TrivialCopyable>(42); >+ static_assert((*c_opt2).x == 42, ""); >+ } >+} >+ >+template <typename T, typename U> >+void optionalTest_Comparisons_EXPECT_LESS(T x, U y) { >+ EXPECT_FALSE(x == y); >+ EXPECT_TRUE(x != y); >+ EXPECT_TRUE(x < y); >+ EXPECT_FALSE(x > y); >+ EXPECT_TRUE(x <= y); >+ EXPECT_FALSE(x >= y); >+} >+ >+template <typename T, typename U> >+void optionalTest_Comparisons_EXPECT_SAME(T x, U y) { >+ EXPECT_TRUE(x == y); >+ EXPECT_FALSE(x != y); >+ EXPECT_FALSE(x < y); >+ EXPECT_FALSE(x > y); >+ EXPECT_TRUE(x <= y); >+ EXPECT_TRUE(x >= y); >+} >+ >+template <typename T, typename U> >+void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) { >+ EXPECT_FALSE(x == y); >+ EXPECT_TRUE(x != y); >+ EXPECT_FALSE(x < y); >+ EXPECT_TRUE(x > y); >+ EXPECT_FALSE(x <= y); >+ EXPECT_TRUE(x >= y); >+} >+ >+ >+template <typename T, typename U, typename V> >+void TestComparisons() { >+ absl::optional<T> ae, a2{2}, a4{4}; >+ absl::optional<U> be, b2{2}, b4{4}; >+ V v3 = 3; >+ >+ // LHS: absl::nullopt, ae, a2, v3, a4 >+ // RHS: absl::nullopt, be, b2, v3, b4 >+ >+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,absl::nullopt); >+ optionalTest_Comparisons_EXPECT_SAME(absl::nullopt, be); >+ optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b2); >+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(absl::nullopt,v3); >+ optionalTest_Comparisons_EXPECT_LESS(absl::nullopt, b4); >+ >+ optionalTest_Comparisons_EXPECT_SAME(ae, absl::nullopt); >+ optionalTest_Comparisons_EXPECT_SAME(ae, be); >+ optionalTest_Comparisons_EXPECT_LESS(ae, b2); >+ optionalTest_Comparisons_EXPECT_LESS(ae, v3); >+ optionalTest_Comparisons_EXPECT_LESS(ae, b4); >+ >+ optionalTest_Comparisons_EXPECT_GREATER(a2, absl::nullopt); >+ optionalTest_Comparisons_EXPECT_GREATER(a2, be); >+ optionalTest_Comparisons_EXPECT_SAME(a2, b2); >+ optionalTest_Comparisons_EXPECT_LESS(a2, v3); >+ optionalTest_Comparisons_EXPECT_LESS(a2, b4); >+ >+ // optionalTest_Comparisons_EXPECT_NOT_TO_WORK(v3,absl::nullopt); >+ optionalTest_Comparisons_EXPECT_GREATER(v3, be); >+ optionalTest_Comparisons_EXPECT_GREATER(v3, b2); >+ optionalTest_Comparisons_EXPECT_SAME(v3, v3); >+ optionalTest_Comparisons_EXPECT_LESS(v3, b4); >+ >+ optionalTest_Comparisons_EXPECT_GREATER(a4, absl::nullopt); >+ optionalTest_Comparisons_EXPECT_GREATER(a4, be); >+ optionalTest_Comparisons_EXPECT_GREATER(a4, b2); >+ optionalTest_Comparisons_EXPECT_GREATER(a4, v3); >+ optionalTest_Comparisons_EXPECT_SAME(a4, b4); >+} >+ >+struct Int1 { >+ Int1() = default; >+ Int1(int i) : i(i) {} // NOLINT(runtime/explicit) >+ int i; >+}; >+ >+struct Int2 { >+ Int2() = default; >+ Int2(int i) : i(i) {} // NOLINT(runtime/explicit) >+ int i; >+}; >+ >+// comparison between Int1 and Int2 >+constexpr bool operator==(const Int1& lhs, const Int2& rhs) { >+ return lhs.i == rhs.i; >+} >+constexpr bool operator!=(const Int1& lhs, const Int2& rhs) { >+ return !(lhs == rhs); >+} >+constexpr bool operator<(const Int1& lhs, const Int2& rhs) { >+ return lhs.i < rhs.i; >+} >+constexpr bool operator<=(const Int1& lhs, const Int2& rhs) { >+ return lhs < rhs || lhs == rhs; >+} >+constexpr bool operator>(const Int1& lhs, const Int2& rhs) { >+ return !(lhs <= rhs); >+} >+constexpr bool operator>=(const Int1& lhs, const Int2& rhs) { >+ return !(lhs < rhs); >+} >+ >+TEST(optionalTest, Comparisons) { >+ TestComparisons<int, int, int>(); >+ TestComparisons<const int, int, int>(); >+ TestComparisons<Int1, int, int>(); >+ TestComparisons<int, Int2, int>(); >+ TestComparisons<Int1, Int2, int>(); >+ >+ // compare absl::optional<std::string> with const char* >+ absl::optional<std::string> opt_str = "abc"; >+ const char* cstr = "abc"; >+ EXPECT_TRUE(opt_str == cstr); >+ // compare absl::optional<std::string> with absl::optional<const char*> >+ absl::optional<const char*> opt_cstr = cstr; >+ EXPECT_TRUE(opt_str == opt_cstr); >+ // compare absl::optional<std::string> with absl::optional<absl::string_view> >+ absl::optional<absl::string_view> e1; >+ absl::optional<std::string> e2; >+ EXPECT_TRUE(e1 == e2); >+} >+ >+ >+TEST(optionalTest, SwapRegression) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ { >+ absl::optional<Listenable> a; >+ absl::optional<Listenable> b(absl::in_place); >+ a.swap(b); >+ } >+ >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.move); >+ EXPECT_EQ(2, listener.destruct); >+ >+ { >+ absl::optional<Listenable> a(absl::in_place); >+ absl::optional<Listenable> b; >+ a.swap(b); >+ } >+ >+ EXPECT_EQ(2, listener.construct0); >+ EXPECT_EQ(2, listener.move); >+ EXPECT_EQ(4, listener.destruct); >+} >+ >+TEST(optionalTest, BigStringLeakCheck) { >+ constexpr size_t n = 1 << 16; >+ >+ using OS = absl::optional<std::string>; >+ >+ OS a; >+ OS b = absl::nullopt; >+ OS c = std::string(n, 'c'); >+ std::string sd(n, 'd'); >+ OS d = sd; >+ OS e(absl::in_place, n, 'e'); >+ OS f; >+ f.emplace(n, 'f'); >+ >+ OS ca(a); >+ OS cb(b); >+ OS cc(c); >+ OS cd(d); >+ OS ce(e); >+ >+ OS oa; >+ OS ob = absl::nullopt; >+ OS oc = std::string(n, 'c'); >+ std::string sod(n, 'd'); >+ OS od = sod; >+ OS oe(absl::in_place, n, 'e'); >+ OS of; >+ of.emplace(n, 'f'); >+ >+ OS ma(std::move(oa)); >+ OS mb(std::move(ob)); >+ OS mc(std::move(oc)); >+ OS md(std::move(od)); >+ OS me(std::move(oe)); >+ OS mf(std::move(of)); >+ >+ OS aa1; >+ OS ab1 = absl::nullopt; >+ OS ac1 = std::string(n, 'c'); >+ std::string sad1(n, 'd'); >+ OS ad1 = sad1; >+ OS ae1(absl::in_place, n, 'e'); >+ OS af1; >+ af1.emplace(n, 'f'); >+ >+ OS aa2; >+ OS ab2 = absl::nullopt; >+ OS ac2 = std::string(n, 'c'); >+ std::string sad2(n, 'd'); >+ OS ad2 = sad2; >+ OS ae2(absl::in_place, n, 'e'); >+ OS af2; >+ af2.emplace(n, 'f'); >+ >+ aa1 = af2; >+ ab1 = ae2; >+ ac1 = ad2; >+ ad1 = ac2; >+ ae1 = ab2; >+ af1 = aa2; >+ >+ OS aa3; >+ OS ab3 = absl::nullopt; >+ OS ac3 = std::string(n, 'c'); >+ std::string sad3(n, 'd'); >+ OS ad3 = sad3; >+ OS ae3(absl::in_place, n, 'e'); >+ OS af3; >+ af3.emplace(n, 'f'); >+ >+ aa3 = absl::nullopt; >+ ab3 = absl::nullopt; >+ ac3 = absl::nullopt; >+ ad3 = absl::nullopt; >+ ae3 = absl::nullopt; >+ af3 = absl::nullopt; >+ >+ OS aa4; >+ OS ab4 = absl::nullopt; >+ OS ac4 = std::string(n, 'c'); >+ std::string sad4(n, 'd'); >+ OS ad4 = sad4; >+ OS ae4(absl::in_place, n, 'e'); >+ OS af4; >+ af4.emplace(n, 'f'); >+ >+ aa4 = OS(absl::in_place, n, 'a'); >+ ab4 = OS(absl::in_place, n, 'b'); >+ ac4 = OS(absl::in_place, n, 'c'); >+ ad4 = OS(absl::in_place, n, 'd'); >+ ae4 = OS(absl::in_place, n, 'e'); >+ af4 = OS(absl::in_place, n, 'f'); >+ >+ OS aa5; >+ OS ab5 = absl::nullopt; >+ OS ac5 = std::string(n, 'c'); >+ std::string sad5(n, 'd'); >+ OS ad5 = sad5; >+ OS ae5(absl::in_place, n, 'e'); >+ OS af5; >+ af5.emplace(n, 'f'); >+ >+ std::string saa5(n, 'a'); >+ std::string sab5(n, 'a'); >+ std::string sac5(n, 'a'); >+ std::string sad52(n, 'a'); >+ std::string sae5(n, 'a'); >+ std::string saf5(n, 'a'); >+ >+ aa5 = saa5; >+ ab5 = sab5; >+ ac5 = sac5; >+ ad5 = sad52; >+ ae5 = sae5; >+ af5 = saf5; >+ >+ OS aa6; >+ OS ab6 = absl::nullopt; >+ OS ac6 = std::string(n, 'c'); >+ std::string sad6(n, 'd'); >+ OS ad6 = sad6; >+ OS ae6(absl::in_place, n, 'e'); >+ OS af6; >+ af6.emplace(n, 'f'); >+ >+ aa6 = std::string(n, 'a'); >+ ab6 = std::string(n, 'b'); >+ ac6 = std::string(n, 'c'); >+ ad6 = std::string(n, 'd'); >+ ae6 = std::string(n, 'e'); >+ af6 = std::string(n, 'f'); >+ >+ OS aa7; >+ OS ab7 = absl::nullopt; >+ OS ac7 = std::string(n, 'c'); >+ std::string sad7(n, 'd'); >+ OS ad7 = sad7; >+ OS ae7(absl::in_place, n, 'e'); >+ OS af7; >+ af7.emplace(n, 'f'); >+ >+ aa7.emplace(n, 'A'); >+ ab7.emplace(n, 'B'); >+ ac7.emplace(n, 'C'); >+ ad7.emplace(n, 'D'); >+ ae7.emplace(n, 'E'); >+ af7.emplace(n, 'F'); >+} >+ >+TEST(optionalTest, MoveAssignRegression) { >+ StructorListener listener; >+ Listenable::listener = &listener; >+ >+ { >+ absl::optional<Listenable> a; >+ Listenable b; >+ a = std::move(b); >+ } >+ >+ EXPECT_EQ(1, listener.construct0); >+ EXPECT_EQ(1, listener.move); >+ EXPECT_EQ(2, listener.destruct); >+} >+ >+TEST(optionalTest, ValueType) { >+ EXPECT_TRUE((std::is_same<absl::optional<int>::value_type, int>::value)); >+ EXPECT_TRUE( >+ (std::is_same<absl::optional<std::string>::value_type, std::string>::value)); >+ EXPECT_FALSE( >+ (std::is_same<absl::optional<int>::value_type, absl::nullopt_t>::value)); >+} >+ >+template <typename T> >+struct is_hash_enabled_for { >+ template <typename U, typename = decltype(std::hash<U>()(std::declval<U>()))> >+ static std::true_type test(int); >+ >+ template <typename U> >+ static std::false_type test(...); >+ >+ static constexpr bool value = decltype(test<T>(0))::value; >+}; >+ >+TEST(optionalTest, Hash) { >+ std::hash<absl::optional<int>> hash; >+ std::set<size_t> hashcodes; >+ hashcodes.insert(hash(absl::nullopt)); >+ for (int i = 0; i < 100; ++i) { >+ hashcodes.insert(hash(i)); >+ } >+ EXPECT_GT(hashcodes.size(), 90); >+ >+ static_assert(is_hash_enabled_for<absl::optional<int>>::value, ""); >+ static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, ""); >+ >+#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ >+ _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11) >+ // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a >+ // static_assert to catch any user-defined type that doesn't provide a hash >+ // specialization. So instantiating std::hash<absl::optional<T>> will result >+ // in a hard error which is not SFINAE friendly. >+#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1 >+#endif >+ >+#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY >+ static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, ""); >+#endif >+ >+ // libstdc++ std::optional is missing remove_const_t, i.e. it's using >+ // std::hash<T> rather than std::hash<std::remove_const_t<T>>. >+ // Reference: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82262 >+#ifndef __GLIBCXX__ >+ static_assert(is_hash_enabled_for<absl::optional<const int>>::value, ""); >+ static_assert(is_hash_enabled_for<absl::optional<const Hashable>>::value, ""); >+ std::hash<absl::optional<const int>> c_hash; >+ for (int i = 0; i < 100; ++i) { >+ EXPECT_EQ(hash(i), c_hash(i)); >+ } >+#endif >+} >+ >+struct MoveMeNoThrow { >+ MoveMeNoThrow() : x(0) {} >+ [[noreturn]] MoveMeNoThrow(const MoveMeNoThrow& other) : x(other.x) { >+ ABSL_RAW_LOG(FATAL, "Should not be called."); >+ abort(); >+ } >+ MoveMeNoThrow(MoveMeNoThrow&& other) noexcept : x(other.x) {} >+ int x; >+}; >+ >+struct MoveMeThrow { >+ MoveMeThrow() : x(0) {} >+ MoveMeThrow(const MoveMeThrow& other) : x(other.x) {} >+ MoveMeThrow(MoveMeThrow&& other) : x(other.x) {} >+ int x; >+}; >+ >+TEST(optionalTest, NoExcept) { >+ static_assert( >+ std::is_nothrow_move_constructible<absl::optional<MoveMeNoThrow>>::value, >+ ""); >+#ifndef ABSL_HAVE_STD_OPTIONAL >+ static_assert(absl::default_allocator_is_nothrow::value == >+ std::is_nothrow_move_constructible< >+ absl::optional<MoveMeThrow>>::value, >+ ""); >+#endif >+ std::vector<absl::optional<MoveMeNoThrow>> v; >+ for (int i = 0; i < 10; ++i) v.emplace_back(); >+} >+ >+struct AnyLike { >+ AnyLike(AnyLike&&) = default; >+ AnyLike(const AnyLike&) = default; >+ >+ template <typename ValueType, >+ typename T = typename std::decay<ValueType>::type, >+ typename std::enable_if< >+ !absl::disjunction< >+ std::is_same<AnyLike, T>, >+ absl::negation<std::is_copy_constructible<T>>>::value, >+ int>::type = 0> >+ AnyLike(ValueType&&) {} // NOLINT(runtime/explicit) >+ >+ AnyLike& operator=(AnyLike&&) = default; >+ AnyLike& operator=(const AnyLike&) = default; >+ >+ template <typename ValueType, >+ typename T = typename std::decay<ValueType>::type> >+ typename std::enable_if< >+ absl::conjunction<absl::negation<std::is_same<AnyLike, T>>, >+ std::is_copy_constructible<T>>::value, >+ AnyLike&>::type >+ operator=(ValueType&& /* rhs */) { >+ return *this; >+ } >+}; >+ >+TEST(optionalTest, ConstructionConstraints) { >+ EXPECT_TRUE((std::is_constructible<AnyLike, absl::optional<AnyLike>>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_constructible<AnyLike, const absl::optional<AnyLike>&>::value)); >+ >+ EXPECT_TRUE((std::is_constructible<absl::optional<AnyLike>, AnyLike>::value)); >+ EXPECT_TRUE( >+ (std::is_constructible<absl::optional<AnyLike>, const AnyLike&>::value)); >+ >+ EXPECT_TRUE((std::is_convertible<absl::optional<AnyLike>, AnyLike>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_convertible<const absl::optional<AnyLike>&, AnyLike>::value)); >+ >+ EXPECT_TRUE((std::is_convertible<AnyLike, absl::optional<AnyLike>>::value)); >+ EXPECT_TRUE( >+ (std::is_convertible<const AnyLike&, absl::optional<AnyLike>>::value)); >+ >+ EXPECT_TRUE(std::is_move_constructible<absl::optional<AnyLike>>::value); >+ EXPECT_TRUE(std::is_copy_constructible<absl::optional<AnyLike>>::value); >+} >+ >+TEST(optionalTest, AssignmentConstraints) { >+ EXPECT_TRUE((std::is_assignable<AnyLike&, absl::optional<AnyLike>>::value)); >+ EXPECT_TRUE( >+ (std::is_assignable<AnyLike&, const absl::optional<AnyLike>&>::value)); >+ EXPECT_TRUE((std::is_assignable<absl::optional<AnyLike>&, AnyLike>::value)); >+ EXPECT_TRUE( >+ (std::is_assignable<absl::optional<AnyLike>&, const AnyLike&>::value)); >+ EXPECT_TRUE(std::is_move_assignable<absl::optional<AnyLike>>::value); >+ EXPECT_TRUE(std::is_copy_assignable<absl::optional<AnyLike>>::value); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span.h >new file mode 100644 >index 00000000000..76be819ecca >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span.h >@@ -0,0 +1,749 @@ >+// >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// span.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines a `Span<T>` type for holding a view of an existing >+// array of data. The `Span` object, much like the `absl::string_view` object, >+// does not own such data itself. A span provides a lightweight way to pass >+// around view of such data. >+// >+// Additionally, this header file defines `MakeSpan()` and `MakeConstSpan()` >+// factory functions, for clearly creating spans of type `Span<T>` or read-only >+// `Span<const T>` when such types may be difficult to identify due to issues >+// with implicit conversion. >+// >+// The C++ standards committee currently has a proposal for a `std::span` type, >+// (http://wg21.link/p0122), which is not yet part of the standard (though may >+// become part of C++20). As of August 2017, the differences between >+// `absl::Span` and this proposal are: >+// * `absl::Span` uses `size_t` for `size_type` >+// * `absl::Span` has no `operator()` >+// * `absl::Span` has no constructors for `std::unique_ptr` or >+// `std::shared_ptr` >+// * `absl::Span` has the factory functions `MakeSpan()` and >+// `MakeConstSpan()` >+// * `absl::Span` has `front()` and `back()` methods >+// * bounds-checked access to `absl::Span` is accomplished with `at()` >+// * `absl::Span` has compiler-provided move and copy constructors and >+// assignment. This is due to them being specified as `constexpr`, but that >+// implies const in C++11. >+// * `absl::Span` has no `element_type` or `index_type` typedefs >+// * A read-only `absl::Span<const T>` can be implicitly constructed from an >+// initializer list. >+// * `absl::Span` has no `bytes()`, `size_bytes()`, `as_bytes()`, or >+// `as_mutable_bytes()` methods >+// * `absl::Span` has no static extent template parameter, nor constructors >+// which exist only because of the static extent parameter. >+// * `absl::Span` has an explicit mutable-reference constructor >+// >+// For more information, see the class comments below. >+#ifndef ABSL_TYPES_SPAN_H_ >+#define ABSL_TYPES_SPAN_H_ >+ >+#include <algorithm> >+#include <cassert> >+#include <cstddef> >+#include <initializer_list> >+#include <iterator> >+#include <string> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/algorithm/algorithm.h" >+#include "absl/base/internal/throw_delegate.h" >+#include "absl/base/macros.h" >+#include "absl/base/optimization.h" >+#include "absl/base/port.h" >+#include "absl/meta/type_traits.h" >+ >+namespace absl { >+ >+template <typename T> >+class Span; >+ >+namespace span_internal { >+// A constexpr min function >+constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; } >+ >+// Wrappers for access to container data pointers. >+template <typename C> >+constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references) >+ -> decltype(c.data()) { >+ return c.data(); >+} >+ >+// Before C++17, std::string::data returns a const char* in all cases. >+inline char* GetDataImpl(std::string& s, // NOLINT(runtime/references) >+ int) noexcept { >+ return &s[0]; >+} >+ >+template <typename C> >+constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references) >+ -> decltype(GetDataImpl(c, 0)) { >+ return GetDataImpl(c, 0); >+} >+ >+// Detection idioms for size() and data(). >+template <typename C> >+using HasSize = >+ std::is_integral<absl::decay_t<decltype(std::declval<C&>().size())>>; >+ >+// We want to enable conversion from vector<T*> to Span<const T* const> but >+// disable conversion from vector<Derived> to Span<Base>. Here we use >+// the fact that U** is convertible to Q* const* if and only if Q is the same >+// type or a more cv-qualified version of U. We also decay the result type of >+// data() to avoid problems with classes which have a member function data() >+// which returns a reference. >+template <typename T, typename C> >+using HasData = >+ std::is_convertible<absl::decay_t<decltype(GetData(std::declval<C&>()))>*, >+ T* const*>; >+ >+// Extracts value type from a Container >+template <typename C> >+struct ElementType { >+ using type = typename absl::remove_reference_t<C>::value_type; >+}; >+ >+template <typename T, size_t N> >+struct ElementType<T (&)[N]> { >+ using type = T; >+}; >+ >+template <typename C> >+using ElementT = typename ElementType<C>::type; >+ >+template <typename T> >+using EnableIfMutable = >+ typename std::enable_if<!std::is_const<T>::value, int>::type; >+ >+template <typename T> >+bool EqualImpl(Span<T> a, Span<T> b) { >+ static_assert(std::is_const<T>::value, ""); >+ return absl::equal(a.begin(), a.end(), b.begin(), b.end()); >+} >+ >+template <typename T> >+bool LessThanImpl(Span<T> a, Span<T> b) { >+ static_assert(std::is_const<T>::value, ""); >+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end()); >+} >+ >+// The `IsConvertible` classes here are needed because of the >+// `std::is_convertible` bug in libcxx when compiled with GCC. This build >+// configuration is used by Android NDK toolchain. Reference link: >+// https://bugs.llvm.org/show_bug.cgi?id=27538. >+template <typename From, typename To> >+struct IsConvertibleHelper { >+ private: >+ static std::true_type testval(To); >+ static std::false_type testval(...); >+ >+ public: >+ using type = decltype(testval(std::declval<From>())); >+}; >+ >+template <typename From, typename To> >+struct IsConvertible : IsConvertibleHelper<From, To>::type {}; >+ >+// TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the >+// older version of libcxx is not supported. >+template <typename From, typename To> >+using EnableIfConvertibleToSpanConst = >+ typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type; >+} // namespace span_internal >+ >+//------------------------------------------------------------------------------ >+// Span >+//------------------------------------------------------------------------------ >+// >+// A `Span` is an "array view" type for holding a view of a contiguous data >+// array; the `Span` object does not and cannot own such data itself. A span >+// provides an easy way to provide overloads for anything operating on >+// contiguous sequences without needing to manage pointers and array lengths >+// manually. >+ >+// A span is conceptually a pointer (ptr) and a length (size) into an already >+// existing array of contiguous memory; the array it represents references the >+// elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span` >+// instead of raw pointers avoids many issues related to index out of bounds >+// errors. >+// >+// Spans may also be constructed from containers holding contiguous sequences. >+// Such containers must supply `data()` and `size() const` methods (e.g >+// `std::vector<T>`, `absl::InlinedVector<T, N>`). All implicit conversions to >+// `absl::Span` from such containers will create spans of type `const T`; >+// spans which can mutate their values (of type `T`) must use explicit >+// constructors. >+// >+// A `Span<T>` is somewhat analogous to an `absl::string_view`, but for an array >+// of elements of type `T`. A user of `Span` must ensure that the data being >+// pointed to outlives the `Span` itself. >+// >+// You can construct a `Span<T>` in several ways: >+// >+// * Explicitly from a reference to a container type >+// * Explicitly from a pointer and size >+// * Implicitly from a container type (but only for spans of type `const T`) >+// * Using the `MakeSpan()` or `MakeConstSpan()` factory functions. >+// >+// Examples: >+// >+// // Construct a Span explicitly from a container: >+// std::vector<int> v = {1, 2, 3, 4, 5}; >+// auto span = absl::Span<const int>(v); >+// >+// // Construct a Span explicitly from a C-style array: >+// int a[5] = {1, 2, 3, 4, 5}; >+// auto span = absl::Span<const int>(a); >+// >+// // Construct a Span implicitly from a container >+// void MyRoutine(absl::Span<const int> a) { >+// ... >+// } >+// std::vector v = {1,2,3,4,5}; >+// MyRoutine(v) // convert to Span<const T> >+// >+// Note that `Span` objects, in addition to requiring that the memory they >+// point to remains alive, must also ensure that such memory does not get >+// reallocated. Therefore, to avoid undefined behavior, containers with >+// associated span views should not invoke operations that may reallocate memory >+// (such as resizing) or invalidate iterators into the container. >+// >+// One common use for a `Span` is when passing arguments to a routine that can >+// accept a variety of array types (e.g. a `std::vector`, `absl::InlinedVector`, >+// a C-style array, etc.). Instead of creating overloads for each case, you >+// can simply specify a `Span` as the argument to such a routine. >+// >+// Example: >+// >+// void MyRoutine(absl::Span<const int> a) { >+// ... >+// } >+// >+// std::vector v = {1,2,3,4,5}; >+// MyRoutine(v); >+// >+// absl::InlinedVector<int, 4> my_inline_vector; >+// MyRoutine(my_inline_vector); >+// >+// // Explicit constructor from pointer,size >+// int* my_array = new int[10]; >+// MyRoutine(absl::Span<const int>(my_array, 10)); >+template <typename T> >+class Span { >+ private: >+ // Used to determine whether a Span can be constructed from a container of >+ // type C. >+ template <typename C> >+ using EnableIfConvertibleFrom = >+ typename std::enable_if<span_internal::HasData<T, C>::value && >+ span_internal::HasSize<C>::value>::type; >+ >+ // Used to SFINAE-enable a function when the slice elements are const. >+ template <typename U> >+ using EnableIfConstView = >+ typename std::enable_if<std::is_const<T>::value, U>::type; >+ >+ // Used to SFINAE-enable a function when the slice elements are mutable. >+ template <typename U> >+ using EnableIfMutableView = >+ typename std::enable_if<!std::is_const<T>::value, U>::type; >+ >+ public: >+ using value_type = absl::remove_cv_t<T>; >+ using pointer = T*; >+ using const_pointer = const T*; >+ using reference = T&; >+ using const_reference = const T&; >+ using iterator = pointer; >+ using const_iterator = const_pointer; >+ using reverse_iterator = std::reverse_iterator<iterator>; >+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; >+ using size_type = size_t; >+ using difference_type = ptrdiff_t; >+ >+ static const size_type npos = ~(size_type(0)); >+ >+ constexpr Span() noexcept : Span(nullptr, 0) {} >+ constexpr Span(pointer array, size_type length) noexcept >+ : ptr_(array), len_(length) {} >+ >+ // Implicit conversion constructors >+ template <size_t N> >+ constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit) >+ : Span(a, N) {} >+ >+ // Explicit reference constructor for a mutable `Span<T>` type. Can be >+ // replaced with MakeSpan() to infer the type parameter. >+ template <typename V, typename = EnableIfConvertibleFrom<V>, >+ typename = EnableIfMutableView<V>> >+ explicit Span(V& v) noexcept // NOLINT(runtime/references) >+ : Span(span_internal::GetData(v), v.size()) {} >+ >+ // Implicit reference constructor for a read-only `Span<const T>` type >+ template <typename V, typename = EnableIfConvertibleFrom<V>, >+ typename = EnableIfConstView<V>> >+ constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit) >+ : Span(span_internal::GetData(v), v.size()) {} >+ >+ // Implicit constructor from an initializer list, making it possible to pass a >+ // brace-enclosed initializer list to a function expecting a `Span`. Such >+ // spans constructed from an initializer list must be of type `Span<const T>`. >+ // >+ // void Process(absl::Span<const int> x); >+ // Process({1, 2, 3}); >+ // >+ // Note that as always the array referenced by the span must outlive the span. >+ // Since an initializer list constructor acts as if it is fed a temporary >+ // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this >+ // constructor only when the `std::initializer_list` itself outlives the span. >+ // In order to meet this requirement it's sufficient to ensure that neither >+ // the span nor a copy of it is used outside of the expression in which it's >+ // created: >+ // >+ // // Assume that this function uses the array directly, not retaining any >+ // // copy of the span or pointer to any of its elements. >+ // void Process(absl::Span<const int> ints); >+ // >+ // // Okay: the std::initializer_list<int> will reference a temporary array >+ // // that isn't destroyed until after the call to Process returns. >+ // Process({ 17, 19 }); >+ // >+ // // Not okay: the storage used by the std::initializer_list<int> is not >+ // // allowed to be referenced after the first line. >+ // absl::Span<const int> ints = { 17, 19 }; >+ // Process(ints); >+ // >+ // // Not okay for the same reason as above: even when the elements of the >+ // // initializer list expression are not temporaries the underlying array >+ // // is, so the initializer list must still outlive the span. >+ // const int foo = 17; >+ // absl::Span<const int> ints = { foo }; >+ // Process(ints); >+ // >+ template <typename LazyT = T, >+ typename = EnableIfConstView<LazyT>> >+ Span( >+ std::initializer_list<value_type> v) noexcept // NOLINT(runtime/explicit) >+ : Span(v.begin(), v.size()) {} >+ >+ // Accessors >+ >+ // Span::data() >+ // >+ // Returns a pointer to the span's underlying array of data (which is held >+ // outside the span). >+ constexpr pointer data() const noexcept { return ptr_; } >+ >+ // Span::size() >+ // >+ // Returns the size of this span. >+ constexpr size_type size() const noexcept { return len_; } >+ >+ // Span::length() >+ // >+ // Returns the length (size) of this span. >+ constexpr size_type length() const noexcept { return size(); } >+ >+ // Span::empty() >+ // >+ // Returns a boolean indicating whether or not this span is considered empty. >+ constexpr bool empty() const noexcept { return size() == 0; } >+ >+ // Span::operator[] >+ // >+ // Returns a reference to the i'th element of this span. >+ constexpr reference operator[](size_type i) const noexcept { >+ // MSVC 2015 accepts this as constexpr, but not ptr_[i] >+ return *(data() + i); >+ } >+ >+ // Span::at() >+ // >+ // Returns a reference to the i'th element of this span. >+ constexpr reference at(size_type i) const { >+ return ABSL_PREDICT_TRUE(i < size()) >+ ? ptr_[i] >+ : (base_internal::ThrowStdOutOfRange( >+ "Span::at failed bounds check"), >+ ptr_[i]); >+ } >+ >+ // Span::front() >+ // >+ // Returns a reference to the first element of this span. >+ reference front() const noexcept { return ABSL_ASSERT(size() > 0), ptr_[0]; } >+ >+ // Span::back() >+ // >+ // Returns a reference to the last element of this span. >+ reference back() const noexcept { >+ return ABSL_ASSERT(size() > 0), ptr_[size() - 1]; >+ } >+ >+ // Span::begin() >+ // >+ // Returns an iterator to the first element of this span. >+ constexpr iterator begin() const noexcept { return ptr_; } >+ >+ // Span::cbegin() >+ // >+ // Returns a const iterator to the first element of this span. >+ constexpr const_iterator cbegin() const noexcept { return ptr_; } >+ >+ // Span::end() >+ // >+ // Returns an iterator to the last element of this span. >+ iterator end() const noexcept { return ptr_ + len_; } >+ >+ // Span::cend() >+ // >+ // Returns a const iterator to the last element of this span. >+ const_iterator cend() const noexcept { return end(); } >+ >+ // Span::rbegin() >+ // >+ // Returns a reverse iterator starting at the last element of this span. >+ reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); } >+ >+ // Span::crbegin() >+ // >+ // Returns a reverse const iterator starting at the last element of this span. >+ const_reverse_iterator crbegin() const noexcept { return rbegin(); } >+ >+ // Span::rend() >+ // >+ // Returns a reverse iterator starting at the first element of this span. >+ reverse_iterator rend() const noexcept { return reverse_iterator(begin()); } >+ >+ // Span::crend() >+ // >+ // Returns a reverse iterator starting at the first element of this span. >+ const_reverse_iterator crend() const noexcept { return rend(); } >+ >+ // Span mutations >+ >+ // Span::remove_prefix() >+ // >+ // Removes the first `n` elements from the span. >+ void remove_prefix(size_type n) noexcept { >+ assert(len_ >= n); >+ ptr_ += n; >+ len_ -= n; >+ } >+ >+ // Span::remove_suffix() >+ // >+ // Removes the last `n` elements from the span. >+ void remove_suffix(size_type n) noexcept { >+ assert(len_ >= n); >+ len_ -= n; >+ } >+ >+ // Span::subspan() >+ // >+ // Returns a `Span` starting at element `pos` and of length `len`. Both `pos` >+ // and `len` are of type `size_type` and thus non-negative. Parameter `pos` >+ // must be <= size(). Any `len` value that points past the end of the span >+ // will be trimmed to at most size() - `pos`. A default `len` value of `npos` >+ // ensures the returned subspan continues until the end of the span. >+ // >+ // Examples: >+ // >+ // std::vector<int> vec = {10, 11, 12, 13}; >+ // absl::MakeSpan(vec).subspan(1, 2); // {11, 12} >+ // absl::MakeSpan(vec).subspan(2, 8); // {12, 13} >+ // absl::MakeSpan(vec).subspan(1); // {11, 12, 13} >+ // absl::MakeSpan(vec).subspan(4); // {} >+ // absl::MakeSpan(vec).subspan(5); // throws std::out_of_range >+ constexpr Span subspan(size_type pos = 0, size_type len = npos) const { >+ return (pos <= len_) >+ ? Span(ptr_ + pos, span_internal::Min(len_ - pos, len)) >+ : (base_internal::ThrowStdOutOfRange("pos > size()"), Span()); >+ } >+ >+ private: >+ pointer ptr_; >+ size_type len_; >+}; >+ >+template <typename T> >+const typename Span<T>::size_type Span<T>::npos; >+ >+// Span relationals >+ >+// Equality is compared element-by-element, while ordering is lexicographical. >+// We provide three overloads for each operator to cover any combination on the >+// left or right hand side of mutable Span<T>, read-only Span<const T>, and >+// convertible-to-read-only Span<T>. >+// TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering >+// template functions, 5 overloads per operator is needed as a workaround. We >+// should update them to 3 overloads per operator using non-deduced context like >+// string_view, i.e. >+// - (Span<T>, Span<T>) >+// - (Span<T>, non_deduced<Span<const T>>) >+// - (non_deduced<Span<const T>>, Span<T>) >+ >+// operator== >+template <typename T> >+bool operator==(Span<T> a, Span<T> b) { >+ return span_internal::EqualImpl<const T>(a, b); >+} >+template <typename T> >+bool operator==(Span<const T> a, Span<T> b) { >+ return span_internal::EqualImpl<const T>(a, b); >+} >+template <typename T> >+bool operator==(Span<T> a, Span<const T> b) { >+ return span_internal::EqualImpl<const T>(a, b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator==(const U& a, Span<T> b) { >+ return span_internal::EqualImpl<const T>(a, b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator==(Span<T> a, const U& b) { >+ return span_internal::EqualImpl<const T>(a, b); >+} >+ >+// operator!= >+template <typename T> >+bool operator!=(Span<T> a, Span<T> b) { >+ return !(a == b); >+} >+template <typename T> >+bool operator!=(Span<const T> a, Span<T> b) { >+ return !(a == b); >+} >+template <typename T> >+bool operator!=(Span<T> a, Span<const T> b) { >+ return !(a == b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator!=(const U& a, Span<T> b) { >+ return !(a == b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator!=(Span<T> a, const U& b) { >+ return !(a == b); >+} >+ >+// operator< >+template <typename T> >+bool operator<(Span<T> a, Span<T> b) { >+ return span_internal::LessThanImpl<const T>(a, b); >+} >+template <typename T> >+bool operator<(Span<const T> a, Span<T> b) { >+ return span_internal::LessThanImpl<const T>(a, b); >+} >+template <typename T> >+bool operator<(Span<T> a, Span<const T> b) { >+ return span_internal::LessThanImpl<const T>(a, b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator<(const U& a, Span<T> b) { >+ return span_internal::LessThanImpl<const T>(a, b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator<(Span<T> a, const U& b) { >+ return span_internal::LessThanImpl<const T>(a, b); >+} >+ >+// operator> >+template <typename T> >+bool operator>(Span<T> a, Span<T> b) { >+ return b < a; >+} >+template <typename T> >+bool operator>(Span<const T> a, Span<T> b) { >+ return b < a; >+} >+template <typename T> >+bool operator>(Span<T> a, Span<const T> b) { >+ return b < a; >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator>(const U& a, Span<T> b) { >+ return b < a; >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator>(Span<T> a, const U& b) { >+ return b < a; >+} >+ >+// operator<= >+template <typename T> >+bool operator<=(Span<T> a, Span<T> b) { >+ return !(b < a); >+} >+template <typename T> >+bool operator<=(Span<const T> a, Span<T> b) { >+ return !(b < a); >+} >+template <typename T> >+bool operator<=(Span<T> a, Span<const T> b) { >+ return !(b < a); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator<=(const U& a, Span<T> b) { >+ return !(b < a); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator<=(Span<T> a, const U& b) { >+ return !(b < a); >+} >+ >+// operator>= >+template <typename T> >+bool operator>=(Span<T> a, Span<T> b) { >+ return !(a < b); >+} >+template <typename T> >+bool operator>=(Span<const T> a, Span<T> b) { >+ return !(a < b); >+} >+template <typename T> >+bool operator>=(Span<T> a, Span<const T> b) { >+ return !(a < b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator>=(const U& a, Span<T> b) { >+ return !(a < b); >+} >+template <typename T, typename U, >+ typename = span_internal::EnableIfConvertibleToSpanConst<U, T>> >+bool operator>=(Span<T> a, const U& b) { >+ return !(a < b); >+} >+ >+// MakeSpan() >+// >+// Constructs a mutable `Span<T>`, deducing `T` automatically from either a >+// container or pointer+size. >+// >+// Because a read-only `Span<const T>` is implicitly constructed from container >+// types regardless of whether the container itself is a const container, >+// constructing mutable spans of type `Span<T>` from containers requires >+// explicit constructors. The container-accepting version of `MakeSpan()` >+// deduces the type of `T` by the constness of the pointer received from the >+// container's `data()` member. Similarly, the pointer-accepting version returns >+// a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise. >+// >+// Examples: >+// >+// void MyRoutine(absl::Span<MyComplicatedType> a) { >+// ... >+// }; >+// // my_vector is a container of non-const types >+// std::vector<MyComplicatedType> my_vector; >+// >+// // Constructing a Span implicitly attempts to create a Span of type >+// // `Span<const T>` >+// MyRoutine(my_vector); // error, type mismatch >+// >+// // Explicitly constructing the Span is verbose >+// MyRoutine(absl::Span<MyComplicatedType>(my_vector)); >+// >+// // Use MakeSpan() to make an absl::Span<T> >+// MyRoutine(absl::MakeSpan(my_vector)); >+// >+// // Construct a span from an array ptr+size >+// absl::Span<T> my_span() { >+// return absl::MakeSpan(&array[0], num_elements_); >+// } >+// >+template <int&... ExplicitArgumentBarrier, typename T> >+constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept { >+ return Span<T>(ptr, size); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename T> >+Span<T> MakeSpan(T* begin, T* end) noexcept { >+ return ABSL_ASSERT(begin <= end), Span<T>(begin, end - begin); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename C> >+constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references) >+ -> decltype(absl::MakeSpan(span_internal::GetData(c), c.size())) { >+ return MakeSpan(span_internal::GetData(c), c.size()); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename T, size_t N> >+constexpr Span<T> MakeSpan(T (&array)[N]) noexcept { >+ return Span<T>(array, N); >+} >+ >+// MakeConstSpan() >+// >+// Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically, >+// but always returning a `Span<const T>`. >+// >+// Examples: >+// >+// void ProcessInts(absl::Span<const int> some_ints); >+// >+// // Call with a pointer and size. >+// int array[3] = { 0, 0, 0 }; >+// ProcessInts(absl::MakeConstSpan(&array[0], 3)); >+// >+// // Call with a [begin, end) pair. >+// ProcessInts(absl::MakeConstSpan(&array[0], &array[3])); >+// >+// // Call directly with an array. >+// ProcessInts(absl::MakeConstSpan(array)); >+// >+// // Call with a contiguous container. >+// std::vector<int> some_ints = ...; >+// ProcessInts(absl::MakeConstSpan(some_ints)); >+// ProcessInts(absl::MakeConstSpan(std::vector<int>{ 0, 0, 0 })); >+// >+template <int&... ExplicitArgumentBarrier, typename T> >+constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept { >+ return Span<const T>(ptr, size); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename T> >+Span<const T> MakeConstSpan(T* begin, T* end) noexcept { >+ return ABSL_ASSERT(begin <= end), Span<const T>(begin, end - begin); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename C> >+constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) { >+ return MakeSpan(c); >+} >+ >+template <int&... ExplicitArgumentBarrier, typename T, size_t N> >+constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept { >+ return Span<const T>(array, N); >+} >+} // namespace absl >+#endif // ABSL_TYPES_SPAN_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span_test.cc >new file mode 100644 >index 00000000000..fbce7e87479 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/span_test.cc >@@ -0,0 +1,781 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/types/span.h" >+ >+#include <array> >+#include <initializer_list> >+#include <numeric> >+#include <stdexcept> >+#include <string> >+#include <type_traits> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/base/config.h" >+#include "absl/base/internal/exception_testing.h" >+#include "absl/container/fixed_array.h" >+#include "absl/container/inlined_vector.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+MATCHER_P(DataIs, data, >+ absl::StrCat("data() is ", negation ? "is " : "isn't ", >+ testing::PrintToString(data))) { >+ return arg.data() == data; >+} >+ >+template <typename T> >+auto SpanIs(T data, size_t size) >+ -> decltype(testing::AllOf(DataIs(data), testing::SizeIs(size))) { >+ return testing::AllOf(DataIs(data), testing::SizeIs(size)); >+} >+ >+template <typename Container> >+auto SpanIs(const Container& c) -> decltype(SpanIs(c.data(), c.size())) { >+ return SpanIs(c.data(), c.size()); >+} >+ >+std::vector<int> MakeRamp(int len, int offset = 0) { >+ std::vector<int> v(len); >+ std::iota(v.begin(), v.end(), offset); >+ return v; >+} >+ >+TEST(IntSpan, EmptyCtors) { >+ absl::Span<int> s; >+ EXPECT_THAT(s, SpanIs(nullptr, 0)); >+} >+ >+TEST(IntSpan, PtrLenCtor) { >+ int a[] = {1, 2, 3}; >+ absl::Span<int> s(&a[0], 2); >+ EXPECT_THAT(s, SpanIs(a, 2)); >+} >+ >+TEST(IntSpan, ArrayCtor) { >+ int a[] = {1, 2, 3}; >+ absl::Span<int> s(a); >+ EXPECT_THAT(s, SpanIs(a, 3)); >+ >+ EXPECT_TRUE((std::is_constructible<absl::Span<const int>, int[3]>::value)); >+ EXPECT_TRUE( >+ (std::is_constructible<absl::Span<const int>, const int[3]>::value)); >+ EXPECT_FALSE((std::is_constructible<absl::Span<int>, const int[3]>::value)); >+ EXPECT_TRUE((std::is_convertible<int[3], absl::Span<const int>>::value)); >+ EXPECT_TRUE( >+ (std::is_convertible<const int[3], absl::Span<const int>>::value)); >+} >+ >+template <typename T> >+void TakesGenericSpan(absl::Span<T>) {} >+ >+TEST(IntSpan, ContainerCtor) { >+ std::vector<int> empty; >+ absl::Span<int> s_empty(empty); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::vector<int> filled{1, 2, 3}; >+ absl::Span<int> s_filled(filled); >+ EXPECT_THAT(s_filled, SpanIs(filled)); >+ >+ absl::Span<int> s_from_span(filled); >+ EXPECT_THAT(s_from_span, SpanIs(s_filled)); >+ >+ absl::Span<const int> const_filled = filled; >+ EXPECT_THAT(const_filled, SpanIs(filled)); >+ >+ absl::Span<const int> const_from_span = s_filled; >+ EXPECT_THAT(const_from_span, SpanIs(s_filled)); >+ >+ EXPECT_TRUE( >+ (std::is_convertible<std::vector<int>&, absl::Span<const int>>::value)); >+ EXPECT_TRUE( >+ (std::is_convertible<absl::Span<int>&, absl::Span<const int>>::value)); >+ >+ TakesGenericSpan(absl::Span<int>(filled)); >+} >+ >+// A struct supplying shallow data() const. >+struct ContainerWithShallowConstData { >+ std::vector<int> storage; >+ int* data() const { return const_cast<int*>(storage.data()); } >+ int size() const { return storage.size(); } >+}; >+ >+TEST(IntSpan, ShallowConstness) { >+ const ContainerWithShallowConstData c{MakeRamp(20)}; >+ absl::Span<int> s( >+ c); // We should be able to do this even though data() is const. >+ s[0] = -1; >+ EXPECT_EQ(c.storage[0], -1); >+} >+ >+TEST(CharSpan, StringCtor) { >+ std::string empty = ""; >+ absl::Span<char> s_empty(empty); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::string abc = "abc"; >+ absl::Span<char> s_abc(abc); >+ EXPECT_THAT(s_abc, SpanIs(abc)); >+ >+ absl::Span<const char> s_const_abc = abc; >+ EXPECT_THAT(s_const_abc, SpanIs(abc)); >+ >+ EXPECT_FALSE((std::is_constructible<absl::Span<int>, std::string>::value)); >+ EXPECT_FALSE((std::is_constructible<absl::Span<const int>, std::string>::value)); >+ EXPECT_TRUE((std::is_convertible<std::string, absl::Span<const char>>::value)); >+} >+ >+TEST(IntSpan, FromConstPointer) { >+ EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>, >+ std::vector<int*>>::value)); >+ EXPECT_TRUE((std::is_constructible<absl::Span<const int* const>, >+ std::vector<const int*>>::value)); >+ EXPECT_FALSE(( >+ std::is_constructible<absl::Span<const int*>, std::vector<int*>>::value)); >+ EXPECT_FALSE(( >+ std::is_constructible<absl::Span<int*>, std::vector<const int*>>::value)); >+} >+ >+struct TypeWithMisleadingData { >+ int& data() { return i; } >+ int size() { return 1; } >+ int i; >+}; >+ >+struct TypeWithMisleadingSize { >+ int* data() { return &i; } >+ const char* size() { return "1"; } >+ int i; >+}; >+ >+TEST(IntSpan, EvilTypes) { >+ EXPECT_FALSE( >+ (std::is_constructible<absl::Span<int>, TypeWithMisleadingData&>::value)); >+ EXPECT_FALSE( >+ (std::is_constructible<absl::Span<int>, TypeWithMisleadingSize&>::value)); >+} >+ >+struct Base { >+ int* data() { return &i; } >+ int size() { return 1; } >+ int i; >+}; >+struct Derived : Base {}; >+ >+TEST(IntSpan, SpanOfDerived) { >+ EXPECT_TRUE((std::is_constructible<absl::Span<int>, Base&>::value)); >+ EXPECT_TRUE((std::is_constructible<absl::Span<int>, Derived&>::value)); >+ EXPECT_FALSE( >+ (std::is_constructible<absl::Span<Base>, std::vector<Derived>>::value)); >+} >+ >+void TestInitializerList(absl::Span<const int> s, const std::vector<int>& v) { >+ EXPECT_TRUE(absl::equal(s.begin(), s.end(), v.begin(), v.end())); >+} >+ >+TEST(ConstIntSpan, InitializerListConversion) { >+ TestInitializerList({}, {}); >+ TestInitializerList({1}, {1}); >+ TestInitializerList({1, 2, 3}, {1, 2, 3}); >+ >+ EXPECT_FALSE((std::is_constructible<absl::Span<int>, >+ std::initializer_list<int>>::value)); >+ EXPECT_FALSE(( >+ std::is_convertible<absl::Span<int>, std::initializer_list<int>>::value)); >+} >+ >+TEST(IntSpan, Data) { >+ int i; >+ absl::Span<int> s(&i, 1); >+ EXPECT_EQ(&i, s.data()); >+} >+ >+TEST(IntSpan, SizeLengthEmpty) { >+ absl::Span<int> empty; >+ EXPECT_EQ(empty.size(), 0); >+ EXPECT_TRUE(empty.empty()); >+ EXPECT_EQ(empty.size(), empty.length()); >+ >+ auto v = MakeRamp(10); >+ absl::Span<int> s(v); >+ EXPECT_EQ(s.size(), 10); >+ EXPECT_FALSE(s.empty()); >+ EXPECT_EQ(s.size(), s.length()); >+} >+ >+TEST(IntSpan, ElementAccess) { >+ auto v = MakeRamp(10); >+ absl::Span<int> s(v); >+ for (int i = 0; i < s.size(); ++i) { >+ EXPECT_EQ(s[i], s.at(i)); >+ } >+ >+ EXPECT_EQ(s.front(), s[0]); >+ EXPECT_EQ(s.back(), s[9]); >+} >+ >+TEST(IntSpan, AtThrows) { >+ auto v = MakeRamp(10); >+ absl::Span<int> s(v); >+ >+ EXPECT_EQ(s.at(9), 9); >+ ABSL_BASE_INTERNAL_EXPECT_FAIL(s.at(10), std::out_of_range, >+ "failed bounds check"); >+} >+ >+TEST(IntSpan, RemovePrefixAndSuffix) { >+ auto v = MakeRamp(20, 1); >+ absl::Span<int> s(v); >+ EXPECT_EQ(s.size(), 20); >+ >+ s.remove_suffix(0); >+ s.remove_prefix(0); >+ EXPECT_EQ(s.size(), 20); >+ >+ s.remove_prefix(1); >+ EXPECT_EQ(s.size(), 19); >+ EXPECT_EQ(s[0], 2); >+ >+ s.remove_suffix(1); >+ EXPECT_EQ(s.size(), 18); >+ EXPECT_EQ(s.back(), 19); >+ >+ s.remove_prefix(7); >+ EXPECT_EQ(s.size(), 11); >+ EXPECT_EQ(s[0], 9); >+ >+ s.remove_suffix(11); >+ EXPECT_EQ(s.size(), 0); >+ >+ EXPECT_EQ(v, MakeRamp(20, 1)); >+} >+ >+TEST(IntSpan, Subspan) { >+ std::vector<int> empty; >+ EXPECT_EQ(absl::MakeSpan(empty).subspan(), empty); >+ EXPECT_THAT(absl::MakeSpan(empty).subspan(0, 0), SpanIs(empty)); >+ EXPECT_THAT(absl::MakeSpan(empty).subspan(0, absl::Span<const int>::npos), >+ SpanIs(empty)); >+ >+ auto ramp = MakeRamp(10); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(), SpanIs(ramp)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 10), SpanIs(ramp)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, absl::Span<const int>::npos), >+ SpanIs(ramp)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 3), SpanIs(ramp.data(), 3)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(5, absl::Span<const int>::npos), >+ SpanIs(ramp.data() + 5, 5)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(3, 3), SpanIs(ramp.data() + 3, 3)); >+ EXPECT_THAT(absl::MakeSpan(ramp).subspan(10, 5), SpanIs(ramp.data() + 10, 0)); >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range); >+#else >+ EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).subspan(11, 5), ""); >+#endif >+} >+ >+TEST(IntSpan, MakeSpanPtrLength) { >+ std::vector<int> empty; >+ auto s_empty = absl::MakeSpan(empty.data(), empty.size()); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::array<int, 3> a{{1, 2, 3}}; >+ auto s = absl::MakeSpan(a.data(), a.size()); >+ EXPECT_THAT(s, SpanIs(a)); >+ >+ EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.size()), SpanIs(s_empty)); >+ EXPECT_THAT(absl::MakeConstSpan(a.data(), a.size()), SpanIs(s)); >+} >+ >+TEST(IntSpan, MakeSpanTwoPtrs) { >+ std::vector<int> empty; >+ auto s_empty = absl::MakeSpan(empty.data(), empty.data()); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::vector<int> v{1, 2, 3}; >+ auto s = absl::MakeSpan(v.data(), v.data() + 1); >+ EXPECT_THAT(s, SpanIs(v.data(), 1)); >+ >+ EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.data()), SpanIs(s_empty)); >+ EXPECT_THAT(absl::MakeConstSpan(v.data(), v.data() + 1), SpanIs(s)); >+} >+ >+TEST(IntSpan, MakeSpanContainer) { >+ std::vector<int> empty; >+ auto s_empty = absl::MakeSpan(empty); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::vector<int> v{1, 2, 3}; >+ auto s = absl::MakeSpan(v); >+ EXPECT_THAT(s, SpanIs(v)); >+ >+ EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty)); >+ EXPECT_THAT(absl::MakeConstSpan(v), SpanIs(s)); >+ >+ EXPECT_THAT(absl::MakeSpan(s), SpanIs(s)); >+ EXPECT_THAT(absl::MakeConstSpan(s), SpanIs(s)); >+} >+ >+TEST(CharSpan, MakeSpanString) { >+ std::string empty = ""; >+ auto s_empty = absl::MakeSpan(empty); >+ EXPECT_THAT(s_empty, SpanIs(empty)); >+ >+ std::string str = "abc"; >+ auto s_str = absl::MakeSpan(str); >+ EXPECT_THAT(s_str, SpanIs(str)); >+ >+ EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty)); >+ EXPECT_THAT(absl::MakeConstSpan(str), SpanIs(s_str)); >+} >+ >+TEST(IntSpan, MakeSpanArray) { >+ int a[] = {1, 2, 3}; >+ auto s = absl::MakeSpan(a); >+ EXPECT_THAT(s, SpanIs(a, 3)); >+ >+ const int ca[] = {1, 2, 3}; >+ auto s_ca = absl::MakeSpan(ca); >+ EXPECT_THAT(s_ca, SpanIs(ca, 3)); >+ >+ EXPECT_THAT(absl::MakeConstSpan(a), SpanIs(s)); >+ EXPECT_THAT(absl::MakeConstSpan(ca), SpanIs(s_ca)); >+} >+ >+// Compile-asserts that the argument has the expected decayed type. >+template <typename Expected, typename T> >+void CheckType(const T& /* value */) { >+ testing::StaticAssertTypeEq<Expected, T>(); >+} >+ >+TEST(IntSpan, MakeSpanTypes) { >+ std::vector<int> vec; >+ const std::vector<int> cvec; >+ int a[1]; >+ const int ca[] = {1}; >+ int* ip = a; >+ const int* cip = ca; >+ std::string s = ""; >+ const std::string cs = ""; >+ CheckType<absl::Span<int>>(absl::MakeSpan(vec)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(cvec)); >+ CheckType<absl::Span<int>>(absl::MakeSpan(ip, ip + 1)); >+ CheckType<absl::Span<int>>(absl::MakeSpan(ip, 1)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(cip, cip + 1)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(cip, 1)); >+ CheckType<absl::Span<int>>(absl::MakeSpan(a)); >+ CheckType<absl::Span<int>>(absl::MakeSpan(a, a + 1)); >+ CheckType<absl::Span<int>>(absl::MakeSpan(a, 1)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca, ca + 1)); >+ CheckType<absl::Span<const int>>(absl::MakeSpan(ca, 1)); >+ CheckType<absl::Span<char>>(absl::MakeSpan(s)); >+ CheckType<absl::Span<const char>>(absl::MakeSpan(cs)); >+} >+ >+TEST(ConstIntSpan, MakeConstSpanTypes) { >+ std::vector<int> vec; >+ const std::vector<int> cvec; >+ int array[1]; >+ const int carray[] = {0}; >+ int* ptr = array; >+ const int* cptr = carray; >+ std::string s = ""; >+ std::string cs = ""; >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(vec)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cvec)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, ptr + 1)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(ptr, 1)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, cptr + 1)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(cptr, 1)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(array)); >+ CheckType<absl::Span<const int>>(absl::MakeConstSpan(carray)); >+ CheckType<absl::Span<const char>>(absl::MakeConstSpan(s)); >+ CheckType<absl::Span<const char>>(absl::MakeConstSpan(cs)); >+} >+ >+TEST(IntSpan, Equality) { >+ const int arr1[] = {1, 2, 3, 4, 5}; >+ int arr2[] = {1, 2, 3, 4, 5}; >+ std::vector<int> vec1(std::begin(arr1), std::end(arr1)); >+ std::vector<int> vec2 = vec1; >+ std::vector<int> other_vec = {2, 4, 6, 8, 10}; >+ // These two slices are from different vectors, but have the same size and >+ // have the same elements (right now). They should compare equal. Test both >+ // == and !=. >+ const absl::Span<const int> from1 = vec1; >+ const absl::Span<const int> from2 = vec2; >+ EXPECT_EQ(from1, from1); >+ EXPECT_FALSE(from1 != from1); >+ EXPECT_EQ(from1, from2); >+ EXPECT_FALSE(from1 != from2); >+ >+ // These two slices have different underlying vector values. They should be >+ // considered not equal. Test both == and !=. >+ const absl::Span<const int> from_other = other_vec; >+ EXPECT_NE(from1, from_other); >+ EXPECT_FALSE(from1 == from_other); >+ >+ // Comparison between a vector and its slice should be equal. And vice-versa. >+ // This ensures implicit conversion to Span works on both sides of ==. >+ EXPECT_EQ(vec1, from1); >+ EXPECT_FALSE(vec1 != from1); >+ EXPECT_EQ(from1, vec1); >+ EXPECT_FALSE(from1 != vec1); >+ >+ // This verifies that absl::Span<T> can be compared freely with >+ // absl::Span<const T>. >+ const absl::Span<int> mutable_from1(vec1); >+ const absl::Span<int> mutable_from2(vec2); >+ EXPECT_EQ(from1, mutable_from1); >+ EXPECT_EQ(mutable_from1, from1); >+ EXPECT_EQ(mutable_from1, mutable_from2); >+ EXPECT_EQ(mutable_from2, mutable_from1); >+ >+ // Comparison between a vector and its slice should be equal for mutable >+ // Spans as well. >+ EXPECT_EQ(vec1, mutable_from1); >+ EXPECT_FALSE(vec1 != mutable_from1); >+ EXPECT_EQ(mutable_from1, vec1); >+ EXPECT_FALSE(mutable_from1 != vec1); >+ >+ // Comparison between convertible-to-Span-of-const and Span-of-mutable. Arrays >+ // are used because they're the only value type which converts to a >+ // Span-of-mutable. EXPECT_TRUE is used instead of EXPECT_EQ to avoid >+ // array-to-pointer decay. >+ EXPECT_TRUE(arr1 == mutable_from1); >+ EXPECT_FALSE(arr1 != mutable_from1); >+ EXPECT_TRUE(mutable_from1 == arr1); >+ EXPECT_FALSE(mutable_from1 != arr1); >+ >+ // Comparison between convertible-to-Span-of-mutable and Span-of-const >+ EXPECT_TRUE(arr2 == from1); >+ EXPECT_FALSE(arr2 != from1); >+ EXPECT_TRUE(from1 == arr2); >+ EXPECT_FALSE(from1 != arr2); >+ >+ // With a different size, the array slices should not be equal. >+ EXPECT_NE(from1, absl::Span<const int>(from1).subspan(0, from1.size() - 1)); >+ >+ // With different contents, the array slices should not be equal. >+ ++vec2.back(); >+ EXPECT_NE(from1, from2); >+} >+ >+class IntSpanOrderComparisonTest : public testing::Test { >+ public: >+ IntSpanOrderComparisonTest() >+ : arr_before_{1, 2, 3}, >+ arr_after_{1, 2, 4}, >+ carr_after_{1, 2, 4}, >+ vec_before_(std::begin(arr_before_), std::end(arr_before_)), >+ vec_after_(std::begin(arr_after_), std::end(arr_after_)), >+ before_(vec_before_), >+ after_(vec_after_), >+ cbefore_(vec_before_), >+ cafter_(vec_after_) {} >+ >+ protected: >+ int arr_before_[3], arr_after_[3]; >+ const int carr_after_[3]; >+ std::vector<int> vec_before_, vec_after_; >+ absl::Span<int> before_, after_; >+ absl::Span<const int> cbefore_, cafter_; >+}; >+ >+TEST_F(IntSpanOrderComparisonTest, CompareSpans) { >+ EXPECT_TRUE(cbefore_ < cafter_); >+ EXPECT_TRUE(cbefore_ <= cafter_); >+ EXPECT_TRUE(cafter_ > cbefore_); >+ EXPECT_TRUE(cafter_ >= cbefore_); >+ >+ EXPECT_FALSE(cbefore_ > cafter_); >+ EXPECT_FALSE(cafter_ < cbefore_); >+ >+ EXPECT_TRUE(before_ < after_); >+ EXPECT_TRUE(before_ <= after_); >+ EXPECT_TRUE(after_ > before_); >+ EXPECT_TRUE(after_ >= before_); >+ >+ EXPECT_FALSE(before_ > after_); >+ EXPECT_FALSE(after_ < before_); >+ >+ EXPECT_TRUE(cbefore_ < after_); >+ EXPECT_TRUE(cbefore_ <= after_); >+ EXPECT_TRUE(after_ > cbefore_); >+ EXPECT_TRUE(after_ >= cbefore_); >+ >+ EXPECT_FALSE(cbefore_ > after_); >+ EXPECT_FALSE(after_ < cbefore_); >+} >+ >+TEST_F(IntSpanOrderComparisonTest, SpanOfConstAndContainer) { >+ EXPECT_TRUE(cbefore_ < vec_after_); >+ EXPECT_TRUE(cbefore_ <= vec_after_); >+ EXPECT_TRUE(vec_after_ > cbefore_); >+ EXPECT_TRUE(vec_after_ >= cbefore_); >+ >+ EXPECT_FALSE(cbefore_ > vec_after_); >+ EXPECT_FALSE(vec_after_ < cbefore_); >+ >+ EXPECT_TRUE(arr_before_ < cafter_); >+ EXPECT_TRUE(arr_before_ <= cafter_); >+ EXPECT_TRUE(cafter_ > arr_before_); >+ EXPECT_TRUE(cafter_ >= arr_before_); >+ >+ EXPECT_FALSE(arr_before_ > cafter_); >+ EXPECT_FALSE(cafter_ < arr_before_); >+} >+ >+TEST_F(IntSpanOrderComparisonTest, SpanOfMutableAndContainer) { >+ EXPECT_TRUE(vec_before_ < after_); >+ EXPECT_TRUE(vec_before_ <= after_); >+ EXPECT_TRUE(after_ > vec_before_); >+ EXPECT_TRUE(after_ >= vec_before_); >+ >+ EXPECT_FALSE(vec_before_ > after_); >+ EXPECT_FALSE(after_ < vec_before_); >+ >+ EXPECT_TRUE(before_ < carr_after_); >+ EXPECT_TRUE(before_ <= carr_after_); >+ EXPECT_TRUE(carr_after_ > before_); >+ EXPECT_TRUE(carr_after_ >= before_); >+ >+ EXPECT_FALSE(before_ > carr_after_); >+ EXPECT_FALSE(carr_after_ < before_); >+} >+ >+TEST_F(IntSpanOrderComparisonTest, EqualSpans) { >+ EXPECT_FALSE(before_ < before_); >+ EXPECT_TRUE(before_ <= before_); >+ EXPECT_FALSE(before_ > before_); >+ EXPECT_TRUE(before_ >= before_); >+} >+ >+TEST_F(IntSpanOrderComparisonTest, Subspans) { >+ auto subspan = before_.subspan(0, 1); >+ EXPECT_TRUE(subspan < before_); >+ EXPECT_TRUE(subspan <= before_); >+ EXPECT_TRUE(before_ > subspan); >+ EXPECT_TRUE(before_ >= subspan); >+ >+ EXPECT_FALSE(subspan > before_); >+ EXPECT_FALSE(before_ < subspan); >+} >+ >+TEST_F(IntSpanOrderComparisonTest, EmptySpans) { >+ absl::Span<int> empty; >+ EXPECT_FALSE(empty < empty); >+ EXPECT_TRUE(empty <= empty); >+ EXPECT_FALSE(empty > empty); >+ EXPECT_TRUE(empty >= empty); >+ >+ EXPECT_TRUE(empty < before_); >+ EXPECT_TRUE(empty <= before_); >+ EXPECT_TRUE(before_ > empty); >+ EXPECT_TRUE(before_ >= empty); >+ >+ EXPECT_FALSE(empty > before_); >+ EXPECT_FALSE(before_ < empty); >+} >+ >+TEST(IntSpan, ExposesContainerTypesAndConsts) { >+ absl::Span<int> slice; >+ CheckType<absl::Span<int>::iterator>(slice.begin()); >+ EXPECT_TRUE((std::is_convertible<decltype(slice.begin()), >+ absl::Span<int>::const_iterator>::value)); >+ CheckType<absl::Span<int>::const_iterator>(slice.cbegin()); >+ EXPECT_TRUE((std::is_convertible<decltype(slice.end()), >+ absl::Span<int>::const_iterator>::value)); >+ CheckType<absl::Span<int>::const_iterator>(slice.cend()); >+ CheckType<absl::Span<int>::reverse_iterator>(slice.rend()); >+ EXPECT_TRUE( >+ (std::is_convertible<decltype(slice.rend()), >+ absl::Span<int>::const_reverse_iterator>::value)); >+ CheckType<absl::Span<int>::const_reverse_iterator>(slice.crend()); >+ testing::StaticAssertTypeEq<int, absl::Span<int>::value_type>(); >+ testing::StaticAssertTypeEq<int, absl::Span<const int>::value_type>(); >+ testing::StaticAssertTypeEq<int*, absl::Span<int>::pointer>(); >+ testing::StaticAssertTypeEq<const int*, absl::Span<const int>::pointer>(); >+ testing::StaticAssertTypeEq<int&, absl::Span<int>::reference>(); >+ testing::StaticAssertTypeEq<const int&, absl::Span<const int>::reference>(); >+ testing::StaticAssertTypeEq<const int&, absl::Span<int>::const_reference>(); >+ testing::StaticAssertTypeEq<const int&, >+ absl::Span<const int>::const_reference>(); >+ EXPECT_EQ(static_cast<absl::Span<int>::size_type>(-1), absl::Span<int>::npos); >+} >+ >+TEST(IntSpan, IteratorsAndReferences) { >+ auto accept_pointer = [](int*) {}; >+ auto accept_reference = [](int&) {}; >+ auto accept_iterator = [](absl::Span<int>::iterator) {}; >+ auto accept_const_iterator = [](absl::Span<int>::const_iterator) {}; >+ auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {}; >+ auto accept_const_reverse_iterator = >+ [](absl::Span<int>::const_reverse_iterator) {}; >+ >+ int a[1]; >+ absl::Span<int> s = a; >+ >+ accept_pointer(s.data()); >+ accept_iterator(s.begin()); >+ accept_const_iterator(s.begin()); >+ accept_const_iterator(s.cbegin()); >+ accept_iterator(s.end()); >+ accept_const_iterator(s.end()); >+ accept_const_iterator(s.cend()); >+ accept_reverse_iterator(s.rbegin()); >+ accept_const_reverse_iterator(s.rbegin()); >+ accept_const_reverse_iterator(s.crbegin()); >+ accept_reverse_iterator(s.rend()); >+ accept_const_reverse_iterator(s.rend()); >+ accept_const_reverse_iterator(s.crend()); >+ >+ accept_reference(s[0]); >+ accept_reference(s.at(0)); >+ accept_reference(s.front()); >+ accept_reference(s.back()); >+} >+ >+TEST(IntSpan, IteratorsAndReferences_Const) { >+ auto accept_pointer = [](int*) {}; >+ auto accept_reference = [](int&) {}; >+ auto accept_iterator = [](absl::Span<int>::iterator) {}; >+ auto accept_const_iterator = [](absl::Span<int>::const_iterator) {}; >+ auto accept_reverse_iterator = [](absl::Span<int>::reverse_iterator) {}; >+ auto accept_const_reverse_iterator = >+ [](absl::Span<int>::const_reverse_iterator) {}; >+ >+ int a[1]; >+ const absl::Span<int> s = a; >+ >+ accept_pointer(s.data()); >+ accept_iterator(s.begin()); >+ accept_const_iterator(s.begin()); >+ accept_const_iterator(s.cbegin()); >+ accept_iterator(s.end()); >+ accept_const_iterator(s.end()); >+ accept_const_iterator(s.cend()); >+ accept_reverse_iterator(s.rbegin()); >+ accept_const_reverse_iterator(s.rbegin()); >+ accept_const_reverse_iterator(s.crbegin()); >+ accept_reverse_iterator(s.rend()); >+ accept_const_reverse_iterator(s.rend()); >+ accept_const_reverse_iterator(s.crend()); >+ >+ accept_reference(s[0]); >+ accept_reference(s.at(0)); >+ accept_reference(s.front()); >+ accept_reference(s.back()); >+} >+ >+TEST(IntSpan, NoexceptTest) { >+ int a[] = {1, 2, 3}; >+ std::vector<int> v; >+ EXPECT_TRUE(noexcept(absl::Span<const int>())); >+ EXPECT_TRUE(noexcept(absl::Span<const int>(a, 2))); >+ EXPECT_TRUE(noexcept(absl::Span<const int>(a))); >+ EXPECT_TRUE(noexcept(absl::Span<const int>(v))); >+ EXPECT_TRUE(noexcept(absl::Span<int>(v))); >+ EXPECT_TRUE(noexcept(absl::Span<const int>({1, 2, 3}))); >+ EXPECT_TRUE(noexcept(absl::MakeSpan(v))); >+ EXPECT_TRUE(noexcept(absl::MakeSpan(a))); >+ EXPECT_TRUE(noexcept(absl::MakeSpan(a, 2))); >+ EXPECT_TRUE(noexcept(absl::MakeSpan(a, a + 1))); >+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(v))); >+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a))); >+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, 2))); >+ EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, a + 1))); >+ >+ absl::Span<int> s(v); >+ EXPECT_TRUE(noexcept(s.data())); >+ EXPECT_TRUE(noexcept(s.size())); >+ EXPECT_TRUE(noexcept(s.length())); >+ EXPECT_TRUE(noexcept(s.empty())); >+ EXPECT_TRUE(noexcept(s[0])); >+ EXPECT_TRUE(noexcept(s.front())); >+ EXPECT_TRUE(noexcept(s.back())); >+ EXPECT_TRUE(noexcept(s.begin())); >+ EXPECT_TRUE(noexcept(s.cbegin())); >+ EXPECT_TRUE(noexcept(s.end())); >+ EXPECT_TRUE(noexcept(s.cend())); >+ EXPECT_TRUE(noexcept(s.rbegin())); >+ EXPECT_TRUE(noexcept(s.crbegin())); >+ EXPECT_TRUE(noexcept(s.rend())); >+ EXPECT_TRUE(noexcept(s.crend())); >+ EXPECT_TRUE(noexcept(s.remove_prefix(0))); >+ EXPECT_TRUE(noexcept(s.remove_suffix(0))); >+} >+ >+// ConstexprTester exercises expressions in a constexpr context. Simply placing >+// the expression in a constexpr function is not enough, as some compilers will >+// simply compile the constexpr function as runtime code. Using template >+// parameters forces compile-time execution. >+template <int i> >+struct ConstexprTester {}; >+ >+#define ABSL_TEST_CONSTEXPR(expr) \ >+ do { \ >+ ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \ >+ } while (0) >+ >+struct ContainerWithConstexprMethods { >+ constexpr int size() const { return 1; } >+ constexpr const int* data() const { return &i; } >+ const int i; >+}; >+ >+TEST(ConstIntSpan, ConstexprTest) { >+ static constexpr int a[] = {1, 2, 3}; >+ static constexpr int sized_arr[2] = {1, 2}; >+ static constexpr ContainerWithConstexprMethods c{1}; >+ ABSL_TEST_CONSTEXPR(absl::Span<const int>()); >+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(a, 2)); >+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(sized_arr)); >+ ABSL_TEST_CONSTEXPR(absl::Span<const int>(c)); >+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(&a[0], 1)); >+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(c)); >+ ABSL_TEST_CONSTEXPR(absl::MakeSpan(a)); >+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(&a[0], 1)); >+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(c)); >+ ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(a)); >+ >+ constexpr absl::Span<const int> span = c; >+ ABSL_TEST_CONSTEXPR(span.data()); >+ ABSL_TEST_CONSTEXPR(span.size()); >+ ABSL_TEST_CONSTEXPR(span.length()); >+ ABSL_TEST_CONSTEXPR(span.empty()); >+ ABSL_TEST_CONSTEXPR(span.begin()); >+ ABSL_TEST_CONSTEXPR(span.cbegin()); >+ ABSL_TEST_CONSTEXPR(span.subspan(0, 0)); >+ ABSL_TEST_CONSTEXPR(span[0]); >+} >+ >+struct BigStruct { >+ char bytes[10000]; >+}; >+ >+TEST(Span, SpanSize) { >+ EXPECT_LE(sizeof(absl::Span<int>), 2 * sizeof(void*)); >+ EXPECT_LE(sizeof(absl::Span<BigStruct>), 2 * sizeof(void*)); >+} >+ >+} // namespace >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant.h >new file mode 100644 >index 00000000000..17e0634de03 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant.h >@@ -0,0 +1,849 @@ >+// Copyright 2018 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// ----------------------------------------------------------------------------- >+// variant.h >+// ----------------------------------------------------------------------------- >+// >+// This header file defines an `absl::variant` type for holding a type-safe >+// value of some prescribed set of types (noted as alternative types), and >+// associated functions for managing variants. >+// >+// The `absl::variant` type is a form of type-safe union. An `absl::variant` >+// should always hold a value of one of its alternative types (except in the >+// "valueless by exception state" -- see below). A default-constructed >+// `absl::variant` will hold the value of its first alternative type, provided >+// it is default-constructable. >+// >+// In exceptional cases due to error, an `absl::variant` can hold no >+// value (known as a "valueless by exception" state), though this is not the >+// norm. >+// >+// As with `absl::optional`, an `absl::variant` -- when it holds a value -- >+// allocates a value of that type directly within the `variant` itself; it >+// cannot hold a reference, array, or the type `void`; it can, however, hold a >+// pointer to externally managed memory. >+// >+// `absl::variant` is a C++11 compatible version of the C++17 `std::variant` >+// abstraction and is designed to be a drop-in replacement for code compliant >+// with C++17. >+ >+#ifndef ABSL_TYPES_VARIANT_H_ >+#define ABSL_TYPES_VARIANT_H_ >+ >+#include "absl/base/config.h" >+#include "absl/utility/utility.h" >+ >+#ifdef ABSL_HAVE_STD_VARIANT >+ >+#include <variant> >+ >+namespace absl { >+using std::bad_variant_access; >+using std::get; >+using std::get_if; >+using std::holds_alternative; >+using std::monostate; >+using std::variant; >+using std::variant_alternative; >+using std::variant_alternative_t; >+using std::variant_npos; >+using std::variant_size; >+using std::variant_size_v; >+using std::visit; >+} // namespace absl >+ >+#else // ABSL_HAVE_STD_VARIANT >+ >+#include <functional> >+#include <new> >+#include <type_traits> >+#include <utility> >+ >+#include "absl/base/macros.h" >+#include "absl/base/port.h" >+#include "absl/meta/type_traits.h" >+#include "absl/types/internal/variant.h" >+ >+namespace absl { >+ >+// ----------------------------------------------------------------------------- >+// absl::variant >+// ----------------------------------------------------------------------------- >+// >+// An 'absl::variant` type is a form of type-safe union. An `absl::variant` -- >+// except in exceptional cases -- always holds a value of one of its alternative >+// types. >+// >+// Example: >+// >+// // Construct a variant that holds either an integer or a std::string and >+// // assign it to a std::string. >+// absl::variant<int, std::string> v = std::string("abc"); >+// >+// // A default-contructed variant will hold a value-initialized value of >+// // the first alternative type. >+// auto a = absl::variant<int, std::string>(); // Holds an int of value '0'. >+// >+// // variants are assignable. >+// >+// // copy assignment >+// auto v1 = absl::variant<int, std::string>("abc"); >+// auto v2 = absl::variant<int, std::string>(10); >+// v2 = v1; // copy assign >+// >+// // move assignment >+// auto v1 = absl::variant<int, std::string>("abc"); >+// v1 = absl::variant<int, std::string>(10); >+// >+// // assignment through type conversion >+// a = 128; // variant contains int >+// a = "128"; // variant contains std::string >+// >+// An `absl::variant` holding a value of one of its alternative types `T` holds >+// an allocation of `T` directly within the variant itself. An `absl::variant` >+// is not allowed to allocate additional storage, such as dynamic memory, to >+// allocate the contained value. The contained value shall be allocated in a >+// region of the variant storage suitably aligned for all alternative types. >+template <typename... Ts> >+class variant; >+ >+// swap() >+// >+// Swaps two `absl::variant` values. This function is equivalent to `v.swap(w)` >+// where `v` and `w` are `absl::variant` types. >+// >+// Note that this function requires all alternative types to be both swappable >+// and move-constructible, because any two variants may refer to either the same >+// type (in which case, they will be swapped) or to two different types (in >+// which case the values will need to be moved). >+// >+template <typename... Ts> >+void swap(variant<Ts...>& v, variant<Ts...>& w) noexcept(noexcept(v.swap(w))) { >+ v.swap(w); >+} >+ >+// variant_size >+// >+// Returns the number of alterative types available for a given `absl::variant` >+// type as a compile-time constant expression. As this is a class template, it >+// is not generally useful for accessing the number of alternative types of >+// any given `absl::variant` instance. >+// >+// Example: >+// >+// auto a = absl::variant<int, std::string>; >+// constexpr int num_types = >+// absl::variant_size<absl::variant<int, std::string>>(); >+// >+// // You can also use the member constant `value`. >+// constexpr int num_types = >+// absl::variant_size<absl::variant<int, std::string>>::value; >+// >+// // `absl::variant_size` is more valuable for use in generic code: >+// template <typename Variant> >+// constexpr bool IsVariantMultivalue() { >+// return absl::variant_size<Variant>() > 1; >+// } >+// >+// Note that the set of cv-qualified specializations of `variant_size` are >+// provided to ensure that those specializations compile (especially when passed >+// within template logic). >+template <class T> >+struct variant_size; >+ >+template <class... Ts> >+struct variant_size<variant<Ts...>> >+ : std::integral_constant<std::size_t, sizeof...(Ts)> {}; >+ >+// Specialization of `variant_size` for const qualified variants. >+template <class T> >+struct variant_size<const T> : variant_size<T>::type {}; >+ >+// Specialization of `variant_size` for volatile qualified variants. >+template <class T> >+struct variant_size<volatile T> : variant_size<T>::type {}; >+ >+// Specialization of `variant_size` for const volatile qualified variants. >+template <class T> >+struct variant_size<const volatile T> : variant_size<T>::type {}; >+ >+// variant_alternative >+// >+// Returns the alternative type for a given `absl::variant` at the passed >+// index value as a compile-time constant expression. As this is a class >+// template resulting in a type, it is not useful for access of the run-time >+// value of any given `absl::variant` variable. >+// >+// Example: >+// >+// // The type of the 0th alternative is "int". >+// using alternative_type_0 >+// = absl::variant_alternative<0, absl::variant<int, std::string>>::type; >+// >+// static_assert(std::is_same<alternative_type_0, int>::value, ""); >+// >+// // `absl::variant_alternative` is more valuable for use in generic code: >+// template <typename Variant> >+// constexpr bool IsFirstElementTrivial() { >+// return std::is_trivial_v<variant_alternative<0, Variant>::type>; >+// } >+// >+// Note that the set of cv-qualified specializations of `variant_alternative` >+// are provided to ensure that those specializations compile (especially when >+// passed within template logic). >+template <std::size_t I, class T> >+struct variant_alternative; >+ >+template <std::size_t I, class... Types> >+struct variant_alternative<I, variant<Types...>> { >+ using type = >+ variant_internal::VariantAlternativeSfinaeT<I, variant<Types...>>; >+}; >+ >+// Specialization of `variant_alternative` for const qualified variants. >+template <std::size_t I, class T> >+struct variant_alternative<I, const T> { >+ using type = const typename variant_alternative<I, T>::type; >+}; >+ >+// Specialization of `variant_alternative` for volatile qualified variants. >+template <std::size_t I, class T> >+struct variant_alternative<I, volatile T> { >+ using type = volatile typename variant_alternative<I, T>::type; >+}; >+ >+// Specialization of `variant_alternative` for const volatile qualified >+// variants. >+template <std::size_t I, class T> >+struct variant_alternative<I, const volatile T> { >+ using type = const volatile typename variant_alternative<I, T>::type; >+}; >+ >+// Template type alias for variant_alternative<I, T>::type. >+// >+// Example: >+// >+// using alternative_type_0 >+// = absl::variant_alternative_t<0, absl::variant<int, std::string>>; >+// static_assert(std::is_same<alternative_type_0, int>::value, ""); >+template <std::size_t I, class T> >+using variant_alternative_t = typename variant_alternative<I, T>::type; >+ >+// holds_alternative() >+// >+// Checks whether the given variant currently holds a given alternative type, >+// returning `true` if so. >+// >+// Example: >+// >+// absl::variant<int, std::string> foo = 42; >+// if (absl::holds_alternative<int>(foo)) { >+// std::cout << "The variant holds an integer"; >+// } >+template <class T, class... Types> >+constexpr bool holds_alternative(const variant<Types...>& v) noexcept { >+ static_assert( >+ variant_internal::UnambiguousIndexOfImpl<variant<Types...>, T, >+ 0>::value != sizeof...(Types), >+ "The type T must occur exactly once in Types..."); >+ return v.index() == >+ variant_internal::UnambiguousIndexOf<variant<Types...>, T>::value; >+} >+ >+// get() >+// >+// Returns a reference to the value currently within a given variant, using >+// either a unique alternative type amongst the variant's set of alternative >+// types, or the variant's index value. Attempting to get a variant's value >+// using a type that is not unique within the variant's set of alternative types >+// is a compile-time error. If the index of the alternative being specified is >+// different from the index of the alternative that is currently stored, throws >+// `absl::bad_variant_access`. >+// >+// Example: >+// >+// auto a = absl::variant<int, std::string>; >+// >+// // Get the value by type (if unique). >+// int i = absl::get<int>(a); >+// >+// auto b = absl::variant<int, int>; >+// >+// // Getting the value by a type that is not unique is ill-formed. >+// int j = absl::get<int>(b); // Compile Error! >+// >+// // Getting value by index not ambiguous and allowed. >+// int k = absl::get<1>(b); >+ >+// Overload for getting a variant's lvalue by type. >+template <class T, class... Types> >+constexpr T& get(variant<Types...>& v) { // NOLINT >+ return variant_internal::VariantCoreAccess::CheckedAccess< >+ variant_internal::IndexOf<T, Types...>::value>(v); >+} >+ >+// Overload for getting a variant's rvalue by type. >+// Note: `absl::move()` is required to allow use of constexpr in C++11. >+template <class T, class... Types> >+constexpr T&& get(variant<Types...>&& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess< >+ variant_internal::IndexOf<T, Types...>::value>(absl::move(v)); >+} >+ >+// Overload for getting a variant's const lvalue by type. >+template <class T, class... Types> >+constexpr const T& get(const variant<Types...>& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess< >+ variant_internal::IndexOf<T, Types...>::value>(v); >+} >+ >+// Overload for getting a variant's const rvalue by type. >+// Note: `absl::move()` is required to allow use of constexpr in C++11. >+template <class T, class... Types> >+constexpr const T&& get(const variant<Types...>&& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess< >+ variant_internal::IndexOf<T, Types...>::value>(absl::move(v)); >+} >+ >+// Overload for getting a variant's lvalue by index. >+template <std::size_t I, class... Types> >+constexpr variant_alternative_t<I, variant<Types...>>& get( >+ variant<Types...>& v) { // NOLINT >+ return variant_internal::VariantCoreAccess::CheckedAccess<I>(v); >+} >+ >+// Overload for getting a variant's rvalue by index. >+// Note: `absl::move()` is required to allow use of constexpr in C++11. >+template <std::size_t I, class... Types> >+constexpr variant_alternative_t<I, variant<Types...>>&& get( >+ variant<Types...>&& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v)); >+} >+ >+// Overload for getting a variant's const lvalue by index. >+template <std::size_t I, class... Types> >+constexpr const variant_alternative_t<I, variant<Types...>>& get( >+ const variant<Types...>& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess<I>(v); >+} >+ >+// Overload for getting a variant's const rvalue by index. >+// Note: `absl::move()` is required to allow use of constexpr in C++11. >+template <std::size_t I, class... Types> >+constexpr const variant_alternative_t<I, variant<Types...>>&& get( >+ const variant<Types...>&& v) { >+ return variant_internal::VariantCoreAccess::CheckedAccess<I>(absl::move(v)); >+} >+ >+// get_if() >+// >+// Returns a pointer to the value currently stored within a given variant, if >+// present, using either a unique alternative type amongst the variant's set of >+// alternative types, or the variant's index value. If such a value does not >+// exist, returns `nullptr`. >+// >+// As with `get`, attempting to get a variant's value using a type that is not >+// unique within the variant's set of alternative types is a compile-time error. >+ >+// Overload for getting a pointer to the value stored in the given variant by >+// index. >+template <std::size_t I, class... Types> >+constexpr absl::add_pointer_t<variant_alternative_t<I, variant<Types...>>> >+get_if(variant<Types...>* v) noexcept { >+ return (v != nullptr && v->index() == I) >+ ? std::addressof( >+ variant_internal::VariantCoreAccess::Access<I>(*v)) >+ : nullptr; >+} >+ >+// Overload for getting a pointer to the const value stored in the given >+// variant by index. >+template <std::size_t I, class... Types> >+constexpr absl::add_pointer_t<const variant_alternative_t<I, variant<Types...>>> >+get_if(const variant<Types...>* v) noexcept { >+ return (v != nullptr && v->index() == I) >+ ? std::addressof( >+ variant_internal::VariantCoreAccess::Access<I>(*v)) >+ : nullptr; >+} >+ >+// Overload for getting a pointer to the value stored in the given variant by >+// type. >+template <class T, class... Types> >+constexpr absl::add_pointer_t<T> get_if(variant<Types...>* v) noexcept { >+ return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v); >+} >+ >+// Overload for getting a pointer to the const value stored in the given variant >+// by type. >+template <class T, class... Types> >+constexpr absl::add_pointer_t<const T> get_if( >+ const variant<Types...>* v) noexcept { >+ return absl::get_if<variant_internal::IndexOf<T, Types...>::value>(v); >+} >+ >+// visit() >+// >+// Calls a provided functor on a given set of variants. `absl::visit()` is >+// commonly used to conditionally inspect the state of a given variant (or set >+// of variants). >+// Requires: The expression in the Effects: element shall be a valid expression >+// of the same type and value category, for all combinations of alternative >+// types of all variants. Otherwise, the program is ill-formed. >+// >+// Example: >+// >+// // Define a visitor functor >+// struct GetVariant { >+// template<typename T> >+// void operator()(const T& i) const { >+// std::cout << "The variant's value is: " << i; >+// } >+// }; >+// >+// // Declare our variant, and call `absl::visit()` on it. >+// std::variant<int, std::string> foo = std::string("foo"); >+// GetVariant visitor; >+// std::visit(visitor, foo); // Prints `The variant's value is: foo' >+template <typename Visitor, typename... Variants> >+variant_internal::VisitResult<Visitor, Variants...> visit(Visitor&& vis, >+ Variants&&... vars) { >+ return variant_internal:: >+ VisitIndices<variant_size<absl::decay_t<Variants> >::value...>::Run( >+ variant_internal::PerformVisitation<Visitor, Variants...>{ >+ std::forward_as_tuple(absl::forward<Variants>(vars)...), >+ absl::forward<Visitor>(vis)}, >+ vars.index()...); >+} >+ >+// monostate >+// >+// The monostate class serves as a first alternative type for a variant for >+// which the first variant type is otherwise not default-constructible. >+struct monostate {}; >+ >+// `absl::monostate` Relational Operators >+ >+constexpr bool operator<(monostate, monostate) noexcept { return false; } >+constexpr bool operator>(monostate, monostate) noexcept { return false; } >+constexpr bool operator<=(monostate, monostate) noexcept { return true; } >+constexpr bool operator>=(monostate, monostate) noexcept { return true; } >+constexpr bool operator==(monostate, monostate) noexcept { return true; } >+constexpr bool operator!=(monostate, monostate) noexcept { return false; } >+ >+ >+//------------------------------------------------------------------------------ >+// `absl::variant` Template Definition >+//------------------------------------------------------------------------------ >+template <typename T0, typename... Tn> >+class variant<T0, Tn...> : private variant_internal::VariantBase<T0, Tn...> { >+ static_assert(absl::conjunction<std::is_object<T0>, >+ std::is_object<Tn>...>::value, >+ "Attempted to instantiate a variant containing a non-object " >+ "type."); >+ // Intentionally not qualifing `negation` with `absl::` to work around a bug >+ // in MSVC 2015 with inline namespace and variadic template. >+ static_assert(absl::conjunction<negation<std::is_array<T0> >, >+ negation<std::is_array<Tn> >...>::value, >+ "Attempted to instantiate a variant containing an array type."); >+ static_assert(absl::conjunction<std::is_nothrow_destructible<T0>, >+ std::is_nothrow_destructible<Tn>...>::value, >+ "Attempted to instantiate a variant containing a non-nothrow " >+ "destructible type."); >+ >+ friend struct variant_internal::VariantCoreAccess; >+ >+ private: >+ using Base = variant_internal::VariantBase<T0, Tn...>; >+ >+ public: >+ // Constructors >+ >+ // Constructs a variant holding a default-initialized value of the first >+ // alternative type. >+ constexpr variant() /*noexcept(see 111above)*/ = default; >+ >+ // Copy constructor, standard semantics >+ variant(const variant& other) = default; >+ >+ // Move constructor, standard semantics >+ variant(variant&& other) /*noexcept(see above)*/ = default; >+ >+ // Constructs a variant of an alternative type specified by overload >+ // resolution of the provided forwarding arguments through >+ // direct-initialization. >+ // >+ // Note: If the selected constructor is a constexpr constructor, this >+ // constructor shall be a constexpr constructor. >+ // >+ // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html >+ // has been voted passed the design phase in the C++ standard meeting in Mar >+ // 2018. It will be implemented and integrated into `absl::variant`. >+ template < >+ class T, >+ std::size_t I = std::enable_if< >+ variant_internal::IsNeitherSelfNorInPlace<variant, >+ absl::decay_t<T>>::value, >+ variant_internal::IndexOfConstructedType<variant, T>>::type::value, >+ class Tj = absl::variant_alternative_t<I, variant>, >+ absl::enable_if_t<std::is_constructible<Tj, T>::value>* = >+ nullptr> >+ constexpr variant(T&& t) noexcept(std::is_nothrow_constructible<Tj, T>::value) >+ : Base(variant_internal::EmplaceTag<I>(), absl::forward<T>(t)) {} >+ >+ // Constructs a variant of an alternative type from the arguments through >+ // direct-initialization. >+ // >+ // Note: If the selected constructor is a constexpr constructor, this >+ // constructor shall be a constexpr constructor. >+ template <class T, class... Args, >+ typename std::enable_if<std::is_constructible< >+ variant_internal::UnambiguousTypeOfT<variant, T>, >+ Args...>::value>::type* = nullptr> >+ constexpr explicit variant(in_place_type_t<T>, Args&&... args) >+ : Base(variant_internal::EmplaceTag< >+ variant_internal::UnambiguousIndexOf<variant, T>::value>(), >+ absl::forward<Args>(args)...) {} >+ >+ // Constructs a variant of an alternative type from an initializer list >+ // and other arguments through direct-initialization. >+ // >+ // Note: If the selected constructor is a constexpr constructor, this >+ // constructor shall be a constexpr constructor. >+ template <class T, class U, class... Args, >+ typename std::enable_if<std::is_constructible< >+ variant_internal::UnambiguousTypeOfT<variant, T>, >+ std::initializer_list<U>&, Args...>::value>::type* = nullptr> >+ constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il, >+ Args&&... args) >+ : Base(variant_internal::EmplaceTag< >+ variant_internal::UnambiguousIndexOf<variant, T>::value>(), >+ il, absl::forward<Args>(args)...) {} >+ >+ // Constructs a variant of an alternative type from a provided index, >+ // through value-initialization using the provided forwarded arguments. >+ template <std::size_t I, class... Args, >+ typename std::enable_if<std::is_constructible< >+ variant_internal::VariantAlternativeSfinaeT<I, variant>, >+ Args...>::value>::type* = nullptr> >+ constexpr explicit variant(in_place_index_t<I>, Args&&... args) >+ : Base(variant_internal::EmplaceTag<I>(), absl::forward<Args>(args)...) {} >+ >+ // Constructs a variant of an alternative type from a provided index, >+ // through value-initialization of an initializer list and the provided >+ // forwarded arguments. >+ template <std::size_t I, class U, class... Args, >+ typename std::enable_if<std::is_constructible< >+ variant_internal::VariantAlternativeSfinaeT<I, variant>, >+ std::initializer_list<U>&, Args...>::value>::type* = nullptr> >+ constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il, >+ Args&&... args) >+ : Base(variant_internal::EmplaceTag<I>(), il, >+ absl::forward<Args>(args)...) {} >+ >+ // Destructors >+ >+ // Destroys the variant's currently contained value, provided that >+ // `absl::valueless_by_exception()` is false. >+ ~variant() = default; >+ >+ // Assignment Operators >+ >+ // Copy assignement operator >+ variant& operator=(const variant& other) = default; >+ >+ // Move assignment operator >+ variant& operator=(variant&& other) /*noexcept(see above)*/ = default; >+ >+ // Converting assignment operator >+ // >+ // NOTE: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0608r1.html >+ // has been voted passed the design phase in the C++ standard meeting in Mar >+ // 2018. It will be implemented and integrated into `absl::variant`. >+ template < >+ class T, >+ std::size_t I = std::enable_if< >+ !std::is_same<absl::decay_t<T>, variant>::value, >+ variant_internal::IndexOfConstructedType<variant, T>>::type::value, >+ class Tj = absl::variant_alternative_t<I, variant>, >+ typename std::enable_if<std::is_assignable<Tj&, T>::value && >+ std::is_constructible<Tj, T>::value>::type* = >+ nullptr> >+ variant& operator=(T&& t) noexcept( >+ std::is_nothrow_assignable<Tj&, T>::value&& >+ std::is_nothrow_constructible<Tj, T>::value) { >+ variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run( >+ variant_internal::VariantCoreAccess::MakeConversionAssignVisitor( >+ this, absl::forward<T>(t)), >+ index()); >+ >+ return *this; >+ } >+ >+ >+ // emplace() Functions >+ >+ // Constructs a value of the given alternative type T within the variant. >+ // >+ // Example: >+ // >+ // absl::variant<std::vector<int>, int, std::string> v; >+ // v.emplace<int>(99); >+ // v.emplace<std::string>("abc"); >+ template < >+ class T, class... Args, >+ typename std::enable_if<std::is_constructible< >+ absl::variant_alternative_t< >+ variant_internal::UnambiguousIndexOf<variant, T>::value, variant>, >+ Args...>::value>::type* = nullptr> >+ T& emplace(Args&&... args) { >+ return variant_internal::VariantCoreAccess::Replace< >+ variant_internal::UnambiguousIndexOf<variant, T>::value>( >+ this, absl::forward<Args>(args)...); >+ } >+ >+ // Constructs a value of the given alternative type T within the variant using >+ // an initializer list. >+ // >+ // Example: >+ // >+ // absl::variant<std::vector<int>, int, std::string> v; >+ // v.emplace<std::vector<int>>({0, 1, 2}); >+ template < >+ class T, class U, class... Args, >+ typename std::enable_if<std::is_constructible< >+ absl::variant_alternative_t< >+ variant_internal::UnambiguousIndexOf<variant, T>::value, variant>, >+ std::initializer_list<U>&, Args...>::value>::type* = nullptr> >+ T& emplace(std::initializer_list<U> il, Args&&... args) { >+ return variant_internal::VariantCoreAccess::Replace< >+ variant_internal::UnambiguousIndexOf<variant, T>::value>( >+ this, il, absl::forward<Args>(args)...); >+ } >+ >+ // Destroys the current value of the variant (provided that >+ // `absl::valueless_by_exception()` is false, and constructs a new value at >+ // the given index. >+ // >+ // Example: >+ // >+ // absl::variant<std::vector<int>, int, int> v; >+ // v.emplace<1>(99); >+ // v.emplace<2>(98); >+ // v.emplace<int>(99); // Won't compile. 'int' isn't a unique type. >+ template <std::size_t I, class... Args, >+ typename std::enable_if< >+ std::is_constructible<absl::variant_alternative_t<I, variant>, >+ Args...>::value>::type* = nullptr> >+ absl::variant_alternative_t<I, variant>& emplace(Args&&... args) { >+ return variant_internal::VariantCoreAccess::Replace<I>( >+ this, absl::forward<Args>(args)...); >+ } >+ >+ // Destroys the current value of the variant (provided that >+ // `absl::valueless_by_exception()` is false, and constructs a new value at >+ // the given index using an initializer list and the provided arguments. >+ // >+ // Example: >+ // >+ // absl::variant<std::vector<int>, int, int> v; >+ // v.emplace<0>({0, 1, 2}); >+ template <std::size_t I, class U, class... Args, >+ typename std::enable_if<std::is_constructible< >+ absl::variant_alternative_t<I, variant>, >+ std::initializer_list<U>&, Args...>::value>::type* = nullptr> >+ absl::variant_alternative_t<I, variant>& emplace(std::initializer_list<U> il, >+ Args&&... args) { >+ return variant_internal::VariantCoreAccess::Replace<I>( >+ this, il, absl::forward<Args>(args)...); >+ } >+ >+ // variant::valueless_by_exception() >+ // >+ // Returns false if and only if the variant currently holds a valid value. >+ constexpr bool valueless_by_exception() const noexcept { >+ return this->index_ == absl::variant_npos; >+ } >+ >+ // variant::index() >+ // >+ // Returns the index value of the variant's currently selected alternative >+ // type. >+ constexpr std::size_t index() const noexcept { return this->index_; } >+ >+ // variant::swap() >+ // >+ // Swaps the values of two variant objects. >+ // >+ // TODO(calabrese) >+ // `variant::swap()` and `swap()` rely on `std::is_(nothrow)_swappable()` >+ // which is introduced in C++17. So we assume `is_swappable()` is always >+ // true and `is_nothrow_swappable()` is same as `std::is_trivial()`. >+ void swap(variant& rhs) noexcept( >+ absl::conjunction<std::is_trivial<T0>, std::is_trivial<Tn>...>::value) { >+ return variant_internal::VisitIndices<sizeof...(Tn) + 1>::Run( >+ variant_internal::Swap<T0, Tn...>{this, &rhs}, rhs.index()); >+ } >+}; >+ >+// We need a valid declaration of variant<> for SFINAE and overload resolution >+// to work properly above, but we don't need a full declaration since this type >+// will never be constructed. This declaration, though incomplete, suffices. >+template <> >+class variant<>; >+ >+//------------------------------------------------------------------------------ >+// Relational Operators >+//------------------------------------------------------------------------------ >+// >+// If neither operand is in the `variant::valueless_by_exception` state: >+// >+// * If the index of both variants is the same, the relational operator >+// returns the result of the corresponding relational operator for the >+// corresponding alternative type. >+// * If the index of both variants is not the same, the relational operator >+// returns the result of that operation applied to the value of the left >+// operand's index and the value of the right operand's index. >+// * If at least one operand is in the valueless_by_exception state: >+// - A variant in the valueless_by_exception state is only considered equal >+// to another variant in the valueless_by_exception state. >+// - If exactly one operand is in the valueless_by_exception state, the >+// variant in the valueless_by_exception state is less than the variant >+// that is not in the valueless_by_exception state. >+// >+// Note: The value 1 is added to each index in the relational comparisons such >+// that the index corresponding to the valueless_by_exception state wraps around >+// to 0 (the lowest value for the index type), and the remaining indices stay in >+// the same relative order. >+ >+// Equal-to operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveEqualT<Types...> operator==( >+ const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() == b.index()) && >+ variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::EqualsOp<Types...>{&a, &b}, a.index()); >+} >+ >+// Not equal operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveNotEqualT<Types...> operator!=( >+ const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() != b.index()) || >+ variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::NotEqualsOp<Types...>{&a, &b}, a.index()); >+} >+ >+// Less-than operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveLessThanT<Types...> operator<( >+ const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() != b.index()) >+ ? (a.index() + 1) < (b.index() + 1) >+ : variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::LessThanOp<Types...>{&a, &b}, a.index()); >+} >+ >+// Greater-than operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveGreaterThanT<Types...> operator>( >+ const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() != b.index()) >+ ? (a.index() + 1) > (b.index() + 1) >+ : variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::GreaterThanOp<Types...>{&a, &b}, >+ a.index()); >+} >+ >+// Less-than or equal-to operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveLessThanOrEqualT<Types...> operator<=( >+ const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() != b.index()) >+ ? (a.index() + 1) < (b.index() + 1) >+ : variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::LessThanOrEqualsOp<Types...>{&a, &b}, >+ a.index()); >+} >+ >+// Greater-than or equal-to operator >+template <typename... Types> >+constexpr variant_internal::RequireAllHaveGreaterThanOrEqualT<Types...> >+operator>=(const variant<Types...>& a, const variant<Types...>& b) { >+ return (a.index() != b.index()) >+ ? (a.index() + 1) > (b.index() + 1) >+ : variant_internal::VisitIndices<sizeof...(Types)>::Run( >+ variant_internal::GreaterThanOrEqualsOp<Types...>{&a, &b}, >+ a.index()); >+} >+ >+} // namespace absl >+ >+namespace std { >+ >+// hash() >+template <> // NOLINT >+struct hash<absl::monostate> { >+ std::size_t operator()(absl::monostate) const { return 0; } >+}; >+ >+template <class... T> // NOLINT >+struct hash<absl::variant<T...>> >+ : absl::variant_internal::VariantHashBase<absl::variant<T...>, void, >+ absl::remove_const_t<T>...> {}; >+ >+} // namespace std >+ >+#endif // ABSL_HAVE_STD_VARIANT >+ >+namespace absl { >+namespace variant_internal { >+ >+// Helper visitor for converting a variant<Ts...>` into another type (mostly >+// variant) that can be constructed from any type. >+template <typename To> >+struct ConversionVisitor { >+ template <typename T> >+ To operator()(T&& v) const { >+ return To(std::forward<T>(v)); >+ } >+}; >+ >+} // namespace variant_internal >+ >+// ConvertVariantTo() >+// >+// Helper functions to convert an `absl::variant` to a variant of another set of >+// types, provided that the alternative type of the new variant type can be >+// converted from any type in the source variant. >+// >+// Example: >+// >+// absl::variant<name1, name2, float> InternalReq(const Req&); >+// >+// // name1 and name2 are convertible to name >+// absl::variant<name, float> ExternalReq(const Req& req) { >+// return absl::ConvertVariantTo<absl::variant<name, float>>( >+// InternalReq(req)); >+// } >+template <typename To, typename Variant> >+To ConvertVariantTo(Variant&& variant) { >+ return absl::visit(variant_internal::ConversionVisitor<To>{}, >+ std::forward<Variant>(variant)); >+} >+ >+} // namespace absl >+ >+#endif // ABSL_TYPES_VARIANT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_benchmark.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_benchmark.cc >new file mode 100644 >index 00000000000..99658ac70c4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_benchmark.cc >@@ -0,0 +1,220 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit tests for the variant template. The 'is' and 'IsEmpty' methods >+// of variant are not explicitly tested because they are used repeatedly >+// in building other tests. All other public variant methods should have >+// explicit tests. >+ >+#include "absl/types/variant.h" >+ >+#include <cstddef> >+#include <cstdlib> >+#include <string> >+#include <tuple> >+ >+#include "benchmark/benchmark.h" >+#include "absl/utility/utility.h" >+ >+namespace absl { >+namespace { >+ >+template <std::size_t I> >+struct VariantAlternative { >+ char member; >+}; >+ >+template <class Indices> >+struct VariantOfAlternativesImpl; >+ >+template <std::size_t... Indices> >+struct VariantOfAlternativesImpl<absl::index_sequence<Indices...>> { >+ using type = absl::variant<VariantAlternative<Indices>...>; >+}; >+ >+template <std::size_t NumAlternatives> >+using VariantOfAlternatives = typename VariantOfAlternativesImpl< >+ absl::make_index_sequence<NumAlternatives>>::type; >+ >+struct Empty {}; >+ >+template <class... T> >+void Ignore(T...) noexcept {} >+ >+template <class T> >+Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept { >+ benchmark::DoNotOptimize(arg); >+ return {}; >+} >+ >+struct VisitorApplier { >+ struct Visitor { >+ template <class... T> >+ void operator()(T&&... args) const noexcept { >+ Ignore(DoNotOptimizeAndReturnEmpty(args)...); >+ } >+ }; >+ >+ template <class... Vars> >+ void operator()(const Vars&... vars) const noexcept { >+ absl::visit(Visitor(), vars...); >+ } >+}; >+ >+template <std::size_t NumIndices, std::size_t CurrIndex = NumIndices - 1> >+struct MakeWithIndex { >+ using Variant = VariantOfAlternatives<NumIndices>; >+ >+ static Variant Run(std::size_t index) { >+ return index == CurrIndex >+ ? Variant(absl::in_place_index_t<CurrIndex>()) >+ : MakeWithIndex<NumIndices, CurrIndex - 1>::Run(index); >+ } >+}; >+ >+template <std::size_t NumIndices> >+struct MakeWithIndex<NumIndices, 0> { >+ using Variant = VariantOfAlternatives<NumIndices>; >+ >+ static Variant Run(std::size_t /*index*/) { return Variant(); } >+}; >+ >+template <std::size_t NumIndices, class Dimensions> >+struct MakeVariantTuple; >+ >+template <class T, std::size_t /*I*/> >+using always_t = T; >+ >+template <std::size_t NumIndices> >+VariantOfAlternatives<NumIndices> MakeVariant(std::size_t dimension, >+ std::size_t index) { >+ return dimension == 0 >+ ? MakeWithIndex<NumIndices>::Run(index % NumIndices) >+ : MakeVariant<NumIndices>(dimension - 1, index / NumIndices); >+} >+ >+template <std::size_t NumIndices, std::size_t... Dimensions> >+struct MakeVariantTuple<NumIndices, absl::index_sequence<Dimensions...>> { >+ using VariantTuple = >+ std::tuple<always_t<VariantOfAlternatives<NumIndices>, Dimensions>...>; >+ >+ static VariantTuple Run(int index) { >+ return std::make_tuple(MakeVariant<NumIndices>(Dimensions, index)...); >+ } >+}; >+ >+constexpr std::size_t integral_pow(std::size_t base, std::size_t power) { >+ return power == 0 ? 1 : base * integral_pow(base, power - 1); >+} >+ >+template <std::size_t End, std::size_t I = 0> >+struct VisitTestBody { >+ template <class Vars, class State> >+ static bool Run(Vars& vars, State& state) { >+ if (state.KeepRunning()) { >+ absl::apply(VisitorApplier(), vars[I]); >+ return VisitTestBody<End, I + 1>::Run(vars, state); >+ } >+ return false; >+ } >+}; >+ >+template <std::size_t End> >+struct VisitTestBody<End, End> { >+ template <class Vars, class State> >+ static bool Run(Vars& /*vars*/, State& /*state*/) { >+ return true; >+ } >+}; >+ >+// Visit operations where branch prediction is likely to give a boost. >+template <std::size_t NumIndices, std::size_t NumDimensions = 1> >+void BM_RedundantVisit(benchmark::State& state) { >+ auto vars = >+ MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>:: >+ Run(static_cast<std::size_t>(state.range(0))); >+ >+ for (auto _ : state) { // NOLINT >+ benchmark::DoNotOptimize(vars); >+ absl::apply(VisitorApplier(), vars); >+ } >+} >+ >+// Visit operations where branch prediction is unlikely to give a boost. >+template <std::size_t NumIndices, std::size_t NumDimensions = 1> >+void BM_Visit(benchmark::State& state) { >+ constexpr std::size_t num_possibilities = >+ integral_pow(NumIndices, NumDimensions); >+ >+ using VariantTupleMaker = >+ MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>; >+ using Tuple = typename VariantTupleMaker::VariantTuple; >+ >+ Tuple vars[num_possibilities]; >+ for (std::size_t i = 0; i < num_possibilities; ++i) >+ vars[i] = VariantTupleMaker::Run(i); >+ >+ while (VisitTestBody<num_possibilities>::Run(vars, state)) { >+ } >+} >+ >+// Visitation >+// Each visit is on a different variant with a different active alternative) >+ >+// Unary visit >+BENCHMARK_TEMPLATE(BM_Visit, 1); >+BENCHMARK_TEMPLATE(BM_Visit, 2); >+BENCHMARK_TEMPLATE(BM_Visit, 3); >+BENCHMARK_TEMPLATE(BM_Visit, 4); >+BENCHMARK_TEMPLATE(BM_Visit, 5); >+BENCHMARK_TEMPLATE(BM_Visit, 6); >+BENCHMARK_TEMPLATE(BM_Visit, 7); >+BENCHMARK_TEMPLATE(BM_Visit, 8); >+BENCHMARK_TEMPLATE(BM_Visit, 16); >+BENCHMARK_TEMPLATE(BM_Visit, 32); >+BENCHMARK_TEMPLATE(BM_Visit, 64); >+ >+// Binary visit >+BENCHMARK_TEMPLATE(BM_Visit, 1, 2); >+BENCHMARK_TEMPLATE(BM_Visit, 2, 2); >+BENCHMARK_TEMPLATE(BM_Visit, 3, 2); >+BENCHMARK_TEMPLATE(BM_Visit, 4, 2); >+BENCHMARK_TEMPLATE(BM_Visit, 5, 2); >+ >+// Ternary visit >+BENCHMARK_TEMPLATE(BM_Visit, 1, 3); >+BENCHMARK_TEMPLATE(BM_Visit, 2, 3); >+BENCHMARK_TEMPLATE(BM_Visit, 3, 3); >+ >+// Quaternary visit >+BENCHMARK_TEMPLATE(BM_Visit, 1, 4); >+BENCHMARK_TEMPLATE(BM_Visit, 2, 4); >+ >+// Redundant Visitation >+// Each visit consistently has the same alternative active >+ >+// Unary visit >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0); >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1); >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7); >+ >+// Binary visit >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0); >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2) >+ ->DenseRange(0, integral_pow(2, 2) - 1); >+BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2) >+ ->DenseRange(0, integral_pow(4, 2) - 1); >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc >new file mode 100644 >index 00000000000..27c0b96ca6f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_exception_safety_test.cc >@@ -0,0 +1,508 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+#include "absl/types/variant.h" >+ >+#include <iostream> >+#include <memory> >+#include <utility> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/internal/exception_safety_testing.h" >+#include "absl/memory/memory.h" >+ >+namespace absl { >+namespace { >+ >+using ::testing::MakeExceptionSafetyTester; >+using ::testing::strong_guarantee; >+using ::testing::TestNothrowOp; >+using ::testing::TestThrowingCtor; >+ >+using Thrower = testing::ThrowingValue<>; >+using CopyNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowCopy>; >+using MoveNothrow = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>; >+using ThrowingAlloc = testing::ThrowingAllocator<Thrower>; >+using ThrowerVec = std::vector<Thrower, ThrowingAlloc>; >+using ThrowingVariant = >+ absl::variant<Thrower, CopyNothrow, MoveNothrow, ThrowerVec>; >+ >+struct ConversionException {}; >+ >+template <class T> >+struct ExceptionOnConversion { >+ operator T() const { // NOLINT >+ throw ConversionException(); >+ } >+}; >+ >+// Forces a variant into the valueless by exception state. >+void ToValuelessByException(ThrowingVariant& v) { // NOLINT >+ try { >+ v.emplace<Thrower>(); >+ v.emplace<Thrower>(ExceptionOnConversion<Thrower>()); >+ } catch (ConversionException& /*e*/) { >+ // This space intentionally left blank. >+ } >+} >+ >+// Check that variant is still in a usable state after an exception is thrown. >+testing::AssertionResult CheckInvariants(ThrowingVariant* v) { >+ using testing::AssertionFailure; >+ using testing::AssertionSuccess; >+ >+ // Try using the active alternative >+ if (absl::holds_alternative<Thrower>(*v)) { >+ auto& t = absl::get<Thrower>(*v); >+ t = Thrower{-100}; >+ if (t.Get() != -100) { >+ return AssertionFailure() << "Thrower should be assigned -100"; >+ } >+ } else if (absl::holds_alternative<ThrowerVec>(*v)) { >+ auto& tv = absl::get<ThrowerVec>(*v); >+ tv.clear(); >+ tv.emplace_back(-100); >+ if (tv.size() != 1 || tv[0].Get() != -100) { >+ return AssertionFailure() << "ThrowerVec should be {Thrower{-100}}"; >+ } >+ } else if (absl::holds_alternative<CopyNothrow>(*v)) { >+ auto& t = absl::get<CopyNothrow>(*v); >+ t = CopyNothrow{-100}; >+ if (t.Get() != -100) { >+ return AssertionFailure() << "CopyNothrow should be assigned -100"; >+ } >+ } else if (absl::holds_alternative<MoveNothrow>(*v)) { >+ auto& t = absl::get<MoveNothrow>(*v); >+ t = MoveNothrow{-100}; >+ if (t.Get() != -100) { >+ return AssertionFailure() << "MoveNothrow should be assigned -100"; >+ } >+ } >+ >+ // Try making variant valueless_by_exception >+ if (!v->valueless_by_exception()) ToValuelessByException(*v); >+ if (!v->valueless_by_exception()) { >+ return AssertionFailure() << "Variant should be valueless_by_exception"; >+ } >+ try { >+ auto unused = absl::get<Thrower>(*v); >+ static_cast<void>(unused); >+ return AssertionFailure() << "Variant should not contain Thrower"; >+ } catch (absl::bad_variant_access) { >+ } catch (...) { >+ return AssertionFailure() << "Unexpected exception throw from absl::get"; >+ } >+ >+ // Try using the variant >+ v->emplace<Thrower>(100); >+ if (!absl::holds_alternative<Thrower>(*v) || >+ absl::get<Thrower>(*v) != Thrower(100)) { >+ return AssertionFailure() << "Variant should contain Thrower(100)"; >+ } >+ v->emplace<ThrowerVec>({Thrower(100)}); >+ if (!absl::holds_alternative<ThrowerVec>(*v) || >+ absl::get<ThrowerVec>(*v)[0] != Thrower(100)) { >+ return AssertionFailure() >+ << "Variant should contain ThrowerVec{Thrower(100)}"; >+ } >+ return AssertionSuccess(); >+} >+ >+template <typename... Args> >+Thrower ExpectedThrower(Args&&... args) { >+ return Thrower(42, args...); >+} >+ >+ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; } >+ThrowingVariant ValuelessByException() { >+ ThrowingVariant v; >+ ToValuelessByException(v); >+ return v; >+} >+ThrowingVariant WithThrower() { return Thrower(39); } >+ThrowingVariant WithThrowerVec() { >+ return ThrowerVec{Thrower(1), Thrower(2), Thrower(3)}; >+} >+ThrowingVariant WithCopyNoThrow() { return CopyNothrow(39); } >+ThrowingVariant WithMoveNoThrow() { return MoveNothrow(39); } >+ >+TEST(VariantExceptionSafetyTest, DefaultConstructor) { >+ TestThrowingCtor<ThrowingVariant>(); >+} >+ >+TEST(VariantExceptionSafetyTest, CopyConstructor) { >+ { >+ ThrowingVariant v(ExpectedThrower()); >+ TestThrowingCtor<ThrowingVariant>(v); >+ } >+ { >+ ThrowingVariant v(ExpectedThrowerVec()); >+ TestThrowingCtor<ThrowingVariant>(v); >+ } >+ { >+ ThrowingVariant v(ValuelessByException()); >+ TestThrowingCtor<ThrowingVariant>(v); >+ } >+} >+ >+TEST(VariantExceptionSafetyTest, MoveConstructor) { >+ { >+ ThrowingVariant v(ExpectedThrower()); >+ TestThrowingCtor<ThrowingVariant>(std::move(v)); >+ } >+ { >+ ThrowingVariant v(ExpectedThrowerVec()); >+ TestThrowingCtor<ThrowingVariant>(std::move(v)); >+ } >+ { >+ ThrowingVariant v(ValuelessByException()); >+ TestThrowingCtor<ThrowingVariant>(std::move(v)); >+ } >+} >+ >+TEST(VariantExceptionSafetyTest, ValueConstructor) { >+ TestThrowingCtor<ThrowingVariant>(ExpectedThrower()); >+ TestThrowingCtor<ThrowingVariant>(ExpectedThrowerVec()); >+} >+ >+TEST(VariantExceptionSafetyTest, InPlaceTypeConstructor) { >+ TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<Thrower>{}, >+ ExpectedThrower()); >+ TestThrowingCtor<ThrowingVariant>(absl::in_place_type_t<ThrowerVec>{}, >+ ExpectedThrowerVec()); >+} >+ >+TEST(VariantExceptionSafetyTest, InPlaceIndexConstructor) { >+ TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<0>{}, >+ ExpectedThrower()); >+ TestThrowingCtor<ThrowingVariant>(absl::in_place_index_t<3>{}, >+ ExpectedThrowerVec()); >+} >+ >+TEST(VariantExceptionSafetyTest, CopyAssign) { >+ // variant& operator=(const variant& rhs); >+ // Let j be rhs.index() >+ { >+ // - neither *this nor rhs holds a value >+ const ThrowingVariant rhs = ValuelessByException(); >+ ThrowingVariant lhs = ValuelessByException(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; })); >+ } >+ { >+ // - *this holds a value but rhs does not >+ const ThrowingVariant rhs = ValuelessByException(); >+ ThrowingVariant lhs = WithThrower(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; })); >+ } >+ // - index() == j >+ { >+ const ThrowingVariant rhs(ExpectedThrower()); >+ auto tester = >+ MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); >+ EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test()); >+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); >+ } >+ { >+ const ThrowingVariant rhs(ExpectedThrowerVec()); >+ auto tester = >+ MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrowerVec()) >+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); >+ EXPECT_TRUE(tester.WithInvariants(CheckInvariants).Test()); >+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); >+ } >+ // libstdc++ std::variant has bugs on copy assignment regarding exception >+ // safety. >+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+ // index() != j >+ // if is_nothrow_copy_constructible_v<Tj> or >+ // !is_nothrow_move_constructible<Tj> is true, equivalent to >+ // emplace<j>(get<j>(rhs)) >+ { >+ // is_nothrow_copy_constructible_v<Tj> == true >+ // should not throw because emplace() invokes Tj's copy ctor >+ // which should not throw. >+ const ThrowingVariant rhs(CopyNothrow{}); >+ ThrowingVariant lhs = WithThrower(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; })); >+ } >+ { >+ // is_nothrow_copy_constructible<Tj> == false && >+ // is_nothrow_move_constructible<Tj> == false >+ // should provide basic guarantee because emplace() invokes Tj's copy ctor >+ // which may throw. >+ const ThrowingVariant rhs(ExpectedThrower()); >+ auto tester = >+ MakeExceptionSafetyTester() >+ .WithInitialValue(WithCopyNoThrow()) >+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); >+ EXPECT_TRUE(tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return lhs->valueless_by_exception(); >+ }) >+ .Test()); >+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); >+ } >+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+ { >+ // is_nothrow_copy_constructible_v<Tj> == false && >+ // is_nothrow_move_constructible_v<Tj> == true >+ // should provide strong guarantee because it is equivalent to >+ // operator=(variant(rhs)) which creates a temporary then invoke the move >+ // ctor which shouldn't throw. >+ const ThrowingVariant rhs(MoveNothrow{}); >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithInvariants(CheckInvariants, strong_guarantee) >+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); >+ } >+} >+ >+TEST(VariantExceptionSafetyTest, MoveAssign) { >+ // variant& operator=(variant&& rhs); >+ // Let j be rhs.index() >+ { >+ // - neither *this nor rhs holds a value >+ ThrowingVariant rhs = ValuelessByException(); >+ ThrowingVariant lhs = ValuelessByException(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); })); >+ } >+ { >+ // - *this holds a value but rhs does not >+ ThrowingVariant rhs = ValuelessByException(); >+ ThrowingVariant lhs = WithThrower(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); })); >+ } >+ { >+ // - index() == j >+ // assign get<j>(std::move(rhs)) to the value contained in *this. >+ // If an exception is thrown during call to Tj's move assignment, the state >+ // of the contained value is as defined by the exception safety guarantee of >+ // Tj's move assignment; index() will be j. >+ ThrowingVariant rhs(ExpectedThrower()); >+ size_t j = rhs.index(); >+ // Since Thrower's move assignment has basic guarantee, so should variant's. >+ auto tester = MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithOperation([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ *lhs = std::move(copy); >+ }); >+ EXPECT_TRUE(tester >+ .WithInvariants( >+ CheckInvariants, >+ [&](ThrowingVariant* lhs) { return lhs->index() == j; }) >+ .Test()); >+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); >+ } >+ { >+ // - otherwise (index() != j), equivalent to >+ // emplace<j>(get<j>(std::move(rhs))) >+ // - If an exception is thrown during the call to Tj's move construction >+ // (with j being rhs.index()), the variant will hold no value. >+ ThrowingVariant rhs(CopyNothrow{}); >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return lhs->valueless_by_exception(); >+ }) >+ .Test([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ *lhs = std::move(copy); >+ })); >+ } >+} >+ >+TEST(VariantExceptionSafetyTest, ValueAssign) { >+ // template<class T> variant& operator=(T&& t); >+ // Let Tj be the type that is selected by overload resolution to be assigned. >+ { >+ // If *this holds a Tj, assigns std::forward<T>(t) to the value contained in >+ // *this. If an exception is thrown during the assignment of >+ // std::forward<T>(t) to the value contained in *this, the state of the >+ // contained value and t are as defined by the exception safety guarantee of >+ // the assignment expression; valueless_by_exception() will be false. >+ // Since Thrower's copy/move assignment has basic guarantee, so should >+ // variant's. >+ Thrower rhs = ExpectedThrower(); >+ // copy assign >+ auto copy_tester = >+ MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithOperation([rhs](ThrowingVariant* lhs) { *lhs = rhs; }); >+ EXPECT_TRUE(copy_tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return !lhs->valueless_by_exception(); >+ }) >+ .Test()); >+ EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test()); >+ // move assign >+ auto move_tester = MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithOperation([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ *lhs = std::move(copy); >+ }); >+ EXPECT_TRUE(move_tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return !lhs->valueless_by_exception(); >+ }) >+ .Test()); >+ >+ EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test()); >+ } >+ // Otherwise (*this holds something else), if is_nothrow_constructible_v<Tj, >+ // T> || !is_nothrow_move_constructible_v<Tj> is true, equivalent to >+ // emplace<j>(std::forward<T>(t)). >+ // We simplify the test by letting T = `const Tj&` or `Tj&&`, so we can reuse >+ // the CopyNothrow and MoveNothrow types. >+ >+ // if is_nothrow_constructible_v<Tj, T> >+ // (i.e. is_nothrow_copy/move_constructible_v<Tj>) is true, emplace() just >+ // invokes the copy/move constructor and it should not throw. >+ { >+ const CopyNothrow rhs; >+ ThrowingVariant lhs = WithThrower(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; })); >+ } >+ { >+ MoveNothrow rhs; >+ ThrowingVariant lhs = WithThrower(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); })); >+ } >+ // if is_nothrow_constructible_v<Tj, T> == false && >+ // is_nothrow_move_constructible<Tj> == false >+ // emplace() invokes the copy/move constructor which may throw so it should >+ // provide basic guarantee and variant object might not hold a value. >+ { >+ Thrower rhs = ExpectedThrower(); >+ // copy >+ auto copy_tester = >+ MakeExceptionSafetyTester() >+ .WithInitialValue(WithCopyNoThrow()) >+ .WithOperation([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }); >+ EXPECT_TRUE(copy_tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return lhs->valueless_by_exception(); >+ }) >+ .Test()); >+ EXPECT_FALSE(copy_tester.WithInvariants(strong_guarantee).Test()); >+ // move >+ auto move_tester = MakeExceptionSafetyTester() >+ .WithInitialValue(WithCopyNoThrow()) >+ .WithOperation([](ThrowingVariant* lhs) { >+ *lhs = ExpectedThrower(testing::nothrow_ctor); >+ }); >+ EXPECT_TRUE(move_tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* lhs) { >+ return lhs->valueless_by_exception(); >+ }) >+ .Test()); >+ EXPECT_FALSE(move_tester.WithInvariants(strong_guarantee).Test()); >+ } >+ // Otherwise (if is_nothrow_constructible_v<Tj, T> == false && >+ // is_nothrow_move_constructible<Tj> == true), >+ // equivalent to operator=(variant(std::forward<T>(t))) >+ // This should have strong guarantee because it creates a temporary variant >+ // and operator=(variant&&) invokes Tj's move ctor which doesn't throw. >+ // libstdc++ std::variant has bugs on conversion assignment regarding >+ // exception safety. >+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+ { >+ MoveNothrow rhs; >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithInvariants(CheckInvariants, strong_guarantee) >+ .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; })); >+ } >+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+} >+ >+TEST(VariantExceptionSafetyTest, Emplace) { >+ // If an exception during the initialization of the contained value, the >+ // variant might not hold a value. The standard requires emplace() to provide >+ // only basic guarantee. >+ { >+ Thrower args = ExpectedThrower(); >+ auto tester = MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithOperation([&args](ThrowingVariant* v) { >+ v->emplace<Thrower>(args); >+ }); >+ EXPECT_TRUE(tester >+ .WithInvariants(CheckInvariants, >+ [](ThrowingVariant* v) { >+ return v->valueless_by_exception(); >+ }) >+ .Test()); >+ EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test()); >+ } >+} >+ >+TEST(VariantExceptionSafetyTest, Swap) { >+ // if both are valueless_by_exception(), no effect >+ { >+ ThrowingVariant rhs = ValuelessByException(); >+ ThrowingVariant lhs = ValuelessByException(); >+ EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); })); >+ } >+ // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs)) >+ // where i is index(). >+ { >+ ThrowingVariant rhs = ExpectedThrower(); >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithThrower()) >+ .WithInvariants(CheckInvariants) >+ .Test([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ lhs->swap(copy); >+ })); >+ } >+ // Otherwise, exchanges the value of rhs and *this. The exception safety >+ // involves variant in moved-from state which is not specified in the >+ // standard, and since swap is 3-step it's impossible for it to provide a >+ // overall strong guarantee. So, we are only checking basic guarantee here. >+ { >+ ThrowingVariant rhs = ExpectedThrower(); >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithCopyNoThrow()) >+ .WithInvariants(CheckInvariants) >+ .Test([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ lhs->swap(copy); >+ })); >+ } >+ { >+ ThrowingVariant rhs = ExpectedThrower(); >+ EXPECT_TRUE(MakeExceptionSafetyTester() >+ .WithInitialValue(WithCopyNoThrow()) >+ .WithInvariants(CheckInvariants) >+ .Test([&](ThrowingVariant* lhs) { >+ auto copy = rhs; >+ copy.swap(*lhs); >+ })); >+ } >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_test.cc >new file mode 100644 >index 00000000000..262bd9446c1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/types/variant_test.cc >@@ -0,0 +1,2612 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+// Unit tests for the variant template. The 'is' and 'IsEmpty' methods >+// of variant are not explicitly tested because they are used repeatedly >+// in building other tests. All other public variant methods should have >+// explicit tests. >+ >+#include "absl/types/variant.h" >+ >+#include <algorithm> >+#include <cstddef> >+#include <functional> >+#include <initializer_list> >+#include <memory> >+#include <ostream> >+#include <queue> >+#include <type_traits> >+#include <unordered_set> >+#include <utility> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/config.h" >+#include "absl/base/port.h" >+#include "absl/memory/memory.h" >+#include "absl/meta/type_traits.h" >+#include "absl/strings/string_view.h" >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \ >+ EXPECT_THROW(expr, exception_t) >+ >+#else >+ >+#define ABSL_VARIANT_TEST_EXPECT_FAIL(expr, exception_t, text) \ >+ EXPECT_DEATH(expr, text) >+ >+#endif // ABSL_HAVE_EXCEPTIONS >+ >+#define ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(...) \ >+ ABSL_VARIANT_TEST_EXPECT_FAIL((__VA_ARGS__), absl::bad_variant_access, \ >+ "Bad variant access") >+ >+struct Hashable {}; >+ >+namespace std { >+template <> >+struct hash<Hashable> { >+ size_t operator()(const Hashable&); >+}; >+} // namespace std >+ >+struct NonHashable {}; >+ >+namespace absl { >+namespace { >+ >+using ::testing::DoubleEq; >+using ::testing::Pointee; >+using ::testing::VariantWith; >+ >+struct MoveCanThrow { >+ MoveCanThrow() : v(0) {} >+ MoveCanThrow(int v) : v(v) {} // NOLINT(runtime/explicit) >+ MoveCanThrow(const MoveCanThrow& other) : v(other.v) {} >+ MoveCanThrow& operator=(const MoveCanThrow& /*other*/) { return *this; } >+ int v; >+}; >+ >+bool operator==(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v == rhs.v; } >+bool operator!=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v != rhs.v; } >+bool operator<(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v < rhs.v; } >+bool operator<=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v <= rhs.v; } >+bool operator>=(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v >= rhs.v; } >+bool operator>(MoveCanThrow lhs, MoveCanThrow rhs) { return lhs.v > rhs.v; } >+ >+// This helper class allows us to determine if it was swapped with std::swap() >+// or with its friend swap() function. >+struct SpecialSwap { >+ explicit SpecialSwap(int i) : i(i) {} >+ friend void swap(SpecialSwap& a, SpecialSwap& b) { >+ a.special_swap = b.special_swap = true; >+ std::swap(a.i, b.i); >+ } >+ bool operator==(SpecialSwap other) const { return i == other.i; } >+ int i; >+ bool special_swap = false; >+}; >+ >+struct MoveOnlyWithListConstructor { >+ MoveOnlyWithListConstructor() = default; >+ explicit MoveOnlyWithListConstructor(std::initializer_list<int> /*ilist*/, >+ int value) >+ : value(value) {} >+ MoveOnlyWithListConstructor(MoveOnlyWithListConstructor&&) = default; >+ MoveOnlyWithListConstructor& operator=(MoveOnlyWithListConstructor&&) = >+ default; >+ >+ int value = 0; >+}; >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+struct ConversionException {}; >+ >+template <class T> >+struct ExceptionOnConversion { >+ operator T() const { // NOLINT(runtime/explicit) >+ throw ConversionException(); >+ } >+}; >+ >+// Forces a variant into the valueless by exception state. >+template <class H, class... T> >+void ToValuelessByException(absl::variant<H, T...>& v) { // NOLINT >+ try { >+ v.template emplace<0>(ExceptionOnConversion<H>()); >+ } catch (ConversionException& /*e*/) { >+ // This space intentionally left blank. >+ } >+} >+ >+#endif // ABSL_HAVE_EXCEPTIONS >+ >+// An indexed sequence of distinct structures holding a single >+// value of type T >+template<typename T, size_t N> >+struct ValueHolder { >+ explicit ValueHolder(const T& x) : value(x) {} >+ typedef T value_type; >+ value_type value; >+ static const size_t kIndex = N; >+}; >+template<typename T, size_t N> >+const size_t ValueHolder<T, N>::kIndex; >+ >+// The following three functions make ValueHolder compatible with >+// EXPECT_EQ and EXPECT_NE >+template<typename T, size_t N> >+inline bool operator==(const ValueHolder<T, N>& left, >+ const ValueHolder<T, N>& right) { >+ return left.value == right.value; >+} >+ >+template<typename T, size_t N> >+inline bool operator!=(const ValueHolder<T, N>& left, >+ const ValueHolder<T, N>& right) { >+ return left.value != right.value; >+} >+ >+template<typename T, size_t N> >+inline std::ostream& operator<<( >+ std::ostream& stream, const ValueHolder<T, N>& object) { >+ return stream << object.value; >+} >+ >+// Makes a variant holding twelve uniquely typed T wrappers. >+template<typename T> >+struct VariantFactory { >+ typedef variant<ValueHolder<T, 1>, ValueHolder<T, 2>, ValueHolder<T, 3>, >+ ValueHolder<T, 4>> >+ Type; >+}; >+ >+// A typelist in 1:1 with VariantFactory, to use type driven unit tests. >+typedef ::testing::Types<ValueHolder<size_t, 1>, ValueHolder<size_t, 2>, >+ ValueHolder<size_t, 3>, >+ ValueHolder<size_t, 4>> VariantTypes; >+ >+// Increments the provided counter pointer in the destructor >+struct IncrementInDtor { >+ explicit IncrementInDtor(int* counter) : counter(counter) {} >+ ~IncrementInDtor() { *counter += 1; } >+ int* counter; >+}; >+ >+struct IncrementInDtorCopyCanThrow { >+ explicit IncrementInDtorCopyCanThrow(int* counter) : counter(counter) {} >+ IncrementInDtorCopyCanThrow(IncrementInDtorCopyCanThrow&& other) noexcept = >+ default; >+ IncrementInDtorCopyCanThrow(const IncrementInDtorCopyCanThrow& other) >+ : counter(other.counter) {} >+ IncrementInDtorCopyCanThrow& operator=( >+ IncrementInDtorCopyCanThrow&&) noexcept = default; >+ IncrementInDtorCopyCanThrow& operator=( >+ IncrementInDtorCopyCanThrow const& other) { >+ counter = other.counter; >+ return *this; >+ } >+ ~IncrementInDtorCopyCanThrow() { *counter += 1; } >+ int* counter; >+}; >+ >+// This is defined so operator== for ValueHolder<IncrementInDtor> will >+// return true if two IncrementInDtor objects increment the same >+// counter >+inline bool operator==(const IncrementInDtor& left, >+ const IncrementInDtor& right) { >+ return left.counter == right.counter; >+} >+ >+// This is defined so EXPECT_EQ can work with IncrementInDtor >+inline std::ostream& operator<<( >+ std::ostream& stream, const IncrementInDtor& object) { >+ return stream << object.counter; >+} >+ >+// A class that can be copied, but not assigned. >+class CopyNoAssign { >+ public: >+ explicit CopyNoAssign(int value) : foo(value) {} >+ CopyNoAssign(const CopyNoAssign& other) : foo(other.foo) {} >+ int foo; >+ private: >+ const CopyNoAssign& operator=(const CopyNoAssign&); >+}; >+ >+// A class that can neither be copied nor assigned. We provide >+// overloads for the constructor with up to four parameters so we can >+// test the overloads of variant::emplace. >+class NonCopyable { >+ public: >+ NonCopyable() >+ : value(0) {} >+ explicit NonCopyable(int value1) >+ : value(value1) {} >+ >+ NonCopyable(int value1, int value2) >+ : value(value1 + value2) {} >+ >+ NonCopyable(int value1, int value2, int value3) >+ : value(value1 + value2 + value3) {} >+ >+ NonCopyable(int value1, int value2, int value3, int value4) >+ : value(value1 + value2 + value3 + value4) {} >+ NonCopyable(const NonCopyable&) = delete; >+ NonCopyable& operator=(const NonCopyable&) = delete; >+ int value; >+}; >+ >+// A typed test and typed test case over the VariantTypes typelist, >+// from which we derive a number of tests that will execute for one of >+// each type. >+template <typename T> >+class VariantTypesTest : public ::testing::Test {}; >+TYPED_TEST_CASE(VariantTypesTest, VariantTypes); >+ >+//////////////////// >+// [variant.ctor] // >+//////////////////// >+ >+struct NonNoexceptDefaultConstructible { >+ NonNoexceptDefaultConstructible() {} >+ int value = 5; >+}; >+ >+struct NonDefaultConstructible { >+ NonDefaultConstructible() = delete; >+}; >+ >+TEST(VariantTest, TestDefaultConstructor) { >+ { >+ using X = variant<int>; >+ constexpr variant<int> x{}; >+ ASSERT_FALSE(x.valueless_by_exception()); >+ ASSERT_EQ(0, x.index()); >+ EXPECT_EQ(0, absl::get<0>(x)); >+ EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); >+ } >+ >+ { >+ using X = variant<NonNoexceptDefaultConstructible>; >+ X x{}; >+ ASSERT_FALSE(x.valueless_by_exception()); >+ ASSERT_EQ(0, x.index()); >+ EXPECT_EQ(5, absl::get<0>(x).value); >+ EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); >+ } >+ >+ { >+ using X = variant<int, NonNoexceptDefaultConstructible>; >+ X x{}; >+ ASSERT_FALSE(x.valueless_by_exception()); >+ ASSERT_EQ(0, x.index()); >+ EXPECT_EQ(0, absl::get<0>(x)); >+ EXPECT_TRUE(std::is_nothrow_default_constructible<X>::value); >+ } >+ >+ { >+ using X = variant<NonNoexceptDefaultConstructible, int>; >+ X x{}; >+ ASSERT_FALSE(x.valueless_by_exception()); >+ ASSERT_EQ(0, x.index()); >+ EXPECT_EQ(5, absl::get<0>(x).value); >+ EXPECT_FALSE(std::is_nothrow_default_constructible<X>::value); >+ } >+ EXPECT_FALSE( >+ std::is_default_constructible<variant<NonDefaultConstructible>>::value); >+ EXPECT_FALSE((std::is_default_constructible< >+ variant<NonDefaultConstructible, int>>::value)); >+ EXPECT_TRUE((std::is_default_constructible< >+ variant<int, NonDefaultConstructible>>::value)); >+} >+ >+// Test that for each slot, copy constructing a variant with that type >+// produces a sensible object that correctly reports its type, and >+// that copies the provided value. >+TYPED_TEST(VariantTypesTest, TestCopyCtor) { >+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ using value_type2 = absl::variant_alternative_t<1, Variant>; >+ using value_type3 = absl::variant_alternative_t<2, Variant>; >+ using value_type4 = absl::variant_alternative_t<3, Variant>; >+ const TypeParam value(TypeParam::kIndex); >+ Variant original(value); >+ Variant copied(original); >+ EXPECT_TRUE(absl::holds_alternative<value_type1>(copied) || >+ TypeParam::kIndex != 1); >+ EXPECT_TRUE(absl::holds_alternative<value_type2>(copied) || >+ TypeParam::kIndex != 2); >+ EXPECT_TRUE(absl::holds_alternative<value_type3>(copied) || >+ TypeParam::kIndex != 3); >+ EXPECT_TRUE(absl::holds_alternative<value_type4>(copied) || >+ TypeParam::kIndex != 4); >+ EXPECT_TRUE((absl::get_if<value_type1>(&original) == >+ absl::get_if<value_type1>(&copied)) || >+ TypeParam::kIndex == 1); >+ EXPECT_TRUE((absl::get_if<value_type2>(&original) == >+ absl::get_if<value_type2>(&copied)) || >+ TypeParam::kIndex == 2); >+ EXPECT_TRUE((absl::get_if<value_type3>(&original) == >+ absl::get_if<value_type3>(&copied)) || >+ TypeParam::kIndex == 3); >+ EXPECT_TRUE((absl::get_if<value_type4>(&original) == >+ absl::get_if<value_type4>(&copied)) || >+ TypeParam::kIndex == 4); >+ EXPECT_TRUE((absl::get_if<value_type1>(&original) == >+ absl::get_if<value_type1>(&copied)) || >+ TypeParam::kIndex == 1); >+ EXPECT_TRUE((absl::get_if<value_type2>(&original) == >+ absl::get_if<value_type2>(&copied)) || >+ TypeParam::kIndex == 2); >+ EXPECT_TRUE((absl::get_if<value_type3>(&original) == >+ absl::get_if<value_type3>(&copied)) || >+ TypeParam::kIndex == 3); >+ EXPECT_TRUE((absl::get_if<value_type4>(&original) == >+ absl::get_if<value_type4>(&copied)) || >+ TypeParam::kIndex == 4); >+ const TypeParam* ovalptr = absl::get_if<TypeParam>(&original); >+ const TypeParam* cvalptr = absl::get_if<TypeParam>(&copied); >+ ASSERT_TRUE(ovalptr != nullptr); >+ ASSERT_TRUE(cvalptr != nullptr); >+ EXPECT_EQ(*ovalptr, *cvalptr); >+ TypeParam* mutable_ovalptr = absl::get_if<TypeParam>(&original); >+ TypeParam* mutable_cvalptr = absl::get_if<TypeParam>(&copied); >+ ASSERT_TRUE(mutable_ovalptr != nullptr); >+ ASSERT_TRUE(mutable_cvalptr != nullptr); >+ EXPECT_EQ(*mutable_ovalptr, *mutable_cvalptr); >+} >+ >+template <class> >+struct MoveOnly { >+ MoveOnly() = default; >+ explicit MoveOnly(int value) : value(value) {} >+ MoveOnly(MoveOnly&&) = default; >+ MoveOnly& operator=(MoveOnly&&) = default; >+ int value = 5; >+}; >+ >+TEST(VariantTest, TestMoveConstruct) { >+ using V = variant<MoveOnly<class A>, MoveOnly<class B>, MoveOnly<class C>>; >+ >+ V v(in_place_index_t<1>{}, 10); >+ V v2 = absl::move(v); >+ EXPECT_EQ(10, absl::get<1>(v2).value); >+} >+ >+// Used internally to emulate missing triviality traits for tests. >+template <class T> >+union SingleUnion { >+ T member; >+}; >+ >+// NOTE: These don't work with types that can't be union members. >+// They are just for testing. >+template <class T> >+struct is_trivially_move_constructible >+ : std::is_move_constructible<SingleUnion<T>>::type {}; >+ >+template <class T> >+struct is_trivially_move_assignable >+ : std::is_move_assignable<SingleUnion<T>>::type {}; >+ >+TEST(VariantTest, NothrowMoveConstructible) { >+ // Verify that variant is nothrow move constructible iff its template >+ // arguments are. >+ using U = std::unique_ptr<int>; >+ struct E { >+ E(E&&) {} >+ }; >+ static_assert(std::is_nothrow_move_constructible<variant<U>>::value, ""); >+ static_assert(std::is_nothrow_move_constructible<variant<U, int>>::value, ""); >+ static_assert(!std::is_nothrow_move_constructible<variant<U, E>>::value, ""); >+} >+ >+// Test that for each slot, constructing a variant with that type >+// produces a sensible object that correctly reports its type, and >+// that copies the provided value. >+TYPED_TEST(VariantTypesTest, TestValueCtor) { >+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ using value_type2 = absl::variant_alternative_t<1, Variant>; >+ using value_type3 = absl::variant_alternative_t<2, Variant>; >+ using value_type4 = absl::variant_alternative_t<3, Variant>; >+ const TypeParam value(TypeParam::kIndex); >+ Variant v(value); >+ EXPECT_TRUE(absl::holds_alternative<value_type1>(v) || >+ TypeParam::kIndex != 1); >+ EXPECT_TRUE(absl::holds_alternative<value_type2>(v) || >+ TypeParam::kIndex != 2); >+ EXPECT_TRUE(absl::holds_alternative<value_type3>(v) || >+ TypeParam::kIndex != 3); >+ EXPECT_TRUE(absl::holds_alternative<value_type4>(v) || >+ TypeParam::kIndex != 4); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) || >+ TypeParam::kIndex != 1); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) || >+ TypeParam::kIndex != 2); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) || >+ TypeParam::kIndex != 3); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) || >+ TypeParam::kIndex != 4); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type1>(&v) || >+ TypeParam::kIndex != 1); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type2>(&v) || >+ TypeParam::kIndex != 2); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type3>(&v) || >+ TypeParam::kIndex != 3); >+ EXPECT_TRUE(nullptr != absl::get_if<value_type4>(&v) || >+ TypeParam::kIndex != 4); >+ const TypeParam* valptr = absl::get_if<TypeParam>(&v); >+ ASSERT_TRUE(nullptr != valptr); >+ EXPECT_EQ(value.value, valptr->value); >+ const TypeParam* mutable_valptr = absl::get_if<TypeParam>(&v); >+ ASSERT_TRUE(nullptr != mutable_valptr); >+ EXPECT_EQ(value.value, mutable_valptr->value); >+} >+ >+TEST(VariantTest, InPlaceType) { >+ using Var = variant<int, std::string, NonCopyable, std::vector<int>>; >+ >+ Var v1(in_place_type_t<int>(), 7); >+ ASSERT_TRUE(absl::holds_alternative<int>(v1)); >+ EXPECT_EQ(7, absl::get<int>(v1)); >+ >+ Var v2(in_place_type_t<std::string>(), "ABC"); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); >+ EXPECT_EQ("ABC", absl::get<std::string>(v2)); >+ >+ Var v3(in_place_type_t<std::string>(), "ABC", 2); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); >+ EXPECT_EQ("AB", absl::get<std::string>(v3)); >+ >+ Var v4(in_place_type_t<NonCopyable>{}); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v4)); >+ >+ Var v5(in_place_type_t<std::vector<int>>(), {1, 2, 3}); >+ ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); >+ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); >+} >+ >+TEST(VariantTest, InPlaceTypeInitializerList) { >+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; >+ >+ Var v1(in_place_type_t<MoveOnlyWithListConstructor>(), {1, 2, 3, 4, 5}, 6); >+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); >+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); >+} >+ >+TEST(VariantTest, InPlaceIndex) { >+ using Var = variant<int, std::string, NonCopyable, std::vector<int>>; >+ >+ Var v1(in_place_index_t<0>(), 7); >+ ASSERT_TRUE(absl::holds_alternative<int>(v1)); >+ EXPECT_EQ(7, absl::get<int>(v1)); >+ >+ Var v2(in_place_index_t<1>(), "ABC"); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(v2)); >+ EXPECT_EQ("ABC", absl::get<std::string>(v2)); >+ >+ Var v3(in_place_index_t<1>(), "ABC", 2); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(v3)); >+ EXPECT_EQ("AB", absl::get<std::string>(v3)); >+ >+ Var v4(in_place_index_t<2>{}); >+ EXPECT_TRUE(absl::holds_alternative<NonCopyable>(v4)); >+ >+ // Verify that a variant with only non-copyables can still be constructed. >+ EXPECT_TRUE(absl::holds_alternative<NonCopyable>( >+ variant<NonCopyable>(in_place_index_t<0>{}))); >+ >+ Var v5(in_place_index_t<3>(), {1, 2, 3}); >+ ASSERT_TRUE(absl::holds_alternative<std::vector<int>>(v5)); >+ EXPECT_THAT(absl::get<std::vector<int>>(v5), ::testing::ElementsAre(1, 2, 3)); >+} >+ >+TEST(VariantTest, InPlaceIndexInitializerList) { >+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; >+ >+ Var v1(in_place_index_t<3>(), {1, 2, 3, 4, 5}, 6); >+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); >+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); >+} >+ >+//////////////////// >+// [variant.dtor] // >+//////////////////// >+ >+// Make sure that the destructor destroys the contained value >+TEST(VariantTest, TestDtor) { >+ typedef VariantFactory<IncrementInDtor>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ using value_type2 = absl::variant_alternative_t<1, Variant>; >+ using value_type3 = absl::variant_alternative_t<2, Variant>; >+ using value_type4 = absl::variant_alternative_t<3, Variant>; >+ int counter = 0; >+ IncrementInDtor counter_adjuster(&counter); >+ EXPECT_EQ(0, counter); >+ >+ value_type1 value1(counter_adjuster); >+ { Variant object(value1); } >+ EXPECT_EQ(1, counter); >+ >+ value_type2 value2(counter_adjuster); >+ { Variant object(value2); } >+ EXPECT_EQ(2, counter); >+ >+ value_type3 value3(counter_adjuster); >+ { Variant object(value3); } >+ EXPECT_EQ(3, counter); >+ >+ value_type4 value4(counter_adjuster); >+ { Variant object(value4); } >+ EXPECT_EQ(4, counter); >+} >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+// Test destruction when in the valueless_by_exception state. >+TEST(VariantTest, TestDtorValuelessByException) { >+ int counter = 0; >+ IncrementInDtor counter_adjuster(&counter); >+ >+ { >+ using Variant = VariantFactory<IncrementInDtor>::Type; >+ >+ Variant v(in_place_index_t<0>(), counter_adjuster); >+ EXPECT_EQ(0, counter); >+ >+ ToValuelessByException(v); >+ ASSERT_TRUE(v.valueless_by_exception()); >+ EXPECT_EQ(1, counter); >+ } >+ EXPECT_EQ(1, counter); >+} >+ >+#endif // ABSL_HAVE_EXCEPTIONS >+ >+////////////////////// >+// [variant.assign] // >+////////////////////// >+ >+// Test that self-assignment doesn't destroy the current value >+TEST(VariantTest, TestSelfAssignment) { >+ typedef VariantFactory<IncrementInDtor>::Type Variant; >+ int counter = 0; >+ IncrementInDtor counter_adjuster(&counter); >+ absl::variant_alternative_t<0, Variant> value(counter_adjuster); >+ Variant object(value); >+ object.operator=(object); >+ EXPECT_EQ(0, counter); >+ >+ // A std::string long enough that it's likely to defeat any inline representation >+ // optimization. >+ const std::string long_str(128, 'a'); >+ >+ std::string foo = long_str; >+ foo = *&foo; >+ EXPECT_EQ(long_str, foo); >+ >+ variant<int, std::string> so = long_str; >+ ASSERT_EQ(1, so.index()); >+ EXPECT_EQ(long_str, absl::get<1>(so)); >+ so = *&so; >+ >+ ASSERT_EQ(1, so.index()); >+ EXPECT_EQ(long_str, absl::get<1>(so)); >+} >+ >+// Test that assigning a variant<..., T, ...> to a variant<..., T, ...> produces >+// a variant<..., T, ...> with the correct value. >+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValueSameTypes) { >+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; >+ const TypeParam value(TypeParam::kIndex); >+ const Variant source(value); >+ Variant target(TypeParam(value.value + 1)); >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); >+ ASSERT_NE(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); >+ target = source; >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); >+ EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); >+} >+ >+// Test that assisnging a variant<..., T, ...> to a variant<1, ...> >+// produces a variant<..., T, ...> with the correct value. >+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingSourceType) { >+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ const TypeParam value(TypeParam::kIndex); >+ const Variant source(value); >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(source)); >+ Variant target(value_type1(1)); >+ ASSERT_TRUE(absl::holds_alternative<value_type1>(target)); >+ target = source; >+ EXPECT_TRUE(absl::holds_alternative<TypeParam>(source)); >+ EXPECT_TRUE(absl::holds_alternative<TypeParam>(target)); >+ EXPECT_EQ(absl::get<TypeParam>(source), absl::get<TypeParam>(target)); >+} >+ >+// Test that assigning a variant<1, ...> to a variant<..., T, ...> >+// produces a variant<1, ...> with the correct value. >+TYPED_TEST(VariantTypesTest, TestAssignmentCopiesValuesVaryingTargetType) { >+ typedef typename VariantFactory<typename TypeParam::value_type>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ const Variant source(value_type1(1)); >+ ASSERT_TRUE(absl::holds_alternative<value_type1>(source)); >+ const TypeParam value(TypeParam::kIndex); >+ Variant target(value); >+ ASSERT_TRUE(absl::holds_alternative<TypeParam>(target)); >+ target = source; >+ EXPECT_TRUE(absl::holds_alternative<value_type1>(target)); >+ EXPECT_TRUE(absl::holds_alternative<value_type1>(source)); >+ EXPECT_EQ(absl::get<value_type1>(source), absl::get<value_type1>(target)); >+} >+ >+// Test that operator=<T> works, that assigning a new value destroys >+// the old and that assigning the new value again does not redestroy >+// the old >+TEST(VariantTest, TestAssign) { >+ typedef VariantFactory<IncrementInDtor>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ using value_type2 = absl::variant_alternative_t<1, Variant>; >+ using value_type3 = absl::variant_alternative_t<2, Variant>; >+ using value_type4 = absl::variant_alternative_t<3, Variant>; >+ >+ const int kSize = 4; >+ int counter[kSize]; >+ std::unique_ptr<IncrementInDtor> counter_adjustor[kSize]; >+ for (int i = 0; i != kSize; i++) { >+ counter[i] = 0; >+ counter_adjustor[i] = absl::make_unique<IncrementInDtor>(&counter[i]); >+ } >+ >+ value_type1 v1(*counter_adjustor[0]); >+ value_type2 v2(*counter_adjustor[1]); >+ value_type3 v3(*counter_adjustor[2]); >+ value_type4 v4(*counter_adjustor[3]); >+ >+ // Test that reassignment causes destruction of old value >+ { >+ Variant object(v1); >+ object = v2; >+ object = v3; >+ object = v4; >+ object = v1; >+ } >+ >+ EXPECT_EQ(2, counter[0]); >+ EXPECT_EQ(1, counter[1]); >+ EXPECT_EQ(1, counter[2]); >+ EXPECT_EQ(1, counter[3]); >+ >+ std::fill(std::begin(counter), std::end(counter), 0); >+ >+ // Test that self-assignment does not cause destruction of old value >+ { >+ Variant object(v1); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[0]); >+ } >+ { >+ Variant object(v2); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[1]); >+ } >+ { >+ Variant object(v3); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[2]); >+ } >+ { >+ Variant object(v4); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[3]); >+ } >+ >+ EXPECT_EQ(1, counter[0]); >+ EXPECT_EQ(1, counter[1]); >+ EXPECT_EQ(1, counter[2]); >+ EXPECT_EQ(1, counter[3]); >+} >+ >+// This tests that we perform a backup if the copy-assign can throw but the move >+// cannot throw. >+TEST(VariantTest, TestBackupAssign) { >+ typedef VariantFactory<IncrementInDtorCopyCanThrow>::Type Variant; >+ using value_type1 = absl::variant_alternative_t<0, Variant>; >+ using value_type2 = absl::variant_alternative_t<1, Variant>; >+ using value_type3 = absl::variant_alternative_t<2, Variant>; >+ using value_type4 = absl::variant_alternative_t<3, Variant>; >+ >+ const int kSize = 4; >+ int counter[kSize]; >+ std::unique_ptr<IncrementInDtorCopyCanThrow> counter_adjustor[kSize]; >+ for (int i = 0; i != kSize; i++) { >+ counter[i] = 0; >+ counter_adjustor[i].reset(new IncrementInDtorCopyCanThrow(&counter[i])); >+ } >+ >+ value_type1 v1(*counter_adjustor[0]); >+ value_type2 v2(*counter_adjustor[1]); >+ value_type3 v3(*counter_adjustor[2]); >+ value_type4 v4(*counter_adjustor[3]); >+ >+ // Test that reassignment causes destruction of old value >+ { >+ Variant object(v1); >+ object = v2; >+ object = v3; >+ object = v4; >+ object = v1; >+ } >+ >+ // libstdc++ doesn't pass this test >+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+ EXPECT_EQ(3, counter[0]); >+ EXPECT_EQ(2, counter[1]); >+ EXPECT_EQ(2, counter[2]); >+ EXPECT_EQ(2, counter[3]); >+#endif >+ >+ std::fill(std::begin(counter), std::end(counter), 0); >+ >+ // Test that self-assignment does not cause destruction of old value >+ { >+ Variant object(v1); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[0]); >+ } >+ { >+ Variant object(v2); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[1]); >+ } >+ { >+ Variant object(v3); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[2]); >+ } >+ { >+ Variant object(v4); >+ object.operator=(object); >+ EXPECT_EQ(0, counter[3]); >+ } >+ >+ EXPECT_EQ(1, counter[0]); >+ EXPECT_EQ(1, counter[1]); >+ EXPECT_EQ(1, counter[2]); >+ EXPECT_EQ(1, counter[3]); >+} >+ >+/////////////////// >+// [variant.mod] // >+/////////////////// >+ >+TEST(VariantTest, TestEmplaceBasic) { >+ using Variant = variant<int, char>; >+ >+ Variant v(absl::in_place_index_t<0>{}, 0); >+ >+ { >+ char& emplace_result = v.emplace<char>(); >+ ASSERT_TRUE(absl::holds_alternative<char>(v)); >+ EXPECT_EQ(absl::get<char>(v), 0); >+ EXPECT_EQ(&emplace_result, &absl::get<char>(v)); >+ } >+ >+ // Make sure that another emplace does zero-initialization >+ absl::get<char>(v) = 'a'; >+ v.emplace<char>('b'); >+ ASSERT_TRUE(absl::holds_alternative<char>(v)); >+ EXPECT_EQ(absl::get<char>(v), 'b'); >+ >+ { >+ int& emplace_result = v.emplace<int>(); >+ EXPECT_TRUE(absl::holds_alternative<int>(v)); >+ EXPECT_EQ(absl::get<int>(v), 0); >+ EXPECT_EQ(&emplace_result, &absl::get<int>(v)); >+ } >+} >+ >+TEST(VariantTest, TestEmplaceInitializerList) { >+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; >+ >+ Var v1(absl::in_place_index_t<0>{}, 555); >+ MoveOnlyWithListConstructor& emplace_result = >+ v1.emplace<MoveOnlyWithListConstructor>({1, 2, 3, 4, 5}, 6); >+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); >+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); >+ EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1)); >+} >+ >+TEST(VariantTest, TestEmplaceIndex) { >+ using Variant = variant<int, char>; >+ >+ Variant v(absl::in_place_index_t<0>{}, 555); >+ >+ { >+ char& emplace_result = v.emplace<1>(); >+ ASSERT_TRUE(absl::holds_alternative<char>(v)); >+ EXPECT_EQ(absl::get<char>(v), 0); >+ EXPECT_EQ(&emplace_result, &absl::get<char>(v)); >+ } >+ >+ // Make sure that another emplace does zero-initialization >+ absl::get<char>(v) = 'a'; >+ v.emplace<1>('b'); >+ ASSERT_TRUE(absl::holds_alternative<char>(v)); >+ EXPECT_EQ(absl::get<char>(v), 'b'); >+ >+ { >+ int& emplace_result = v.emplace<0>(); >+ EXPECT_TRUE(absl::holds_alternative<int>(v)); >+ EXPECT_EQ(absl::get<int>(v), 0); >+ EXPECT_EQ(&emplace_result, &absl::get<int>(v)); >+ } >+} >+ >+TEST(VariantTest, TestEmplaceIndexInitializerList) { >+ using Var = variant<int, std::string, NonCopyable, MoveOnlyWithListConstructor>; >+ >+ Var v1(absl::in_place_index_t<0>{}, 555); >+ MoveOnlyWithListConstructor& emplace_result = >+ v1.emplace<3>({1, 2, 3, 4, 5}, 6); >+ ASSERT_TRUE(absl::holds_alternative<MoveOnlyWithListConstructor>(v1)); >+ EXPECT_EQ(6, absl::get<MoveOnlyWithListConstructor>(v1).value); >+ EXPECT_EQ(&emplace_result, &absl::get<MoveOnlyWithListConstructor>(v1)); >+} >+ >+////////////////////// >+// [variant.status] // >+////////////////////// >+ >+TEST(VariantTest, Index) { >+ using Var = variant<int, std::string, double>; >+ >+ Var v = 1; >+ EXPECT_EQ(0, v.index()); >+ v = "str"; >+ EXPECT_EQ(1, v.index()); >+ v = 0.; >+ EXPECT_EQ(2, v.index()); >+ >+ Var v2 = v; >+ EXPECT_EQ(2, v2.index()); >+ v2.emplace<int>(3); >+ EXPECT_EQ(0, v2.index()); >+} >+ >+TEST(VariantTest, NotValuelessByException) { >+ using Var = variant<int, std::string, double>; >+ >+ Var v = 1; >+ EXPECT_FALSE(v.valueless_by_exception()); >+ v = "str"; >+ EXPECT_FALSE(v.valueless_by_exception()); >+ v = 0.; >+ EXPECT_FALSE(v.valueless_by_exception()); >+ >+ Var v2 = v; >+ EXPECT_FALSE(v.valueless_by_exception()); >+ v2.emplace<int>(3); >+ EXPECT_FALSE(v.valueless_by_exception()); >+} >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+TEST(VariantTest, IndexValuelessByException) { >+ using Var = variant<MoveCanThrow, std::string, double>; >+ >+ Var v(absl::in_place_index_t<0>{}); >+ EXPECT_EQ(0, v.index()); >+ ToValuelessByException(v); >+ EXPECT_EQ(absl::variant_npos, v.index()); >+ v = "str"; >+ EXPECT_EQ(1, v.index()); >+} >+ >+TEST(VariantTest, ValuelessByException) { >+ using Var = variant<MoveCanThrow, std::string, double>; >+ >+ Var v(absl::in_place_index_t<0>{}); >+ EXPECT_FALSE(v.valueless_by_exception()); >+ ToValuelessByException(v); >+ EXPECT_TRUE(v.valueless_by_exception()); >+ v = "str"; >+ EXPECT_FALSE(v.valueless_by_exception()); >+} >+ >+#endif // ABSL_HAVE_EXCEPTIONS >+ >+//////////////////// >+// [variant.swap] // >+//////////////////// >+ >+TEST(VariantTest, MemberSwap) { >+ SpecialSwap v1(3); >+ SpecialSwap v2(7); >+ >+ variant<SpecialSwap> a = v1, b = v2; >+ >+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); >+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); >+ >+ a.swap(b); >+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v2)); >+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v1)); >+ EXPECT_TRUE(absl::get<SpecialSwap>(a).special_swap); >+ >+ using V = variant<MoveCanThrow, std::string, int>; >+ int i = 33; >+ std::string s = "abc"; >+ V valueless(in_place_index_t<0>{}); >+ ToValuelessByException(valueless); >+ { >+ // lhs and rhs holds different alternative >+ V lhs(i), rhs(s); >+ lhs.swap(rhs); >+ EXPECT_THAT(lhs, VariantWith<std::string>(s)); >+ EXPECT_THAT(rhs, VariantWith<int>(i)); >+ } >+ { >+ // lhs is valueless >+ V lhs(valueless), rhs(i); >+ lhs.swap(rhs); >+ EXPECT_THAT(lhs, VariantWith<int>(i)); >+ EXPECT_TRUE(rhs.valueless_by_exception()); >+ } >+ { >+ // rhs is valueless >+ V lhs(s), rhs(valueless); >+ lhs.swap(rhs); >+ EXPECT_THAT(rhs, VariantWith<std::string>(s)); >+ EXPECT_TRUE(lhs.valueless_by_exception()); >+ } >+ { >+ // both are valueless >+ V lhs(valueless), rhs(valueless); >+ lhs.swap(rhs); >+ EXPECT_TRUE(lhs.valueless_by_exception()); >+ EXPECT_TRUE(rhs.valueless_by_exception()); >+ } >+} >+ >+////////////////////// >+// [variant.helper] // >+////////////////////// >+ >+TEST(VariantTest, VariantSize) { >+ { >+ using Size1Variant = absl::variant<int>; >+ EXPECT_EQ(1, absl::variant_size<Size1Variant>::value); >+ EXPECT_EQ(1, absl::variant_size<const Size1Variant>::value); >+ EXPECT_EQ(1, absl::variant_size<volatile Size1Variant>::value); >+ EXPECT_EQ(1, absl::variant_size<const volatile Size1Variant>::value); >+ } >+ >+ { >+ using Size3Variant = absl::variant<int, float, int>; >+ EXPECT_EQ(3, absl::variant_size<Size3Variant>::value); >+ EXPECT_EQ(3, absl::variant_size<const Size3Variant>::value); >+ EXPECT_EQ(3, absl::variant_size<volatile Size3Variant>::value); >+ EXPECT_EQ(3, absl::variant_size<const volatile Size3Variant>::value); >+ } >+} >+ >+TEST(VariantTest, VariantAlternative) { >+ { >+ using V = absl::variant<float, int, const char*>; >+ EXPECT_TRUE( >+ (std::is_same<float, absl::variant_alternative_t<0, V>>::value)); >+ EXPECT_TRUE((std::is_same<const float, >+ absl::variant_alternative_t<0, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<volatile float, >+ absl::variant_alternative_t<0, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const volatile float, >+ absl::variant_alternative_t<0, const volatile V>>::value)); >+ >+ EXPECT_TRUE((std::is_same<int, absl::variant_alternative_t<1, V>>::value)); >+ EXPECT_TRUE((std::is_same<const int, >+ absl::variant_alternative_t<1, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<volatile int, >+ absl::variant_alternative_t<1, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const volatile int, >+ absl::variant_alternative_t<1, const volatile V>>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value)); >+ EXPECT_TRUE((std::is_same<const char* const, >+ absl::variant_alternative_t<2, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<const char* volatile, >+ absl::variant_alternative_t<2, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const char* const volatile, >+ absl::variant_alternative_t<2, const volatile V>>::value)); >+ } >+ >+ { >+ using V = absl::variant<float, volatile int, const char*>; >+ EXPECT_TRUE( >+ (std::is_same<float, absl::variant_alternative_t<0, V>>::value)); >+ EXPECT_TRUE((std::is_same<const float, >+ absl::variant_alternative_t<0, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<volatile float, >+ absl::variant_alternative_t<0, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const volatile float, >+ absl::variant_alternative_t<0, const volatile V>>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_same<volatile int, absl::variant_alternative_t<1, V>>::value)); >+ EXPECT_TRUE((std::is_same<const volatile int, >+ absl::variant_alternative_t<1, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<volatile int, >+ absl::variant_alternative_t<1, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const volatile int, >+ absl::variant_alternative_t<1, const volatile V>>::value)); >+ >+ EXPECT_TRUE( >+ (std::is_same<const char*, absl::variant_alternative_t<2, V>>::value)); >+ EXPECT_TRUE((std::is_same<const char* const, >+ absl::variant_alternative_t<2, const V>>::value)); >+ EXPECT_TRUE( >+ (std::is_same<const char* volatile, >+ absl::variant_alternative_t<2, volatile V>>::value)); >+ EXPECT_TRUE(( >+ std::is_same<const char* const volatile, >+ absl::variant_alternative_t<2, const volatile V>>::value)); >+ } >+} >+ >+/////////////////// >+// [variant.get] // >+/////////////////// >+ >+TEST(VariantTest, HoldsAlternative) { >+ using Var = variant<int, std::string, double>; >+ >+ Var v = 1; >+ EXPECT_TRUE(absl::holds_alternative<int>(v)); >+ EXPECT_FALSE(absl::holds_alternative<std::string>(v)); >+ EXPECT_FALSE(absl::holds_alternative<double>(v)); >+ v = "str"; >+ EXPECT_FALSE(absl::holds_alternative<int>(v)); >+ EXPECT_TRUE(absl::holds_alternative<std::string>(v)); >+ EXPECT_FALSE(absl::holds_alternative<double>(v)); >+ v = 0.; >+ EXPECT_FALSE(absl::holds_alternative<int>(v)); >+ EXPECT_FALSE(absl::holds_alternative<std::string>(v)); >+ EXPECT_TRUE(absl::holds_alternative<double>(v)); >+ >+ Var v2 = v; >+ EXPECT_FALSE(absl::holds_alternative<int>(v2)); >+ EXPECT_FALSE(absl::holds_alternative<std::string>(v2)); >+ EXPECT_TRUE(absl::holds_alternative<double>(v2)); >+ v2.emplace<int>(3); >+ EXPECT_TRUE(absl::holds_alternative<int>(v2)); >+ EXPECT_FALSE(absl::holds_alternative<std::string>(v2)); >+ EXPECT_FALSE(absl::holds_alternative<double>(v2)); >+} >+ >+TEST(VariantTest, GetIndex) { >+ using Var = variant<int, std::string, double, int>; >+ >+ { >+ Var v(absl::in_place_index_t<0>{}, 0); >+ >+ using LValueGetType = decltype(absl::get<0>(v)); >+ using RValueGetType = decltype(absl::get<0>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); >+ EXPECT_EQ(absl::get<0>(v), 0); >+ EXPECT_EQ(absl::get<0>(absl::move(v)), 0); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<0>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<0>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); >+ EXPECT_EQ(absl::get<0>(const_v), 0); >+ EXPECT_EQ(absl::get<0>(absl::move(const_v)), 0); >+ } >+ >+ { >+ Var v = std::string("Hello"); >+ >+ using LValueGetType = decltype(absl::get<1>(v)); >+ using RValueGetType = decltype(absl::get<1>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value)); >+ EXPECT_EQ(absl::get<1>(v), "Hello"); >+ EXPECT_EQ(absl::get<1>(absl::move(v)), "Hello"); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<1>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value)); >+ EXPECT_EQ(absl::get<1>(const_v), "Hello"); >+ EXPECT_EQ(absl::get<1>(absl::move(const_v)), "Hello"); >+ } >+ >+ { >+ Var v = 2.0; >+ >+ using LValueGetType = decltype(absl::get<2>(v)); >+ using RValueGetType = decltype(absl::get<2>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, double&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value)); >+ EXPECT_EQ(absl::get<2>(v), 2.); >+ EXPECT_EQ(absl::get<2>(absl::move(v)), 2.); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<2>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value)); >+ EXPECT_EQ(absl::get<2>(const_v), 2.); >+ EXPECT_EQ(absl::get<2>(absl::move(const_v)), 2.); >+ } >+ >+ { >+ Var v(absl::in_place_index_t<0>{}, 0); >+ v.emplace<3>(1); >+ >+ using LValueGetType = decltype(absl::get<3>(v)); >+ using RValueGetType = decltype(absl::get<3>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); >+ EXPECT_EQ(absl::get<3>(v), 1); >+ EXPECT_EQ(absl::get<3>(absl::move(v)), 1); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<3>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<3>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); >+ EXPECT_EQ(absl::get<3>(const_v), 1); >+ EXPECT_EQ(absl::get<3>(absl::move(const_v)), 1); // NOLINT >+ } >+} >+ >+TEST(VariantTest, BadGetIndex) { >+ using Var = variant<int, std::string, double>; >+ >+ { >+ Var v = 1; >+ >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(std::move(v))); >+ >+ const Var& const_v = v; >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<1>(const_v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( >+ absl::get<1>(std::move(const_v))); // NOLINT >+ } >+ >+ { >+ Var v = std::string("Hello"); >+ >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(std::move(v))); >+ >+ const Var& const_v = v; >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<0>(const_v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( >+ absl::get<0>(std::move(const_v))); // NOLINT >+ } >+} >+ >+TEST(VariantTest, GetType) { >+ using Var = variant<int, std::string, double>; >+ >+ { >+ Var v = 1; >+ >+ using LValueGetType = decltype(absl::get<int>(v)); >+ using RValueGetType = decltype(absl::get<int>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, int&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, int&&>::value)); >+ EXPECT_EQ(absl::get<int>(v), 1); >+ EXPECT_EQ(absl::get<int>(absl::move(v)), 1); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<int>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<int>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const int&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const int&&>::value)); >+ EXPECT_EQ(absl::get<int>(const_v), 1); >+ EXPECT_EQ(absl::get<int>(absl::move(const_v)), 1); >+ } >+ >+ { >+ Var v = std::string("Hello"); >+ >+ using LValueGetType = decltype(absl::get<1>(v)); >+ using RValueGetType = decltype(absl::get<1>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, std::string&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, std::string&&>::value)); >+ EXPECT_EQ(absl::get<std::string>(v), "Hello"); >+ EXPECT_EQ(absl::get<std::string>(absl::move(v)), "Hello"); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<1>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<1>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const std::string&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const std::string&&>::value)); >+ EXPECT_EQ(absl::get<std::string>(const_v), "Hello"); >+ EXPECT_EQ(absl::get<std::string>(absl::move(const_v)), "Hello"); >+ } >+ >+ { >+ Var v = 2.0; >+ >+ using LValueGetType = decltype(absl::get<2>(v)); >+ using RValueGetType = decltype(absl::get<2>(absl::move(v))); >+ >+ EXPECT_TRUE((std::is_same<LValueGetType, double&>::value)); >+ EXPECT_TRUE((std::is_same<RValueGetType, double&&>::value)); >+ EXPECT_EQ(absl::get<double>(v), 2.); >+ EXPECT_EQ(absl::get<double>(absl::move(v)), 2.); >+ >+ const Var& const_v = v; >+ using ConstLValueGetType = decltype(absl::get<2>(const_v)); >+ using ConstRValueGetType = decltype(absl::get<2>(absl::move(const_v))); >+ EXPECT_TRUE((std::is_same<ConstLValueGetType, const double&>::value)); >+ EXPECT_TRUE((std::is_same<ConstRValueGetType, const double&&>::value)); >+ EXPECT_EQ(absl::get<double>(const_v), 2.); >+ EXPECT_EQ(absl::get<double>(absl::move(const_v)), 2.); >+ } >+} >+ >+TEST(VariantTest, BadGetType) { >+ using Var = variant<int, std::string, double>; >+ >+ { >+ Var v = 1; >+ >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( >+ absl::get<std::string>(std::move(v))); >+ >+ const Var& const_v = v; >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<std::string>(const_v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( >+ absl::get<std::string>(std::move(const_v))); // NOLINT >+ } >+ >+ { >+ Var v = std::string("Hello"); >+ >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(std::move(v))); >+ >+ const Var& const_v = v; >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS(absl::get<int>(const_v)); >+ ABSL_VARIANT_TEST_EXPECT_BAD_VARIANT_ACCESS( >+ absl::get<int>(std::move(const_v))); // NOLINT >+ } >+} >+ >+TEST(VariantTest, GetIfIndex) { >+ using Var = variant<int, std::string, double, int>; >+ >+ { >+ Var v(absl::in_place_index_t<0>{}, 0); >+ EXPECT_TRUE(noexcept(absl::get_if<0>(&v))); >+ >+ { >+ auto* elem = absl::get_if<0>(&v); >+ EXPECT_TRUE((std::is_same<decltype(elem), int*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 0); >+ { >+ auto* bad_elem = absl::get_if<1>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ } >+ >+ const Var& const_v = v; >+ EXPECT_TRUE(noexcept(absl::get_if<0>(&const_v))); >+ >+ { >+ auto* elem = absl::get_if<0>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 0); >+ { >+ auto* bad_elem = absl::get_if<1>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&const_v); >+ EXPECT_EQ(bad_elem, nullptr); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ } >+ } >+ } >+ >+ { >+ Var v = std::string("Hello"); >+ EXPECT_TRUE(noexcept(absl::get_if<1>(&v))); >+ >+ { >+ auto* elem = absl::get_if<1>(&v); >+ EXPECT_TRUE((std::is_same<decltype(elem), std::string*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, "Hello"); >+ { >+ auto* bad_elem = absl::get_if<0>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ } >+ >+ const Var& const_v = v; >+ EXPECT_TRUE(noexcept(absl::get_if<1>(&const_v))); >+ >+ { >+ auto* elem = absl::get_if<1>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(elem), const std::string*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, "Hello"); >+ { >+ auto* bad_elem = absl::get_if<0>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&const_v); >+ EXPECT_EQ(bad_elem, nullptr); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ } >+ } >+ } >+ >+ { >+ Var v = 2.0; >+ EXPECT_TRUE(noexcept(absl::get_if<2>(&v))); >+ >+ { >+ auto* elem = absl::get_if<2>(&v); >+ EXPECT_TRUE((std::is_same<decltype(elem), double*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 2.0); >+ { >+ auto* bad_elem = absl::get_if<0>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<1>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ } >+ >+ const Var& const_v = v; >+ EXPECT_TRUE(noexcept(absl::get_if<2>(&const_v))); >+ >+ { >+ auto* elem = absl::get_if<2>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(elem), const double*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 2.0); >+ { >+ auto* bad_elem = absl::get_if<0>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<1>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<3>(&const_v); >+ EXPECT_EQ(bad_elem, nullptr); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ } >+ } >+ } >+ >+ { >+ Var v(absl::in_place_index_t<0>{}, 0); >+ v.emplace<3>(1); >+ EXPECT_TRUE(noexcept(absl::get_if<3>(&v))); >+ >+ { >+ auto* elem = absl::get_if<3>(&v); >+ EXPECT_TRUE((std::is_same<decltype(elem), int*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 1); >+ { >+ auto* bad_elem = absl::get_if<0>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<1>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), double*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ } >+ >+ const Var& const_v = v; >+ EXPECT_TRUE(noexcept(absl::get_if<3>(&const_v))); >+ >+ { >+ auto* elem = absl::get_if<3>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(elem), const int*>::value)); >+ ASSERT_NE(elem, nullptr); >+ EXPECT_EQ(*elem, 1); >+ { >+ auto* bad_elem = absl::get_if<0>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const int*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<1>(&const_v); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const std::string*>::value)); >+ EXPECT_EQ(bad_elem, nullptr); >+ } >+ { >+ auto* bad_elem = absl::get_if<2>(&const_v); >+ EXPECT_EQ(bad_elem, nullptr); >+ EXPECT_TRUE((std::is_same<decltype(bad_elem), const double*>::value)); >+ } >+ } >+ } >+} >+ >+////////////////////// >+// [variant.relops] // >+////////////////////// >+ >+TEST(VariantTest, OperatorEquals) { >+ variant<int, std::string> a(1), b(1); >+ EXPECT_TRUE(a == b); >+ EXPECT_TRUE(b == a); >+ EXPECT_FALSE(a != b); >+ EXPECT_FALSE(b != a); >+ >+ b = "str"; >+ EXPECT_FALSE(a == b); >+ EXPECT_FALSE(b == a); >+ EXPECT_TRUE(a != b); >+ EXPECT_TRUE(b != a); >+ >+ b = 0; >+ EXPECT_FALSE(a == b); >+ EXPECT_FALSE(b == a); >+ EXPECT_TRUE(a != b); >+ EXPECT_TRUE(b != a); >+ >+ a = b = "foo"; >+ EXPECT_TRUE(a == b); >+ EXPECT_TRUE(b == a); >+ EXPECT_FALSE(a != b); >+ EXPECT_FALSE(b != a); >+ >+ a = "bar"; >+ EXPECT_FALSE(a == b); >+ EXPECT_FALSE(b == a); >+ EXPECT_TRUE(a != b); >+ EXPECT_TRUE(b != a); >+} >+ >+TEST(VariantTest, OperatorRelational) { >+ variant<int, std::string> a(1), b(1); >+ EXPECT_FALSE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_FALSE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_TRUE(b <= a); >+ EXPECT_TRUE(a >= b); >+ EXPECT_TRUE(b >= a); >+ >+ b = "str"; >+ EXPECT_TRUE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_TRUE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_FALSE(b <= a); >+ EXPECT_FALSE(a >= b); >+ EXPECT_TRUE(b >= a); >+ >+ b = 0; >+ EXPECT_FALSE(a < b); >+ EXPECT_TRUE(b < a); >+ EXPECT_TRUE(a > b); >+ EXPECT_FALSE(b > a); >+ EXPECT_FALSE(a <= b); >+ EXPECT_TRUE(b <= a); >+ EXPECT_TRUE(a >= b); >+ EXPECT_FALSE(b >= a); >+ >+ a = b = "foo"; >+ EXPECT_FALSE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_FALSE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_TRUE(b <= a); >+ EXPECT_TRUE(a >= b); >+ EXPECT_TRUE(b >= a); >+ >+ a = "bar"; >+ EXPECT_TRUE(a < b); >+ EXPECT_FALSE(b < a); >+ EXPECT_FALSE(a > b); >+ EXPECT_TRUE(b > a); >+ EXPECT_TRUE(a <= b); >+ EXPECT_FALSE(b <= a); >+ EXPECT_FALSE(a >= b); >+ EXPECT_TRUE(b >= a); >+} >+ >+#ifdef ABSL_HAVE_EXCEPTIONS >+ >+TEST(VariantTest, ValuelessOperatorEquals) { >+ variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), >+ valueless(absl::in_place_index_t<0>{}), >+ other_valueless(absl::in_place_index_t<0>{}); >+ ToValuelessByException(valueless); >+ ToValuelessByException(other_valueless); >+ >+ EXPECT_TRUE(valueless == other_valueless); >+ EXPECT_TRUE(other_valueless == valueless); >+ EXPECT_FALSE(valueless == int_v); >+ EXPECT_FALSE(valueless == string_v); >+ EXPECT_FALSE(int_v == valueless); >+ EXPECT_FALSE(string_v == valueless); >+ >+ EXPECT_FALSE(valueless != other_valueless); >+ EXPECT_FALSE(other_valueless != valueless); >+ EXPECT_TRUE(valueless != int_v); >+ EXPECT_TRUE(valueless != string_v); >+ EXPECT_TRUE(int_v != valueless); >+ EXPECT_TRUE(string_v != valueless); >+} >+ >+TEST(VariantTest, ValuelessOperatorRelational) { >+ variant<MoveCanThrow, std::string> int_v(1), string_v("Hello"), >+ valueless(absl::in_place_index_t<0>{}), >+ other_valueless(absl::in_place_index_t<0>{}); >+ ToValuelessByException(valueless); >+ ToValuelessByException(other_valueless); >+ >+ EXPECT_FALSE(valueless < other_valueless); >+ EXPECT_FALSE(other_valueless < valueless); >+ EXPECT_TRUE(valueless < int_v); >+ EXPECT_TRUE(valueless < string_v); >+ EXPECT_FALSE(int_v < valueless); >+ EXPECT_FALSE(string_v < valueless); >+ >+ EXPECT_TRUE(valueless <= other_valueless); >+ EXPECT_TRUE(other_valueless <= valueless); >+ EXPECT_TRUE(valueless <= int_v); >+ EXPECT_TRUE(valueless <= string_v); >+ EXPECT_FALSE(int_v <= valueless); >+ EXPECT_FALSE(string_v <= valueless); >+ >+ EXPECT_TRUE(valueless >= other_valueless); >+ EXPECT_TRUE(other_valueless >= valueless); >+ EXPECT_FALSE(valueless >= int_v); >+ EXPECT_FALSE(valueless >= string_v); >+ EXPECT_TRUE(int_v >= valueless); >+ EXPECT_TRUE(string_v >= valueless); >+ >+ EXPECT_FALSE(valueless > other_valueless); >+ EXPECT_FALSE(other_valueless > valueless); >+ EXPECT_FALSE(valueless > int_v); >+ EXPECT_FALSE(valueless > string_v); >+ EXPECT_TRUE(int_v > valueless); >+ EXPECT_TRUE(string_v > valueless); >+} >+ >+#endif >+ >+///////////////////// >+// [variant.visit] // >+///////////////////// >+ >+template <typename T> >+struct ConvertTo { >+ template <typename U> >+ T operator()(const U& u) const { >+ return u; >+ } >+}; >+ >+TEST(VariantTest, VisitSimple) { >+ variant<std::string, const char*> v = "A"; >+ >+ std::string str = absl::visit(ConvertTo<std::string>{}, v); >+ EXPECT_EQ("A", str); >+ >+ v = std::string("B"); >+ >+ absl::string_view piece = absl::visit(ConvertTo<absl::string_view>{}, v); >+ EXPECT_EQ("B", piece); >+ >+ struct StrLen { >+ int operator()(const std::string& s) const { return s.size(); } >+ int operator()(const char* s) const { return strlen(s); } >+ }; >+ >+ v = "SomeStr"; >+ EXPECT_EQ(7, absl::visit(StrLen{}, v)); >+ v = std::string("VeryLargeThisTime"); >+ EXPECT_EQ(17, absl::visit(StrLen{}, v)); >+} >+ >+TEST(VariantTest, VisitRValue) { >+ variant<std::string> v = std::string("X"); >+ struct Visitor { >+ bool operator()(const std::string&) const { return false; } >+ bool operator()(std::string&&) const { return true; } // NOLINT >+ >+ int operator()(const std::string&, const std::string&) const { return 0; } >+ int operator()(const std::string&, std::string&&) const { return 1; } // NOLINT >+ int operator()(std::string&&, const std::string&) const { return 2; } // NOLINT >+ int operator()(std::string&&, std::string&&) const { return 3; } // NOLINT >+ }; >+ EXPECT_FALSE(absl::visit(Visitor{}, v)); >+ EXPECT_TRUE(absl::visit(Visitor{}, absl::move(v))); >+ >+ // Also test the variadic overload. >+ EXPECT_EQ(0, absl::visit(Visitor{}, v, v)); >+ EXPECT_EQ(1, absl::visit(Visitor{}, v, absl::move(v))); >+ EXPECT_EQ(2, absl::visit(Visitor{}, absl::move(v), v)); >+ EXPECT_EQ(3, absl::visit(Visitor{}, absl::move(v), absl::move(v))); >+} >+ >+TEST(VariantTest, VisitRValueVisitor) { >+ variant<std::string> v = std::string("X"); >+ struct Visitor { >+ bool operator()(const std::string&) const& { return false; } >+ bool operator()(const std::string&) && { return true; } >+ }; >+ Visitor visitor; >+ EXPECT_FALSE(absl::visit(visitor, v)); >+ EXPECT_TRUE(absl::visit(Visitor{}, v)); >+} >+ >+TEST(VariantTest, VisitResultTypeDifferent) { >+ variant<std::string> v = std::string("X"); >+ struct LValue_LValue {}; >+ struct RValue_LValue {}; >+ struct LValue_RValue {}; >+ struct RValue_RValue {}; >+ struct Visitor { >+ LValue_LValue operator()(const std::string&) const& { return {}; } >+ RValue_LValue operator()(std::string&&) const& { return {}; } // NOLINT >+ LValue_RValue operator()(const std::string&) && { return {}; } >+ RValue_RValue operator()(std::string&&) && { return {}; } // NOLINT >+ } visitor; >+ >+ EXPECT_TRUE( >+ (std::is_same<LValue_LValue, decltype(absl::visit(visitor, v))>::value)); >+ EXPECT_TRUE( >+ (std::is_same<RValue_LValue, >+ decltype(absl::visit(visitor, absl::move(v)))>::value)); >+ EXPECT_TRUE(( >+ std::is_same<LValue_RValue, decltype(absl::visit(Visitor{}, v))>::value)); >+ EXPECT_TRUE( >+ (std::is_same<RValue_RValue, >+ decltype(absl::visit(Visitor{}, absl::move(v)))>::value)); >+} >+ >+TEST(VariantTest, VisitVariadic) { >+ using A = variant<int, std::string>; >+ using B = variant<std::unique_ptr<int>, absl::string_view>; >+ >+ struct Visitor { >+ std::pair<int, int> operator()(int a, std::unique_ptr<int> b) const { >+ return {a, *b}; >+ } >+ std::pair<int, int> operator()(absl::string_view a, >+ std::unique_ptr<int> b) const { >+ return {static_cast<int>(a.size()), static_cast<int>(*b)}; >+ } >+ std::pair<int, int> operator()(int a, absl::string_view b) const { >+ return {a, static_cast<int>(b.size())}; >+ } >+ std::pair<int, int> operator()(absl::string_view a, >+ absl::string_view b) const { >+ return {static_cast<int>(a.size()), static_cast<int>(b.size())}; >+ } >+ }; >+ >+ EXPECT_THAT(absl::visit(Visitor(), A(1), B(std::unique_ptr<int>(new int(7)))), >+ ::testing::Pair(1, 7)); >+ EXPECT_THAT(absl::visit(Visitor(), A(1), B(absl::string_view("ABC"))), >+ ::testing::Pair(1, 3)); >+ EXPECT_THAT(absl::visit(Visitor(), A(std::string("BBBBB")), >+ B(std::unique_ptr<int>(new int(7)))), >+ ::testing::Pair(5, 7)); >+ EXPECT_THAT( >+ absl::visit(Visitor(), A(std::string("BBBBB")), B(absl::string_view("ABC"))), >+ ::testing::Pair(5, 3)); >+} >+ >+TEST(VariantTest, VisitNoArgs) { >+ EXPECT_EQ(5, absl::visit([] { return 5; })); >+} >+ >+struct ConstFunctor { >+ int operator()(int a, int b) const { return a - b; } >+}; >+ >+struct MutableFunctor { >+ int operator()(int a, int b) { return a - b; } >+}; >+ >+struct Class { >+ int Method(int a, int b) { return a - b; } >+ int ConstMethod(int a, int b) const { return a - b; } >+ >+ int member; >+}; >+ >+TEST(VariantTest, VisitReferenceWrapper) { >+ ConstFunctor cf; >+ MutableFunctor mf; >+ absl::variant<int> three = 3; >+ absl::variant<int> two = 2; >+ >+ EXPECT_EQ(1, absl::visit(std::cref(cf), three, two)); >+ EXPECT_EQ(1, absl::visit(std::ref(cf), three, two)); >+ EXPECT_EQ(1, absl::visit(std::ref(mf), three, two)); >+} >+ >+// libstdc++ std::variant doesn't support the INVOKE semantics. >+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+TEST(VariantTest, VisitMemberFunction) { >+ absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>()); >+ absl::variant<std::unique_ptr<const Class>> cp( >+ absl::make_unique<const Class>()); >+ absl::variant<int> three = 3; >+ absl::variant<int> two = 2; >+ >+ EXPECT_EQ(1, absl::visit(&Class::Method, p, three, two)); >+ EXPECT_EQ(1, absl::visit(&Class::ConstMethod, p, three, two)); >+ EXPECT_EQ(1, absl::visit(&Class::ConstMethod, cp, three, two)); >+} >+ >+TEST(VariantTest, VisitDataMember) { >+ absl::variant<std::unique_ptr<Class>> p(absl::make_unique<Class>(Class{42})); >+ absl::variant<std::unique_ptr<const Class>> cp( >+ absl::make_unique<const Class>(Class{42})); >+ EXPECT_EQ(42, absl::visit(&Class::member, p)); >+ >+ absl::visit(&Class::member, p) = 5; >+ EXPECT_EQ(5, absl::visit(&Class::member, p)); >+ >+ EXPECT_EQ(42, absl::visit(&Class::member, cp)); >+} >+#endif // !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+ >+///////////////////////// >+// [variant.monostate] // >+///////////////////////// >+ >+TEST(VariantTest, MonostateBasic) { >+ absl::monostate mono; >+ (void)mono; >+ >+ // TODO(mattcalabrese) Expose move triviality metafunctions in absl. >+ EXPECT_TRUE(absl::is_trivially_default_constructible<absl::monostate>::value); >+ EXPECT_TRUE(is_trivially_move_constructible<absl::monostate>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<absl::monostate>::value); >+ EXPECT_TRUE(is_trivially_move_assignable<absl::monostate>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<absl::monostate>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<absl::monostate>::value); >+} >+ >+TEST(VariantTest, VariantMonostateDefaultConstruction) { >+ absl::variant<absl::monostate, NonDefaultConstructible> var; >+ EXPECT_EQ(var.index(), 0); >+} >+ >+//////////////////////////////// >+// [variant.monostate.relops] // >+//////////////////////////////// >+ >+TEST(VariantTest, MonostateComparisons) { >+ absl::monostate lhs, rhs; >+ >+ EXPECT_EQ(lhs, lhs); >+ EXPECT_EQ(lhs, rhs); >+ >+ EXPECT_FALSE(lhs != lhs); >+ EXPECT_FALSE(lhs != rhs); >+ EXPECT_FALSE(lhs < lhs); >+ EXPECT_FALSE(lhs < rhs); >+ EXPECT_FALSE(lhs > lhs); >+ EXPECT_FALSE(lhs > rhs); >+ >+ EXPECT_LE(lhs, lhs); >+ EXPECT_LE(lhs, rhs); >+ EXPECT_GE(lhs, lhs); >+ EXPECT_GE(lhs, rhs); >+ >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() == >+ std::declval<absl::monostate>())); >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() != >+ std::declval<absl::monostate>())); >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() < >+ std::declval<absl::monostate>())); >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() > >+ std::declval<absl::monostate>())); >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() <= >+ std::declval<absl::monostate>())); >+ EXPECT_TRUE(noexcept(std::declval<absl::monostate>() >= >+ std::declval<absl::monostate>())); >+} >+ >+/////////////////////// >+// [variant.specalg] // >+/////////////////////// >+ >+TEST(VariantTest, NonmemberSwap) { >+ using std::swap; >+ >+ SpecialSwap v1(3); >+ SpecialSwap v2(7); >+ >+ variant<SpecialSwap> a = v1, b = v2; >+ >+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); >+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); >+ >+ std::swap(a, b); >+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v2)); >+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v1)); >+#ifndef ABSL_HAVE_STD_VARIANT >+ EXPECT_FALSE(absl::get<SpecialSwap>(a).special_swap); >+#endif >+ >+ swap(a, b); >+ EXPECT_THAT(a, VariantWith<SpecialSwap>(v1)); >+ EXPECT_THAT(b, VariantWith<SpecialSwap>(v2)); >+ EXPECT_TRUE(absl::get<SpecialSwap>(b).special_swap); >+} >+ >+////////////////////////// >+// [variant.bad.access] // >+////////////////////////// >+ >+TEST(VariantTest, BadAccess) { >+ EXPECT_TRUE(noexcept(absl::bad_variant_access())); >+ absl::bad_variant_access exception_obj; >+ std::exception* base = &exception_obj; >+ (void)base; >+} >+ >+//////////////////// >+// [variant.hash] // >+//////////////////// >+ >+TEST(VariantTest, MonostateHash) { >+ absl::monostate mono, other_mono; >+ std::hash<absl::monostate> const hasher{}; >+ static_assert(std::is_same<decltype(hasher(mono)), std::size_t>::value, ""); >+ EXPECT_EQ(hasher(mono), hasher(other_mono)); >+} >+ >+TEST(VariantTest, Hash) { >+ static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, ""); >+ static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value, >+ ""); >+ static_assert( >+ type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, ""); >+ >+#if defined(_MSC_VER) || \ >+ (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \ >+ _LIBCPP_STD_VER > 11) || \ >+ defined(__APPLE__) >+ // For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a >+ // static_assert to catch any user-defined type T that doesn't provide a hash >+ // specialization. So instantiating std::hash<variant<T>> will result >+ // in a hard error which is not SFINAE friendly. >+#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1 >+#endif >+ >+#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY >+ static_assert( >+ !type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, ""); >+ static_assert(!type_traits_internal::IsHashEnabled< >+ variant<Hashable, NonHashable>>::value, >+ ""); >+#endif >+ >+// MSVC std::hash<std::variant> does not use the index, thus produce the same >+// result on the same value as different alternative. >+#if !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT)) >+ { >+ // same value as different alternative >+ variant<int, int> v0(in_place_index_t<0>{}, 42); >+ variant<int, int> v1(in_place_index_t<1>{}, 42); >+ std::hash<variant<int, int>> hash; >+ EXPECT_NE(hash(v0), hash(v1)); >+ } >+#endif // !(defined(_MSC_VER) && defined(ABSL_HAVE_STD_VARIANT)) >+ >+ { >+ std::hash<variant<int>> hash; >+ std::set<size_t> hashcodes; >+ for (int i = 0; i < 100; ++i) { >+ hashcodes.insert(hash(i)); >+ } >+ EXPECT_GT(hashcodes.size(), 90); >+ >+ // test const-qualified >+ static_assert( >+ type_traits_internal::IsHashEnabled<variant<const int>>::value, ""); >+ static_assert( >+ type_traits_internal::IsHashEnabled<variant<const Hashable>>::value, >+ ""); >+ std::hash<absl::variant<const int>> c_hash; >+ for (int i = 0; i < 100; ++i) { >+ EXPECT_EQ(hash(i), c_hash(i)); >+ } >+ } >+} >+ >+//////////////////////////////////////// >+// Miscellaneous and deprecated tests // >+//////////////////////////////////////// >+ >+// Test that a set requiring a basic type conversion works correctly. >+TEST(VariantTest, TestConvertingSet) { >+ typedef variant<double> Variant; >+ Variant v(1.0); >+ const int two = 2; >+ v = two; >+ EXPECT_TRUE(absl::holds_alternative<double>(v)); >+ ASSERT_TRUE(nullptr != absl::get_if<double>(&v)); >+ EXPECT_DOUBLE_EQ(2, absl::get<double>(v)); >+} >+ >+// Test that a vector of variants behaves reasonably. >+TEST(VariantTest, Container) { >+ typedef variant<int, float> Variant; >+ >+ // Creation of vector should work >+ std::vector<Variant> vec; >+ vec.push_back(Variant(10)); >+ vec.push_back(Variant(20.0f)); >+ >+ // Vector resizing should work if we supply a value for new slots >+ vec.resize(10, Variant(0)); >+} >+ >+// Test that a variant with a non-copyable type can be constructed and >+// manipulated to some degree. >+TEST(VariantTest, TestVariantWithNonCopyableType) { >+ typedef variant<int, NonCopyable> Variant; >+ const int kValue = 1; >+ Variant v(kValue); >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ EXPECT_EQ(kValue, absl::get<int>(v)); >+} >+ >+// Test that a variant with a non-copyable type can be transformed to >+// the non-copyable type with a call to `emplace` for different numbers >+// of arguments. We do not need to test this for each of T1 ... T8 >+// because `emplace` does not overload on T1 ... to T8, so if this >+// works for any one of T1 ... T8, then it works for all of them. We >+// do need to test that it works with varying numbers of parameters >+// though. >+TEST(VariantTest, TestEmplace) { >+ typedef variant<int, NonCopyable> Variant; >+ const int kValue = 1; >+ Variant v(kValue); >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ EXPECT_EQ(kValue, absl::get<int>(v)); >+ >+ // emplace with zero arguments, then back to 'int' >+ v.emplace<NonCopyable>(); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(0, absl::get<NonCopyable>(v).value); >+ v = kValue; >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ >+ // emplace with one argument: >+ v.emplace<NonCopyable>(1); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(1, absl::get<NonCopyable>(v).value); >+ v = kValue; >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ >+ // emplace with two arguments: >+ v.emplace<NonCopyable>(1, 2); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(3, absl::get<NonCopyable>(v).value); >+ v = kValue; >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ >+ // emplace with three arguments >+ v.emplace<NonCopyable>(1, 2, 3); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(6, absl::get<NonCopyable>(v).value); >+ v = kValue; >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ >+ // emplace with four arguments >+ v.emplace<NonCopyable>(1, 2, 3, 4); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(10, absl::get<NonCopyable>(v).value); >+ v = kValue; >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+} >+ >+TEST(VariantTest, TestEmplaceDestroysCurrentValue) { >+ typedef variant<int, IncrementInDtor, NonCopyable> Variant; >+ int counter = 0; >+ Variant v(0); >+ ASSERT_TRUE(absl::holds_alternative<int>(v)); >+ v.emplace<IncrementInDtor>(&counter); >+ ASSERT_TRUE(absl::holds_alternative<IncrementInDtor>(v)); >+ ASSERT_EQ(0, counter); >+ v.emplace<NonCopyable>(); >+ ASSERT_TRUE(absl::holds_alternative<NonCopyable>(v)); >+ EXPECT_EQ(1, counter); >+} >+ >+TEST(VariantTest, TestMoveSemantics) { >+ typedef variant<std::unique_ptr<int>, std::unique_ptr<std::string>> Variant; >+ >+ // Construct a variant by moving from an element value. >+ Variant v(absl::WrapUnique(new int(10))); >+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v)); >+ >+ // Construct a variant by moving from another variant. >+ Variant v2(absl::move(v)); >+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v2)); >+ ASSERT_NE(nullptr, absl::get<std::unique_ptr<int>>(v2)); >+ EXPECT_EQ(10, *absl::get<std::unique_ptr<int>>(v2)); >+ >+ // Moving from a variant object leaves it holding moved-from value of the >+ // same element type. >+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<int>>(v)); >+ ASSERT_NE(nullptr, absl::get_if<std::unique_ptr<int>>(&v)); >+ EXPECT_EQ(nullptr, absl::get<std::unique_ptr<int>>(v)); >+ >+ // Assign a variant from an element value by move. >+ v = absl::make_unique<std::string>("foo"); >+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v)); >+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v)); >+ >+ // Move-assign a variant. >+ v2 = absl::move(v); >+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v2)); >+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<std::string>>(v2)); >+ EXPECT_TRUE(absl::holds_alternative<std::unique_ptr<std::string>>(v)); >+} >+ >+variant<int, std::string> PassThrough(const variant<int, std::string>& arg) { >+ return arg; >+} >+ >+TEST(VariantTest, TestImplicitConversion) { >+ EXPECT_TRUE(absl::holds_alternative<int>(PassThrough(0))); >+ >+ // We still need the explicit cast for std::string, because C++ won't apply >+ // two user-defined implicit conversions in a row. >+ EXPECT_TRUE(absl::holds_alternative<std::string>(PassThrough(std::string("foo")))); >+} >+ >+struct Convertible2; >+struct Convertible1 { >+ Convertible1() {} >+ Convertible1(const Convertible1&) {} >+ Convertible1& operator=(const Convertible1&) { return *this; } >+ >+ // implicit conversion from Convertible2 >+ Convertible1(const Convertible2&) {} // NOLINT(runtime/explicit) >+}; >+ >+struct Convertible2 { >+ Convertible2() {} >+ Convertible2(const Convertible2&) {} >+ Convertible2& operator=(const Convertible2&) { return *this; } >+ >+ // implicit conversion from Convertible1 >+ Convertible2(const Convertible1&) {} // NOLINT(runtime/explicit) >+}; >+ >+TEST(VariantTest, TestRvalueConversion) { >+ variant<double, std::string> var( >+ ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(0))); >+ ASSERT_TRUE(absl::holds_alternative<double>(var)); >+ EXPECT_EQ(0.0, absl::get<double>(var)); >+ >+ var = ConvertVariantTo<variant<double, std::string>>( >+ variant<const char*, float>("foo")); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(var)); >+ EXPECT_EQ("foo", absl::get<std::string>(var)); >+ >+ variant<double> singleton( >+ ConvertVariantTo<variant<double>>(variant<int, float>(42))); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_EQ(42.0, absl::get<double>(singleton)); >+ >+ singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f)); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); >+ >+ singleton = ConvertVariantTo<variant<double>>(variant<int>(0)); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_EQ(0.0, absl::get<double>(singleton)); >+ >+ variant<int32_t, uint32_t> variant2( >+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); >+ ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); >+ EXPECT_EQ(42, absl::get<int32_t>(variant2)); >+ >+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); >+ ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); >+ EXPECT_EQ(42, absl::get<uint32_t>(variant2)); >+ >+ variant<Convertible1, Convertible2> variant3( >+ ConvertVariantTo<variant<Convertible1, Convertible2>>( >+ (variant<Convertible2, Convertible1>(Convertible1())))); >+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); >+ >+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>( >+ variant<Convertible2, Convertible1>(Convertible2())); >+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); >+} >+ >+TEST(VariantTest, TestLvalueConversion) { >+ variant<std::string, int> source1 = 0; >+ variant<double, std::string> destination( >+ ConvertVariantTo<variant<double, std::string>>(source1)); >+ ASSERT_TRUE(absl::holds_alternative<double>(destination)); >+ EXPECT_EQ(0.0, absl::get<double>(destination)); >+ >+ variant<const char*, float> source2 = "foo"; >+ destination = ConvertVariantTo<variant<double, std::string>>(source2); >+ ASSERT_TRUE(absl::holds_alternative<std::string>(destination)); >+ EXPECT_EQ("foo", absl::get<std::string>(destination)); >+ >+ variant<int, float> source3(42); >+ variant<double> singleton(ConvertVariantTo<variant<double>>(source3)); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_EQ(42.0, absl::get<double>(singleton)); >+ >+ source3 = 3.14f; >+ singleton = ConvertVariantTo<variant<double>>(source3); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); >+ >+ variant<int> source4(0); >+ singleton = ConvertVariantTo<variant<double>>(source4); >+ ASSERT_TRUE(absl::holds_alternative<double>(singleton)); >+ EXPECT_EQ(0.0, absl::get<double>(singleton)); >+ >+ variant<int32_t> source5(42); >+ variant<int32_t, uint32_t> variant2( >+ ConvertVariantTo<variant<int32_t, uint32_t>>(source5)); >+ ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2)); >+ EXPECT_EQ(42, absl::get<int32_t>(variant2)); >+ >+ variant<uint32_t> source6(42); >+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); >+ ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2)); >+ EXPECT_EQ(42, absl::get<uint32_t>(variant2)); >+ >+ variant<Convertible2, Convertible1> source7((Convertible1())); >+ variant<Convertible1, Convertible2> variant3( >+ ConvertVariantTo<variant<Convertible1, Convertible2>>(source7)); >+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); >+ >+ source7 = Convertible2(); >+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7); >+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); >+} >+ >+TEST(VariantTest, TestMoveConversion) { >+ using Variant = >+ variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; >+ using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; >+ >+ Variant var( >+ ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(0)})); >+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const int>>(var)); >+ ASSERT_NE(absl::get<std::unique_ptr<const int>>(var), nullptr); >+ EXPECT_EQ(0, *absl::get<std::unique_ptr<const int>>(var)); >+ >+ var = >+ ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo"))); >+ ASSERT_TRUE(absl::holds_alternative<std::unique_ptr<const std::string>>(var)); >+ EXPECT_EQ("foo", *absl::get<std::unique_ptr<const std::string>>(var)); >+} >+ >+TEST(VariantTest, DoesNotMoveFromLvalues) { >+ // We use shared_ptr here because it's both copyable and movable, and >+ // a moved-from shared_ptr is guaranteed to be null, so we can detect >+ // whether moving or copying has occurred. >+ using Variant = >+ variant<std::shared_ptr<const int>, std::shared_ptr<const std::string>>; >+ using OtherVariant = variant<std::shared_ptr<int>, std::shared_ptr<std::string>>; >+ >+ Variant v1(std::make_shared<const int>(0)); >+ >+ // Test copy constructor >+ Variant v2(v1); >+ EXPECT_EQ(absl::get<std::shared_ptr<const int>>(v1), >+ absl::get<std::shared_ptr<const int>>(v2)); >+ >+ // Test copy-assignment operator >+ v1 = std::make_shared<const std::string>("foo"); >+ v2 = v1; >+ EXPECT_EQ(absl::get<std::shared_ptr<const std::string>>(v1), >+ absl::get<std::shared_ptr<const std::string>>(v2)); >+ >+ // Test converting copy constructor >+ OtherVariant other(std::make_shared<int>(0)); >+ Variant v3(ConvertVariantTo<Variant>(other)); >+ EXPECT_EQ(absl::get<std::shared_ptr<int>>(other), >+ absl::get<std::shared_ptr<const int>>(v3)); >+ >+ other = std::make_shared<std::string>("foo"); >+ v3 = ConvertVariantTo<Variant>(other); >+ EXPECT_EQ(absl::get<std::shared_ptr<std::string>>(other), >+ absl::get<std::shared_ptr<const std::string>>(v3)); >+} >+ >+TEST(VariantTest, TestRvalueConversionViaConvertVariantTo) { >+ variant<double, std::string> var( >+ ConvertVariantTo<variant<double, std::string>>(variant<std::string, int>(3))); >+ EXPECT_THAT(absl::get_if<double>(&var), Pointee(3.0)); >+ >+ var = ConvertVariantTo<variant<double, std::string>>( >+ variant<const char*, float>("foo")); >+ EXPECT_THAT(absl::get_if<std::string>(&var), Pointee(std::string("foo"))); >+ >+ variant<double> singleton( >+ ConvertVariantTo<variant<double>>(variant<int, float>(42))); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0)); >+ >+ singleton = ConvertVariantTo<variant<double>>(variant<int, float>(3.14f)); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f))); >+ >+ singleton = ConvertVariantTo<variant<double>>(variant<int>(3)); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0)); >+ >+ variant<int32_t, uint32_t> variant2( >+ ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42))); >+ EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); >+ >+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42)); >+ EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); >+ >+ variant<Convertible1, Convertible2> variant3( >+ ConvertVariantTo<variant<Convertible1, Convertible2>>( >+ (variant<Convertible2, Convertible1>(Convertible1())))); >+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); >+ >+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>( >+ variant<Convertible2, Convertible1>(Convertible2())); >+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); >+} >+ >+TEST(VariantTest, TestLvalueConversionViaConvertVariantTo) { >+ variant<std::string, int> source1 = 3; >+ variant<double, std::string> destination( >+ ConvertVariantTo<variant<double, std::string>>(source1)); >+ EXPECT_THAT(absl::get_if<double>(&destination), Pointee(3.0)); >+ >+ variant<const char*, float> source2 = "foo"; >+ destination = ConvertVariantTo<variant<double, std::string>>(source2); >+ EXPECT_THAT(absl::get_if<std::string>(&destination), Pointee(std::string("foo"))); >+ >+ variant<int, float> source3(42); >+ variant<double> singleton(ConvertVariantTo<variant<double>>(source3)); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(42.0)); >+ >+ source3 = 3.14f; >+ singleton = ConvertVariantTo<variant<double>>(source3); >+ EXPECT_FLOAT_EQ(3.14f, static_cast<float>(absl::get<double>(singleton))); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(DoubleEq(3.14f))); >+ >+ variant<int> source4(3); >+ singleton = ConvertVariantTo<variant<double>>(source4); >+ EXPECT_THAT(absl::get_if<double>(&singleton), Pointee(3.0)); >+ >+ variant<int32_t> source5(42); >+ variant<int32_t, uint32_t> variant2( >+ ConvertVariantTo<variant<int32_t, uint32_t>>(source5)); >+ EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42)); >+ >+ variant<uint32_t> source6(42); >+ variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(source6); >+ EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42)); >+ >+ variant<Convertible2, Convertible1> source7((Convertible1())); >+ variant<Convertible1, Convertible2> variant3( >+ ConvertVariantTo<variant<Convertible1, Convertible2>>(source7)); >+ ASSERT_TRUE(absl::holds_alternative<Convertible1>(variant3)); >+ >+ source7 = Convertible2(); >+ variant3 = ConvertVariantTo<variant<Convertible1, Convertible2>>(source7); >+ ASSERT_TRUE(absl::holds_alternative<Convertible2>(variant3)); >+} >+ >+TEST(VariantTest, TestMoveConversionViaConvertVariantTo) { >+ using Variant = >+ variant<std::unique_ptr<const int>, std::unique_ptr<const std::string>>; >+ using OtherVariant = variant<std::unique_ptr<int>, std::unique_ptr<std::string>>; >+ >+ Variant var( >+ ConvertVariantTo<Variant>(OtherVariant{absl::make_unique<int>(3)})); >+ EXPECT_THAT(absl::get_if<std::unique_ptr<const int>>(&var), >+ Pointee(Pointee(3))); >+ >+ var = >+ ConvertVariantTo<Variant>(OtherVariant(absl::make_unique<std::string>("foo"))); >+ EXPECT_THAT(absl::get_if<std::unique_ptr<const std::string>>(&var), >+ Pointee(Pointee(std::string("foo")))); >+} >+ >+// If all alternatives are trivially copy/move constructible, variant should >+// also be trivially copy/move constructible. This is not required by the >+// standard and we know that libstdc++ variant doesn't have this feature. >+// For more details see the paper: >+// http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0602r0.html >+#if !(defined(ABSL_HAVE_STD_VARIANT) && defined(__GLIBCXX__)) >+#define ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY 1 >+#endif >+ >+TEST(VariantTest, TestCopyAndMoveTypeTraits) { >+ EXPECT_TRUE(std::is_copy_constructible<variant<std::string>>::value); >+ EXPECT_TRUE(std::is_copy_assignable<variant<std::string>>::value); >+ EXPECT_TRUE(std::is_move_constructible<variant<std::string>>::value); >+ EXPECT_TRUE(std::is_move_assignable<variant<std::string>>::value); >+ EXPECT_TRUE(std::is_move_constructible<variant<std::unique_ptr<int>>>::value); >+ EXPECT_TRUE(std::is_move_assignable<variant<std::unique_ptr<int>>>::value); >+ EXPECT_FALSE( >+ std::is_copy_constructible<variant<std::unique_ptr<int>>>::value); >+ EXPECT_FALSE(std::is_copy_assignable<variant<std::unique_ptr<int>>>::value); >+ >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<variant<std::string>>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<variant<std::string>>::value); >+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<variant<int>>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<variant<int>>::value); >+ EXPECT_TRUE(is_trivially_move_constructible<variant<int>>::value); >+ EXPECT_TRUE(is_trivially_move_assignable<variant<int>>::value); >+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+} >+ >+TEST(VariantTest, TestVectorOfMoveonlyVariant) { >+ // Verify that variant<MoveonlyType> works correctly as a std::vector element. >+ std::vector<variant<std::unique_ptr<int>, std::string>> vec; >+ vec.push_back(absl::make_unique<int>(42)); >+ vec.emplace_back("Hello"); >+ vec.reserve(3); >+ auto another_vec = absl::move(vec); >+ // As a sanity check, verify vector contents. >+ ASSERT_EQ(2, another_vec.size()); >+ EXPECT_EQ(42, *absl::get<std::unique_ptr<int>>(another_vec[0])); >+ EXPECT_EQ("Hello", absl::get<std::string>(another_vec[1])); >+} >+ >+TEST(VariantTest, NestedVariant) { >+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+ static_assert(absl::is_trivially_copy_constructible<variant<int>>(), ""); >+ static_assert(absl::is_trivially_copy_assignable<variant<int>>(), ""); >+ static_assert(is_trivially_move_constructible<variant<int>>(), ""); >+ static_assert(is_trivially_move_assignable<variant<int>>(), ""); >+ >+ static_assert(absl::is_trivially_copy_constructible<variant<variant<int>>>(), >+ ""); >+ static_assert(absl::is_trivially_copy_assignable<variant<variant<int>>>(), >+ ""); >+ static_assert(is_trivially_move_constructible<variant<variant<int>>>(), ""); >+ static_assert(is_trivially_move_assignable<variant<variant<int>>>(), ""); >+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+ >+ variant<int> x(42); >+ variant<variant<int>> y(x); >+ variant<variant<int>> z(y); >+ EXPECT_TRUE(absl::holds_alternative<variant<int>>(z)); >+ EXPECT_EQ(x, absl::get<variant<int>>(z)); >+} >+ >+struct TriviallyDestructible { >+ TriviallyDestructible(TriviallyDestructible&&) {} >+ TriviallyDestructible(const TriviallyDestructible&) {} >+ TriviallyDestructible& operator=(TriviallyDestructible&&) { return *this; } >+ TriviallyDestructible& operator=(const TriviallyDestructible&) { >+ return *this; >+ } >+}; >+ >+struct TriviallyMovable { >+ TriviallyMovable(TriviallyMovable&&) = default; >+ TriviallyMovable(TriviallyMovable const&) {} >+ TriviallyMovable& operator=(const TriviallyMovable&) { return *this; } >+}; >+ >+struct TriviallyCopyable { >+ TriviallyCopyable(const TriviallyCopyable&) = default; >+ TriviallyCopyable& operator=(const TriviallyCopyable&) { return *this; } >+}; >+ >+struct TriviallyMoveAssignable { >+ TriviallyMoveAssignable(TriviallyMoveAssignable&&) = default; >+ TriviallyMoveAssignable(const TriviallyMoveAssignable&) {} >+ TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default; >+ TriviallyMoveAssignable& operator=(const TriviallyMoveAssignable&) { >+ return *this; >+ } >+}; >+ >+struct TriviallyCopyAssignable {}; >+ >+#if ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+TEST(VariantTest, TestTriviality) { >+ { >+ using TrivDestVar = absl::variant<TriviallyDestructible>; >+ >+ EXPECT_FALSE(is_trivially_move_constructible<TrivDestVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivDestVar>::value); >+ EXPECT_FALSE(is_trivially_move_assignable<TrivDestVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivDestVar>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivDestVar>::value); >+ } >+ >+ { >+ using TrivMoveVar = absl::variant<TriviallyMovable>; >+ >+ EXPECT_TRUE(is_trivially_move_constructible<TrivMoveVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_constructible<TrivMoveVar>::value); >+ EXPECT_FALSE(is_trivially_move_assignable<TrivMoveVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveVar>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveVar>::value); >+ } >+ >+ { >+ using TrivCopyVar = absl::variant<TriviallyCopyable>; >+ >+ EXPECT_TRUE(is_trivially_move_constructible<TrivCopyVar>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_constructible<TrivCopyVar>::value); >+ EXPECT_FALSE(is_trivially_move_assignable<TrivCopyVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivCopyVar>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyVar>::value); >+ } >+ >+ { >+ using TrivMoveAssignVar = absl::variant<TriviallyMoveAssignable>; >+ >+ EXPECT_TRUE(is_trivially_move_constructible<TrivMoveAssignVar>::value); >+ EXPECT_FALSE( >+ absl::is_trivially_copy_constructible<TrivMoveAssignVar>::value); >+ EXPECT_TRUE(is_trivially_move_assignable<TrivMoveAssignVar>::value); >+ EXPECT_FALSE(absl::is_trivially_copy_assignable<TrivMoveAssignVar>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivMoveAssignVar>::value); >+ } >+ >+ { >+ using TrivCopyAssignVar = absl::variant<TriviallyCopyAssignable>; >+ >+ EXPECT_TRUE(is_trivially_move_constructible<TrivCopyAssignVar>::value); >+ EXPECT_TRUE( >+ absl::is_trivially_copy_constructible<TrivCopyAssignVar>::value); >+ EXPECT_TRUE(is_trivially_move_assignable<TrivCopyAssignVar>::value); >+ EXPECT_TRUE(absl::is_trivially_copy_assignable<TrivCopyAssignVar>::value); >+ EXPECT_TRUE(absl::is_trivially_destructible<TrivCopyAssignVar>::value); >+ } >+} >+#endif // ABSL_VARIANT_PROPAGATE_COPY_MOVE_TRIVIALITY >+ >+// To verify that absl::variant correctly use the nontrivial move ctor of its >+// member rather than use the trivial copy constructor. >+TEST(VariantTest, MoveCtorBug) { >+ // To simulate std::tuple in libstdc++. >+ struct TrivialCopyNontrivialMove { >+ TrivialCopyNontrivialMove() = default; >+ TrivialCopyNontrivialMove(const TrivialCopyNontrivialMove&) = default; >+ TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) { called = true; } >+ bool called = false; >+ }; >+ { >+ using V = absl::variant<TrivialCopyNontrivialMove, int>; >+ V v1(absl::in_place_index_t<0>{}); >+ // this should invoke the move ctor, rather than the trivial copy ctor. >+ V v2(std::move(v1)); >+ EXPECT_TRUE(absl::get<0>(v2).called); >+ } >+ { >+ // this case failed to compile before our fix due to a GCC bug. >+ using V = absl::variant<int, TrivialCopyNontrivialMove>; >+ V v1(absl::in_place_index_t<1>{}); >+ // this should invoke the move ctor, rather than the trivial copy ctor. >+ V v2(std::move(v1)); >+ EXPECT_TRUE(absl::get<1>(v2).called); >+ } >+} >+ >+} // namespace >+} // namespace absl >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.bazel b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.bazel >new file mode 100644 >index 00000000000..c01b49bc97d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.bazel >@@ -0,0 +1,33 @@ >+load( >+ "//absl:copts.bzl", >+ "ABSL_DEFAULT_COPTS", >+ "ABSL_TEST_COPTS", >+) >+ >+package(default_visibility = ["//visibility:public"]) >+ >+licenses(["notice"]) # Apache 2.0 >+ >+cc_library( >+ name = "utility", >+ hdrs = ["utility.h"], >+ copts = ABSL_DEFAULT_COPTS, >+ deps = [ >+ "//absl/base:base_internal", >+ "//absl/base:config", >+ "//absl/meta:type_traits", >+ ], >+) >+ >+cc_test( >+ name = "utility_test", >+ srcs = ["utility_test.cc"], >+ copts = ABSL_TEST_COPTS, >+ deps = [ >+ ":utility", >+ "//absl/base:core_headers", >+ "//absl/memory", >+ "//absl/strings", >+ "@com_google_googletest//:gtest_main", >+ ], >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.gn >new file mode 100644 >index 00000000000..4cf3c810e65 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/BUILD.gn >@@ -0,0 +1,32 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//build_overrides/build.gni") >+ >+if (build_with_chromium) { >+ visibility = [ >+ "//third_party/webrtc/*", >+ "//third_party/abseil-cpp/*", >+ "//third_party/googletest:gtest", >+ ] >+} else { >+ visibility = [ "*" ] >+} >+ >+source_set("utility") { >+ configs -= [ "//build/config/compiler:chromium_code" ] >+ configs += [ >+ "//build/config/compiler:no_chromium_code", >+ "//third_party/abseil-cpp:absl_default_cflags_cc", >+ ] >+ public_configs = [ "//third_party/abseil-cpp:absl_include_config" ] >+ public = [ >+ "utility.h", >+ ] >+ deps = [ >+ "../base:base_internal", >+ "../base:config", >+ "../meta:type_traits", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/CMakeLists.txt b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/CMakeLists.txt >new file mode 100644 >index 00000000000..dc3a6319054 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/CMakeLists.txt >@@ -0,0 +1,52 @@ >+# >+# Copyright 2017 The Abseil Authors. >+# >+# Licensed under the Apache License, Version 2.0 (the "License"); >+# you may not use this file except in compliance with the License. >+# You may obtain a copy of the License at >+# >+# http://www.apache.org/licenses/LICENSE-2.0 >+# >+# Unless required by applicable law or agreed to in writing, software >+# distributed under the License is distributed on an "AS IS" BASIS, >+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+# See the License for the specific language governing permissions and >+# limitations under the License. >+# >+ >+ >+list(APPEND UTILITY_PUBLIC_HEADERS >+ "utility.h" >+) >+ >+absl_header_library( >+ TARGET >+ absl_utility >+ PUBLIC_LIBRARIES >+ absl::base >+ EXPORT_NAME >+ utility >+) >+ >+ >+# >+## TESTS >+# >+ >+# test utility_test >+set(UTILITY_TEST_SRC "utility_test.cc") >+set(UTILITY_TEST_PUBLIC_LIBRARIES >+ absl::base >+ absl::memory >+ absl::strings >+ absl::utility >+) >+ >+absl_test( >+ TARGET >+ utility_test >+ SOURCES >+ ${UTILITY_TEST_SRC} >+ PUBLIC_LIBRARIES >+ ${UTILITY_TEST_PUBLIC_LIBRARIES} >+) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility.h b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility.h >new file mode 100644 >index 00000000000..d73602c47d3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility.h >@@ -0,0 +1,291 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+// >+// This header file contains C++11 versions of standard <utility> header >+// abstractions available within C++14 and C++17, and are designed to be drop-in >+// replacement for code compliant with C++14 and C++17. >+// >+// The following abstractions are defined: >+// >+// * integer_sequence<T, Ints...> == std::integer_sequence<T, Ints...> >+// * index_sequence<Ints...> == std::index_sequence<Ints...> >+// * make_integer_sequence<T, N> == std::make_integer_sequence<T, N> >+// * make_index_sequence<N> == std::make_index_sequence<N> >+// * index_sequence_for<Ts...> == std::index_sequence_for<Ts...> >+// * apply<Functor, Tuple> == std::apply<Functor, Tuple> >+// * exchange<T> == std::exchange<T> >+// >+// This header file also provides the tag types `in_place_t`, `in_place_type_t`, >+// and `in_place_index_t`, as well as the constant `in_place`, and >+// `constexpr` `std::move()` and `std::forward()` implementations in C++11. >+// >+// References: >+// >+// http://en.cppreference.com/w/cpp/utility/integer_sequence >+// http://en.cppreference.com/w/cpp/utility/apply >+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html >+// >+ >+#ifndef ABSL_UTILITY_UTILITY_H_ >+#define ABSL_UTILITY_UTILITY_H_ >+ >+#include <cstddef> >+#include <cstdlib> >+#include <tuple> >+#include <utility> >+ >+#include "absl/base/config.h" >+#include "absl/base/internal/inline_variable.h" >+#include "absl/base/internal/invoke.h" >+#include "absl/meta/type_traits.h" >+ >+namespace absl { >+ >+// integer_sequence >+// >+// Class template representing a compile-time integer sequence. An instantiation >+// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its >+// type through its template arguments (which is a common need when >+// working with C++11 variadic templates). `absl::integer_sequence` is designed >+// to be a drop-in replacement for C++14's `std::integer_sequence`. >+// >+// Example: >+// >+// template< class T, T... Ints > >+// void user_function(integer_sequence<T, Ints...>); >+// >+// int main() >+// { >+// // user_function's `T` will be deduced to `int` and `Ints...` >+// // will be deduced to `0, 1, 2, 3, 4`. >+// user_function(make_integer_sequence<int, 5>()); >+// } >+template <typename T, T... Ints> >+struct integer_sequence { >+ using value_type = T; >+ static constexpr size_t size() noexcept { return sizeof...(Ints); } >+}; >+ >+// index_sequence >+// >+// A helper template for an `integer_sequence` of `size_t`, >+// `absl::index_sequence` is designed to be a drop-in replacement for C++14's >+// `std::index_sequence`. >+template <size_t... Ints> >+using index_sequence = integer_sequence<size_t, Ints...>; >+ >+namespace utility_internal { >+ >+template <typename Seq, size_t SeqSize, size_t Rem> >+struct Extend; >+ >+// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. >+template <typename T, T... Ints, size_t SeqSize> >+struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> { >+ using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>; >+}; >+ >+template <typename T, T... Ints, size_t SeqSize> >+struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> { >+ using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>; >+}; >+ >+// Recursion helper for 'make_integer_sequence<T, N>'. >+// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. >+template <typename T, size_t N> >+struct Gen { >+ using type = >+ typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type; >+}; >+ >+template <typename T> >+struct Gen<T, 0> { >+ using type = integer_sequence<T>; >+}; >+ >+} // namespace utility_internal >+ >+// Compile-time sequences of integers >+ >+// make_integer_sequence >+// >+// This template alias is equivalent to >+// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in >+// replacement for C++14's `std::make_integer_sequence`. >+template <typename T, T N> >+using make_integer_sequence = typename utility_internal::Gen<T, N>::type; >+ >+// make_index_sequence >+// >+// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, >+// and is designed to be a drop-in replacement for C++14's >+// `std::make_index_sequence`. >+template <size_t N> >+using make_index_sequence = make_integer_sequence<size_t, N>; >+ >+// index_sequence_for >+// >+// Converts a typename pack into an index sequence of the same length, and >+// is designed to be a drop-in replacement for C++14's >+// `std::index_sequence_for()` >+template <typename... Ts> >+using index_sequence_for = make_index_sequence<sizeof...(Ts)>; >+ >+// Tag types >+ >+#ifdef ABSL_HAVE_STD_OPTIONAL >+ >+using std::in_place_t; >+using std::in_place; >+ >+#else // ABSL_HAVE_STD_OPTIONAL >+ >+// in_place_t >+// >+// Tag type used to specify in-place construction, such as with >+// `absl::optional`, designed to be a drop-in replacement for C++17's >+// `std::in_place_t`. >+struct in_place_t {}; >+ >+ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {}); >+ >+#endif // ABSL_HAVE_STD_OPTIONAL >+ >+#if defined(ABSL_HAVE_STD_ANY) || defined(ABSL_HAVE_STD_VARIANT) >+using std::in_place_type_t; >+#else >+ >+// in_place_type_t >+// >+// Tag type used for in-place construction when the type to construct needs to >+// be specified, such as with `absl::any`, designed to be a drop-in replacement >+// for C++17's `std::in_place_type_t`. >+template <typename T> >+struct in_place_type_t {}; >+#endif // ABSL_HAVE_STD_ANY || ABSL_HAVE_STD_VARIANT >+ >+#ifdef ABSL_HAVE_STD_VARIANT >+using std::in_place_index_t; >+#else >+ >+// in_place_index_t >+// >+// Tag type used for in-place construction when the type to construct needs to >+// be specified, such as with `absl::any`, designed to be a drop-in replacement >+// for C++17's `std::in_place_index_t`. >+template <size_t I> >+struct in_place_index_t {}; >+#endif // ABSL_HAVE_STD_VARIANT >+ >+// Constexpr move and forward >+ >+// move() >+// >+// A constexpr version of `std::move()`, designed to be a drop-in replacement >+// for C++14's `std::move()`. >+template <typename T> >+constexpr absl::remove_reference_t<T>&& move(T&& t) noexcept { >+ return static_cast<absl::remove_reference_t<T>&&>(t); >+} >+ >+// forward() >+// >+// A constexpr version of `std::forward()`, designed to be a drop-in replacement >+// for C++14's `std::forward()`. >+template <typename T> >+constexpr T&& forward( >+ absl::remove_reference_t<T>& t) noexcept { // NOLINT(runtime/references) >+ return static_cast<T&&>(t); >+} >+ >+namespace utility_internal { >+// Helper method for expanding tuple into a called method. >+template <typename Functor, typename Tuple, std::size_t... Indexes> >+auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>) >+ -> decltype(absl::base_internal::Invoke( >+ absl::forward<Functor>(functor), >+ std::get<Indexes>(absl::forward<Tuple>(t))...)) { >+ return absl::base_internal::Invoke( >+ absl::forward<Functor>(functor), >+ std::get<Indexes>(absl::forward<Tuple>(t))...); >+} >+ >+} // namespace utility_internal >+ >+// apply >+// >+// Invokes a Callable using elements of a tuple as its arguments. >+// Each element of the tuple corresponds to an argument of the call (in order). >+// Both the Callable argument and the tuple argument are perfect-forwarded. >+// For member-function Callables, the first tuple element acts as the `this` >+// pointer. `absl::apply` is designed to be a drop-in replacement for C++17's >+// `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`. >+// >+// Example: >+// >+// class Foo{void Bar(int);}; >+// void user_function(int, std::string); >+// void user_function(std::unique_ptr<Foo>); >+// >+// int main() >+// { >+// std::tuple<int, std::string> tuple1(42, "bar"); >+// // Invokes the user function overload on int, std::string. >+// absl::apply(&user_function, tuple1); >+// >+// auto foo = absl::make_unique<Foo>(); >+// std::tuple<Foo*, int> tuple2(foo.get(), 42); >+// // Invokes the method Bar on foo with one argument 42. >+// absl::apply(&Foo::Bar, foo.get(), 42); >+// >+// std::tuple<std::unique_ptr<Foo>> tuple3(absl::make_unique<Foo>()); >+// // Invokes the user function that takes ownership of the unique >+// // pointer. >+// absl::apply(&user_function, std::move(tuple)); >+// } >+template <typename Functor, typename Tuple> >+auto apply(Functor&& functor, Tuple&& t) >+ -> decltype(utility_internal::apply_helper( >+ absl::forward<Functor>(functor), absl::forward<Tuple>(t), >+ absl::make_index_sequence<std::tuple_size< >+ typename std::remove_reference<Tuple>::type>::value>{})) { >+ return utility_internal::apply_helper( >+ absl::forward<Functor>(functor), absl::forward<Tuple>(t), >+ absl::make_index_sequence<std::tuple_size< >+ typename std::remove_reference<Tuple>::type>::value>{}); >+} >+ >+// exchange >+// >+// Replaces the value of `obj` with `new_value` and returns the old value of >+// `obj`. `absl::exchange` is designed to be a drop-in replacement for C++14's >+// `std::exchange`. >+// >+// Example: >+// >+// Foo& operator=(Foo&& other) { >+// ptr1_ = absl::exchange(other.ptr1_, nullptr); >+// int1_ = absl::exchange(other.int1_, -1); >+// return *this; >+// } >+template <typename T, typename U = T> >+T exchange(T& obj, U&& new_value) { >+ T old_value = absl::move(obj); >+ obj = absl::forward<U>(new_value); >+ return old_value; >+} >+ >+} // namespace absl >+ >+#endif // ABSL_UTILITY_UTILITY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility_test.cc >new file mode 100644 >index 00000000000..3c447b20bb0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/absl/utility/utility_test.cc >@@ -0,0 +1,345 @@ >+// Copyright 2017 The Abseil Authors. >+// >+// Licensed under the Apache License, Version 2.0 (the "License"); >+// you may not use this file except in compliance with the License. >+// You may obtain a copy of the License at >+// >+// http://www.apache.org/licenses/LICENSE-2.0 >+// >+// Unless required by applicable law or agreed to in writing, software >+// distributed under the License is distributed on an "AS IS" BASIS, >+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+// See the License for the specific language governing permissions and >+// limitations under the License. >+ >+#include "absl/utility/utility.h" >+ >+#include <sstream> >+#include <string> >+#include <tuple> >+#include <type_traits> >+#include <vector> >+ >+#include "gmock/gmock.h" >+#include "gtest/gtest.h" >+#include "absl/base/attributes.h" >+#include "absl/memory/memory.h" >+#include "absl/strings/str_cat.h" >+ >+namespace { >+ >+#ifdef _MSC_VER >+// Warnings for unused variables in this test are false positives. On other >+// platforms, they are suppressed by ABSL_ATTRIBUTE_UNUSED, but that doesn't >+// work on MSVC. >+// Both the unused variables and the name length warnings are due to calls >+// to absl::make_index_sequence with very large values, creating very long type >+// names. The resulting warnings are so long they make build output unreadable. >+#pragma warning( push ) >+#pragma warning( disable : 4503 ) // decorated name length exceeded >+#pragma warning( disable : 4101 ) // unreferenced local variable >+#endif // _MSC_VER >+ >+using ::testing::ElementsAre; >+using ::testing::Pointee; >+using ::testing::StaticAssertTypeEq; >+ >+TEST(IntegerSequenceTest, ValueType) { >+ StaticAssertTypeEq<int, absl::integer_sequence<int>::value_type>(); >+ StaticAssertTypeEq<char, absl::integer_sequence<char>::value_type>(); >+} >+ >+TEST(IntegerSequenceTest, Size) { >+ EXPECT_EQ(0, (absl::integer_sequence<int>::size())); >+ EXPECT_EQ(1, (absl::integer_sequence<int, 0>::size())); >+ EXPECT_EQ(1, (absl::integer_sequence<int, 1>::size())); >+ EXPECT_EQ(2, (absl::integer_sequence<int, 1, 2>::size())); >+ EXPECT_EQ(3, (absl::integer_sequence<int, 0, 1, 2>::size())); >+ EXPECT_EQ(3, (absl::integer_sequence<int, -123, 123, 456>::size())); >+ constexpr size_t sz = absl::integer_sequence<int, 0, 1>::size(); >+ EXPECT_EQ(2, sz); >+} >+ >+TEST(IntegerSequenceTest, MakeIndexSequence) { >+ StaticAssertTypeEq<absl::index_sequence<>, absl::make_index_sequence<0>>(); >+ StaticAssertTypeEq<absl::index_sequence<0>, absl::make_index_sequence<1>>(); >+ StaticAssertTypeEq<absl::index_sequence<0, 1>, >+ absl::make_index_sequence<2>>(); >+ StaticAssertTypeEq<absl::index_sequence<0, 1, 2>, >+ absl::make_index_sequence<3>>(); >+} >+ >+TEST(IntegerSequenceTest, MakeIntegerSequence) { >+ StaticAssertTypeEq<absl::integer_sequence<int>, >+ absl::make_integer_sequence<int, 0>>(); >+ StaticAssertTypeEq<absl::integer_sequence<int, 0>, >+ absl::make_integer_sequence<int, 1>>(); >+ StaticAssertTypeEq<absl::integer_sequence<int, 0, 1>, >+ absl::make_integer_sequence<int, 2>>(); >+ StaticAssertTypeEq<absl::integer_sequence<int, 0, 1, 2>, >+ absl::make_integer_sequence<int, 3>>(); >+} >+ >+template <typename... Ts> >+class Counter {}; >+ >+template <size_t... Is> >+void CountAll(absl::index_sequence<Is...>) { >+ // We only need an alias here, but instantiate a variable to silence warnings >+ // for unused typedefs in some compilers. >+ ABSL_ATTRIBUTE_UNUSED Counter<absl::make_index_sequence<Is>...> seq; >+} >+ >+// This test verifies that absl::make_index_sequence can handle large arguments >+// without blowing up template instantiation stack, going OOM or taking forever >+// to compile (there is hard 15 minutes limit imposed by forge). >+TEST(IntegerSequenceTest, MakeIndexSequencePerformance) { >+ // O(log N) template instantiations. >+ // We only need an alias here, but instantiate a variable to silence warnings >+ // for unused typedefs in some compilers. >+ ABSL_ATTRIBUTE_UNUSED absl::make_index_sequence<(1 << 16) - 1> seq; >+ // O(N) template instantiations. >+ CountAll(absl::make_index_sequence<(1 << 8) - 1>()); >+} >+ >+template <typename F, typename Tup, size_t... Is> >+auto ApplyFromTupleImpl(F f, const Tup& tup, absl::index_sequence<Is...>) >+ -> decltype(f(std::get<Is>(tup)...)) { >+ return f(std::get<Is>(tup)...); >+} >+ >+template <typename Tup> >+using TupIdxSeq = absl::make_index_sequence<std::tuple_size<Tup>::value>; >+ >+template <typename F, typename Tup> >+auto ApplyFromTuple(F f, const Tup& tup) >+ -> decltype(ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{})) { >+ return ApplyFromTupleImpl(f, tup, TupIdxSeq<Tup>{}); >+} >+ >+template <typename T> >+std::string Fmt(const T& x) { >+ std::ostringstream os; >+ os << x; >+ return os.str(); >+} >+ >+struct PoorStrCat { >+ template <typename... Args> >+ std::string operator()(const Args&... args) const { >+ std::string r; >+ for (const auto& e : {Fmt(args)...}) r += e; >+ return r; >+ } >+}; >+ >+template <typename Tup, size_t... Is> >+std::vector<std::string> TupStringVecImpl(const Tup& tup, >+ absl::index_sequence<Is...>) { >+ return {Fmt(std::get<Is>(tup))...}; >+} >+ >+template <typename... Ts> >+std::vector<std::string> TupStringVec(const std::tuple<Ts...>& tup) { >+ return TupStringVecImpl(tup, absl::index_sequence_for<Ts...>()); >+} >+ >+TEST(MakeIndexSequenceTest, ApplyFromTupleExample) { >+ PoorStrCat f{}; >+ EXPECT_EQ("12abc3.14", f(12, "abc", 3.14)); >+ EXPECT_EQ("12abc3.14", ApplyFromTuple(f, std::make_tuple(12, "abc", 3.14))); >+} >+ >+TEST(IndexSequenceForTest, Basic) { >+ StaticAssertTypeEq<absl::index_sequence<>, absl::index_sequence_for<>>(); >+ StaticAssertTypeEq<absl::index_sequence<0>, absl::index_sequence_for<int>>(); >+ StaticAssertTypeEq<absl::index_sequence<0, 1, 2, 3>, >+ absl::index_sequence_for<int, void, char, int>>(); >+} >+ >+TEST(IndexSequenceForTest, Example) { >+ EXPECT_THAT(TupStringVec(std::make_tuple(12, "abc", 3.14)), >+ ElementsAre("12", "abc", "3.14")); >+} >+ >+int Function(int a, int b) { return a - b; } >+ >+int Sink(std::unique_ptr<int> p) { return *p; } >+ >+std::unique_ptr<int> Factory(int n) { return absl::make_unique<int>(n); } >+ >+void NoOp() {} >+ >+struct ConstFunctor { >+ int operator()(int a, int b) const { return a - b; } >+}; >+ >+struct MutableFunctor { >+ int operator()(int a, int b) { return a - b; } >+}; >+ >+struct EphemeralFunctor { >+ EphemeralFunctor() {} >+ EphemeralFunctor(const EphemeralFunctor&) {} >+ EphemeralFunctor(EphemeralFunctor&&) {} >+ int operator()(int a, int b) && { return a - b; } >+}; >+ >+struct OverloadedFunctor { >+ OverloadedFunctor() {} >+ OverloadedFunctor(const OverloadedFunctor&) {} >+ OverloadedFunctor(OverloadedFunctor&&) {} >+ template <typename... Args> >+ std::string operator()(const Args&... args) & { >+ return absl::StrCat("&", args...); >+ } >+ template <typename... Args> >+ std::string operator()(const Args&... args) const& { >+ return absl::StrCat("const&", args...); >+ } >+ template <typename... Args> >+ std::string operator()(const Args&... args) && { >+ return absl::StrCat("&&", args...); >+ } >+}; >+ >+struct Class { >+ int Method(int a, int b) { return a - b; } >+ int ConstMethod(int a, int b) const { return a - b; } >+ >+ int member; >+}; >+ >+struct FlipFlop { >+ int ConstMethod() const { return member; } >+ FlipFlop operator*() const { return {-member}; } >+ >+ int member; >+}; >+ >+TEST(ApplyTest, Function) { >+ EXPECT_EQ(1, absl::apply(Function, std::make_tuple(3, 2))); >+ EXPECT_EQ(1, absl::apply(&Function, std::make_tuple(3, 2))); >+} >+ >+TEST(ApplyTest, NonCopyableArgument) { >+ EXPECT_EQ(42, absl::apply(Sink, std::make_tuple(absl::make_unique<int>(42)))); >+} >+ >+TEST(ApplyTest, NonCopyableResult) { >+ EXPECT_THAT(absl::apply(Factory, std::make_tuple(42)), >+ ::testing::Pointee(42)); >+} >+ >+TEST(ApplyTest, VoidResult) { absl::apply(NoOp, std::tuple<>()); } >+ >+TEST(ApplyTest, ConstFunctor) { >+ EXPECT_EQ(1, absl::apply(ConstFunctor(), std::make_tuple(3, 2))); >+} >+ >+TEST(ApplyTest, MutableFunctor) { >+ MutableFunctor f; >+ EXPECT_EQ(1, absl::apply(f, std::make_tuple(3, 2))); >+ EXPECT_EQ(1, absl::apply(MutableFunctor(), std::make_tuple(3, 2))); >+} >+TEST(ApplyTest, EphemeralFunctor) { >+ EphemeralFunctor f; >+ EXPECT_EQ(1, absl::apply(std::move(f), std::make_tuple(3, 2))); >+ EXPECT_EQ(1, absl::apply(EphemeralFunctor(), std::make_tuple(3, 2))); >+} >+TEST(ApplyTest, OverloadedFunctor) { >+ OverloadedFunctor f; >+ const OverloadedFunctor& cf = f; >+ >+ EXPECT_EQ("&", absl::apply(f, std::tuple<>{})); >+ EXPECT_EQ("& 42", absl::apply(f, std::make_tuple(" 42"))); >+ >+ EXPECT_EQ("const&", absl::apply(cf, std::tuple<>{})); >+ EXPECT_EQ("const& 42", absl::apply(cf, std::make_tuple(" 42"))); >+ >+ EXPECT_EQ("&&", absl::apply(std::move(f), std::tuple<>{})); >+ OverloadedFunctor f2; >+ EXPECT_EQ("&& 42", absl::apply(std::move(f2), std::make_tuple(" 42"))); >+} >+ >+TEST(ApplyTest, ReferenceWrapper) { >+ ConstFunctor cf; >+ MutableFunctor mf; >+ EXPECT_EQ(1, absl::apply(std::cref(cf), std::make_tuple(3, 2))); >+ EXPECT_EQ(1, absl::apply(std::ref(cf), std::make_tuple(3, 2))); >+ EXPECT_EQ(1, absl::apply(std::ref(mf), std::make_tuple(3, 2))); >+} >+ >+TEST(ApplyTest, MemberFunction) { >+ std::unique_ptr<Class> p(new Class); >+ std::unique_ptr<const Class> cp(new Class); >+ EXPECT_EQ( >+ 1, absl::apply(&Class::Method, >+ std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::Method, >+ std::tuple<Class*, int, int>(p.get(), 3, 2))); >+ EXPECT_EQ( >+ 1, absl::apply(&Class::Method, std::tuple<Class&, int, int>(*p, 3, 2))); >+ >+ EXPECT_EQ( >+ 1, absl::apply(&Class::ConstMethod, >+ std::tuple<std::unique_ptr<Class>&, int, int>(p, 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::tuple<Class*, int, int>(p.get(), 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::tuple<Class&, int, int>(*p, 3, 2))); >+ >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::tuple<std::unique_ptr<const Class>&, int, int>( >+ cp, 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::tuple<const Class*, int, int>(cp.get(), 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::tuple<const Class&, int, int>(*cp, 3, 2))); >+ >+ EXPECT_EQ(1, absl::apply(&Class::Method, >+ std::make_tuple(absl::make_unique<Class>(), 3, 2))); >+ EXPECT_EQ(1, absl::apply(&Class::ConstMethod, >+ std::make_tuple(absl::make_unique<Class>(), 3, 2))); >+ EXPECT_EQ( >+ 1, absl::apply(&Class::ConstMethod, >+ std::make_tuple(absl::make_unique<const Class>(), 3, 2))); >+} >+ >+TEST(ApplyTest, DataMember) { >+ std::unique_ptr<Class> p(new Class{42}); >+ std::unique_ptr<const Class> cp(new Class{42}); >+ EXPECT_EQ( >+ 42, absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p))); >+ EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class&>(*p))); >+ EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<Class*>(p.get()))); >+ >+ absl::apply(&Class::member, std::tuple<std::unique_ptr<Class>&>(p)) = 42; >+ absl::apply(&Class::member, std::tuple<Class*>(p.get())) = 42; >+ absl::apply(&Class::member, std::tuple<Class&>(*p)) = 42; >+ >+ EXPECT_EQ(42, absl::apply(&Class::member, >+ std::tuple<std::unique_ptr<const Class>&>(cp))); >+ EXPECT_EQ(42, absl::apply(&Class::member, std::tuple<const Class&>(*cp))); >+ EXPECT_EQ(42, >+ absl::apply(&Class::member, std::tuple<const Class*>(cp.get()))); >+} >+ >+TEST(ApplyTest, FlipFlop) { >+ FlipFlop obj = {42}; >+ // This call could resolve to (obj.*&FlipFlop::ConstMethod)() or >+ // ((*obj).*&FlipFlop::ConstMethod)(). We verify that it's the former. >+ EXPECT_EQ(42, absl::apply(&FlipFlop::ConstMethod, std::make_tuple(obj))); >+ EXPECT_EQ(42, absl::apply(&FlipFlop::member, std::make_tuple(obj))); >+} >+ >+TEST(ExchangeTest, MoveOnly) { >+ auto a = Factory(1); >+ EXPECT_EQ(1, *a); >+ auto b = absl::exchange(a, Factory(2)); >+ EXPECT_EQ(2, *a); >+ EXPECT_EQ(1, *b); >+} >+ >+} // namespace >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/rename_dynamic_annotations.sh b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/rename_dynamic_annotations.sh >new file mode 100755 >index 00000000000..b39017f9585 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/abseil-cpp/rename_dynamic_annotations.sh >@@ -0,0 +1,127 @@ >+#!/bin/bash >+ >+# This script renames all the functions and the macros defined in >+# absl/base/dynamic_annotations.{h,cc}. >+# >+# Chromium's dynamic_annotations live in //base/third_party/dynamic_annotations >+# and the are in conflict with Abseil's dynamic_annotations (ODR violations and >+# macro clashing). >+# In order to avoid problems in Chromium, this copy of Abseil has its own >+# dynamic_annotations renamed. >+ >+for w in \ >+ AnnotateBarrierDestroy \ >+ AnnotateBarrierInit \ >+ AnnotateBarrierWaitAfter \ >+ AnnotateBarrierWaitBefore \ >+ AnnotateBenignRace \ >+ AnnotateBenignRaceSized \ >+ AnnotateCondVarSignal \ >+ AnnotateCondVarSignalAll \ >+ AnnotateCondVarWait \ >+ AnnotateEnableRaceDetection \ >+ AnnotateExpectRace \ >+ AnnotateFlushExpectedRaces \ >+ AnnotateFlushState \ >+ AnnotateHappensAfter \ >+ AnnotateHappensBefore \ >+ AnnotateIgnoreReadsBegin \ >+ AnnotateIgnoreReadsEnd \ >+ AnnotateIgnoreSyncBegin \ >+ AnnotateIgnoreSyncEnd \ >+ AnnotateIgnoreWritesBegin \ >+ AnnotateIgnoreWritesEnd \ >+ AnnotateMemoryIsInitialized \ >+ AnnotateMemoryIsUninitialized \ >+ AnnotateMutexIsNotPHB \ >+ AnnotateMutexIsUsedAsCondVar \ >+ AnnotateNewMemory \ >+ AnnotateNoOp \ >+ AnnotatePCQCreate \ >+ AnnotatePCQDestroy \ >+ AnnotatePCQGet \ >+ AnnotatePCQPut \ >+ AnnotatePublishMemoryRange \ >+ AnnotateRWLockAcquired \ >+ AnnotateRWLockCreate \ >+ AnnotateRWLockCreateStatic \ >+ AnnotateRWLockDestroy \ >+ AnnotateRWLockReleased \ >+ AnnotateThreadName \ >+ AnnotateTraceMemory \ >+ AnnotateUnpublishMemoryRange \ >+ GetRunningOnValgrind \ >+ RunningOnValgrind \ >+ StaticAnnotateIgnoreReadsBegin \ >+ StaticAnnotateIgnoreReadsEnd \ >+ StaticAnnotateIgnoreWritesBegin \ >+ StaticAnnotateIgnoreWritesEnd \ >+ ValgrindSlowdown \ >+; do >+ find absl/ -type f -exec sed -i "s/\b$w\b/Absl$w/g" {} \; >+done >+ >+for w in \ >+ ADDRESS_SANITIZER_REDZONE \ >+ ANNOTALYSIS_ENABLED \ >+ ANNOTATE_BARRIER_DESTROY \ >+ ANNOTATE_BARRIER_INIT \ >+ ANNOTATE_BARRIER_WAIT_AFTER \ >+ ANNOTATE_BARRIER_WAIT_BEFORE \ >+ ANNOTATE_BENIGN_RACE \ >+ ANNOTATE_BENIGN_RACE_SIZED \ >+ ANNOTATE_BENIGN_RACE_STATIC \ >+ ANNOTATE_CONDVAR_LOCK_WAIT \ >+ ANNOTATE_CONDVAR_SIGNAL \ >+ ANNOTATE_CONDVAR_SIGNAL_ALL \ >+ ANNOTATE_CONDVAR_WAIT \ >+ ANNOTATE_CONTIGUOUS_CONTAINER \ >+ ANNOTATE_ENABLE_RACE_DETECTION \ >+ ANNOTATE_EXPECT_RACE \ >+ ANNOTATE_FLUSH_EXPECTED_RACES \ >+ ANNOTATE_FLUSH_STATE \ >+ ANNOTATE_HAPPENS_AFTER \ >+ ANNOTATE_HAPPENS_BEFORE \ >+ ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN ANNOTATE_IGNORE_READS_AND_WRITES_END \ >+ ANNOTATE_IGNORE_READS_BEGIN \ >+ ANNOTATE_IGNORE_READS_END \ >+ ANNOTATE_IGNORE_SYNC_BEGIN \ >+ ANNOTATE_IGNORE_SYNC_END \ >+ ANNOTATE_IGNORE_WRITES_BEGIN \ >+ ANNOTATE_IGNORE_WRITES_END \ >+ ANNOTATE_MEMORY_IS_INITIALIZED \ >+ ANNOTATE_MEMORY_IS_UNINITIALIZED \ >+ ANNOTATE_MUTEX_IS_USED_AS_CONDVAR \ >+ ANNOTATE_NEW_MEMORY \ >+ ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX \ >+ ANNOTATE_NO_OP \ >+ ANNOTATE_PCQ_CREATE ANNOTATE_PCQ_DESTROY \ >+ ANNOTATE_PCQ_GET ANNOTATE_PCQ_PUT \ >+ ANNOTATE_PUBLISH_MEMORY_RANGE \ >+ ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX \ >+ ANNOTATE_RWLOCK_ACQUIRED \ >+ ANNOTATE_RWLOCK_CREATE \ >+ ANNOTATE_RWLOCK_CREATE_STATIC \ >+ ANNOTATE_RWLOCK_DESTROY \ >+ ANNOTATE_RWLOCK_RELEASED \ >+ ANNOTATE_SWAP_MEMORY_RANGE \ >+ ANNOTATE_THREAD_NAME \ >+ ANNOTATE_TRACE_MEMORY \ >+ ANNOTATE_UNPROTECTED_READ \ >+ ANNOTATE_UNPUBLISH_MEMORY_RANGE \ >+ ANNOTATIONS_ENABLED \ >+ ATTRIBUTE_IGNORE_READS_BEGIN \ >+ ATTRIBUTE_IGNORE_READS_END \ >+ DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK \ >+ DYNAMIC_ANNOTATIONS_ENABLED \ >+ DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL \ >+ DYNAMIC_ANNOTATIONS_GLUE \ >+ DYNAMIC_ANNOTATIONS_GLUE0 \ >+ DYNAMIC_ANNOTATIONS_IMPL \ >+ DYNAMIC_ANNOTATIONS_NAME \ >+ DYNAMIC_ANNOTATIONS_PREFIX \ >+ DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND \ >+ DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK \ >+; do >+ find absl/ -type f -exec sed -i "s/\b$w\b/ABSL_$w/g" {} \; >+done >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/.gn b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/.gn >index 015d0f0e5e8..26a4a62d199 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/.gn >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/.gn >@@ -6,6 +6,8 @@ > # in the file PATENTS. All contributing project authors may > # be found in the AUTHORS file in the root of the source tree. > >+import("//build/dotfile_settings.gni") >+ > # The location of the build configuration file. > buildconfig = "//build/config/BUILDCONFIG.gn" > >@@ -23,29 +25,8 @@ check_targets = [ "//libyuv/*" ] > # These are the list of GN files that run exec_script. This whitelist exists > # to force additional review for new uses of exec_script, which is strongly > # discouraged except for gypi_to_gn calls. >-exec_script_whitelist = [ >- "//build/config/android/BUILD.gn", >- "//build/config/android/config.gni", >- "//build/config/android/internal_rules.gni", >- "//build/config/android/rules.gni", >- "//build/config/BUILD.gn", >- "//build/config/compiler/BUILD.gn", >- "//build/config/gcc/gcc_version.gni", >- "//build/config/ios/ios_sdk.gni", >- "//build/config/linux/BUILD.gn", >- "//build/config/linux/pkg_config.gni", >- "//build/config/mac/mac_sdk.gni", >- "//build/config/posix/BUILD.gn", >- "//build/config/sysroot.gni", >- "//build/config/win/BUILD.gn", >- "//build/config/win/visual_studio_version.gni", >- "//build/gn_helpers.py", >- "//build/gypi_to_gn.py", >- "//build/toolchain/concurrent_links.gni", >- "//build/toolchain/gcc_toolchain.gni", >- "//build/toolchain/mac/BUILD.gn", >- "//build/toolchain/win/BUILD.gn", >-] >+exec_script_whitelist = build_dotfile_settings.exec_script_whitelist + >+ [ "//build_overrides/build.gni" ] > > default_args = { > mac_sdk_min = "10.11" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.bp b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.bp >index a3d8d834ac7..7d95a7865ab 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.bp >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.bp >@@ -24,14 +24,12 @@ cc_library { > "source/rotate_any.cc", > "source/rotate_argb.cc", > "source/rotate_common.cc", >- "source/rotate_dspr2.cc", > "source/rotate_gcc.cc", > "source/rotate_msa.cc", > "source/rotate_neon.cc", > "source/rotate_neon64.cc", > "source/row_any.cc", > "source/row_common.cc", >- "source/row_dspr2.cc", > "source/row_gcc.cc", > "source/row_msa.cc", > "source/row_neon.cc", >@@ -40,7 +38,6 @@ cc_library { > "source/scale_any.cc", > "source/scale_argb.cc", > "source/scale_common.cc", >- "source/scale_dspr2.cc", > "source/scale_gcc.cc", > "source/scale_msa.cc", > "source/scale_neon.cc", >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.mk b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.mk >index 854020610ea..dbc6cad37ab 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.mk >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/Android.mk >@@ -24,14 +24,12 @@ LOCAL_SRC_FILES := \ > source/rotate_any.cc \ > source/rotate_argb.cc \ > source/rotate_common.cc \ >- source/rotate_dspr2.cc \ > source/rotate_gcc.cc \ > source/rotate_msa.cc \ > source/rotate_neon.cc \ > source/rotate_neon64.cc \ > source/row_any.cc \ > source/row_common.cc \ >- source/row_dspr2.cc \ > source/row_gcc.cc \ > source/row_msa.cc \ > source/row_neon.cc \ >@@ -40,7 +38,6 @@ LOCAL_SRC_FILES := \ > source/scale_any.cc \ > source/scale_argb.cc \ > source/scale_common.cc \ >- source/scale_dspr2.cc \ > source/scale_gcc.cc \ > source/scale_msa.cc \ > source/scale_neon.cc \ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/BUILD.gn >index 9badf08c846..03ce499e6d9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/BUILD.gn >@@ -12,6 +12,11 @@ import("//testing/test.gni") > declare_args() { > # Set to false to disable building with gflags. > libyuv_use_gflags = true >+ >+ # When building a shared library using a target in WebRTC or >+ # Chromium projects that depends on libyuv, setting this flag >+ # to true makes libyuv symbols visible inside that library. >+ libyuv_symbols_visible = false > } > > config("libyuv_config") { >@@ -42,7 +47,8 @@ group("default") { > } > > group("libyuv") { >- public_configs = [ ":libyuv_config" ] >+ all_dependent_configs = [ ":libyuv_config" ] >+ deps = [] > > if (is_win && target_cpu == "x64") { > # Compile with clang in order to get inline assembly >@@ -55,13 +61,19 @@ group("libyuv") { > ] > } > >+ if (libyuv_use_neon) { >+ deps += [ ":libyuv_neon" ] >+ } >+ >+ if (libyuv_use_msa) { >+ deps += [ ":libyuv_msa" ] >+ } >+ > if (!is_ios) { > # Make sure that clients of libyuv link with libjpeg. This can't go in > # libyuv_internal because in Windows x64 builds that will generate a clang > # build of libjpeg, and we don't want two copies. >- deps = [ >- "//third_party:jpeg", >- ] >+ deps += [ "//third_party:jpeg" ] > } > } > >@@ -110,19 +122,16 @@ static_library("libyuv_internal") { > "source/rotate_any.cc", > "source/rotate_argb.cc", > "source/rotate_common.cc", >- "source/rotate_dspr2.cc", > "source/rotate_gcc.cc", > "source/rotate_win.cc", > "source/row_any.cc", > "source/row_common.cc", >- "source/row_dspr2.cc", > "source/row_gcc.cc", > "source/row_win.cc", > "source/scale.cc", > "source/scale_any.cc", > "source/scale_argb.cc", > "source/scale_common.cc", >- "source/scale_dspr2.cc", > "source/scale_gcc.cc", > "source/scale_win.cc", > "source/video_common.cc", >@@ -132,6 +141,11 @@ static_library("libyuv_internal") { > defines = [] > deps = [] > >+ if (libyuv_symbols_visible) { >+ configs -= [ "//build/config/gcc:symbol_visibility_hidden" ] >+ configs += [ "//build/config/gcc:symbol_visibility_default" ] >+ } >+ > if (!is_ios) { > defines += [ "HAVE_JPEG" ] > >@@ -140,14 +154,6 @@ static_library("libyuv_internal") { > deps += [ "//third_party:jpeg_includes" ] > } > >- if (libyuv_use_neon) { >- deps += [ ":libyuv_neon" ] >- } >- >- if (libyuv_use_msa) { >- deps += [ ":libyuv_msa" ] >- } >- > # Always enable optimization for Release and NaCl builds (to workaround > # crbug.com/538243). > if (!is_debug || is_nacl) { >@@ -167,6 +173,7 @@ static_library("libyuv_internal") { > ] > } > } >+ > if (libyuv_use_neon) { > static_library("libyuv_neon") { > sources = [ >@@ -181,6 +188,10 @@ if (libyuv_use_neon) { > "source/scale_neon64.cc", > ] > >+ deps = [ >+ ":libyuv_internal", >+ ] >+ > public_configs = [ ":libyuv_config" ] > > # Always enable optimization for Release and NaCl builds (to workaround >@@ -210,6 +221,10 @@ if (libyuv_use_msa) { > "source/scale_msa.cc", > ] > >+ deps = [ >+ ":libyuv_internal", >+ ] >+ > public_configs = [ ":libyuv_config" ] > } > } >@@ -302,7 +317,6 @@ if (libyuv_include_tests) { > # Enable the following 3 macros to turn off assembly for specified CPU. > # "LIBYUV_DISABLE_X86", > # "LIBYUV_DISABLE_NEON", >- # "LIBYUV_DISABLE_DSPR2", > # Enable the following macro to build libyuv as a shared library (dll). > # "LIBYUV_USING_SHARED_LIBRARY" > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/DEPS b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/DEPS >index fdb133c7ac1..266327470b7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/DEPS >@@ -1,38 +1,38 @@ > vars = { > 'chromium_git': 'https://chromium.googlesource.com', >- 'chromium_revision': 'ff3b31782d552b03104a6d831c7530605b52b13f', >- 'swarming_revision': '5e8001d9a710121ce7a68efd0804430a34b4f9e4', >+ 'chromium_revision': '80f0c5570649c35a869429b2ab8c381a0a7246cb', >+ 'swarming_revision': '88229872dd17e71658fe96763feaa77915d8cbd6', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling lss > # and whatever else without interference from each other. >- 'lss_revision': '63f24c8221a229f677d26ebe8f3d1528a9d787ac', >+ 'lss_revision': 'e6527b0cd469e3ff5764785dadcb39bf7d787154', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling catapult > # and whatever else without interference from each other. >- 'catapult_revision': 'aa736cc76ee5e35215abcfb83a8c354f12d0c684', >+ 'catapult_revision': 'e7298f36f7912f2caa122086cfbe71734d04b73f', > } > > deps = { > 'src/build': >- Var('chromium_git') + '/chromium/src/build' + '@' + '156ba982d749902e3403c242e23ded87fd316494', >+ Var('chromium_git') + '/chromium/src/build' + '@' + '39738e75b27f39d4c0030a0b11d5d2ddd34715f7', > 'src/buildtools': >- Var('chromium_git') + '/chromium/buildtools.git' + '@' + 'f6d165d9d842ddd29056c127a5f3a3c5d8e0d2e3', >+ Var('chromium_git') + '/chromium/buildtools.git' + '@' + 'a09e064635a49f08e585e3b173d5fbc3dd3f485e', > 'src/testing': >- Var('chromium_git') + '/chromium/src/testing' + '@' + 'cc96d3d66b5b9613fd0fe055509cfec5eb54b19c', >+ Var('chromium_git') + '/chromium/src/testing' + '@' + '5f7e36cad6434fd3d65674af96653a23ecc9f694', > 'src/third_party': >- Var('chromium_git') + '/chromium/src/third_party' + '@' + '72c52c224cdd3c377f7caff8ffed0f5749e79549', >+ Var('chromium_git') + '/chromium/src/third_party' + '@' + '2c0ced3ddbf84ce1c0759b277d9538da42f23650', > 'src/third_party/catapult': >- Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + Var('catapult_revision'), >+ Var('chromium_git') + '/catapult.git' + '@' + Var('catapult_revision'), > 'src/third_party/colorama/src': > Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', > 'src/third_party/googletest/src': >- Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '7f8fefabedf2965980585be8c2bff97458f28e0b', >+ Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '0062e4869f07a3ef235703ddf63af604b712446c', > 'src/third_party/libjpeg_turbo': > Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'a1750dbc79a8792dde3d3f7d7d8ac28ba01ac9dd', > 'src/third_party/yasm/source/patched-yasm': > Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc', > 'src/tools': >- Var('chromium_git') + '/chromium/src/tools' + '@' + 'eceb2c420b20350a2d2ba261953109280968647a', >+ Var('chromium_git') + '/chromium/src/tools' + '@' + '6202b67fc46a9984097caf237e12e3b8f7a9f7da', > 'src/tools/gyp': > Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb', > 'src/tools/swarming_client': >@@ -45,45 +45,84 @@ deps = { > Var('chromium_git') + '/external/github.com/gflags/gflags' + '@' + '03bebcb065c83beff83d50ae025a55a4bf94dfca', > 'src/third_party/gtest-parallel': > Var('chromium_git') + '/external/webrtc/deps/third_party/gtest-parallel' + '@' + '1dad0e9f6d82ff994130b529d7d814b40eb32b0e', >-} > >-deps_os = { >- 'android': { >- 'src/base': >- Var('chromium_git') + '/chromium/src/base' + '@' + '9b543d487c7c38be191c6180001ff9ce186ae326', >- 'src/third_party/android_tools': >- Var('chromium_git') + '/android_tools.git' + '@' + 'aadb2fed04af8606545b0afe4e3060bc1a15fad7', >- 'src/third_party/ced/src': >- Var('chromium_git') + '/external/github.com/google/compact_enc_det.git' + '@' + '94c367a1fe3a13207f4b22604fcfd1d9f9ddf6d9', >- 'src/third_party/icu': >- Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '08cb956852a5ccdba7f9c941728bb833529ba3c6', >- 'src/third_party/jsr-305/src': >- Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', >- 'src/third_party/junit/src': >- Var('chromium_git') + '/external/junit.git' + '@' + '64155f8a9babcfcf4263cf4d08253a1556e75481', >- 'src/third_party/lss': >- Var('chromium_git') + '/linux-syscall-support.git' + '@' + Var('lss_revision'), >- 'src/third_party/mockito/src': >- Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'de83ad4598ad4cf5ea53c69a8a8053780b04b850', >- 'src/third_party/requests/src': >- Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', >- 'src/third_party/robolectric/robolectric': >- Var('chromium_git') + '/external/robolectric.git' + '@' + 'b02c65cc6d7465f58f0de48a39914aa905692afa', >- 'src/third_party/ub-uiautomator/lib': >- Var('chromium_git') + '/chromium/third_party/ub-uiautomator.git' + '@' + '00270549ce3161ae72ceb24712618ea28b4f9434', >- }, >- 'ios': { >- 'src/ios': >- Var('chromium_git') + '/chromium/src/ios' + '@' + '39c4b2fcf73f5b1e82af3b9c57267c17217d6a30', >- }, >- 'unix': { >- 'src/third_party/lss': >- Var('chromium_git') + '/linux-syscall-support.git' + '@' + Var('lss_revision'), >- }, >- 'win': { >- # Dependencies used by libjpeg-turbo >- 'src/third_party/yasm/binaries': >- Var('chromium_git') + '/chromium/deps/yasm/binaries.git' + '@' + '52f9b3f4b0aa06da24ef8b123058bb61ee468881', >+ 'src/third_party/lss': { >+ 'url': Var('chromium_git') + '/linux-syscall-support.git' + '@' + Var('lss_revision'), >+ 'condition': 'checkout_android or checkout_linux', >+ }, >+ >+ # Android deps: >+ 'src/third_party/auto/src': { >+ 'url': Var('chromium_git') + '/external/github.com/google/auto.git' + '@' + '8a81a858ae7b78a1aef71ac3905fade0bbd64e82', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/auto/src': { >+ 'url': Var('chromium_git') + '/external/github.com/google/auto.git' + '@' + '8a81a858ae7b78a1aef71ac3905fade0bbd64e82', >+ 'condition': 'checkout_android', >+ }, >+ 'src/base': { >+ 'url': Var('chromium_git') + '/chromium/src/base' + '@' + 'ac3d2b81181b085a9952cb83dba748420eefe691', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/android_ndk': { >+ 'url': Var('chromium_git') + '/android_ndk.git' + '@' + 'e951c37287c7d8cd915bf8d4149fd4a06d808b55', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/android_tools': { >+ 'url': Var('chromium_git') + '/android_tools.git' + '@' + '9a70d48fcdd68cd0e7e968f342bd767ee6323bd1', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/ced/src': { >+ 'url': Var('chromium_git') + '/external/github.com/google/compact_enc_det.git' + '@' + '94c367a1fe3a13207f4b22604fcfd1d9f9ddf6d9', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/errorprone/lib': { >+ 'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + 'ecc57c2b00627667874744b9ad8efe10734d97a8', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/findbugs': { >+ 'url': Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '4275d9ac8610db6b1bc9a5e887f97e41b33fac67', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/icu': { >+ 'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'd888fd2a1be890f4d35e43f68d6d79f42519a357', >+ }, >+ 'src/third_party/jsr-305/src': { >+ 'url': Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/junit/src': { >+ 'url': Var('chromium_git') + '/external/junit.git' + '@' + '64155f8a9babcfcf4263cf4d08253a1556e75481', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/mockito/src': { >+ 'url': Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'de83ad4598ad4cf5ea53c69a8a8053780b04b850', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/requests/src': { >+ 'url': Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/robolectric/robolectric': { >+ 'url': Var('chromium_git') + '/external/robolectric.git' + '@' + '7e067f1112e1502caa742f7be72d37b5678d3403', >+ 'condition': 'checkout_android', >+ }, >+ 'src/third_party/ub-uiautomator/lib': { >+ 'url': Var('chromium_git') + '/chromium/third_party/ub-uiautomator.git' + '@' + '00270549ce3161ae72ceb24712618ea28b4f9434', >+ 'condition': 'checkout_android', >+ }, >+ >+ # iOS deps: >+ 'src/ios': { >+ 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '299ef76e844a74a1f2f4ce7f06d101861fb49aba', >+ 'condition': 'checkout_ios' >+ }, >+ >+ # Win deps: >+ # Dependencies used by libjpeg-turbo >+ 'src/third_party/yasm/binaries': { >+ 'url': Var('chromium_git') + '/chromium/deps/yasm/binaries.git' + '@' + '52f9b3f4b0aa06da24ef8b123058bb61ee468881', >+ 'condition': 'checkout_win', > }, > } > >@@ -116,200 +155,41 @@ hooks = [ > 'src', > ], > }, >- # Android dependencies. Many are downloaded using Google Storage these days. >- # They're copied from https://cs.chromium.org/chromium/src/DEPS for all >- # such dependencies we share with Chromium. >- { >- # This downloads SDK extras and puts them in the >- # third_party/android_tools/sdk/extras directory. >- 'name': 'sdkextras', >- 'pattern': '.', >- # When adding a new sdk extras package to download, add the package >- # directory and zip file to .gitignore in third_party/android_tools. >- 'action': ['python', >- 'src/build/android/play_services/update.py', >- 'download' >- ], >- }, >- { >- 'name': 'intellij', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-intellij', >- '-l', 'third_party/intellij' >- ], >- }, >- { >- 'name': 'javax_inject', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-javax-inject', >- '-l', 'third_party/javax_inject' >- ], >- }, >- { >- 'name': 'hamcrest', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-hamcrest', >- '-l', 'third_party/hamcrest' >- ], >- }, >- { >- 'name': 'guava', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-guava', >- '-l', 'third_party/guava' >- ], >- }, >- { >- 'name': 'android_support_test_runner', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-android-support-test-runner', >- '-l', 'third_party/android_support_test_runner' >- ], >- }, >- { >- 'name': 'byte_buddy', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-byte-buddy', >- '-l', 'third_party/byte_buddy' >- ], >- }, >+ # Downloads the current stable linux sysroot to build/linux/ if needed. > { >- 'name': 'espresso', >+ 'name': 'sysroot_arm', > 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-espresso', >- '-l', 'third_party/espresso' >- ], >- }, >- { >- 'name': 'robolectric_libs', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-robolectric', >- '-l', 'third_party/robolectric' >- ], >- }, >- { >- 'name': 'apache_velocity', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-apache-velocity', >- '-l', 'third_party/apache_velocity' >- ], >- }, >- { >- 'name': 'ow2_asm', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-ow2-asm', >- '-l', 'third_party/ow2_asm' >- ], >- }, >- { >- 'name': 'desugar', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-android-tools/bazel/desugar', >- '-l', 'third_party/bazel/desugar' >- ], >- }, >- { >- 'name': 'icu4j', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-icu4j', >- '-l', 'third_party/icu4j' >- ], >- }, >- { >- 'name': 'accessibility_test_framework', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-accessibility-test-framework', >- '-l', 'third_party/accessibility_test_framework' >- ], >- }, >- { >- 'name': 'bouncycastle', >- 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-bouncycastle', >- '-l', 'third_party/bouncycastle' >- ], >+ 'condition': 'checkout_linux and checkout_arm', >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=arm'], > }, > { >- 'name': 'sqlite4java', >+ 'name': 'sysroot_arm64', > 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-sqlite4java', >- '-l', 'third_party/sqlite4java' >- ], >+ 'condition': 'checkout_linux and checkout_arm64', >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=arm64'], > }, > { >- 'name': 'xstream', >+ 'name': 'sysroot_x86', > 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-robolectric', >- '-l', 'third_party/xstream' >- ], >+ 'condition': 'checkout_linux and (checkout_x86 or checkout_x64)', >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=x86'], > }, > { >- 'name': 'objenesis', >+ 'name': 'sysroot_mips', > 'pattern': '.', >- 'action': ['python', >- 'src/build/android/update_deps/update_third_party_deps.py', >- 'download', >- '-b', 'chromium-objenesis', >- '-l', 'third_party/objenesis' >- ], >+ 'condition': 'checkout_linux and checkout_mips', >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=mips'], > }, > { >- # Downloads the current stable linux sysroot to build/linux/ if needed. >- # This sysroot updates at about the same rate that the chrome build deps >- # change. This script is a no-op except for linux users who are doing >- # official chrome builds or cross compiling. >- 'name': 'sysroot', >+ 'name': 'sysroot_x64', > 'pattern': '.', >+ 'condition': 'checkout_linux and checkout_x64', > 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >- '--running-as-hook'], >+ '--arch=x64'], > }, > { > # Update the Windows toolchain if necessary. >@@ -444,6 +324,30 @@ hooks = [ > '-d', 'src/tools/luci-go/linux64', > ], > }, >+ { >+ 'name': 'Android CIPD Ensure', >+ 'pattern': '.', >+ 'condition': 'checkout_android', >+ 'action': ['src/build/cipd/cipd_wrapper.py', >+ '--chromium-root', 'src', >+ '--ensure-file', 'src/build/cipd/android/android.ensure', >+ ], >+ }, >+ # Android dependencies. Many are downloaded using Google Storage these days. >+ # They're copied from https://cs.chromium.org/chromium/src/DEPS for all >+ # such dependencies we share with Chromium. >+ { >+ # This downloads SDK extras and puts them in the >+ # third_party/android_tools/sdk/extras directory. >+ 'name': 'sdkextras', >+ 'pattern': '.', >+ # When adding a new sdk extras package to download, add the package >+ # directory and zip file to .gitignore in third_party/android_tools. >+ 'action': ['python', >+ 'src/build/android/play_services/update.py', >+ 'download' >+ ], >+ }, > ] > > recursedeps = [ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.chromium b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.chromium >index 88c069734ac..c25373e23ce 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.chromium >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.chromium >@@ -1,6 +1,6 @@ > Name: libyuv > URL: http://code.google.com/p/libyuv/ >-Version: 1678 >+Version: 1703 > License: BSD > License File: LICENSE > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.md b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.md >index b59b71c5d2b..7b6619220b8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.md >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/README.md >@@ -1,12 +1,12 @@ > **libyuv** is an open source project that includes YUV scaling and conversion functionality. > > * Scale YUV to prepare content for compression, with point, bilinear or box filter. >-* Convert to YUV from webcam formats. >-* Convert from YUV to formats for rendering/effects. >+* Convert to YUV from webcam formats for compression. >+* Convert to RGB formats for rendering/effects. > * Rotate by 90/180/270 degrees to adjust for mobile devices in portrait mode. >-* Optimized for SSE2/SSSE3/AVX2 on x86/x64. >+* Optimized for SSSE3/AVX2 on x86/x64. > * Optimized for Neon on Arm. >-* Optimized for DSP R2 on Mips. >+* Optimized for MSA on Mips. > > ### Development > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/deprecated_builds.md b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/deprecated_builds.md >index d54a0282c15..29e0bf9bc30 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/deprecated_builds.md >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/deprecated_builds.md >@@ -165,11 +165,11 @@ mipsel > > arm32 disassembly: > >- third_party/android_tools/ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objdump -d out/Release/obj/source/libyuv.row_neon.o >+ third_party/android_ndk/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objdump -d out/Release/obj/source/libyuv.row_neon.o > > arm64 disassembly: > >- third_party/android_tools/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d out/Release/obj/source/libyuv.row_neon64.o >+ third_party/android_ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d out/Release/obj/source/libyuv.row_neon64.o > > Running tests: > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/environment_variables.md b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/environment_variables.md >index 9071c54de23..c28d83e7dc1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/environment_variables.md >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/environment_variables.md >@@ -17,7 +17,7 @@ By default the cpu is detected and the most advanced form of SIMD is used. But > LIBYUV_DISABLE_AVX512BW > LIBYUV_DISABLE_ERMS > LIBYUV_DISABLE_FMA3 >- LIBYUV_DISABLE_DSPR2 >+ LIBYUV_DISABLE_MSA > LIBYUV_DISABLE_NEON > > # Test Width/Height/Repeat >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/formats.md b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/formats.md >index 2b75d31ac75..f78f57bb4c4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/formats.md >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/formats.md >@@ -35,9 +35,8 @@ This is how OSX formats map to libyuv > # FOURCC (Four Charactacter Code) List > > The following is extracted from video_common.h as a complete list of formats supported by libyuv. >- > enum FourCC { >- // 8 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. >+ // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. > FOURCC_I420 = FOURCC('I', '4', '2', '0'), > FOURCC_I422 = FOURCC('I', '4', '2', '2'), > FOURCC_I444 = FOURCC('I', '4', '4', '4'), >@@ -46,37 +45,35 @@ The following is extracted from video_common.h as a complete list of formats sup > FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), > FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), > FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), >+ FOURCC_H010 = FOURCC('H', '0', '1', '0'), // unofficial fourcc. 10 bit lsb > >- // 1 Secondary YUV formats: row biplanar. >+ // 1 Secondary YUV format: row biplanar. > FOURCC_M420 = FOURCC('M', '4', '2', '0'), > >- // 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp. >+ // 11 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc > FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), > FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), > FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), >+ FOURCC_AR30 = FOURCC('A', 'R', '3', '0'), // 10 bit per channel. 2101010. >+ FOURCC_AB30 = FOURCC('A', 'B', '3', '0'), // ABGR version of 10 bit > FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), >- FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), >+ FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), > FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), > FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // rgb565 LE. > FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 LE. > FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 LE. > >- // 4 Secondary RGB formats: 4 Bayer Patterns. >- FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), >- FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), >- FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), >- FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), >- > // 1 Primary Compressed YUV format. > FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), > >- // 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. >+ // 7 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. > FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), > FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), > FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), > FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420. > FOURCC_J420 = FOURCC('J', '4', '2', '0'), >- FOURCC_J400 = FOURCC('J', '4', '0', '0'), >+ FOURCC_J400 = FOURCC('J', '4', '0', '0'), // unofficial fourcc >+ FOURCC_H420 = FOURCC('H', '4', '2', '0'), // unofficial fourcc > > // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc. > FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420. >@@ -97,9 +94,6 @@ The following is extracted from video_common.h as a complete list of formats sup > FOURCC_L565 = FOURCC('L', '5', '6', '5'), // Alias for RGBP. > FOURCC_5551 = FOURCC('5', '5', '5', '1'), // Alias for RGBO. > >- // 1 Auxiliary compressed YUV format set aside for capturer. >- FOURCC_H264 = FOURCC('H', '2', '6', '4'), >- > # Planar YUV > The following formats contains a full size Y plane followed by 1 or 2 > planes for UV: I420, I422, I444, I400, NV21, NV12, I400 >@@ -145,3 +139,24 @@ There are 2 RGB layouts - RGB24 (aka 24BG) and RAW > > RGB24 is B,G,R in memory > RAW is R,G,B in memory >+ >+# AR30 and XR30 >+ >+AR30 is 2 10 10 10 ARGB stored in little endian order. >+The 2 bit alpha has 4 values. Here are the comparable 8 bit alpha values. >+0 - 0. 00000000b = 0x00 = 0 >+1 - 33%. 01010101b = 0x55 = 85 >+2 - 66%. 10101010b = 0xaa = 170 >+3 - 100%. 11111111b = 0xff = 255 >+The 10 bit RGB values range from 0 to 1023. >+XR30 is the same as AR30 but with no alpha channel. >+ >+# NV12 and NV21 >+ >+NV12 is a biplanar format with a full sized Y plane followed by a single >+chroma plane with weaved U and V values. >+NV21 is the same but with weaved V and U values. >+The 12 in NV12 refers to 12 bits per pixel. NV12 has a half width and half >+height chroma channel, and therefore is a 420 subsampling. >+NV16 is 16 bits per pixel, with half width and full height. aka 422. >+NV24 is 24 bits per pixel with full sized chroma channel. aka 444. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/getting_started.md b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/getting_started.md >index 58e05f3cbcb..09297b66a5c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/getting_started.md >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/docs/getting_started.md >@@ -129,25 +129,20 @@ ia32 > ninja -v -C out/Debug libyuv_unittest > ninja -v -C out/Release libyuv_unittest > >-mipsel >+mips > >- gn gen out/Release "--args=is_debug=false target_os=\"android\" target_cpu=\"mipsel\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=false" >- gn gen out/Debug "--args=is_debug=true target_os=\"android\" target_cpu=\"mipsel\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=false" >- ninja -v -C out/Debug libyuv_unittest >- ninja -v -C out/Release libyuv_unittest >- >- gn gen out/Release "--args=is_debug=false target_os=\"android\" target_cpu=\"mips64el\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=false" >- gn gen out/Debug "--args=is_debug=true target_os=\"android\" target_cpu=\"mips64el\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=false" >+ gn gen out/Release "--args=is_debug=false target_os=\"android\" target_cpu=\"mips64el\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=true" >+ gn gen out/Debug "--args=is_debug=true target_os=\"android\" target_cpu=\"mips64el\" mips_arch_variant=\"r6\" mips_use_msa=true is_component_build=true is_clang=true" > ninja -v -C out/Debug libyuv_unittest > ninja -v -C out/Release libyuv_unittest > > arm disassembly: > >- third_party/android_tools/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv/row_common.o >row_common.txt >+ third_party/android_ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv/row_common.o >row_common.txt > >- third_party/android_tools/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv_neon/row_neon.o >row_neon.txt >+ third_party/android_ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv_neon/row_neon.o >row_neon.txt > >- third_party/android_tools/ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv_neon/row_neon64.o >row_neon64.txt >+ third_party/android_ndk/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump -d ./out/Release/obj/libyuv_neon/row_neon64.o >row_neon64.txt > > Running tests: > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/basic_types.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/basic_types.h >index 7d98bb93f0e..01d9dfc7736 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/basic_types.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/basic_types.h >@@ -11,79 +11,33 @@ > #ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_ > #define INCLUDE_LIBYUV_BASIC_TYPES_H_ > >-#include <stddef.h> // for NULL, size_t >+#include <stddef.h> // For size_t and NULL >+ >+#if !defined(INT_TYPES_DEFINED) && !defined(GG_LONGLONG) >+#define INT_TYPES_DEFINED > > #if defined(_MSC_VER) && (_MSC_VER < 1600) > #include <sys/types.h> // for uintptr_t on x86 >+typedef unsigned __int64 uint64_t; >+typedef __int64 int64_t; >+typedef unsigned int uint32_t; >+typedef int int32_t; >+typedef unsigned short uint16_t; >+typedef short int16_t; >+typedef unsigned char uint8_t; >+typedef signed char int8_t; > #else >-#include <stdint.h> // for uintptr_t >-#endif >- >-#ifndef GG_LONGLONG >-#ifndef INT_TYPES_DEFINED >-#define INT_TYPES_DEFINED >-#ifdef COMPILER_MSVC >-typedef unsigned __int64 uint64; >-typedef __int64 int64; >-#ifndef INT64_C >-#define INT64_C(x) x##I64 >-#endif >-#ifndef UINT64_C >-#define UINT64_C(x) x##UI64 >-#endif >-#define INT64_F "I64" >-#else // COMPILER_MSVC >-#if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) >-typedef unsigned long uint64; // NOLINT >-typedef long int64; // NOLINT >-#ifndef INT64_C >-#define INT64_C(x) x##L >-#endif >-#ifndef UINT64_C >-#define UINT64_C(x) x##UL >-#endif >-#define INT64_F "l" >-#else // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) >-typedef unsigned long long uint64; // NOLINT >-typedef long long int64; // NOLINT >-#ifndef INT64_C >-#define INT64_C(x) x##LL >-#endif >-#ifndef UINT64_C >-#define UINT64_C(x) x##ULL >-#endif >-#define INT64_F "ll" >-#endif // __LP64__ >-#endif // COMPILER_MSVC >-typedef unsigned int uint32; >-typedef int int32; >-typedef unsigned short uint16; // NOLINT >-typedef short int16; // NOLINT >-typedef unsigned char uint8; >-typedef signed char int8; >+#include <stdint.h> // for uintptr_t and C99 types >+#endif // defined(_MSC_VER) && (_MSC_VER < 1600) >+typedef uint64_t uint64; >+typedef int64_t int64; >+typedef uint32_t uint32; >+typedef int32_t int32; >+typedef uint16_t uint16; >+typedef int16_t int16; >+typedef uint8_t uint8; >+typedef int8_t int8; > #endif // INT_TYPES_DEFINED >-#endif // GG_LONGLONG >- >-// Detect compiler is for x86 or x64. >-#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ >- defined(_M_IX86) >-#define CPU_X86 1 >-#endif >-// Detect compiler is for ARM. >-#if defined(__arm__) || defined(_M_ARM) >-#define CPU_ARM 1 >-#endif >- >-#ifndef ALIGNP >-#ifdef __cplusplus >-#define ALIGNP(p, t) \ >- reinterpret_cast<uint8*>( \ >- ((reinterpret_cast<uintptr_t>(p) + ((t)-1)) & ~((t)-1))) >-#else >-#define ALIGNP(p, t) \ >- (uint8*)((((uintptr_t)(p) + ((t)-1)) & ~((t)-1))) /* NOLINT */ >-#endif >-#endif > > #if !defined(LIBYUV_API) > #if defined(_WIN32) || defined(__CYGWIN__) >@@ -103,15 +57,9 @@ typedef signed char int8; > #endif // __GNUC__ > #endif // LIBYUV_API > >+// TODO(fbarchard): Remove bool macros. > #define LIBYUV_BOOL int > #define LIBYUV_FALSE 0 > #define LIBYUV_TRUE 1 > >-// Visual C x86 or GCC little endian. >-#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ >- defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) || \ >- (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) >-#define LIBYUV_LITTLE_ENDIAN >-#endif >- > #endif // INCLUDE_LIBYUV_BASIC_TYPES_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare.h >index a06eff2066f..3353ad71c68 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare.h >@@ -20,80 +20,85 @@ extern "C" { > > // Compute a hash for specified memory. Seed of 5381 recommended. > LIBYUV_API >-uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed); >+uint32_t HashDjb2(const uint8_t* src, uint64_t count, uint32_t seed); > > // Hamming Distance > LIBYUV_API >-uint64 ComputeHammingDistance(const uint8* src_a, >- const uint8* src_b, >- int count); >+uint64_t ComputeHammingDistance(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); > > // Scan an opaque argb image and return fourcc based on alpha offset. > // Returns FOURCC_ARGB, FOURCC_BGRA, or 0 if unknown. > LIBYUV_API >-uint32 ARGBDetect(const uint8* argb, int stride_argb, int width, int height); >+uint32_t ARGBDetect(const uint8_t* argb, >+ int stride_argb, >+ int width, >+ int height); > > // Sum Square Error - used to compute Mean Square Error or PSNR. > LIBYUV_API >-uint64 ComputeSumSquareError(const uint8* src_a, const uint8* src_b, int count); >+uint64_t ComputeSumSquareError(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); > > LIBYUV_API >-uint64 ComputeSumSquareErrorPlane(const uint8* src_a, >- int stride_a, >- const uint8* src_b, >- int stride_b, >- int width, >- int height); >+uint64_t ComputeSumSquareErrorPlane(const uint8_t* src_a, >+ int stride_a, >+ const uint8_t* src_b, >+ int stride_b, >+ int width, >+ int height); > > static const int kMaxPsnr = 128; > > LIBYUV_API >-double SumSquareErrorToPsnr(uint64 sse, uint64 count); >+double SumSquareErrorToPsnr(uint64_t sse, uint64_t count); > > LIBYUV_API >-double CalcFramePsnr(const uint8* src_a, >+double CalcFramePsnr(const uint8_t* src_a, > int stride_a, >- const uint8* src_b, >+ const uint8_t* src_b, > int stride_b, > int width, > int height); > > LIBYUV_API >-double I420Psnr(const uint8* src_y_a, >+double I420Psnr(const uint8_t* src_y_a, > int stride_y_a, >- const uint8* src_u_a, >+ const uint8_t* src_u_a, > int stride_u_a, >- const uint8* src_v_a, >+ const uint8_t* src_v_a, > int stride_v_a, >- const uint8* src_y_b, >+ const uint8_t* src_y_b, > int stride_y_b, >- const uint8* src_u_b, >+ const uint8_t* src_u_b, > int stride_u_b, >- const uint8* src_v_b, >+ const uint8_t* src_v_b, > int stride_v_b, > int width, > int height); > > LIBYUV_API >-double CalcFrameSsim(const uint8* src_a, >+double CalcFrameSsim(const uint8_t* src_a, > int stride_a, >- const uint8* src_b, >+ const uint8_t* src_b, > int stride_b, > int width, > int height); > > LIBYUV_API >-double I420Ssim(const uint8* src_y_a, >+double I420Ssim(const uint8_t* src_y_a, > int stride_y_a, >- const uint8* src_u_a, >+ const uint8_t* src_u_a, > int stride_u_a, >- const uint8* src_v_a, >+ const uint8_t* src_v_a, > int stride_v_a, >- const uint8* src_y_b, >+ const uint8_t* src_y_b, > int stride_y_b, >- const uint8* src_u_b, >+ const uint8_t* src_u_b, > int stride_u_b, >- const uint8* src_v_b, >+ const uint8_t* src_v_b, > int stride_v_b, > int width, > int height); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare_row.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare_row.h >index 2e5ebe508d1..72ee740600a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare_row.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/compare_row.h >@@ -18,17 +18,20 @@ namespace libyuv { > extern "C" { > #endif > >-#if defined(__pnacl__) || defined(__CLR_VER) || \ >+#if defined(__pnacl__) || defined(__CLR_VER) || \ >+ (defined(__native_client__) && defined(__x86_64__)) || \ > (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) > #define LIBYUV_DISABLE_X86 > #endif >+#if defined(__native_client__) >+#define LIBYUV_DISABLE_NEON >+#endif > // MemorySanitizer does not support assembly code yet. http://crbug.com/344505 > #if defined(__has_feature) > #if __has_feature(memory_sanitizer) > #define LIBYUV_DISABLE_X86 > #endif > #endif >- > // Visual C 2012 required for AVX2. > #if defined(_M_IX86) && !defined(__clang__) && defined(_MSC_VER) && \ > _MSC_VER >= 1700 >@@ -87,22 +90,44 @@ extern "C" { > #define HAS_SUMSQUAREERROR_MSA > #endif > >-uint32 HammingDistance_C(const uint8* src_a, const uint8* src_b, int count); >-uint32 HammingDistance_SSE42(const uint8* src_a, const uint8* src_b, int count); >-uint32 HammingDistance_SSSE3(const uint8* src_a, const uint8* src_b, int count); >-uint32 HammingDistance_AVX2(const uint8* src_a, const uint8* src_b, int count); >-uint32 HammingDistance_NEON(const uint8* src_a, const uint8* src_b, int count); >-uint32 HammingDistance_MSA(const uint8* src_a, const uint8* src_b, int count); >- >-uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count); >-uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count); >-uint32 SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count); >-uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count); >-uint32 SumSquareError_MSA(const uint8* src_a, const uint8* src_b, int count); >- >-uint32 HashDjb2_C(const uint8* src, int count, uint32 seed); >-uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed); >-uint32 HashDjb2_AVX2(const uint8* src, int count, uint32 seed); >+uint32_t HammingDistance_C(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t HammingDistance_SSE42(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t HammingDistance_SSSE3(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t HammingDistance_AVX2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t HammingDistance_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t HammingDistance_MSA(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+ >+uint32_t SumSquareError_C(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t SumSquareError_SSE2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t SumSquareError_AVX2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t SumSquareError_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+uint32_t SumSquareError_MSA(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); >+ >+uint32_t HashDjb2_C(const uint8_t* src, int count, uint32_t seed); >+uint32_t HashDjb2_SSE41(const uint8_t* src, int count, uint32_t seed); >+uint32_t HashDjb2_AVX2(const uint8_t* src, int count, uint32_t seed); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert.h >index f096d193a74..d12ef24f799 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert.h >@@ -27,34 +27,34 @@ extern "C" { > > // Convert I444 to I420. > LIBYUV_API >-int I444ToI420(const uint8* src_y, >+int I444ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert I422 to I420. > LIBYUV_API >-int I422ToI420(const uint8* src_y, >+int I422ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); >@@ -62,30 +62,67 @@ int I422ToI420(const uint8* src_y, > // Copy I420 to I420. > #define I420ToI420 I420Copy > LIBYUV_API >-int I420Copy(const uint8* src_y, >+int I420Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > >+// Copy I010 to I010 >+#define I010ToI010 I010Copy >+#define H010ToH010 I010Copy >+LIBYUV_API >+int I010Copy(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ uint16_t* dst_u, >+ int dst_stride_u, >+ uint16_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height); >+ >+// Convert 10 bit YUV to 8 bit >+#define H010ToH420 I010ToI420 >+LIBYUV_API >+int I010ToI420(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height); >+ > // Convert I400 (grey) to I420. > LIBYUV_API >-int I400ToI420(const uint8* src_y, >+int I400ToI420(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); >@@ -94,204 +131,204 @@ int I400ToI420(const uint8* src_y, > > // Convert NV12 to I420. > LIBYUV_API >-int NV12ToI420(const uint8* src_y, >+int NV12ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert NV21 to I420. > LIBYUV_API >-int NV21ToI420(const uint8* src_y, >+int NV21ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_vu, >+ const uint8_t* src_vu, > int src_stride_vu, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert YUY2 to I420. > LIBYUV_API >-int YUY2ToI420(const uint8* src_yuy2, >+int YUY2ToI420(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert UYVY to I420. > LIBYUV_API >-int UYVYToI420(const uint8* src_uyvy, >+int UYVYToI420(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert M420 to I420. > LIBYUV_API >-int M420ToI420(const uint8* src_m420, >+int M420ToI420(const uint8_t* src_m420, > int src_stride_m420, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert Android420 to I420. > LIBYUV_API >-int Android420ToI420(const uint8* src_y, >+int Android420ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- int pixel_stride_uv, >- uint8* dst_y, >+ int src_pixel_stride_uv, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // ARGB little endian (bgra in memory) to I420. > LIBYUV_API >-int ARGBToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int ARGBToI420(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // BGRA little endian (argb in memory) to I420. > LIBYUV_API >-int BGRAToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int BGRAToI420(const uint8_t* src_bgra, >+ int src_stride_bgra, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // ABGR little endian (rgba in memory) to I420. > LIBYUV_API >-int ABGRToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int ABGRToI420(const uint8_t* src_abgr, >+ int src_stride_abgr, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGBA little endian (abgr in memory) to I420. > LIBYUV_API >-int RGBAToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int RGBAToI420(const uint8_t* src_rgba, >+ int src_stride_rgba, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGB little endian (bgr in memory) to I420. > LIBYUV_API >-int RGB24ToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int RGB24ToI420(const uint8_t* src_rgb24, >+ int src_stride_rgb24, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGB big endian (rgb in memory) to I420. > LIBYUV_API >-int RAWToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int RAWToI420(const uint8_t* src_raw, >+ int src_stride_raw, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGB16 (RGBP fourcc) little endian to I420. > LIBYUV_API >-int RGB565ToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int RGB565ToI420(const uint8_t* src_rgb565, >+ int src_stride_rgb565, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGB15 (RGBO fourcc) little endian to I420. > LIBYUV_API >-int ARGB1555ToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int ARGB1555ToI420(const uint8_t* src_argb1555, >+ int src_stride_argb1555, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // RGB12 (R444 fourcc) little endian to I420. > LIBYUV_API >-int ARGB4444ToI420(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_y, >+int ARGB4444ToI420(const uint8_t* src_argb4444, >+ int src_stride_argb4444, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); >@@ -300,13 +337,13 @@ int ARGB4444ToI420(const uint8* src_frame, > // src_width/height provided by capture. > // dst_width/height for clipping determine final size. > LIBYUV_API >-int MJPGToI420(const uint8* sample, >+int MJPGToI420(const uint8_t* sample, > size_t sample_size, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int src_width, > int src_height, >@@ -315,7 +352,10 @@ int MJPGToI420(const uint8* sample, > > // Query size of MJPG in pixels. > LIBYUV_API >-int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height); >+int MJPGSize(const uint8_t* sample, >+ size_t sample_size, >+ int* width, >+ int* height); > #endif > > // Convert camera sample to I420 with cropping, rotation and vertical flip. >@@ -338,16 +378,16 @@ int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height); > // Must be less than or equal to src_width/src_height > // Cropping parameters are pre-rotation. > // "rotation" can be 0, 90, 180 or 270. >-// "format" is a fourcc. ie 'I420', 'YUY2' >+// "fourcc" is a fourcc. ie 'I420', 'YUY2' > // Returns 0 for successful; -1 for invalid parameter. Non-zero for failure. > LIBYUV_API >-int ConvertToI420(const uint8* src_frame, >- size_t src_size, >- uint8* dst_y, >+int ConvertToI420(const uint8_t* sample, >+ size_t sample_size, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int crop_x, > int crop_y, >@@ -356,7 +396,7 @@ int ConvertToI420(const uint8* src_frame, > int crop_width, > int crop_height, > enum RotationMode rotation, >- uint32 format); >+ uint32_t fourcc); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_argb.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_argb.h >index f43a5060bdb..ab772b6c323 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_argb.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_argb.h >@@ -30,102 +30,167 @@ extern "C" { > > // Copy ARGB to ARGB. > LIBYUV_API >-int ARGBCopy(const uint8* src_argb, >+int ARGBCopy(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert I420 to ARGB. > LIBYUV_API >-int I420ToARGB(const uint8* src_y, >+int I420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Duplicate prototype for function in convert_from.h for remoting. > LIBYUV_API >-int I420ToABGR(const uint8* src_y, >+int I420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ >+// Convert I010 to ARGB. >+LIBYUV_API >+int I010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > >+// Convert I010 to ARGB. >+LIBYUV_API >+int I010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height); >+ >+// Convert I010 to ABGR. >+LIBYUV_API >+int I010ToABGR(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ >+// Convert H010 to ARGB. >+LIBYUV_API >+int H010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height); >+ >+// Convert H010 to ABGR. >+LIBYUV_API >+int H010ToABGR(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ > // Convert I422 to ARGB. > LIBYUV_API >-int I422ToARGB(const uint8* src_y, >+int I422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert I444 to ARGB. > LIBYUV_API >-int I444ToARGB(const uint8* src_y, >+int I444ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert J444 to ARGB. > LIBYUV_API >-int J444ToARGB(const uint8* src_y, >+int J444ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert I444 to ABGR. > LIBYUV_API >-int I444ToABGR(const uint8* src_y, >+int I444ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert I420 with Alpha to preattenuated ARGB. > LIBYUV_API >-int I420AlphaToARGB(const uint8* src_y, >+int I420AlphaToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- const uint8* src_a, >+ const uint8_t* src_a, > int src_stride_a, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >@@ -133,15 +198,15 @@ int I420AlphaToARGB(const uint8* src_y, > > // Convert I420 with Alpha to preattenuated ABGR. > LIBYUV_API >-int I420AlphaToABGR(const uint8* src_y, >+int I420AlphaToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- const uint8* src_a, >+ const uint8_t* src_a, > int src_stride_a, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height, >@@ -149,18 +214,18 @@ int I420AlphaToABGR(const uint8* src_y, > > // Convert I400 (grey) to ARGB. Reverse of ARGBToI400. > LIBYUV_API >-int I400ToARGB(const uint8* src_y, >+int I400ToARGB(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert J400 (jpeg grey) to ARGB. > LIBYUV_API >-int J400ToARGB(const uint8* src_y, >+int J400ToARGB(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); >@@ -170,180 +235,288 @@ int J400ToARGB(const uint8* src_y, > > // Convert NV12 to ARGB. > LIBYUV_API >-int NV12ToARGB(const uint8* src_y, >+int NV12ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert NV21 to ARGB. > LIBYUV_API >-int NV21ToARGB(const uint8* src_y, >+int NV21ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_vu, >+ const uint8_t* src_vu, > int src_stride_vu, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > >+// Convert NV12 to ABGR. >+int NV12ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ >+// Convert NV21 to ABGR. >+LIBYUV_API >+int NV21ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ >+// Convert NV12 to RGB24. >+LIBYUV_API >+int NV12ToRGB24(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ int width, >+ int height); >+ >+// Convert NV21 to RGB24. >+LIBYUV_API >+int NV21ToRGB24(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ int width, >+ int height); >+ > // Convert M420 to ARGB. > LIBYUV_API >-int M420ToARGB(const uint8* src_m420, >+int M420ToARGB(const uint8_t* src_m420, > int src_stride_m420, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert YUY2 to ARGB. > LIBYUV_API >-int YUY2ToARGB(const uint8* src_yuy2, >+int YUY2ToARGB(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert UYVY to ARGB. > LIBYUV_API >-int UYVYToARGB(const uint8* src_uyvy, >+int UYVYToARGB(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert J420 to ARGB. > LIBYUV_API >-int J420ToARGB(const uint8* src_y, >+int J420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert J422 to ARGB. > LIBYUV_API >-int J422ToARGB(const uint8* src_y, >+int J422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert J420 to ABGR. > LIBYUV_API >-int J420ToABGR(const uint8* src_y, >+int J420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert J422 to ABGR. > LIBYUV_API >-int J422ToABGR(const uint8* src_y, >+int J422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert H420 to ARGB. > LIBYUV_API >-int H420ToARGB(const uint8* src_y, >+int H420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert H422 to ARGB. > LIBYUV_API >-int H422ToARGB(const uint8* src_y, >+int H422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert H420 to ABGR. > LIBYUV_API >-int H420ToABGR(const uint8* src_y, >+int H420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert H422 to ABGR. > LIBYUV_API >-int H422ToABGR(const uint8* src_y, >+int H422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > >+// Convert H010 to ARGB. >+LIBYUV_API >+int H010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height); >+ >+// Convert I010 to AR30. >+LIBYUV_API >+int I010ToAR30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ >+// Convert H010 to AR30. >+LIBYUV_API >+int H010ToAR30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ >+// Convert I010 to AB30. >+LIBYUV_API >+int I010ToAB30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height); >+ >+// Convert H010 to AB30. >+LIBYUV_API >+int H010ToAB30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height); >+ > // BGRA little endian (argb in memory) to ARGB. > LIBYUV_API >-int BGRAToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int BGRAToARGB(const uint8_t* src_bgra, >+ int src_stride_bgra, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // ABGR little endian (rgba in memory) to ARGB. > LIBYUV_API >-int ABGRToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int ABGRToARGB(const uint8_t* src_abgr, >+ int src_stride_abgr, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // RGBA little endian (abgr in memory) to ARGB. > LIBYUV_API >-int RGBAToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int RGBAToARGB(const uint8_t* src_rgba, >+ int src_stride_rgba, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); >@@ -353,56 +526,88 @@ int RGBAToARGB(const uint8* src_frame, > > // RGB little endian (bgr in memory) to ARGB. > LIBYUV_API >-int RGB24ToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int RGB24ToARGB(const uint8_t* src_rgb24, >+ int src_stride_rgb24, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // RGB big endian (rgb in memory) to ARGB. > LIBYUV_API >-int RAWToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int RAWToARGB(const uint8_t* src_raw, >+ int src_stride_raw, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // RGB16 (RGBP fourcc) little endian to ARGB. > LIBYUV_API >-int RGB565ToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int RGB565ToARGB(const uint8_t* src_rgb565, >+ int src_stride_rgb565, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // RGB15 (RGBO fourcc) little endian to ARGB. > LIBYUV_API >-int ARGB1555ToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int ARGB1555ToARGB(const uint8_t* src_argb1555, >+ int src_stride_argb1555, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // RGB12 (R444 fourcc) little endian to ARGB. > LIBYUV_API >-int ARGB4444ToARGB(const uint8* src_frame, >- int src_stride_frame, >- uint8* dst_argb, >+int ARGB4444ToARGB(const uint8_t* src_argb4444, >+ int src_stride_argb4444, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > >+// Aliases >+#define AB30ToARGB AR30ToABGR >+#define AB30ToABGR AR30ToARGB >+#define AB30ToAR30 AR30ToAB30 >+ >+// Convert AR30 To ARGB. >+LIBYUV_API >+int AR30ToARGB(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height); >+ >+// Convert AR30 To ABGR. >+LIBYUV_API >+int AR30ToABGR(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ >+// Convert AR30 To AB30. >+LIBYUV_API >+int AR30ToAB30(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height); >+ > #ifdef HAVE_JPEG > // src_width/height provided by capture > // dst_width/height for clipping determine final size. > LIBYUV_API >-int MJPGToARGB(const uint8* sample, >+int MJPGToARGB(const uint8_t* sample, > size_t sample_size, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int src_width, > int src_height, >@@ -410,8 +615,36 @@ int MJPGToARGB(const uint8* sample, > int dst_height); > #endif > >+// Convert Android420 to ARGB. >+LIBYUV_API >+int Android420ToARGB(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height); >+ >+// Convert Android420 to ABGR. >+LIBYUV_API >+int Android420ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height); >+ > // Convert camera sample to ARGB with cropping, rotation and vertical flip. >-// "src_size" is needed to parse MJPG. >+// "sample_size" is needed to parse MJPG. > // "dst_stride_argb" number of bytes in a row of the dst_argb plane. > // Normally this would be the same as dst_width, with recommended alignment > // to 16 bytes for better efficiency. >@@ -430,12 +663,12 @@ int MJPGToARGB(const uint8* sample, > // Must be less than or equal to src_width/src_height > // Cropping parameters are pre-rotation. > // "rotation" can be 0, 90, 180 or 270. >-// "format" is a fourcc. ie 'I420', 'YUY2' >+// "fourcc" is a fourcc. ie 'I420', 'YUY2' > // Returns 0 for successful; -1 for invalid parameter. Non-zero for failure. > LIBYUV_API >-int ConvertToARGB(const uint8* src_frame, >- size_t src_size, >- uint8* dst_argb, >+int ConvertToARGB(const uint8_t* sample, >+ size_t sample_size, >+ uint8_t* dst_argb, > int dst_stride_argb, > int crop_x, > int crop_y, >@@ -444,7 +677,7 @@ int ConvertToARGB(const uint8* src_frame, > int crop_width, > int crop_height, > enum RotationMode rotation, >- uint32 format); >+ uint32_t fourcc); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from.h >index 237f68f57aa..5cd8a4bfc04 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from.h >@@ -21,218 +21,233 @@ extern "C" { > > // See Also convert.h for conversions from formats to I420. > >-// I420Copy in convert to I420ToI420. >+// Convert 8 bit YUV to 10 bit. >+#define H420ToH010 I420ToI010 >+int I420ToI010(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ uint16_t* dst_u, >+ int dst_stride_u, >+ uint16_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height); > > LIBYUV_API >-int I420ToI422(const uint8* src_y, >+int I420ToI422(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > LIBYUV_API >-int I420ToI444(const uint8* src_y, >+int I420ToI444(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Copy to I400. Source can be I420, I422, I444, I400, NV12 or NV21. > LIBYUV_API >-int I400Copy(const uint8* src_y, >+int I400Copy(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); > > LIBYUV_API >-int I420ToNV12(const uint8* src_y, >+int I420ToNV12(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height); > > LIBYUV_API >-int I420ToNV21(const uint8* src_y, >+int I420ToNV21(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_vu, >+ uint8_t* dst_vu, > int dst_stride_vu, > int width, > int height); > > LIBYUV_API >-int I420ToYUY2(const uint8* src_y, >+int I420ToYUY2(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_yuy2, >+ int dst_stride_yuy2, > int width, > int height); > > LIBYUV_API >-int I420ToUYVY(const uint8* src_y, >+int I420ToUYVY(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_uyvy, >+ int dst_stride_uyvy, > int width, > int height); > > LIBYUV_API >-int I420ToARGB(const uint8* src_y, >+int I420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > LIBYUV_API >-int I420ToBGRA(const uint8* src_y, >+int I420ToBGRA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >- int dst_stride_argb, >+ uint8_t* dst_bgra, >+ int dst_stride_bgra, > int width, > int height); > > LIBYUV_API >-int I420ToABGR(const uint8* src_y, >+int I420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >- int dst_stride_argb, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, > int width, > int height); > > LIBYUV_API >-int I420ToRGBA(const uint8* src_y, >+int I420ToRGBA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height); > > LIBYUV_API >-int I420ToRGB24(const uint8* src_y, >+int I420ToRGB24(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, > int width, > int height); > > LIBYUV_API >-int I420ToRAW(const uint8* src_y, >+int I420ToRAW(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_raw, >+ int dst_stride_raw, > int width, > int height); > > LIBYUV_API >-int H420ToRGB24(const uint8* src_y, >+int H420ToRGB24(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, > int width, > int height); > > LIBYUV_API >-int H420ToRAW(const uint8* src_y, >+int H420ToRAW(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_raw, >+ int dst_stride_raw, > int width, > int height); > > LIBYUV_API >-int I420ToRGB565(const uint8* src_y, >+int I420ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_rgb565, >+ int dst_stride_rgb565, > int width, > int height); > > LIBYUV_API >-int I422ToRGB565(const uint8* src_y, >+int I422ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_rgb565, >+ int dst_stride_rgb565, > int width, > int height); > >@@ -241,57 +256,83 @@ int I422ToRGB565(const uint8* src_y, > // The order of the dither matrix is first byte is upper left. > > LIBYUV_API >-int I420ToRGB565Dither(const uint8* src_y, >+int I420ToRGB565Dither(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >- const uint8* dither4x4, >+ uint8_t* dst_rgb565, >+ int dst_stride_rgb565, >+ const uint8_t* dither4x4, > int width, > int height); > > LIBYUV_API >-int I420ToARGB1555(const uint8* src_y, >+int I420ToARGB1555(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_argb1555, >+ int dst_stride_argb1555, > int width, > int height); > > LIBYUV_API >-int I420ToARGB4444(const uint8* src_y, >+int I420ToARGB4444(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_argb4444, >+ int dst_stride_argb4444, > int width, > int height); > >+// Convert I420 to AR30. >+LIBYUV_API >+int I420ToAR30(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ >+// Convert H420 to AR30. >+LIBYUV_API >+int H420ToAR30(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ > // Convert I420 to specified format. > // "dst_sample_stride" is bytes in a row for the destination. Pass 0 if the > // buffer has contiguous rows. Can be negative. A multiple of 16 is optimal. > LIBYUV_API >-int ConvertFromI420(const uint8* y, >+int ConvertFromI420(const uint8_t* y, > int y_stride, >- const uint8* u, >+ const uint8_t* u, > int u_stride, >- const uint8* v, >+ const uint8_t* v, > int v_stride, >- uint8* dst_sample, >+ uint8_t* dst_sample, > int dst_sample_stride, > int width, > int height, >- uint32 format); >+ uint32_t fourcc); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from_argb.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from_argb.h >index 50722d76102..05c815a093e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from_argb.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/convert_from_argb.h >@@ -21,63 +21,85 @@ extern "C" { > // Copy ARGB to ARGB. > #define ARGBToARGB ARGBCopy > LIBYUV_API >-int ARGBCopy(const uint8* src_argb, >+int ARGBCopy(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert ARGB To BGRA. > LIBYUV_API >-int ARGBToBGRA(const uint8* src_argb, >+int ARGBToBGRA(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_bgra, >+ uint8_t* dst_bgra, > int dst_stride_bgra, > int width, > int height); > > // Convert ARGB To ABGR. > LIBYUV_API >-int ARGBToABGR(const uint8* src_argb, >+int ARGBToABGR(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert ARGB To RGBA. > LIBYUV_API >-int ARGBToRGBA(const uint8* src_argb, >+int ARGBToRGBA(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height); > >+// Aliases >+#define ARGBToAB30 ABGRToAR30 >+#define ABGRToAB30 ARGBToAR30 >+ >+// Convert ABGR To AR30. >+LIBYUV_API >+int ABGRToAR30(const uint8_t* src_abgr, >+ int src_stride_abgr, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ >+// Convert ARGB To AR30. >+LIBYUV_API >+int ARGBToAR30(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height); >+ > // Convert ARGB To RGB24. > LIBYUV_API >-int ARGBToRGB24(const uint8* src_argb, >+int ARGBToRGB24(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height); > > // Convert ARGB To RAW. > LIBYUV_API >-int ARGBToRAW(const uint8* src_argb, >+int ARGBToRAW(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb, >- int dst_stride_rgb, >+ uint8_t* dst_raw, >+ int dst_stride_raw, > int width, > int height); > > // Convert ARGB To RGB565. > LIBYUV_API >-int ARGBToRGB565(const uint8* src_argb, >+int ARGBToRGB565(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height); >@@ -86,173 +108,173 @@ int ARGBToRGB565(const uint8* src_argb, > // Values in dither matrix from 0 to 7 recommended. > // The order of the dither matrix is first byte is upper left. > // TODO(fbarchard): Consider pointer to 2d array for dither4x4. >-// const uint8(*dither)[4][4]; >+// const uint8_t(*dither)[4][4]; > LIBYUV_API >-int ARGBToRGB565Dither(const uint8* src_argb, >+int ARGBToRGB565Dither(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, >- const uint8* dither4x4, >+ const uint8_t* dither4x4, > int width, > int height); > > // Convert ARGB To ARGB1555. > LIBYUV_API >-int ARGBToARGB1555(const uint8* src_argb, >+int ARGBToARGB1555(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb1555, >+ uint8_t* dst_argb1555, > int dst_stride_argb1555, > int width, > int height); > > // Convert ARGB To ARGB4444. > LIBYUV_API >-int ARGBToARGB4444(const uint8* src_argb, >+int ARGBToARGB4444(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb4444, >+ uint8_t* dst_argb4444, > int dst_stride_argb4444, > int width, > int height); > > // Convert ARGB To I444. > LIBYUV_API >-int ARGBToI444(const uint8* src_argb, >+int ARGBToI444(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert ARGB To I422. > LIBYUV_API >-int ARGBToI422(const uint8* src_argb, >+int ARGBToI422(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert ARGB To I420. (also in convert.h) > LIBYUV_API >-int ARGBToI420(const uint8* src_argb, >+int ARGBToI420(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert ARGB to J420. (JPeg full range I420). > LIBYUV_API >-int ARGBToJ420(const uint8* src_argb, >+int ARGBToJ420(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert ARGB to J422. > LIBYUV_API >-int ARGBToJ422(const uint8* src_argb, >+int ARGBToJ422(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert ARGB to J400. (JPeg full range). > LIBYUV_API >-int ARGBToJ400(const uint8* src_argb, >+int ARGBToJ400(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, > int width, > int height); > > // Convert ARGB to I400. > LIBYUV_API >-int ARGBToI400(const uint8* src_argb, >+int ARGBToI400(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); > > // Convert ARGB to G. (Reverse of J400toARGB, which replicates G back to ARGB) > LIBYUV_API >-int ARGBToG(const uint8* src_argb, >+int ARGBToG(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_g, >+ uint8_t* dst_g, > int dst_stride_g, > int width, > int height); > > // Convert ARGB To NV12. > LIBYUV_API >-int ARGBToNV12(const uint8* src_argb, >+int ARGBToNV12(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height); > > // Convert ARGB To NV21. > LIBYUV_API >-int ARGBToNV21(const uint8* src_argb, >+int ARGBToNV21(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_vu, >+ uint8_t* dst_vu, > int dst_stride_vu, > int width, > int height); > > // Convert ARGB To NV21. > LIBYUV_API >-int ARGBToNV21(const uint8* src_argb, >+int ARGBToNV21(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_vu, >+ uint8_t* dst_vu, > int dst_stride_vu, > int width, > int height); > > // Convert ARGB To YUY2. > LIBYUV_API >-int ARGBToYUY2(const uint8* src_argb, >+int ARGBToYUY2(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yuy2, >+ uint8_t* dst_yuy2, > int dst_stride_yuy2, > int width, > int height); > > // Convert ARGB To UYVY. > LIBYUV_API >-int ARGBToUYVY(const uint8* src_argb, >+int ARGBToUYVY(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_uyvy, >+ uint8_t* dst_uyvy, > int dst_stride_uyvy, > int width, > int height); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/cpu_id.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/cpu_id.h >index c2e9bbbd954..91480c68b01 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/cpu_id.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/cpu_id.h >@@ -47,8 +47,7 @@ static const int kCpuHasAVX512VPOPCNTDQ = 0x100000; > > // These flags are only valid on MIPS processors. > static const int kCpuHasMIPS = 0x200000; >-static const int kCpuHasDSPR2 = 0x400000; >-static const int kCpuHasMSA = 0x800000; >+static const int kCpuHasMSA = 0x400000; > > // Optional init function. TestCpuFlag does an auto-init. > // Returns cpu_info flags. >@@ -85,7 +84,7 @@ int MaskCpuFlags(int enable_flags); > // eax is the info type that you want. > // ecx is typically the cpu number, and should normally be zero. > LIBYUV_API >-void CpuId(int eax, int ecx, int* cpu_info); >+void CpuId(int info_eax, int info_ecx, int* cpu_info); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/macros_msa.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/macros_msa.h >index 61be352e3af..921eb0714d6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/macros_msa.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/macros_msa.h >@@ -16,38 +16,38 @@ > #include <stdint.h> > > #if (__mips_isa_rev >= 6) >-#define LW(psrc) \ >- ({ \ >- uint8* psrc_lw_m = (uint8*)(psrc); /* NOLINT */ \ >- uint32 val_m; \ >- asm volatile("lw %[val_m], %[psrc_lw_m] \n" \ >- : [val_m] "=r"(val_m) \ >- : [psrc_lw_m] "m"(*psrc_lw_m)); \ >- val_m; \ >+#define LW(psrc) \ >+ ({ \ >+ uint8_t* psrc_lw_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint32_t val_m; \ >+ asm volatile("lw %[val_m], %[psrc_lw_m] \n" \ >+ : [val_m] "=r"(val_m) \ >+ : [psrc_lw_m] "m"(*psrc_lw_m)); \ >+ val_m; \ > }) > > #if (__mips == 64) >-#define LD(psrc) \ >- ({ \ >- uint8* psrc_ld_m = (uint8*)(psrc); /* NOLINT */ \ >- uint64 val_m = 0; \ >- asm volatile("ld %[val_m], %[psrc_ld_m] \n" \ >- : [val_m] "=r"(val_m) \ >- : [psrc_ld_m] "m"(*psrc_ld_m)); \ >- val_m; \ >+#define LD(psrc) \ >+ ({ \ >+ uint8_t* psrc_ld_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint64_t val_m = 0; \ >+ asm volatile("ld %[val_m], %[psrc_ld_m] \n" \ >+ : [val_m] "=r"(val_m) \ >+ : [psrc_ld_m] "m"(*psrc_ld_m)); \ >+ val_m; \ > }) > #else // !(__mips == 64) >-#define LD(psrc) \ >- ({ \ >- uint8* psrc_ld_m = (uint8*)(psrc); /* NOLINT */ \ >- uint32 val0_m, val1_m; \ >- uint64 val_m = 0; \ >- val0_m = LW(psrc_ld_m); \ >- val1_m = LW(psrc_ld_m + 4); \ >- val_m = (uint64)(val1_m); /* NOLINT */ \ >- val_m = (uint64)((val_m << 32) & 0xFFFFFFFF00000000); /* NOLINT */ \ >- val_m = (uint64)(val_m | (uint64)val0_m); /* NOLINT */ \ >- val_m; \ >+#define LD(psrc) \ >+ ({ \ >+ uint8_t* psrc_ld_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint32_t val0_m, val1_m; \ >+ uint64_t val_m = 0; \ >+ val0_m = LW(psrc_ld_m); \ >+ val1_m = LW(psrc_ld_m + 4); \ >+ val_m = (uint64_t)(val1_m); /* NOLINT */ \ >+ val_m = (uint64_t)((val_m << 32) & 0xFFFFFFFF00000000); /* NOLINT */ \ >+ val_m = (uint64_t)(val_m | (uint64_t)val0_m); /* NOLINT */ \ >+ val_m; \ > }) > #endif // (__mips == 64) > >@@ -81,38 +81,38 @@ > }) > #endif // !(__mips == 64) > #else // !(__mips_isa_rev >= 6) >-#define LW(psrc) \ >- ({ \ >- uint8* psrc_lw_m = (uint8*)(psrc); /* NOLINT */ \ >- uint32 val_m; \ >- asm volatile("ulw %[val_m], %[psrc_lw_m] \n" \ >- : [val_m] "=r"(val_m) \ >- : [psrc_lw_m] "m"(*psrc_lw_m)); \ >- val_m; \ >+#define LW(psrc) \ >+ ({ \ >+ uint8_t* psrc_lw_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint32_t val_m; \ >+ asm volatile("ulw %[val_m], %[psrc_lw_m] \n" \ >+ : [val_m] "=r"(val_m) \ >+ : [psrc_lw_m] "m"(*psrc_lw_m)); \ >+ val_m; \ > }) > > #if (__mips == 64) >-#define LD(psrc) \ >- ({ \ >- uint8* psrc_ld_m = (uint8*)(psrc); /* NOLINT */ \ >- uint64 val_m = 0; \ >- asm volatile("uld %[val_m], %[psrc_ld_m] \n" \ >- : [val_m] "=r"(val_m) \ >- : [psrc_ld_m] "m"(*psrc_ld_m)); \ >- val_m; \ >+#define LD(psrc) \ >+ ({ \ >+ uint8_t* psrc_ld_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint64_t val_m = 0; \ >+ asm volatile("uld %[val_m], %[psrc_ld_m] \n" \ >+ : [val_m] "=r"(val_m) \ >+ : [psrc_ld_m] "m"(*psrc_ld_m)); \ >+ val_m; \ > }) > #else // !(__mips == 64) >-#define LD(psrc) \ >- ({ \ >- uint8* psrc_ld_m = (uint8*)(psrc); /* NOLINT */ \ >- uint32 val0_m, val1_m; \ >- uint64 val_m = 0; \ >- val0_m = LW(psrc_ld_m); \ >- val1_m = LW(psrc_ld_m + 4); \ >- val_m = (uint64)(val1_m); /* NOLINT */ \ >- val_m = (uint64)((val_m << 32) & 0xFFFFFFFF00000000); /* NOLINT */ \ >- val_m = (uint64)(val_m | (uint64)val0_m); /* NOLINT */ \ >- val_m; \ >+#define LD(psrc) \ >+ ({ \ >+ uint8_t* psrc_ld_m = (uint8_t*)(psrc); /* NOLINT */ \ >+ uint32_t val0_m, val1_m; \ >+ uint64_t val_m = 0; \ >+ val0_m = LW(psrc_ld_m); \ >+ val1_m = LW(psrc_ld_m + 4); \ >+ val_m = (uint64_t)(val1_m); /* NOLINT */ \ >+ val_m = (uint64_t)((val_m << 32) & 0xFFFFFFFF00000000); /* NOLINT */ \ >+ val_m = (uint64_t)(val_m | (uint64_t)val0_m); /* NOLINT */ \ >+ val_m; \ > }) > #endif // (__mips == 64) > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/mjpeg_decoder.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/mjpeg_decoder.h >index 8a4f282205b..6c12633387f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/mjpeg_decoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/mjpeg_decoder.h >@@ -26,13 +26,13 @@ namespace libyuv { > extern "C" { > #endif > >-LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size); >+LIBYUV_BOOL ValidateJpeg(const uint8_t* sample, size_t sample_size); > > #ifdef __cplusplus > } // extern "C" > #endif > >-static const uint32 kUnknownDataSize = 0xFFFFFFFF; >+static const uint32_t kUnknownDataSize = 0xFFFFFFFF; > > enum JpegSubsamplingType { > kJpegYuv420, >@@ -43,7 +43,7 @@ enum JpegSubsamplingType { > }; > > struct Buffer { >- const uint8* data; >+ const uint8_t* data; > int len; > }; > >@@ -65,7 +65,7 @@ struct SetJmpErrorMgr; > class LIBYUV_API MJpegDecoder { > public: > typedef void (*CallbackFunction)(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows); > >@@ -85,7 +85,7 @@ class LIBYUV_API MJpegDecoder { > // If return value is LIBYUV_TRUE, then the values for all the following > // getters are populated. > // src_len is the size of the compressed mjpeg frame in bytes. >- LIBYUV_BOOL LoadFrame(const uint8* src, size_t src_len); >+ LIBYUV_BOOL LoadFrame(const uint8_t* src, size_t src_len); > > // Returns width of the last loaded frame in pixels. > int GetWidth(); >@@ -138,7 +138,7 @@ class LIBYUV_API MJpegDecoder { > // at least GetComponentSize(i). The pointers in planes are incremented > // to point to after the end of the written data. > // TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded. >- LIBYUV_BOOL DecodeToBuffers(uint8** planes, int dst_width, int dst_height); >+ LIBYUV_BOOL DecodeToBuffers(uint8_t** planes, int dst_width, int dst_height); > > // Decodes the entire image and passes the data via repeated calls to a > // callback function. Each call will get the data for a whole number of >@@ -162,14 +162,14 @@ class LIBYUV_API MJpegDecoder { > LIBYUV_BOOL StartDecode(); > LIBYUV_BOOL FinishDecode(); > >- void SetScanlinePointers(uint8** data); >+ void SetScanlinePointers(uint8_t** data); > LIBYUV_BOOL DecodeImcuRow(); > > int GetComponentScanlinePadding(int component); > > // A buffer holding the input data for a frame. >- Buffer buf_; >- BufferVector buf_vec_; >+ Buffer buf_{}; >+ BufferVector buf_vec_{}; > > jpeg_decompress_struct* decompress_struct_; > jpeg_source_mgr* source_mgr_; >@@ -181,12 +181,12 @@ class LIBYUV_API MJpegDecoder { > > // Temporaries used to point to scanline outputs. > int num_outbufs_; // Outermost size of all arrays below. >- uint8*** scanlines_; >- int* scanlines_sizes_; >+ uint8_t*** scanlines_{}; >+ int* scanlines_sizes_{}; > // Temporary buffer used for decoding when we can't decode directly to the > // output buffers. Large enough for just one iMCU row. >- uint8** databuf_; >- int* databuf_strides_; >+ uint8_t** databuf_{}; >+ int* databuf_strides_{}; > }; > > } // namespace libyuv >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/planar_functions.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/planar_functions.h >index c91501a9c2c..91137baba25 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/planar_functions.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/planar_functions.h >@@ -22,84 +22,120 @@ namespace libyuv { > extern "C" { > #endif > >+// TODO(fbarchard): Move cpu macros to row.h >+#if defined(__pnacl__) || defined(__CLR_VER) || \ >+ (defined(__native_client__) && defined(__x86_64__)) || \ >+ (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) >+#define LIBYUV_DISABLE_X86 >+#endif >+// MemorySanitizer does not support assembly code yet. http://crbug.com/344505 >+#if defined(__has_feature) >+#if __has_feature(memory_sanitizer) >+#define LIBYUV_DISABLE_X86 >+#endif >+#endif >+// The following are available on all x86 platforms: >+#if !defined(LIBYUV_DISABLE_X86) && \ >+ (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) >+#define HAS_ARGBAFFINEROW_SSE2 >+#endif >+ > // Copy a plane of data. > LIBYUV_API >-void CopyPlane(const uint8* src_y, >+void CopyPlane(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); > > LIBYUV_API >-void CopyPlane_16(const uint16* src_y, >+void CopyPlane_16(const uint16_t* src_y, > int src_stride_y, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, > int width, > int height); > >+LIBYUV_API >+void Convert16To8Plane(const uint16_t* src_y, >+ int src_stride_y, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ int scale, // 16384 for 10 bits >+ int width, >+ int height); >+ >+LIBYUV_API >+void Convert8To16Plane(const uint8_t* src_y, >+ int src_stride_y, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ int scale, // 1024 for 10 bits >+ int width, >+ int height); >+ > // Set a plane of data to a 32 bit value. > LIBYUV_API >-void SetPlane(uint8* dst_y, >+void SetPlane(uint8_t* dst_y, > int dst_stride_y, > int width, > int height, >- uint32 value); >+ uint32_t value); > > // Split interleaved UV plane into separate U and V planes. > LIBYUV_API >-void SplitUVPlane(const uint8* src_uv, >+void SplitUVPlane(const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Merge separate U and V planes into one interleaved UV plane. > LIBYUV_API >-void MergeUVPlane(const uint8* src_u, >+void MergeUVPlane(const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height); > > // Split interleaved RGB plane into separate R, G and B planes. > LIBYUV_API >-void SplitRGBPlane(const uint8* src_rgb, >+void SplitRGBPlane(const uint8_t* src_rgb, > int src_stride_rgb, >- uint8* dst_r, >+ uint8_t* dst_r, > int dst_stride_r, >- uint8* dst_g, >+ uint8_t* dst_g, > int dst_stride_g, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); > > // Merge separate R, G and B planes into one interleaved RGB plane. > LIBYUV_API >-void MergeRGBPlane(const uint8* src_r, >+void MergeRGBPlane(const uint8_t* src_r, > int src_stride_r, >- const uint8* src_g, >+ const uint8_t* src_g, > int src_stride_g, >- const uint8* src_b, >+ const uint8_t* src_b, > int src_stride_b, >- uint8* dst_rgb, >+ uint8_t* dst_rgb, > int dst_stride_rgb, > int width, > int height); > > // Copy I400. Supports inverting. > LIBYUV_API >-int I400ToI400(const uint8* src_y, >+int I400ToI400(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); >@@ -109,17 +145,17 @@ int I400ToI400(const uint8* src_y, > // Copy I422 to I422. > #define I422ToI422 I422Copy > LIBYUV_API >-int I422Copy(const uint8* src_y, >+int I422Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); >@@ -127,84 +163,84 @@ int I422Copy(const uint8* src_y, > // Copy I444 to I444. > #define I444ToI444 I444Copy > LIBYUV_API >-int I444Copy(const uint8* src_y, >+int I444Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert YUY2 to I422. > LIBYUV_API >-int YUY2ToI422(const uint8* src_yuy2, >+int YUY2ToI422(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Convert UYVY to I422. > LIBYUV_API >-int UYVYToI422(const uint8* src_uyvy, >+int UYVYToI422(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > LIBYUV_API >-int YUY2ToNV12(const uint8* src_yuy2, >+int YUY2ToNV12(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height); > > LIBYUV_API >-int UYVYToNV12(const uint8* src_uyvy, >+int UYVYToNV12(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height); > > LIBYUV_API >-int YUY2ToY(const uint8* src_yuy2, >+int YUY2ToY(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); > > // Convert I420 to I400. (calls CopyPlane ignoring u/v). > LIBYUV_API >-int I420ToI400(const uint8* src_y, >+int I420ToI400(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); >@@ -215,17 +251,17 @@ int I420ToI400(const uint8* src_y, > > // I420 mirror. > LIBYUV_API >-int I420Mirror(const uint8* src_y, >+int I420Mirror(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); >@@ -236,9 +272,9 @@ int I420Mirror(const uint8* src_y, > // I400 mirror. A single plane is mirrored horizontally. > // Pass negative height to achieve 180 degree rotation. > LIBYUV_API >-int I400Mirror(const uint8* src_y, >+int I400Mirror(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); >@@ -248,20 +284,20 @@ int I400Mirror(const uint8* src_y, > > // ARGB mirror. > LIBYUV_API >-int ARGBMirror(const uint8* src_argb, >+int ARGBMirror(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert NV12 to RGB565. > LIBYUV_API >-int NV12ToRGB565(const uint8* src_y, >+int NV12ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height); >@@ -269,39 +305,39 @@ int NV12ToRGB565(const uint8* src_y, > // I422ToARGB is in convert_argb.h > // Convert I422 to BGRA. > LIBYUV_API >-int I422ToBGRA(const uint8* src_y, >+int I422ToBGRA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_bgra, >+ uint8_t* dst_bgra, > int dst_stride_bgra, > int width, > int height); > > // Convert I422 to ABGR. > LIBYUV_API >-int I422ToABGR(const uint8* src_y, >+int I422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height); > > // Convert I422 to RGBA. > LIBYUV_API >-int I422ToRGBA(const uint8* src_y, >+int I422ToRGBA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height); >@@ -310,20 +346,20 @@ int I422ToRGBA(const uint8* src_y, > #define RGB24ToRAW RAWToRGB24 > > LIBYUV_API >-int RAWToRGB24(const uint8* src_raw, >+int RAWToRGB24(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height); > > // Draw a rectangle into I420. > LIBYUV_API >-int I420Rect(uint8* dst_y, >+int I420Rect(uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int x, > int y, >@@ -335,38 +371,38 @@ int I420Rect(uint8* dst_y, > > // Draw a rectangle into ARGB. > LIBYUV_API >-int ARGBRect(uint8* dst_argb, >+int ARGBRect(uint8_t* dst_argb, > int dst_stride_argb, >- int x, >- int y, >+ int dst_x, >+ int dst_y, > int width, > int height, >- uint32 value); >+ uint32_t value); > > // Convert ARGB to gray scale ARGB. > LIBYUV_API >-int ARGBGrayTo(const uint8* src_argb, >+int ARGBGrayTo(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Make a rectangle of ARGB gray scale. > LIBYUV_API >-int ARGBGray(uint8* dst_argb, >+int ARGBGray(uint8_t* dst_argb, > int dst_stride_argb, >- int x, >- int y, >+ int dst_x, >+ int dst_y, > int width, > int height); > > // Make a rectangle of ARGB Sepia tone. > LIBYUV_API >-int ARGBSepia(uint8* dst_argb, >+int ARGBSepia(uint8_t* dst_argb, > int dst_stride_argb, >- int x, >- int y, >+ int dst_x, >+ int dst_y, > int width, > int height); > >@@ -377,11 +413,11 @@ int ARGBSepia(uint8* dst_argb, > // The next 4 coefficients apply to B, G, R, A and produce R of the output. > // The last 4 coefficients apply to B, G, R, A and produce A of the output. > LIBYUV_API >-int ARGBColorMatrix(const uint8* src_argb, >+int ARGBColorMatrix(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const int8* matrix_argb, >+ const int8_t* matrix_argb, > int width, > int height); > >@@ -392,33 +428,33 @@ int ARGBColorMatrix(const uint8* src_argb, > // The next 4 coefficients apply to B, G, R, A and produce G of the output. > // The last 4 coefficients apply to B, G, R, A and produce R of the output. > LIBYUV_API >-int RGBColorMatrix(uint8* dst_argb, >+int RGBColorMatrix(uint8_t* dst_argb, > int dst_stride_argb, >- const int8* matrix_rgb, >- int x, >- int y, >+ const int8_t* matrix_rgb, >+ int dst_x, >+ int dst_y, > int width, > int height); > > // Apply a color table each ARGB pixel. > // Table contains 256 ARGB values. > LIBYUV_API >-int ARGBColorTable(uint8* dst_argb, >+int ARGBColorTable(uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* table_argb, >- int x, >- int y, >+ const uint8_t* table_argb, >+ int dst_x, >+ int dst_y, > int width, > int height); > > // Apply a color table each ARGB pixel but preserve destination alpha. > // Table contains 256 ARGB values. > LIBYUV_API >-int RGBColorTable(uint8* dst_argb, >+int RGBColorTable(uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* table_argb, >- int x, >- int y, >+ const uint8_t* table_argb, >+ int dst_x, >+ int dst_y, > int width, > int height); > >@@ -426,11 +462,11 @@ int RGBColorTable(uint8* dst_argb, > // Table contains 32768 values indexed by [Y][C] where 7 it 7 bit luma from > // RGB (YJ style) and C is an 8 bit color component (R, G or B). > LIBYUV_API >-int ARGBLumaColorTable(const uint8* src_argb, >+int ARGBLumaColorTable(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* luma_rgb_table, >+ const uint8_t* luma, > int width, > int height); > >@@ -443,9 +479,9 @@ int ARGBLumaColorTable(const uint8* src_argb, > // A polynomial approximation can be dirived using software such as 'R'. > > LIBYUV_API >-int ARGBPolynomial(const uint8* src_argb, >+int ARGBPolynomial(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const float* poly, > int width, >@@ -454,68 +490,72 @@ int ARGBPolynomial(const uint8* src_argb, > // Convert plane of 16 bit shorts to half floats. > // Source values are multiplied by scale before storing as half float. > LIBYUV_API >-int HalfFloatPlane(const uint16* src_y, >+int HalfFloatPlane(const uint16_t* src_y, > int src_stride_y, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, > float scale, > int width, > int height); > >+// Convert a buffer of bytes to floats, scale the values and store as floats. >+LIBYUV_API >+int ByteToFloat(const uint8_t* src_y, float* dst_y, float scale, int width); >+ > // Quantize a rectangle of ARGB. Alpha unaffected. > // scale is a 16 bit fractional fixed point scaler between 0 and 65535. > // interval_size should be a value between 1 and 255. > // interval_offset should be a value between 0 and 255. > LIBYUV_API >-int ARGBQuantize(uint8* dst_argb, >+int ARGBQuantize(uint8_t* dst_argb, > int dst_stride_argb, > int scale, > int interval_size, > int interval_offset, >- int x, >- int y, >+ int dst_x, >+ int dst_y, > int width, > int height); > > // Copy ARGB to ARGB. > LIBYUV_API >-int ARGBCopy(const uint8* src_argb, >+int ARGBCopy(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Copy Alpha channel of ARGB to alpha of ARGB. > LIBYUV_API >-int ARGBCopyAlpha(const uint8* src_argb, >+int ARGBCopyAlpha(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Extract the alpha channel from ARGB. > LIBYUV_API >-int ARGBExtractAlpha(const uint8* src_argb, >+int ARGBExtractAlpha(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, > int width, > int height); > > // Copy Y channel to Alpha of ARGB. > LIBYUV_API >-int ARGBCopyYToAlpha(const uint8* src_y, >+int ARGBCopyYToAlpha(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > >-typedef void (*ARGBBlendRow)(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+typedef void (*ARGBBlendRow)(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); > > // Get function to Alpha Blend ARGB pixels and store to destination. >@@ -526,11 +566,11 @@ ARGBBlendRow GetARGBBlend(); > // Source is pre-multiplied by alpha using ARGBAttenuate. > // Alpha of destination is set to 255. > LIBYUV_API >-int ARGBBlend(const uint8* src_argb0, >+int ARGBBlend(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); >@@ -538,13 +578,13 @@ int ARGBBlend(const uint8* src_argb0, > // Alpha Blend plane and store to destination. > // Source is not pre-multiplied by alpha. > LIBYUV_API >-int BlendPlane(const uint8* src_y0, >+int BlendPlane(const uint8_t* src_y0, > int src_stride_y0, >- const uint8* src_y1, >+ const uint8_t* src_y1, > int src_stride_y1, >- const uint8* alpha, >+ const uint8_t* alpha, > int alpha_stride, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); >@@ -553,102 +593,102 @@ int BlendPlane(const uint8* src_y0, > // Source is not pre-multiplied by alpha. > // Alpha is full width x height and subsampled to half size to apply to UV. > LIBYUV_API >-int I420Blend(const uint8* src_y0, >+int I420Blend(const uint8_t* src_y0, > int src_stride_y0, >- const uint8* src_u0, >+ const uint8_t* src_u0, > int src_stride_u0, >- const uint8* src_v0, >+ const uint8_t* src_v0, > int src_stride_v0, >- const uint8* src_y1, >+ const uint8_t* src_y1, > int src_stride_y1, >- const uint8* src_u1, >+ const uint8_t* src_u1, > int src_stride_u1, >- const uint8* src_v1, >+ const uint8_t* src_v1, > int src_stride_v1, >- const uint8* alpha, >+ const uint8_t* alpha, > int alpha_stride, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height); > > // Multiply ARGB image by ARGB image. Shifted down by 8. Saturates to 255. > LIBYUV_API >-int ARGBMultiply(const uint8* src_argb0, >+int ARGBMultiply(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Add ARGB image with ARGB image. Saturates to 255. > LIBYUV_API >-int ARGBAdd(const uint8* src_argb0, >+int ARGBAdd(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Subtract ARGB image (argb1) from ARGB image (argb0). Saturates to 0. > LIBYUV_API >-int ARGBSubtract(const uint8* src_argb0, >+int ARGBSubtract(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert I422 to YUY2. > LIBYUV_API >-int I422ToYUY2(const uint8* src_y, >+int I422ToYUY2(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_yuy2, >+ int dst_stride_yuy2, > int width, > int height); > > // Convert I422 to UYVY. > LIBYUV_API >-int I422ToUYVY(const uint8* src_y, >+int I422ToUYVY(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_frame, >- int dst_stride_frame, >+ uint8_t* dst_uyvy, >+ int dst_stride_uyvy, > int width, > int height); > > // Convert unattentuated ARGB to preattenuated ARGB. > LIBYUV_API >-int ARGBAttenuate(const uint8* src_argb, >+int ARGBAttenuate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Convert preattentuated ARGB to unattenuated ARGB. > LIBYUV_API >-int ARGBUnattenuate(const uint8* src_argb, >+int ARGBUnattenuate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); >@@ -657,9 +697,9 @@ int ARGBUnattenuate(const uint8* src_argb, > // Computes table of cumulative sum for image where the value is the sum > // of all values above and to the left of the entry. Used by ARGBBlur. > LIBYUV_API >-int ARGBComputeCumulativeSum(const uint8* src_argb, >+int ARGBComputeCumulativeSum(const uint8_t* src_argb, > int src_stride_argb, >- int32* dst_cumsum, >+ int32_t* dst_cumsum, > int dst_stride32_cumsum, > int width, > int height); >@@ -671,11 +711,11 @@ int ARGBComputeCumulativeSum(const uint8* src_argb, > // radius is number of pixels around the center. e.g. 1 = 3x3. 2=5x5. > // Blur is optimized for radius of 5 (11x11) or less. > LIBYUV_API >-int ARGBBlur(const uint8* src_argb, >+int ARGBBlur(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- int32* dst_cumsum, >+ int32_t* dst_cumsum, > int dst_stride32_cumsum, > int width, > int height, >@@ -683,24 +723,24 @@ int ARGBBlur(const uint8* src_argb, > > // Multiply ARGB image by ARGB value. > LIBYUV_API >-int ARGBShade(const uint8* src_argb, >+int ARGBShade(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >- uint32 value); >+ uint32_t value); > > // Interpolate between two images using specified amount of interpolation > // (0 to 255) and store to destination. > // 'interpolation' is specified as 8 bit fraction where 0 means 100% src0 > // and 255 means 1% src0 and 99% src1. > LIBYUV_API >-int InterpolatePlane(const uint8* src0, >+int InterpolatePlane(const uint8_t* src0, > int src_stride0, >- const uint8* src1, >+ const uint8_t* src1, > int src_stride1, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height, >@@ -709,11 +749,11 @@ int InterpolatePlane(const uint8* src0, > // Interpolate between two ARGB images using specified amount of interpolation > // Internally calls InterpolatePlane with width * 4 (bpp). > LIBYUV_API >-int ARGBInterpolate(const uint8* src_argb0, >+int ARGBInterpolate(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >@@ -723,93 +763,78 @@ int ARGBInterpolate(const uint8* src_argb0, > // Internally calls InterpolatePlane on each plane where the U and V planes > // are half width and half height. > LIBYUV_API >-int I420Interpolate(const uint8* src0_y, >+int I420Interpolate(const uint8_t* src0_y, > int src0_stride_y, >- const uint8* src0_u, >+ const uint8_t* src0_u, > int src0_stride_u, >- const uint8* src0_v, >+ const uint8_t* src0_v, > int src0_stride_v, >- const uint8* src1_y, >+ const uint8_t* src1_y, > int src1_stride_y, >- const uint8* src1_u, >+ const uint8_t* src1_u, > int src1_stride_u, >- const uint8* src1_v, >+ const uint8_t* src1_v, > int src1_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height, > int interpolation); > >-#if defined(__pnacl__) || defined(__CLR_VER) || \ >- (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) >-#define LIBYUV_DISABLE_X86 >-#endif >-// MemorySanitizer does not support assembly code yet. http://crbug.com/344505 >-#if defined(__has_feature) >-#if __has_feature(memory_sanitizer) >-#define LIBYUV_DISABLE_X86 >-#endif >-#endif >-// The following are available on all x86 platforms: >-#if !defined(LIBYUV_DISABLE_X86) && \ >- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) >-#define HAS_ARGBAFFINEROW_SSE2 >-#endif >- > // Row function for copying pixels from a source with a slope to a row > // of destination. Useful for scaling, rotation, mirror, texture mapping. > LIBYUV_API >-void ARGBAffineRow_C(const uint8* src_argb, >+void ARGBAffineRow_C(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* uv_dudv, > int width); >+// TODO(fbarchard): Move ARGBAffineRow_SSE2 to row.h > LIBYUV_API >-void ARGBAffineRow_SSE2(const uint8* src_argb, >+void ARGBAffineRow_SSE2(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* uv_dudv, > int width); > > // Shuffle ARGB channel order. e.g. BGRA to ARGB. > // shuffler is 16 bytes and must be aligned. > LIBYUV_API >-int ARGBShuffle(const uint8* src_bgra, >+int ARGBShuffle(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* shuffler, >+ const uint8_t* shuffler, > int width, > int height); > > // Sobel ARGB effect with planar output. > LIBYUV_API >-int ARGBSobelToPlane(const uint8* src_argb, >+int ARGBSobelToPlane(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height); > > // Sobel ARGB effect. > LIBYUV_API >-int ARGBSobel(const uint8* src_argb, >+int ARGBSobel(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); > > // Sobel ARGB effect w/ Sobel X, Sobel, Sobel Y in ARGB. > LIBYUV_API >-int ARGBSobelXY(const uint8* src_argb, >+int ARGBSobelXY(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate.h >index b9f7154a51d..76b692be8b0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate.h >@@ -33,79 +33,79 @@ typedef enum RotationMode { > > // Rotate I420 frame. > LIBYUV_API >-int I420Rotate(const uint8* src_y, >+int I420Rotate(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, >- int src_width, >- int src_height, >+ int width, >+ int height, > enum RotationMode mode); > > // Rotate NV12 input and store in I420. > LIBYUV_API >-int NV12ToI420Rotate(const uint8* src_y, >+int NV12ToI420Rotate(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, >- int src_width, >- int src_height, >+ int width, >+ int height, > enum RotationMode mode); > > // Rotate a plane by 0, 90, 180, or 270. > LIBYUV_API >-int RotatePlane(const uint8* src, >+int RotatePlane(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, >- int src_width, >- int src_height, >+ int width, >+ int height, > enum RotationMode mode); > > // Rotate planes by 90, 180, 270. Deprecated. > LIBYUV_API >-void RotatePlane90(const uint8* src, >+void RotatePlane90(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height); > > LIBYUV_API >-void RotatePlane180(const uint8* src, >+void RotatePlane180(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height); > > LIBYUV_API >-void RotatePlane270(const uint8* src, >+void RotatePlane270(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height); > > LIBYUV_API >-void RotateUV90(const uint8* src, >+void RotateUV90(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); >@@ -115,21 +115,21 @@ void RotateUV90(const uint8* src, > // split the data into two buffers while > // rotating them. Deprecated. > LIBYUV_API >-void RotateUV180(const uint8* src, >+void RotateUV180(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); > > LIBYUV_API >-void RotateUV270(const uint8* src, >+void RotateUV270(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); >@@ -139,19 +139,19 @@ void RotateUV270(const uint8* src, > // order will result in a rotation by +- 90 degrees. > // Deprecated. > LIBYUV_API >-void TransposePlane(const uint8* src, >+void TransposePlane(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height); > > LIBYUV_API >-void TransposeUV(const uint8* src, >+void TransposeUV(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_argb.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_argb.h >index be0190c1787..20432949ab4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_argb.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_argb.h >@@ -21,9 +21,9 @@ extern "C" { > > // Rotate ARGB frame > LIBYUV_API >-int ARGBRotate(const uint8* src_argb, >+int ARGBRotate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int src_width, > int src_height, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_row.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_row.h >index 973fc15284f..5edc0fcf13a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_row.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/rotate_row.h >@@ -18,10 +18,14 @@ namespace libyuv { > extern "C" { > #endif > >-#if defined(__pnacl__) || defined(__CLR_VER) || \ >+#if defined(__pnacl__) || defined(__CLR_VER) || \ >+ (defined(__native_client__) && defined(__x86_64__)) || \ > (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) > #define LIBYUV_DISABLE_X86 > #endif >+#if defined(__native_client__) >+#define LIBYUV_DISABLE_NEON >+#endif > // MemorySanitizer does not support assembly code yet. http://crbug.com/344505 > #if defined(__has_feature) > #if __has_feature(memory_sanitizer) >@@ -34,189 +38,151 @@ extern "C" { > #define HAS_TRANSPOSEUVWX8_SSE2 > #endif > >-// The following are available for GCC 32 or 64 bit but not NaCL for 64 bit: >-#if !defined(LIBYUV_DISABLE_X86) && \ >- (defined(__i386__) || \ >- (defined(__x86_64__) && !defined(__native_client__))) >+// The following are available for GCC 32 or 64 bit: >+#if !defined(LIBYUV_DISABLE_X86) && (defined(__i386__) || defined(__x86_64__)) > #define HAS_TRANSPOSEWX8_SSSE3 > #endif > >-// The following are available for 64 bit GCC but not NaCL: >-#if !defined(LIBYUV_DISABLE_X86) && !defined(__native_client__) && \ >- defined(__x86_64__) >+// The following are available for 64 bit GCC: >+#if !defined(LIBYUV_DISABLE_X86) && defined(__x86_64__) > #define HAS_TRANSPOSEWX8_FAST_SSSE3 > #define HAS_TRANSPOSEUVWX8_SSE2 > #endif > >-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \ >+#if !defined(LIBYUV_DISABLE_NEON) && \ > (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__)) > #define HAS_TRANSPOSEWX8_NEON > #define HAS_TRANSPOSEUVWX8_NEON > #endif > >-#if !defined(LIBYUV_DISABLE_DSPR2) && !defined(__native_client__) && \ >- defined(__mips__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2) >-#define HAS_TRANSPOSEWX8_DSPR2 >-#define HAS_TRANSPOSEUVWX8_DSPR2 >-#endif // defined(__mips__) >- > #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa) > #define HAS_TRANSPOSEWX16_MSA > #define HAS_TRANSPOSEUVWX16_MSA > #endif > >-void TransposeWxH_C(const uint8* src, >+void TransposeWxH_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height); > >-void TransposeWx8_C(const uint8* src, >+void TransposeWx8_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx16_C(const uint8* src, >+void TransposeWx16_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_NEON(const uint8* src, >+void TransposeWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_SSSE3(const uint8* src, >+void TransposeWx8_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_Fast_SSSE3(const uint8* src, >+void TransposeWx8_Fast_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >- int width); >-void TransposeWx8_Fast_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >- int width); >-void TransposeWx16_MSA(const uint8* src, >+void TransposeWx16_MSA(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); > >-void TransposeWx8_Any_NEON(const uint8* src, >+void TransposeWx8_Any_NEON(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_Any_SSSE3(const uint8* src, >+void TransposeWx8_Any_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_Fast_Any_SSSE3(const uint8* src, >+void TransposeWx8_Fast_Any_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); >-void TransposeWx8_Any_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >- int width); >-void TransposeWx16_Any_MSA(const uint8* src, >+void TransposeWx16_Any_MSA(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width); > >-void TransposeUVWxH_C(const uint8* src, >+void TransposeUVWxH_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height); > >-void TransposeUVWx8_C(const uint8* src, >+void TransposeUVWx8_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx16_C(const uint8* src, >+void TransposeUVWx16_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx8_SSE2(const uint8* src, >+void TransposeUVWx8_SSE2(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx8_NEON(const uint8* src, >+void TransposeUVWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx8_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst_a, >- int dst_stride_a, >- uint8* dst_b, >- int dst_stride_b, >- int width); >-void TransposeUVWx16_MSA(const uint8* src, >+void TransposeUVWx16_MSA(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); > >-void TransposeUVWx8_Any_SSE2(const uint8* src, >+void TransposeUVWx8_Any_SSE2(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx8_Any_NEON(const uint8* src, >+void TransposeUVWx8_Any_NEON(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); >-void TransposeUVWx8_Any_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst_a, >- int dst_stride_a, >- uint8* dst_b, >- int dst_stride_b, >- int width); >-void TransposeUVWx16_Any_MSA(const uint8* src, >+void TransposeUVWx16_Any_MSA(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width); > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/row.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/row.h >index 34d727641a8..b5a42d0e62c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/row.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/row.h >@@ -20,34 +20,20 @@ namespace libyuv { > extern "C" { > #endif > >-#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a)-1))) >- >-#define align_buffer_64(var, size) \ >- uint8* var##_mem = (uint8*)(malloc((size) + 63)); /* NOLINT */ \ >- uint8* var = (uint8*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */ >- >-#define free_aligned_buffer_64(var) \ >- free(var##_mem); \ >- var = 0 >- >-#if defined(__pnacl__) || defined(__CLR_VER) || \ >+#if defined(__pnacl__) || defined(__CLR_VER) || \ >+ (defined(__native_client__) && defined(__x86_64__)) || \ > (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) > #define LIBYUV_DISABLE_X86 > #endif >+#if defined(__native_client__) >+#define LIBYUV_DISABLE_NEON >+#endif > // MemorySanitizer does not support assembly code yet. http://crbug.com/344505 > #if defined(__has_feature) > #if __has_feature(memory_sanitizer) > #define LIBYUV_DISABLE_X86 > #endif > #endif >-// True if compiling for SSSE3 as a requirement. >-#if defined(__SSSE3__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 3)) >-#define LIBYUV_SSSE3_ONLY >-#endif >- >-#if defined(__native_client__) >-#define LIBYUV_DISABLE_NEON >-#endif > // clang >= 3.5.0 required for Arm64. > #if defined(__clang__) && defined(__aarch64__) && !defined(LIBYUV_DISABLE_NEON) > #if (__clang_major__ < 3) || (__clang_major__ == 3 && (__clang_minor__ < 5)) >@@ -85,7 +71,6 @@ extern "C" { > #define HAS_ARGB4444TOARGBROW_SSE2 > #define HAS_ARGBEXTRACTALPHAROW_SSE2 > #define HAS_ARGBSETROW_X86 >-#define HAS_ARGBSHUFFLEROW_SSE2 > #define HAS_ARGBSHUFFLEROW_SSSE3 > #define HAS_ARGBTOARGB1555ROW_SSE2 > #define HAS_ARGBTOARGB4444ROW_SSE2 >@@ -184,7 +169,6 @@ extern "C" { > > // The following are available on all x86 platforms, but > // require VS2012, clang 3.4 or gcc 4.7. >-// The code supports NaCL but requires a new compiler and validator. > #if !defined(LIBYUV_DISABLE_X86) && \ > (defined(VISUALC_HAS_AVX2) || defined(CLANG_HAS_AVX2) || \ > defined(GCC_HAS_AVX2)) >@@ -268,6 +252,14 @@ extern "C" { > // TODO(fbarchard): Port to Visual C > #if !defined(LIBYUV_DISABLE_X86) && \ > (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) >+#define HAS_ABGRTOAR30ROW_SSSE3 >+#define HAS_ARGBTOAR30ROW_SSSE3 >+#define HAS_CONVERT16TO8ROW_SSSE3 >+#define HAS_CONVERT8TO16ROW_SSE2 >+// I210 is for H010. 2 = 422. I for 601 vs H for 709. >+#define HAS_I210TOAR30ROW_SSSE3 >+#define HAS_I210TOARGBROW_SSSE3 >+#define HAS_I422TOAR30ROW_SSSE3 > #define HAS_MERGERGBROW_SSSE3 > #define HAS_SPLITRGBROW_SSSE3 > #endif >@@ -277,6 +269,15 @@ extern "C" { > #if !defined(LIBYUV_DISABLE_X86) && \ > (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) && \ > (defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2)) >+#define HAS_ABGRTOAR30ROW_AVX2 >+#define HAS_ARGBTOAR30ROW_AVX2 >+#define HAS_CONVERT16TO8ROW_AVX2 >+#define HAS_CONVERT8TO16ROW_AVX2 >+#define HAS_I210TOARGBROW_AVX2 >+#define HAS_I210TOAR30ROW_AVX2 >+#define HAS_I422TOAR30ROW_AVX2 >+#define HAS_I422TOUYVYROW_AVX2 >+#define HAS_I422TOYUY2ROW_AVX2 > #define HAS_MERGEUVROW_16_AVX2 > #define HAS_MULTIPLYROW_16_AVX2 > #endif >@@ -307,6 +308,7 @@ extern "C" { > #define HAS_ARGBTOYROW_NEON > #define HAS_BGRATOUVROW_NEON > #define HAS_BGRATOYROW_NEON >+#define HAS_BYTETOFLOATROW_NEON > #define HAS_COPYROW_NEON > #define HAS_HALFFLOATROW_NEON > #define HAS_I400TOARGBROW_NEON >@@ -325,8 +327,10 @@ extern "C" { > #define HAS_MIRRORROW_NEON > #define HAS_MIRRORUVROW_NEON > #define HAS_NV12TOARGBROW_NEON >+#define HAS_NV12TORGB24ROW_NEON > #define HAS_NV12TORGB565ROW_NEON > #define HAS_NV21TOARGBROW_NEON >+#define HAS_NV21TORGB24ROW_NEON > #define HAS_RAWTOARGBROW_NEON > #define HAS_RAWTORGB24ROW_NEON > #define HAS_RAWTOUVROW_NEON >@@ -376,37 +380,6 @@ extern "C" { > #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) > #define HAS_SCALESUMSAMPLES_NEON > #endif >- >-// The following are available on Mips platforms: >-#if !defined(LIBYUV_DISABLE_DSPR2) && defined(__mips__) && \ >- (_MIPS_SIM == _MIPS_SIM_ABI32) && (__mips_isa_rev < 6) >-#define HAS_COPYROW_MIPS >-#if defined(__mips_dsp) && (__mips_dsp_rev >= 2) >-#define HAS_I422TOARGBROW_DSPR2 >-#define HAS_INTERPOLATEROW_DSPR2 >-#define HAS_MIRRORROW_DSPR2 >-#define HAS_MIRRORUVROW_DSPR2 >-#define HAS_SPLITUVROW_DSPR2 >-#define HAS_RGB24TOARGBROW_DSPR2 >-#define HAS_RAWTOARGBROW_DSPR2 >-#define HAS_RGB565TOARGBROW_DSPR2 >-#define HAS_ARGB1555TOARGBROW_DSPR2 >-#define HAS_ARGB4444TOARGBROW_DSPR2 >-#define HAS_I444TOARGBROW_DSPR2 >-#define HAS_I422TOARGB4444ROW_DSPR2 >-#define HAS_I422TOARGB1555ROW_DSPR2 >-#define HAS_NV12TOARGBROW_DSPR2 >-#define HAS_BGRATOUVROW_DSPR2 >-#define HAS_BGRATOYROW_DSPR2 >-#define HAS_ABGRTOUVROW_DSPR2 >-#define HAS_ARGBTOYROW_DSPR2 >-#define HAS_ABGRTOYROW_DSPR2 >-#define HAS_RGBATOUVROW_DSPR2 >-#define HAS_RGBATOYROW_DSPR2 >-#define HAS_ARGBTOUVROW_DSPR2 >-#endif >-#endif >- > #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa) > #define HAS_ABGRTOUVROW_MSA > #define HAS_ABGRTOYROW_MSA >@@ -492,18 +465,18 @@ extern "C" { > #else > #define SIMD_ALIGNED(var) __declspec(align(16)) var > #endif >-typedef __declspec(align(16)) int16 vec16[8]; >-typedef __declspec(align(16)) int32 vec32[4]; >-typedef __declspec(align(16)) int8 vec8[16]; >-typedef __declspec(align(16)) uint16 uvec16[8]; >-typedef __declspec(align(16)) uint32 uvec32[4]; >-typedef __declspec(align(16)) uint8 uvec8[16]; >-typedef __declspec(align(32)) int16 lvec16[16]; >-typedef __declspec(align(32)) int32 lvec32[8]; >-typedef __declspec(align(32)) int8 lvec8[32]; >-typedef __declspec(align(32)) uint16 ulvec16[16]; >-typedef __declspec(align(32)) uint32 ulvec32[8]; >-typedef __declspec(align(32)) uint8 ulvec8[32]; >+typedef __declspec(align(16)) int16_t vec16[8]; >+typedef __declspec(align(16)) int32_t vec32[4]; >+typedef __declspec(align(16)) int8_t vec8[16]; >+typedef __declspec(align(16)) uint16_t uvec16[8]; >+typedef __declspec(align(16)) uint32_t uvec32[4]; >+typedef __declspec(align(16)) uint8_t uvec8[16]; >+typedef __declspec(align(32)) int16_t lvec16[16]; >+typedef __declspec(align(32)) int32_t lvec32[8]; >+typedef __declspec(align(32)) int8_t lvec8[32]; >+typedef __declspec(align(32)) uint16_t ulvec16[16]; >+typedef __declspec(align(32)) uint32_t ulvec32[8]; >+typedef __declspec(align(32)) uint8_t ulvec8[32]; > #elif !defined(__pnacl__) && (defined(__GNUC__) || defined(__clang__)) > // Caveat GCC 4.2 to 4.7 have a known issue using vectors with const. > #if defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2) >@@ -511,32 +484,32 @@ typedef __declspec(align(32)) uint8 ulvec8[32]; > #else > #define SIMD_ALIGNED(var) var __attribute__((aligned(16))) > #endif >-typedef int16 __attribute__((vector_size(16))) vec16; >-typedef int32 __attribute__((vector_size(16))) vec32; >-typedef int8 __attribute__((vector_size(16))) vec8; >-typedef uint16 __attribute__((vector_size(16))) uvec16; >-typedef uint32 __attribute__((vector_size(16))) uvec32; >-typedef uint8 __attribute__((vector_size(16))) uvec8; >-typedef int16 __attribute__((vector_size(32))) lvec16; >-typedef int32 __attribute__((vector_size(32))) lvec32; >-typedef int8 __attribute__((vector_size(32))) lvec8; >-typedef uint16 __attribute__((vector_size(32))) ulvec16; >-typedef uint32 __attribute__((vector_size(32))) ulvec32; >-typedef uint8 __attribute__((vector_size(32))) ulvec8; >+typedef int16_t __attribute__((vector_size(16))) vec16; >+typedef int32_t __attribute__((vector_size(16))) vec32; >+typedef int8_t __attribute__((vector_size(16))) vec8; >+typedef uint16_t __attribute__((vector_size(16))) uvec16; >+typedef uint32_t __attribute__((vector_size(16))) uvec32; >+typedef uint8_t __attribute__((vector_size(16))) uvec8; >+typedef int16_t __attribute__((vector_size(32))) lvec16; >+typedef int32_t __attribute__((vector_size(32))) lvec32; >+typedef int8_t __attribute__((vector_size(32))) lvec8; >+typedef uint16_t __attribute__((vector_size(32))) ulvec16; >+typedef uint32_t __attribute__((vector_size(32))) ulvec32; >+typedef uint8_t __attribute__((vector_size(32))) ulvec8; > #else > #define SIMD_ALIGNED(var) var >-typedef int16 vec16[8]; >-typedef int32 vec32[4]; >-typedef int8 vec8[16]; >-typedef uint16 uvec16[8]; >-typedef uint32 uvec32[4]; >-typedef uint8 uvec8[16]; >-typedef int16 lvec16[16]; >-typedef int32 lvec32[8]; >-typedef int8 lvec8[32]; >-typedef uint16 ulvec16[16]; >-typedef uint32 ulvec32[8]; >-typedef uint8 ulvec8[32]; >+typedef int16_t vec16[8]; >+typedef int32_t vec32[4]; >+typedef int8_t vec8[16]; >+typedef uint16_t uvec16[8]; >+typedef uint32_t uvec32[4]; >+typedef uint8_t uvec8[16]; >+typedef int16_t lvec16[16]; >+typedef int32_t lvec32[8]; >+typedef int8_t lvec8[32]; >+typedef uint16_t ulvec16[16]; >+typedef uint32_t ulvec32[8]; >+typedef uint8_t ulvec8[32]; > #endif > > #if defined(__aarch64__) >@@ -560,13 +533,13 @@ struct YuvConstants { > #else > // This struct is for Intel color conversion. > struct YuvConstants { >- int8 kUVToB[32]; >- int8 kUVToG[32]; >- int8 kUVToR[32]; >- int16 kUVBiasB[16]; >- int16 kUVBiasG[16]; >- int16 kUVBiasR[16]; >- int16 kYToRgb[16]; >+ int8_t kUVToB[32]; >+ int8_t kUVToG[32]; >+ int8_t kUVToR[32]; >+ int16_t kUVBiasB[16]; >+ int16_t kUVBiasG[16]; >+ int16_t kUVBiasR[16]; >+ int16_t kYToRgb[16]; > }; > > // Offsets into YuvConstants structure >@@ -589,6 +562,16 @@ extern const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants); // BT.601 > extern const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants); // JPeg > extern const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants); // BT.709 > >+#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a)-1))) >+ >+#define align_buffer_64(var, size) \ >+ uint8_t* var##_mem = (uint8_t*)(malloc((size) + 63)); /* NOLINT */ \ >+ uint8_t* var = (uint8_t*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */ >+ >+#define free_aligned_buffer_64(var) \ >+ free(var##_mem); \ >+ var = 0 >+ > #if defined(__APPLE__) || defined(__x86_64__) || defined(__llvm__) > #define OMITFP > #else >@@ -601,62 +584,6 @@ extern const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants); // BT.709 > #else > #define LABELALIGN > #endif >-#if defined(__native_client__) && defined(__x86_64__) >-// r14 is used for MEMOP macros. >-#define NACL_R14 "r14", >-#define BUNDLELOCK ".bundle_lock\n" >-#define BUNDLEUNLOCK ".bundle_unlock\n" >-#define MEMACCESS(base) "%%nacl:(%%r15,%q" #base ")" >-#define MEMACCESS2(offset, base) "%%nacl:" #offset "(%%r15,%q" #base ")" >-#define MEMLEA(offset, base) #offset "(%q" #base ")" >-#define MEMLEA3(offset, index, scale) #offset "(,%q" #index "," #scale ")" >-#define MEMLEA4(offset, base, index, scale) \ >- #offset "(%q" #base ",%q" #index "," #scale ")" >-#define MEMMOVESTRING(s, d) "%%nacl:(%q" #s "),%%nacl:(%q" #d "), %%r15" >-#define MEMSTORESTRING(reg, d) "%%" #reg ",%%nacl:(%q" #d "), %%r15" >-#define MEMOPREG(opcode, offset, base, index, scale, reg) \ >- BUNDLELOCK \ >- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" #opcode \ >- " (%%r15,%%r14),%%" #reg "\n" BUNDLEUNLOCK >-#define MEMOPMEM(opcode, reg, offset, base, index, scale) \ >- BUNDLELOCK \ >- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" #opcode \ >- " %%" #reg ",(%%r15,%%r14)\n" BUNDLEUNLOCK >-#define MEMOPARG(opcode, offset, base, index, scale, arg) \ >- BUNDLELOCK \ >- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" #opcode \ >- " (%%r15,%%r14),%" #arg "\n" BUNDLEUNLOCK >-#define VMEMOPREG(opcode, offset, base, index, scale, reg1, reg2) \ >- BUNDLELOCK \ >- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" #opcode \ >- " (%%r15,%%r14),%%" #reg1 ",%%" #reg2 "\n" BUNDLEUNLOCK >-#define VEXTOPMEM(op, sel, reg, offset, base, index, scale) \ >- BUNDLELOCK \ >- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" #op \ >- " $" #sel ",%%" #reg ",(%%r15,%%r14)\n" BUNDLEUNLOCK >-#else // defined(__native_client__) && defined(__x86_64__) >-#define NACL_R14 >-#define BUNDLEALIGN >-#define MEMACCESS(base) "(%" #base ")" >-#define MEMACCESS2(offset, base) #offset "(%" #base ")" >-#define MEMLEA(offset, base) #offset "(%" #base ")" >-#define MEMLEA3(offset, index, scale) #offset "(,%" #index "," #scale ")" >-#define MEMLEA4(offset, base, index, scale) \ >- #offset "(%" #base ",%" #index "," #scale ")" >-#define MEMMOVESTRING(s, d) >-#define MEMSTORESTRING(reg, d) >-#define MEMOPREG(opcode, offset, base, index, scale, reg) \ >- #opcode " " #offset "(%" #base ",%" #index "," #scale "),%%" #reg "\n" >-#define MEMOPMEM(opcode, reg, offset, base, index, scale) \ >- #opcode " %%" #reg "," #offset "(%" #base ",%" #index "," #scale ")\n" >-#define MEMOPARG(opcode, offset, base, index, scale, arg) \ >- #opcode " " #offset "(%" #base ",%" #index "," #scale "),%" #arg "\n" >-#define VMEMOPREG(opcode, offset, base, index, scale, reg1, reg2) \ >- #opcode " " #offset "(%" #base ",%" #index "," #scale "),%%" #reg1 \ >- ",%%" #reg2 "\n" >-#define VEXTOPMEM(op, sel, reg, offset, base, index, scale) \ >- #op " $" #sel ",%%" #reg "," #offset "(%" #base ",%" #index "," #scale ")\n" >-#endif // defined(__native_client__) && defined(__x86_64__) > > // Intel Code Analizer markers. Insert IACA_START IACA_END around code to be > // measured and then run with iaca -64 libyuv_unittest. >@@ -709,2583 +636,2743 @@ extern const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants); // BT.709 > IACA_UD_BYTES \ > } > >-void I444ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_NEON(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_NEON(const uint8* src_yuy2, >- uint8* dst_argb, >+void NV12ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void NV21ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void YUY2ToARGBRow_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_NEON(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGB4444Row_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGB1555Row_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >- const struct YuvConstants* yuvconstants, >- int width); >-void NV12ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); > >-void I422ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_MSA(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB565Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_MSA(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_MSA(const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_MSA(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_MSA(const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); > >-void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width); >-void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_SSSE3(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_SSSE3(const uint8* src_raw, uint8* dst_y, int width); >-void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYRow_MSA(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_MSA(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToUV444Row_NEON(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToUVRow_NEON(const uint8* src_argb, >+void ARGBToYRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void ARGBToYRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void ARGBToYJRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void ARGBToYJRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYJRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void BGRAToYRow_SSSE3(const uint8_t* src_bgra, uint8_t* dst_y, int width); >+void ABGRToYRow_SSSE3(const uint8_t* src_abgr, uint8_t* dst_y, int width); >+void RGBAToYRow_SSSE3(const uint8_t* src_rgba, uint8_t* dst_y, int width); >+void RGB24ToYRow_SSSE3(const uint8_t* src_rgb24, uint8_t* dst_y, int width); >+void RAWToYRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_y, int width); >+void ARGBToYRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void ARGBToYJRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width); >+void ARGBToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void ARGBToYJRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void ARGBToUV444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void ARGBToUVRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUV444Row_MSA(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_MSA(const uint8* src_argb, >+void ARGBToUVRow_MSA(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_NEON(const uint8* src_argb, >+void ARGBToUVJRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_NEON(const uint8* src_bgra, >+void BGRAToUVRow_NEON(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_NEON(const uint8* src_abgr, >+void ABGRToUVRow_NEON(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_NEON(const uint8* src_rgba, >+void RGBAToUVRow_NEON(const uint8_t* src_rgba, > int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB24ToUVRow_NEON(const uint8* src_rgb24, >+void RGB24ToUVRow_NEON(const uint8_t* src_rgb24, > int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RAWToUVRow_NEON(const uint8* src_raw, >+void RAWToUVRow_NEON(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB565ToUVRow_NEON(const uint8* src_rgb565, >+void RGB565ToUVRow_NEON(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, >+void ARGB1555ToUVRow_NEON(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, >+void ARGB4444ToUVRow_NEON(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_MSA(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_MSA(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+void BGRAToUVRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_MSA(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+void ABGRToUVRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_MSA(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+void RGBAToUVRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB24ToUVRow_MSA(const uint8* src_rgb24, >- int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+void RGB24ToUVRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RAWToUVRow_MSA(const uint8* src_raw, >- int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+void RAWToUVRow_MSA(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB565ToUVRow_MSA(const uint8* src_rgb565, >+void RGB565ToUVRow_MSA(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB1555ToUVRow_MSA(const uint8* src_argb1555, >+void ARGB1555ToUVRow_MSA(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int width); >-void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int width); >-void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int width); >-void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int width); >-void BGRAToYRow_MSA(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_MSA(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_MSA(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_MSA(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_MSA(const uint8* src_raw, uint8* dst_y, int width); >-void RGB565ToYRow_MSA(const uint8* src_rgb565, uint8* dst_y, int width); >-void ARGB1555ToYRow_MSA(const uint8* src_argb1555, uint8* dst_y, int width); >-void BGRAToUVRow_DSPR2(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void BGRAToYRow_DSPR2(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToUVRow_DSPR2(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToYRow_DSPR2(const uint8* src_argb, uint8* dst_y, int width); >-void ABGRToYRow_DSPR2(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToUVRow_DSPR2(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void RGBAToYRow_DSPR2(const uint8* src_rgba, uint8* dst_y, int width); >-void ARGBToUVRow_DSPR2(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToYRow_C(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_C(const uint8* src_argb, uint8* dst_y, int width); >-void BGRAToYRow_C(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_C(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_C(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_C(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_C(const uint8* src_raw, uint8* dst_y, int width); >-void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int width); >-void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int width); >-void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int width); >-void ARGBToYRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int width); >-void BGRAToYRow_Any_SSSE3(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_Any_SSSE3(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_Any_SSSE3(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_Any_SSSE3(const uint8* src_raw, uint8* dst_y, int width); >-void ARGBToYRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYJRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int width); >-void BGRAToYRow_Any_NEON(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_Any_NEON(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_Any_NEON(const uint8* src_rgba, uint8* dst_y, int width); >-void RGB24ToYRow_Any_NEON(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_Any_NEON(const uint8* src_raw, uint8* dst_y, int width); >-void RGB565ToYRow_Any_NEON(const uint8* src_rgb565, uint8* dst_y, int width); >-void ARGB1555ToYRow_Any_NEON(const uint8* src_argb1555, >- uint8* dst_y, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void BGRAToYRow_NEON(const uint8_t* src_bgra, uint8_t* dst_y, int width); >+void ABGRToYRow_NEON(const uint8_t* src_abgr, uint8_t* dst_y, int width); >+void RGBAToYRow_NEON(const uint8_t* src_rgba, uint8_t* dst_y, int width); >+void RGB24ToYRow_NEON(const uint8_t* src_rgb24, uint8_t* dst_y, int width); >+void RAWToYRow_NEON(const uint8_t* src_raw, uint8_t* dst_y, int width); >+void RGB565ToYRow_NEON(const uint8_t* src_rgb565, uint8_t* dst_y, int width); >+void ARGB1555ToYRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_y, >+ int width); >+void ARGB4444ToYRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_y, >+ int width); >+void BGRAToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void ABGRToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGBAToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGB24ToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RAWToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGB565ToYRow_MSA(const uint8_t* src_rgb565, uint8_t* dst_y, int width); >+void ARGB1555ToYRow_MSA(const uint8_t* src_argb1555, uint8_t* dst_y, int width); >+void ARGBToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void ARGBToYJRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void BGRAToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void ABGRToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGBAToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGB24ToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RAWToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width); >+void RGB565ToYRow_C(const uint8_t* src_rgb565, uint8_t* dst_y, int width); >+void ARGB1555ToYRow_C(const uint8_t* src_argb1555, uint8_t* dst_y, int width); >+void ARGB4444ToYRow_C(const uint8_t* src_argb4444, uint8_t* dst_y, int width); >+void ARGBToYRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYJRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void BGRAToYRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ABGRToYRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGBAToYRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB24ToYRow_Any_SSSE3(const uint8_t* src_rgb24, uint8_t* dst_y, int width); >+void RAWToYRow_Any_SSSE3(const uint8_t* src_raw, uint8_t* dst_y, int width); >+void ARGBToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYJRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void BGRAToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ABGRToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGBAToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB24ToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RAWToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB565ToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGB1555ToYRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void BGRAToYRow_Any_DSPR2(const uint8* src_bgra, uint8* dst_y, int width); >-void ARGBToYRow_Any_DSPR2(const uint8* src_argb, uint8* dst_y, int width); >-void ABGRToYRow_Any_DSPR2(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_Any_DSPR2(const uint8* src_rgba, uint8* dst_y, int width); >-void ARGB4444ToYRow_Any_NEON(const uint8* src_argb4444, >- uint8* dst_y, >+void ARGB4444ToYRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void BGRAToYRow_Any_MSA(const uint8* src_bgra, uint8* dst_y, int width); >-void ABGRToYRow_Any_MSA(const uint8* src_abgr, uint8* dst_y, int width); >-void RGBAToYRow_Any_MSA(const uint8* src_rgba, uint8* dst_y, int width); >-void ARGBToYJRow_Any_MSA(const uint8* src_argb, uint8* dst_y, int width); >-void ARGBToYRow_Any_MSA(const uint8* src_argb, uint8* dst_y, int width); >-void RGB24ToYRow_Any_MSA(const uint8* src_rgb24, uint8* dst_y, int width); >-void RAWToYRow_Any_MSA(const uint8* src_raw, uint8* dst_y, int width); >-void RGB565ToYRow_Any_MSA(const uint8* src_rgb565, uint8* dst_y, int width); >-void ARGB1555ToYRow_Any_MSA(const uint8* src_argb1555, uint8* dst_y, int width); >- >-void ARGBToUVRow_AVX2(const uint8* src_argb, >+void BGRAToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ABGRToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGBAToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYJRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB24ToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RAWToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB565ToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGB1555ToYRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+ >+void ARGBToUVRow_AVX2(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_AVX2(const uint8* src_argb, >+void ARGBToUVJRow_AVX2(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_SSSE3(const uint8* src_argb, >+void ARGBToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_SSSE3(const uint8* src_argb, >+void ARGBToUVJRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_SSSE3(const uint8* src_bgra, >+void BGRAToUVRow_SSSE3(const uint8_t* src_bgra0, > int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_SSSE3(const uint8* src_abgr, >+void ABGRToUVRow_SSSE3(const uint8_t* src_abgr0, > int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_SSSE3(const uint8* src_rgba, >+void RGBAToUVRow_SSSE3(const uint8_t* src_rgba0, > int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_Any_AVX2(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVRow_Any_AVX2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_Any_AVX2(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_Any_AVX2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_Any_SSSE3(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVRow_Any_SSSE3(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_Any_SSSE3(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void BGRAToUVRow_Any_SSSE3(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_Any_SSSE3(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void BGRAToUVRow_Any_SSSE3(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_Any_SSSE3(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+void ABGRToUVRow_Any_SSSE3(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_Any_SSSE3(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+void RGBAToUVRow_Any_SSSE3(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUV444Row_Any_NEON(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_Any_NEON(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUV444Row_Any_MSA(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToUVRow_Any_MSA(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToUVJRow_Any_NEON(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void ARGBToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void ARGBToUVJRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_Any_NEON(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+void BGRAToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_Any_NEON(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+void ABGRToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_Any_NEON(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+void RGBAToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB24ToUVRow_Any_NEON(const uint8* src_rgb24, >- int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+void RGB24ToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RAWToUVRow_Any_NEON(const uint8* src_raw, >- int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void RGB565ToUVRow_Any_NEON(const uint8* src_rgb565, >- int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGB1555ToUVRow_Any_NEON(const uint8* src_argb1555, >- int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+void RAWToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void RGB565ToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void ARGB1555ToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB4444ToUVRow_Any_NEON(const uint8* src_argb4444, >- int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+void ARGB4444ToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_Any_MSA(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_Any_MSA(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ABGRToUVRow_Any_MSA(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void RGBAToUVRow_Any_MSA(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void RGB24ToUVRow_Any_MSA(const uint8* src_rgb24, >- int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+void BGRAToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void ABGRToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void RGBAToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void RGB24ToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RAWToUVRow_Any_MSA(const uint8* src_raw, >- int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+void RAWToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB565ToUVRow_Any_MSA(const uint8* src_rgb565, >- int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+void RGB565ToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB1555ToUVRow_Any_MSA(const uint8* src_argb1555, >- int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+void ARGB1555ToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_Any_DSPR2(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ABGRToUVRow_Any_DSPR2(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void RGBAToUVRow_Any_DSPR2(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToUVRow_Any_DSPR2(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void ARGBToUVRow_C(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_C(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVRow_C(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUVJRow_C(const uint8* src_argb, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUVJRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void BGRAToUVRow_C(const uint8* src_bgra, >- int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+void BGRAToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ABGRToUVRow_C(const uint8* src_abgr, >- int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+void ABGRToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGBAToUVRow_C(const uint8* src_rgba, >- int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+void RGBAToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB24ToUVRow_C(const uint8* src_rgb24, >- int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+void RGB24ToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RAWToUVRow_C(const uint8* src_raw, >- int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+void RAWToUVRow_C(const uint8_t* src_rgb0, >+ int src_stride_rgb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void RGB565ToUVRow_C(const uint8* src_rgb565, >+void RGB565ToUVRow_C(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB1555ToUVRow_C(const uint8* src_argb1555, >+void ARGB1555ToUVRow_C(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGB4444ToUVRow_C(const uint8* src_argb4444, >+void ARGB4444ToUVRow_C(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void ARGBToUV444Row_SSSE3(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void ARGBToUV444Row_Any_SSSE3(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void ARGBToUV444Row_C(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_C(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void MirrorRow_AVX2(const uint8* src, uint8* dst, int width); >-void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width); >-void MirrorRow_NEON(const uint8* src, uint8* dst, int width); >-void MirrorRow_DSPR2(const uint8* src, uint8* dst, int width); >-void MirrorRow_MSA(const uint8* src, uint8* dst, int width); >-void MirrorRow_C(const uint8* src, uint8* dst, int width); >-void MirrorRow_Any_AVX2(const uint8* src, uint8* dst, int width); >-void MirrorRow_Any_SSSE3(const uint8* src, uint8* dst, int width); >-void MirrorRow_Any_SSE2(const uint8* src, uint8* dst, int width); >-void MirrorRow_Any_NEON(const uint8* src, uint8* dst, int width); >-void MirrorRow_Any_MSA(const uint8* src, uint8* dst, int width); >- >-void MirrorUVRow_SSSE3(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_SSSE3(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_MSA(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_C(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void MirrorRow_Any_SSSE3(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void MirrorRow_Any_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void MirrorRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void MirrorRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+ >+void MirrorUVRow_SSSE3(const uint8_t* src, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void MirrorUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void MirrorUVRow_DSPR2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void MirrorUVRow_MSA(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_MSA(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width); >- >-void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_SSE2(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_MSA(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_Any_AVX2(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_Any_SSE2(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_Any_NEON(const uint8* src, uint8* dst, int width); >-void ARGBMirrorRow_Any_MSA(const uint8* src, uint8* dst, int width); >- >-void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width); >-void SplitUVRow_SSE2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_C(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+ >+void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBMirrorRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBMirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width); >+void ARGBMirrorRow_MSA(const uint8_t* src, uint8_t* dst, int width); >+void ARGBMirrorRow_C(const uint8_t* src, uint8_t* dst, int width); >+void ARGBMirrorRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBMirrorRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBMirrorRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBMirrorRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+ >+void SplitUVRow_C(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void SplitUVRow_SSE2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void SplitUVRow_AVX2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_AVX2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void SplitUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void SplitUVRow_DSPR2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void SplitUVRow_MSA(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width); >-void SplitUVRow_Any_SSE2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void SplitUVRow_Any_AVX2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void SplitUVRow_Any_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void SplitUVRow_Any_DSPR2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void SplitUVRow_Any_MSA(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_MSA(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void SplitUVRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void SplitUVRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void SplitUVRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void SplitUVRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void MergeUVRow_C(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_C(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width); >-void MergeUVRow_SSE2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_SSE2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width); >-void MergeUVRow_AVX2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_AVX2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width); >-void MergeUVRow_NEON(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_NEON(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width); >-void MergeUVRow_MSA(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_MSA(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width); >-void MergeUVRow_Any_SSE2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void MergeUVRow_Any_AVX2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void MergeUVRow_Any_NEON(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void MergeUVRow_Any_MSA(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); > >-void SplitRGBRow_C(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_C(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width); >-void SplitRGBRow_SSSE3(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_SSSE3(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width); >-void SplitRGBRow_NEON(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_NEON(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width); >-void SplitRGBRow_Any_SSSE3(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width); >-void SplitRGBRow_Any_NEON(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width); > >-void MergeRGBRow_C(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_C(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width); >-void MergeRGBRow_SSSE3(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_SSSE3(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width); >-void MergeRGBRow_NEON(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_NEON(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width); >-void MergeRGBRow_Any_SSSE3(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > int width); >-void MergeRGBRow_Any_NEON(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_Any_NEON(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width); > >-void MergeUVRow_16_C(const uint16* src_u, >- const uint16* src_v, >- uint16* dst_uv, >+void MergeUVRow_16_C(const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint16_t* dst_uv, > int scale, /* 64 for 10 bit */ > int width); >-void MergeUVRow_16_AVX2(const uint16* src_u, >- const uint16* src_v, >- uint16* dst_uv, >+void MergeUVRow_16_AVX2(const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint16_t* dst_uv, > int scale, > int width); > >-void MultiplyRow_16_AVX2(const uint16* src_y, >- uint16* dst_y, >+void MultiplyRow_16_AVX2(const uint16_t* src_y, >+ uint16_t* dst_y, > int scale, > int width); >-void MultiplyRow_16_C(const uint16* src_y, uint16* dst_y, int scale, int width); >- >-void CopyRow_SSE2(const uint8* src, uint8* dst, int count); >-void CopyRow_AVX(const uint8* src, uint8* dst, int count); >-void CopyRow_ERMS(const uint8* src, uint8* dst, int count); >-void CopyRow_NEON(const uint8* src, uint8* dst, int count); >-void CopyRow_MIPS(const uint8* src, uint8* dst, int count); >-void CopyRow_C(const uint8* src, uint8* dst, int count); >-void CopyRow_Any_SSE2(const uint8* src, uint8* dst, int count); >-void CopyRow_Any_AVX(const uint8* src, uint8* dst, int count); >-void CopyRow_Any_NEON(const uint8* src, uint8* dst, int count); >- >-void CopyRow_16_C(const uint16* src, uint16* dst, int count); >- >-void ARGBCopyAlphaRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBCopyAlphaRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBCopyAlphaRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBCopyAlphaRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+void MultiplyRow_16_C(const uint16_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width); >+ >+void Convert8To16Row_C(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width); >+void Convert8To16Row_SSE2(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width); >+void Convert8To16Row_AVX2(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width); >+void Convert8To16Row_Any_SSE2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int scale, >+ int width); >+void Convert8To16Row_Any_AVX2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int scale, >+ int width); >+ >+void Convert16To8Row_C(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width); >+void Convert16To8Row_SSSE3(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width); >+void Convert16To8Row_AVX2(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width); >+void Convert16To8Row_Any_SSSE3(const uint16_t* src_ptr, >+ uint8_t* dst_ptr, >+ int scale, > int width); >-void ARGBCopyAlphaRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void Convert16To8Row_Any_AVX2(const uint16_t* src_ptr, >+ uint8_t* dst_ptr, >+ int scale, >+ int width); >+ >+void CopyRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void CopyRow_AVX(const uint8_t* src, uint8_t* dst, int width); >+void CopyRow_ERMS(const uint8_t* src, uint8_t* dst, int width); >+void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width); >+void CopyRow_MIPS(const uint8_t* src, uint8_t* dst, int count); >+void CopyRow_C(const uint8_t* src, uint8_t* dst, int count); >+void CopyRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void CopyRow_Any_AVX(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void CopyRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+ >+void CopyRow_16_C(const uint16_t* src, uint16_t* dst, int count); >+ >+void ARGBCopyAlphaRow_C(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyAlphaRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBCopyAlphaRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void ARGBExtractAlphaRow_C(const uint8* src_argb, uint8* dst_a, int width); >-void ARGBExtractAlphaRow_SSE2(const uint8* src_argb, uint8* dst_a, int width); >-void ARGBExtractAlphaRow_AVX2(const uint8* src_argb, uint8* dst_a, int width); >-void ARGBExtractAlphaRow_NEON(const uint8* src_argb, uint8* dst_a, int width); >-void ARGBExtractAlphaRow_MSA(const uint8* src_argb, uint8* dst_a, int width); >-void ARGBExtractAlphaRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_a, >+void ARGBExtractAlphaRow_C(const uint8_t* src_argb, uint8_t* dst_a, int width); >+void ARGBExtractAlphaRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width); >+void ARGBExtractAlphaRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width); >+void ARGBExtractAlphaRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width); >+void ARGBExtractAlphaRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width); >+void ARGBExtractAlphaRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBExtractAlphaRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_a, >+void ARGBExtractAlphaRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBExtractAlphaRow_Any_NEON(const uint8* src_argb, >- uint8* dst_a, >+void ARGBExtractAlphaRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBExtractAlphaRow_Any_MSA(const uint8* src_argb, >- uint8* dst_a, >+void ARGBExtractAlphaRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void ARGBCopyYToAlphaRow_C(const uint8* src_y, uint8* dst_argb, int width); >-void ARGBCopyYToAlphaRow_SSE2(const uint8* src_y, uint8* dst_argb, int width); >-void ARGBCopyYToAlphaRow_AVX2(const uint8* src_y, uint8* dst_argb, int width); >-void ARGBCopyYToAlphaRow_Any_SSE2(const uint8* src_y, >- uint8* dst_argb, >+void ARGBCopyYToAlphaRow_C(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyYToAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyYToAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBCopyYToAlphaRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBCopyYToAlphaRow_Any_AVX2(const uint8* src_y, >- uint8* dst_argb, >+void ARGBCopyYToAlphaRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void SetRow_C(uint8* dst, uint8 v8, int count); >-void SetRow_MSA(uint8* dst, uint8 v8, int count); >-void SetRow_X86(uint8* dst, uint8 v8, int count); >-void SetRow_ERMS(uint8* dst, uint8 v8, int count); >-void SetRow_NEON(uint8* dst, uint8 v8, int count); >-void SetRow_Any_X86(uint8* dst, uint8 v8, int count); >-void SetRow_Any_NEON(uint8* dst, uint8 v8, int count); >- >-void ARGBSetRow_C(uint8* dst_argb, uint32 v32, int count); >-void ARGBSetRow_X86(uint8* dst_argb, uint32 v32, int count); >-void ARGBSetRow_NEON(uint8* dst_argb, uint32 v32, int count); >-void ARGBSetRow_Any_NEON(uint8* dst_argb, uint32 v32, int count); >-void ARGBSetRow_MSA(uint8* dst_argb, uint32 v32, int count); >-void ARGBSetRow_Any_MSA(uint8* dst_argb, uint32 v32, int count); >+void SetRow_C(uint8_t* dst, uint8_t v8, int width); >+void SetRow_MSA(uint8_t* dst, uint8_t v8, int width); >+void SetRow_X86(uint8_t* dst, uint8_t v8, int width); >+void SetRow_ERMS(uint8_t* dst, uint8_t v8, int width); >+void SetRow_NEON(uint8_t* dst, uint8_t v8, int width); >+void SetRow_Any_X86(uint8_t* dst_ptr, uint8_t v32, int width); >+void SetRow_Any_NEON(uint8_t* dst_ptr, uint8_t v32, int width); >+ >+void ARGBSetRow_C(uint8_t* dst_argb, uint32_t v32, int width); >+void ARGBSetRow_X86(uint8_t* dst_argb, uint32_t v32, int width); >+void ARGBSetRow_NEON(uint8_t* dst, uint32_t v32, int width); >+void ARGBSetRow_Any_NEON(uint8_t* dst_ptr, uint32_t v32, int width); >+void ARGBSetRow_MSA(uint8_t* dst_argb, uint32_t v32, int width); >+void ARGBSetRow_Any_MSA(uint8_t* dst_ptr, uint32_t v32, int width); > > // ARGBShufflers for BGRAToARGB etc. >-void ARGBShuffleRow_C(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width); >-void ARGBShuffleRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >- int width); >-void ARGBShuffleRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width); >-void ARGBShuffleRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width); >-void ARGBShuffleRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width); >-void ARGBShuffleRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width); >-void ARGBShuffleRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >- int width); >-void ARGBShuffleRow_Any_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint8_t* param, > int width); >-void ARGBShuffleRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint8_t* param, > int width); >-void ARGBShuffleRow_Any_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint8_t* param, > int width); >-void ARGBShuffleRow_Any_MSA(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >- int width); >- >-void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToRGB24Row_SSSE3(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, uint8* dst_argb, int width); >-void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, >- uint8* dst_argb, >- int width); >-void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, >- uint8* dst_argb, >- int width); >-void RGB565ToARGBRow_AVX2(const uint8* src_rgb565, uint8* dst_argb, int width); >-void ARGB1555ToARGBRow_AVX2(const uint8* src_argb1555, >- uint8* dst_argb, >- int width); >-void ARGB4444ToARGBRow_AVX2(const uint8* src_argb4444, >- uint8* dst_argb, >- int width); >- >-void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RGB24ToARGBRow_MSA(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToARGBRow_MSA(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToRGB24Row_NEON(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RAWToRGB24Row_MSA(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int width); >-void RGB565ToARGBRow_MSA(const uint8* src_rgb565, uint8* dst_argb, int width); >-void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, >- uint8* dst_argb, >- int width); >-void ARGB1555ToARGBRow_MSA(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGBShuffleRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint8_t* param, >+ int width); >+ >+void RGB24ToARGBRow_SSSE3(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width); >+void RAWToARGBRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_argb, int width); >+void RAWToRGB24Row_SSSE3(const uint8_t* src_raw, uint8_t* dst_rgb24, int width); >+void RGB565ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGB1555ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGB4444ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void RGB565ToARGBRow_AVX2(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width); >+void ARGB1555ToARGBRow_AVX2(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, >+ int width); >+void ARGB4444ToARGBRow_AVX2(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, >+ int width); >+ >+void RGB24ToARGBRow_NEON(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width); >+void RGB24ToARGBRow_MSA(const uint8_t* src_rgb24, uint8_t* dst_argb, int width); >+void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width); >+void RAWToARGBRow_MSA(const uint8_t* src_raw, uint8_t* dst_argb, int width); >+void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width); >+void RAWToRGB24Row_MSA(const uint8_t* src_raw, uint8_t* dst_rgb24, int width); >+void RGB565ToARGBRow_NEON(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width); >+void RGB565ToARGBRow_MSA(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width); >+void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, >+ int width); >+void ARGB1555ToARGBRow_MSA(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width); >-void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, >- uint8* dst_argb, >- int width); >-void RGB24ToARGBRow_DSPR2(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RAWToARGBRow_DSPR2(const uint8* src_raw, uint8* dst_argb, int width); >-void RGB565ToARGBRow_DSPR2(const uint8* src_rgb565, uint8* dst_argb, int width); >-void ARGB1555ToARGBRow_DSPR2(const uint8* src_argb1555, >- uint8* dst_argb, >- int width); >-void ARGB4444ToARGBRow_DSPR2(const uint8* src_argb4444, >- uint8* dst_argb, >- int width); >-void ARGB4444ToARGBRow_MSA(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, >+ int width); >+void ARGB4444ToARGBRow_MSA(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width); >-void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToRGB24Row_C(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RGB565ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int width); >-void ARGB1555ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGB4444ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void RGB24ToARGBRow_Any_SSSE3(const uint8* src_rgb24, >- uint8* dst_argb, >+void RGB24ToARGBRow_C(const uint8_t* src_rgb24, uint8_t* dst_argb, int width); >+void RAWToARGBRow_C(const uint8_t* src_raw, uint8_t* dst_argb, int width); >+void RAWToRGB24Row_C(const uint8_t* src_raw, uint8_t* dst_rgb24, int width); >+void RGB565ToARGBRow_C(const uint8_t* src_rgb565, uint8_t* dst_argb, int width); >+void ARGB1555ToARGBRow_C(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, >+ int width); >+void ARGB4444ToARGBRow_C(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, >+ int width); >+void AR30ToARGBRow_C(const uint8_t* src_ar30, uint8_t* dst_argb, int width); >+void AR30ToABGRRow_C(const uint8_t* src_ar30, uint8_t* dst_abgr, int width); >+void ARGBToAR30Row_C(const uint8_t* src_argb, uint8_t* dst_ar30, int width); >+void AR30ToAB30Row_C(const uint8_t* src_ar30, uint8_t* dst_ab30, int width); >+ >+void RGB24ToARGBRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void RAWToARGBRow_Any_SSSE3(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToRGB24Row_Any_SSSE3(const uint8* src_raw, uint8* dst_rgb24, int width); >+void RAWToARGBRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void RAWToRGB24Row_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); > >-void RGB565ToARGBRow_Any_SSE2(const uint8* src_rgb565, >- uint8* dst_argb, >+void RGB565ToARGBRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB1555ToARGBRow_Any_SSE2(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB4444ToARGBRow_Any_SSE2(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void RGB565ToARGBRow_Any_AVX2(const uint8* src_rgb565, >- uint8* dst_argb, >+void RGB565ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB1555ToARGBRow_Any_AVX2(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB4444ToARGBRow_Any_AVX2(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void RGB24ToARGBRow_Any_NEON(const uint8* src_rgb24, >- uint8* dst_argb, >+void RGB24ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void RGB24ToARGBRow_Any_MSA(const uint8* src_rgb24, uint8* dst_argb, int width); >-void RAWToARGBRow_Any_NEON(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToARGBRow_Any_MSA(const uint8* src_raw, uint8* dst_argb, int width); >-void RAWToRGB24Row_Any_NEON(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RAWToRGB24Row_Any_MSA(const uint8* src_raw, uint8* dst_rgb24, int width); >-void RGB565ToARGBRow_Any_NEON(const uint8* src_rgb565, >- uint8* dst_argb, >+void RGB24ToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void RAWToARGBRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RAWToARGBRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RAWToRGB24Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void RAWToRGB24Row_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void RGB565ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void RGB565ToARGBRow_Any_MSA(const uint8* src_rgb565, >- uint8* dst_argb, >+void RGB565ToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB1555ToARGBRow_Any_NEON(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB1555ToARGBRow_Any_MSA(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGB4444ToARGBRow_Any_NEON(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void RGB24ToARGBRow_Any_DSPR2(const uint8* src_rgb24, >- uint8* dst_argb, >- int width); >-void RAWToARGBRow_Any_DSPR2(const uint8* src_raw, uint8* dst_argb, int width); >-void RGB565ToARGBRow_Any_DSPR2(const uint8* src_rgb565, >- uint8* dst_argb, >- int width); >-void ARGB1555ToARGBRow_Any_DSPR2(const uint8* src_argb1555, >- uint8* dst_argb, >- int width); >-void ARGB4444ToARGBRow_Any_DSPR2(const uint8* src_argb4444, >- uint8* dst_argb, >- int width); > >-void ARGB4444ToARGBRow_Any_MSA(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void ARGBToRGB24Row_SSSE3(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_SSSE3(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB4444Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int width); >- >-void ARGBToRGB565DitherRow_C(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB24Row_SSSE3(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToRAWRow_SSSE3(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToRGB565Row_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToARGB1555Row_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToARGB4444Row_SSE2(const uint8_t* src, uint8_t* dst, int width); >+void ABGRToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width); >+ >+void ARGBToRGB565DitherRow_C(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width); >-void ARGBToRGB565DitherRow_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_SSE2(const uint8_t* src, >+ uint8_t* dst, >+ const uint32_t dither4, > int width); >-void ARGBToRGB565DitherRow_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_AVX2(const uint8_t* src, >+ uint8_t* dst, >+ const uint32_t dither4, > int width); > >-void ARGBToRGB565Row_AVX2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_AVX2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB4444Row_AVX2(const uint8* src_argb, uint8* dst_rgb, int width); >- >-void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565DitherRow_NEON(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565Row_AVX2(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToARGB1555Row_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width); >+void ARGBToARGB4444Row_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width); >+void ABGRToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width); >+void ARGBToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width); >+ >+void ARGBToRGB24Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb24, >+ int width); >+void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width); >+void ARGBToRGB565Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb565, >+ int width); >+void ARGBToARGB1555Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb1555, >+ int width); >+void ARGBToARGB4444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb4444, >+ int width); >+void ARGBToRGB565DitherRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width); >-void ARGBToRGB24Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB4444Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565DitherRow_MSA(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB24Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToRAWRow_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToRGB565Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToARGB1555Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width); >+void ARGBToARGB4444Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width); >+void ARGBToRGB565DitherRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width); > >-void ARGBToRGBARow_C(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int width); >- >-void J400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_AVX2(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_MSA(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_Any_SSE2(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_Any_AVX2(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_Any_NEON(const uint8* src_y, uint8* dst_argb, int width); >-void J400ToARGBRow_Any_MSA(const uint8* src_y, uint8* dst_argb, int width); >- >-void I444ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void ARGBToRGBARow_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToRGB24Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToRAWRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToRGB565Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToARGB1555Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ARGBToARGB4444Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width); >+void ABGRToAR30Row_C(const uint8_t* src_abgr, uint8_t* dst_ar30, int width); >+void ARGBToAR30Row_C(const uint8_t* src_argb, uint8_t* dst_ar30, int width); >+ >+void J400ToARGBRow_SSE2(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void J400ToARGBRow_AVX2(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void J400ToARGBRow_MSA(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void J400ToARGBRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void J400ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void J400ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void J400ToARGBRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+ >+void I444ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422ToAR30Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I210ToAR30Row_C(const uint16_t* src_y, >+ const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I210ToARGBRow_C(const uint16_t* src_y, >+ const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_C(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_C(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_C(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_C(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV21ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_C(const uint8* src_yuy2, >- uint8* dst_argb, >+void NV12ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void NV21ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void YUY2ToARGBRow_C(const uint8_t* src_yuy2, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_C(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_C(const uint8_t* src_uyvy, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB1555Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGBARow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width); >+ >+void I422ToAR30Row_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ar30, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I210ToAR30Row_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToARGBRow_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422ToAR30Row_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToARGBRow_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToAR30Row_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422AlphaToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void NV12ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV21ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV21ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_SSSE3(const uint8_t* yuy2_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_SSSE3(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_SSSE3(const uint8_t* uyvy_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_AVX2(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_AVX2(const uint8_t* yuy2_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_AVX2(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_AVX2(const uint8_t* uyvy_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB4444Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB4444Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB1555Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB1555Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB565Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB565Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGBARow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422ToAR30Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToAR30Row_Any_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_Any_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I210ToARGBRow_Any_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422ToAR30Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToARGBRow_Any_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I210ToAR30Row_Any_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void I422AlphaToARGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_Any_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_Any_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_Any_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_Any_SSSE3(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_Any_AVX2(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_Any_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_Any_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_Any_SSSE3(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_Any_SSSE3(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_Any_AVX2(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_Any_AVX2(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToARGB4444Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToARGB4444Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToARGB1555Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToARGB1555Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGB565Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGB565Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_Any_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB24Row_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_Any_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB24Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); > >-void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_AVX2(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_MSA(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_Any_SSE2(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_Any_AVX2(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_Any_NEON(const uint8* src_y, uint8* dst_argb, int width); >-void I400ToARGBRow_Any_MSA(const uint8* src_y, uint8* dst_argb, int width); >+void I400ToARGBRow_C(const uint8_t* src_y, uint8_t* rgb_buf, int width); >+void I400ToARGBRow_SSE2(const uint8_t* y_buf, uint8_t* dst_argb, int width); >+void I400ToARGBRow_AVX2(const uint8_t* y_buf, uint8_t* dst_argb, int width); >+void I400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void I400ToARGBRow_MSA(const uint8_t* src_y, uint8_t* dst_argb, int width); >+void I400ToARGBRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void I400ToARGBRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void I400ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void I400ToARGBRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); > > // ARGB preattenuated alpha blend. >-void ARGBBlendRow_SSSE3(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_SSSE3(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBBlendRow_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBBlendRow_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBBlendRow_C(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); > > // Unattenuated planar alpha blend. >-void BlendPlaneRow_SSSE3(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >- int width); >-void BlendPlaneRow_Any_SSSE3(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_SSSE3(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, >+ int width); >+void BlendPlaneRow_Any_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > int width); >-void BlendPlaneRow_AVX2(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_AVX2(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width); >-void BlendPlaneRow_Any_AVX2(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >- int width); >-void BlendPlaneRow_C(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void BlendPlaneRow_C(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width); > > // ARGB multiply images. Same API as Blend, but these require > // pointer and width alignment for SSE2. >-void ARGBMultiplyRow_C(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBMultiplyRow_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBMultiplyRow_Any_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBMultiplyRow_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBMultiplyRow_Any_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBMultiplyRow_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBMultiplyRow_Any_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBMultiplyRow_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBMultiplyRow_Any_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); > > // ARGB add images. >-void ARGBAddRow_C(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBAddRow_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBAddRow_Any_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBAddRow_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBAddRow_Any_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBAddRow_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBAddRow_Any_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBAddRow_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBAddRow_Any_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); > > // ARGB subtract images. Same API as Blend, but these require > // pointer and width alignment for SSE2. >-void ARGBSubtractRow_C(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBSubtractRow_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBSubtractRow_Any_SSE2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBSubtractRow_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBSubtractRow_Any_AVX2(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBSubtractRow_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBSubtractRow_Any_NEON(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void ARGBSubtractRow_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width); >-void ARGBSubtractRow_Any_MSA(const uint8* src_argb, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); > >-void ARGBToRGB24Row_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_Any_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToRGB24Row_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToRAWRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToRGB565Row_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToARGB1555Row_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToARGB4444Row_Any_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToARGB4444Row_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >+void ABGRToAR30Row_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToAR30Row_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); > >-void ARGBToRGB565DitherRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint32_t param, > int width); >-void ARGBToRGB565DitherRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint32_t param, > int width); > >-void ARGBToRGB565Row_Any_AVX2(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_Any_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToRGB565Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToARGB1555Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToARGB4444Row_Any_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToARGB4444Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >+void ABGRToAR30Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToAR30Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); > >-void ARGBToRGB24Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_Any_NEON(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToRGB24Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToRAWRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToRGB565Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToARGB1555Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToARGB4444Row_Any_NEON(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToARGB4444Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToRGB565DitherRow_Any_NEON(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint32_t param, > int width); >-void ARGBToRGB24Row_Any_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRAWRow_Any_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToRGB565Row_Any_MSA(const uint8* src_argb, uint8* dst_rgb, int width); >-void ARGBToARGB1555Row_Any_MSA(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToRGB24Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToRAWRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void ARGBToRGB565Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ int width); >+void ARGBToARGB1555Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToARGB4444Row_Any_MSA(const uint8* src_argb, >- uint8* dst_rgb, >+void ARGBToARGB4444Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBToRGB565DitherRow_Any_MSA(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, >+ const uint32_t param, > int width); > >-void I444ToARGBRow_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* dst_argb, >+void I422AlphaToARGBRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGBARow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB24Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB4444Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGB1555Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGB565Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_Any_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_Any_NEON(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_Any_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB24Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void NV21ToRGB24Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, >+ const struct YuvConstants* yuvconstants, >+ int width); >+void NV12ToRGB565Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_Any_NEON(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_Any_NEON(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I444ToARGBRow_Any_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGB4444Row_Any_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGBRow_Any_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGB1555Row_Any_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I411ToARGBRow_Any_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void NV12ToARGBRow_Any_DSPR2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I422ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width); >-void I444ToARGBRow_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGBRow_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGBARow_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToRGBARow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422AlphaToARGBRow_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* dst_argb, >+void I422AlphaToARGBRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB24Row_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToRGB565Row_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB4444Row_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void I422ToARGB1555Row_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToARGBRow_Any_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV12ToRGB565Row_Any_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToRGB565Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void NV21ToARGBRow_Any_MSA(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void YUY2ToARGBRow_Any_MSA(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); >-void UYVYToARGBRow_Any_MSA(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > const struct YuvConstants* yuvconstants, > int width); > >-void YUY2ToYRow_AVX2(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_AVX2(const uint8* src_yuy2, >+void YUY2ToYRow_AVX2(const uint8_t* src_yuy2, uint8_t* dst_y, int width); >+void YUY2ToUVRow_AVX2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_AVX2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_SSE2(const uint8* src_yuy2, >+void YUY2ToYRow_SSE2(const uint8_t* src_yuy2, uint8_t* dst_y, int width); >+void YUY2ToUVRow_SSE2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_SSE2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_NEON(const uint8* src_yuy2, >+void YUY2ToYRow_NEON(const uint8_t* src_yuy2, uint8_t* dst_y, int width); >+void YUY2ToUVRow_NEON(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_NEON(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void YUY2ToYRow_MSA(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_MSA(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void YUY2ToYRow_MSA(const uint8_t* src_yuy2, uint8_t* dst_y, int width); >+void YUY2ToUVRow_MSA(const uint8_t* src_yuy2, >+ int src_stride_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_MSA(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_MSA(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_C(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToYRow_C(const uint8_t* src_yuy2, uint8_t* dst_y, int width); >+void YUY2ToUVRow_C(const uint8_t* src_yuy2, >+ int src_stride_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_C(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_C(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_Any_AVX2(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_Any_AVX2(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToYRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void YUY2ToUVRow_Any_AVX2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_Any_AVX2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_Any_SSE2(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_Any_SSE2(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToYRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void YUY2ToUVRow_Any_SSE2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_Any_SSE2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_Any_NEON(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_Any_NEON(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void YUY2ToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToUV422Row_Any_NEON(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void YUY2ToYRow_Any_MSA(const uint8* src_yuy2, uint8* dst_y, int width); >-void YUY2ToUVRow_Any_MSA(const uint8* src_yuy2, >- int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void YUY2ToUV422Row_Any_MSA(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_AVX2(const uint8* src_uyvy, >+void YUY2ToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void YUY2ToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void YUY2ToUV422Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void UYVYToYRow_AVX2(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_AVX2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_AVX2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_AVX2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_SSE2(const uint8* src_uyvy, >+void UYVYToYRow_SSE2(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_SSE2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_SSE2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_SSE2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_AVX2(const uint8* src_uyvy, >+void UYVYToYRow_AVX2(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_AVX2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_AVX2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_AVX2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_NEON(const uint8* src_uyvy, >+void UYVYToYRow_NEON(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_NEON(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_NEON(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >- int width); >-void UYVYToYRow_MSA(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_MSA(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width); >+void UYVYToYRow_MSA(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_MSA(const uint8_t* src_uyvy, >+ int src_stride_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_MSA(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_MSA(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_C(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToYRow_C(const uint8_t* src_uyvy, uint8_t* dst_y, int width); >+void UYVYToUVRow_C(const uint8_t* src_uyvy, >+ int src_stride_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_C(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_C(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_Any_AVX2(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_Any_AVX2(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToYRow_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void UYVYToUVRow_Any_AVX2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_Any_AVX2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_Any_SSE2(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_Any_SSE2(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToYRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void UYVYToUVRow_Any_SSE2(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_Any_SSE2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_Any_NEON(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_Any_NEON(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToYRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void UYVYToUVRow_Any_NEON(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_Any_NEON(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToYRow_Any_MSA(const uint8* src_uyvy, uint8* dst_y, int width); >-void UYVYToUVRow_Any_MSA(const uint8* src_uyvy, >- int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToYRow_Any_MSA(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); >+void UYVYToUVRow_Any_MSA(const uint8_t* src_ptr, >+ int src_stride_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); >-void UYVYToUV422Row_Any_MSA(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width); > >-void I422ToYUY2Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width); >-void I422ToUYVYRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width); >-void I422ToYUY2Row_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width); >-void I422ToUYVYRow_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width); >-void I422ToYUY2Row_Any_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >- int width); >-void I422ToUYVYRow_Any_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >- int width); >-void I422ToYUY2Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToUYVYRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToYUY2Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, >+ int width); >+void I422ToUYVYRow_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, >+ int width); >+void I422ToYUY2Row_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToUYVYRow_Any_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToYUY2Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width); >-void I422ToUYVYRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width); >-void I422ToYUY2Row_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >- int width); >-void I422ToUYVYRow_Any_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >- int width); >-void I422ToYUY2Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToUYVYRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, >+ int width); >+void I422ToYUY2Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width); >-void I422ToUYVYRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width); >-void I422ToYUY2Row_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > int width); >-void I422ToUYVYRow_Any_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ptr, > int width); > > // Effects related row functions. >-void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBAttenuateRow_MSA(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBAttenuateRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_argb, >- int width); >-void ARGBAttenuateRow_Any_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBAttenuateRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width); >+void ARGBAttenuateRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBAttenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBAttenuateRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBAttenuateRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBAttenuateRow_Any_SSSE3(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBAttenuateRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBAttenuateRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBAttenuateRow_Any_NEON(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBAttenuateRow_Any_NEON(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBAttenuateRow_Any_MSA(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBAttenuateRow_Any_MSA(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > > // Inverse table for unattenuate, shared by C and SSE2. >-extern const uint32 fixed_invtbl8[256]; >-void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBUnattenuateRow_Any_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+extern const uint32_t fixed_invtbl8[256]; >+void ARGBUnattenuateRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBUnattenuateRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width); >+void ARGBUnattenuateRow_Any_SSE2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); >-void ARGBUnattenuateRow_Any_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBUnattenuateRow_Any_AVX2(const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > int width); > >-void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width); >-void ARGBGrayRow_MSA(const uint8* src_argb, uint8* dst_argb, int width); >+void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width); >+void ARGBGrayRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_argb, int width); >+void ARGBGrayRow_NEON(const uint8_t* src_argb, uint8_t* dst_argb, int width); >+void ARGBGrayRow_MSA(const uint8_t* src_argb, uint8_t* dst_argb, int width); > >-void ARGBSepiaRow_C(uint8* dst_argb, int width); >-void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width); >-void ARGBSepiaRow_NEON(uint8* dst_argb, int width); >-void ARGBSepiaRow_MSA(uint8* dst_argb, int width); >+void ARGBSepiaRow_C(uint8_t* dst_argb, int width); >+void ARGBSepiaRow_SSSE3(uint8_t* dst_argb, int width); >+void ARGBSepiaRow_NEON(uint8_t* dst_argb, int width); >+void ARGBSepiaRow_MSA(uint8_t* dst_argb, int width); > >-void ARGBColorMatrixRow_C(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width); >-void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width); >-void ARGBColorMatrixRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width); >-void ARGBColorMatrixRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width); > >-void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width); >-void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width); >+void ARGBColorTableRow_C(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width); >+void ARGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width); > >-void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width); >-void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width); >+void RGBColorTableRow_C(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width); >+void RGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width); > >-void ARGBQuantizeRow_C(uint8* dst_argb, >+void ARGBQuantizeRow_C(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, > int width); >-void ARGBQuantizeRow_SSE2(uint8* dst_argb, >+void ARGBQuantizeRow_SSE2(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, > int width); >-void ARGBQuantizeRow_NEON(uint8* dst_argb, >+void ARGBQuantizeRow_NEON(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, > int width); >-void ARGBQuantizeRow_MSA(uint8* dst_argb, >+void ARGBQuantizeRow_MSA(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, > int width); > >-void ARGBShadeRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value); >-void ARGBShadeRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+ uint32_t value); >+void ARGBShadeRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value); >-void ARGBShadeRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >+ uint32_t value); >+void ARGBShadeRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value); >-void ARGBShadeRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >+ uint32_t value); >+void ARGBShadeRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value); >+ uint32_t value); > > // Used for blur. >-void CumulativeSumToAverageRow_SSE2(const int32* topleft, >- const int32* botleft, >+void CumulativeSumToAverageRow_SSE2(const int32_t* topleft, >+ const int32_t* botleft, > int width, > int area, >- uint8* dst, >+ uint8_t* dst, > int count); >-void ComputeCumulativeSumRow_SSE2(const uint8* row, >- int32* cumsum, >- const int32* previous_cumsum, >+void ComputeCumulativeSumRow_SSE2(const uint8_t* row, >+ int32_t* cumsum, >+ const int32_t* previous_cumsum, > int width); > >-void CumulativeSumToAverageRow_C(const int32* topleft, >- const int32* botleft, >- int width, >+void CumulativeSumToAverageRow_C(const int32_t* tl, >+ const int32_t* bl, >+ int w, > int area, >- uint8* dst, >+ uint8_t* dst, > int count); >-void ComputeCumulativeSumRow_C(const uint8* row, >- int32* cumsum, >- const int32* previous_cumsum, >+void ComputeCumulativeSumRow_C(const uint8_t* row, >+ int32_t* cumsum, >+ const int32_t* previous_cumsum, > int width); > > LIBYUV_API >-void ARGBAffineRow_C(const uint8* src_argb, >+void ARGBAffineRow_C(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* uv_dudv, > int width); > LIBYUV_API >-void ARGBAffineRow_SSE2(const uint8* src_argb, >+void ARGBAffineRow_SSE2(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >- const float* uv_dudv, >+ uint8_t* dst_argb, >+ const float* src_dudv, > int width); > > // Used for I420Scale, ARGBScale, and ARGBInterpolate. >-void InterpolateRow_C(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >+void InterpolateRow_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, >+ ptrdiff_t src_stride, > int width, > int source_y_fraction); >-void InterpolateRow_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >- int width, >+void InterpolateRow_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, >+ ptrdiff_t src_stride, >+ int dst_width, > int source_y_fraction); >-void InterpolateRow_AVX2(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >- int width, >+void InterpolateRow_AVX2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, >+ ptrdiff_t src_stride, >+ int dst_width, > int source_y_fraction); >-void InterpolateRow_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >- int width, >+void InterpolateRow_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, >+ ptrdiff_t src_stride, >+ int dst_width, > int source_y_fraction); >-void InterpolateRow_DSPR2(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >- int width, >- int source_y_fraction); >-void InterpolateRow_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >+void InterpolateRow_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, >+ ptrdiff_t src_stride, > int width, > int source_y_fraction); >-void InterpolateRow_Any_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_Any_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride_ptr, > int width, > int source_y_fraction); >-void InterpolateRow_Any_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_Any_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride_ptr, > int width, > int source_y_fraction); >-void InterpolateRow_Any_AVX2(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_Any_AVX2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride_ptr, > int width, > int source_y_fraction); >-void InterpolateRow_Any_DSPR2(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride_ptr, >- int width, >- int source_y_fraction); >-void InterpolateRow_Any_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_Any_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride_ptr, > int width, > int source_y_fraction); > >-void InterpolateRow_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >- ptrdiff_t src_stride_ptr, >+void InterpolateRow_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, >+ ptrdiff_t src_stride, > int width, > int source_y_fraction); > > // Sobel images. >-void SobelXRow_C(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_C(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width); >-void SobelXRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width); >-void SobelXRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width); >-void SobelXRow_MSA(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_MSA(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width); >-void SobelYRow_C(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_C(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width); >-void SobelYRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width); >-void SobelYRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width); >-void SobelYRow_MSA(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_MSA(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width); >-void SobelRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelToPlaneRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width); >-void SobelToPlaneRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width); >-void SobelToPlaneRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width); >-void SobelToPlaneRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width); >-void SobelXYRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelXYRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelXYRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelXYRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width); >-void SobelRow_Any_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelRow_Any_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelRow_Any_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelToPlaneRow_Any_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelToPlaneRow_Any_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelToPlaneRow_Any_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelXYRow_Any_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_Any_SSE2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelXYRow_Any_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_Any_NEON(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); >-void SobelXYRow_Any_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_Any_MSA(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_ptr, > int width); > >-void ARGBPolynomialRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width); >-void ARGBPolynomialRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width); >-void ARGBPolynomialRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width); > > // Scale and convert to half float. >-void HalfFloatRow_C(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_SSE2(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_Any_SSE2(const uint16* src, >- uint16* dst, >- float scale, >+void HalfFloatRow_C(const uint16_t* src, uint16_t* dst, float scale, int width); >+void HalfFloatRow_SSE2(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloatRow_Any_SSE2(const uint16_t* src_ptr, >+ uint16_t* dst_ptr, >+ float param, > int width); >-void HalfFloatRow_AVX2(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_Any_AVX2(const uint16* src, >- uint16* dst, >- float scale, >+void HalfFloatRow_AVX2(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloatRow_Any_AVX2(const uint16_t* src_ptr, >+ uint16_t* dst_ptr, >+ float param, > int width); >-void HalfFloatRow_F16C(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_Any_F16C(const uint16* src, >- uint16* dst, >+void HalfFloatRow_F16C(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloatRow_Any_F16C(const uint16_t* src, >+ uint16_t* dst, > float scale, > int width); >-void HalfFloat1Row_F16C(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloat1Row_Any_F16C(const uint16* src, >- uint16* dst, >+void HalfFloat1Row_F16C(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloat1Row_Any_F16C(const uint16_t* src, >+ uint16_t* dst, > float scale, > int width); >-void HalfFloatRow_NEON(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_Any_NEON(const uint16* src, >- uint16* dst, >- float scale, >+void HalfFloatRow_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloatRow_Any_NEON(const uint16_t* src_ptr, >+ uint16_t* dst_ptr, >+ float param, > int width); >-void HalfFloat1Row_NEON(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloat1Row_Any_NEON(const uint16* src, >- uint16* dst, >- float scale, >+void HalfFloat1Row_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloat1Row_Any_NEON(const uint16_t* src_ptr, >+ uint16_t* dst_ptr, >+ float param, > int width); >-void HalfFloatRow_MSA(const uint16* src, uint16* dst, float scale, int width); >-void HalfFloatRow_Any_MSA(const uint16* src, >- uint16* dst, >- float scale, >+void HalfFloatRow_MSA(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width); >+void HalfFloatRow_Any_MSA(const uint16_t* src_ptr, >+ uint16_t* dst_ptr, >+ float param, > int width); >+void ByteToFloatRow_C(const uint8_t* src, float* dst, float scale, int width); >+void ByteToFloatRow_NEON(const uint8_t* src, >+ float* dst, >+ float scale, >+ int width); >+void ByteToFloatRow_Any_NEON(const uint8_t* src, >+ float* dst, >+ float scale, >+ int width); > >-void ARGBLumaColorTableRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBLumaColorTableRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- const uint8* luma, >- uint32 lumacoeff); >-void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* luma, >+ uint32_t lumacoeff); >+void ARGBLumaColorTableRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- const uint8* luma, >- uint32 lumacoeff); >+ const uint8_t* luma, >+ uint32_t lumacoeff); > > float ScaleMaxSamples_C(const float* src, float* dst, float scale, int width); > float ScaleMaxSamples_NEON(const float* src, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale.h >index 6d6b9a8583a..b937d348cab 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale.h >@@ -28,22 +28,22 @@ typedef enum FilterMode { > > // Scale a YUV plane. > LIBYUV_API >-void ScalePlane(const uint8* src, >+void ScalePlane(const uint8_t* src, > int src_stride, > int src_width, > int src_height, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int dst_width, > int dst_height, > enum FilterMode filtering); > > LIBYUV_API >-void ScalePlane_16(const uint16* src, >+void ScalePlane_16(const uint16_t* src, > int src_stride, > int src_width, > int src_height, >- uint16* dst, >+ uint16_t* dst, > int dst_stride, > int dst_width, > int dst_height, >@@ -60,38 +60,38 @@ void ScalePlane_16(const uint16* src, > // Returns 0 if successful. > > LIBYUV_API >-int I420Scale(const uint8* src_y, >+int I420Scale(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, > int src_width, > int src_height, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int dst_width, > int dst_height, > enum FilterMode filtering); > > LIBYUV_API >-int I420Scale_16(const uint16* src_y, >+int I420Scale_16(const uint16_t* src_y, > int src_stride_y, >- const uint16* src_u, >+ const uint16_t* src_u, > int src_stride_u, >- const uint16* src_v, >+ const uint16_t* src_v, > int src_stride_v, > int src_width, > int src_height, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, >- uint16* dst_u, >+ uint16_t* dst_u, > int dst_stride_u, >- uint16* dst_v, >+ uint16_t* dst_v, > int dst_stride_v, > int dst_width, > int dst_height, >@@ -100,17 +100,17 @@ int I420Scale_16(const uint16* src_y, > #ifdef __cplusplus > // Legacy API. Deprecated. > LIBYUV_API >-int Scale(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >+int Scale(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, > int src_stride_y, > int src_stride_u, > int src_stride_v, > int src_width, > int src_height, >- uint8* dst_y, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_y, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int dst_stride_y, > int dst_stride_u, > int dst_stride_v, >@@ -118,17 +118,6 @@ int Scale(const uint8* src_y, > int dst_height, > LIBYUV_BOOL interpolate); > >-// Legacy API. Deprecated. >-LIBYUV_API >-int ScaleOffset(const uint8* src_i420, >- int src_width, >- int src_height, >- uint8* dst_i420, >- int dst_width, >- int dst_height, >- int dst_yoffset, >- LIBYUV_BOOL interpolate); >- > // For testing, allow disabling of specialized scalers. > LIBYUV_API > void SetUseReferenceImpl(LIBYUV_BOOL use); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_argb.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_argb.h >index 3d25e579cde..7641f18e341 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_argb.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_argb.h >@@ -20,11 +20,11 @@ extern "C" { > #endif > > LIBYUV_API >-int ARGBScale(const uint8* src_argb, >+int ARGBScale(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -32,11 +32,11 @@ int ARGBScale(const uint8* src_argb, > > // Clipped scale takes destination rectangle coordinates for clip values. > LIBYUV_API >-int ARGBScaleClip(const uint8* src_argb, >+int ARGBScaleClip(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -48,18 +48,18 @@ int ARGBScaleClip(const uint8* src_argb, > > // Scale with YUV conversion to ARGB and clipping. > LIBYUV_API >-int YUVToARGBScaleClip(const uint8* src_y, >+int YUVToARGBScaleClip(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint32 src_fourcc, >+ uint32_t src_fourcc, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- uint32 dst_fourcc, >+ uint32_t dst_fourcc, > int dst_width, > int dst_height, > int clip_x, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_row.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_row.h >index c4a66aa07b1..7194ba09f84 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_row.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/scale_row.h >@@ -19,17 +19,20 @@ namespace libyuv { > extern "C" { > #endif > >-#if defined(__pnacl__) || defined(__CLR_VER) || \ >+#if defined(__pnacl__) || defined(__CLR_VER) || \ >+ (defined(__native_client__) && defined(__x86_64__)) || \ > (defined(__i386__) && !defined(__SSE__) && !defined(__clang__)) > #define LIBYUV_DISABLE_X86 > #endif >+#if defined(__native_client__) >+#define LIBYUV_DISABLE_NEON >+#endif > // MemorySanitizer does not support assembly code yet. http://crbug.com/344505 > #if defined(__has_feature) > #if __has_feature(memory_sanitizer) > #define LIBYUV_DISABLE_X86 > #endif > #endif >- > // GCC >= 4.7.0 required for AVX2. > #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) > #if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7)) >@@ -81,7 +84,7 @@ extern "C" { > #endif > > // The following are available on Neon platforms: >-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \ >+#if !defined(LIBYUV_DISABLE_NEON) && \ > (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__)) > #define HAS_SCALEARGBCOLS_NEON > #define HAS_SCALEARGBROWDOWN2_NEON >@@ -94,16 +97,6 @@ extern "C" { > #define HAS_SCALEARGBFILTERCOLS_NEON > #endif > >-// The following are available on Mips platforms: >-#if !defined(LIBYUV_DISABLE_DSPR2) && !defined(__native_client__) && \ >- defined(__mips__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2) >-#define HAS_SCALEROWDOWN2_DSPR2 >-#define HAS_SCALEROWDOWN4_DSPR2 >-#define HAS_SCALEROWDOWN34_DSPR2 >-#define HAS_SCALEROWDOWN38_DSPR2 >-#define HAS_SCALEADDROW_DSPR2 >-#endif >- > #if !defined(LIBYUV_DISABLE_MSA) && defined(__mips_msa) > #define HAS_SCALEADDROW_MSA > #define HAS_SCALEARGBCOLS_MSA >@@ -123,8 +116,8 @@ void ScalePlaneVertical(int src_height, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int y, > int dy, >@@ -136,8 +129,8 @@ void ScalePlaneVertical_16(int src_height, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_argb, >- uint16* dst_argb, >+ const uint16_t* src_argb, >+ uint16_t* dst_argb, > int x, > int y, > int dy, >@@ -176,425 +169,431 @@ void ScaleSlope(int src_width, > int* dx, > int* dy); > >-void ScaleRowDown2_C(const uint8* src_ptr, >+void ScaleRowDown2_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2_16_C(const uint16* src_ptr, >+void ScaleRowDown2_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown2Linear_C(const uint8* src_ptr, >+void ScaleRowDown2Linear_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2Linear_16_C(const uint16* src_ptr, >+void ScaleRowDown2Linear_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown2Box_C(const uint8* src_ptr, >+void ScaleRowDown2Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2Box_Odd_C(const uint8* src_ptr, >+void ScaleRowDown2Box_Odd_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2Box_16_C(const uint16* src_ptr, >+void ScaleRowDown2Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown4_C(const uint8* src_ptr, >+void ScaleRowDown4_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown4_16_C(const uint16* src_ptr, >+void ScaleRowDown4_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown4Box_C(const uint8* src_ptr, >+void ScaleRowDown4Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown4Box_16_C(const uint16* src_ptr, >+void ScaleRowDown4Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown34_C(const uint8* src_ptr, >+void ScaleRowDown34_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown34_16_C(const uint16* src_ptr, >+void ScaleRowDown34_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown34_0_Box_C(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width); >-void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown34_0_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* d, >+ uint16_t* d, > int dst_width); >-void ScaleRowDown34_1_Box_C(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width); >-void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown34_1_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* d, >+ uint16_t* d, > int dst_width); >-void ScaleCols_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleCols_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleCols_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleCols_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleColsUp2_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleColsUp2_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int, > int); >-void ScaleColsUp2_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleColsUp2_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int, > int); >-void ScaleFilterCols_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleFilterCols_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleFilterCols_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleFilterCols64_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols64_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, >- int x, >+ int x32, > int dx); >-void ScaleFilterCols64_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleFilterCols64_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, >- int x, >+ int x32, > int dx); >-void ScaleRowDown38_C(const uint8* src_ptr, >+void ScaleRowDown38_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown38_16_C(const uint16* src_ptr, >+void ScaleRowDown38_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-void ScaleRowDown38_3_Box_C(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown38_3_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_2_Box_C(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown38_2_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int dst_width); >-void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_16_C(const uint16* src_ptr, uint32* dst_ptr, int src_width); >-void ScaleARGBRowDown2_C(const uint8* src_argb, >+void ScaleAddRow_C(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width); >+void ScaleAddRow_16_C(const uint16_t* src_ptr, >+ uint32_t* dst_ptr, >+ int src_width); >+void ScaleARGBRowDown2_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2Linear_C(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2Box_C(const uint8* src_argb, >+void ScaleARGBRowDown2Box_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEven_C(const uint8* src_argb, >+void ScaleARGBRowDownEven_C(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEvenBox_C(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_C(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBCols_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBCols64_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols64_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, >- int x, >+ int x32, > int dx); >-void ScaleARGBColsUp2_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBColsUp2_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int, > int); >-void ScaleARGBFilterCols_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols64_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols64_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, >- int x, >+ int x32, > int dx); > > // Specialized scalers for x86. >-void ScaleRowDown2_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Linear_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2_AVX2(const uint8* src_ptr, >+void ScaleRowDown2_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Linear_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4_AVX2(const uint8* src_ptr, >+void ScaleRowDown4_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_AVX2(const uint8* src_ptr, >+void ScaleRowDown4Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleRowDown34_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Linear_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Linear_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Odd_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Box_Odd_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2_Any_AVX2(const uint8* src_ptr, >+void ScaleRowDown2_Any_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Linear_Any_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Linear_Any_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Any_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Box_Any_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Odd_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Box_Odd_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4_Any_AVX2(const uint8* src_ptr, >+void ScaleRowDown4_Any_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_Any_AVX2(const uint8* src_ptr, >+void ScaleRowDown4Box_Any_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleRowDown34_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_1_Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_0_Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_3_Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown38_2_Box_Any_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_Any_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleAddRow_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_Any_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_Any_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width); >- >-void ScaleFilterCols_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleAddRow_SSE2(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width); >+void ScaleAddRow_AVX2(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width); >+void ScaleAddRow_Any_SSE2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int src_width); >+void ScaleAddRow_Any_AVX2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int src_width); >+ >+void ScaleFilterCols_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleColsUp2_SSE2(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleColsUp2_SSE2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); > > // ARGB Column functions >-void ScaleARGBCols_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_SSSE3(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBColsUp2_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBColsUp2_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols_Any_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_Any_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleARGBCols_Any_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_Any_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_MSA(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBCols_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_MSA(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx); >-void ScaleARGBFilterCols_Any_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_Any_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleARGBCols_Any_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_Any_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); > > // ARGB Row functions >-void ScaleARGBRowDown2_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Box_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); > void ScaleARGBRowDown2_MSA(const uint8_t* src_argb, > ptrdiff_t src_stride, >@@ -608,274 +607,231 @@ void ScaleARGBRowDown2Box_MSA(const uint8_t* src_argb, > ptrdiff_t src_stride, > uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDown2_Any_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2_Any_SSE2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Linear_Any_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_Any_SSE2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Box_Any_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Box_Any_SSE2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2_Any_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Linear_Any_NEON(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Box_Any_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2_Any_MSA(const uint8_t* src_argb, >+void ScaleARGBRowDown2_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Linear_Any_MSA(const uint8_t* src_argb, >+void ScaleARGBRowDown2Linear_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDown2Box_Any_MSA(const uint8_t* src_argb, >+void ScaleARGBRowDown2Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEven_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEven_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); > void ScaleARGBRowDownEven_MSA(const uint8_t* src_argb, > ptrdiff_t src_stride, > int32_t src_stepx, > uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEvenBox_MSA(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_MSA(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width); >-void ScaleARGBRowDownEven_Any_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEven_Any_SSE2(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDownEvenBox_Any_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_Any_SSE2(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDownEven_Any_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEven_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDownEvenBox_Any_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDownEven_Any_MSA(const uint8_t* src_argb, >+void ScaleARGBRowDownEven_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int32_t src_stepx, >- uint8_t* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleARGBRowDownEvenBox_Any_MSA(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_ptr, > int dst_width); > > // ScaleRowDown2Box also used by planar functions > // NEON downscalers with interpolation. > > // Note - not static due to reuse in convert for 444 to 420. >-void ScaleRowDown2_NEON(const uint8* src_ptr, >+void ScaleRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2Linear_NEON(const uint8* src_ptr, >+void ScaleRowDown2Linear_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width); > >-void ScaleRowDown4_NEON(const uint8* src_ptr, >+void ScaleRowDown4_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_NEON(const uint8* src_ptr, >+void ScaleRowDown4Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > > // Down scale from 4 to 3 pixels. Use the neon multilane read/write > // to load up the every 4th pixel into a 4 different registers. > // Point samples 32 pixels to 24 pixels. >-void ScaleRowDown34_NEON(const uint8* src_ptr, >+void ScaleRowDown34_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > > // 32 -> 12 >-void ScaleRowDown38_NEON(const uint8* src_ptr, >+void ScaleRowDown38_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > // 32x3 -> 12x1 >-void ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > // 32x2 -> 12x1 >-void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleRowDown2_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown2_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Linear_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown2Linear_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown2Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown2Box_Odd_NEON(const uint8* src_ptr, >+void ScaleRowDown2Box_Odd_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown4_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown4Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown4Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown34_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_0_Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_1_Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > // 32 -> 12 >-void ScaleRowDown38_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown38_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > // 32x3 -> 12x1 >-void ScaleRowDown38_3_Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > // 32x2 -> 12x1 >-void ScaleRowDown38_2_Box_Any_NEON(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_Any_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > >-void ScaleAddRow_NEON(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_Any_NEON(const uint8* src_ptr, uint16* dst_ptr, int src_width); >+void ScaleAddRow_NEON(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width); >+void ScaleAddRow_Any_NEON(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int src_width); > >-void ScaleFilterCols_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); > >-void ScaleFilterCols_Any_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_Any_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); > >-void ScaleRowDown2_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown2Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown4_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown4Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown34_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown34_0_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* d, >- int dst_width); >-void ScaleRowDown34_1_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* d, >- int dst_width); >-void ScaleRowDown38_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width); >-void ScaleRowDown38_2_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst_ptr, >- int dst_width); >-void ScaleRowDown38_3_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst_ptr, >- int dst_width); >-void ScaleAddRow_DSPR2(const uint8* src_ptr, uint16* dst_ptr, int src_width); >-void ScaleAddRow_Any_DSPR2(const uint8* src_ptr, >- uint16* dst_ptr, >- int src_width); >- > void ScaleRowDown2_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, > uint8_t* dst, >@@ -909,47 +865,47 @@ void ScaleRowDown38_3_Box_MSA(const uint8_t* src_ptr, > uint8_t* dst_ptr, > int dst_width); > void ScaleAddRow_MSA(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width); >-void ScaleFilterCols_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleRowDown34_MSA(const uint8* src_ptr, >+void ScaleRowDown34_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst, > int dst_width); >-void ScaleRowDown34_0_Box_MSA(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* d, > int dst_width); >-void ScaleRowDown34_1_Box_MSA(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* d, > int dst_width); > > void ScaleRowDown2_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown2Linear_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown2Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown4_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown4Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown38_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8_t* dst, >+ uint8_t* dst_ptr, > int dst_width); > void ScaleRowDown38_2_Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >@@ -962,22 +918,22 @@ void ScaleRowDown38_3_Box_Any_MSA(const uint8_t* src_ptr, > void ScaleAddRow_Any_MSA(const uint8_t* src_ptr, > uint16_t* dst_ptr, > int src_width); >-void ScaleFilterCols_Any_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_Any_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx); >-void ScaleRowDown34_Any_MSA(const uint8* src_ptr, >+void ScaleRowDown34_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_0_Box_Any_MSA(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); >-void ScaleRowDown34_1_Box_Any_MSA(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_Any_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width); > > #ifdef __cplusplus >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/version.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/version.h >index 838c70f1349..21522cf351c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/version.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/version.h >@@ -11,6 +11,6 @@ > #ifndef INCLUDE_LIBYUV_VERSION_H_ > #define INCLUDE_LIBYUV_VERSION_H_ > >-#define LIBYUV_VERSION 1678 >+#define LIBYUV_VERSION 1703 > > #endif // INCLUDE_LIBYUV_VERSION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/video_common.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/video_common.h >index f3711c423ba..bcef378b5a4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/video_common.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/include/libyuv/video_common.h >@@ -28,13 +28,13 @@ extern "C" { > // Needs to be a macro otherwise the OS X compiler complains when the kFormat* > // constants are used in a switch. > #ifdef __cplusplus >-#define FOURCC(a, b, c, d) \ >- ((static_cast<uint32>(a)) | (static_cast<uint32>(b) << 8) | \ >- (static_cast<uint32>(c) << 16) | (static_cast<uint32>(d) << 24)) >+#define FOURCC(a, b, c, d) \ >+ ((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) | \ >+ (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24)) > #else >-#define FOURCC(a, b, c, d) \ >- (((uint32)(a)) | ((uint32)(b) << 8) | /* NOLINT */ \ >- ((uint32)(c) << 16) | ((uint32)(d) << 24)) /* NOLINT */ >+#define FOURCC(a, b, c, d) \ >+ (((uint32_t)(a)) | ((uint32_t)(b) << 8) | /* NOLINT */ \ >+ ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) /* NOLINT */ > #endif > > // Some pages discussing FourCC codes: >@@ -49,25 +49,26 @@ extern "C" { > // Secondary formats are converted in 2 steps. > // Auxilliary formats call primary converters. > enum FourCC { >- // 8 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. >+ // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. > FOURCC_I420 = FOURCC('I', '4', '2', '0'), > FOURCC_I422 = FOURCC('I', '4', '2', '2'), > FOURCC_I444 = FOURCC('I', '4', '4', '4'), >- FOURCC_I411 = FOURCC('I', '4', '1', '1'), // deprecated. > FOURCC_I400 = FOURCC('I', '4', '0', '0'), > FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), > FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), > FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), > FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), >+ FOURCC_H010 = FOURCC('H', '0', '1', '0'), // unofficial fourcc. 10 bit lsb > > // 1 Secondary YUV format: row biplanar. > FOURCC_M420 = FOURCC('M', '4', '2', '0'), >- FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), // deprecated. > >- // 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp. >+ // 11 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc > FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), > FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), > FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), >+ FOURCC_AR30 = FOURCC('A', 'R', '3', '0'), // 10 bit per channel. 2101010. >+ FOURCC_AB30 = FOURCC('A', 'B', '3', '0'), // ABGR version of 10 bit > FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), > FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), > FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), >@@ -75,16 +76,10 @@ enum FourCC { > FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 LE. > FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 LE. > >- // 4 Secondary RGB formats: 4 Bayer Patterns. deprecated. >- FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), >- FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), >- FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), >- FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), >- > // 1 Primary Compressed YUV format. > FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), > >- // 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. >+ // 7 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. > FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), > FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), > FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), >@@ -112,7 +107,13 @@ enum FourCC { > FOURCC_L565 = FOURCC('L', '5', '6', '5'), // Alias for RGBP. > FOURCC_5551 = FOURCC('5', '5', '5', '1'), // Alias for RGBO. > >- // 1 Auxiliary compressed YUV format set aside for capturer. >+ // deprecated formats. Not supported, but defined for backward compatibility. >+ FOURCC_I411 = FOURCC('I', '4', '1', '1'), >+ FOURCC_Q420 = FOURCC('Q', '4', '2', '0'), >+ FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'), >+ FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'), >+ FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'), >+ FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'), > FOURCC_H264 = FOURCC('H', '2', '6', '4'), > > // Match any fourcc. >@@ -136,6 +137,8 @@ enum FourCCBpp { > FOURCC_BPP_BGRA = 32, > FOURCC_BPP_ABGR = 32, > FOURCC_BPP_RGBA = 32, >+ FOURCC_BPP_AR30 = 32, >+ FOURCC_BPP_AB30 = 32, > FOURCC_BPP_24BG = 24, > FOURCC_BPP_RAW = 24, > FOURCC_BPP_RGBP = 16, >@@ -152,6 +155,7 @@ enum FourCCBpp { > FOURCC_BPP_J420 = 12, > FOURCC_BPP_J400 = 8, > FOURCC_BPP_H420 = 12, >+ FOURCC_BPP_H010 = 24, > FOURCC_BPP_MJPG = 0, // 0 means unknown. > FOURCC_BPP_H264 = 0, > FOURCC_BPP_IYUV = 12, >@@ -174,7 +178,7 @@ enum FourCCBpp { > }; > > // Converts fourcc aliases into canonical ones. >-LIBYUV_API uint32 CanonicalFourCC(uint32 fourcc); >+LIBYUV_API uint32_t CanonicalFourCC(uint32_t fourcc); > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gyp b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gyp >index f73a1a4b745..e853ba3197a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gyp >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gyp >@@ -121,7 +121,6 @@ > # Enable the following 3 macros to turn off assembly for specified CPU. > # 'LIBYUV_DISABLE_X86', > # 'LIBYUV_DISABLE_NEON', >- # 'LIBYUV_DISABLE_DSPR2', > # Enable the following macro to build libyuv as a shared library (dll). > # 'LIBYUV_USING_SHARED_LIBRARY', > # TODO(fbarchard): Make these into gyp defines. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gypi b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gypi >index ec81bc9bbab..9467adfc515 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gypi >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv.gypi >@@ -55,7 +55,6 @@ > 'source/rotate_argb.cc', > 'source/rotate_common.cc', > 'source/rotate_gcc.cc', >- 'source/rotate_dspr2.cc', > 'source/rotate_msa.cc', > 'source/rotate_neon.cc', > 'source/rotate_neon64.cc', >@@ -63,7 +62,6 @@ > 'source/row_any.cc', > 'source/row_common.cc', > 'source/row_gcc.cc', >- 'source/row_dspr2.cc', > 'source/row_msa.cc', > 'source/row_neon.cc', > 'source/row_neon64.cc', >@@ -73,7 +71,6 @@ > 'source/scale_argb.cc', > 'source/scale_common.cc', > 'source/scale_gcc.cc', >- 'source/scale_dspr2.cc', > 'source/scale_msa.cc', > 'source/scale_neon.cc', > 'source/scale_neon64.cc', >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv_test.gyp b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv_test.gyp >index 4222cf26da7..5fe154c610a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv_test.gyp >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/libyuv_test.gyp >@@ -100,7 +100,6 @@ > # Enable the following 3 macros to turn off assembly for specified CPU. > # 'LIBYUV_DISABLE_X86', > # 'LIBYUV_DISABLE_NEON', >- # 'LIBYUV_DISABLE_DSPR2', > # Enable the following macro to build libyuv as a shared library (dll). > # 'LIBYUV_USING_SHARED_LIBRARY', > ], >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/linux.mk b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/linux.mk >index 7e9aa5e4e8b..b84c89f912e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/linux.mk >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/linux.mk >@@ -32,14 +32,12 @@ LOCAL_OBJ_FILES := \ > source/rotate.o \ > source/rotate_common.o \ > source/rotate_gcc.o \ >- source/rotate_dspr2.o \ > source/rotate_neon64.o \ > source/rotate_neon.o \ > source/rotate_win.o \ > source/row_any.o \ > source/row_common.o \ > source/row_gcc.o \ >- source/row_dspr2.o \ > source/row_neon64.o \ > source/row_neon.o \ > source/row_win.o \ >@@ -48,7 +46,6 @@ LOCAL_OBJ_FILES := \ > source/scale.o \ > source/scale_common.o \ > source/scale_gcc.o \ >- source/scale_dspr2.o \ > source/scale_neon64.o \ > source/scale_neon.o \ > source/scale_win.o \ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare.cc >index 8c379b59cb8..50e3abd0556 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare.cc >@@ -29,10 +29,11 @@ extern "C" { > > // hash seed of 5381 recommended. > LIBYUV_API >-uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed) { >+uint32_t HashDjb2(const uint8_t* src, uint64_t count, uint32_t seed) { > const int kBlockSize = 1 << 15; // 32768; > int remainder; >- uint32 (*HashDjb2_SSE)(const uint8* src, int count, uint32 seed) = HashDjb2_C; >+ uint32_t (*HashDjb2_SSE)(const uint8_t* src, int count, uint32_t seed) = >+ HashDjb2_C; > #if defined(HAS_HASHDJB2_SSE41) > if (TestCpuFlag(kCpuHasSSE41)) { > HashDjb2_SSE = HashDjb2_SSE41; >@@ -44,7 +45,7 @@ uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed) { > } > #endif > >- while (count >= (uint64)(kBlockSize)) { >+ while (count >= (uint64_t)(kBlockSize)) { > seed = HashDjb2_SSE(src, kBlockSize, seed); > src += kBlockSize; > count -= kBlockSize; >@@ -62,7 +63,7 @@ uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed) { > return seed; > } > >-static uint32 ARGBDetectRow_C(const uint8* argb, int width) { >+static uint32_t ARGBDetectRow_C(const uint8_t* argb, int width) { > int x; > for (x = 0; x < width - 1; x += 2) { > if (argb[0] != 255) { // First byte is not Alpha of 255, so not ARGB. >@@ -93,8 +94,11 @@ static uint32 ARGBDetectRow_C(const uint8* argb, int width) { > // Scan an opaque argb image and return fourcc based on alpha offset. > // Returns FOURCC_ARGB, FOURCC_BGRA, or 0 if unknown. > LIBYUV_API >-uint32 ARGBDetect(const uint8* argb, int stride_argb, int width, int height) { >- uint32 fourcc = 0; >+uint32_t ARGBDetect(const uint8_t* argb, >+ int stride_argb, >+ int width, >+ int height) { >+ uint32_t fourcc = 0; > int h; > > // Coalesce rows. >@@ -114,17 +118,17 @@ uint32 ARGBDetect(const uint8* argb, int stride_argb, int width, int height) { > // So actual maximum is 1 less loop, which is 64436 - 32 bytes. > > LIBYUV_API >-uint64 ComputeHammingDistance(const uint8* src_a, >- const uint8* src_b, >- int count) { >+uint64_t ComputeHammingDistance(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { > const int kBlockSize = 1 << 15; // 32768; > const int kSimdSize = 64; > // SIMD for multiple of 64, and C for remainder > int remainder = count & (kBlockSize - 1) & ~(kSimdSize - 1); >- uint64 diff = 0; >+ uint64_t diff = 0; > int i; >- uint32 (*HammingDistance)(const uint8* src_a, const uint8* src_b, int count) = >- HammingDistance_C; >+ uint32_t (*HammingDistance)(const uint8_t* src_a, const uint8_t* src_b, >+ int count) = HammingDistance_C; > #if defined(HAS_HAMMINGDISTANCE_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > HammingDistance = HammingDistance_NEON; >@@ -172,18 +176,18 @@ uint64 ComputeHammingDistance(const uint8* src_a, > > // TODO(fbarchard): Refactor into row function. > LIBYUV_API >-uint64 ComputeSumSquareError(const uint8* src_a, >- const uint8* src_b, >- int count) { >+uint64_t ComputeSumSquareError(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { > // SumSquareError returns values 0 to 65535 for each squared difference. >- // Up to 65536 of those can be summed and remain within a uint32. >- // After each block of 65536 pixels, accumulate into a uint64. >+ // Up to 65536 of those can be summed and remain within a uint32_t. >+ // After each block of 65536 pixels, accumulate into a uint64_t. > const int kBlockSize = 65536; > int remainder = count & (kBlockSize - 1) & ~31; >- uint64 sse = 0; >+ uint64_t sse = 0; > int i; >- uint32 (*SumSquareError)(const uint8* src_a, const uint8* src_b, int count) = >- SumSquareError_C; >+ uint32_t (*SumSquareError)(const uint8_t* src_a, const uint8_t* src_b, >+ int count) = SumSquareError_C; > #if defined(HAS_SUMSQUAREERROR_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > SumSquareError = SumSquareError_NEON; >@@ -227,13 +231,13 @@ uint64 ComputeSumSquareError(const uint8* src_a, > } > > LIBYUV_API >-uint64 ComputeSumSquareErrorPlane(const uint8* src_a, >- int stride_a, >- const uint8* src_b, >- int stride_b, >- int width, >- int height) { >- uint64 sse = 0; >+uint64_t ComputeSumSquareErrorPlane(const uint8_t* src_a, >+ int stride_a, >+ const uint8_t* src_b, >+ int stride_b, >+ int width, >+ int height) { >+ uint64_t sse = 0; > int h; > // Coalesce rows. > if (stride_a == width && stride_b == width) { >@@ -250,7 +254,7 @@ uint64 ComputeSumSquareErrorPlane(const uint8* src_a, > } > > LIBYUV_API >-double SumSquareErrorToPsnr(uint64 sse, uint64 count) { >+double SumSquareErrorToPsnr(uint64_t sse, uint64_t count) { > double psnr; > if (sse > 0) { > double mse = (double)count / (double)sse; >@@ -259,65 +263,67 @@ double SumSquareErrorToPsnr(uint64 sse, uint64 count) { > psnr = kMaxPsnr; // Limit to prevent divide by 0 > } > >- if (psnr > kMaxPsnr) >+ if (psnr > kMaxPsnr) { > psnr = kMaxPsnr; >+ } > > return psnr; > } > > LIBYUV_API >-double CalcFramePsnr(const uint8* src_a, >+double CalcFramePsnr(const uint8_t* src_a, > int stride_a, >- const uint8* src_b, >+ const uint8_t* src_b, > int stride_b, > int width, > int height) { >- const uint64 samples = width * height; >- const uint64 sse = ComputeSumSquareErrorPlane(src_a, stride_a, src_b, >- stride_b, width, height); >+ const uint64_t samples = (uint64_t)width * (uint64_t)height; >+ const uint64_t sse = ComputeSumSquareErrorPlane(src_a, stride_a, src_b, >+ stride_b, width, height); > return SumSquareErrorToPsnr(sse, samples); > } > > LIBYUV_API >-double I420Psnr(const uint8* src_y_a, >+double I420Psnr(const uint8_t* src_y_a, > int stride_y_a, >- const uint8* src_u_a, >+ const uint8_t* src_u_a, > int stride_u_a, >- const uint8* src_v_a, >+ const uint8_t* src_v_a, > int stride_v_a, >- const uint8* src_y_b, >+ const uint8_t* src_y_b, > int stride_y_b, >- const uint8* src_u_b, >+ const uint8_t* src_u_b, > int stride_u_b, >- const uint8* src_v_b, >+ const uint8_t* src_v_b, > int stride_v_b, > int width, > int height) { >- const uint64 sse_y = ComputeSumSquareErrorPlane(src_y_a, stride_y_a, src_y_b, >- stride_y_b, width, height); >+ const uint64_t sse_y = ComputeSumSquareErrorPlane( >+ src_y_a, stride_y_a, src_y_b, stride_y_b, width, height); > const int width_uv = (width + 1) >> 1; > const int height_uv = (height + 1) >> 1; >- const uint64 sse_u = ComputeSumSquareErrorPlane( >+ const uint64_t sse_u = ComputeSumSquareErrorPlane( > src_u_a, stride_u_a, src_u_b, stride_u_b, width_uv, height_uv); >- const uint64 sse_v = ComputeSumSquareErrorPlane( >+ const uint64_t sse_v = ComputeSumSquareErrorPlane( > src_v_a, stride_v_a, src_v_b, stride_v_b, width_uv, height_uv); >- const uint64 samples = width * height + 2 * (width_uv * height_uv); >- const uint64 sse = sse_y + sse_u + sse_v; >+ const uint64_t samples = (uint64_t)width * (uint64_t)height + >+ 2 * ((uint64_t)width_uv * (uint64_t)height_uv); >+ const uint64_t sse = sse_y + sse_u + sse_v; > return SumSquareErrorToPsnr(sse, samples); > } > >-static const int64 cc1 = 26634; // (64^2*(.01*255)^2 >-static const int64 cc2 = 239708; // (64^2*(.03*255)^2 >+static const int64_t cc1 = 26634; // (64^2*(.01*255)^2 >+static const int64_t cc2 = 239708; // (64^2*(.03*255)^2 > >-static double Ssim8x8_C(const uint8* src_a, >+static double Ssim8x8_C(const uint8_t* src_a, > int stride_a, >- const uint8* src_b, >+ const uint8_t* src_b, > int stride_b) { >- int64 sum_a = 0; >- int64 sum_b = 0; >- int64 sum_sq_a = 0; >- int64 sum_sq_b = 0; >- int64 sum_axb = 0; >+ int64_t sum_a = 0; >+ int64_t sum_b = 0; >+ int64_t sum_sq_a = 0; >+ int64_t sum_sq_b = 0; >+ int64_t sum_axb = 0; > > int i; > for (i = 0; i < 8; ++i) { >@@ -335,20 +341,20 @@ static double Ssim8x8_C(const uint8* src_a, > } > > { >- const int64 count = 64; >+ const int64_t count = 64; > // scale the constants by number of pixels >- const int64 c1 = (cc1 * count * count) >> 12; >- const int64 c2 = (cc2 * count * count) >> 12; >+ const int64_t c1 = (cc1 * count * count) >> 12; >+ const int64_t c2 = (cc2 * count * count) >> 12; > >- const int64 sum_a_x_sum_b = sum_a * sum_b; >+ const int64_t sum_a_x_sum_b = sum_a * sum_b; > >- const int64 ssim_n = (2 * sum_a_x_sum_b + c1) * >- (2 * count * sum_axb - 2 * sum_a_x_sum_b + c2); >+ const int64_t ssim_n = (2 * sum_a_x_sum_b + c1) * >+ (2 * count * sum_axb - 2 * sum_a_x_sum_b + c2); > >- const int64 sum_a_sq = sum_a * sum_a; >- const int64 sum_b_sq = sum_b * sum_b; >+ const int64_t sum_a_sq = sum_a * sum_a; >+ const int64_t sum_b_sq = sum_b * sum_b; > >- const int64 ssim_d = >+ const int64_t ssim_d = > (sum_a_sq + sum_b_sq + c1) * > (count * sum_sq_a - sum_a_sq + count * sum_sq_b - sum_b_sq + c2); > >@@ -363,15 +369,15 @@ static double Ssim8x8_C(const uint8* src_a, > // on the 4x4 pixel grid. Such arrangement allows the windows to overlap > // block boundaries to penalize blocking artifacts. > LIBYUV_API >-double CalcFrameSsim(const uint8* src_a, >+double CalcFrameSsim(const uint8_t* src_a, > int stride_a, >- const uint8* src_b, >+ const uint8_t* src_b, > int stride_b, > int width, > int height) { > int samples = 0; > double ssim_total = 0; >- double (*Ssim8x8)(const uint8* src_a, int stride_a, const uint8* src_b, >+ double (*Ssim8x8)(const uint8_t* src_a, int stride_a, const uint8_t* src_b, > int stride_b) = Ssim8x8_C; > > // sample point start with each 4x4 location >@@ -392,17 +398,17 @@ double CalcFrameSsim(const uint8* src_a, > } > > LIBYUV_API >-double I420Ssim(const uint8* src_y_a, >+double I420Ssim(const uint8_t* src_y_a, > int stride_y_a, >- const uint8* src_u_a, >+ const uint8_t* src_u_a, > int stride_u_a, >- const uint8* src_v_a, >+ const uint8_t* src_v_a, > int stride_v_a, >- const uint8* src_y_b, >+ const uint8_t* src_y_b, > int stride_y_b, >- const uint8* src_u_b, >+ const uint8_t* src_u_b, > int stride_u_b, >- const uint8* src_v_b, >+ const uint8_t* src_v_b, > int stride_v_b, > int width, > int height) { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_common.cc >index 83564a1bcb5..633466addb5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_common.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_common.cc >@@ -18,8 +18,10 @@ extern "C" { > #endif > > #if ORIGINAL_OPT >-uint32 HammingDistance_C1(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_C1(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > int i; > for (i = 0; i < count; ++i) { >@@ -46,13 +48,15 @@ uint32 HammingDistance_C1(const uint8* src_a, const uint8* src_b, int count) { > #endif > > // Hakmem method for hamming distance. >-uint32 HammingDistance_C(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_C(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > int i; > for (i = 0; i < count - 3; i += 4) { >- uint32 x = *((uint32*)src_a) ^ *((uint32*)src_b); >- uint32 u = x - ((x >> 1) & 0x55555555); >+ uint32_t x = *((uint32_t*)src_a) ^ *((uint32_t*)src_b); // NOLINT >+ uint32_t u = x - ((x >> 1) & 0x55555555); > u = ((u >> 2) & 0x33333333) + (u & 0x33333333); > diff += ((((u + (u >> 4)) & 0x0f0f0f0f) * 0x01010101) >> 24); > src_a += 4; >@@ -60,8 +64,8 @@ uint32 HammingDistance_C(const uint8* src_a, const uint8* src_b, int count) { > } > > for (; i < count; ++i) { >- uint32 x = *src_a ^ *src_b; >- uint32 u = x - ((x >> 1) & 0x55); >+ uint32_t x = *src_a ^ *src_b; >+ uint32_t u = x - ((x >> 1) & 0x55); > u = ((u >> 2) & 0x33) + (u & 0x33); > diff += (u + (u >> 4)) & 0x0f; > src_a += 1; >@@ -71,20 +75,22 @@ uint32 HammingDistance_C(const uint8* src_a, const uint8* src_b, int count) { > return diff; > } > >-uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count) { >- uint32 sse = 0u; >+uint32_t SumSquareError_C(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse = 0u; > int i; > for (i = 0; i < count; ++i) { > int diff = src_a[i] - src_b[i]; >- sse += (uint32)(diff * diff); >+ sse += (uint32_t)(diff * diff); > } > return sse; > } > > // hash seed of 5381 recommended. > // Internal C version of HashDjb2 with int sized count for efficiency. >-uint32 HashDjb2_C(const uint8* src, int count, uint32 seed) { >- uint32 hash = seed; >+uint32_t HashDjb2_C(const uint8_t* src, int count, uint32_t seed) { >+ uint32_t hash = seed; > int i; > for (i = 0; i < count; ++i) { > hash += (hash << 5) + src[i]; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc >index 595c8ec4ae2..676527c1b1b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc >@@ -23,10 +23,10 @@ extern "C" { > (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) > > #if defined(__x86_64__) >-uint32 HammingDistance_SSE42(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint64 diff = 0u; >+uint32_t HammingDistance_SSE42(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint64_t diff = 0u; > > asm volatile( > "xor %3,%3 \n" >@@ -68,13 +68,13 @@ uint32 HammingDistance_SSE42(const uint8* src_a, > : > : "memory", "cc", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10"); > >- return static_cast<uint32>(diff); >+ return static_cast<uint32_t>(diff); > } > #else >-uint32 HammingDistance_SSE42(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_SSE42(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > asm volatile( > // Process 16 bytes per loop. >@@ -111,14 +111,14 @@ uint32 HammingDistance_SSE42(const uint8* src_a, > } > #endif > >-static vec8 kNibbleMask = {15, 15, 15, 15, 15, 15, 15, 15, >- 15, 15, 15, 15, 15, 15, 15, 15}; >-static vec8 kBitCount = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; >+static const vec8 kNibbleMask = {15, 15, 15, 15, 15, 15, 15, 15, >+ 15, 15, 15, 15, 15, 15, 15, 15}; >+static const vec8 kBitCount = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; > >-uint32 HammingDistance_SSSE3(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_SSSE3(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > asm volatile( > "movdqa %4,%%xmm2 \n" >@@ -174,8 +174,10 @@ uint32 HammingDistance_SSSE3(const uint8* src_a, > } > > #ifdef HAS_HAMMINGDISTANCE_AVX2 >-uint32 HammingDistance_AVX2(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_AVX2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > asm volatile( > "vbroadcastf128 %4,%%ymm2 \n" >@@ -227,124 +229,127 @@ uint32 HammingDistance_AVX2(const uint8* src_a, const uint8* src_b, int count) { > } > #endif // HAS_HAMMINGDISTANCE_AVX2 > >-uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count) { >- uint32 sse; >- asm volatile ( >- "pxor %%xmm0,%%xmm0 \n" >- "pxor %%xmm5,%%xmm5 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "lea " MEMLEA(0x10, 0) ",%0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm2 \n" >- "lea " MEMLEA(0x10, 1) ",%1 \n" >- "movdqa %%xmm1,%%xmm3 \n" >- "psubusb %%xmm2,%%xmm1 \n" >- "psubusb %%xmm3,%%xmm2 \n" >- "por %%xmm2,%%xmm1 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "punpcklbw %%xmm5,%%xmm1 \n" >- "punpckhbw %%xmm5,%%xmm2 \n" >- "pmaddwd %%xmm1,%%xmm1 \n" >- "pmaddwd %%xmm2,%%xmm2 \n" >- "paddd %%xmm1,%%xmm0 \n" >- "paddd %%xmm2,%%xmm0 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >+uint32_t SumSquareError_SSE2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse; >+ asm volatile( >+ "pxor %%xmm0,%%xmm0 \n" >+ "pxor %%xmm5,%%xmm5 \n" > >- "pshufd $0xee,%%xmm0,%%xmm1 \n" >- "paddd %%xmm1,%%xmm0 \n" >- "pshufd $0x1,%%xmm0,%%xmm1 \n" >- "paddd %%xmm1,%%xmm0 \n" >- "movd %%xmm0,%3 \n" >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqu (%1),%%xmm2 \n" >+ "lea 0x10(%1),%1 \n" >+ "movdqa %%xmm1,%%xmm3 \n" >+ "psubusb %%xmm2,%%xmm1 \n" >+ "psubusb %%xmm3,%%xmm2 \n" >+ "por %%xmm2,%%xmm1 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "punpckhbw %%xmm5,%%xmm2 \n" >+ "pmaddwd %%xmm1,%%xmm1 \n" >+ "pmaddwd %%xmm2,%%xmm2 \n" >+ "paddd %%xmm1,%%xmm0 \n" >+ "paddd %%xmm2,%%xmm0 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" > >- : "+r"(src_a), // %0 >- "+r"(src_b), // %1 >- "+r"(count), // %2 >- "=g"(sse) // %3 >- :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ "pshufd $0xee,%%xmm0,%%xmm1 \n" >+ "paddd %%xmm1,%%xmm0 \n" >+ "pshufd $0x1,%%xmm0,%%xmm1 \n" >+ "paddd %%xmm1,%%xmm0 \n" >+ "movd %%xmm0,%3 \n" >+ >+ : "+r"(src_a), // %0 >+ "+r"(src_b), // %1 >+ "+r"(count), // %2 >+ "=g"(sse) // %3 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > return sse; > } > >-static uvec32 kHash16x33 = {0x92d9e201, 0, 0, 0}; // 33 ^ 16 >-static uvec32 kHashMul0 = { >+static const uvec32 kHash16x33 = {0x92d9e201, 0, 0, 0}; // 33 ^ 16 >+static const uvec32 kHashMul0 = { > 0x0c3525e1, // 33 ^ 15 > 0xa3476dc1, // 33 ^ 14 > 0x3b4039a1, // 33 ^ 13 > 0x4f5f0981, // 33 ^ 12 > }; >-static uvec32 kHashMul1 = { >+static const uvec32 kHashMul1 = { > 0x30f35d61, // 33 ^ 11 > 0x855cb541, // 33 ^ 10 > 0x040a9121, // 33 ^ 9 > 0x747c7101, // 33 ^ 8 > }; >-static uvec32 kHashMul2 = { >+static const uvec32 kHashMul2 = { > 0xec41d4e1, // 33 ^ 7 > 0x4cfa3cc1, // 33 ^ 6 > 0x025528a1, // 33 ^ 5 > 0x00121881, // 33 ^ 4 > }; >-static uvec32 kHashMul3 = { >+static const uvec32 kHashMul3 = { > 0x00008c61, // 33 ^ 3 > 0x00000441, // 33 ^ 2 > 0x00000021, // 33 ^ 1 > 0x00000001, // 33 ^ 0 > }; > >-uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) { >- uint32 hash; >- asm volatile ( >- "movd %2,%%xmm0 \n" >- "pxor %%xmm7,%%xmm7 \n" >- "movdqa %4,%%xmm6 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "lea " MEMLEA(0x10, 0) ",%0 \n" >- "pmulld %%xmm6,%%xmm0 \n" >- "movdqa %5,%%xmm5 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "punpcklbw %%xmm7,%%xmm2 \n" >- "movdqa %%xmm2,%%xmm3 \n" >- "punpcklwd %%xmm7,%%xmm3 \n" >- "pmulld %%xmm5,%%xmm3 \n" >- "movdqa %6,%%xmm5 \n" >- "movdqa %%xmm2,%%xmm4 \n" >- "punpckhwd %%xmm7,%%xmm4 \n" >- "pmulld %%xmm5,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "punpckhbw %%xmm7,%%xmm1 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "punpcklwd %%xmm7,%%xmm2 \n" >- "pmulld %%xmm5,%%xmm2 \n" >- "movdqa %8,%%xmm5 \n" >- "punpckhwd %%xmm7,%%xmm1 \n" >- "pmulld %%xmm5,%%xmm1 \n" >- "paddd %%xmm4,%%xmm3 \n" >- "paddd %%xmm2,%%xmm1 \n" >- "paddd %%xmm3,%%xmm1 \n" >- "pshufd $0xe,%%xmm1,%%xmm2 \n" >- "paddd %%xmm2,%%xmm1 \n" >- "pshufd $0x1,%%xmm1,%%xmm2 \n" >- "paddd %%xmm2,%%xmm1 \n" >- "paddd %%xmm1,%%xmm0 \n" >- "sub $0x10,%1 \n" >- "jg 1b \n" >- "movd %%xmm0,%3 \n" >- : "+r"(src), // %0 >- "+r"(count), // %1 >- "+rm"(seed), // %2 >- "=g"(hash) // %3 >- : "m"(kHash16x33), // %4 >- "m"(kHashMul0), // %5 >- "m"(kHashMul1), // %6 >- "m"(kHashMul2), // %7 >- "m"(kHashMul3) // %8 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+uint32_t HashDjb2_SSE41(const uint8_t* src, int count, uint32_t seed) { >+ uint32_t hash; >+ asm volatile( >+ "movd %2,%%xmm0 \n" >+ "pxor %%xmm7,%%xmm7 \n" >+ "movdqa %4,%%xmm6 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "pmulld %%xmm6,%%xmm0 \n" >+ "movdqa %5,%%xmm5 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "punpcklbw %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm2,%%xmm3 \n" >+ "punpcklwd %%xmm7,%%xmm3 \n" >+ "pmulld %%xmm5,%%xmm3 \n" >+ "movdqa %6,%%xmm5 \n" >+ "movdqa %%xmm2,%%xmm4 \n" >+ "punpckhwd %%xmm7,%%xmm4 \n" >+ "pmulld %%xmm5,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "punpckhbw %%xmm7,%%xmm1 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "punpcklwd %%xmm7,%%xmm2 \n" >+ "pmulld %%xmm5,%%xmm2 \n" >+ "movdqa %8,%%xmm5 \n" >+ "punpckhwd %%xmm7,%%xmm1 \n" >+ "pmulld %%xmm5,%%xmm1 \n" >+ "paddd %%xmm4,%%xmm3 \n" >+ "paddd %%xmm2,%%xmm1 \n" >+ "paddd %%xmm3,%%xmm1 \n" >+ "pshufd $0xe,%%xmm1,%%xmm2 \n" >+ "paddd %%xmm2,%%xmm1 \n" >+ "pshufd $0x1,%%xmm1,%%xmm2 \n" >+ "paddd %%xmm2,%%xmm1 \n" >+ "paddd %%xmm1,%%xmm0 \n" >+ "sub $0x10,%1 \n" >+ "jg 1b \n" >+ "movd %%xmm0,%3 \n" >+ : "+r"(src), // %0 >+ "+r"(count), // %1 >+ "+rm"(seed), // %2 >+ "=g"(hash) // %3 >+ : "m"(kHash16x33), // %4 >+ "m"(kHashMul0), // %5 >+ "m"(kHashMul1), // %6 >+ "m"(kHashMul2), // %7 >+ "m"(kHashMul3) // %8 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > return hash; > } > #endif // defined(__x86_64__) || (defined(__i386__) && !defined(__pic__))) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc >index efb5185aac7..e944235f020 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc >@@ -22,8 +22,10 @@ namespace libyuv { > extern "C" { > #endif > >-uint32 HammingDistance_MSA(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_MSA(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > int i; > v16u8 src0, src1, src2, src3; > v2i64 vec0 = {0}, vec1 = {0}; >@@ -42,13 +44,15 @@ uint32 HammingDistance_MSA(const uint8* src_a, const uint8* src_b, int count) { > } > > vec0 += vec1; >- diff = (uint32)__msa_copy_u_w((v4i32)vec0, 0); >- diff += (uint32)__msa_copy_u_w((v4i32)vec0, 2); >+ diff = (uint32_t)__msa_copy_u_w((v4i32)vec0, 0); >+ diff += (uint32_t)__msa_copy_u_w((v4i32)vec0, 2); > return diff; > } > >-uint32 SumSquareError_MSA(const uint8* src_a, const uint8* src_b, int count) { >- uint32 sse = 0u; >+uint32_t SumSquareError_MSA(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse = 0u; > int i; > v16u8 src0, src1, src2, src3; > v8i16 vec0, vec1, vec2, vec3; >@@ -80,8 +84,8 @@ uint32 SumSquareError_MSA(const uint8* src_a, const uint8* src_b, int count) { > reg2 += reg3; > reg0 += reg2; > tmp0 = __msa_hadd_s_d(reg0, reg0); >- sse = (uint32)__msa_copy_u_w((v4i32)tmp0, 0); >- sse += (uint32)__msa_copy_u_w((v4i32)tmp0, 2); >+ sse = (uint32_t)__msa_copy_u_w((v4i32)tmp0, 0); >+ sse += (uint32_t)__msa_copy_u_w((v4i32)tmp0, 2); > return sse; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc >index 5dfa71edcbf..2a2181e0cb3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc >@@ -23,8 +23,10 @@ extern "C" { > > // 256 bits at a time > // uses short accumulator which restricts count to 131 KB >-uint32 HammingDistance_NEON(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff; >+uint32_t HammingDistance_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff; > > asm volatile( > "vmov.u16 q4, #0 \n" // accumulator >@@ -52,8 +54,10 @@ uint32 HammingDistance_NEON(const uint8* src_a, const uint8* src_b, int count) { > return diff; > } > >-uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count) { >- uint32 sse; >+uint32_t SumSquareError_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse; > asm volatile( > "vmov.u8 q8, #0 \n" > "vmov.u8 q10, #0 \n" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc >index ddf98fa68b2..6e8f672ab73 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc >@@ -22,8 +22,10 @@ extern "C" { > > // 256 bits at a time > // uses short accumulator which restricts count to 131 KB >-uint32 HammingDistance_NEON(const uint8* src_a, const uint8* src_b, int count) { >- uint32 diff; >+uint32_t HammingDistance_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff; > asm volatile( > "movi v4.8h, #0 \n" > >@@ -47,8 +49,10 @@ uint32 HammingDistance_NEON(const uint8* src_a, const uint8* src_b, int count) { > return diff; > } > >-uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count) { >- uint32 sse; >+uint32_t SumSquareError_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse; > asm volatile( > "eor v16.16b, v16.16b, v16.16b \n" > "eor v18.16b, v18.16b, v18.16b \n" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_win.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_win.cc >index bcd6a88ebbb..d57d3d9d1c8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_win.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/compare_win.cc >@@ -25,14 +25,14 @@ extern "C" { > // This module is for 32 bit Visual C x86 and clangcl > #if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER) > >-uint32 HammingDistance_SSE42(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint32 diff = 0u; >+uint32_t HammingDistance_SSE42(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t diff = 0u; > > int i; > for (i = 0; i < count - 3; i += 4) { >- uint32 x = *((uint32*)src_a) ^ *((uint32*)src_b); >+ uint32_t x = *((uint32_t*)src_a) ^ *((uint32_t*)src_b); // NOLINT > src_a += 4; > src_b += 4; > diff += __popcnt(x); >@@ -40,8 +40,8 @@ uint32 HammingDistance_SSE42(const uint8* src_a, > return diff; > } > >-__declspec(naked) uint32 >- SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count) { >+__declspec(naked) uint32_t >+ SumSquareError_SSE2(const uint8_t* src_a, const uint8_t* src_b, int count) { > __asm { > mov eax, [esp + 4] // src_a > mov edx, [esp + 8] // src_b >@@ -81,8 +81,8 @@ __declspec(naked) uint32 > #if _MSC_VER >= 1700 > // C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX. > #pragma warning(disable : 4752) >-__declspec(naked) uint32 >- SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count) { >+__declspec(naked) uint32_t >+ SumSquareError_AVX2(const uint8_t* src_a, const uint8_t* src_b, int count) { > __asm { > mov eax, [esp + 4] // src_a > mov edx, [esp + 8] // src_b >@@ -146,8 +146,8 @@ uvec32 kHashMul3 = { > 0x00000001, // 33 ^ 0 > }; > >-__declspec(naked) uint32 >- HashDjb2_SSE41(const uint8* src, int count, uint32 seed) { >+__declspec(naked) uint32_t >+ HashDjb2_SSE41(const uint8_t* src, int count, uint32_t seed) { > __asm { > mov eax, [esp + 4] // src > mov ecx, [esp + 8] // count >@@ -197,8 +197,8 @@ __declspec(naked) uint32 > > // Visual C 2012 required for AVX2. > #if _MSC_VER >= 1700 >-__declspec(naked) uint32 >- HashDjb2_AVX2(const uint8* src, int count, uint32 seed) { >+__declspec(naked) uint32_t >+ HashDjb2_AVX2(const uint8_t* src, int count, uint32_t seed) { > __asm { > mov eax, [esp + 4] // src > mov ecx, [esp + 8] // count >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert.cc >index dfa83a5a6d8..375cc732c1d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert.cc >@@ -28,17 +28,17 @@ static __inline int Abs(int v) { > } > > // Any I4xx To I420 format with mirroring. >-static int I4xxToI420(const uint8* src_y, >+static int I4xxToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int src_y_width, > int src_y_height, >@@ -62,21 +62,21 @@ static int I4xxToI420(const uint8* src_y, > return 0; > } > >-// Copy I420 with optional flipping >+// Copy I420 with optional flipping. > // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure > // is does row coalescing. > LIBYUV_API >-int I420Copy(const uint8* src_y, >+int I420Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -106,20 +106,106 @@ int I420Copy(const uint8* src_y, > return 0; > } > >+// Copy I010 with optional flipping. >+LIBYUV_API >+int I010Copy(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ uint16_t* dst_u, >+ int dst_stride_u, >+ uint16_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height) { >+ int halfwidth = (width + 1) >> 1; >+ int halfheight = (height + 1) >> 1; >+ if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ halfheight = (height + 1) >> 1; >+ src_y = src_y + (height - 1) * src_stride_y; >+ src_u = src_u + (halfheight - 1) * src_stride_u; >+ src_v = src_v + (halfheight - 1) * src_stride_v; >+ src_stride_y = -src_stride_y; >+ src_stride_u = -src_stride_u; >+ src_stride_v = -src_stride_v; >+ } >+ >+ if (dst_y) { >+ CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); >+ } >+ // Copy UV planes. >+ CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); >+ CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); >+ return 0; >+} >+ >+// Convert 10 bit YUV to 8 bit. >+LIBYUV_API >+int I010ToI420(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height) { >+ int halfwidth = (width + 1) >> 1; >+ int halfheight = (height + 1) >> 1; >+ if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ halfheight = (height + 1) >> 1; >+ src_y = src_y + (height - 1) * src_stride_y; >+ src_u = src_u + (halfheight - 1) * src_stride_u; >+ src_v = src_v + (halfheight - 1) * src_stride_v; >+ src_stride_y = -src_stride_y; >+ src_stride_u = -src_stride_u; >+ src_stride_v = -src_stride_v; >+ } >+ >+ // Convert Y plane. >+ Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width, >+ height); >+ // Convert UV planes. >+ Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth, >+ halfheight); >+ Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth, >+ halfheight); >+ return 0; >+} >+ > // 422 chroma is 1/2 width, 1x height > // 420 chroma is 1/2 width, 1/2 height > LIBYUV_API >-int I422ToI420(const uint8* src_y, >+int I422ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -132,17 +218,17 @@ int I422ToI420(const uint8* src_y, > // 444 chroma is 1x width, 1x height > // 420 chroma is 1/2 width, 1/2 height > LIBYUV_API >-int I444ToI420(const uint8* src_y, >+int I444ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -153,13 +239,13 @@ int I444ToI420(const uint8* src_y, > > // I400 is greyscale typically used in MJPG > LIBYUV_API >-int I400ToI420(const uint8* src_y, >+int I400ToI420(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -183,15 +269,15 @@ int I400ToI420(const uint8* src_y, > return 0; > } > >-static void CopyPlane2(const uint8* src, >+static void CopyPlane2(const uint8_t* src, > int src_stride_0, > int src_stride_1, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { > int y; >- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; >+ void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C; > #if defined(HAS_COPYROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; >@@ -212,11 +298,6 @@ static void CopyPlane2(const uint8* src, > CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; > } > #endif >-#if defined(HAS_COPYROW_MIPS) >- if (TestCpuFlag(kCpuHasMIPS)) { >- CopyRow = CopyRow_MIPS; >- } >-#endif > > // Copy plane > for (y = 0; y < height - 1; y += 2) { >@@ -239,16 +320,16 @@ static void CopyPlane2(const uint8* src, > // src_stride_m420 is row planar. Normally this will be the width in pixels. > // The UV plane is half width, but 2 values, so src_stride_m420 applies to > // this as well as the two Y planes. >-static int X420ToI420(const uint8* src_y, >+static int X420ToI420(const uint8_t* src_y, > int src_stride_y0, > int src_stride_y1, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -303,15 +384,15 @@ static int X420ToI420(const uint8* src_y, > > // Convert NV12 to I420. > LIBYUV_API >-int NV12ToI420(const uint8* src_y, >+int NV12ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -322,15 +403,15 @@ int NV12ToI420(const uint8* src_y, > > // Convert NV21 to I420. Same as NV12 but u and v pointers swapped. > LIBYUV_API >-int NV21ToI420(const uint8* src_y, >+int NV21ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_vu, >+ const uint8_t* src_vu, > int src_stride_vu, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -341,13 +422,13 @@ int NV21ToI420(const uint8* src_y, > > // Convert M420 to I420. > LIBYUV_API >-int M420ToI420(const uint8* src_m420, >+int M420ToI420(const uint8_t* src_m420, > int src_stride_m420, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -359,20 +440,21 @@ int M420ToI420(const uint8* src_m420, > > // Convert YUY2 to I420. > LIBYUV_API >-int YUY2ToI420(const uint8* src_yuy2, >+int YUY2ToI420(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, uint8* dst_u, >- uint8* dst_v, int width) = YUY2ToUVRow_C; >- void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) = >+ void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ YUY2ToUVRow_C; >+ void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = > YUY2ToYRow_C; > // Negative height means invert the image. > if (height < 0) { >@@ -439,20 +521,21 @@ int YUY2ToI420(const uint8* src_yuy2, > > // Convert UYVY to I420. > LIBYUV_API >-int UYVYToI420(const uint8* src_uyvy, >+int UYVYToI420(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_u, >- uint8* dst_v, int width) = UYVYToUVRow_C; >- void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) = >+ void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ UYVYToUVRow_C; >+ void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) = > UYVYToYRow_C; > // Negative height means invert the image. > if (height < 0) { >@@ -519,20 +602,21 @@ int UYVYToI420(const uint8* src_uyvy, > > // Convert ARGB to I420. > LIBYUV_API >-int ARGBToI420(const uint8* src_argb, >+int ARGBToI420(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -579,14 +663,6 @@ int ARGBToI420(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGBTOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGBToYRow = ARGBToYRow_Any_MSA; >@@ -595,14 +671,6 @@ int ARGBToI420(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGBTOUVROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGBToUVRow = ARGBToUVRow_Any_MSA; >@@ -630,20 +698,21 @@ int ARGBToI420(const uint8* src_argb, > > // Convert BGRA to I420. > LIBYUV_API >-int BGRAToI420(const uint8* src_bgra, >+int BGRAToI420(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, uint8* dst_u, >- uint8* dst_v, int width) = BGRAToUVRow_C; >- void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) = >+ void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ BGRAToUVRow_C; >+ void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) = > BGRAToYRow_C; > if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -680,22 +749,6 @@ int BGRAToI420(const uint8* src_bgra, > } > } > #endif >-#if defined(HAS_BGRATOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- BGRAToYRow = BGRAToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- BGRAToYRow = BGRAToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_BGRATOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- BGRAToUVRow = BGRAToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- BGRAToUVRow = BGRAToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_BGRATOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > BGRAToYRow = BGRAToYRow_Any_MSA; >@@ -731,20 +784,21 @@ int BGRAToI420(const uint8* src_bgra, > > // Convert ABGR to I420. > LIBYUV_API >-int ABGRToI420(const uint8* src_abgr, >+int ABGRToI420(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, uint8* dst_u, >- uint8* dst_v, int width) = ABGRToUVRow_C; >- void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) = >+ void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ABGRToUVRow_C; >+ void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) = > ABGRToYRow_C; > if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -781,22 +835,6 @@ int ABGRToI420(const uint8* src_abgr, > } > } > #endif >-#if defined(HAS_ABGRTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ABGRToYRow = ABGRToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ABGRToYRow = ABGRToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ABGRTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ABGRToUVRow = ABGRToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ABGRToUVRow = ABGRToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ABGRTOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ABGRToYRow = ABGRToYRow_Any_MSA; >@@ -832,20 +870,21 @@ int ABGRToI420(const uint8* src_abgr, > > // Convert RGBA to I420. > LIBYUV_API >-int RGBAToI420(const uint8* src_rgba, >+int RGBAToI420(const uint8_t* src_rgba, > int src_stride_rgba, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, uint8* dst_u, >- uint8* dst_v, int width) = RGBAToUVRow_C; >- void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) = >+ void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ RGBAToUVRow_C; >+ void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) = > RGBAToYRow_C; > if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -882,22 +921,6 @@ int RGBAToI420(const uint8* src_rgba, > } > } > #endif >-#if defined(HAS_RGBATOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RGBAToYRow = RGBAToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- RGBAToYRow = RGBAToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_RGBATOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RGBAToUVRow = RGBAToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- RGBAToUVRow = RGBAToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_RGBATOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > RGBAToYRow = RGBAToYRow_Any_MSA; >@@ -933,28 +956,30 @@ int RGBAToI420(const uint8* src_rgba, > > // Convert RGB24 to I420. > LIBYUV_API >-int RGB24ToI420(const uint8* src_rgb24, >+int RGB24ToI420(const uint8_t* src_rgb24, > int src_stride_rgb24, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) >- void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24, >- uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C; >- void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int width) = >+ void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ RGB24ToUVRow_C; >+ void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) = > RGB24ToYRow_C; > #else >- void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >+ void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = > RGB24ToARGBRow_C; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > #endif > if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { >@@ -1063,28 +1088,29 @@ int RGB24ToI420(const uint8* src_rgb24, > > // Convert RAW to I420. > LIBYUV_API >-int RAWToI420(const uint8* src_raw, >+int RAWToI420(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) >- void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, uint8* dst_u, >- uint8* dst_v, int width) = RAWToUVRow_C; >- void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) = >+ void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u, >+ uint8_t* dst_v, int width) = RAWToUVRow_C; >+ void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) = > RAWToYRow_C; > #else >- void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >+ void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = > RAWToARGBRow_C; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > #endif > if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { >@@ -1193,29 +1219,30 @@ int RAWToI420(const uint8* src_raw, > > // Convert RGB565 to I420. > LIBYUV_API >-int RGB565ToI420(const uint8* src_rgb565, >+int RGB565ToI420(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) >- void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565, >- uint8* dst_u, uint8* dst_v, int width) = >+ void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = > RGB565ToUVRow_C; >- void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) = >+ void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) = > RGB565ToYRow_C; > #else >- void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >- RGB565ToARGBRow_C; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, >+ int width) = RGB565ToARGBRow_C; >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > #endif > if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { >@@ -1287,14 +1314,6 @@ int RGB565ToI420(const uint8* src_rgb565, > } > } > #endif >-#if defined(HAS_RGB565TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- RGB565ToARGBRow = RGB565ToARGBRow_DSPR2; >- } >- } >-#endif > #endif > { > #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) >@@ -1338,29 +1357,30 @@ int RGB565ToI420(const uint8* src_rgb565, > > // Convert ARGB1555 to I420. > LIBYUV_API >-int ARGB1555ToI420(const uint8* src_argb1555, >+int ARGB1555ToI420(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) >- void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555, >- uint8* dst_u, uint8* dst_v, int width) = >+ void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = > ARGB1555ToUVRow_C; >- void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) = >- ARGB1555ToYRow_C; >+ void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y, >+ int width) = ARGB1555ToYRow_C; > #else >- void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >- ARGB1555ToARGBRow_C; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, >+ int width) = ARGB1555ToARGBRow_C; >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > #endif > if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 || >@@ -1479,29 +1499,30 @@ int ARGB1555ToI420(const uint8* src_argb1555, > > // Convert ARGB4444 to I420. > LIBYUV_API >-int ARGB4444ToI420(const uint8* src_argb4444, >+int ARGB4444ToI420(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > #if defined(HAS_ARGB4444TOYROW_NEON) >- void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444, >- uint8* dst_u, uint8* dst_v, int width) = >+ void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = > ARGB4444ToUVRow_C; >- void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) = >- ARGB4444ToYRow_C; >+ void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y, >+ int width) = ARGB4444ToYRow_C; > #else >- void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >- ARGB4444ToARGBRow_C; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, >+ int width) = ARGB4444ToARGBRow_C; >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > #endif > if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 || >@@ -1630,9 +1651,9 @@ int ARGB4444ToI420(const uint8* src_argb4444, > return 0; > } > >-static void SplitPixels(const uint8* src_u, >+static void SplitPixels(const uint8_t* src_u, > int src_pixel_stride_uv, >- uint8* dst_u, >+ uint8_t* dst_u, > int width) { > int i; > for (i = 0; i < width; ++i) { >@@ -1644,18 +1665,18 @@ static void SplitPixels(const uint8* src_u, > > // Convert Android420 to I420. > LIBYUV_API >-int Android420ToI420(const uint8* src_y, >+int Android420ToI420(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, > int src_pixel_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -1688,14 +1709,15 @@ int Android420ToI420(const uint8* src_y, > CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); > return 0; > // Split UV planes - NV21 >- } else if (src_pixel_stride_uv == 2 && vu_off == -1 && >- src_stride_u == src_stride_v) { >+ } >+ if (src_pixel_stride_uv == 2 && vu_off == -1 && >+ src_stride_u == src_stride_v) { > SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u, > halfwidth, halfheight); > return 0; > // Split UV planes - NV12 >- } else if (src_pixel_stride_uv == 2 && vu_off == 1 && >- src_stride_u == src_stride_v) { >+ } >+ if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { > SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v, > halfwidth, halfheight); > return 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc >index 5007bdb9708..4c317ae30c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc >@@ -26,9 +26,9 @@ extern "C" { > > // Copy ARGB with optional flipping > LIBYUV_API >-int ARGBCopy(const uint8* src_argb, >+int ARGBCopy(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -47,21 +47,21 @@ int ARGBCopy(const uint8* src_argb, > return 0; > } > >-// Convert I422 to ARGB with matrix >-static int I420ToARGBMatrix(const uint8* src_y, >+// Convert I420 to ARGB with matrix >+static int I420ToARGBMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToARGBRow_C; > if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { >@@ -97,15 +97,6 @@ static int I420ToARGBMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { >- I422ToARGBRow = I422ToARGBRow_DSPR2; >- } >-#endif > #if defined(HAS_I422TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGBRow = I422ToARGBRow_Any_MSA; >@@ -129,13 +120,13 @@ static int I420ToARGBMatrix(const uint8* src_y, > > // Convert I420 to ARGB. > LIBYUV_API >-int I420ToARGB(const uint8* src_y, >+int I420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -146,13 +137,13 @@ int I420ToARGB(const uint8* src_y, > > // Convert I420 to ABGR. > LIBYUV_API >-int I420ToABGR(const uint8* src_y, >+int I420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -165,13 +156,13 @@ int I420ToABGR(const uint8* src_y, > > // Convert J420 to ARGB. > LIBYUV_API >-int J420ToARGB(const uint8* src_y, >+int J420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -182,13 +173,13 @@ int J420ToARGB(const uint8* src_y, > > // Convert J420 to ABGR. > LIBYUV_API >-int J420ToABGR(const uint8* src_y, >+int J420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -201,13 +192,13 @@ int J420ToABGR(const uint8* src_y, > > // Convert H420 to ARGB. > LIBYUV_API >-int H420ToARGB(const uint8* src_y, >+int H420ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -218,13 +209,13 @@ int H420ToARGB(const uint8* src_y, > > // Convert H420 to ABGR. > LIBYUV_API >-int H420ToABGR(const uint8* src_y, >+int H420ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -236,20 +227,20 @@ int H420ToABGR(const uint8* src_y, > } > > // Convert I422 to ARGB with matrix >-static int I422ToARGBMatrix(const uint8* src_y, >+static int I422ToARGBMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToARGBRow_C; > if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { >@@ -292,15 +283,6 @@ static int I422ToARGBMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { >- I422ToARGBRow = I422ToARGBRow_DSPR2; >- } >-#endif > #if defined(HAS_I422TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGBRow = I422ToARGBRow_Any_MSA; >@@ -322,13 +304,13 @@ static int I422ToARGBMatrix(const uint8* src_y, > > // Convert I422 to ARGB. > LIBYUV_API >-int I422ToARGB(const uint8* src_y, >+int I422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -339,13 +321,13 @@ int I422ToARGB(const uint8* src_y, > > // Convert I422 to ABGR. > LIBYUV_API >-int I422ToABGR(const uint8* src_y, >+int I422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -358,13 +340,13 @@ int I422ToABGR(const uint8* src_y, > > // Convert J422 to ARGB. > LIBYUV_API >-int J422ToARGB(const uint8* src_y, >+int J422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -375,13 +357,13 @@ int J422ToARGB(const uint8* src_y, > > // Convert J422 to ABGR. > LIBYUV_API >-int J422ToABGR(const uint8* src_y, >+int J422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -394,13 +376,13 @@ int J422ToABGR(const uint8* src_y, > > // Convert H422 to ARGB. > LIBYUV_API >-int H422ToARGB(const uint8* src_y, >+int H422ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -411,13 +393,13 @@ int H422ToARGB(const uint8* src_y, > > // Convert H422 to ABGR. > LIBYUV_API >-int H422ToABGR(const uint8* src_y, >+int H422ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -428,21 +410,271 @@ int H422ToABGR(const uint8* src_y, > width, height); > } > >+// Convert 10 bit YUV to ARGB with matrix >+// TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to >+// multiply 10 bit yuv into high bits to allow any number of bits. >+static int I010ToAR30Matrix(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf, >+ const uint16_t* v_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = >+ I210ToAR30Row_C; >+ if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30; >+ dst_stride_ar30 = -dst_stride_ar30; >+ } >+#if defined(HAS_I210TOAR30ROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ I210ToAR30Row = I210ToAR30Row_Any_SSSE3; >+ if (IS_ALIGNED(width, 8)) { >+ I210ToAR30Row = I210ToAR30Row_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_I210TOAR30ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I210ToAR30Row = I210ToAR30Row_Any_AVX2; >+ if (IS_ALIGNED(width, 16)) { >+ I210ToAR30Row = I210ToAR30Row_AVX2; >+ } >+ } >+#endif >+ for (y = 0; y < height; ++y) { >+ I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width); >+ dst_ar30 += dst_stride_ar30; >+ src_y += src_stride_y; >+ if (y & 1) { >+ src_u += src_stride_u; >+ src_v += src_stride_v; >+ } >+ } >+ return 0; >+} >+ >+// Convert I010 to AR30. >+LIBYUV_API >+int I010ToAR30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_ar30, dst_stride_ar30, >+ &kYuvI601Constants, width, height); >+} >+ >+// Convert H010 to AR30. >+LIBYUV_API >+int H010ToAR30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_ar30, dst_stride_ar30, >+ &kYuvH709Constants, width, height); >+} >+ >+// Convert I010 to AB30. >+LIBYUV_API >+int I010ToAB30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height) { >+ return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, >+ src_stride_u, dst_ab30, dst_stride_ab30, >+ &kYvuI601Constants, width, height); >+} >+ >+// Convert H010 to AB30. >+LIBYUV_API >+int H010ToAB30(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height) { >+ return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, >+ src_stride_u, dst_ab30, dst_stride_ab30, >+ &kYvuH709Constants, width, height); >+} >+ >+// Convert 10 bit YUV to ARGB with matrix >+static int I010ToARGBMatrix(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf, >+ const uint16_t* v_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = >+ I210ToARGBRow_C; >+ if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_argb = dst_argb + (height - 1) * dst_stride_argb; >+ dst_stride_argb = -dst_stride_argb; >+ } >+#if defined(HAS_I210TOARGBROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ I210ToARGBRow = I210ToARGBRow_Any_SSSE3; >+ if (IS_ALIGNED(width, 8)) { >+ I210ToARGBRow = I210ToARGBRow_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_I210TOARGBROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I210ToARGBRow = I210ToARGBRow_Any_AVX2; >+ if (IS_ALIGNED(width, 16)) { >+ I210ToARGBRow = I210ToARGBRow_AVX2; >+ } >+ } >+#endif >+ for (y = 0; y < height; ++y) { >+ I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); >+ dst_argb += dst_stride_argb; >+ src_y += src_stride_y; >+ if (y & 1) { >+ src_u += src_stride_u; >+ src_v += src_stride_v; >+ } >+ } >+ return 0; >+} >+ >+// Convert I010 to ARGB. >+LIBYUV_API >+int I010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height) { >+ return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_argb, dst_stride_argb, >+ &kYuvI601Constants, width, height); >+} >+ >+// Convert I010 to ABGR. >+LIBYUV_API >+int I010ToABGR(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ return I010ToARGBMatrix(src_y, src_stride_y, src_v, >+ src_stride_v, // Swap U and V >+ src_u, src_stride_u, dst_abgr, dst_stride_abgr, >+ &kYvuI601Constants, // Use Yvu matrix >+ width, height); >+} >+ >+// Convert H010 to ARGB. >+LIBYUV_API >+int H010ToARGB(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height) { >+ return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_argb, dst_stride_argb, >+ &kYuvH709Constants, width, height); >+} >+ >+// Convert H010 to ABGR. >+LIBYUV_API >+int H010ToABGR(const uint16_t* src_y, >+ int src_stride_y, >+ const uint16_t* src_u, >+ int src_stride_u, >+ const uint16_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ return I010ToARGBMatrix(src_y, src_stride_y, src_v, >+ src_stride_v, // Swap U and V >+ src_u, src_stride_u, dst_abgr, dst_stride_abgr, >+ &kYvuH709Constants, // Use Yvu matrix >+ width, height); >+} >+ > // Convert I444 to ARGB with matrix >-static int I444ToARGBMatrix(const uint8* src_y, >+static int I444ToARGBMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I444ToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I444ToARGBRow_C; > if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { >@@ -485,14 +717,6 @@ static int I444ToARGBMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I444TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- I444ToARGBRow = I444ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- I444ToARGBRow = I444ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_I444TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I444ToARGBRow = I444ToARGBRow_Any_MSA; >@@ -514,13 +738,13 @@ static int I444ToARGBMatrix(const uint8* src_y, > > // Convert I444 to ARGB. > LIBYUV_API >-int I444ToARGB(const uint8* src_y, >+int I444ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -531,13 +755,13 @@ int I444ToARGB(const uint8* src_y, > > // Convert I444 to ABGR. > LIBYUV_API >-int I444ToABGR(const uint8* src_y, >+int I444ToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height) { >@@ -550,13 +774,13 @@ int I444ToABGR(const uint8* src_y, > > // Convert J444 to ARGB. > LIBYUV_API >-int J444ToARGB(const uint8* src_y, >+int J444ToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >@@ -566,28 +790,28 @@ int J444ToARGB(const uint8* src_y, > } > > // Convert I420 with Alpha to preattenuated ARGB. >-static int I420AlphaToARGBMatrix(const uint8* src_y, >+static int I420AlphaToARGBMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- const uint8* src_a, >+ const uint8_t* src_a, > int src_stride_a, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const struct YuvConstants* yuvconstants, > int width, > int height, > int attenuate) { > int y; >- void (*I422AlphaToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, const uint8* a_buf, >- uint8* dst_argb, >+ void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) = I422AlphaToARGBRow_C; >- void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) = >- ARGBAttenuateRow_C; >+ void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb, >+ int width) = ARGBAttenuateRow_C; > if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -621,15 +845,6 @@ static int I420AlphaToARGBMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422ALPHATOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { >- I422AlphaToARGBRow = I422AlphaToARGBRow_DSPR2; >- } >-#endif > #if defined(HAS_I422ALPHATOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA; >@@ -690,15 +905,15 @@ static int I420AlphaToARGBMatrix(const uint8* src_y, > > // Convert I420 with Alpha to ARGB. > LIBYUV_API >-int I420AlphaToARGB(const uint8* src_y, >+int I420AlphaToARGB(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- const uint8* src_a, >+ const uint8_t* src_a, > int src_stride_a, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >@@ -711,15 +926,15 @@ int I420AlphaToARGB(const uint8* src_y, > > // Convert I420 with Alpha to ABGR. > LIBYUV_API >-int I420AlphaToABGR(const uint8* src_y, >+int I420AlphaToABGR(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- const uint8* src_a, >+ const uint8_t* src_a, > int src_stride_a, >- uint8* dst_abgr, >+ uint8_t* dst_abgr, > int dst_stride_abgr, > int width, > int height, >@@ -733,14 +948,14 @@ int I420AlphaToABGR(const uint8* src_y, > > // Convert I400 to ARGB. > LIBYUV_API >-int I400ToARGB(const uint8* src_y, >+int I400ToARGB(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*I400ToARGBRow)(const uint8* y_buf, uint8* rgb_buf, int width) = >+ void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) = > I400ToARGBRow_C; > if (!src_y || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -800,14 +1015,14 @@ int I400ToARGB(const uint8* src_y, > > // Convert J400 to ARGB. > LIBYUV_API >-int J400ToARGB(const uint8* src_y, >+int J400ToARGB(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*J400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int width) = >+ void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) = > J400ToARGBRow_C; > if (!src_y || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -865,87 +1080,87 @@ int J400ToARGB(const uint8* src_y, > } > > // Shuffle table for converting BGRA to ARGB. >-static uvec8 kShuffleMaskBGRAToARGB = {3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, >- 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u}; >+static const uvec8 kShuffleMaskBGRAToARGB = { >+ 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u}; > > // Shuffle table for converting ABGR to ARGB. >-static uvec8 kShuffleMaskABGRToARGB = {2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, >- 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u}; >+static const uvec8 kShuffleMaskABGRToARGB = { >+ 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u}; > > // Shuffle table for converting RGBA to ARGB. >-static uvec8 kShuffleMaskRGBAToARGB = {1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, >- 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u}; >+static const uvec8 kShuffleMaskRGBAToARGB = { >+ 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u}; > > // Convert BGRA to ARGB. > LIBYUV_API >-int BGRAToARGB(const uint8* src_bgra, >+int BGRAToARGB(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, >- (const uint8*)(&kShuffleMaskBGRAToARGB), width, height); >+ (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); > } > > // Convert ARGB to BGRA (same as BGRAToARGB). > LIBYUV_API >-int ARGBToBGRA(const uint8* src_bgra, >+int ARGBToBGRA(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, >- (const uint8*)(&kShuffleMaskBGRAToARGB), width, height); >+ (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); > } > > // Convert ABGR to ARGB. > LIBYUV_API >-int ABGRToARGB(const uint8* src_abgr, >+int ABGRToARGB(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, >- (const uint8*)(&kShuffleMaskABGRToARGB), width, height); >+ (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); > } > > // Convert ARGB to ABGR to (same as ABGRToARGB). > LIBYUV_API >-int ARGBToABGR(const uint8* src_abgr, >+int ARGBToABGR(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, >- (const uint8*)(&kShuffleMaskABGRToARGB), width, height); >+ (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); > } > > // Convert RGBA to ARGB. > LIBYUV_API >-int RGBAToARGB(const uint8* src_rgba, >+int RGBAToARGB(const uint8_t* src_rgba, > int src_stride_rgba, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb, >- (const uint8*)(&kShuffleMaskRGBAToARGB), width, height); >+ (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height); > } > > // Convert RGB24 to ARGB. > LIBYUV_API >-int RGB24ToARGB(const uint8* src_rgb24, >+int RGB24ToARGB(const uint8_t* src_rgb24, > int src_stride_rgb24, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >+ void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = > RGB24ToARGBRow_C; > if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -978,14 +1193,6 @@ int RGB24ToARGB(const uint8* src_rgb24, > } > } > #endif >-#if defined(HAS_RGB24TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RGB24ToARGBRow = RGB24ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- RGB24ToARGBRow = RGB24ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_RGB24TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA; >@@ -1005,14 +1212,14 @@ int RGB24ToARGB(const uint8* src_rgb24, > > // Convert RAW to ARGB. > LIBYUV_API >-int RAWToARGB(const uint8* src_raw, >+int RAWToARGB(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) = >+ void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = > RAWToARGBRow_C; > if (!src_raw || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1045,14 +1252,6 @@ int RAWToARGB(const uint8* src_raw, > } > } > #endif >-#if defined(HAS_RAWTOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RAWToARGBRow = RAWToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- RAWToARGBRow = RAWToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_RAWTOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > RAWToARGBRow = RAWToARGBRow_Any_MSA; >@@ -1072,15 +1271,15 @@ int RAWToARGB(const uint8* src_raw, > > // Convert RGB565 to ARGB. > LIBYUV_API >-int RGB565ToARGB(const uint8* src_rgb565, >+int RGB565ToARGB(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int width) = >- RGB565ToARGBRow_C; >+ void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb, >+ int width) = RGB565ToARGBRow_C; > if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1120,14 +1319,6 @@ int RGB565ToARGB(const uint8* src_rgb565, > } > } > #endif >-#if defined(HAS_RGB565TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- RGB565ToARGBRow = RGB565ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_RGB565TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA; >@@ -1147,14 +1338,14 @@ int RGB565ToARGB(const uint8* src_rgb565, > > // Convert ARGB1555 to ARGB. > LIBYUV_API >-int ARGB1555ToARGB(const uint8* src_argb1555, >+int ARGB1555ToARGB(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb, >+ void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb, > int width) = ARGB1555ToARGBRow_C; > if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1195,14 +1386,6 @@ int ARGB1555ToARGB(const uint8* src_argb1555, > } > } > #endif >-#if defined(HAS_ARGB1555TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 4)) { >- ARGB1555ToARGBRow = ARGB1555ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGB1555TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA; >@@ -1222,14 +1405,14 @@ int ARGB1555ToARGB(const uint8* src_argb1555, > > // Convert ARGB4444 to ARGB. > LIBYUV_API >-int ARGB4444ToARGB(const uint8* src_argb4444, >+int ARGB4444ToARGB(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb, >+ void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb, > int width) = ARGB4444ToARGBRow_C; > if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1270,14 +1453,6 @@ int ARGB4444ToARGB(const uint8* src_argb4444, > } > } > #endif >-#if defined(HAS_ARGB4444TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 4)) { >- ARGB4444ToARGBRow = ARGB4444ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGB4444TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; >@@ -1295,20 +1470,116 @@ int ARGB4444ToARGB(const uint8* src_argb4444, > return 0; > } > >-// Convert NV12 to ARGB. >+// Convert AR30 to ARGB. > LIBYUV_API >-int NV12ToARGB(const uint8* src_y, >- int src_stride_y, >- const uint8* src_uv, >- int src_stride_uv, >- uint8* dst_argb, >+int AR30ToARGB(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, int width) = >- NV12ToARGBRow_C; >+ if (!src_ar30 || !dst_argb || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; >+ src_stride_ar30 = -src_stride_ar30; >+ } >+ // Coalesce rows. >+ if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) { >+ width *= height; >+ height = 1; >+ src_stride_ar30 = dst_stride_argb = 0; >+ } >+ for (y = 0; y < height; ++y) { >+ AR30ToARGBRow_C(src_ar30, dst_argb, width); >+ src_ar30 += src_stride_ar30; >+ dst_argb += dst_stride_argb; >+ } >+ return 0; >+} >+ >+// Convert AR30 to ABGR. >+LIBYUV_API >+int AR30ToABGR(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ int y; >+ if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; >+ src_stride_ar30 = -src_stride_ar30; >+ } >+ // Coalesce rows. >+ if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) { >+ width *= height; >+ height = 1; >+ src_stride_ar30 = dst_stride_abgr = 0; >+ } >+ for (y = 0; y < height; ++y) { >+ AR30ToABGRRow_C(src_ar30, dst_abgr, width); >+ src_ar30 += src_stride_ar30; >+ dst_abgr += dst_stride_abgr; >+ } >+ return 0; >+} >+ >+// Convert AR30 to AB30. >+LIBYUV_API >+int AR30ToAB30(const uint8_t* src_ar30, >+ int src_stride_ar30, >+ uint8_t* dst_ab30, >+ int dst_stride_ab30, >+ int width, >+ int height) { >+ int y; >+ if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; >+ src_stride_ar30 = -src_stride_ar30; >+ } >+ // Coalesce rows. >+ if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) { >+ width *= height; >+ height = 1; >+ src_stride_ar30 = dst_stride_ab30 = 0; >+ } >+ for (y = 0; y < height; ++y) { >+ AR30ToAB30Row_C(src_ar30, dst_ab30, width); >+ src_ar30 += src_stride_ar30; >+ dst_ab30 += dst_stride_ab30; >+ } >+ return 0; >+} >+ >+// Convert NV12 to ARGB with matrix >+static int NV12ToARGBMatrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*NV12ToARGBRow)( >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; > if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1342,14 +1613,6 @@ int NV12ToARGB(const uint8* src_y, > } > } > #endif >-#if defined(HAS_NV12TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- NV12ToARGBRow = NV12ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_NV12TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > NV12ToARGBRow = NV12ToARGBRow_Any_MSA; >@@ -1360,7 +1623,7 @@ int NV12ToARGB(const uint8* src_y, > #endif > > for (y = 0; y < height; ++y) { >- NV12ToARGBRow(src_y, src_uv, dst_argb, &kYuvI601Constants, width); >+ NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width); > dst_argb += dst_stride_argb; > src_y += src_stride_y; > if (y & 1) { >@@ -1370,21 +1633,21 @@ int NV12ToARGB(const uint8* src_y, > return 0; > } > >-// Convert NV21 to ARGB. >-LIBYUV_API >-int NV21ToARGB(const uint8* src_y, >- int src_stride_y, >- const uint8* src_uv, >- int src_stride_uv, >- uint8* dst_argb, >- int dst_stride_argb, >- int width, >- int height) { >+// Convert NV21 to ARGB with matrix >+static int NV21ToARGBMatrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { > int y; >- void (*NV21ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, int width) = >- NV21ToARGBRow_C; >- if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) { >+ void (*NV21ToARGBRow)( >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C; >+ if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) { > return -1; > } > // Negative height means invert the image. >@@ -1427,9 +1690,110 @@ int NV21ToARGB(const uint8* src_y, > #endif > > for (y = 0; y < height; ++y) { >- NV21ToARGBRow(src_y, src_uv, dst_argb, &kYuvI601Constants, width); >+ NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width); > dst_argb += dst_stride_argb; > src_y += src_stride_y; >+ if (y & 1) { >+ src_vu += src_stride_vu; >+ } >+ } >+ return 0; >+} >+ >+// Convert NV12 to ARGB. >+LIBYUV_API >+int NV12ToARGB(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height) { >+ return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb, >+ dst_stride_argb, &kYuvI601Constants, width, height); >+} >+ >+// Convert NV21 to ARGB. >+LIBYUV_API >+int NV21ToARGB(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height) { >+ return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb, >+ dst_stride_argb, &kYuvI601Constants, width, height); >+} >+ >+// Convert NV12 to ABGR. >+// To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix. >+// To swap the UV use NV12 instead of NV21.LIBYUV_API >+int NV12ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr, >+ dst_stride_abgr, &kYvuI601Constants, width, height); >+} >+ >+// Convert NV21 to ABGR. >+LIBYUV_API >+int NV21ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr, >+ dst_stride_abgr, &kYvuI601Constants, width, height); >+} >+ >+// TODO(fbarchard): Consider SSSE3 2 step conversion. >+// Convert NV12 to RGB24 with matrix >+static int NV12ToRGB24Matrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*NV12ToRGB24Row)( >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C; >+ if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; >+ dst_stride_rgb24 = -dst_stride_rgb24; >+ } >+#if defined(HAS_NV12TORGB24ROW_NEON) >+ if (TestCpuFlag(kCpuHasNEON)) { >+ NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON; >+ if (IS_ALIGNED(width, 8)) { >+ NV12ToRGB24Row = NV12ToRGB24Row_NEON; >+ } >+ } >+#endif >+ >+ for (y = 0; y < height; ++y) { >+ NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width); >+ dst_rgb24 += dst_stride_rgb24; >+ src_y += src_stride_y; > if (y & 1) { > src_uv += src_stride_uv; > } >@@ -1437,18 +1801,92 @@ int NV21ToARGB(const uint8* src_y, > return 0; > } > >+// Convert NV21 to RGB24 with matrix >+static int NV21ToRGB24Matrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*NV21ToRGB24Row)( >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C; >+ if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; >+ dst_stride_rgb24 = -dst_stride_rgb24; >+ } >+#if defined(HAS_NV21TORGB24ROW_NEON) >+ if (TestCpuFlag(kCpuHasNEON)) { >+ NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON; >+ if (IS_ALIGNED(width, 8)) { >+ NV21ToRGB24Row = NV21ToRGB24Row_NEON; >+ } >+ } >+#endif >+ >+ for (y = 0; y < height; ++y) { >+ NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width); >+ dst_rgb24 += dst_stride_rgb24; >+ src_y += src_stride_y; >+ if (y & 1) { >+ src_vu += src_stride_vu; >+ } >+ } >+ return 0; >+} >+ >+// TODO(fbarchard): \(fbarchard): NV12ToRAW can be implemented by mirrored >+// matrix. Convert NV12 to RGB24. >+LIBYUV_API >+int NV12ToRGB24(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ int width, >+ int height) { >+ return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv, >+ dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, >+ width, height); >+} >+ >+// Convert NV21 to RGB24. >+LIBYUV_API >+int NV21ToRGB24(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_vu, >+ int src_stride_vu, >+ uint8_t* dst_rgb24, >+ int dst_stride_rgb24, >+ int width, >+ int height) { >+ return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu, >+ dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, >+ width, height); >+} >+ > // Convert M420 to ARGB. > LIBYUV_API >-int M420ToARGB(const uint8* src_m420, >+int M420ToARGB(const uint8_t* src_m420, > int src_stride_m420, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*NV12ToARGBRow)(const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, int width) = >- NV12ToARGBRow_C; >+ void (*NV12ToARGBRow)( >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; > if (!src_m420 || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1482,14 +1920,6 @@ int M420ToARGB(const uint8* src_m420, > } > } > #endif >-#if defined(HAS_NV12TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- NV12ToARGBRow = NV12ToARGBRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- NV12ToARGBRow = NV12ToARGBRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_NV12TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > NV12ToARGBRow = NV12ToARGBRow_Any_MSA; >@@ -1516,14 +1946,14 @@ int M420ToARGB(const uint8* src_m420, > > // Convert YUY2 to ARGB. > LIBYUV_API >-int YUY2ToARGB(const uint8* src_yuy2, >+int YUY2ToARGB(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, >+ void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, int width) = > YUY2ToARGBRow_C; > if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) { >@@ -1583,14 +2013,14 @@ int YUY2ToARGB(const uint8* src_yuy2, > > // Convert UYVY to ARGB. > LIBYUV_API >-int UYVYToARGB(const uint8* src_uyvy, >+int UYVYToARGB(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, >+ void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, int width) = > UYVYToARGBRow_C; > if (!src_uyvy || !dst_argb || width <= 0 || height == 0) { >@@ -1647,6 +2077,121 @@ int UYVYToARGB(const uint8* src_uyvy, > } > return 0; > } >+static void WeavePixels(const uint8_t* src_u, >+ const uint8_t* src_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_uv, >+ int width) { >+ int i; >+ for (i = 0; i < width; ++i) { >+ dst_uv[0] = *src_u; >+ dst_uv[1] = *src_v; >+ dst_uv += 2; >+ src_u += src_pixel_stride_uv; >+ src_v += src_pixel_stride_uv; >+ } >+} >+ >+// Convert Android420 to ARGB. >+LIBYUV_API >+int Android420ToARGBMatrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ uint8_t* dst_uv; >+ const ptrdiff_t vu_off = src_v - src_u; >+ int halfwidth = (width + 1) >> 1; >+ int halfheight = (height + 1) >> 1; >+ if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ halfheight = (height + 1) >> 1; >+ dst_argb = dst_argb + (height - 1) * dst_stride_argb; >+ dst_stride_argb = -dst_stride_argb; >+ } >+ >+ // I420 >+ if (src_pixel_stride_uv == 1) { >+ return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_argb, dst_stride_argb, >+ yuvconstants, width, height); >+ // NV21 >+ } >+ if (src_pixel_stride_uv == 2 && vu_off == -1 && >+ src_stride_u == src_stride_v) { >+ return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb, >+ dst_stride_argb, yuvconstants, width, height); >+ // NV12 >+ } >+ if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { >+ return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb, >+ dst_stride_argb, yuvconstants, width, height); >+ } >+ >+ // General case fallback creates NV12 >+ align_buffer_64(plane_uv, halfwidth * 2 * halfheight); >+ dst_uv = plane_uv; >+ for (y = 0; y < halfheight; ++y) { >+ WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth); >+ src_u += src_stride_u; >+ src_v += src_stride_v; >+ dst_uv += halfwidth * 2; >+ } >+ NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb, >+ dst_stride_argb, yuvconstants, width, height); >+ free_aligned_buffer_64(plane_uv); >+ return 0; >+} >+ >+// Convert Android420 to ARGB. >+LIBYUV_API >+int Android420ToARGB(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int width, >+ int height) { >+ return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, src_pixel_stride_uv, dst_argb, >+ dst_stride_argb, &kYuvI601Constants, width, >+ height); >+} >+ >+// Convert Android420 to ABGR. >+LIBYUV_API >+int Android420ToABGR(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ int src_pixel_stride_uv, >+ uint8_t* dst_abgr, >+ int dst_stride_abgr, >+ int width, >+ int height) { >+ return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u, >+ src_stride_u, src_pixel_stride_uv, dst_abgr, >+ dst_stride_abgr, &kYvuI601Constants, width, >+ height); >+} > > #ifdef __cplusplus > } // extern "C" >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from.cc >index 0f52f9ef9e0..b5587ced625 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from.cc >@@ -30,17 +30,17 @@ static __inline int Abs(int v) { > } > > // I420 To any I4xx YUV format with mirroring. >-static int I420ToI4xx(const uint8* src_y, >+static int I420ToI4xx(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int src_y_width, > int src_y_height, >@@ -65,20 +65,64 @@ static int I420ToI4xx(const uint8* src_y, > return 0; > } > >+// Convert 8 bit YUV to 10 bit. >+LIBYUV_API >+int I420ToI010(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ uint16_t* dst_u, >+ int dst_stride_u, >+ uint16_t* dst_v, >+ int dst_stride_v, >+ int width, >+ int height) { >+ int halfwidth = (width + 1) >> 1; >+ int halfheight = (height + 1) >> 1; >+ if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ halfheight = (height + 1) >> 1; >+ src_y = src_y + (height - 1) * src_stride_y; >+ src_u = src_u + (halfheight - 1) * src_stride_u; >+ src_v = src_v + (halfheight - 1) * src_stride_v; >+ src_stride_y = -src_stride_y; >+ src_stride_u = -src_stride_u; >+ src_stride_v = -src_stride_v; >+ } >+ >+ // Convert Y plane. >+ Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width, >+ height); >+ // Convert UV planes. >+ Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth, >+ halfheight); >+ Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth, >+ halfheight); >+ return 0; >+} >+ > // 420 chroma is 1/2 width, 1/2 height > // 422 chroma is 1/2 width, 1x height > LIBYUV_API >-int I420ToI422(const uint8* src_y, >+int I420ToI422(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -93,17 +137,17 @@ int I420ToI422(const uint8* src_y, > // 420 chroma is 1/2 width, 1/2 height > // 444 chroma is 1x width, 1x height > LIBYUV_API >-int I420ToI444(const uint8* src_y, >+int I420ToI444(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -117,9 +161,9 @@ int I420ToI444(const uint8* src_y, > > // Copy to I400. Source can be I420,422,444,400,NV12,NV21 > LIBYUV_API >-int I400Copy(const uint8* src_y, >+int I400Copy(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { >@@ -137,19 +181,19 @@ int I400Copy(const uint8* src_y, > } > > LIBYUV_API >-int I422ToYUY2(const uint8* src_y, >+int I422ToYUY2(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_yuy2, >+ uint8_t* dst_yuy2, > int dst_stride_yuy2, > int width, > int height) { > int y; >- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_yuy2, int width) = >+ void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_yuy2, int width) = > I422ToYUY2Row_C; > if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) { > return -1; >@@ -175,6 +219,14 @@ int I422ToYUY2(const uint8* src_y, > } > } > #endif >+#if defined(HAS_I422TOYUY2ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToYUY2Row = I422ToYUY2Row_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToYUY2Row = I422ToYUY2Row_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOYUY2ROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToYUY2Row = I422ToYUY2Row_Any_NEON; >@@ -195,19 +247,19 @@ int I422ToYUY2(const uint8* src_y, > } > > LIBYUV_API >-int I420ToYUY2(const uint8* src_y, >+int I420ToYUY2(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_yuy2, >+ uint8_t* dst_yuy2, > int dst_stride_yuy2, > int width, > int height) { > int y; >- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_yuy2, int width) = >+ void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_yuy2, int width) = > I422ToYUY2Row_C; > if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) { > return -1; >@@ -226,6 +278,14 @@ int I420ToYUY2(const uint8* src_y, > } > } > #endif >+#if defined(HAS_I422TOYUY2ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToYUY2Row = I422ToYUY2Row_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToYUY2Row = I422ToYUY2Row_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOYUY2ROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToYUY2Row = I422ToYUY2Row_Any_NEON; >@@ -259,19 +319,19 @@ int I420ToYUY2(const uint8* src_y, > } > > LIBYUV_API >-int I422ToUYVY(const uint8* src_y, >+int I422ToUYVY(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_uyvy, >+ uint8_t* dst_uyvy, > int dst_stride_uyvy, > int width, > int height) { > int y; >- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_uyvy, int width) = >+ void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_uyvy, int width) = > I422ToUYVYRow_C; > if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) { > return -1; >@@ -297,6 +357,14 @@ int I422ToUYVY(const uint8* src_y, > } > } > #endif >+#if defined(HAS_I422TOUYVYROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToUYVYRow = I422ToUYVYRow_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToUYVYRow = I422ToUYVYRow_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOUYVYROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToUYVYRow = I422ToUYVYRow_Any_NEON; >@@ -325,19 +393,19 @@ int I422ToUYVY(const uint8* src_y, > } > > LIBYUV_API >-int I420ToUYVY(const uint8* src_y, >+int I420ToUYVY(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_uyvy, >+ uint8_t* dst_uyvy, > int dst_stride_uyvy, > int width, > int height) { > int y; >- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_uyvy, int width) = >+ void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_uyvy, int width) = > I422ToUYVYRow_C; > if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) { > return -1; >@@ -356,6 +424,14 @@ int I420ToUYVY(const uint8* src_y, > } > } > #endif >+#if defined(HAS_I422TOUYVYROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToUYVYRow = I422ToUYVYRow_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToUYVYRow = I422ToUYVYRow_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOUYVYROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToUYVYRow = I422ToUYVYRow_Any_NEON; >@@ -390,15 +466,15 @@ int I420ToUYVY(const uint8* src_y, > > // TODO(fbarchard): test negative height for invert. > LIBYUV_API >-int I420ToNV12(const uint8* src_y, >+int I420ToNV12(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height) { >@@ -417,15 +493,15 @@ int I420ToNV12(const uint8* src_y, > } > > LIBYUV_API >-int I420ToNV21(const uint8* src_y, >+int I420ToNV21(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_vu, >+ uint8_t* dst_vu, > int dst_stride_vu, > int width, > int height) { >@@ -435,20 +511,20 @@ int I420ToNV21(const uint8* src_y, > } > > // Convert I422 to RGBA with matrix >-static int I420ToRGBAMatrix(const uint8* src_y, >+static int I420ToRGBAMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToRGBARow_C; > if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) { >@@ -484,15 +560,6 @@ static int I420ToRGBAMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TORGBAROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) { >- I422ToRGBARow = I422ToRGBARow_DSPR2; >- } >-#endif > #if defined(HAS_I422TORGBAROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToRGBARow = I422ToRGBARow_Any_MSA; >@@ -516,13 +583,13 @@ static int I420ToRGBAMatrix(const uint8* src_y, > > // Convert I420 to RGBA. > LIBYUV_API >-int I420ToRGBA(const uint8* src_y, >+int I420ToRGBA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height) { >@@ -533,13 +600,13 @@ int I420ToRGBA(const uint8* src_y, > > // Convert I420 to BGRA. > LIBYUV_API >-int I420ToBGRA(const uint8* src_y, >+int I420ToBGRA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_bgra, >+ uint8_t* dst_bgra, > int dst_stride_bgra, > int width, > int height) { >@@ -551,20 +618,20 @@ int I420ToBGRA(const uint8* src_y, > } > > // Convert I420 to RGB24 with matrix >-static int I420ToRGB24Matrix(const uint8* src_y, >+static int I420ToRGB24Matrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I422ToRGB24Row)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToRGB24Row_C; > if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) { >@@ -623,13 +690,13 @@ static int I420ToRGB24Matrix(const uint8* src_y, > > // Convert I420 to RGB24. > LIBYUV_API >-int I420ToRGB24(const uint8* src_y, >+int I420ToRGB24(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height) { >@@ -640,13 +707,13 @@ int I420ToRGB24(const uint8* src_y, > > // Convert I420 to RAW. > LIBYUV_API >-int I420ToRAW(const uint8* src_y, >+int I420ToRAW(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_raw, >+ uint8_t* dst_raw, > int dst_stride_raw, > int width, > int height) { >@@ -659,13 +726,13 @@ int I420ToRAW(const uint8* src_y, > > // Convert H420 to RGB24. > LIBYUV_API >-int H420ToRGB24(const uint8* src_y, >+int H420ToRGB24(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height) { >@@ -676,13 +743,13 @@ int H420ToRGB24(const uint8* src_y, > > // Convert H420 to RAW. > LIBYUV_API >-int H420ToRAW(const uint8* src_y, >+int H420ToRAW(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_raw, >+ uint8_t* dst_raw, > int dst_stride_raw, > int width, > int height) { >@@ -695,19 +762,19 @@ int H420ToRAW(const uint8* src_y, > > // Convert I420 to ARGB1555. > LIBYUV_API >-int I420ToARGB1555(const uint8* src_y, >+int I420ToARGB1555(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb1555, >+ uint8_t* dst_argb1555, > int dst_stride_argb1555, > int width, > int height) { > int y; >- void (*I422ToARGB1555Row)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) = I422ToARGB1555Row_C; > if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 || >@@ -744,14 +811,6 @@ int I420ToARGB1555(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TOARGB1555ROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- I422ToARGB1555Row = I422ToARGB1555Row_Any_DSPR2; >- if (IS_ALIGNED(width, 4)) { >- I422ToARGB1555Row = I422ToARGB1555Row_DSPR2; >- } >- } >-#endif > #if defined(HAS_I422TOARGB1555ROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA; >@@ -776,19 +835,19 @@ int I420ToARGB1555(const uint8* src_y, > > // Convert I420 to ARGB4444. > LIBYUV_API >-int I420ToARGB4444(const uint8* src_y, >+int I420ToARGB4444(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_argb4444, >+ uint8_t* dst_argb4444, > int dst_stride_argb4444, > int width, > int height) { > int y; >- void (*I422ToARGB4444Row)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) = I422ToARGB4444Row_C; > if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 || >@@ -825,14 +884,6 @@ int I420ToARGB4444(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TOARGB4444ROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- I422ToARGB4444Row = I422ToARGB4444Row_Any_DSPR2; >- if (IS_ALIGNED(width, 4)) { >- I422ToARGB4444Row = I422ToARGB4444Row_DSPR2; >- } >- } >-#endif > #if defined(HAS_I422TOARGB4444ROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA; >@@ -857,19 +908,19 @@ int I420ToARGB4444(const uint8* src_y, > > // Convert I420 to RGB565. > LIBYUV_API >-int I420ToRGB565(const uint8* src_y, >+int I420ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height) { > int y; >- void (*I422ToRGB565Row)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToRGB565Row_C; > if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) { >@@ -928,19 +979,19 @@ int I420ToRGB565(const uint8* src_y, > > // Convert I422 to RGB565. > LIBYUV_API >-int I422ToRGB565(const uint8* src_y, >+int I422ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height) { > int y; >- void (*I422ToRGB565Row)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToRGB565Row_C; > if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) { >@@ -996,30 +1047,30 @@ int I422ToRGB565(const uint8* src_y, > } > > // Ordered 8x8 dither for 888 to 565. Values from 0 to 7. >-static const uint8 kDither565_4x4[16] = { >+static const uint8_t kDither565_4x4[16] = { > 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2, > }; > > // Convert I420 to RGB565 with dithering. > LIBYUV_API >-int I420ToRGB565Dither(const uint8* src_y, >+int I420ToRGB565Dither(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, >- const uint8* dither4x4, >+ const uint8_t* dither4x4, > int width, > int height) { > int y; >- void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToARGBRow_C; >- void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb, >- const uint32 dither4, int width) = >+ void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb, >+ const uint32_t dither4, int width) = > ARGBToRGB565DitherRow_C; > if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) { > return -1; >@@ -1057,14 +1108,6 @@ int I420ToRGB565Dither(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) { >- I422ToARGBRow = I422ToARGBRow_DSPR2; >- } >-#endif > #if defined(HAS_I422TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGBRow = I422ToARGBRow_Any_MSA; >@@ -1111,8 +1154,8 @@ int I420ToRGB565Dither(const uint8* src_y, > for (y = 0; y < height; ++y) { > I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width); > ARGBToRGB565DitherRow(row_argb, dst_rgb565, >- *(uint32*)(dither4x4 + ((y & 3) << 2)), // NOLINT >- width); // NOLINT >+ *(uint32_t*)(dither4x4 + ((y & 3) << 2)), // NOLINT >+ width); // NOLINT > dst_rgb565 += dst_stride_rgb565; > src_y += src_stride_y; > if (y & 1) { >@@ -1125,20 +1168,111 @@ int I420ToRGB565Dither(const uint8* src_y, > return 0; > } > >+// Convert I420 to AR30 with matrix >+static int I420ToAR30Matrix(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width, >+ int height) { >+ int y; >+ void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, int width) = >+ I422ToAR30Row_C; >+ >+ if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) { >+ return -1; >+ } >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30; >+ dst_stride_ar30 = -dst_stride_ar30; >+ } >+ >+#if defined(HAS_I422TOAR30ROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ I422ToAR30Row = I422ToAR30Row_Any_SSSE3; >+ if (IS_ALIGNED(width, 8)) { >+ I422ToAR30Row = I422ToAR30Row_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_I422TOAR30ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToAR30Row = I422ToAR30Row_Any_AVX2; >+ if (IS_ALIGNED(width, 16)) { >+ I422ToAR30Row = I422ToAR30Row_AVX2; >+ } >+ } >+#endif >+ >+ for (y = 0; y < height; ++y) { >+ I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width); >+ dst_ar30 += dst_stride_ar30; >+ src_y += src_stride_y; >+ if (y & 1) { >+ src_u += src_stride_u; >+ src_v += src_stride_v; >+ } >+ } >+ return 0; >+} >+ >+// Convert I420 to AR30. >+LIBYUV_API >+int I420ToAR30(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_ar30, dst_stride_ar30, >+ &kYuvI601Constants, width, height); >+} >+ >+// Convert H420 to AR30. >+LIBYUV_API >+int H420ToAR30(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_u, >+ int src_stride_u, >+ const uint8_t* src_v, >+ int src_stride_v, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, >+ src_stride_v, dst_ar30, dst_stride_ar30, >+ &kYvuH709Constants, width, height); >+} >+ > // Convert I420 to specified format > LIBYUV_API >-int ConvertFromI420(const uint8* y, >+int ConvertFromI420(const uint8_t* y, > int y_stride, >- const uint8* u, >+ const uint8_t* u, > int u_stride, >- const uint8* v, >+ const uint8_t* v, > int v_stride, >- uint8* dst_sample, >+ uint8_t* dst_sample, > int dst_sample_stride, > int width, > int height, >- uint32 fourcc) { >- uint32 format = CanonicalFourCC(fourcc); >+ uint32_t fourcc) { >+ uint32_t format = CanonicalFourCC(fourcc); > int r = 0; > if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) { > return -1; >@@ -1200,13 +1334,18 @@ int ConvertFromI420(const uint8* y, > dst_sample_stride ? dst_sample_stride : width * 4, width, > height); > break; >+ case FOURCC_AR30: >+ r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample, >+ dst_sample_stride ? dst_sample_stride : width * 4, width, >+ height); >+ break; > case FOURCC_I400: > r = I400Copy(y, y_stride, dst_sample, > dst_sample_stride ? dst_sample_stride : width, width, > height); > break; > case FOURCC_NV12: { >- uint8* dst_uv = dst_sample + width * height; >+ uint8_t* dst_uv = dst_sample + width * height; > r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample, > dst_sample_stride ? dst_sample_stride : width, dst_uv, > dst_sample_stride ? dst_sample_stride : width, width, >@@ -1214,7 +1353,7 @@ int ConvertFromI420(const uint8* y, > break; > } > case FOURCC_NV21: { >- uint8* dst_vu = dst_sample + width * height; >+ uint8_t* dst_vu = dst_sample + width * height; > r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample, > dst_sample_stride ? dst_sample_stride : width, dst_vu, > dst_sample_stride ? dst_sample_stride : width, width, >@@ -1228,8 +1367,8 @@ int ConvertFromI420(const uint8* y, > dst_sample_stride = dst_sample_stride ? dst_sample_stride : width; > int halfstride = (dst_sample_stride + 1) / 2; > int halfheight = (height + 1) / 2; >- uint8* dst_u; >- uint8* dst_v; >+ uint8_t* dst_u; >+ uint8_t* dst_v; > if (format == FOURCC_YV12) { > dst_v = dst_sample + dst_sample_stride * height; > dst_u = dst_v + halfstride * halfheight; >@@ -1246,8 +1385,8 @@ int ConvertFromI420(const uint8* y, > case FOURCC_YV16: { > dst_sample_stride = dst_sample_stride ? dst_sample_stride : width; > int halfstride = (dst_sample_stride + 1) / 2; >- uint8* dst_u; >- uint8* dst_v; >+ uint8_t* dst_u; >+ uint8_t* dst_v; > if (format == FOURCC_YV16) { > dst_v = dst_sample + dst_sample_stride * height; > dst_u = dst_v + halfstride * height; >@@ -1263,8 +1402,8 @@ int ConvertFromI420(const uint8* y, > case FOURCC_I444: > case FOURCC_YV24: { > dst_sample_stride = dst_sample_stride ? dst_sample_stride : width; >- uint8* dst_u; >- uint8* dst_v; >+ uint8_t* dst_u; >+ uint8_t* dst_v; > if (format == FOURCC_YV24) { > dst_v = dst_sample + dst_sample_stride * height; > dst_u = dst_v + dst_sample_stride * height; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc >index 88f38279ace..16b838458f0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc >@@ -22,21 +22,21 @@ extern "C" { > > // ARGB little endian (bgra in memory) to I444 > LIBYUV_API >-int ARGBToI444(const uint8* src_argb, >+int ARGBToI444(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; >- void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v, >- int width) = ARGBToUV444Row_C; >+ void (*ARGBToUV444Row)(const uint8_t* src_argb, uint8_t* dst_u, >+ uint8_t* dst_v, int width) = ARGBToUV444Row_C; > if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; > } >@@ -100,14 +100,6 @@ int ARGBToI444(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGBTOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGBToYRow = ARGBToYRow_Any_MSA; >@@ -130,20 +122,21 @@ int ARGBToI444(const uint8* src_argb, > > // ARGB little endian (bgra in memory) to I422 > LIBYUV_API >-int ARGBToI422(const uint8* src_argb, >+int ARGBToI422(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -197,22 +190,6 @@ int ARGBToI422(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > > #if defined(HAS_ARGBTOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { >@@ -243,22 +220,23 @@ int ARGBToI422(const uint8* src_argb, > } > > LIBYUV_API >-int ARGBToNV12(const uint8* src_argb, >+int ARGBToNV12(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height) { > int y; > int halfwidth = (width + 1) >> 1; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; >- void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, >- int width) = MergeUVRow_C; >+ void (*MergeUVRow_)(const uint8_t* src_u, const uint8_t* src_v, >+ uint8_t* dst_uv, int width) = MergeUVRow_C; > if (!src_argb || !dst_y || !dst_uv || width <= 0 || height == 0) { > return -1; > } >@@ -344,22 +322,6 @@ int ARGBToNV12(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_MERGEUVROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > MergeUVRow_ = MergeUVRow_Any_MSA; >@@ -371,7 +333,7 @@ int ARGBToNV12(const uint8* src_argb, > { > // Allocate a rows of uv. > align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2); >- uint8* row_v = row_u + ((halfwidth + 31) & ~31); >+ uint8_t* row_v = row_u + ((halfwidth + 31) & ~31); > > for (y = 0; y < height - 1; y += 2) { > ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); >@@ -394,23 +356,24 @@ int ARGBToNV12(const uint8* src_argb, > > // Same as NV12 but U and V swapped. > LIBYUV_API >-int ARGBToNV21(const uint8* src_argb, >+int ARGBToNV21(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >- int dst_stride_uv, >+ uint8_t* dst_vu, >+ int dst_stride_vu, > int width, > int height) { > int y; > int halfwidth = (width + 1) >> 1; >- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; >- void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, >- int width) = MergeUVRow_C; >- if (!src_argb || !dst_y || !dst_uv || width <= 0 || height == 0) { >+ void (*MergeUVRow_)(const uint8_t* src_u, const uint8_t* src_v, >+ uint8_t* dst_vu, int width) = MergeUVRow_C; >+ if (!src_argb || !dst_y || !dst_vu || width <= 0 || height == 0) { > return -1; > } > // Negative height means invert the image. >@@ -495,22 +458,6 @@ int ARGBToNV21(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_MERGEUVROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > MergeUVRow_ = MergeUVRow_Any_MSA; >@@ -522,20 +469,20 @@ int ARGBToNV21(const uint8* src_argb, > { > // Allocate a rows of uv. > align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2); >- uint8* row_v = row_u + ((halfwidth + 31) & ~31); >+ uint8_t* row_v = row_u + ((halfwidth + 31) & ~31); > > for (y = 0; y < height - 1; y += 2) { > ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width); >- MergeUVRow_(row_v, row_u, dst_uv, halfwidth); >+ MergeUVRow_(row_v, row_u, dst_vu, halfwidth); > ARGBToYRow(src_argb, dst_y, width); > ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); > src_argb += src_stride_argb * 2; > dst_y += dst_stride_y * 2; >- dst_uv += dst_stride_uv; >+ dst_vu += dst_stride_vu; > } > if (height & 1) { > ARGBToUVRow(src_argb, 0, row_u, row_v, width); >- MergeUVRow_(row_v, row_u, dst_uv, halfwidth); >+ MergeUVRow_(row_v, row_u, dst_vu, halfwidth); > ARGBToYRow(src_argb, dst_y, width); > } > free_aligned_buffer_64(row_u); >@@ -545,19 +492,20 @@ int ARGBToNV21(const uint8* src_argb, > > // Convert ARGB to YUY2. > LIBYUV_API >-int ARGBToYUY2(const uint8* src_argb, >+int ARGBToYUY2(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yuy2, >+ uint8_t* dst_yuy2, > int dst_stride_yuy2, > int width, > int height) { > int y; >- void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; >- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_yuy2, int width) = >+ void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_yuy2, int width) = > I422ToYUY2Row_C; > > if (!src_argb || !dst_yuy2 || width <= 0 || height == 0) { >@@ -635,6 +583,14 @@ int ARGBToYUY2(const uint8* src_argb, > } > } > #endif >+#if defined(HAS_I422TOYUY2ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToYUY2Row = I422ToYUY2Row_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToYUY2Row = I422ToYUY2Row_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOYUY2ROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToYUY2Row = I422ToYUY2Row_Any_NEON; >@@ -643,22 +599,6 @@ int ARGBToYUY2(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_I422TOYUY2ROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToYUY2Row = I422ToYUY2Row_Any_MSA; >@@ -671,8 +611,8 @@ int ARGBToYUY2(const uint8* src_argb, > { > // Allocate a rows of yuv. > align_buffer_64(row_y, ((width + 63) & ~63) * 2); >- uint8* row_u = row_y + ((width + 63) & ~63); >- uint8* row_v = row_u + ((width + 63) & ~63) / 2; >+ uint8_t* row_u = row_y + ((width + 63) & ~63); >+ uint8_t* row_v = row_u + ((width + 63) & ~63) / 2; > > for (y = 0; y < height; ++y) { > ARGBToUVRow(src_argb, 0, row_u, row_v, width); >@@ -689,19 +629,20 @@ int ARGBToYUY2(const uint8* src_argb, > > // Convert ARGB to UYVY. > LIBYUV_API >-int ARGBToUYVY(const uint8* src_argb, >+int ARGBToUYVY(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_uyvy, >+ uint8_t* dst_uyvy, > int dst_stride_uyvy, > int width, > int height) { > int y; >- void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, uint8* dst_u, >- uint8* dst_v, int width) = ARGBToUVRow_C; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToUVRow)(const uint8_t* src_argb, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVRow_C; >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; >- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u, >- const uint8* src_v, uint8* dst_uyvy, int width) = >+ void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u, >+ const uint8_t* src_v, uint8_t* dst_uyvy, int width) = > I422ToUYVYRow_C; > > if (!src_argb || !dst_uyvy || width <= 0 || height == 0) { >@@ -779,6 +720,14 @@ int ARGBToUYVY(const uint8* src_argb, > } > } > #endif >+#if defined(HAS_I422TOUYVYROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ I422ToUYVYRow = I422ToUYVYRow_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ I422ToUYVYRow = I422ToUYVYRow_AVX2; >+ } >+ } >+#endif > #if defined(HAS_I422TOUYVYROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > I422ToUYVYRow = I422ToUYVYRow_Any_NEON; >@@ -787,22 +736,6 @@ int ARGBToUYVY(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif >-#if defined(HAS_ARGBTOUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToUVRow = ARGBToUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- ARGBToUVRow = ARGBToUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_I422TOUYVYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToUYVYRow = I422ToUYVYRow_Any_MSA; >@@ -815,8 +748,8 @@ int ARGBToUYVY(const uint8* src_argb, > { > // Allocate a rows of yuv. > align_buffer_64(row_y, ((width + 63) & ~63) * 2); >- uint8* row_u = row_y + ((width + 63) & ~63); >- uint8* row_v = row_u + ((width + 63) & ~63) / 2; >+ uint8_t* row_u = row_y + ((width + 63) & ~63); >+ uint8_t* row_v = row_u + ((width + 63) & ~63) / 2; > > for (y = 0; y < height; ++y) { > ARGBToUVRow(src_argb, 0, row_u, row_v, width); >@@ -833,14 +766,14 @@ int ARGBToUYVY(const uint8* src_argb, > > // Convert ARGB to I400. > LIBYUV_API >-int ARGBToI400(const uint8* src_argb, >+int ARGBToI400(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) = >+ void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = > ARGBToYRow_C; > if (!src_argb || !dst_y || width <= 0 || height == 0) { > return -1; >@@ -880,14 +813,6 @@ int ARGBToI400(const uint8* src_argb, > } > } > #endif >-#if defined(HAS_ARGBTOYROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ARGBToYRow = ARGBToYRow_Any_DSPR2; >- if (IS_ALIGNED(width, 8)) { >- ARGBToYRow = ARGBToYRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_ARGBTOYROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ARGBToYRow = ARGBToYRow_Any_MSA; >@@ -906,31 +831,31 @@ int ARGBToI400(const uint8* src_argb, > } > > // Shuffle table for converting ARGB to RGBA. >-static uvec8 kShuffleMaskARGBToRGBA = {3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, >- 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u}; >+static const uvec8 kShuffleMaskARGBToRGBA = { >+ 3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u}; > > // Convert ARGB to RGBA. > LIBYUV_API >-int ARGBToRGBA(const uint8* src_argb, >+int ARGBToRGBA(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height) { > return ARGBShuffle(src_argb, src_stride_argb, dst_rgba, dst_stride_rgba, >- (const uint8*)(&kShuffleMaskARGBToRGBA), width, height); >+ (const uint8_t*)(&kShuffleMaskARGBToRGBA), width, height); > } > > // Convert ARGB To RGB24. > LIBYUV_API >-int ARGBToRGB24(const uint8* src_argb, >+int ARGBToRGB24(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height) { > int y; >- void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int width) = >+ void (*ARGBToRGB24Row)(const uint8_t* src_argb, uint8_t* dst_rgb, int width) = > ARGBToRGB24Row_C; > if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) { > return -1; >@@ -981,14 +906,14 @@ int ARGBToRGB24(const uint8* src_argb, > > // Convert ARGB To RAW. > LIBYUV_API >-int ARGBToRAW(const uint8* src_argb, >+int ARGBToRAW(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_raw, >+ uint8_t* dst_raw, > int dst_stride_raw, > int width, > int height) { > int y; >- void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int width) = >+ void (*ARGBToRAWRow)(const uint8_t* src_argb, uint8_t* dst_rgb, int width) = > ARGBToRAWRow_C; > if (!src_argb || !dst_raw || width <= 0 || height == 0) { > return -1; >@@ -1038,22 +963,22 @@ int ARGBToRAW(const uint8* src_argb, > } > > // Ordered 8x8 dither for 888 to 565. Values from 0 to 7. >-static const uint8 kDither565_4x4[16] = { >+static const uint8_t kDither565_4x4[16] = { > 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2, > }; > > // Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes). > LIBYUV_API >-int ARGBToRGB565Dither(const uint8* src_argb, >+int ARGBToRGB565Dither(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, >- const uint8* dither4x4, >+ const uint8_t* dither4x4, > int width, > int height) { > int y; >- void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb, >- const uint32 dither4, int width) = >+ void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb, >+ const uint32_t dither4, int width) = > ARGBToRGB565DitherRow_C; > if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) { > return -1; >@@ -1101,7 +1026,7 @@ int ARGBToRGB565Dither(const uint8* src_argb, > > for (y = 0; y < height; ++y) { > ARGBToRGB565DitherRow(src_argb, dst_rgb565, >- *(uint32*)(dither4x4 + ((y & 3) << 2)), >+ *(uint32_t*)(dither4x4 + ((y & 3) << 2)), // NOLINT > width); /* NOLINT */ > src_argb += src_stride_argb; > dst_rgb565 += dst_stride_rgb565; >@@ -1112,15 +1037,15 @@ int ARGBToRGB565Dither(const uint8* src_argb, > // Convert ARGB To RGB565. > // TODO(fbarchard): Consider using dither function low level with zeros. > LIBYUV_API >-int ARGBToRGB565(const uint8* src_argb, >+int ARGBToRGB565(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height) { > int y; >- void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int width) = >- ARGBToRGB565Row_C; >+ void (*ARGBToRGB565Row)(const uint8_t* src_argb, uint8_t* dst_rgb, >+ int width) = ARGBToRGB565Row_C; > if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) { > return -1; > } >@@ -1178,15 +1103,15 @@ int ARGBToRGB565(const uint8* src_argb, > > // Convert ARGB To ARGB1555. > LIBYUV_API >-int ARGBToARGB1555(const uint8* src_argb, >+int ARGBToARGB1555(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb1555, >+ uint8_t* dst_argb1555, > int dst_stride_argb1555, > int width, > int height) { > int y; >- void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int width) = >- ARGBToARGB1555Row_C; >+ void (*ARGBToARGB1555Row)(const uint8_t* src_argb, uint8_t* dst_rgb, >+ int width) = ARGBToARGB1555Row_C; > if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) { > return -1; > } >@@ -1244,15 +1169,15 @@ int ARGBToARGB1555(const uint8* src_argb, > > // Convert ARGB To ARGB4444. > LIBYUV_API >-int ARGBToARGB4444(const uint8* src_argb, >+int ARGBToARGB4444(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb4444, >+ uint8_t* dst_argb4444, > int dst_stride_argb4444, > int width, > int height) { > int y; >- void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int width) = >- ARGBToARGB4444Row_C; >+ void (*ARGBToARGB4444Row)(const uint8_t* src_argb, uint8_t* dst_rgb, >+ int width) = ARGBToARGB4444Row_C; > if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) { > return -1; > } >@@ -1308,22 +1233,121 @@ int ARGBToARGB4444(const uint8* src_argb, > return 0; > } > >+// Convert ABGR To AR30. >+LIBYUV_API >+int ABGRToAR30(const uint8_t* src_abgr, >+ int src_stride_abgr, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ int y; >+ void (*ABGRToAR30Row)(const uint8_t* src_abgr, uint8_t* dst_rgb, int width) = >+ ABGRToAR30Row_C; >+ if (!src_abgr || !dst_ar30 || width <= 0 || height == 0) { >+ return -1; >+ } >+ if (height < 0) { >+ height = -height; >+ src_abgr = src_abgr + (height - 1) * src_stride_abgr; >+ src_stride_abgr = -src_stride_abgr; >+ } >+ // Coalesce rows. >+ if (src_stride_abgr == width * 4 && dst_stride_ar30 == width * 4) { >+ width *= height; >+ height = 1; >+ src_stride_abgr = dst_stride_ar30 = 0; >+ } >+#if defined(HAS_ABGRTOAR30ROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ ABGRToAR30Row = ABGRToAR30Row_Any_SSSE3; >+ if (IS_ALIGNED(width, 4)) { >+ ABGRToAR30Row = ABGRToAR30Row_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_ABGRTOAR30ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ ABGRToAR30Row = ABGRToAR30Row_Any_AVX2; >+ if (IS_ALIGNED(width, 8)) { >+ ABGRToAR30Row = ABGRToAR30Row_AVX2; >+ } >+ } >+#endif >+ for (y = 0; y < height; ++y) { >+ ABGRToAR30Row(src_abgr, dst_ar30, width); >+ src_abgr += src_stride_abgr; >+ dst_ar30 += dst_stride_ar30; >+ } >+ return 0; >+} >+ >+// Convert ARGB To AR30. >+LIBYUV_API >+int ARGBToAR30(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_ar30, >+ int dst_stride_ar30, >+ int width, >+ int height) { >+ int y; >+ void (*ARGBToAR30Row)(const uint8_t* src_argb, uint8_t* dst_rgb, int width) = >+ ARGBToAR30Row_C; >+ if (!src_argb || !dst_ar30 || width <= 0 || height == 0) { >+ return -1; >+ } >+ if (height < 0) { >+ height = -height; >+ src_argb = src_argb + (height - 1) * src_stride_argb; >+ src_stride_argb = -src_stride_argb; >+ } >+ // Coalesce rows. >+ if (src_stride_argb == width * 4 && dst_stride_ar30 == width * 4) { >+ width *= height; >+ height = 1; >+ src_stride_argb = dst_stride_ar30 = 0; >+ } >+#if defined(HAS_ARGBTOAR30ROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ ARGBToAR30Row = ARGBToAR30Row_Any_SSSE3; >+ if (IS_ALIGNED(width, 4)) { >+ ARGBToAR30Row = ARGBToAR30Row_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_ARGBTOAR30ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ ARGBToAR30Row = ARGBToAR30Row_Any_AVX2; >+ if (IS_ALIGNED(width, 8)) { >+ ARGBToAR30Row = ARGBToAR30Row_AVX2; >+ } >+ } >+#endif >+ for (y = 0; y < height; ++y) { >+ ARGBToAR30Row(src_argb, dst_ar30, width); >+ src_argb += src_stride_argb; >+ dst_ar30 += dst_stride_ar30; >+ } >+ return 0; >+} >+ > // Convert ARGB to J420. (JPeg full range I420). > LIBYUV_API >-int ARGBToJ420(const uint8* src_argb, >+int ARGBToJ420(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb, >- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C; >- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = >+ void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVJRow_C; >+ void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_yj, int width) = > ARGBToYJRow_C; > if (!src_argb || !dst_yj || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -1403,20 +1427,21 @@ int ARGBToJ420(const uint8* src_argb, > > // Convert ARGB to J422. (JPeg full range I422). > LIBYUV_API >-int ARGBToJ422(const uint8* src_argb, >+int ARGBToJ422(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb, >- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C; >- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = >+ void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb, >+ uint8_t* dst_u, uint8_t* dst_v, int width) = >+ ARGBToUVJRow_C; >+ void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_yj, int width) = > ARGBToYJRow_C; > if (!src_argb || !dst_yj || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -1498,14 +1523,14 @@ int ARGBToJ422(const uint8* src_argb, > > // Convert ARGB to J400. > LIBYUV_API >-int ARGBToJ400(const uint8* src_argb, >+int ARGBToJ400(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_yj, >+ uint8_t* dst_yj, > int dst_stride_yj, > int width, > int height) { > int y; >- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) = >+ void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_yj, int width) = > ARGBToYJRow_C; > if (!src_argb || !dst_yj || width <= 0 || height == 0) { > return -1; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc >index 216a9f26d87..ae3cc18cd24 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc >@@ -22,18 +22,18 @@ extern "C" { > > #ifdef HAVE_JPEG > struct I420Buffers { >- uint8* y; >+ uint8_t* y; > int y_stride; >- uint8* u; >+ uint8_t* u; > int u_stride; >- uint8* v; >+ uint8_t* v; > int v_stride; > int w; > int h; > }; > > static void JpegCopyI420(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > I420Buffers* dest = (I420Buffers*)(opaque); >@@ -47,7 +47,7 @@ static void JpegCopyI420(void* opaque, > } > > static void JpegI422ToI420(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > I420Buffers* dest = (I420Buffers*)(opaque); >@@ -61,7 +61,7 @@ static void JpegI422ToI420(void* opaque, > } > > static void JpegI444ToI420(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > I420Buffers* dest = (I420Buffers*)(opaque); >@@ -75,7 +75,7 @@ static void JpegI444ToI420(void* opaque, > } > > static void JpegI400ToI420(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > I420Buffers* dest = (I420Buffers*)(opaque); >@@ -89,7 +89,10 @@ static void JpegI400ToI420(void* opaque, > > // Query size of MJPG in pixels. > LIBYUV_API >-int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height) { >+int MJPGSize(const uint8_t* sample, >+ size_t sample_size, >+ int* width, >+ int* height) { > MJpegDecoder mjpeg_decoder; > LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); > if (ret) { >@@ -101,20 +104,21 @@ int MJPGSize(const uint8* sample, size_t sample_size, int* width, int* height) { > } > > // MJPG (Motion JPeg) to I420 >-// TODO(fbarchard): review w and h requirement. dw and dh may be enough. >+// TODO(fbarchard): review src_width and src_height requirement. dst_width and >+// dst_height may be enough. > LIBYUV_API >-int MJPGToI420(const uint8* sample, >+int MJPGToI420(const uint8_t* sample, > size_t sample_size, >- uint8* y, >- int y_stride, >- uint8* u, >- int u_stride, >- uint8* v, >- int v_stride, >- int w, >- int h, >- int dw, >- int dh) { >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, >+ int src_width, >+ int src_height, >+ int dst_width, >+ int dst_height) { > if (sample_size == kUnknownDataSize) { > // ERROR: MJPEG frame size unknown > return -1; >@@ -123,14 +127,15 @@ int MJPGToI420(const uint8* sample, > // TODO(fbarchard): Port MJpeg to C. > MJpegDecoder mjpeg_decoder; > LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); >- if (ret && >- (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) { >+ if (ret && (mjpeg_decoder.GetWidth() != src_width || >+ mjpeg_decoder.GetHeight() != src_height)) { > // ERROR: MJPEG frame has unexpected dimensions > mjpeg_decoder.UnloadFrame(); > return 1; // runtime failure > } > if (ret) { >- I420Buffers bufs = {y, y_stride, u, u_stride, v, v_stride, dw, dh}; >+ I420Buffers bufs = {dst_y, dst_stride_y, dst_u, dst_stride_u, >+ dst_v, dst_stride_v, dst_width, dst_height}; > // YUV420 > if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && > mjpeg_decoder.GetNumComponents() == 3 && >@@ -140,7 +145,8 @@ int MJPGToI420(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dst_width, >+ dst_height); > // YUV422 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceYCbCr && >@@ -151,7 +157,8 @@ int MJPGToI420(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dst_width, >+ dst_height); > // YUV444 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceYCbCr && >@@ -162,14 +169,16 @@ int MJPGToI420(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dst_width, >+ dst_height); > // YUV400 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceGrayscale && > mjpeg_decoder.GetNumComponents() == 1 && > mjpeg_decoder.GetVertSampFactor(0) == 1 && > mjpeg_decoder.GetHorizSampFactor(0) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dst_width, >+ dst_height); > } else { > // TODO(fbarchard): Implement conversion for any other colorspace/sample > // factors that occur in practice. >@@ -183,14 +192,14 @@ int MJPGToI420(const uint8* sample, > > #ifdef HAVE_JPEG > struct ARGBBuffers { >- uint8* argb; >+ uint8_t* argb; > int argb_stride; > int w; > int h; > }; > > static void JpegI420ToARGB(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > ARGBBuffers* dest = (ARGBBuffers*)(opaque); >@@ -201,7 +210,7 @@ static void JpegI420ToARGB(void* opaque, > } > > static void JpegI422ToARGB(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > ARGBBuffers* dest = (ARGBBuffers*)(opaque); >@@ -212,7 +221,7 @@ static void JpegI422ToARGB(void* opaque, > } > > static void JpegI444ToARGB(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > ARGBBuffers* dest = (ARGBBuffers*)(opaque); >@@ -223,7 +232,7 @@ static void JpegI444ToARGB(void* opaque, > } > > static void JpegI400ToARGB(void* opaque, >- const uint8* const* data, >+ const uint8_t* const* data, > const int* strides, > int rows) { > ARGBBuffers* dest = (ARGBBuffers*)(opaque); >@@ -233,16 +242,17 @@ static void JpegI400ToARGB(void* opaque, > } > > // MJPG (Motion JPeg) to ARGB >-// TODO(fbarchard): review w and h requirement. dw and dh may be enough. >+// TODO(fbarchard): review src_width and src_height requirement. dst_width and >+// dst_height may be enough. > LIBYUV_API >-int MJPGToARGB(const uint8* sample, >+int MJPGToARGB(const uint8_t* sample, > size_t sample_size, >- uint8* argb, >- int argb_stride, >- int w, >- int h, >- int dw, >- int dh) { >+ uint8_t* dst_argb, >+ int dst_stride_argb, >+ int src_width, >+ int src_height, >+ int dst_width, >+ int dst_height) { > if (sample_size == kUnknownDataSize) { > // ERROR: MJPEG frame size unknown > return -1; >@@ -251,14 +261,14 @@ int MJPGToARGB(const uint8* sample, > // TODO(fbarchard): Port MJpeg to C. > MJpegDecoder mjpeg_decoder; > LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size); >- if (ret && >- (mjpeg_decoder.GetWidth() != w || mjpeg_decoder.GetHeight() != h)) { >+ if (ret && (mjpeg_decoder.GetWidth() != src_width || >+ mjpeg_decoder.GetHeight() != src_height)) { > // ERROR: MJPEG frame has unexpected dimensions > mjpeg_decoder.UnloadFrame(); > return 1; // runtime failure > } > if (ret) { >- ARGBBuffers bufs = {argb, argb_stride, dw, dh}; >+ ARGBBuffers bufs = {dst_argb, dst_stride_argb, dst_width, dst_height}; > // YUV420 > if (mjpeg_decoder.GetColorSpace() == MJpegDecoder::kColorSpaceYCbCr && > mjpeg_decoder.GetNumComponents() == 3 && >@@ -268,7 +278,8 @@ int MJPGToARGB(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dst_width, >+ dst_height); > // YUV422 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceYCbCr && >@@ -279,7 +290,8 @@ int MJPGToARGB(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dst_width, >+ dst_height); > // YUV444 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceYCbCr && >@@ -290,14 +302,16 @@ int MJPGToARGB(const uint8* sample, > mjpeg_decoder.GetHorizSampFactor(1) == 1 && > mjpeg_decoder.GetVertSampFactor(2) == 1 && > mjpeg_decoder.GetHorizSampFactor(2) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dst_width, >+ dst_height); > // YUV400 > } else if (mjpeg_decoder.GetColorSpace() == > MJpegDecoder::kColorSpaceGrayscale && > mjpeg_decoder.GetNumComponents() == 1 && > mjpeg_decoder.GetVertSampFactor(0) == 1 && > mjpeg_decoder.GetHorizSampFactor(0) == 1) { >- ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh); >+ ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dst_width, >+ dst_height); > } else { > // TODO(fbarchard): Implement conversion for any other colorspace/sample > // factors that occur in practice. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc >index 63a5104b3c7..677e5d56fcc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc >@@ -29,10 +29,10 @@ extern "C" { > // sample_size is measured in bytes and is the size of the frame. > // With MJPEG it is the compressed size of the frame. > LIBYUV_API >-int ConvertToARGB(const uint8* sample, >+int ConvertToARGB(const uint8_t* sample, > size_t sample_size, >- uint8* crop_argb, >- int argb_stride, >+ uint8_t* dst_argb, >+ int dst_stride_argb, > int crop_x, > int crop_y, > int src_width, >@@ -40,11 +40,11 @@ int ConvertToARGB(const uint8* sample, > int crop_width, > int crop_height, > enum RotationMode rotation, >- uint32 fourcc) { >- uint32 format = CanonicalFourCC(fourcc); >+ uint32_t fourcc) { >+ uint32_t format = CanonicalFourCC(fourcc); > int aligned_src_width = (src_width + 1) & ~1; >- const uint8* src; >- const uint8* src_uv; >+ const uint8_t* src; >+ const uint8_t* src_uv; > int abs_src_height = (src_height < 0) ? -src_height : src_height; > int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height; > int r = 0; >@@ -52,17 +52,17 @@ int ConvertToARGB(const uint8* sample, > // One pass rotation is available for some formats. For the rest, convert > // to ARGB (with optional vertical flipping) into a temporary ARGB buffer, > // and then rotate the ARGB to the final destination buffer. >- // For in-place conversion, if destination crop_argb is same as source sample, >+ // For in-place conversion, if destination dst_argb is same as source sample, > // also enable temporary buffer. > LIBYUV_BOOL need_buf = >- (rotation && format != FOURCC_ARGB) || crop_argb == sample; >- uint8* dest_argb = crop_argb; >- int dest_argb_stride = argb_stride; >- uint8* rotate_buffer = NULL; >+ (rotation && format != FOURCC_ARGB) || dst_argb == sample; >+ uint8_t* dest_argb = dst_argb; >+ int dest_dst_stride_argb = dst_stride_argb; >+ uint8_t* rotate_buffer = NULL; > int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height; > >- if (crop_argb == NULL || sample == NULL || src_width <= 0 || >- crop_width <= 0 || src_height == 0 || crop_height == 0) { >+ if (dst_argb == NULL || sample == NULL || src_width <= 0 || crop_width <= 0 || >+ src_height == 0 || crop_height == 0) { > return -1; > } > if (src_height < 0) { >@@ -71,76 +71,76 @@ int ConvertToARGB(const uint8* sample, > > if (need_buf) { > int argb_size = crop_width * 4 * abs_crop_height; >- rotate_buffer = (uint8*)malloc(argb_size); /* NOLINT */ >+ rotate_buffer = (uint8_t*)malloc(argb_size); /* NOLINT */ > if (!rotate_buffer) { > return 1; // Out of memory runtime error. > } >- crop_argb = rotate_buffer; >- argb_stride = crop_width * 4; >+ dst_argb = rotate_buffer; >+ dst_stride_argb = crop_width * 4; > } > > switch (format) { > // Single plane formats > case FOURCC_YUY2: > src = sample + (aligned_src_width * crop_y + crop_x) * 2; >- r = YUY2ToARGB(src, aligned_src_width * 2, crop_argb, argb_stride, >+ r = YUY2ToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb, > crop_width, inv_crop_height); > break; > case FOURCC_UYVY: > src = sample + (aligned_src_width * crop_y + crop_x) * 2; >- r = UYVYToARGB(src, aligned_src_width * 2, crop_argb, argb_stride, >+ r = UYVYToARGB(src, aligned_src_width * 2, dst_argb, dst_stride_argb, > crop_width, inv_crop_height); > break; > case FOURCC_24BG: > src = sample + (src_width * crop_y + crop_x) * 3; >- r = RGB24ToARGB(src, src_width * 3, crop_argb, argb_stride, crop_width, >+ r = RGB24ToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > case FOURCC_RAW: > src = sample + (src_width * crop_y + crop_x) * 3; >- r = RAWToARGB(src, src_width * 3, crop_argb, argb_stride, crop_width, >+ r = RAWToARGB(src, src_width * 3, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > case FOURCC_ARGB: > if (!need_buf && !rotation) { > src = sample + (src_width * crop_y + crop_x) * 4; >- r = ARGBToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width, >- inv_crop_height); >+ r = ARGBToARGB(src, src_width * 4, dst_argb, dst_stride_argb, >+ crop_width, inv_crop_height); > } > break; > case FOURCC_BGRA: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = BGRAToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width, >+ r = BGRAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > case FOURCC_ABGR: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = ABGRToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width, >+ r = ABGRToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > case FOURCC_RGBA: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = RGBAToARGB(src, src_width * 4, crop_argb, argb_stride, crop_width, >+ r = RGBAToARGB(src, src_width * 4, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > case FOURCC_RGBP: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = RGB565ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width, >- inv_crop_height); >+ r = RGB565ToARGB(src, src_width * 2, dst_argb, dst_stride_argb, >+ crop_width, inv_crop_height); > break; > case FOURCC_RGBO: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = ARGB1555ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width, >- inv_crop_height); >+ r = ARGB1555ToARGB(src, src_width * 2, dst_argb, dst_stride_argb, >+ crop_width, inv_crop_height); > break; > case FOURCC_R444: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = ARGB4444ToARGB(src, src_width * 2, crop_argb, argb_stride, crop_width, >- inv_crop_height); >+ r = ARGB4444ToARGB(src, src_width * 2, dst_argb, dst_stride_argb, >+ crop_width, inv_crop_height); > break; > case FOURCC_I400: > src = sample + src_width * crop_y + crop_x; >- r = I400ToARGB(src, src_width, crop_argb, argb_stride, crop_width, >+ r = I400ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > >@@ -148,27 +148,27 @@ int ConvertToARGB(const uint8* sample, > case FOURCC_NV12: > src = sample + (src_width * crop_y + crop_x); > src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; >- r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, crop_argb, >- argb_stride, crop_width, inv_crop_height); >+ r = NV12ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb, >+ dst_stride_argb, crop_width, inv_crop_height); > break; > case FOURCC_NV21: > src = sample + (src_width * crop_y + crop_x); > src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x; > // Call NV12 but with u and v parameters swapped. >- r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, crop_argb, >- argb_stride, crop_width, inv_crop_height); >+ r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb, >+ dst_stride_argb, crop_width, inv_crop_height); > break; > case FOURCC_M420: > src = sample + (src_width * crop_y) * 12 / 8 + crop_x; >- r = M420ToARGB(src, src_width, crop_argb, argb_stride, crop_width, >+ r = M420ToARGB(src, src_width, dst_argb, dst_stride_argb, crop_width, > inv_crop_height); > break; > // Triplanar formats > case FOURCC_I420: > case FOURCC_YV12: { >- const uint8* src_y = sample + (src_width * crop_y + crop_x); >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + (src_width * crop_y + crop_x); >+ const uint8_t* src_u; >+ const uint8_t* src_v; > int halfwidth = (src_width + 1) / 2; > int halfheight = (abs_src_height + 1) / 2; > if (format == FOURCC_YV12) { >@@ -183,14 +183,14 @@ int ConvertToARGB(const uint8* sample, > halfwidth * (halfheight + crop_y / 2) + crop_x / 2; > } > r = I420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth, >- crop_argb, argb_stride, crop_width, inv_crop_height); >+ dst_argb, dst_stride_argb, crop_width, inv_crop_height); > break; > } > > case FOURCC_J420: { >- const uint8* src_y = sample + (src_width * crop_y + crop_x); >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + (src_width * crop_y + crop_x); >+ const uint8_t* src_u; >+ const uint8_t* src_v; > int halfwidth = (src_width + 1) / 2; > int halfheight = (abs_src_height + 1) / 2; > src_u = sample + src_width * abs_src_height + >@@ -198,15 +198,15 @@ int ConvertToARGB(const uint8* sample, > src_v = sample + src_width * abs_src_height + > halfwidth * (halfheight + crop_y / 2) + crop_x / 2; > r = J420ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth, >- crop_argb, argb_stride, crop_width, inv_crop_height); >+ dst_argb, dst_stride_argb, crop_width, inv_crop_height); > break; > } > > case FOURCC_I422: > case FOURCC_YV16: { >- const uint8* src_y = sample + src_width * crop_y + crop_x; >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + src_width * crop_y + crop_x; >+ const uint8_t* src_u; >+ const uint8_t* src_v; > int halfwidth = (src_width + 1) / 2; > if (format == FOURCC_YV16) { > src_v = sample + src_width * abs_src_height + halfwidth * crop_y + >@@ -220,14 +220,14 @@ int ConvertToARGB(const uint8* sample, > halfwidth * (abs_src_height + crop_y) + crop_x / 2; > } > r = I422ToARGB(src_y, src_width, src_u, halfwidth, src_v, halfwidth, >- crop_argb, argb_stride, crop_width, inv_crop_height); >+ dst_argb, dst_stride_argb, crop_width, inv_crop_height); > break; > } > case FOURCC_I444: > case FOURCC_YV24: { >- const uint8* src_y = sample + src_width * crop_y + crop_x; >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + src_width * crop_y + crop_x; >+ const uint8_t* src_u; >+ const uint8_t* src_v; > if (format == FOURCC_YV24) { > src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; > src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; >@@ -236,12 +236,12 @@ int ConvertToARGB(const uint8* sample, > src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; > } > r = I444ToARGB(src_y, src_width, src_u, src_width, src_v, src_width, >- crop_argb, argb_stride, crop_width, inv_crop_height); >+ dst_argb, dst_stride_argb, crop_width, inv_crop_height); > break; > } > #ifdef HAVE_JPEG > case FOURCC_MJPG: >- r = MJPGToARGB(sample, sample_size, crop_argb, argb_stride, src_width, >+ r = MJPGToARGB(sample, sample_size, dst_argb, dst_stride_argb, src_width, > abs_src_height, crop_width, inv_crop_height); > break; > #endif >@@ -251,13 +251,13 @@ int ConvertToARGB(const uint8* sample, > > if (need_buf) { > if (!r) { >- r = ARGBRotate(crop_argb, argb_stride, dest_argb, dest_argb_stride, >+ r = ARGBRotate(dst_argb, dst_stride_argb, dest_argb, dest_dst_stride_argb, > crop_width, abs_crop_height, rotation); > } > free(rotate_buffer); > } else if (rotation) { > src = sample + (src_width * crop_y + crop_x) * 4; >- r = ARGBRotate(src, src_width * 4, crop_argb, argb_stride, crop_width, >+ r = ARGBRotate(src, src_width * 4, dst_argb, dst_stride_argb, crop_width, > inv_crop_height, rotation); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc >index a50689db949..1bed9d6440d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc >@@ -25,14 +25,14 @@ extern "C" { > // sample_size is measured in bytes and is the size of the frame. > // With MJPEG it is the compressed size of the frame. > LIBYUV_API >-int ConvertToI420(const uint8* sample, >+int ConvertToI420(const uint8_t* sample, > size_t sample_size, >- uint8* y, >- int y_stride, >- uint8* u, >- int u_stride, >- uint8* v, >- int v_stride, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, > int crop_x, > int crop_y, > int src_width, >@@ -40,11 +40,11 @@ int ConvertToI420(const uint8* sample, > int crop_width, > int crop_height, > enum RotationMode rotation, >- uint32 fourcc) { >- uint32 format = CanonicalFourCC(fourcc); >+ uint32_t fourcc) { >+ uint32_t format = CanonicalFourCC(fourcc); > int aligned_src_width = (src_width + 1) & ~1; >- const uint8* src; >- const uint8* src_uv; >+ const uint8_t* src; >+ const uint8_t* src_uv; > const int abs_src_height = (src_height < 0) ? -src_height : src_height; > // TODO(nisse): Why allow crop_height < 0? > const int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height; >@@ -52,132 +52,143 @@ int ConvertToI420(const uint8* sample, > LIBYUV_BOOL need_buf = > (rotation && format != FOURCC_I420 && format != FOURCC_NV12 && > format != FOURCC_NV21 && format != FOURCC_YV12) || >- y == sample; >- uint8* tmp_y = y; >- uint8* tmp_u = u; >- uint8* tmp_v = v; >- int tmp_y_stride = y_stride; >- int tmp_u_stride = u_stride; >- int tmp_v_stride = v_stride; >- uint8* rotate_buffer = NULL; >+ dst_y == sample; >+ uint8_t* tmp_y = dst_y; >+ uint8_t* tmp_u = dst_u; >+ uint8_t* tmp_v = dst_v; >+ int tmp_y_stride = dst_stride_y; >+ int tmp_u_stride = dst_stride_u; >+ int tmp_v_stride = dst_stride_v; >+ uint8_t* rotate_buffer = NULL; > const int inv_crop_height = > (src_height < 0) ? -abs_crop_height : abs_crop_height; > >- if (!y || !u || !v || !sample || src_width <= 0 || crop_width <= 0 || >- src_height == 0 || crop_height == 0) { >+ if (!dst_y || !dst_u || !dst_v || !sample || src_width <= 0 || >+ crop_width <= 0 || src_height == 0 || crop_height == 0) { > return -1; > } > > // One pass rotation is available for some formats. For the rest, convert > // to I420 (with optional vertical flipping) into a temporary I420 buffer, > // and then rotate the I420 to the final destination buffer. >- // For in-place conversion, if destination y is same as source sample, >+ // For in-place conversion, if destination dst_y is same as source sample, > // also enable temporary buffer. > if (need_buf) { > int y_size = crop_width * abs_crop_height; > int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2); >- rotate_buffer = (uint8*)malloc(y_size + uv_size * 2); /* NOLINT */ >+ rotate_buffer = (uint8_t*)malloc(y_size + uv_size * 2); /* NOLINT */ > if (!rotate_buffer) { > return 1; // Out of memory runtime error. > } >- y = rotate_buffer; >- u = y + y_size; >- v = u + uv_size; >- y_stride = crop_width; >- u_stride = v_stride = ((crop_width + 1) / 2); >+ dst_y = rotate_buffer; >+ dst_u = dst_y + y_size; >+ dst_v = dst_u + uv_size; >+ dst_stride_y = crop_width; >+ dst_stride_u = dst_stride_v = ((crop_width + 1) / 2); > } > > switch (format) { > // Single plane formats > case FOURCC_YUY2: > src = sample + (aligned_src_width * crop_y + crop_x) * 2; >- r = YUY2ToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v, >- v_stride, crop_width, inv_crop_height); >+ r = YUY2ToI420(src, aligned_src_width * 2, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_UYVY: > src = sample + (aligned_src_width * crop_y + crop_x) * 2; >- r = UYVYToI420(src, aligned_src_width * 2, y, y_stride, u, u_stride, v, >- v_stride, crop_width, inv_crop_height); >+ r = UYVYToI420(src, aligned_src_width * 2, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_RGBP: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = RGB565ToI420(src, src_width * 2, y, y_stride, u, u_stride, v, >- v_stride, crop_width, inv_crop_height); >+ r = RGB565ToI420(src, src_width * 2, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_RGBO: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = ARGB1555ToI420(src, src_width * 2, y, y_stride, u, u_stride, v, >- v_stride, crop_width, inv_crop_height); >+ r = ARGB1555ToI420(src, src_width * 2, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_R444: > src = sample + (src_width * crop_y + crop_x) * 2; >- r = ARGB4444ToI420(src, src_width * 2, y, y_stride, u, u_stride, v, >- v_stride, crop_width, inv_crop_height); >+ r = ARGB4444ToI420(src, src_width * 2, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_24BG: > src = sample + (src_width * crop_y + crop_x) * 3; >- r = RGB24ToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = RGB24ToI420(src, src_width * 3, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_RAW: > src = sample + (src_width * crop_y + crop_x) * 3; >- r = RAWToI420(src, src_width * 3, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = RAWToI420(src, src_width * 3, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_ARGB: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = ARGBToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = ARGBToI420(src, src_width * 4, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_BGRA: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = BGRAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = BGRAToI420(src, src_width * 4, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_ABGR: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = ABGRToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = ABGRToI420(src, src_width * 4, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_RGBA: > src = sample + (src_width * crop_y + crop_x) * 4; >- r = RGBAToI420(src, src_width * 4, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = RGBAToI420(src, src_width * 4, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, crop_width, >+ inv_crop_height); > break; > case FOURCC_I400: > src = sample + src_width * crop_y + crop_x; >- r = I400ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = I400ToI420(src, src_width, dst_y, dst_stride_y, dst_u, dst_stride_u, >+ dst_v, dst_stride_v, crop_width, inv_crop_height); > break; > // Biplanar formats > case FOURCC_NV12: > src = sample + (src_width * crop_y + crop_x); > src_uv = sample + (src_width * src_height) + > ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2); >- r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y, >- y_stride, u, u_stride, v, v_stride, crop_width, >- inv_crop_height, rotation); >+ r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, dst_y, >+ dst_stride_y, dst_u, dst_stride_u, dst_v, >+ dst_stride_v, crop_width, inv_crop_height, rotation); > break; > case FOURCC_NV21: > src = sample + (src_width * crop_y + crop_x); > src_uv = sample + (src_width * src_height) + > ((crop_y / 2) * aligned_src_width) + ((crop_x / 2) * 2); >- // Call NV12 but with u and v parameters swapped. >- r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, y, >- y_stride, v, v_stride, u, u_stride, crop_width, >- inv_crop_height, rotation); >+ // Call NV12 but with dst_u and dst_v parameters swapped. >+ r = NV12ToI420Rotate(src, src_width, src_uv, aligned_src_width, dst_y, >+ dst_stride_y, dst_v, dst_stride_v, dst_u, >+ dst_stride_u, crop_width, inv_crop_height, rotation); > break; > case FOURCC_M420: > src = sample + (src_width * crop_y) * 12 / 8 + crop_x; >- r = M420ToI420(src, src_width, y, y_stride, u, u_stride, v, v_stride, >- crop_width, inv_crop_height); >+ r = M420ToI420(src, src_width, dst_y, dst_stride_y, dst_u, dst_stride_u, >+ dst_v, dst_stride_v, crop_width, inv_crop_height); > break; > // Triplanar formats > case FOURCC_I420: > case FOURCC_YV12: { >- const uint8* src_y = sample + (src_width * crop_y + crop_x); >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + (src_width * crop_y + crop_x); >+ const uint8_t* src_u; >+ const uint8_t* src_v; > int halfwidth = (src_width + 1) / 2; > int halfheight = (abs_src_height + 1) / 2; > if (format == FOURCC_YV12) { >@@ -191,16 +202,16 @@ int ConvertToI420(const uint8* sample, > src_v = sample + src_width * abs_src_height + > halfwidth * (halfheight + crop_y / 2) + crop_x / 2; > } >- r = I420Rotate(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y, >- y_stride, u, u_stride, v, v_stride, crop_width, >- inv_crop_height, rotation); >+ r = I420Rotate(src_y, src_width, src_u, halfwidth, src_v, halfwidth, >+ dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, >+ dst_stride_v, crop_width, inv_crop_height, rotation); > break; > } > case FOURCC_I422: > case FOURCC_YV16: { >- const uint8* src_y = sample + src_width * crop_y + crop_x; >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + src_width * crop_y + crop_x; >+ const uint8_t* src_u; >+ const uint8_t* src_v; > int halfwidth = (src_width + 1) / 2; > if (format == FOURCC_YV16) { > src_v = sample + src_width * abs_src_height + halfwidth * crop_y + >@@ -213,16 +224,16 @@ int ConvertToI420(const uint8* sample, > src_v = sample + src_width * abs_src_height + > halfwidth * (abs_src_height + crop_y) + crop_x / 2; > } >- r = I422ToI420(src_y, src_width, src_u, halfwidth, src_v, halfwidth, y, >- y_stride, u, u_stride, v, v_stride, crop_width, >- inv_crop_height); >+ r = I422ToI420(src_y, src_width, src_u, halfwidth, src_v, halfwidth, >+ dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, >+ dst_stride_v, crop_width, inv_crop_height); > break; > } > case FOURCC_I444: > case FOURCC_YV24: { >- const uint8* src_y = sample + src_width * crop_y + crop_x; >- const uint8* src_u; >- const uint8* src_v; >+ const uint8_t* src_y = sample + src_width * crop_y + crop_x; >+ const uint8_t* src_u; >+ const uint8_t* src_v; > if (format == FOURCC_YV24) { > src_v = sample + src_width * (abs_src_height + crop_y) + crop_x; > src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; >@@ -230,15 +241,16 @@ int ConvertToI420(const uint8* sample, > src_u = sample + src_width * (abs_src_height + crop_y) + crop_x; > src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x; > } >- r = I444ToI420(src_y, src_width, src_u, src_width, src_v, src_width, y, >- y_stride, u, u_stride, v, v_stride, crop_width, >- inv_crop_height); >+ r = I444ToI420(src_y, src_width, src_u, src_width, src_v, src_width, >+ dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, >+ dst_stride_v, crop_width, inv_crop_height); > break; > } > #ifdef HAVE_JPEG > case FOURCC_MJPG: >- r = MJPGToI420(sample, sample_size, y, y_stride, u, u_stride, v, v_stride, >- src_width, abs_src_height, crop_width, inv_crop_height); >+ r = MJPGToI420(sample, sample_size, dst_y, dst_stride_y, dst_u, >+ dst_stride_u, dst_v, dst_stride_v, src_width, >+ abs_src_height, crop_width, inv_crop_height); > break; > #endif > default: >@@ -247,9 +259,10 @@ int ConvertToI420(const uint8* sample, > > if (need_buf) { > if (!r) { >- r = I420Rotate(y, y_stride, u, u_stride, v, v_stride, tmp_y, tmp_y_stride, >- tmp_u, tmp_u_stride, tmp_v, tmp_v_stride, crop_width, >- abs_crop_height, rotation); >+ r = I420Rotate(dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, >+ dst_stride_v, tmp_y, tmp_y_stride, tmp_u, tmp_u_stride, >+ tmp_v, tmp_v_stride, crop_width, abs_crop_height, >+ rotation); > } > free(rotate_buffer); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc >index 344f3c06a2b..446aad12078 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc >@@ -27,8 +27,6 @@ > #include <stdio.h> > #include <string.h> > >-#include "libyuv/basic_types.h" // For CPU_X86 >- > #ifdef __cplusplus > namespace libyuv { > extern "C" { >@@ -179,7 +177,7 @@ LIBYUV_API SAFEBUFFERS int MipsCpuCaps(const char* cpuinfo_name, > if (strcmp(ase, " msa") == 0) { > return kCpuHasMSA; > } >- return kCpuHasDSPR2; >+ return 0; > } > while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) { > if (memcmp(cpuinfo_line, "ASEs implemented", 16) == 0) { >@@ -189,7 +187,7 @@ LIBYUV_API SAFEBUFFERS int MipsCpuCaps(const char* cpuinfo_name, > if (strcmp(ase, " msa") == 0) { > return kCpuHasMSA; > } >- return kCpuHasDSPR2; >+ return 0; > } > } > } >@@ -218,7 +216,9 @@ static LIBYUV_BOOL TestEnv(const char*) { > > static SAFEBUFFERS int GetCpuFlags(void) { > int cpu_info = 0; >-#if !defined(__pnacl__) && !defined(__CLR_VER) && defined(CPU_X86) >+#if !defined(__pnacl__) && !defined(__CLR_VER) && \ >+ (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ >+ defined(_M_IX86)) > int cpu_info0[4] = {0, 0, 0, 0}; > int cpu_info1[4] = {0, 0, 0, 0}; > int cpu_info7[4] = {0, 0, 0, 0}; >@@ -290,16 +290,10 @@ static SAFEBUFFERS int GetCpuFlags(void) { > > #endif > #if defined(__mips__) && defined(__linux__) >-#if defined(__mips_dspr2) >- cpu_info |= kCpuHasDSPR2; >-#endif > #if defined(__mips_msa) > cpu_info = MipsCpuCaps("/proc/cpuinfo", " msa"); > #endif > cpu_info |= kCpuHasMIPS; >- if (getenv("LIBYUV_DISABLE_DSPR2")) { >- cpu_info &= ~kCpuHasDSPR2; >- } > if (getenv("LIBYUV_DISABLE_MSA")) { > cpu_info &= ~kCpuHasMSA; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc >index b43c008bdd2..eaf2530130b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc >@@ -102,7 +102,7 @@ MJpegDecoder::~MJpegDecoder() { > DestroyOutputBuffers(); > } > >-LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) { >+LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) { > if (!ValidateJpeg(src, src_len)) { > return LIBYUV_FALSE; > } >@@ -129,7 +129,7 @@ LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) { > if (scanlines_[i]) { > delete scanlines_[i]; > } >- scanlines_[i] = new uint8*[scanlines_size]; >+ scanlines_[i] = new uint8_t*[scanlines_size]; > scanlines_sizes_[i] = scanlines_size; > } > >@@ -145,7 +145,7 @@ LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) { > if (databuf_[i]) { > delete databuf_[i]; > } >- databuf_[i] = new uint8[databuf_size]; >+ databuf_[i] = new uint8_t[databuf_size]; > databuf_strides_[i] = databuf_stride; > } > >@@ -243,7 +243,7 @@ LIBYUV_BOOL MJpegDecoder::UnloadFrame() { > } > > // TODO(fbarchard): Allow rectangle to be specified: x, y, width, height. >-LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(uint8** planes, >+LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(uint8_t** planes, > int dst_width, > int dst_height) { > if (dst_width != GetWidth() || dst_height > GetHeight()) { >@@ -469,9 +469,9 @@ void MJpegDecoder::AllocOutputBuffers(int num_outbufs) { > // it. > DestroyOutputBuffers(); > >- scanlines_ = new uint8**[num_outbufs]; >+ scanlines_ = new uint8_t**[num_outbufs]; > scanlines_sizes_ = new int[num_outbufs]; >- databuf_ = new uint8*[num_outbufs]; >+ databuf_ = new uint8_t*[num_outbufs]; > databuf_strides_ = new int[num_outbufs]; > > for (int i = 0; i < num_outbufs; ++i) { >@@ -527,9 +527,9 @@ LIBYUV_BOOL MJpegDecoder::FinishDecode() { > return LIBYUV_TRUE; > } > >-void MJpegDecoder::SetScanlinePointers(uint8** data) { >+void MJpegDecoder::SetScanlinePointers(uint8_t** data) { > for (int i = 0; i < num_outbufs_; ++i) { >- uint8* data_i = data[i]; >+ uint8_t* data_i = data[i]; > for (int j = 0; j < scanlines_sizes_[i]; ++j) { > scanlines_[i][j] = data_i; > data_i += GetComponentStride(i); >@@ -552,13 +552,13 @@ JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper( > if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 2 && > subsample_y[1] == 2 && subsample_x[2] == 2 && subsample_y[2] == 2) { > return kJpegYuv420; >- } else if (subsample_x[0] == 1 && subsample_y[0] == 1 && >- subsample_x[1] == 2 && subsample_y[1] == 1 && >- subsample_x[2] == 2 && subsample_y[2] == 1) { >+ } >+ if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 2 && >+ subsample_y[1] == 1 && subsample_x[2] == 2 && subsample_y[2] == 1) { > return kJpegYuv422; >- } else if (subsample_x[0] == 1 && subsample_y[0] == 1 && >- subsample_x[1] == 1 && subsample_y[1] == 1 && >- subsample_x[2] == 1 && subsample_y[2] == 1) { >+ } >+ if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 1 && >+ subsample_y[1] == 1 && subsample_x[2] == 1 && subsample_y[2] == 1) { > return kJpegYuv444; > } > } else if (number_of_components == 1) { // Grey-scale images. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc >index bd760425359..80c2cc0cb9b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc >@@ -18,13 +18,13 @@ extern "C" { > #endif > > // Helper function to scan for EOI marker (0xff 0xd9). >-static LIBYUV_BOOL ScanEOI(const uint8* sample, size_t sample_size) { >+static LIBYUV_BOOL ScanEOI(const uint8_t* sample, size_t sample_size) { > if (sample_size >= 2) { >- const uint8* end = sample + sample_size - 1; >- const uint8* it = sample; >+ const uint8_t* end = sample + sample_size - 1; >+ const uint8_t* it = sample; > while (it < end) { > // TODO(fbarchard): scan for 0xd9 instead. >- it = (const uint8*)(memchr(it, 0xff, end - it)); >+ it = (const uint8_t*)(memchr(it, 0xff, end - it)); > if (it == NULL) { > break; > } >@@ -39,7 +39,7 @@ static LIBYUV_BOOL ScanEOI(const uint8* sample, size_t sample_size) { > } > > // Helper function to validate the jpeg appears intact. >-LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size) { >+LIBYUV_BOOL ValidateJpeg(const uint8_t* sample, size_t sample_size) { > // Maximum size that ValidateJpeg will consider valid. > const size_t kMaxJpegSize = 0x7fffffffull; > const size_t kBackSearchSize = 1024; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc >index dd311d1f08e..5eae3f763a7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc >@@ -26,14 +26,14 @@ extern "C" { > > // Copy a plane of data > LIBYUV_API >-void CopyPlane(const uint8* src_y, >+void CopyPlane(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; >+ void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C; > // Negative height means invert the image. > if (height < 0) { > height = -height; >@@ -50,6 +50,7 @@ void CopyPlane(const uint8* src_y, > if (src_y == dst_y && src_stride_y == dst_stride_y) { > return; > } >+ > #if defined(HAS_COPYROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; >@@ -70,11 +71,6 @@ void CopyPlane(const uint8* src_y, > CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; > } > #endif >-#if defined(HAS_COPYROW_MIPS) >- if (TestCpuFlag(kCpuHasMIPS)) { >- CopyRow = CopyRow_MIPS; >- } >-#endif > > // Copy plane > for (y = 0; y < height; ++y) { >@@ -87,14 +83,14 @@ void CopyPlane(const uint8* src_y, > // TODO(fbarchard): Consider support for negative height. > // TODO(fbarchard): Consider stride measured in bytes. > LIBYUV_API >-void CopyPlane_16(const uint16* src_y, >+void CopyPlane_16(const uint16_t* src_y, > int src_stride_y, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*CopyRow)(const uint16* src, uint16* dst, int width) = CopyRow_16_C; >+ void (*CopyRow)(const uint16_t* src, uint16_t* dst, int width) = CopyRow_16_C; > // Coalesce rows. > if (src_stride_y == width && dst_stride_y == width) { > width *= height; >@@ -116,11 +112,6 @@ void CopyPlane_16(const uint16* src_y, > CopyRow = CopyRow_16_NEON; > } > #endif >-#if defined(HAS_COPYROW_16_MIPS) >- if (TestCpuFlag(kCpuHasMIPS)) { >- CopyRow = CopyRow_16_MIPS; >- } >-#endif > > // Copy plane > for (y = 0; y < height; ++y) { >@@ -130,19 +121,119 @@ void CopyPlane_16(const uint16* src_y, > } > } > >+// Convert a plane of 16 bit data to 8 bit >+LIBYUV_API >+void Convert16To8Plane(const uint16_t* src_y, >+ int src_stride_y, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ int scale, // 16384 for 10 bits >+ int width, >+ int height) { >+ int y; >+ void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale, >+ int width) = Convert16To8Row_C; >+ >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_y = dst_y + (height - 1) * dst_stride_y; >+ dst_stride_y = -dst_stride_y; >+ } >+ // Coalesce rows. >+ if (src_stride_y == width && dst_stride_y == width) { >+ width *= height; >+ height = 1; >+ src_stride_y = dst_stride_y = 0; >+ } >+#if defined(HAS_CONVERT16TO8ROW_SSSE3) >+ if (TestCpuFlag(kCpuHasSSSE3)) { >+ Convert16To8Row = Convert16To8Row_Any_SSSE3; >+ if (IS_ALIGNED(width, 16)) { >+ Convert16To8Row = Convert16To8Row_SSSE3; >+ } >+ } >+#endif >+#if defined(HAS_CONVERT16TO8ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ Convert16To8Row = Convert16To8Row_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ Convert16To8Row = Convert16To8Row_AVX2; >+ } >+ } >+#endif >+ >+ // Convert plane >+ for (y = 0; y < height; ++y) { >+ Convert16To8Row(src_y, dst_y, scale, width); >+ src_y += src_stride_y; >+ dst_y += dst_stride_y; >+ } >+} >+ >+// Convert a plane of 8 bit data to 16 bit >+LIBYUV_API >+void Convert8To16Plane(const uint8_t* src_y, >+ int src_stride_y, >+ uint16_t* dst_y, >+ int dst_stride_y, >+ int scale, // 16384 for 10 bits >+ int width, >+ int height) { >+ int y; >+ void (*Convert8To16Row)(const uint8_t* src_y, uint16_t* dst_y, int scale, >+ int width) = Convert8To16Row_C; >+ >+ // Negative height means invert the image. >+ if (height < 0) { >+ height = -height; >+ dst_y = dst_y + (height - 1) * dst_stride_y; >+ dst_stride_y = -dst_stride_y; >+ } >+ // Coalesce rows. >+ if (src_stride_y == width && dst_stride_y == width) { >+ width *= height; >+ height = 1; >+ src_stride_y = dst_stride_y = 0; >+ } >+#if defined(HAS_CONVERT8TO16ROW_SSE2) >+ if (TestCpuFlag(kCpuHasSSE2)) { >+ Convert8To16Row = Convert8To16Row_Any_SSE2; >+ if (IS_ALIGNED(width, 16)) { >+ Convert8To16Row = Convert8To16Row_SSE2; >+ } >+ } >+#endif >+#if defined(HAS_CONVERT8TO16ROW_AVX2) >+ if (TestCpuFlag(kCpuHasAVX2)) { >+ Convert8To16Row = Convert8To16Row_Any_AVX2; >+ if (IS_ALIGNED(width, 32)) { >+ Convert8To16Row = Convert8To16Row_AVX2; >+ } >+ } >+#endif >+ >+ // Convert plane >+ for (y = 0; y < height; ++y) { >+ Convert8To16Row(src_y, dst_y, scale, width); >+ src_y += src_stride_y; >+ dst_y += dst_stride_y; >+ } >+} >+ > // Copy I422. > LIBYUV_API >-int I422Copy(const uint8* src_y, >+int I422Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -171,17 +262,17 @@ int I422Copy(const uint8* src_y, > > // Copy I444. > LIBYUV_API >-int I444Copy(const uint8* src_y, >+int I444Copy(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -209,9 +300,9 @@ int I444Copy(const uint8* src_y, > > // Copy I400. > LIBYUV_API >-int I400ToI400(const uint8* src_y, >+int I400ToI400(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { >@@ -230,13 +321,13 @@ int I400ToI400(const uint8* src_y, > > // Convert I420 to I400. > LIBYUV_API >-int I420ToI400(const uint8* src_y, >+int I420ToI400(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { >@@ -261,16 +352,16 @@ int I420ToI400(const uint8* src_y, > // Support function for NV12 etc UV channels. > // Width and height are plane sizes (typically half pixel width). > LIBYUV_API >-void SplitUVPlane(const uint8* src_uv, >+void SplitUVPlane(const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, >+ void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, > int width) = SplitUVRow_C; > // Negative height means invert the image. > if (height < 0) { >@@ -311,16 +402,6 @@ void SplitUVPlane(const uint8* src_uv, > } > } > #endif >-#if defined(HAS_SPLITUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_u, 4) && >- IS_ALIGNED(dst_stride_u, 4) && IS_ALIGNED(dst_v, 4) && >- IS_ALIGNED(dst_stride_v, 4)) { >- SplitUVRow = SplitUVRow_Any_DSPR2; >- if (IS_ALIGNED(width, 16)) { >- SplitUVRow = SplitUVRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_SPLITUVROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > SplitUVRow = SplitUVRow_Any_MSA; >@@ -340,17 +421,17 @@ void SplitUVPlane(const uint8* src_uv, > } > > LIBYUV_API >-void MergeUVPlane(const uint8* src_u, >+void MergeUVPlane(const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height) { > int y; >- void (*MergeUVRow)(const uint8* src_u, const uint8* src_v, uint8* dst_uv, >- int width) = MergeUVRow_C; >+ void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v, >+ uint8_t* dst_uv, int width) = MergeUVRow_C; > // Coalesce rows. > // Negative height means invert the image. > if (height < 0) { >@@ -410,19 +491,19 @@ void MergeUVPlane(const uint8* src_u, > // Support function for NV12 etc RGB channels. > // Width and height are plane sizes (typically half pixel width). > LIBYUV_API >-void SplitRGBPlane(const uint8* src_rgb, >+void SplitRGBPlane(const uint8_t* src_rgb, > int src_stride_rgb, >- uint8* dst_r, >+ uint8_t* dst_r, > int dst_stride_r, >- uint8* dst_g, >+ uint8_t* dst_g, > int dst_stride_g, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { > int y; >- void (*SplitRGBRow)(const uint8* src_rgb, uint8* dst_r, uint8* dst_g, >- uint8* dst_b, int width) = SplitRGBRow_C; >+ void (*SplitRGBRow)(const uint8_t* src_rgb, uint8_t* dst_r, uint8_t* dst_g, >+ uint8_t* dst_b, int width) = SplitRGBRow_C; > // Negative height means invert the image. > if (height < 0) { > height = -height; >@@ -468,19 +549,19 @@ void SplitRGBPlane(const uint8* src_rgb, > } > > LIBYUV_API >-void MergeRGBPlane(const uint8* src_r, >+void MergeRGBPlane(const uint8_t* src_r, > int src_stride_r, >- const uint8* src_g, >+ const uint8_t* src_g, > int src_stride_g, >- const uint8* src_b, >+ const uint8_t* src_b, > int src_stride_b, >- uint8* dst_rgb, >+ uint8_t* dst_rgb, > int dst_stride_rgb, > int width, > int height) { > int y; >- void (*MergeRGBRow)(const uint8* src_r, const uint8* src_g, >- const uint8* src_b, uint8* dst_rgb, int width) = >+ void (*MergeRGBRow)(const uint8_t* src_r, const uint8_t* src_g, >+ const uint8_t* src_b, uint8_t* dst_rgb, int width) = > MergeRGBRow_C; > // Coalesce rows. > // Negative height means invert the image. >@@ -524,14 +605,14 @@ void MergeRGBPlane(const uint8* src_r, > } > > // Mirror a plane of data. >-void MirrorPlane(const uint8* src_y, >+void MirrorPlane(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C; >+ void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C; > // Negative height means invert the image. > if (height < 0) { > height = -height; >@@ -562,14 +643,6 @@ void MirrorPlane(const uint8* src_y, > } > } > #endif >-// TODO(fbarchard): Mirror on mips handle unaligned memory. >-#if defined(HAS_MIRRORROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_y, 4) && >- IS_ALIGNED(src_stride_y, 4) && IS_ALIGNED(dst_y, 4) && >- IS_ALIGNED(dst_stride_y, 4)) { >- MirrorRow = MirrorRow_DSPR2; >- } >-#endif > #if defined(HAS_MIRRORROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > MirrorRow = MirrorRow_Any_MSA; >@@ -589,20 +662,20 @@ void MirrorPlane(const uint8* src_y, > > // Convert YUY2 to I422. > LIBYUV_API >-int YUY2ToI422(const uint8* src_yuy2, >+int YUY2ToI422(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v, >- int width) = YUY2ToUV422Row_C; >- void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) = >+ void (*YUY2ToUV422Row)(const uint8_t* src_yuy2, uint8_t* dst_u, >+ uint8_t* dst_v, int width) = YUY2ToUV422Row_C; >+ void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = > YUY2ToYRow_C; > if (!src_yuy2 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -675,20 +748,20 @@ int YUY2ToI422(const uint8* src_yuy2, > > // Convert UYVY to I422. > LIBYUV_API >-int UYVYToI422(const uint8* src_uyvy, >+int UYVYToI422(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; >- void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v, >- int width) = UYVYToUV422Row_C; >- void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) = >+ void (*UYVYToUV422Row)(const uint8_t* src_uyvy, uint8_t* dst_u, >+ uint8_t* dst_v, int width) = UYVYToUV422Row_C; >+ void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) = > UYVYToYRow_C; > if (!src_uyvy || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -761,14 +834,14 @@ int UYVYToI422(const uint8* src_uyvy, > > // Convert YUY2 to Y. > LIBYUV_API >-int YUY2ToY(const uint8* src_yuy2, >+int YUY2ToY(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) = >+ void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = > YUY2ToYRow_C; > if (!src_yuy2 || !dst_y || width <= 0 || height == 0) { > return -1; >@@ -828,9 +901,9 @@ int YUY2ToY(const uint8* src_yuy2, > > // Mirror I400 with optional flipping > LIBYUV_API >-int I400Mirror(const uint8* src_y, >+int I400Mirror(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { >@@ -850,17 +923,17 @@ int I400Mirror(const uint8* src_y, > > // Mirror I420 with optional flipping > LIBYUV_API >-int I420Mirror(const uint8* src_y, >+int I420Mirror(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { >@@ -892,14 +965,14 @@ int I420Mirror(const uint8* src_y, > > // ARGB mirror. > LIBYUV_API >-int ARGBMirror(const uint8* src_argb, >+int ARGBMirror(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) = >+ void (*ARGBMirrorRow)(const uint8_t* src, uint8_t* dst, int width) = > ARGBMirrorRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -957,8 +1030,8 @@ int ARGBMirror(const uint8* src_argb, > // the same blend function for all pixels if possible. > LIBYUV_API > ARGBBlendRow GetARGBBlend() { >- void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1, >- uint8* dst_argb, int width) = ARGBBlendRow_C; >+ void (*ARGBBlendRow)(const uint8_t* src_argb, const uint8_t* src_argb1, >+ uint8_t* dst_argb, int width) = ARGBBlendRow_C; > #if defined(HAS_ARGBBLENDROW_SSSE3) > if (TestCpuFlag(kCpuHasSSSE3)) { > ARGBBlendRow = ARGBBlendRow_SSSE3; >@@ -980,17 +1053,17 @@ ARGBBlendRow GetARGBBlend() { > > // Alpha Blend 2 ARGB images and store to destination. > LIBYUV_API >-int ARGBBlend(const uint8* src_argb0, >+int ARGBBlend(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1, >- uint8* dst_argb, int width) = GetARGBBlend(); >+ void (*ARGBBlendRow)(const uint8_t* src_argb, const uint8_t* src_argb1, >+ uint8_t* dst_argb, int width) = GetARGBBlend(); > if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1019,19 +1092,19 @@ int ARGBBlend(const uint8* src_argb0, > > // Alpha Blend plane and store to destination. > LIBYUV_API >-int BlendPlane(const uint8* src_y0, >+int BlendPlane(const uint8_t* src_y0, > int src_stride_y0, >- const uint8* src_y1, >+ const uint8_t* src_y1, > int src_stride_y1, >- const uint8* alpha, >+ const uint8_t* alpha, > int alpha_stride, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { > int y; >- void (*BlendPlaneRow)(const uint8* src0, const uint8* src1, >- const uint8* alpha, uint8* dst, int width) = >+ void (*BlendPlaneRow)(const uint8_t* src0, const uint8_t* src1, >+ const uint8_t* alpha, uint8_t* dst, int width) = > BlendPlaneRow_C; > if (!src_y0 || !src_y1 || !alpha || !dst_y || width <= 0 || height == 0) { > return -1; >@@ -1081,36 +1154,36 @@ int BlendPlane(const uint8* src_y0, > #define MAXTWIDTH 2048 > // Alpha Blend YUV images and store to destination. > LIBYUV_API >-int I420Blend(const uint8* src_y0, >+int I420Blend(const uint8_t* src_y0, > int src_stride_y0, >- const uint8* src_u0, >+ const uint8_t* src_u0, > int src_stride_u0, >- const uint8* src_v0, >+ const uint8_t* src_v0, > int src_stride_v0, >- const uint8* src_y1, >+ const uint8_t* src_y1, > int src_stride_y1, >- const uint8* src_u1, >+ const uint8_t* src_u1, > int src_stride_u1, >- const uint8* src_v1, >+ const uint8_t* src_v1, > int src_stride_v1, >- const uint8* alpha, >+ const uint8_t* alpha, > int alpha_stride, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height) { > int y; > // Half width/height for UV. > int halfwidth = (width + 1) >> 1; >- void (*BlendPlaneRow)(const uint8* src0, const uint8* src1, >- const uint8* alpha, uint8* dst, int width) = >+ void (*BlendPlaneRow)(const uint8_t* src0, const uint8_t* src1, >+ const uint8_t* alpha, uint8_t* dst, int width) = > BlendPlaneRow_C; >- void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width) = ScaleRowDown2Box_C; >+ void (*ScaleRowDown2)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width) = ScaleRowDown2Box_C; > if (!src_y0 || !src_u0 || !src_v0 || !src_y1 || !src_u1 || !src_v1 || > !alpha || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { > return -1; >@@ -1205,17 +1278,17 @@ int I420Blend(const uint8* src_y0, > > // Multiply 2 ARGB images and store to destination. > LIBYUV_API >-int ARGBMultiply(const uint8* src_argb0, >+int ARGBMultiply(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst, >- int width) = ARGBMultiplyRow_C; >+ void (*ARGBMultiplyRow)(const uint8_t* src0, const uint8_t* src1, >+ uint8_t* dst, int width) = ARGBMultiplyRow_C; > if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1277,16 +1350,16 @@ int ARGBMultiply(const uint8* src_argb0, > > // Add 2 ARGB images and store to destination. > LIBYUV_API >-int ARGBAdd(const uint8* src_argb0, >+int ARGBAdd(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst, >+ void (*ARGBAddRow)(const uint8_t* src0, const uint8_t* src1, uint8_t* dst, > int width) = ARGBAddRow_C; > if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1354,17 +1427,17 @@ int ARGBAdd(const uint8* src_argb0, > > // Subtract 2 ARGB images and store to destination. > LIBYUV_API >-int ARGBSubtract(const uint8* src_argb0, >+int ARGBSubtract(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst, >- int width) = ARGBSubtractRow_C; >+ void (*ARGBSubtractRow)(const uint8_t* src0, const uint8_t* src1, >+ uint8_t* dst, int width) = ARGBSubtractRow_C; > if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1424,20 +1497,20 @@ int ARGBSubtract(const uint8* src_argb0, > return 0; > } > // Convert I422 to RGBA with matrix >-static int I422ToRGBAMatrix(const uint8* src_y, >+static int I422ToRGBAMatrix(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > const struct YuvConstants* yuvconstants, > int width, > int height) { > int y; >- void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, >+ void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = > I422ToRGBARow_C; > if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) { >@@ -1473,15 +1546,6 @@ static int I422ToRGBAMatrix(const uint8* src_y, > } > } > #endif >-#if defined(HAS_I422TORGBAROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) { >- I422ToRGBARow = I422ToRGBARow_DSPR2; >- } >-#endif > #if defined(HAS_I422TORGBAROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToRGBARow = I422ToRGBARow_Any_MSA; >@@ -1503,13 +1567,13 @@ static int I422ToRGBAMatrix(const uint8* src_y, > > // Convert I422 to RGBA. > LIBYUV_API >-int I422ToRGBA(const uint8* src_y, >+int I422ToRGBA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_rgba, >+ uint8_t* dst_rgba, > int dst_stride_rgba, > int width, > int height) { >@@ -1520,13 +1584,13 @@ int I422ToRGBA(const uint8* src_y, > > // Convert I422 to BGRA. > LIBYUV_API >-int I422ToBGRA(const uint8* src_y, >+int I422ToBGRA(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_bgra, >+ uint8_t* dst_bgra, > int dst_stride_bgra, > int width, > int height) { >@@ -1539,17 +1603,17 @@ int I422ToBGRA(const uint8* src_y, > > // Convert NV12 to RGB565. > LIBYUV_API >-int NV12ToRGB565(const uint8* src_y, >+int NV12ToRGB565(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_rgb565, >+ uint8_t* dst_rgb565, > int dst_stride_rgb565, > int width, > int height) { > int y; > void (*NV12ToRGB565Row)( >- const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf, >+ const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, int width) = NV12ToRGB565Row_C; > if (!src_y || !src_uv || !dst_rgb565 || width <= 0 || height == 0) { > return -1; >@@ -1606,14 +1670,14 @@ int NV12ToRGB565(const uint8* src_y, > > // Convert RAW to RGB24. > LIBYUV_API >-int RAWToRGB24(const uint8* src_raw, >+int RAWToRGB24(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_rgb24, >+ uint8_t* dst_rgb24, > int dst_stride_rgb24, > int width, > int height) { > int y; >- void (*RAWToRGB24Row)(const uint8* src_rgb, uint8* dst_rgb24, int width) = >+ void (*RAWToRGB24Row)(const uint8_t* src_rgb, uint8_t* dst_rgb24, int width) = > RAWToRGB24Row_C; > if (!src_raw || !dst_rgb24 || width <= 0 || height == 0) { > return -1; >@@ -1664,13 +1728,13 @@ int RAWToRGB24(const uint8* src_raw, > } > > LIBYUV_API >-void SetPlane(uint8* dst_y, >+void SetPlane(uint8_t* dst_y, > int dst_stride_y, > int width, > int height, >- uint32 value) { >+ uint32_t value) { > int y; >- void (*SetRow)(uint8 * dst, uint8 value, int width) = SetRow_C; >+ void (*SetRow)(uint8_t * dst, uint8_t value, int width) = SetRow_C; > if (height < 0) { > height = -height; > dst_y = dst_y + (height - 1) * dst_stride_y; >@@ -1718,11 +1782,11 @@ void SetPlane(uint8* dst_y, > > // Draw a rectangle into I420 > LIBYUV_API >-int I420Rect(uint8* dst_y, >+int I420Rect(uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int x, > int y, >@@ -1733,9 +1797,9 @@ int I420Rect(uint8* dst_y, > int value_v) { > int halfwidth = (width + 1) >> 1; > int halfheight = (height + 1) >> 1; >- uint8* start_y = dst_y + y * dst_stride_y + x; >- uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2); >- uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2); >+ uint8_t* start_y = dst_y + y * dst_stride_y + x; >+ uint8_t* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2); >+ uint8_t* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2); > if (!dst_y || !dst_u || !dst_v || width <= 0 || height == 0 || x < 0 || > y < 0 || value_y < 0 || value_y > 255 || value_u < 0 || value_u > 255 || > value_v < 0 || value_v > 255) { >@@ -1750,15 +1814,16 @@ int I420Rect(uint8* dst_y, > > // Draw a rectangle into ARGB > LIBYUV_API >-int ARGBRect(uint8* dst_argb, >+int ARGBRect(uint8_t* dst_argb, > int dst_stride_argb, > int dst_x, > int dst_y, > int width, > int height, >- uint32 value) { >+ uint32_t value) { > int y; >- void (*ARGBSetRow)(uint8 * dst_argb, uint32 value, int width) = ARGBSetRow_C; >+ void (*ARGBSetRow)(uint8_t * dst_argb, uint32_t value, int width) = >+ ARGBSetRow_C; > if (!dst_argb || width <= 0 || height == 0 || dst_x < 0 || dst_y < 0) { > return -1; > } >@@ -1819,15 +1884,15 @@ int ARGBRect(uint8* dst_argb, > // f is foreground pixel premultiplied by alpha > > LIBYUV_API >-int ARGBAttenuate(const uint8* src_argb, >+int ARGBAttenuate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) = >- ARGBAttenuateRow_C; >+ void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb, >+ int width) = ARGBAttenuateRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -1885,14 +1950,14 @@ int ARGBAttenuate(const uint8* src_argb, > > // Convert preattentuated ARGB to unattenuated ARGB. > LIBYUV_API >-int ARGBUnattenuate(const uint8* src_argb, >+int ARGBUnattenuate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb, >+ void (*ARGBUnattenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb, > int width) = ARGBUnattenuateRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1936,14 +2001,14 @@ int ARGBUnattenuate(const uint8* src_argb, > > // Convert ARGB to Grayed ARGB. > LIBYUV_API >-int ARGBGrayTo(const uint8* src_argb, >+int ARGBGrayTo(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) = >+ void (*ARGBGrayRow)(const uint8_t* src_argb, uint8_t* dst_argb, int width) = > ARGBGrayRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -1985,16 +2050,16 @@ int ARGBGrayTo(const uint8* src_argb, > > // Make a rectangle of ARGB gray scale. > LIBYUV_API >-int ARGBGray(uint8* dst_argb, >+int ARGBGray(uint8_t* dst_argb, > int dst_stride_argb, > int dst_x, > int dst_y, > int width, > int height) { > int y; >- void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) = >+ void (*ARGBGrayRow)(const uint8_t* src_argb, uint8_t* dst_argb, int width) = > ARGBGrayRow_C; >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) { > return -1; > } >@@ -2029,15 +2094,15 @@ int ARGBGray(uint8* dst_argb, > > // Make a rectangle of ARGB Sepia tone. > LIBYUV_API >-int ARGBSepia(uint8* dst_argb, >+int ARGBSepia(uint8_t* dst_argb, > int dst_stride_argb, > int dst_x, > int dst_y, > int width, > int height) { > int y; >- void (*ARGBSepiaRow)(uint8 * dst_argb, int width) = ARGBSepiaRow_C; >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ void (*ARGBSepiaRow)(uint8_t * dst_argb, int width) = ARGBSepiaRow_C; >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) { > return -1; > } >@@ -2073,16 +2138,16 @@ int ARGBSepia(uint8* dst_argb, > // Apply a 4x4 matrix to each ARGB pixel. > // Note: Normally for shading, but can be used to swizzle or invert. > LIBYUV_API >-int ARGBColorMatrix(const uint8* src_argb, >+int ARGBColorMatrix(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const int8* matrix_argb, >+ const int8_t* matrix_argb, > int width, > int height) { > int y; >- void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb, >- const int8* matrix_argb, int width) = >+ void (*ARGBColorMatrixRow)(const uint8_t* src_argb, uint8_t* dst_argb, >+ const int8_t* matrix_argb, int width) = > ARGBColorMatrixRow_C; > if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) { > return -1; >@@ -2124,15 +2189,15 @@ int ARGBColorMatrix(const uint8* src_argb, > // Apply a 4x3 matrix to each ARGB pixel. > // Deprecated. > LIBYUV_API >-int RGBColorMatrix(uint8* dst_argb, >+int RGBColorMatrix(uint8_t* dst_argb, > int dst_stride_argb, >- const int8* matrix_rgb, >+ const int8_t* matrix_rgb, > int dst_x, > int dst_y, > int width, > int height) { >- SIMD_ALIGNED(int8 matrix_argb[16]); >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ SIMD_ALIGNED(int8_t matrix_argb[16]); >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 || dst_x < 0 || > dst_y < 0) { > return -1; >@@ -2154,24 +2219,24 @@ int RGBColorMatrix(uint8* dst_argb, > matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0; > matrix_argb[15] = 64; // 1.0 > >- return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb, dst, >+ return ARGBColorMatrix((const uint8_t*)(dst), dst_stride_argb, dst, > dst_stride_argb, &matrix_argb[0], width, height); > } > > // Apply a color table each ARGB pixel. > // Table contains 256 ARGB values. > LIBYUV_API >-int ARGBColorTable(uint8* dst_argb, >+int ARGBColorTable(uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* table_argb, >+ const uint8_t* table_argb, > int dst_x, > int dst_y, > int width, > int height) { > int y; >- void (*ARGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb, >+ void (*ARGBColorTableRow)(uint8_t * dst_argb, const uint8_t* table_argb, > int width) = ARGBColorTableRow_C; >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 || > dst_y < 0) { > return -1; >@@ -2197,17 +2262,17 @@ int ARGBColorTable(uint8* dst_argb, > // Apply a color table each ARGB pixel but preserve destination alpha. > // Table contains 256 ARGB values. > LIBYUV_API >-int RGBColorTable(uint8* dst_argb, >+int RGBColorTable(uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* table_argb, >+ const uint8_t* table_argb, > int dst_x, > int dst_y, > int width, > int height) { > int y; >- void (*RGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb, >+ void (*RGBColorTableRow)(uint8_t * dst_argb, const uint8_t* table_argb, > int width) = RGBColorTableRow_C; >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 || > dst_y < 0) { > return -1; >@@ -2240,7 +2305,7 @@ int RGBColorTable(uint8* dst_argb, > // Caveat - although SSE2 saturates, the C function does not and should be used > // with care if doing anything but quantization. > LIBYUV_API >-int ARGBQuantize(uint8* dst_argb, >+int ARGBQuantize(uint8_t* dst_argb, > int dst_stride_argb, > int scale, > int interval_size, >@@ -2250,9 +2315,9 @@ int ARGBQuantize(uint8* dst_argb, > int width, > int height) { > int y; >- void (*ARGBQuantizeRow)(uint8 * dst_argb, int scale, int interval_size, >+ void (*ARGBQuantizeRow)(uint8_t * dst_argb, int scale, int interval_size, > int interval_offset, int width) = ARGBQuantizeRow_C; >- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; >+ uint8_t* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4; > if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 || > interval_size < 1 || interval_size > 255) { > return -1; >@@ -2288,17 +2353,17 @@ int ARGBQuantize(uint8* dst_argb, > // Computes table of cumulative sum for image where the value is the sum > // of all values above and to the left of the entry. Used by ARGBBlur. > LIBYUV_API >-int ARGBComputeCumulativeSum(const uint8* src_argb, >+int ARGBComputeCumulativeSum(const uint8_t* src_argb, > int src_stride_argb, >- int32* dst_cumsum, >+ int32_t* dst_cumsum, > int dst_stride32_cumsum, > int width, > int height) { > int y; >- void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum, >- const int32* previous_cumsum, int width) = >+ void (*ComputeCumulativeSumRow)(const uint8_t* row, int32_t* cumsum, >+ const int32_t* previous_cumsum, int width) = > ComputeCumulativeSumRow_C; >- int32* previous_cumsum = dst_cumsum; >+ int32_t* previous_cumsum = dst_cumsum; > if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) { > return -1; > } >@@ -2322,25 +2387,25 @@ int ARGBComputeCumulativeSum(const uint8* src_argb, > // aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory > // as the buffer is treated as circular. > LIBYUV_API >-int ARGBBlur(const uint8* src_argb, >+int ARGBBlur(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- int32* dst_cumsum, >+ int32_t* dst_cumsum, > int dst_stride32_cumsum, > int width, > int height, > int radius) { > int y; >- void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum, >- const int32* previous_cumsum, int width) = >+ void (*ComputeCumulativeSumRow)(const uint8_t* row, int32_t* cumsum, >+ const int32_t* previous_cumsum, int width) = > ComputeCumulativeSumRow_C; >- void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft, >- int width, int area, uint8* dst, >- int count) = CumulativeSumToAverageRow_C; >- int32* cumsum_bot_row; >- int32* max_cumsum_bot_row; >- int32* cumsum_top_row; >+ void (*CumulativeSumToAverageRow)( >+ const int32_t* topleft, const int32_t* botleft, int width, int area, >+ uint8_t* dst, int count) = CumulativeSumToAverageRow_C; >+ int32_t* cumsum_bot_row; >+ int32_t* max_cumsum_bot_row; >+ int32_t* cumsum_top_row; > > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; >@@ -2394,7 +2459,7 @@ int ARGBBlur(const uint8* src_argb, > // Increment cumsum_bot_row pointer with circular buffer wrap around and > // then fill in a row of CumulativeSum. > if ((y + radius) < height) { >- const int32* prev_cumsum_bot_row = cumsum_bot_row; >+ const int32_t* prev_cumsum_bot_row = cumsum_bot_row; > cumsum_bot_row += dst_stride32_cumsum; > if (cumsum_bot_row >= max_cumsum_bot_row) { > cumsum_bot_row = dst_cumsum; >@@ -2432,16 +2497,16 @@ int ARGBBlur(const uint8* src_argb, > > // Multiply ARGB image by a specified ARGB value. > LIBYUV_API >-int ARGBShade(const uint8* src_argb, >+int ARGBShade(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >- uint32 value) { >+ uint32_t value) { > int y; >- void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb, int width, >- uint32 value) = ARGBShadeRow_C; >+ void (*ARGBShadeRow)(const uint8_t* src_argb, uint8_t* dst_argb, int width, >+ uint32_t value) = ARGBShadeRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) { > return -1; > } >@@ -2482,17 +2547,17 @@ int ARGBShade(const uint8* src_argb, > > // Interpolate 2 planes by specified amount (0 to 255). > LIBYUV_API >-int InterpolatePlane(const uint8* src0, >+int InterpolatePlane(const uint8_t* src0, > int src_stride0, >- const uint8* src1, >+ const uint8_t* src1, > int src_stride1, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height, > int interpolation) { > int y; >- void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr, >+ void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > if (!src0 || !src1 || !dst || width <= 0 || height == 0) { >@@ -2534,14 +2599,6 @@ int InterpolatePlane(const uint8* src0, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src0, 4) && >- IS_ALIGNED(src_stride0, 4) && IS_ALIGNED(src1, 4) && >- IS_ALIGNED(src_stride1, 4) && IS_ALIGNED(dst, 4) && >- IS_ALIGNED(dst_stride, 4) && IS_ALIGNED(width, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -2562,11 +2619,11 @@ int InterpolatePlane(const uint8* src0, > > // Interpolate 2 ARGB images by specified amount (0 to 255). > LIBYUV_API >-int ARGBInterpolate(const uint8* src_argb0, >+int ARGBInterpolate(const uint8_t* src_argb0, > int src_stride_argb0, >- const uint8* src_argb1, >+ const uint8_t* src_argb1, > int src_stride_argb1, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >@@ -2578,23 +2635,23 @@ int ARGBInterpolate(const uint8* src_argb0, > > // Interpolate 2 YUV images by specified amount (0 to 255). > LIBYUV_API >-int I420Interpolate(const uint8* src0_y, >+int I420Interpolate(const uint8_t* src0_y, > int src0_stride_y, >- const uint8* src0_u, >+ const uint8_t* src0_u, > int src0_stride_u, >- const uint8* src0_v, >+ const uint8_t* src0_v, > int src0_stride_v, >- const uint8* src1_y, >+ const uint8_t* src1_y, > int src1_stride_y, >- const uint8* src1_u, >+ const uint8_t* src1_u, > int src1_stride_u, >- const uint8* src1_v, >+ const uint8_t* src1_v, > int src1_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height, >@@ -2616,16 +2673,16 @@ int I420Interpolate(const uint8* src0_y, > > // Shuffle ARGB channel order. e.g. BGRA to ARGB. > LIBYUV_API >-int ARGBShuffle(const uint8* src_bgra, >+int ARGBShuffle(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* shuffler, >+ const uint8_t* shuffler, > int width, > int height) { > int y; >- void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb, >- const uint8* shuffler, int width) = ARGBShuffleRow_C; >+ void (*ARGBShuffleRow)(const uint8_t* src_bgra, uint8_t* dst_argb, >+ const uint8_t* shuffler, int width) = ARGBShuffleRow_C; > if (!src_bgra || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -2641,14 +2698,6 @@ int ARGBShuffle(const uint8* src_bgra, > height = 1; > src_stride_bgra = dst_stride_argb = 0; > } >-#if defined(HAS_ARGBSHUFFLEROW_SSE2) >- if (TestCpuFlag(kCpuHasSSE2)) { >- ARGBShuffleRow = ARGBShuffleRow_Any_SSE2; >- if (IS_ALIGNED(width, 4)) { >- ARGBShuffleRow = ARGBShuffleRow_SSE2; >- } >- } >-#endif > #if defined(HAS_ARGBSHUFFLEROW_SSSE3) > if (TestCpuFlag(kCpuHasSSSE3)) { > ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3; >@@ -2691,23 +2740,23 @@ int ARGBShuffle(const uint8* src_bgra, > } > > // Sobel ARGB effect. >-static int ARGBSobelize(const uint8* src_argb, >+static int ARGBSobelize(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >- void (*SobelRow)(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst, >+ void (*SobelRow)(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst, > int width)) { > int y; >- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_g, int width) = >+ void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_g, int width) = > ARGBToYJRow_C; >- void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1, uint8* dst_sobely, >- int width) = SobelYRow_C; >- void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1, >- const uint8* src_y2, uint8* dst_sobely, int width) = >+ void (*SobelYRow)(const uint8_t* src_y0, const uint8_t* src_y1, >+ uint8_t* dst_sobely, int width) = SobelYRow_C; >+ void (*SobelXRow)(const uint8_t* src_y0, const uint8_t* src_y1, >+ const uint8_t* src_y2, uint8_t* dst_sobely, int width) = > SobelXRow_C; > const int kEdge = 16; // Extra pixels at start of row for extrude/align. > if (!src_argb || !dst_argb || width <= 0 || height == 0) { >@@ -2787,14 +2836,14 @@ static int ARGBSobelize(const uint8* src_argb, > // 3 rows with edges before/after. > const int kRowSize = (width + kEdge + 31) & ~31; > align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge)); >- uint8* row_sobelx = rows; >- uint8* row_sobely = rows + kRowSize; >- uint8* row_y = rows + kRowSize * 2; >+ uint8_t* row_sobelx = rows; >+ uint8_t* row_sobely = rows + kRowSize; >+ uint8_t* row_y = rows + kRowSize * 2; > > // Convert first row. >- uint8* row_y0 = row_y + kEdge; >- uint8* row_y1 = row_y0 + kRowSize; >- uint8* row_y2 = row_y1 + kRowSize; >+ uint8_t* row_y0 = row_y + kEdge; >+ uint8_t* row_y1 = row_y0 + kRowSize; >+ uint8_t* row_y2 = row_y1 + kRowSize; > ARGBToYJRow(src_argb, row_y0, width); > row_y0[-1] = row_y0[0]; > memset(row_y0 + width, row_y0[width - 1], 16); // Extrude 16 for valgrind. >@@ -2818,7 +2867,7 @@ static int ARGBSobelize(const uint8* src_argb, > > // Cycle thru circular queue of 3 row_y buffers. > { >- uint8* row_yt = row_y0; >+ uint8_t* row_yt = row_y0; > row_y0 = row_y1; > row_y1 = row_y2; > row_y2 = row_yt; >@@ -2833,14 +2882,14 @@ static int ARGBSobelize(const uint8* src_argb, > > // Sobel ARGB effect. > LIBYUV_API >-int ARGBSobel(const uint8* src_argb, >+int ARGBSobel(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >- void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely, >- uint8* dst_argb, int width) = SobelRow_C; >+ void (*SobelRow)(const uint8_t* src_sobelx, const uint8_t* src_sobely, >+ uint8_t* dst_argb, int width) = SobelRow_C; > #if defined(HAS_SOBELROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > SobelRow = SobelRow_Any_SSE2; >@@ -2871,14 +2920,14 @@ int ARGBSobel(const uint8* src_argb, > > // Sobel ARGB effect with planar output. > LIBYUV_API >-int ARGBSobelToPlane(const uint8* src_argb, >+int ARGBSobelToPlane(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, > int width, > int height) { >- void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely, >- uint8* dst_, int width) = SobelToPlaneRow_C; >+ void (*SobelToPlaneRow)(const uint8_t* src_sobelx, const uint8_t* src_sobely, >+ uint8_t* dst_, int width) = SobelToPlaneRow_C; > #if defined(HAS_SOBELTOPLANEROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > SobelToPlaneRow = SobelToPlaneRow_Any_SSE2; >@@ -2910,14 +2959,14 @@ int ARGBSobelToPlane(const uint8* src_argb, > // SobelXY ARGB effect. > // Similar to Sobel, but also stores Sobel X in R and Sobel Y in B. G = Sobel. > LIBYUV_API >-int ARGBSobelXY(const uint8* src_argb, >+int ARGBSobelXY(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { >- void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely, >- uint8* dst_argb, int width) = SobelXYRow_C; >+ void (*SobelXYRow)(const uint8_t* src_sobelx, const uint8_t* src_sobely, >+ uint8_t* dst_argb, int width) = SobelXYRow_C; > #if defined(HAS_SOBELXYROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > SobelXYRow = SobelXYRow_Any_SSE2; >@@ -2948,15 +2997,15 @@ int ARGBSobelXY(const uint8* src_argb, > > // Apply a 4x4 polynomial to each ARGB pixel. > LIBYUV_API >-int ARGBPolynomial(const uint8* src_argb, >+int ARGBPolynomial(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > const float* poly, > int width, > int height) { > int y; >- void (*ARGBPolynomialRow)(const uint8* src_argb, uint8* dst_argb, >+ void (*ARGBPolynomialRow)(const uint8_t* src_argb, uint8_t* dst_argb, > const float* poly, int width) = ARGBPolynomialRow_C; > if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) { > return -1; >@@ -2996,16 +3045,16 @@ int ARGBPolynomial(const uint8* src_argb, > // Convert plane of 16 bit shorts to half floats. > // Source values are multiplied by scale before storing as half float. > LIBYUV_API >-int HalfFloatPlane(const uint16* src_y, >+int HalfFloatPlane(const uint16_t* src_y, > int src_stride_y, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, > float scale, > int width, > int height) { > int y; >- void (*HalfFloatRow)(const uint16* src, uint16* dst, float scale, int width) = >- HalfFloatRow_C; >+ void (*HalfFloatRow)(const uint16_t* src, uint16_t* dst, float scale, >+ int width) = HalfFloatRow_C; > if (!src_y || !dst_y || width <= 0 || height == 0) { > return -1; > } >@@ -3074,19 +3123,40 @@ int HalfFloatPlane(const uint16* src_y, > return 0; > } > >+// Convert a buffer of bytes to floats, scale the values and store as floats. >+LIBYUV_API >+int ByteToFloat(const uint8_t* src_y, float* dst_y, float scale, int width) { >+ void (*ByteToFloatRow)(const uint8_t* src, float* dst, float scale, >+ int width) = ByteToFloatRow_C; >+ if (!src_y || !dst_y || width <= 0) { >+ return -1; >+ } >+#if defined(HAS_BYTETOFLOATROW_NEON) >+ if (TestCpuFlag(kCpuHasNEON)) { >+ ByteToFloatRow = ByteToFloatRow_Any_NEON; >+ if (IS_ALIGNED(width, 8)) { >+ ByteToFloatRow = ByteToFloatRow_NEON; >+ } >+ } >+#endif >+ >+ ByteToFloatRow(src_y, dst_y, scale, width); >+ return 0; >+} >+ > // Apply a lumacolortable to each ARGB pixel. > LIBYUV_API >-int ARGBLumaColorTable(const uint8* src_argb, >+int ARGBLumaColorTable(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- const uint8* luma, >+ const uint8_t* luma, > int width, > int height) { > int y; > void (*ARGBLumaColorTableRow)( >- const uint8* src_argb, uint8* dst_argb, int width, const uint8* luma, >- const uint32 lumacoeff) = ARGBLumaColorTableRow_C; >+ const uint8_t* src_argb, uint8_t* dst_argb, int width, >+ const uint8_t* luma, const uint32_t lumacoeff) = ARGBLumaColorTableRow_C; > if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) { > return -1; > } >@@ -3118,15 +3188,15 @@ int ARGBLumaColorTable(const uint8* src_argb, > > // Copy Alpha from one ARGB image to another. > LIBYUV_API >-int ARGBCopyAlpha(const uint8* src_argb, >+int ARGBCopyAlpha(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) = >- ARGBCopyAlphaRow_C; >+ void (*ARGBCopyAlphaRow)(const uint8_t* src_argb, uint8_t* dst_argb, >+ int width) = ARGBCopyAlphaRow_C; > if (!src_argb || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -3169,10 +3239,10 @@ int ARGBCopyAlpha(const uint8* src_argb, > > // Extract just the alpha channel from ARGB. > LIBYUV_API >-int ARGBExtractAlpha(const uint8* src_argb, >- int src_stride, >- uint8* dst_a, >- int dst_stride, >+int ARGBExtractAlpha(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_a, >+ int dst_stride_a, > int width, > int height) { > if (!src_argb || !dst_a || width <= 0 || height == 0) { >@@ -3181,17 +3251,17 @@ int ARGBExtractAlpha(const uint8* src_argb, > // Negative height means invert the image. > if (height < 0) { > height = -height; >- src_argb += (height - 1) * src_stride; >- src_stride = -src_stride; >+ src_argb += (height - 1) * src_stride_argb; >+ src_stride_argb = -src_stride_argb; > } > // Coalesce rows. >- if (src_stride == width * 4 && dst_stride == width) { >+ if (src_stride_argb == width * 4 && dst_stride_a == width) { > width *= height; > height = 1; >- src_stride = dst_stride = 0; >+ src_stride_argb = dst_stride_a = 0; > } >- void (*ARGBExtractAlphaRow)(const uint8* src_argb, uint8* dst_a, int width) = >- ARGBExtractAlphaRow_C; >+ void (*ARGBExtractAlphaRow)(const uint8_t* src_argb, uint8_t* dst_a, >+ int width) = ARGBExtractAlphaRow_C; > #if defined(HAS_ARGBEXTRACTALPHAROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2 >@@ -3219,23 +3289,23 @@ int ARGBExtractAlpha(const uint8* src_argb, > > for (int y = 0; y < height; ++y) { > ARGBExtractAlphaRow(src_argb, dst_a, width); >- src_argb += src_stride; >- dst_a += dst_stride; >+ src_argb += src_stride_argb; >+ dst_a += dst_stride_a; > } > return 0; > } > > // Copy a planar Y channel to the alpha channel of a destination ARGB image. > LIBYUV_API >-int ARGBCopyYToAlpha(const uint8* src_y, >+int ARGBCopyYToAlpha(const uint8_t* src_y, > int src_stride_y, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height) { > int y; >- void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) = >- ARGBCopyYToAlphaRow_C; >+ void (*ARGBCopyYToAlphaRow)(const uint8_t* src_y, uint8_t* dst_argb, >+ int width) = ARGBCopyYToAlphaRow_C; > if (!src_y || !dst_argb || width <= 0 || height == 0) { > return -1; > } >@@ -3280,19 +3350,19 @@ int ARGBCopyYToAlpha(const uint8* src_y, > // directly. A SplitUVRow_Odd function could copy the remaining chroma. > > LIBYUV_API >-int YUY2ToNV12(const uint8* src_yuy2, >+int YUY2ToNV12(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height) { > int y; > int halfwidth = (width + 1) >> 1; >- void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, >+ void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, > int width) = SplitUVRow_C; >- void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr, >+ void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > if (!src_yuy2 || !dst_y || !dst_uv || width <= 0 || height == 0) { >@@ -3396,19 +3466,19 @@ int YUY2ToNV12(const uint8* src_yuy2, > } > > LIBYUV_API >-int UYVYToNV12(const uint8* src_uyvy, >+int UYVYToNV12(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int dst_stride_uv, > int width, > int height) { > int y; > int halfwidth = (width + 1) >> 1; >- void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, >+ void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, > int width) = SplitUVRow_C; >- void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr, >+ void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > if (!src_uyvy || !dst_y || !dst_uv || width <= 0 || height == 0) { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate.cc >index b16af507185..f2bed85b755 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate.cc >@@ -22,18 +22,18 @@ extern "C" { > #endif > > LIBYUV_API >-void TransposePlane(const uint8* src, >+void TransposePlane(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { > int i = height; > #if defined(HAS_TRANSPOSEWX16_MSA) >- void (*TransposeWx16)(const uint8* src, int src_stride, uint8* dst, >+ void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst, > int dst_stride, int width) = TransposeWx16_C; > #else >- void (*TransposeWx8)(const uint8* src, int src_stride, uint8* dst, >+ void (*TransposeWx8)(const uint8_t* src, int src_stride, uint8_t* dst, > int dst_stride, int width) = TransposeWx8_C; > #endif > #if defined(HAS_TRANSPOSEWX8_NEON) >@@ -57,16 +57,6 @@ void TransposePlane(const uint8* src, > } > } > #endif >-#if defined(HAS_TRANSPOSEWX8_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- if (IS_ALIGNED(width, 4) && IS_ALIGNED(src, 4) && >- IS_ALIGNED(src_stride, 4)) { >- TransposeWx8 = TransposeWx8_Fast_DSPR2; >- } else { >- TransposeWx8 = TransposeWx8_DSPR2; >- } >- } >-#endif > #if defined(HAS_TRANSPOSEWX16_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > TransposeWx16 = TransposeWx16_Any_MSA; >@@ -100,9 +90,9 @@ void TransposePlane(const uint8* src, > } > > LIBYUV_API >-void RotatePlane90(const uint8* src, >+void RotatePlane90(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { >@@ -115,9 +105,9 @@ void RotatePlane90(const uint8* src, > } > > LIBYUV_API >-void RotatePlane270(const uint8* src, >+void RotatePlane270(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { >@@ -130,20 +120,20 @@ void RotatePlane270(const uint8* src, > } > > LIBYUV_API >-void RotatePlane180(const uint8* src, >+void RotatePlane180(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { > // Swap first and last row and mirror the content. Uses a temporary row. > align_buffer_64(row, width); >- const uint8* src_bot = src + src_stride * (height - 1); >- uint8* dst_bot = dst + dst_stride * (height - 1); >+ const uint8_t* src_bot = src + src_stride * (height - 1); >+ uint8_t* dst_bot = dst + dst_stride * (height - 1); > int half_height = (height + 1) >> 1; > int y; >- void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C; >- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; >+ void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C; >+ void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C; > #if defined(HAS_MIRRORROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > MirrorRow = MirrorRow_Any_NEON; >@@ -168,14 +158,6 @@ void RotatePlane180(const uint8* src, > } > } > #endif >-// TODO(fbarchard): Mirror on mips handle unaligned memory. >-#if defined(HAS_MIRRORROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src, 4) && >- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst, 4) && >- IS_ALIGNED(dst_stride, 4)) { >- MirrorRow = MirrorRow_DSPR2; >- } >-#endif > #if defined(HAS_MIRRORROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > MirrorRow = MirrorRow_Any_MSA; >@@ -204,11 +186,6 @@ void RotatePlane180(const uint8* src, > CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; > } > #endif >-#if defined(HAS_COPYROW_MIPS) >- if (TestCpuFlag(kCpuHasMIPS)) { >- CopyRow = CopyRow_MIPS; >- } >-#endif > > // Odd height will harmlessly mirror the middle row twice. > for (y = 0; y < half_height; ++y) { >@@ -224,22 +201,22 @@ void RotatePlane180(const uint8* src, > } > > LIBYUV_API >-void TransposeUV(const uint8* src, >+void TransposeUV(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { > int i = height; > #if defined(HAS_TRANSPOSEUVWX16_MSA) >- void (*TransposeUVWx16)(const uint8* src, int src_stride, uint8* dst_a, >- int dst_stride_a, uint8* dst_b, int dst_stride_b, >+ void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a, >+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b, > int width) = TransposeUVWx16_C; > #else >- void (*TransposeUVWx8)(const uint8* src, int src_stride, uint8* dst_a, >- int dst_stride_a, uint8* dst_b, int dst_stride_b, >+ void (*TransposeUVWx8)(const uint8_t* src, int src_stride, uint8_t* dst_a, >+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b, > int width) = TransposeUVWx8_C; > #endif > #if defined(HAS_TRANSPOSEUVWX8_NEON) >@@ -255,12 +232,6 @@ void TransposeUV(const uint8* src, > } > } > #endif >-#if defined(HAS_TRANSPOSEUVWX8_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 2) && IS_ALIGNED(src, 4) && >- IS_ALIGNED(src_stride, 4)) { >- TransposeUVWx8 = TransposeUVWx8_DSPR2; >- } >-#endif > #if defined(HAS_TRANSPOSEUVWX16_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > TransposeUVWx16 = TransposeUVWx16_Any_MSA; >@@ -299,11 +270,11 @@ void TransposeUV(const uint8* src, > } > > LIBYUV_API >-void RotateUV90(const uint8* src, >+void RotateUV90(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { >@@ -315,11 +286,11 @@ void RotateUV90(const uint8* src, > } > > LIBYUV_API >-void RotateUV270(const uint8* src, >+void RotateUV270(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { >@@ -334,17 +305,17 @@ void RotateUV270(const uint8* src, > > // Rotate 180 is a horizontal and vertical flip. > LIBYUV_API >-void RotateUV180(const uint8* src, >+void RotateUV180(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { > int i; >- void (*MirrorUVRow)(const uint8* src, uint8* dst_u, uint8* dst_v, int width) = >- MirrorUVRow_C; >+ void (*MirrorUVRow)(const uint8_t* src, uint8_t* dst_u, uint8_t* dst_v, >+ int width) = MirrorUVRow_C; > #if defined(HAS_MIRRORUVROW_NEON) > if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) { > MirrorUVRow = MirrorUVRow_NEON; >@@ -355,12 +326,6 @@ void RotateUV180(const uint8* src, > MirrorUVRow = MirrorUVRow_SSSE3; > } > #endif >-#if defined(HAS_MIRRORUVROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src, 4) && >- IS_ALIGNED(src_stride, 4)) { >- MirrorUVRow = MirrorUVRow_DSPR2; >- } >-#endif > #if defined(HAS_MIRRORUVROW_MSA) > if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 32)) { > MirrorUVRow = MirrorUVRow_MSA; >@@ -379,9 +344,9 @@ void RotateUV180(const uint8* src, > } > > LIBYUV_API >-int RotatePlane(const uint8* src, >+int RotatePlane(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height, >@@ -418,17 +383,17 @@ int RotatePlane(const uint8* src, > } > > LIBYUV_API >-int I420Rotate(const uint8* src_y, >+int I420Rotate(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height, >@@ -486,15 +451,15 @@ int I420Rotate(const uint8* src_y, > } > > LIBYUV_API >-int NV12ToI420Rotate(const uint8* src_y, >+int NV12ToI420Rotate(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_uv, >+ const uint8_t* src_uv, > int src_stride_uv, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int width, > int height, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc >index 562096b926c..c2752e6222c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc >@@ -19,8 +19,8 @@ extern "C" { > #endif > > #define TANY(NAMEANY, TPOS_SIMD, MASK) \ >- void NAMEANY(const uint8* src, int src_stride, uint8* dst, int dst_stride, \ >- int width) { \ >+ void NAMEANY(const uint8_t* src, int src_stride, uint8_t* dst, \ >+ int dst_stride, int width) { \ > int r = width & MASK; \ > int n = width - r; \ > if (n > 0) { \ >@@ -38,17 +38,15 @@ TANY(TransposeWx8_Any_SSSE3, TransposeWx8_SSSE3, 7) > #ifdef HAS_TRANSPOSEWX8_FAST_SSSE3 > TANY(TransposeWx8_Fast_Any_SSSE3, TransposeWx8_Fast_SSSE3, 15) > #endif >-#ifdef HAS_TRANSPOSEWX8_DSPR2 >-TANY(TransposeWx8_Any_DSPR2, TransposeWx8_DSPR2, 7) >-#endif > #ifdef HAS_TRANSPOSEWX16_MSA > TANY(TransposeWx16_Any_MSA, TransposeWx16_MSA, 15) > #endif > #undef TANY > > #define TUVANY(NAMEANY, TPOS_SIMD, MASK) \ >- void NAMEANY(const uint8* src, int src_stride, uint8* dst_a, \ >- int dst_stride_a, uint8* dst_b, int dst_stride_b, int width) { \ >+ void NAMEANY(const uint8_t* src, int src_stride, uint8_t* dst_a, \ >+ int dst_stride_a, uint8_t* dst_b, int dst_stride_b, \ >+ int width) { \ > int r = width & MASK; \ > int n = width - r; \ > if (n > 0) { \ >@@ -64,9 +62,6 @@ TUVANY(TransposeUVWx8_Any_NEON, TransposeUVWx8_NEON, 7) > #ifdef HAS_TRANSPOSEUVWX8_SSE2 > TUVANY(TransposeUVWx8_Any_SSE2, TransposeUVWx8_SSE2, 7) > #endif >-#ifdef HAS_TRANSPOSEUVWX8_DSPR2 >-TUVANY(TransposeUVWx8_Any_DSPR2, TransposeUVWx8_DSPR2, 7) >-#endif > #ifdef HAS_TRANSPOSEUVWX16_MSA > TUVANY(TransposeUVWx16_Any_MSA, TransposeUVWx16_MSA, 7) > #endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc >index ede4eafa6c2..5a6e05376f1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc >@@ -14,113 +14,102 @@ > #include "libyuv/cpu_id.h" > #include "libyuv/planar_functions.h" > #include "libyuv/row.h" >+#include "libyuv/scale_row.h" /* for ScaleARGBRowDownEven_ */ > > #ifdef __cplusplus > namespace libyuv { > extern "C" { > #endif > >-// ARGBScale has a function to copy pixels to a row, striding each source >-// pixel by a constant. >-#if !defined(LIBYUV_DISABLE_X86) && \ >- (defined(_M_IX86) || \ >- (defined(__x86_64__) && !defined(__native_client__)) || \ >- defined(__i386__)) >-#define HAS_SCALEARGBROWDOWNEVEN_SSE2 >-void ScaleARGBRowDownEven_SSE2(const uint8* src_ptr, >- int src_stride, >- int src_stepx, >- uint8* dst_ptr, >- int dst_width); >-#endif >-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \ >- (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__)) >-#define HAS_SCALEARGBROWDOWNEVEN_NEON >-void ScaleARGBRowDownEven_NEON(const uint8* src_ptr, >- int src_stride, >- int src_stepx, >- uint8* dst_ptr, >- int dst_width); >-#endif >- >-void ScaleARGBRowDownEven_C(const uint8* src_ptr, >- int, >- int src_stepx, >- uint8* dst_ptr, >- int dst_width); >- >-static void ARGBTranspose(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >+static void ARGBTranspose(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_argb, >+ int dst_stride_argb, > int width, > int height) { > int i; >- int src_pixel_step = src_stride >> 2; >- void (*ScaleARGBRowDownEven)(const uint8* src_ptr, int src_stride, >- int src_step, uint8* dst_ptr, int dst_width) = >- ScaleARGBRowDownEven_C; >+ int src_pixel_step = src_stride_argb >> 2; >+ void (*ScaleARGBRowDownEven)( >+ const uint8_t* src_argb, ptrdiff_t src_stride_argb, int src_step, >+ uint8_t* dst_argb, int dst_width) = ScaleARGBRowDownEven_C; > #if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2) >- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(height, 4)) { // Width of dest. >- ScaleARGBRowDownEven = ScaleARGBRowDownEven_SSE2; >+ if (TestCpuFlag(kCpuHasSSE2)) { >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_Any_SSE2; >+ if (IS_ALIGNED(height, 4)) { // Width of dest. >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_SSE2; >+ } > } > #endif > #if defined(HAS_SCALEARGBROWDOWNEVEN_NEON) >- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(height, 4)) { // Width of dest. >- ScaleARGBRowDownEven = ScaleARGBRowDownEven_NEON; >+ if (TestCpuFlag(kCpuHasNEON)) { >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_Any_NEON; >+ if (IS_ALIGNED(height, 4)) { // Width of dest. >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_NEON; >+ } >+ } >+#endif >+#if defined(HAS_SCALEARGBROWDOWNEVEN_MSA) >+ if (TestCpuFlag(kCpuHasMSA)) { >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_Any_MSA; >+ if (IS_ALIGNED(height, 4)) { // Width of dest. >+ ScaleARGBRowDownEven = ScaleARGBRowDownEven_MSA; >+ } > } > #endif > > for (i = 0; i < width; ++i) { // column of source to row of dest. >- ScaleARGBRowDownEven(src, 0, src_pixel_step, dst, height); >- dst += dst_stride; >- src += 4; >+ ScaleARGBRowDownEven(src_argb, 0, src_pixel_step, dst_argb, height); >+ dst_argb += dst_stride_argb; >+ src_argb += 4; > } > } > >-void ARGBRotate90(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >+void ARGBRotate90(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_argb, >+ int dst_stride_argb, > int width, > int height) { > // Rotate by 90 is a ARGBTranspose with the source read > // from bottom to top. So set the source pointer to the end > // of the buffer and flip the sign of the source stride. >- src += src_stride * (height - 1); >- src_stride = -src_stride; >- ARGBTranspose(src, src_stride, dst, dst_stride, width, height); >+ src_argb += src_stride_argb * (height - 1); >+ src_stride_argb = -src_stride_argb; >+ ARGBTranspose(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width, >+ height); > } > >-void ARGBRotate270(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >+void ARGBRotate270(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_argb, >+ int dst_stride_argb, > int width, > int height) { > // Rotate by 270 is a ARGBTranspose with the destination written > // from bottom to top. So set the destination pointer to the end > // of the buffer and flip the sign of the destination stride. >- dst += dst_stride * (width - 1); >- dst_stride = -dst_stride; >- ARGBTranspose(src, src_stride, dst, dst_stride, width, height); >+ dst_argb += dst_stride_argb * (width - 1); >+ dst_stride_argb = -dst_stride_argb; >+ ARGBTranspose(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width, >+ height); > } > >-void ARGBRotate180(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >+void ARGBRotate180(const uint8_t* src_argb, >+ int src_stride_argb, >+ uint8_t* dst_argb, >+ int dst_stride_argb, > int width, > int height) { > // Swap first and last row and mirror the content. Uses a temporary row. > align_buffer_64(row, width * 4); >- const uint8* src_bot = src + src_stride * (height - 1); >- uint8* dst_bot = dst + dst_stride * (height - 1); >+ const uint8_t* src_bot = src_argb + src_stride_argb * (height - 1); >+ uint8_t* dst_bot = dst_argb + dst_stride_argb * (height - 1); > int half_height = (height + 1) >> 1; > int y; >- void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) = >+ void (*ARGBMirrorRow)(const uint8_t* src_argb, uint8_t* dst_argb, int width) = > ARGBMirrorRow_C; >- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C; >+ void (*CopyRow)(const uint8_t* src_argb, uint8_t* dst_argb, int width) = >+ CopyRow_C; > #if defined(HAS_ARGBMIRRORROW_NEON) > if (TestCpuFlag(kCpuHasNEON)) { > ARGBMirrorRow = ARGBMirrorRow_Any_NEON; >@@ -173,29 +162,24 @@ void ARGBRotate180(const uint8* src, > CopyRow = IS_ALIGNED(width * 4, 32) ? CopyRow_NEON : CopyRow_Any_NEON; > } > #endif >-#if defined(HAS_COPYROW_MIPS) >- if (TestCpuFlag(kCpuHasMIPS)) { >- CopyRow = CopyRow_MIPS; >- } >-#endif > > // Odd height will harmlessly mirror the middle row twice. > for (y = 0; y < half_height; ++y) { >- ARGBMirrorRow(src, row, width); // Mirror first row into a buffer >- ARGBMirrorRow(src_bot, dst, width); // Mirror last row into first row >- CopyRow(row, dst_bot, width * 4); // Copy first mirrored row into last >- src += src_stride; >- dst += dst_stride; >- src_bot -= src_stride; >- dst_bot -= dst_stride; >+ ARGBMirrorRow(src_argb, row, width); // Mirror first row into a buffer >+ ARGBMirrorRow(src_bot, dst_argb, width); // Mirror last row into first row >+ CopyRow(row, dst_bot, width * 4); // Copy first mirrored row into last >+ src_argb += src_stride_argb; >+ dst_argb += dst_stride_argb; >+ src_bot -= src_stride_argb; >+ dst_bot -= dst_stride_argb; > } > free_aligned_buffer_64(row); > } > > LIBYUV_API >-int ARGBRotate(const uint8* src_argb, >+int ARGBRotate(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int width, > int height, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc >index 89357e732d2..ff212adebc4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc >@@ -16,9 +16,9 @@ namespace libyuv { > extern "C" { > #endif > >-void TransposeWx8_C(const uint8* src, >+void TransposeWx8_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > int i; >@@ -36,11 +36,11 @@ void TransposeWx8_C(const uint8* src, > } > } > >-void TransposeUVWx8_C(const uint8* src, >+void TransposeUVWx8_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { > int i; >@@ -67,9 +67,9 @@ void TransposeUVWx8_C(const uint8* src, > } > } > >-void TransposeWxH_C(const uint8* src, >+void TransposeWxH_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width, > int height) { >@@ -82,11 +82,11 @@ void TransposeWxH_C(const uint8* src, > } > } > >-void TransposeUVWxH_C(const uint8* src, >+void TransposeUVWxH_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width, > int height) { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_dspr2.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_dspr2.cc >deleted file mode 100644 >index 5d2338deff6..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_dspr2.cc >+++ /dev/null >@@ -1,475 +0,0 @@ >-/* >- * Copyright 2011 The LibYuv 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 "libyuv/rotate_row.h" >-#include "libyuv/row.h" >- >-#include "libyuv/basic_types.h" >- >-#ifdef __cplusplus >-namespace libyuv { >-extern "C" { >-#endif >- >-#if !defined(LIBYUV_DISABLE_DSPR2) && defined(__mips_dsp) && \ >- (__mips_dsp_rev >= 2) && (_MIPS_SIM == _MIPS_SIM_ABI32) >- >-void TransposeWx8_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >- int width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "sll $t2, %[src_stride], 0x1 \n" // src_stride x 2 >- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4 >- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8 >- "addu $t3, $t2, %[src_stride] \n" >- "addu $t5, $t4, %[src_stride] \n" >- "addu $t6, $t2, $t4 \n" >- "andi $t0, %[dst], 0x3 \n" >- "andi $t1, %[dst_stride], 0x3 \n" >- "or $t0, $t0, $t1 \n" >- "bnez $t0, 11f \n" >- " subu $t7, $t9, %[src_stride] \n" >- // dst + dst_stride word aligned >- "1: \n" >- "lbu $t0, 0(%[src]) \n" >- "lbux $t1, %[src_stride](%[src]) \n" >- "lbux $t8, $t2(%[src]) \n" >- "lbux $t9, $t3(%[src]) \n" >- "sll $t1, $t1, 16 \n" >- "sll $t9, $t9, 16 \n" >- "or $t0, $t0, $t1 \n" >- "or $t8, $t8, $t9 \n" >- "precr.qb.ph $s0, $t8, $t0 \n" >- "lbux $t0, $t4(%[src]) \n" >- "lbux $t1, $t5(%[src]) \n" >- "lbux $t8, $t6(%[src]) \n" >- "lbux $t9, $t7(%[src]) \n" >- "sll $t1, $t1, 16 \n" >- "sll $t9, $t9, 16 \n" >- "or $t0, $t0, $t1 \n" >- "or $t8, $t8, $t9 \n" >- "precr.qb.ph $s1, $t8, $t0 \n" >- "sw $s0, 0(%[dst]) \n" >- "addiu %[width], -1 \n" >- "addiu %[src], 1 \n" >- "sw $s1, 4(%[dst]) \n" >- "bnez %[width], 1b \n" >- " addu %[dst], %[dst], %[dst_stride] \n" >- "b 2f \n" >- // dst + dst_stride unaligned >- "11: \n" >- "lbu $t0, 0(%[src]) \n" >- "lbux $t1, %[src_stride](%[src]) \n" >- "lbux $t8, $t2(%[src]) \n" >- "lbux $t9, $t3(%[src]) \n" >- "sll $t1, $t1, 16 \n" >- "sll $t9, $t9, 16 \n" >- "or $t0, $t0, $t1 \n" >- "or $t8, $t8, $t9 \n" >- "precr.qb.ph $s0, $t8, $t0 \n" >- "lbux $t0, $t4(%[src]) \n" >- "lbux $t1, $t5(%[src]) \n" >- "lbux $t8, $t6(%[src]) \n" >- "lbux $t9, $t7(%[src]) \n" >- "sll $t1, $t1, 16 \n" >- "sll $t9, $t9, 16 \n" >- "or $t0, $t0, $t1 \n" >- "or $t8, $t8, $t9 \n" >- "precr.qb.ph $s1, $t8, $t0 \n" >- "swr $s0, 0(%[dst]) \n" >- "swl $s0, 3(%[dst]) \n" >- "addiu %[width], -1 \n" >- "addiu %[src], 1 \n" >- "swr $s1, 4(%[dst]) \n" >- "swl $s1, 7(%[dst]) \n" >- "bnez %[width], 11b \n" >- "addu %[dst], %[dst], %[dst_stride] \n" >- "2: \n" >- ".set pop \n" >- : [src] "+r"(src), [dst] "+r"(dst), [width] "+r"(width) >- : [src_stride] "r"(src_stride), [dst_stride] "r"(dst_stride) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "s0", "s1"); >-} >- >-void TransposeWx8_Fast_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst, >- int dst_stride, >- int width) { >- __asm__ __volatile__( >- ".set noat \n" >- ".set push \n" >- ".set noreorder \n" >- "beqz %[width], 2f \n" >- " sll $t2, %[src_stride], 0x1 \n" // src_stride x 2 >- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4 >- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8 >- "addu $t3, $t2, %[src_stride] \n" >- "addu $t5, $t4, %[src_stride] \n" >- "addu $t6, $t2, $t4 \n" >- >- "srl $AT, %[width], 0x2 \n" >- "andi $t0, %[dst], 0x3 \n" >- "andi $t1, %[dst_stride], 0x3 \n" >- "or $t0, $t0, $t1 \n" >- "bnez $t0, 11f \n" >- " subu $t7, $t9, %[src_stride] \n" >- // dst + dst_stride word aligned >- "1: \n" >- "lw $t0, 0(%[src]) \n" >- "lwx $t1, %[src_stride](%[src]) \n" >- "lwx $t8, $t2(%[src]) \n" >- "lwx $t9, $t3(%[src]) \n" >- >- // t0 = | 30 | 20 | 10 | 00 | >- // t1 = | 31 | 21 | 11 | 01 | >- // t8 = | 32 | 22 | 12 | 02 | >- // t9 = | 33 | 23 | 13 | 03 | >- >- "precr.qb.ph $s0, $t1, $t0 \n" >- "precr.qb.ph $s1, $t9, $t8 \n" >- "precrq.qb.ph $s2, $t1, $t0 \n" >- "precrq.qb.ph $s3, $t9, $t8 \n" >- >- // s0 = | 21 | 01 | 20 | 00 | >- // s1 = | 23 | 03 | 22 | 02 | >- // s2 = | 31 | 11 | 30 | 10 | >- // s3 = | 33 | 13 | 32 | 12 | >- >- "precr.qb.ph $s4, $s1, $s0 \n" >- "precrq.qb.ph $s5, $s1, $s0 \n" >- "precr.qb.ph $s6, $s3, $s2 \n" >- "precrq.qb.ph $s7, $s3, $s2 \n" >- >- // s4 = | 03 | 02 | 01 | 00 | >- // s5 = | 23 | 22 | 21 | 20 | >- // s6 = | 13 | 12 | 11 | 10 | >- // s7 = | 33 | 32 | 31 | 30 | >- >- "lwx $t0, $t4(%[src]) \n" >- "lwx $t1, $t5(%[src]) \n" >- "lwx $t8, $t6(%[src]) \n" >- "lwx $t9, $t7(%[src]) \n" >- >- // t0 = | 34 | 24 | 14 | 04 | >- // t1 = | 35 | 25 | 15 | 05 | >- // t8 = | 36 | 26 | 16 | 06 | >- // t9 = | 37 | 27 | 17 | 07 | >- >- "precr.qb.ph $s0, $t1, $t0 \n" >- "precr.qb.ph $s1, $t9, $t8 \n" >- "precrq.qb.ph $s2, $t1, $t0 \n" >- "precrq.qb.ph $s3, $t9, $t8 \n" >- >- // s0 = | 25 | 05 | 24 | 04 | >- // s1 = | 27 | 07 | 26 | 06 | >- // s2 = | 35 | 15 | 34 | 14 | >- // s3 = | 37 | 17 | 36 | 16 | >- >- "precr.qb.ph $t0, $s1, $s0 \n" >- "precrq.qb.ph $t1, $s1, $s0 \n" >- "precr.qb.ph $t8, $s3, $s2 \n" >- "precrq.qb.ph $t9, $s3, $s2 \n" >- >- // t0 = | 07 | 06 | 05 | 04 | >- // t1 = | 27 | 26 | 25 | 24 | >- // t8 = | 17 | 16 | 15 | 14 | >- // t9 = | 37 | 36 | 35 | 34 | >- >- "addu $s0, %[dst], %[dst_stride] \n" >- "addu $s1, $s0, %[dst_stride] \n" >- "addu $s2, $s1, %[dst_stride] \n" >- >- "sw $s4, 0(%[dst]) \n" >- "sw $t0, 4(%[dst]) \n" >- "sw $s6, 0($s0) \n" >- "sw $t8, 4($s0) \n" >- "sw $s5, 0($s1) \n" >- "sw $t1, 4($s1) \n" >- "sw $s7, 0($s2) \n" >- "sw $t9, 4($s2) \n" >- >- "addiu $AT, -1 \n" >- "addiu %[src], 4 \n" >- >- "bnez $AT, 1b \n" >- " addu %[dst], $s2, %[dst_stride] \n" >- "b 2f \n" >- // dst + dst_stride unaligned >- "11: \n" >- "lw $t0, 0(%[src]) \n" >- "lwx $t1, %[src_stride](%[src]) \n" >- "lwx $t8, $t2(%[src]) \n" >- "lwx $t9, $t3(%[src]) \n" >- >- // t0 = | 30 | 20 | 10 | 00 | >- // t1 = | 31 | 21 | 11 | 01 | >- // t8 = | 32 | 22 | 12 | 02 | >- // t9 = | 33 | 23 | 13 | 03 | >- >- "precr.qb.ph $s0, $t1, $t0 \n" >- "precr.qb.ph $s1, $t9, $t8 \n" >- "precrq.qb.ph $s2, $t1, $t0 \n" >- "precrq.qb.ph $s3, $t9, $t8 \n" >- >- // s0 = | 21 | 01 | 20 | 00 | >- // s1 = | 23 | 03 | 22 | 02 | >- // s2 = | 31 | 11 | 30 | 10 | >- // s3 = | 33 | 13 | 32 | 12 | >- >- "precr.qb.ph $s4, $s1, $s0 \n" >- "precrq.qb.ph $s5, $s1, $s0 \n" >- "precr.qb.ph $s6, $s3, $s2 \n" >- "precrq.qb.ph $s7, $s3, $s2 \n" >- >- // s4 = | 03 | 02 | 01 | 00 | >- // s5 = | 23 | 22 | 21 | 20 | >- // s6 = | 13 | 12 | 11 | 10 | >- // s7 = | 33 | 32 | 31 | 30 | >- >- "lwx $t0, $t4(%[src]) \n" >- "lwx $t1, $t5(%[src]) \n" >- "lwx $t8, $t6(%[src]) \n" >- "lwx $t9, $t7(%[src]) \n" >- >- // t0 = | 34 | 24 | 14 | 04 | >- // t1 = | 35 | 25 | 15 | 05 | >- // t8 = | 36 | 26 | 16 | 06 | >- // t9 = | 37 | 27 | 17 | 07 | >- >- "precr.qb.ph $s0, $t1, $t0 \n" >- "precr.qb.ph $s1, $t9, $t8 \n" >- "precrq.qb.ph $s2, $t1, $t0 \n" >- "precrq.qb.ph $s3, $t9, $t8 \n" >- >- // s0 = | 25 | 05 | 24 | 04 | >- // s1 = | 27 | 07 | 26 | 06 | >- // s2 = | 35 | 15 | 34 | 14 | >- // s3 = | 37 | 17 | 36 | 16 | >- >- "precr.qb.ph $t0, $s1, $s0 \n" >- "precrq.qb.ph $t1, $s1, $s0 \n" >- "precr.qb.ph $t8, $s3, $s2 \n" >- "precrq.qb.ph $t9, $s3, $s2 \n" >- >- // t0 = | 07 | 06 | 05 | 04 | >- // t1 = | 27 | 26 | 25 | 24 | >- // t8 = | 17 | 16 | 15 | 14 | >- // t9 = | 37 | 36 | 35 | 34 | >- >- "addu $s0, %[dst], %[dst_stride] \n" >- "addu $s1, $s0, %[dst_stride] \n" >- "addu $s2, $s1, %[dst_stride] \n" >- >- "swr $s4, 0(%[dst]) \n" >- "swl $s4, 3(%[dst]) \n" >- "swr $t0, 4(%[dst]) \n" >- "swl $t0, 7(%[dst]) \n" >- "swr $s6, 0($s0) \n" >- "swl $s6, 3($s0) \n" >- "swr $t8, 4($s0) \n" >- "swl $t8, 7($s0) \n" >- "swr $s5, 0($s1) \n" >- "swl $s5, 3($s1) \n" >- "swr $t1, 4($s1) \n" >- "swl $t1, 7($s1) \n" >- "swr $s7, 0($s2) \n" >- "swl $s7, 3($s2) \n" >- "swr $t9, 4($s2) \n" >- "swl $t9, 7($s2) \n" >- >- "addiu $AT, -1 \n" >- "addiu %[src], 4 \n" >- >- "bnez $AT, 11b \n" >- " addu %[dst], $s2, %[dst_stride] \n" >- "2: \n" >- ".set pop \n" >- ".set at \n" >- : [src] "+r"(src), [dst] "+r"(dst), [width] "+r"(width) >- : [src_stride] "r"(src_stride), [dst_stride] "r"(dst_stride) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "s0", "s1", >- "s2", "s3", "s4", "s5", "s6", "s7"); >-} >- >-void TransposeUVWx8_DSPR2(const uint8* src, >- int src_stride, >- uint8* dst_a, >- int dst_stride_a, >- uint8* dst_b, >- int dst_stride_b, >- int width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "beqz %[width], 2f \n" >- " sll $t2, %[src_stride], 0x1 \n" // src_stride x 2 >- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4 >- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8 >- "addu $t3, $t2, %[src_stride] \n" >- "addu $t5, $t4, %[src_stride] \n" >- "addu $t6, $t2, $t4 \n" >- "subu $t7, $t9, %[src_stride] \n" >- "srl $t1, %[width], 1 \n" >- >- // check word aligment for dst_a, dst_b, dst_stride_a and dst_stride_b >- "andi $t0, %[dst_a], 0x3 \n" >- "andi $t8, %[dst_b], 0x3 \n" >- "or $t0, $t0, $t8 \n" >- "andi $t8, %[dst_stride_a], 0x3 \n" >- "andi $s5, %[dst_stride_b], 0x3 \n" >- "or $t8, $t8, $s5 \n" >- "or $t0, $t0, $t8 \n" >- "bnez $t0, 11f \n" >- " nop \n" >- // dst + dst_stride word aligned (both, a & b dst addresses) >- "1: \n" >- "lw $t0, 0(%[src]) \n" // |B0|A0|b0|a0| >- "lwx $t8, %[src_stride](%[src]) \n" // |B1|A1|b1|a1| >- "addu $s5, %[dst_a], %[dst_stride_a] \n" >- "lwx $t9, $t2(%[src]) \n" // |B2|A2|b2|a2| >- "lwx $s0, $t3(%[src]) \n" // |B3|A3|b3|a3| >- "addu $s6, %[dst_b], %[dst_stride_b] \n" >- >- "precrq.ph.w $s1, $t8, $t0 \n" // |B1|A1|B0|A0| >- "precrq.ph.w $s2, $s0, $t9 \n" // |B3|A3|B2|A2| >- "precr.qb.ph $s3, $s2, $s1 \n" // |A3|A2|A1|A0| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |B3|B2|B1|B0| >- >- "sll $t0, $t0, 16 \n" >- "packrl.ph $s1, $t8, $t0 \n" // |b1|a1|b0|a0| >- "sll $t9, $t9, 16 \n" >- "packrl.ph $s2, $s0, $t9 \n" // |b3|a3|b2|a2| >- >- "sw $s3, 0($s5) \n" >- "sw $s4, 0($s6) \n" >- >- "precr.qb.ph $s3, $s2, $s1 \n" // |a3|a2|a1|a0| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |b3|b2|b1|b0| >- >- "lwx $t0, $t4(%[src]) \n" // |B4|A4|b4|a4| >- "lwx $t8, $t5(%[src]) \n" // |B5|A5|b5|a5| >- "lwx $t9, $t6(%[src]) \n" // |B6|A6|b6|a6| >- "lwx $s0, $t7(%[src]) \n" // |B7|A7|b7|a7| >- "sw $s3, 0(%[dst_a]) \n" >- "sw $s4, 0(%[dst_b]) \n" >- >- "precrq.ph.w $s1, $t8, $t0 \n" // |B5|A5|B4|A4| >- "precrq.ph.w $s2, $s0, $t9 \n" // |B6|A6|B7|A7| >- "precr.qb.ph $s3, $s2, $s1 \n" // |A7|A6|A5|A4| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |B7|B6|B5|B4| >- >- "sll $t0, $t0, 16 \n" >- "packrl.ph $s1, $t8, $t0 \n" // |b5|a5|b4|a4| >- "sll $t9, $t9, 16 \n" >- "packrl.ph $s2, $s0, $t9 \n" // |b7|a7|b6|a6| >- "sw $s3, 4($s5) \n" >- "sw $s4, 4($s6) \n" >- >- "precr.qb.ph $s3, $s2, $s1 \n" // |a7|a6|a5|a4| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |b7|b6|b5|b4| >- >- "addiu %[src], 4 \n" >- "addiu $t1, -1 \n" >- "sll $t0, %[dst_stride_a], 1 \n" >- "sll $t8, %[dst_stride_b], 1 \n" >- "sw $s3, 4(%[dst_a]) \n" >- "sw $s4, 4(%[dst_b]) \n" >- "addu %[dst_a], %[dst_a], $t0 \n" >- "bnez $t1, 1b \n" >- " addu %[dst_b], %[dst_b], $t8 \n" >- "b 2f \n" >- " nop \n" >- >- // dst_a or dst_b or dst_stride_a or dst_stride_b not word aligned >- "11: \n" >- "lw $t0, 0(%[src]) \n" // |B0|A0|b0|a0| >- "lwx $t8, %[src_stride](%[src]) \n" // |B1|A1|b1|a1| >- "addu $s5, %[dst_a], %[dst_stride_a] \n" >- "lwx $t9, $t2(%[src]) \n" // |B2|A2|b2|a2| >- "lwx $s0, $t3(%[src]) \n" // |B3|A3|b3|a3| >- "addu $s6, %[dst_b], %[dst_stride_b] \n" >- >- "precrq.ph.w $s1, $t8, $t0 \n" // |B1|A1|B0|A0| >- "precrq.ph.w $s2, $s0, $t9 \n" // |B3|A3|B2|A2| >- "precr.qb.ph $s3, $s2, $s1 \n" // |A3|A2|A1|A0| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |B3|B2|B1|B0| >- >- "sll $t0, $t0, 16 \n" >- "packrl.ph $s1, $t8, $t0 \n" // |b1|a1|b0|a0| >- "sll $t9, $t9, 16 \n" >- "packrl.ph $s2, $s0, $t9 \n" // |b3|a3|b2|a2| >- >- "swr $s3, 0($s5) \n" >- "swl $s3, 3($s5) \n" >- "swr $s4, 0($s6) \n" >- "swl $s4, 3($s6) \n" >- >- "precr.qb.ph $s3, $s2, $s1 \n" // |a3|a2|a1|a0| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |b3|b2|b1|b0| >- >- "lwx $t0, $t4(%[src]) \n" // |B4|A4|b4|a4| >- "lwx $t8, $t5(%[src]) \n" // |B5|A5|b5|a5| >- "lwx $t9, $t6(%[src]) \n" // |B6|A6|b6|a6| >- "lwx $s0, $t7(%[src]) \n" // |B7|A7|b7|a7| >- "swr $s3, 0(%[dst_a]) \n" >- "swl $s3, 3(%[dst_a]) \n" >- "swr $s4, 0(%[dst_b]) \n" >- "swl $s4, 3(%[dst_b]) \n" >- >- "precrq.ph.w $s1, $t8, $t0 \n" // |B5|A5|B4|A4| >- "precrq.ph.w $s2, $s0, $t9 \n" // |B6|A6|B7|A7| >- "precr.qb.ph $s3, $s2, $s1 \n" // |A7|A6|A5|A4| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |B7|B6|B5|B4| >- >- "sll $t0, $t0, 16 \n" >- "packrl.ph $s1, $t8, $t0 \n" // |b5|a5|b4|a4| >- "sll $t9, $t9, 16 \n" >- "packrl.ph $s2, $s0, $t9 \n" // |b7|a7|b6|a6| >- >- "swr $s3, 4($s5) \n" >- "swl $s3, 7($s5) \n" >- "swr $s4, 4($s6) \n" >- "swl $s4, 7($s6) \n" >- >- "precr.qb.ph $s3, $s2, $s1 \n" // |a7|a6|a5|a4| >- "precrq.qb.ph $s4, $s2, $s1 \n" // |b7|b6|b5|b4| >- >- "addiu %[src], 4 \n" >- "addiu $t1, -1 \n" >- "sll $t0, %[dst_stride_a], 1 \n" >- "sll $t8, %[dst_stride_b], 1 \n" >- "swr $s3, 4(%[dst_a]) \n" >- "swl $s3, 7(%[dst_a]) \n" >- "swr $s4, 4(%[dst_b]) \n" >- "swl $s4, 7(%[dst_b]) \n" >- "addu %[dst_a], %[dst_a], $t0 \n" >- "bnez $t1, 11b \n" >- " addu %[dst_b], %[dst_b], $t8 \n" >- >- "2: \n" >- ".set pop \n" >- : [src] "+r"(src), [dst_a] "+r"(dst_a), [dst_b] "+r"(dst_b), >- [width] "+r"(width), [src_stride] "+r"(src_stride) >- : [dst_stride_a] "r"(dst_stride_a), [dst_stride_b] "r"(dst_stride_b) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "s0", "s1", >- "s2", "s3", "s4", "s5", "s6"); >-} >- >-#endif // defined(__mips_dsp) && (__mips_dsp_rev >= 2) >- >-#ifdef __cplusplus >-} // extern "C" >-} // namespace libyuv >-#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc >index 74b48ac4084..04e19e29eef 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc >@@ -22,9 +22,9 @@ extern "C" { > > // Transpose 8x8. 32 or 64 bit, but not NaCL for 64 bit. > #if defined(HAS_TRANSPOSEWX8_SSSE3) >-void TransposeWx8_SSSE3(const uint8* src, >+void TransposeWx8_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > asm volatile( >@@ -112,9 +112,9 @@ void TransposeWx8_SSSE3(const uint8* src, > > // Transpose 16x8. 64 bit > #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3) >-void TransposeWx8_Fast_SSSE3(const uint8* src, >+void TransposeWx8_Fast_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > asm volatile( >@@ -255,11 +255,11 @@ void TransposeWx8_Fast_SSSE3(const uint8* src, > > // Transpose UV 8x8. 64 bit. > #if defined(HAS_TRANSPOSEUVWX8_SSE2) >-void TransposeUVWx8_SSE2(const uint8* src, >+void TransposeUVWx8_SSE2(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { > asm volatile( >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc >index 8907765aba7..99bdca65b32 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc >@@ -51,9 +51,9 @@ extern "C" { > out3 = (v16u8)__msa_ilvl_d((v2i64)in3, (v2i64)in2); \ > } > >-void TransposeWx16_C(const uint8* src, >+void TransposeWx16_C(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > TransposeWx8_C(src, src_stride, dst, dst_stride, width); >@@ -61,11 +61,11 @@ void TransposeWx16_C(const uint8* src, > width); > } > >-void TransposeUVWx16_C(const uint8* src, >+void TransposeUVWx16_C(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { > TransposeUVWx8_C(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, >@@ -74,13 +74,13 @@ void TransposeUVWx16_C(const uint8* src, > dst_stride_a, (dst_b + 8), dst_stride_b, width); > } > >-void TransposeWx16_MSA(const uint8* src, >+void TransposeWx16_MSA(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > int x; >- const uint8* s; >+ const uint8_t* s; > v16u8 src0, src1, src2, src3, dst0, dst1, dst2, dst3, vec0, vec1, vec2, vec3; > v16u8 reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7; > v16u8 res0, res1, res2, res3, res4, res5, res6, res7, res8, res9; >@@ -153,15 +153,15 @@ void TransposeWx16_MSA(const uint8* src, > } > } > >-void TransposeUVWx16_MSA(const uint8* src, >+void TransposeUVWx16_MSA(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { > int x; >- const uint8* s; >+ const uint8_t* s; > v16u8 src0, src1, src2, src3, dst0, dst1, dst2, dst3, vec0, vec1, vec2, vec3; > v16u8 reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7; > v16u8 res0, res1, res2, res3, res4, res5, res6, res7, res8, res9; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc >index d9bbc78cdab..fdc0dd476c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc >@@ -21,15 +21,15 @@ extern "C" { > #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ > !defined(__aarch64__) > >-static uvec8 kVTbl4x4Transpose = {0, 4, 8, 12, 1, 5, 9, 13, >- 2, 6, 10, 14, 3, 7, 11, 15}; >+static const uvec8 kVTbl4x4Transpose = {0, 4, 8, 12, 1, 5, 9, 13, >+ 2, 6, 10, 14, 3, 7, 11, 15}; > >-void TransposeWx8_NEON(const uint8* src, >+void TransposeWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { >- const uint8* src_temp; >+ const uint8_t* src_temp; > asm volatile( > // loops are on blocks of 8. loop will stop when > // counter gets to or below 0. starting the counter >@@ -189,17 +189,17 @@ void TransposeWx8_NEON(const uint8* src, > : "memory", "cc", "q0", "q1", "q2", "q3"); > } > >-static uvec8 kVTbl4x4TransposeDi = {0, 8, 1, 9, 2, 10, 3, 11, >- 4, 12, 5, 13, 6, 14, 7, 15}; >+static const uvec8 kVTbl4x4TransposeDi = {0, 8, 1, 9, 2, 10, 3, 11, >+ 4, 12, 5, 13, 6, 14, 7, 15}; > >-void TransposeUVWx8_NEON(const uint8* src, >+void TransposeUVWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { >- const uint8* src_temp; >+ const uint8_t* src_temp; > asm volatile( > // loops are on blocks of 8. loop will stop when > // counter gets to or below 0. starting the counter >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc >index 59db7f9f3da..f469baacf68 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc >@@ -21,15 +21,15 @@ extern "C" { > // This module is for GCC Neon armv8 64 bit. > #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) > >-static uvec8 kVTbl4x4Transpose = {0, 4, 8, 12, 1, 5, 9, 13, >- 2, 6, 10, 14, 3, 7, 11, 15}; >+static const uvec8 kVTbl4x4Transpose = {0, 4, 8, 12, 1, 5, 9, 13, >+ 2, 6, 10, 14, 3, 7, 11, 15}; > >-void TransposeWx8_NEON(const uint8* src, >+void TransposeWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { >- const uint8* src_temp; >+ const uint8_t* src_temp; > asm volatile( > // loops are on blocks of 8. loop will stop when > // counter gets to or below 0. starting the counter >@@ -196,18 +196,18 @@ void TransposeWx8_NEON(const uint8* src, > "v17", "v18", "v19", "v20", "v21", "v22", "v23"); > } > >-static uint8 kVTbl4x4TransposeDi[32] = { >+static const uint8_t kVTbl4x4TransposeDi[32] = { > 0, 16, 32, 48, 2, 18, 34, 50, 4, 20, 36, 52, 6, 22, 38, 54, > 1, 17, 33, 49, 3, 19, 35, 51, 5, 21, 37, 53, 7, 23, 39, 55}; > >-void TransposeUVWx8_NEON(const uint8* src, >+void TransposeUVWx8_NEON(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int width) { >- const uint8* src_temp; >+ const uint8_t* src_temp; > asm volatile( > // loops are on blocks of 8. loop will stop when > // counter gets to or below 0. starting the counter >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc >index fb052f65212..e887dd525c7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc >@@ -19,9 +19,9 @@ extern "C" { > // This module is for 32 bit Visual C x86 and clangcl > #if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER) > >-__declspec(naked) void TransposeWx8_SSSE3(const uint8* src, >+__declspec(naked) void TransposeWx8_SSSE3(const uint8_t* src, > int src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int width) { > __asm { >@@ -112,11 +112,11 @@ __declspec(naked) void TransposeWx8_SSSE3(const uint8* src, > } > } > >-__declspec(naked) void TransposeUVWx8_SSE2(const uint8* src, >+__declspec(naked) void TransposeUVWx8_SSE2(const uint8_t* src, > int src_stride, >- uint8* dst_a, >+ uint8_t* dst_a, > int dst_stride_a, >- uint8* dst_b, >+ uint8_t* dst_b, > int dst_stride_b, > int w) { > __asm { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_any.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_any.cc >index 8b31ac9fccc..cc5914dd29d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_any.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_any.cc >@@ -31,25 +31,25 @@ extern "C" { > #define SS(width, shift) (((width) + (1 << (shift)) - 1) >> (shift)) > > // Any 4 planes to 1 with yuvconstants >-#define ANY41C(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, BPP, MASK) \ >- void NAMEANY(const uint8* y_buf, const uint8* u_buf, const uint8* v_buf, \ >- const uint8* a_buf, uint8* dst_ptr, \ >- const struct YuvConstants* yuvconstants, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 5]); \ >- memset(temp, 0, 64 * 4); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(y_buf, u_buf, v_buf, a_buf, dst_ptr, yuvconstants, n); \ >- } \ >- memcpy(temp, y_buf + n, r); \ >- memcpy(temp + 64, u_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >- memcpy(temp + 128, v_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >- memcpy(temp + 192, a_buf + n, r); \ >- ANY_SIMD(temp, temp + 64, temp + 128, temp + 192, temp + 256, \ >- yuvconstants, MASK + 1); \ >- memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, temp + 256, \ >- SS(r, DUVSHIFT) * BPP); \ >+#define ANY41C(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, BPP, MASK) \ >+ void NAMEANY(const uint8_t* y_buf, const uint8_t* u_buf, \ >+ const uint8_t* v_buf, const uint8_t* a_buf, uint8_t* dst_ptr, \ >+ const struct YuvConstants* yuvconstants, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 5]); \ >+ memset(temp, 0, 64 * 4); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(y_buf, u_buf, v_buf, a_buf, dst_ptr, yuvconstants, n); \ >+ } \ >+ memcpy(temp, y_buf + n, r); \ >+ memcpy(temp + 64, u_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >+ memcpy(temp + 128, v_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >+ memcpy(temp + 192, a_buf + n, r); \ >+ ANY_SIMD(temp, temp + 64, temp + 128, temp + 192, temp + 256, \ >+ yuvconstants, MASK + 1); \ >+ memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, temp + 256, \ >+ SS(r, DUVSHIFT) * BPP); \ > } > > #ifdef HAS_I422ALPHATOARGBROW_SSSE3 >@@ -67,22 +67,22 @@ ANY41C(I422AlphaToARGBRow_Any_MSA, I422AlphaToARGBRow_MSA, 1, 0, 4, 7) > #undef ANY41C > > // Any 3 planes to 1. >-#define ANY31(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, BPP, MASK) \ >- void NAMEANY(const uint8* y_buf, const uint8* u_buf, const uint8* v_buf, \ >- uint8* dst_ptr, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 4]); \ >- memset(temp, 0, 64 * 3); /* for YUY2 and msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(y_buf, u_buf, v_buf, dst_ptr, n); \ >- } \ >- memcpy(temp, y_buf + n, r); \ >- memcpy(temp + 64, u_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >- memcpy(temp + 128, v_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >- ANY_SIMD(temp, temp + 64, temp + 128, temp + 192, MASK + 1); \ >- memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, temp + 192, \ >- SS(r, DUVSHIFT) * BPP); \ >+#define ANY31(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, BPP, MASK) \ >+ void NAMEANY(const uint8_t* y_buf, const uint8_t* u_buf, \ >+ const uint8_t* v_buf, uint8_t* dst_ptr, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 4]); \ >+ memset(temp, 0, 64 * 3); /* for YUY2 and msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(y_buf, u_buf, v_buf, dst_ptr, n); \ >+ } \ >+ memcpy(temp, y_buf + n, r); \ >+ memcpy(temp + 64, u_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >+ memcpy(temp + 128, v_buf + (n >> UVSHIFT), SS(r, UVSHIFT)); \ >+ ANY_SIMD(temp, temp + 64, temp + 128, temp + 192, MASK + 1); \ >+ memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, temp + 192, \ >+ SS(r, DUVSHIFT) * BPP); \ > } > > // Merge functions. >@@ -96,6 +96,10 @@ ANY31(MergeRGBRow_Any_NEON, MergeRGBRow_NEON, 0, 0, 3, 15) > ANY31(I422ToYUY2Row_Any_SSE2, I422ToYUY2Row_SSE2, 1, 1, 4, 15) > ANY31(I422ToUYVYRow_Any_SSE2, I422ToUYVYRow_SSE2, 1, 1, 4, 15) > #endif >+#ifdef HAS_I422TOYUY2ROW_AVX2 >+ANY31(I422ToYUY2Row_Any_AVX2, I422ToYUY2Row_AVX2, 1, 1, 4, 31) >+ANY31(I422ToUYVYRow_Any_AVX2, I422ToUYVYRow_AVX2, 1, 1, 4, 31) >+#endif > #ifdef HAS_I422TOYUY2ROW_NEON > ANY31(I422ToYUY2Row_Any_NEON, I422ToYUY2Row_NEON, 1, 1, 4, 15) > #endif >@@ -120,10 +124,10 @@ ANY31(BlendPlaneRow_Any_SSSE3, BlendPlaneRow_SSSE3, 0, 0, 1, 7) > // on arm that subsamples 444 to 422 internally. > // Any 3 planes to 1 with yuvconstants > #define ANY31C(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, BPP, MASK) \ >- void NAMEANY(const uint8* y_buf, const uint8* u_buf, const uint8* v_buf, \ >- uint8* dst_ptr, const struct YuvConstants* yuvconstants, \ >- int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 4]); \ >+ void NAMEANY(const uint8_t* y_buf, const uint8_t* u_buf, \ >+ const uint8_t* v_buf, uint8_t* dst_ptr, \ >+ const struct YuvConstants* yuvconstants, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 4]); \ > memset(temp, 0, 64 * 3); /* for YUY2 and msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -145,6 +149,12 @@ ANY31(BlendPlaneRow_Any_SSSE3, BlendPlaneRow_SSSE3, 0, 0, 1, 7) > #ifdef HAS_I422TOARGBROW_SSSE3 > ANY31C(I422ToARGBRow_Any_SSSE3, I422ToARGBRow_SSSE3, 1, 0, 4, 7) > #endif >+#ifdef HAS_I422TOAR30ROW_SSSE3 >+ANY31C(I422ToAR30Row_Any_SSSE3, I422ToAR30Row_SSSE3, 1, 0, 4, 7) >+#endif >+#ifdef HAS_I422TOAR30ROW_AVX2 >+ANY31C(I422ToAR30Row_Any_AVX2, I422ToAR30Row_AVX2, 1, 0, 4, 15) >+#endif > #ifdef HAS_I444TOARGBROW_SSSE3 > ANY31C(I444ToARGBRow_Any_SSSE3, I444ToARGBRow_SSSE3, 0, 0, 4, 7) > ANY31C(I422ToRGBARow_Any_SSSE3, I422ToRGBARow_SSSE3, 1, 0, 4, 7) >@@ -183,12 +193,6 @@ ANY31C(I422ToARGB4444Row_Any_NEON, I422ToARGB4444Row_NEON, 1, 0, 2, 7) > ANY31C(I422ToARGB1555Row_Any_NEON, I422ToARGB1555Row_NEON, 1, 0, 2, 7) > ANY31C(I422ToRGB565Row_Any_NEON, I422ToRGB565Row_NEON, 1, 0, 2, 7) > #endif >-#ifdef HAS_I422TOARGBROW_DSPR2 >-ANY31C(I444ToARGBRow_Any_DSPR2, I444ToARGBRow_DSPR2, 0, 0, 4, 7) >-ANY31C(I422ToARGBRow_Any_DSPR2, I422ToARGBRow_DSPR2, 1, 0, 4, 7) >-ANY31C(I422ToARGB4444Row_Any_DSPR2, I422ToARGB4444Row_DSPR2, 1, 0, 2, 7) >-ANY31C(I422ToARGB1555Row_Any_DSPR2, I422ToARGB1555Row_DSPR2, 1, 0, 2, 7) >-#endif > #ifdef HAS_I422TOARGBROW_MSA > ANY31C(I444ToARGBRow_Any_MSA, I444ToARGBRow_MSA, 0, 0, 4, 7) > ANY31C(I422ToARGBRow_Any_MSA, I422ToARGBRow_MSA, 1, 0, 4, 7) >@@ -200,22 +204,57 @@ ANY31C(I422ToRGB565Row_Any_MSA, I422ToRGB565Row_MSA, 1, 0, 2, 7) > #endif > #undef ANY31C > >+// Any 3 planes of 16 bit to 1 with yuvconstants >+// TODO(fbarchard): consider sharing this code with ANY31C >+#define ANY31CT(NAMEANY, ANY_SIMD, UVSHIFT, DUVSHIFT, T, SBPP, BPP, MASK) \ >+ void NAMEANY(const T* y_buf, const T* u_buf, const T* v_buf, \ >+ uint8_t* dst_ptr, const struct YuvConstants* yuvconstants, \ >+ int width) { \ >+ SIMD_ALIGNED(T temp[16 * 3]); \ >+ SIMD_ALIGNED(uint8_t out[64]); \ >+ memset(temp, 0, 16 * 3 * SBPP); /* for YUY2 and msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(y_buf, u_buf, v_buf, dst_ptr, yuvconstants, n); \ >+ } \ >+ memcpy(temp, y_buf + n, r * SBPP); \ >+ memcpy(temp + 16, u_buf + (n >> UVSHIFT), SS(r, UVSHIFT) * SBPP); \ >+ memcpy(temp + 32, v_buf + (n >> UVSHIFT), SS(r, UVSHIFT) * SBPP); \ >+ ANY_SIMD(temp, temp + 16, temp + 32, out, yuvconstants, MASK + 1); \ >+ memcpy(dst_ptr + (n >> DUVSHIFT) * BPP, out, SS(r, DUVSHIFT) * BPP); \ >+ } >+ >+#ifdef HAS_I210TOAR30ROW_SSSE3 >+ANY31CT(I210ToAR30Row_Any_SSSE3, I210ToAR30Row_SSSE3, 1, 0, uint16_t, 2, 4, 7) >+#endif >+#ifdef HAS_I210TOARGBROW_SSSE3 >+ANY31CT(I210ToARGBRow_Any_SSSE3, I210ToARGBRow_SSSE3, 1, 0, uint16_t, 2, 4, 7) >+#endif >+#ifdef HAS_I210TOARGBROW_AVX2 >+ANY31CT(I210ToARGBRow_Any_AVX2, I210ToARGBRow_AVX2, 1, 0, uint16_t, 2, 4, 15) >+#endif >+#ifdef HAS_I210TOAR30ROW_AVX2 >+ANY31CT(I210ToAR30Row_Any_AVX2, I210ToAR30Row_AVX2, 1, 0, uint16_t, 2, 4, 15) >+#endif >+#undef ANY31CT >+ > // Any 2 planes to 1. >-#define ANY21(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, SBPP2, BPP, MASK) \ >- void NAMEANY(const uint8* y_buf, const uint8* uv_buf, uint8* dst_ptr, \ >- int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 3]); \ >- memset(temp, 0, 64 * 2); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(y_buf, uv_buf, dst_ptr, n); \ >- } \ >- memcpy(temp, y_buf + n * SBPP, r * SBPP); \ >- memcpy(temp + 64, uv_buf + (n >> UVSHIFT) * SBPP2, \ >- SS(r, UVSHIFT) * SBPP2); \ >- ANY_SIMD(temp, temp + 64, temp + 128, MASK + 1); \ >- memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ >+#define ANY21(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, SBPP2, BPP, MASK) \ >+ void NAMEANY(const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* dst_ptr, \ >+ int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 3]); \ >+ memset(temp, 0, 64 * 2); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(y_buf, uv_buf, dst_ptr, n); \ >+ } \ >+ memcpy(temp, y_buf + n * SBPP, r * SBPP); \ >+ memcpy(temp + 64, uv_buf + (n >> UVSHIFT) * SBPP2, \ >+ SS(r, UVSHIFT) * SBPP2); \ >+ ANY_SIMD(temp, temp + 64, temp + 128, MASK + 1); \ >+ memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ > } > > // Merge functions. >@@ -299,21 +338,21 @@ ANY21(SobelXYRow_Any_MSA, SobelXYRow_MSA, 0, 1, 1, 4, 15) > #undef ANY21 > > // Any 2 planes to 1 with yuvconstants >-#define ANY21C(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, SBPP2, BPP, MASK) \ >- void NAMEANY(const uint8* y_buf, const uint8* uv_buf, uint8* dst_ptr, \ >- const struct YuvConstants* yuvconstants, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 3]); \ >- memset(temp, 0, 64 * 2); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(y_buf, uv_buf, dst_ptr, yuvconstants, n); \ >- } \ >- memcpy(temp, y_buf + n * SBPP, r * SBPP); \ >- memcpy(temp + 64, uv_buf + (n >> UVSHIFT) * SBPP2, \ >- SS(r, UVSHIFT) * SBPP2); \ >- ANY_SIMD(temp, temp + 64, temp + 128, yuvconstants, MASK + 1); \ >- memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ >+#define ANY21C(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, SBPP2, BPP, MASK) \ >+ void NAMEANY(const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* dst_ptr, \ >+ const struct YuvConstants* yuvconstants, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 3]); \ >+ memset(temp, 0, 64 * 2); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(y_buf, uv_buf, dst_ptr, yuvconstants, n); \ >+ } \ >+ memcpy(temp, y_buf + n * SBPP, r * SBPP); \ >+ memcpy(temp + 64, uv_buf + (n >> UVSHIFT) * SBPP2, \ >+ SS(r, UVSHIFT) * SBPP2); \ >+ ANY_SIMD(temp, temp + 64, temp + 128, yuvconstants, MASK + 1); \ >+ memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ > } > > // Biplanar to RGB. >@@ -326,9 +365,6 @@ ANY21C(NV12ToARGBRow_Any_AVX2, NV12ToARGBRow_AVX2, 1, 1, 2, 4, 15) > #ifdef HAS_NV12TOARGBROW_NEON > ANY21C(NV12ToARGBRow_Any_NEON, NV12ToARGBRow_NEON, 1, 1, 2, 4, 7) > #endif >-#ifdef HAS_NV12TOARGBROW_DSPR2 >-ANY21C(NV12ToARGBRow_Any_DSPR2, NV12ToARGBRow_DSPR2, 1, 1, 2, 4, 7) >-#endif > #ifdef HAS_NV12TOARGBROW_MSA > ANY21C(NV12ToARGBRow_Any_MSA, NV12ToARGBRow_MSA, 1, 1, 2, 4, 7) > #endif >@@ -344,6 +380,12 @@ ANY21C(NV21ToARGBRow_Any_NEON, NV21ToARGBRow_NEON, 1, 1, 2, 4, 7) > #ifdef HAS_NV21TOARGBROW_MSA > ANY21C(NV21ToARGBRow_Any_MSA, NV21ToARGBRow_MSA, 1, 1, 2, 4, 7) > #endif >+#ifdef HAS_NV12TORGB24ROW_NEON >+ANY21C(NV12ToRGB24Row_Any_NEON, NV12ToRGB24Row_NEON, 1, 1, 2, 3, 7) >+#endif >+#ifdef HAS_NV21TORGB24ROW_NEON >+ANY21C(NV21ToRGB24Row_Any_NEON, NV21ToRGB24Row_NEON, 1, 1, 2, 3, 7) >+#endif > #ifdef HAS_NV12TORGB565ROW_SSSE3 > ANY21C(NV12ToRGB565Row_Any_SSSE3, NV12ToRGB565Row_SSSE3, 1, 1, 2, 2, 7) > #endif >@@ -360,8 +402,8 @@ ANY21C(NV12ToRGB565Row_Any_MSA, NV12ToRGB565Row_MSA, 1, 1, 2, 2, 7) > > // Any 1 to 1. > #define ANY11(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_ptr, int width) { \ >- SIMD_ALIGNED(uint8 temp[128 * 2]); \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_ptr, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[128 * 2]); \ > memset(temp, 0, 128); /* for YUY2 and msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -396,6 +438,18 @@ ANY11(ARGBToRGB565Row_Any_AVX2, ARGBToRGB565Row_AVX2, 0, 4, 2, 7) > ANY11(ARGBToARGB1555Row_Any_AVX2, ARGBToARGB1555Row_AVX2, 0, 4, 2, 7) > ANY11(ARGBToARGB4444Row_Any_AVX2, ARGBToARGB4444Row_AVX2, 0, 4, 2, 7) > #endif >+#if defined(HAS_ABGRTOAR30ROW_SSSE3) >+ANY11(ABGRToAR30Row_Any_SSSE3, ABGRToAR30Row_SSSE3, 0, 4, 4, 3) >+#endif >+#if defined(HAS_ARGBTOAR30ROW_SSSE3) >+ANY11(ARGBToAR30Row_Any_SSSE3, ARGBToAR30Row_SSSE3, 0, 4, 4, 3) >+#endif >+#if defined(HAS_ABGRTOAR30ROW_AVX2) >+ANY11(ABGRToAR30Row_Any_AVX2, ABGRToAR30Row_AVX2, 0, 4, 4, 7) >+#endif >+#if defined(HAS_ARGBTOAR30ROW_AVX2) >+ANY11(ARGBToAR30Row_Any_AVX2, ARGBToAR30Row_AVX2, 0, 4, 4, 7) >+#endif > #if defined(HAS_J400TOARGBROW_SSE2) > ANY11(J400ToARGBRow_Any_SSE2, J400ToARGBRow_SSE2, 0, 1, 4, 7) > #endif >@@ -572,33 +626,6 @@ ANY11(ARGB1555ToARGBRow_Any_MSA, ARGB1555ToARGBRow_MSA, 0, 2, 4, 15) > #ifdef HAS_ARGB4444TOARGBROW_NEON > ANY11(ARGB4444ToARGBRow_Any_NEON, ARGB4444ToARGBRow_NEON, 0, 2, 4, 7) > #endif >-#ifdef HAS_RGB24TOARGBROW_DSPR2 >-ANY11(RGB24ToARGBRow_Any_DSPR2, RGB24ToARGBRow_DSPR2, 0, 3, 4, 7) >-#endif >-#ifdef HAS_RAWTOARGBROW_DSPR2 >-ANY11(RAWToARGBRow_Any_DSPR2, RAWToARGBRow_DSPR2, 0, 3, 4, 7) >-#endif >-#ifdef HAS_RGB565TOARGBROW_DSPR2 >-ANY11(RGB565ToARGBRow_Any_DSPR2, RGB565ToARGBRow_DSPR2, 0, 2, 4, 7) >-#endif >-#ifdef HAS_ARGB1555TOARGBROW_DSPR2 >-ANY11(ARGB1555ToARGBRow_Any_DSPR2, ARGB1555ToARGBRow_DSPR2, 0, 2, 4, 7) >-#endif >-#ifdef HAS_ARGB4444TOARGBROW_DSPR2 >-ANY11(ARGB4444ToARGBRow_Any_DSPR2, ARGB4444ToARGBRow_DSPR2, 0, 2, 4, 7) >-#endif >-#ifdef HAS_BGRATOYROW_DSPR2 >-ANY11(BGRAToYRow_Any_DSPR2, BGRAToYRow_DSPR2, 0, 4, 1, 7) >-#endif >-#ifdef HAS_ARGBTOYROW_DSPR2 >-ANY11(ARGBToYRow_Any_DSPR2, ARGBToYRow_DSPR2, 0, 4, 1, 7) >-#endif >-#ifdef HAS_ABGRTOYROW_DSPR2 >-ANY11(ABGRToYRow_Any_DSPR2, ABGRToYRow_DSPR2, 0, 4, 1, 7) >-#endif >-#ifdef HAS_RGBATOYROW_DSPR2 >-ANY11(RGBAToYRow_Any_DSPR2, RGBAToYRow_DSPR2, 0, 4, 1, 7) >-#endif > #ifdef HAS_ARGB4444TOARGBROW_MSA > ANY11(ARGB4444ToARGBRow_Any_MSA, ARGB4444ToARGBRow_MSA, 0, 2, 4, 15) > #endif >@@ -636,8 +663,8 @@ ANY11(ARGBExtractAlphaRow_Any_MSA, ARGBExtractAlphaRow_MSA, 0, 4, 1, 15) > > // Any 1 to 1 blended. Destination is read, modify, write. > #define ANY11B(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_ptr, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 2]); \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_ptr, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 2]); \ > memset(temp, 0, 64 * 2); /* for msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -665,24 +692,24 @@ ANY11B(ARGBCopyYToAlphaRow_Any_SSE2, ARGBCopyYToAlphaRow_SSE2, 0, 1, 4, 7) > #undef ANY11B > > // Any 1 to 1 with parameter. >-#define ANY11P(NAMEANY, ANY_SIMD, T, SBPP, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_ptr, T param, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 2]); \ >- memset(temp, 0, 64); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(src_ptr, dst_ptr, param, n); \ >- } \ >- memcpy(temp, src_ptr + n * SBPP, r * SBPP); \ >- ANY_SIMD(temp, temp + 64, param, MASK + 1); \ >- memcpy(dst_ptr + n * BPP, temp + 64, r * BPP); \ >+#define ANY11P(NAMEANY, ANY_SIMD, T, SBPP, BPP, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_ptr, T param, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 2]); \ >+ memset(temp, 0, 64); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(src_ptr, dst_ptr, param, n); \ >+ } \ >+ memcpy(temp, src_ptr + n * SBPP, r * SBPP); \ >+ ANY_SIMD(temp, temp + 64, param, MASK + 1); \ >+ memcpy(dst_ptr + n * BPP, temp + 64, r * BPP); \ > } > > #if defined(HAS_ARGBTORGB565DITHERROW_SSE2) > ANY11P(ARGBToRGB565DitherRow_Any_SSE2, > ARGBToRGB565DitherRow_SSE2, >- const uint32, >+ const uint32_t, > 4, > 2, > 3) >@@ -690,7 +717,7 @@ ANY11P(ARGBToRGB565DitherRow_Any_SSE2, > #if defined(HAS_ARGBTORGB565DITHERROW_AVX2) > ANY11P(ARGBToRGB565DitherRow_Any_AVX2, > ARGBToRGB565DitherRow_AVX2, >- const uint32, >+ const uint32_t, > 4, > 2, > 7) >@@ -698,7 +725,7 @@ ANY11P(ARGBToRGB565DitherRow_Any_AVX2, > #if defined(HAS_ARGBTORGB565DITHERROW_NEON) > ANY11P(ARGBToRGB565DitherRow_Any_NEON, > ARGBToRGB565DitherRow_NEON, >- const uint32, >+ const uint32_t, > 4, > 2, > 7) >@@ -706,67 +733,134 @@ ANY11P(ARGBToRGB565DitherRow_Any_NEON, > #if defined(HAS_ARGBTORGB565DITHERROW_MSA) > ANY11P(ARGBToRGB565DitherRow_Any_MSA, > ARGBToRGB565DitherRow_MSA, >- const uint32, >+ const uint32_t, > 4, > 2, > 7) > #endif >-#ifdef HAS_ARGBSHUFFLEROW_SSE2 >-ANY11P(ARGBShuffleRow_Any_SSE2, ARGBShuffleRow_SSE2, const uint8*, 4, 4, 3) >-#endif > #ifdef HAS_ARGBSHUFFLEROW_SSSE3 >-ANY11P(ARGBShuffleRow_Any_SSSE3, ARGBShuffleRow_SSSE3, const uint8*, 4, 4, 7) >+ANY11P(ARGBShuffleRow_Any_SSSE3, ARGBShuffleRow_SSSE3, const uint8_t*, 4, 4, 7) > #endif > #ifdef HAS_ARGBSHUFFLEROW_AVX2 >-ANY11P(ARGBShuffleRow_Any_AVX2, ARGBShuffleRow_AVX2, const uint8*, 4, 4, 15) >+ANY11P(ARGBShuffleRow_Any_AVX2, ARGBShuffleRow_AVX2, const uint8_t*, 4, 4, 15) > #endif > #ifdef HAS_ARGBSHUFFLEROW_NEON >-ANY11P(ARGBShuffleRow_Any_NEON, ARGBShuffleRow_NEON, const uint8*, 4, 4, 3) >+ANY11P(ARGBShuffleRow_Any_NEON, ARGBShuffleRow_NEON, const uint8_t*, 4, 4, 3) > #endif > #ifdef HAS_ARGBSHUFFLEROW_MSA >-ANY11P(ARGBShuffleRow_Any_MSA, ARGBShuffleRow_MSA, const uint8*, 4, 4, 7) >+ANY11P(ARGBShuffleRow_Any_MSA, ARGBShuffleRow_MSA, const uint8_t*, 4, 4, 7) > #endif > #undef ANY11P > > // Any 1 to 1 with parameter and shorts. BPP measures in shorts. >-#define ANY11P16(NAMEANY, ANY_SIMD, T, SBPP, BPP, MASK) \ >- void NAMEANY(const uint16* src_ptr, uint16* dst_ptr, T param, int width) { \ >- SIMD_ALIGNED(uint16 temp[16 * 2]); \ >- memset(temp, 0, 32); /* for msan */ \ >+#define ANY11C(NAMEANY, ANY_SIMD, SBPP, BPP, STYPE, DTYPE, MASK) \ >+ void NAMEANY(const STYPE* src_ptr, DTYPE* dst_ptr, int scale, int width) { \ >+ SIMD_ALIGNED(STYPE temp[32]); \ >+ SIMD_ALIGNED(DTYPE out[32]); \ >+ memset(temp, 0, 32 * SBPP); /* for msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ > if (n > 0) { \ >- ANY_SIMD(src_ptr, dst_ptr, param, n); \ >+ ANY_SIMD(src_ptr, dst_ptr, scale, n); \ > } \ > memcpy(temp, src_ptr + n, r * SBPP); \ >- ANY_SIMD(temp, temp + 16, param, MASK + 1); \ >- memcpy(dst_ptr + n, temp + 16, r * BPP); \ >+ ANY_SIMD(temp, out, scale, MASK + 1); \ >+ memcpy(dst_ptr + n, out, r * BPP); \ >+ } >+ >+#ifdef HAS_CONVERT16TO8ROW_SSSE3 >+ANY11C(Convert16To8Row_Any_SSSE3, >+ Convert16To8Row_SSSE3, >+ 2, >+ 1, >+ uint16_t, >+ uint8_t, >+ 15) >+#endif >+#ifdef HAS_CONVERT16TO8ROW_AVX2 >+ANY11C(Convert16To8Row_Any_AVX2, >+ Convert16To8Row_AVX2, >+ 2, >+ 1, >+ uint16_t, >+ uint8_t, >+ 31) >+#endif >+#ifdef HAS_CONVERT8TO16ROW_SSE2 >+ANY11C(Convert8To16Row_Any_SSE2, >+ Convert8To16Row_SSE2, >+ 1, >+ 2, >+ uint8_t, >+ uint16_t, >+ 15) >+#endif >+#ifdef HAS_CONVERT8TO16ROW_AVX2 >+ANY11C(Convert8To16Row_Any_AVX2, >+ Convert8To16Row_AVX2, >+ 1, >+ 2, >+ uint8_t, >+ uint16_t, >+ 31) >+#endif >+#undef ANY11C >+ >+// Any 1 to 1 with parameter and shorts to byte. BPP measures in shorts. >+#define ANY11P16(NAMEANY, ANY_SIMD, ST, T, SBPP, BPP, MASK) \ >+ void NAMEANY(const ST* src_ptr, T* dst_ptr, float param, int width) { \ >+ SIMD_ALIGNED(ST temp[32]); \ >+ SIMD_ALIGNED(T out[32]); \ >+ memset(temp, 0, SBPP * 32); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(src_ptr, dst_ptr, param, n); \ >+ } \ >+ memcpy(temp, src_ptr + n, r * SBPP); \ >+ ANY_SIMD(temp, out, param, MASK + 1); \ >+ memcpy(dst_ptr + n, out, r * BPP); \ > } > > #ifdef HAS_HALFFLOATROW_SSE2 >-ANY11P16(HalfFloatRow_Any_SSE2, HalfFloatRow_SSE2, float, 2, 2, 7) >+ANY11P16(HalfFloatRow_Any_SSE2, HalfFloatRow_SSE2, uint16_t, uint16_t, 2, 2, 7) > #endif > #ifdef HAS_HALFFLOATROW_AVX2 >-ANY11P16(HalfFloatRow_Any_AVX2, HalfFloatRow_AVX2, float, 2, 2, 15) >+ANY11P16(HalfFloatRow_Any_AVX2, HalfFloatRow_AVX2, uint16_t, uint16_t, 2, 2, 15) > #endif > #ifdef HAS_HALFFLOATROW_F16C >-ANY11P16(HalfFloatRow_Any_F16C, HalfFloatRow_F16C, float, 2, 2, 15) >-ANY11P16(HalfFloat1Row_Any_F16C, HalfFloat1Row_F16C, float, 2, 2, 15) >+ANY11P16(HalfFloatRow_Any_F16C, HalfFloatRow_F16C, uint16_t, uint16_t, 2, 2, 15) >+ANY11P16(HalfFloat1Row_Any_F16C, >+ HalfFloat1Row_F16C, >+ uint16_t, >+ uint16_t, >+ 2, >+ 2, >+ 15) > #endif > #ifdef HAS_HALFFLOATROW_NEON >-ANY11P16(HalfFloatRow_Any_NEON, HalfFloatRow_NEON, float, 2, 2, 7) >-ANY11P16(HalfFloat1Row_Any_NEON, HalfFloat1Row_NEON, float, 2, 2, 7) >+ANY11P16(HalfFloatRow_Any_NEON, HalfFloatRow_NEON, uint16_t, uint16_t, 2, 2, 7) >+ANY11P16(HalfFloat1Row_Any_NEON, >+ HalfFloat1Row_NEON, >+ uint16_t, >+ uint16_t, >+ 2, >+ 2, >+ 7) > #endif > #ifdef HAS_HALFFLOATROW_MSA >-ANY11P16(HalfFloatRow_Any_MSA, HalfFloatRow_MSA, float, 2, 2, 31) >+ANY11P16(HalfFloatRow_Any_MSA, HalfFloatRow_MSA, uint16_t, uint16_t, 2, 2, 31) >+#endif >+#ifdef HAS_BYTETOFLOATROW_NEON >+ANY11P16(ByteToFloatRow_Any_NEON, ByteToFloatRow_NEON, uint8_t, float, 1, 3, 7) > #endif > #undef ANY11P16 > > // Any 1 to 1 with yuvconstants > #define ANY11C(NAMEANY, ANY_SIMD, UVSHIFT, SBPP, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_ptr, \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_ptr, \ > const struct YuvConstants* yuvconstants, int width) { \ >- SIMD_ALIGNED(uint8 temp[128 * 2]); \ >+ SIMD_ALIGNED(uint8_t temp[128 * 2]); \ > memset(temp, 0, 128); /* for YUY2 and msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -796,20 +890,20 @@ ANY11C(UYVYToARGBRow_Any_MSA, UYVYToARGBRow_MSA, 1, 4, 4, 7) > #undef ANY11C > > // Any 1 to 1 interpolate. Takes 2 rows of source via stride. >-#define ANY11T(NAMEANY, ANY_SIMD, SBPP, BPP, MASK) \ >- void NAMEANY(uint8* dst_ptr, const uint8* src_ptr, ptrdiff_t src_stride_ptr, \ >- int width, int source_y_fraction) { \ >- SIMD_ALIGNED(uint8 temp[64 * 3]); \ >- memset(temp, 0, 64 * 2); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(dst_ptr, src_ptr, src_stride_ptr, n, source_y_fraction); \ >- } \ >- memcpy(temp, src_ptr + n * SBPP, r * SBPP); \ >- memcpy(temp + 64, src_ptr + src_stride_ptr + n * SBPP, r * SBPP); \ >- ANY_SIMD(temp + 128, temp, 64, MASK + 1, source_y_fraction); \ >- memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ >+#define ANY11T(NAMEANY, ANY_SIMD, SBPP, BPP, MASK) \ >+ void NAMEANY(uint8_t* dst_ptr, const uint8_t* src_ptr, \ >+ ptrdiff_t src_stride_ptr, int width, int source_y_fraction) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 3]); \ >+ memset(temp, 0, 64 * 2); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(dst_ptr, src_ptr, src_stride_ptr, n, source_y_fraction); \ >+ } \ >+ memcpy(temp, src_ptr + n * SBPP, r * SBPP); \ >+ memcpy(temp + 64, src_ptr + src_stride_ptr + n * SBPP, r * SBPP); \ >+ ANY_SIMD(temp + 128, temp, 64, MASK + 1, source_y_fraction); \ >+ memcpy(dst_ptr + n * BPP, temp + 128, r * BPP); \ > } > > #ifdef HAS_INTERPOLATEROW_AVX2 >@@ -821,9 +915,6 @@ ANY11T(InterpolateRow_Any_SSSE3, InterpolateRow_SSSE3, 1, 1, 15) > #ifdef HAS_INTERPOLATEROW_NEON > ANY11T(InterpolateRow_Any_NEON, InterpolateRow_NEON, 1, 1, 15) > #endif >-#ifdef HAS_INTERPOLATEROW_DSPR2 >-ANY11T(InterpolateRow_Any_DSPR2, InterpolateRow_DSPR2, 1, 1, 3) >-#endif > #ifdef HAS_INTERPOLATEROW_MSA > ANY11T(InterpolateRow_Any_MSA, InterpolateRow_MSA, 1, 1, 31) > #endif >@@ -831,8 +922,8 @@ ANY11T(InterpolateRow_Any_MSA, InterpolateRow_MSA, 1, 1, 31) > > // Any 1 to 1 mirror. > #define ANY11M(NAMEANY, ANY_SIMD, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_ptr, int width) { \ >- SIMD_ALIGNED(uint8 temp[64 * 2]); \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_ptr, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64 * 2]); \ > memset(temp, 0, 64); /* for msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -871,46 +962,47 @@ ANY11M(ARGBMirrorRow_Any_MSA, ARGBMirrorRow_MSA, 4, 15) > #undef ANY11M > > // Any 1 plane. (memset) >-#define ANY1(NAMEANY, ANY_SIMD, T, BPP, MASK) \ >- void NAMEANY(uint8* dst_ptr, T v32, int width) { \ >- SIMD_ALIGNED(uint8 temp[64]); \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(dst_ptr, v32, n); \ >- } \ >- ANY_SIMD(temp, v32, MASK + 1); \ >- memcpy(dst_ptr + n * BPP, temp, r * BPP); \ >+#define ANY1(NAMEANY, ANY_SIMD, T, BPP, MASK) \ >+ void NAMEANY(uint8_t* dst_ptr, T v32, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[64]); \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(dst_ptr, v32, n); \ >+ } \ >+ ANY_SIMD(temp, v32, MASK + 1); \ >+ memcpy(dst_ptr + n * BPP, temp, r * BPP); \ > } > > #ifdef HAS_SETROW_X86 >-ANY1(SetRow_Any_X86, SetRow_X86, uint8, 1, 3) >+ANY1(SetRow_Any_X86, SetRow_X86, uint8_t, 1, 3) > #endif > #ifdef HAS_SETROW_NEON >-ANY1(SetRow_Any_NEON, SetRow_NEON, uint8, 1, 15) >+ANY1(SetRow_Any_NEON, SetRow_NEON, uint8_t, 1, 15) > #endif > #ifdef HAS_ARGBSETROW_NEON >-ANY1(ARGBSetRow_Any_NEON, ARGBSetRow_NEON, uint32, 4, 3) >+ANY1(ARGBSetRow_Any_NEON, ARGBSetRow_NEON, uint32_t, 4, 3) > #endif > #ifdef HAS_ARGBSETROW_MSA >-ANY1(ARGBSetRow_Any_MSA, ARGBSetRow_MSA, uint32, 4, 3) >+ANY1(ARGBSetRow_Any_MSA, ARGBSetRow_MSA, uint32_t, 4, 3) > #endif > #undef ANY1 > > // Any 1 to 2. Outputs UV planes. >-#define ANY12(NAMEANY, ANY_SIMD, UVSHIFT, BPP, DUVSHIFT, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_u, uint8* dst_v, int width) { \ >- SIMD_ALIGNED(uint8 temp[128 * 3]); \ >- memset(temp, 0, 128); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(src_ptr, dst_u, dst_v, n); \ >- } \ >- memcpy(temp, src_ptr + (n >> UVSHIFT) * BPP, SS(r, UVSHIFT) * BPP); \ >- ANY_SIMD(temp, temp + 128, temp + 256, MASK + 1); \ >- memcpy(dst_u + (n >> DUVSHIFT), temp + 128, SS(r, DUVSHIFT)); \ >- memcpy(dst_v + (n >> DUVSHIFT), temp + 256, SS(r, DUVSHIFT)); \ >+#define ANY12(NAMEANY, ANY_SIMD, UVSHIFT, BPP, DUVSHIFT, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_u, uint8_t* dst_v, \ >+ int width) { \ >+ SIMD_ALIGNED(uint8_t temp[128 * 3]); \ >+ memset(temp, 0, 128); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(src_ptr, dst_u, dst_v, n); \ >+ } \ >+ memcpy(temp, src_ptr + (n >> UVSHIFT) * BPP, SS(r, UVSHIFT) * BPP); \ >+ ANY_SIMD(temp, temp + 128, temp + 256, MASK + 1); \ >+ memcpy(dst_u + (n >> DUVSHIFT), temp + 128, SS(r, DUVSHIFT)); \ >+ memcpy(dst_v + (n >> DUVSHIFT), temp + 256, SS(r, DUVSHIFT)); \ > } > > #ifdef HAS_SPLITUVROW_SSE2 >@@ -922,9 +1014,6 @@ ANY12(SplitUVRow_Any_AVX2, SplitUVRow_AVX2, 0, 2, 0, 31) > #ifdef HAS_SPLITUVROW_NEON > ANY12(SplitUVRow_Any_NEON, SplitUVRow_NEON, 0, 2, 0, 15) > #endif >-#ifdef HAS_SPLITUVROW_DSPR2 >-ANY12(SplitUVRow_Any_DSPR2, SplitUVRow_DSPR2, 0, 2, 0, 15) >-#endif > #ifdef HAS_SPLITUVROW_MSA > ANY12(SplitUVRow_Any_MSA, SplitUVRow_MSA, 0, 2, 0, 31) > #endif >@@ -952,21 +1041,21 @@ ANY12(UYVYToUV422Row_Any_MSA, UYVYToUV422Row_MSA, 1, 4, 1, 31) > #undef ANY12 > > // Any 1 to 3. Outputs RGB planes. >-#define ANY13(NAMEANY, ANY_SIMD, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint8* dst_r, uint8* dst_g, uint8* dst_b, \ >- int width) { \ >- SIMD_ALIGNED(uint8 temp[16 * 6]); \ >- memset(temp, 0, 16 * 3); /* for msan */ \ >- int r = width & MASK; \ >- int n = width & ~MASK; \ >- if (n > 0) { \ >- ANY_SIMD(src_ptr, dst_r, dst_g, dst_b, n); \ >- } \ >- memcpy(temp, src_ptr + n * BPP, r * BPP); \ >- ANY_SIMD(temp, temp + 16 * 3, temp + 16 * 4, temp + 16 * 5, MASK + 1); \ >- memcpy(dst_r + n, temp + 16 * 3, r); \ >- memcpy(dst_g + n, temp + 16 * 4, r); \ >- memcpy(dst_b + n, temp + 16 * 5, r); \ >+#define ANY13(NAMEANY, ANY_SIMD, BPP, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, uint8_t* dst_r, uint8_t* dst_g, \ >+ uint8_t* dst_b, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[16 * 6]); \ >+ memset(temp, 0, 16 * 3); /* for msan */ \ >+ int r = width & MASK; \ >+ int n = width & ~MASK; \ >+ if (n > 0) { \ >+ ANY_SIMD(src_ptr, dst_r, dst_g, dst_b, n); \ >+ } \ >+ memcpy(temp, src_ptr + n * BPP, r * BPP); \ >+ ANY_SIMD(temp, temp + 16 * 3, temp + 16 * 4, temp + 16 * 5, MASK + 1); \ >+ memcpy(dst_r + n, temp + 16 * 3, r); \ >+ memcpy(dst_g + n, temp + 16 * 4, r); \ >+ memcpy(dst_b + n, temp + 16 * 5, r); \ > } > > #ifdef HAS_SPLITRGBROW_SSSE3 >@@ -979,9 +1068,9 @@ ANY13(SplitRGBRow_Any_NEON, SplitRGBRow_NEON, 3, 15) > // Any 1 to 2 with source stride (2 rows of source). Outputs UV planes. > // 128 byte row allows for 32 avx ARGB pixels. > #define ANY12S(NAMEANY, ANY_SIMD, UVSHIFT, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, int src_stride_ptr, uint8* dst_u, \ >- uint8* dst_v, int width) { \ >- SIMD_ALIGNED(uint8 temp[128 * 4]); \ >+ void NAMEANY(const uint8_t* src_ptr, int src_stride_ptr, uint8_t* dst_u, \ >+ uint8_t* dst_v, int width) { \ >+ SIMD_ALIGNED(uint8_t temp[128 * 4]); \ > memset(temp, 0, 128 * 2); /* for msan */ \ > int r = width & MASK; \ > int n = width & ~MASK; \ >@@ -1086,18 +1175,6 @@ ANY12S(YUY2ToUVRow_Any_NEON, YUY2ToUVRow_NEON, 1, 4, 15) > #ifdef HAS_UYVYTOUVROW_NEON > ANY12S(UYVYToUVRow_Any_NEON, UYVYToUVRow_NEON, 1, 4, 15) > #endif >-#ifdef HAS_BGRATOUVROW_DSPR2 >-ANY12S(BGRAToUVRow_Any_DSPR2, BGRAToUVRow_DSPR2, 0, 4, 15) >-#endif >-#ifdef HAS_ABGRTOUVROW_DSPR2 >-ANY12S(ABGRToUVRow_Any_DSPR2, ABGRToUVRow_DSPR2, 0, 4, 15) >-#endif >-#ifdef HAS_RGBATOUVROW_DSPR2 >-ANY12S(RGBAToUVRow_Any_DSPR2, RGBAToUVRow_DSPR2, 0, 4, 15) >-#endif >-#ifdef HAS_ARGBTOUVROW_DSPR2 >-ANY12S(ARGBToUVRow_Any_DSPR2, ARGBToUVRow_DSPR2, 0, 4, 15) >-#endif > #ifdef HAS_YUY2TOUVROW_MSA > ANY12S(YUY2ToUVRow_Any_MSA, YUY2ToUVRow_MSA, 1, 4, 31) > #endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_common.cc >index 6ffc4febbf6..da97821f796 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_common.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_common.cc >@@ -10,6 +10,7 @@ > > #include "libyuv/row.h" > >+#include <stdio.h> > #include <string.h> // For memcpy and memset. > > #include "libyuv/basic_types.h" >@@ -23,59 +24,69 @@ extern "C" { > > #define USE_BRANCHLESS 1 > #if USE_BRANCHLESS >-static __inline int32 clamp0(int32 v) { >+static __inline int32_t clamp0(int32_t v) { > return ((-(v) >> 31) & (v)); > } > >-static __inline int32 clamp255(int32 v) { >+static __inline int32_t clamp255(int32_t v) { > return (((255 - (v)) >> 31) | (v)) & 255; > } > >-static __inline uint32 Clamp(int32 val) { >- int v = clamp0(val); >- return (uint32)(clamp255(v)); >+static __inline int32_t clamp1023(int32_t v) { >+ return (((1023 - (v)) >> 31) | (v)) & 1023; > } > >-static __inline uint32 Abs(int32 v) { >+static __inline uint32_t Abs(int32_t v) { > int m = v >> 31; > return (v + m) ^ m; > } > #else // USE_BRANCHLESS >-static __inline int32 clamp0(int32 v) { >+static __inline int32_t clamp0(int32_t v) { > return (v < 0) ? 0 : v; > } > >-static __inline int32 clamp255(int32 v) { >+static __inline int32_t clamp255(int32_t v) { > return (v > 255) ? 255 : v; > } > >-static __inline uint32 Clamp(int32 val) { >- int v = clamp0(val); >- return (uint32)(clamp255(v)); >+static __inline int32_t clamp1023(int32_t v) { >+ return (v > 1023) ? 1023 : v; > } > >-static __inline uint32 Abs(int32 v) { >+static __inline uint32_t Abs(int32_t v) { > return (v < 0) ? -v : v; > } > #endif // USE_BRANCHLESS >+static __inline uint32_t Clamp(int32_t val) { >+ int v = clamp0(val); >+ return (uint32_t)(clamp255(v)); >+} >+ >+static __inline uint32_t Clamp10(int32_t val) { >+ int v = clamp0(val); >+ return (uint32_t)(clamp1023(v)); >+} > >-#ifdef LIBYUV_LITTLE_ENDIAN >-#define WRITEWORD(p, v) *(uint32*)(p) = v >+// Little Endian >+#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ >+ defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) || \ >+ (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) >+#define WRITEWORD(p, v) *(uint32_t*)(p) = v > #else >-static inline void WRITEWORD(uint8* p, uint32 v) { >- p[0] = (uint8)(v & 255); >- p[1] = (uint8)((v >> 8) & 255); >- p[2] = (uint8)((v >> 16) & 255); >- p[3] = (uint8)((v >> 24) & 255); >+static inline void WRITEWORD(uint8_t* p, uint32_t v) { >+ p[0] = (uint8_t)(v & 255); >+ p[1] = (uint8_t)((v >> 8) & 255); >+ p[2] = (uint8_t)((v >> 16) & 255); >+ p[3] = (uint8_t)((v >> 24) & 255); > } > #endif > >-void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int width) { >+void RGB24ToARGBRow_C(const uint8_t* src_rgb24, uint8_t* dst_argb, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_rgb24[0]; >- uint8 g = src_rgb24[1]; >- uint8 r = src_rgb24[2]; >+ uint8_t b = src_rgb24[0]; >+ uint8_t g = src_rgb24[1]; >+ uint8_t r = src_rgb24[2]; > dst_argb[0] = b; > dst_argb[1] = g; > dst_argb[2] = r; >@@ -85,12 +96,12 @@ void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int width) { > } > } > >-void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int width) { >+void RAWToARGBRow_C(const uint8_t* src_raw, uint8_t* dst_argb, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 r = src_raw[0]; >- uint8 g = src_raw[1]; >- uint8 b = src_raw[2]; >+ uint8_t r = src_raw[0]; >+ uint8_t g = src_raw[1]; >+ uint8_t b = src_raw[2]; > dst_argb[0] = b; > dst_argb[1] = g; > dst_argb[2] = r; >@@ -100,12 +111,12 @@ void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int width) { > } > } > >-void RAWToRGB24Row_C(const uint8* src_raw, uint8* dst_rgb24, int width) { >+void RAWToRGB24Row_C(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 r = src_raw[0]; >- uint8 g = src_raw[1]; >- uint8 b = src_raw[2]; >+ uint8_t r = src_raw[0]; >+ uint8_t g = src_raw[1]; >+ uint8_t b = src_raw[2]; > dst_rgb24[0] = b; > dst_rgb24[1] = g; > dst_rgb24[2] = r; >@@ -114,12 +125,14 @@ void RAWToRGB24Row_C(const uint8* src_raw, uint8* dst_rgb24, int width) { > } > } > >-void RGB565ToARGBRow_C(const uint8* src_rgb565, uint8* dst_argb, int width) { >+void RGB565ToARGBRow_C(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_rgb565[0] & 0x1f; >- uint8 g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >- uint8 r = src_rgb565[1] >> 3; >+ uint8_t b = src_rgb565[0] & 0x1f; >+ uint8_t g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >+ uint8_t r = src_rgb565[1] >> 3; > dst_argb[0] = (b << 3) | (b >> 2); > dst_argb[1] = (g << 2) | (g >> 4); > dst_argb[2] = (r << 3) | (r >> 2); >@@ -129,15 +142,15 @@ void RGB565ToARGBRow_C(const uint8* src_rgb565, uint8* dst_argb, int width) { > } > } > >-void ARGB1555ToARGBRow_C(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_C(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb1555[0] & 0x1f; >- uint8 g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >- uint8 r = (src_argb1555[1] & 0x7c) >> 2; >- uint8 a = src_argb1555[1] >> 7; >+ uint8_t b = src_argb1555[0] & 0x1f; >+ uint8_t g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >+ uint8_t r = (src_argb1555[1] & 0x7c) >> 2; >+ uint8_t a = src_argb1555[1] >> 7; > dst_argb[0] = (b << 3) | (b >> 2); > dst_argb[1] = (g << 3) | (g >> 2); > dst_argb[2] = (r << 3) | (r >> 2); >@@ -147,15 +160,15 @@ void ARGB1555ToARGBRow_C(const uint8* src_argb1555, > } > } > >-void ARGB4444ToARGBRow_C(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_C(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb4444[0] & 0x0f; >- uint8 g = src_argb4444[0] >> 4; >- uint8 r = src_argb4444[1] & 0x0f; >- uint8 a = src_argb4444[1] >> 4; >+ uint8_t b = src_argb4444[0] & 0x0f; >+ uint8_t g = src_argb4444[0] >> 4; >+ uint8_t r = src_argb4444[1] & 0x0f; >+ uint8_t a = src_argb4444[1] >> 4; > dst_argb[0] = (b << 4) | b; > dst_argb[1] = (g << 4) | g; > dst_argb[2] = (r << 4) | r; >@@ -165,12 +178,53 @@ void ARGB4444ToARGBRow_C(const uint8* src_argb4444, > } > } > >-void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { >+void AR30ToARGBRow_C(const uint8_t* src_ar30, uint8_t* dst_argb, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb[0]; >- uint8 g = src_argb[1]; >- uint8 r = src_argb[2]; >+ uint32_t ar30 = *(uint32_t*)src_ar30; >+ uint32_t b = (ar30 >> 2) & 0xff; >+ uint32_t g = (ar30 >> 12) & 0xff; >+ uint32_t r = (ar30 >> 22) & 0xff; >+ uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. >+ *(uint32_t*)(dst_argb) = b | (g << 8) | (r << 16) | (a << 24); >+ dst_argb += 4; >+ src_ar30 += 4; >+ } >+} >+ >+void AR30ToABGRRow_C(const uint8_t* src_ar30, uint8_t* dst_abgr, int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ uint32_t ar30 = *(uint32_t*)src_ar30; >+ uint32_t b = (ar30 >> 2) & 0xff; >+ uint32_t g = (ar30 >> 12) & 0xff; >+ uint32_t r = (ar30 >> 22) & 0xff; >+ uint32_t a = (ar30 >> 30) * 0x55; // Replicate 2 bits to 8 bits. >+ *(uint32_t*)(dst_abgr) = r | (g << 8) | (b << 16) | (a << 24); >+ dst_abgr += 4; >+ src_ar30 += 4; >+ } >+} >+ >+void AR30ToAB30Row_C(const uint8_t* src_ar30, uint8_t* dst_ab30, int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ uint32_t ar30 = *(uint32_t*)src_ar30; >+ uint32_t b = ar30 & 0x3ff; >+ uint32_t ga = ar30 & 0xc00ffc00; >+ uint32_t r = (ar30 >> 20) & 0x3ff; >+ *(uint32_t*)(dst_ab30) = r | ga | (b << 20); >+ dst_ab30 += 4; >+ src_ar30 += 4; >+ } >+} >+ >+void ARGBToRGB24Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ uint8_t b = src_argb[0]; >+ uint8_t g = src_argb[1]; >+ uint8_t r = src_argb[2]; > dst_rgb[0] = b; > dst_rgb[1] = g; > dst_rgb[2] = r; >@@ -179,12 +233,12 @@ void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToRAWRow_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb[0]; >- uint8 g = src_argb[1]; >- uint8 r = src_argb[2]; >+ uint8_t b = src_argb[0]; >+ uint8_t g = src_argb[1]; >+ uint8_t r = src_argb[2]; > dst_rgb[0] = r; > dst_rgb[1] = g; > dst_rgb[2] = b; >@@ -193,25 +247,25 @@ void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToRGB565Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_argb[0] >> 3; >- uint8 g0 = src_argb[1] >> 2; >- uint8 r0 = src_argb[2] >> 3; >- uint8 b1 = src_argb[4] >> 3; >- uint8 g1 = src_argb[5] >> 2; >- uint8 r1 = src_argb[6] >> 3; >+ uint8_t b0 = src_argb[0] >> 3; >+ uint8_t g0 = src_argb[1] >> 2; >+ uint8_t r0 = src_argb[2] >> 3; >+ uint8_t b1 = src_argb[4] >> 3; >+ uint8_t g1 = src_argb[5] >> 2; >+ uint8_t r1 = src_argb[6] >> 3; > WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | > (r1 << 27)); > dst_rgb += 4; > src_argb += 8; > } > if (width & 1) { >- uint8 b0 = src_argb[0] >> 3; >- uint8 g0 = src_argb[1] >> 2; >- uint8 r0 = src_argb[2] >> 3; >- *(uint16*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); >+ uint8_t b0 = src_argb[0] >> 3; >+ uint8_t g0 = src_argb[1] >> 2; >+ uint8_t r0 = src_argb[2] >> 3; >+ *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); > } > } > >@@ -223,20 +277,20 @@ void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { > // endian will not affect order of the original matrix. But the dither4 > // will containing the first pixel in the lower byte for little endian > // or the upper byte for big endian. >-void ARGBToRGB565DitherRow_C(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_C(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { > int dither0 = ((const unsigned char*)(&dither4))[x & 3]; > int dither1 = ((const unsigned char*)(&dither4))[(x + 1) & 3]; >- uint8 b0 = clamp255(src_argb[0] + dither0) >> 3; >- uint8 g0 = clamp255(src_argb[1] + dither0) >> 2; >- uint8 r0 = clamp255(src_argb[2] + dither0) >> 3; >- uint8 b1 = clamp255(src_argb[4] + dither1) >> 3; >- uint8 g1 = clamp255(src_argb[5] + dither1) >> 2; >- uint8 r1 = clamp255(src_argb[6] + dither1) >> 3; >+ uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; >+ uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; >+ uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; >+ uint8_t b1 = clamp255(src_argb[4] + dither1) >> 3; >+ uint8_t g1 = clamp255(src_argb[5] + dither1) >> 2; >+ uint8_t r1 = clamp255(src_argb[6] + dither1) >> 3; > WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | > (r1 << 27)); > dst_rgb += 4; >@@ -244,112 +298,138 @@ void ARGBToRGB565DitherRow_C(const uint8* src_argb, > } > if (width & 1) { > int dither0 = ((const unsigned char*)(&dither4))[(width - 1) & 3]; >- uint8 b0 = clamp255(src_argb[0] + dither0) >> 3; >- uint8 g0 = clamp255(src_argb[1] + dither0) >> 2; >- uint8 r0 = clamp255(src_argb[2] + dither0) >> 3; >- *(uint16*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); >+ uint8_t b0 = clamp255(src_argb[0] + dither0) >> 3; >+ uint8_t g0 = clamp255(src_argb[1] + dither0) >> 2; >+ uint8_t r0 = clamp255(src_argb[2] + dither0) >> 3; >+ *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11); > } > } > >-void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToARGB1555Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_argb[0] >> 3; >- uint8 g0 = src_argb[1] >> 3; >- uint8 r0 = src_argb[2] >> 3; >- uint8 a0 = src_argb[3] >> 7; >- uint8 b1 = src_argb[4] >> 3; >- uint8 g1 = src_argb[5] >> 3; >- uint8 r1 = src_argb[6] >> 3; >- uint8 a1 = src_argb[7] >> 7; >- *(uint32*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15) | >- (b1 << 16) | (g1 << 21) | (r1 << 26) | (a1 << 31); >+ uint8_t b0 = src_argb[0] >> 3; >+ uint8_t g0 = src_argb[1] >> 3; >+ uint8_t r0 = src_argb[2] >> 3; >+ uint8_t a0 = src_argb[3] >> 7; >+ uint8_t b1 = src_argb[4] >> 3; >+ uint8_t g1 = src_argb[5] >> 3; >+ uint8_t r1 = src_argb[6] >> 3; >+ uint8_t a1 = src_argb[7] >> 7; >+ *(uint32_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15) | >+ (b1 << 16) | (g1 << 21) | (r1 << 26) | (a1 << 31); > dst_rgb += 4; > src_argb += 8; > } > if (width & 1) { >- uint8 b0 = src_argb[0] >> 3; >- uint8 g0 = src_argb[1] >> 3; >- uint8 r0 = src_argb[2] >> 3; >- uint8 a0 = src_argb[3] >> 7; >- *(uint16*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15); >+ uint8_t b0 = src_argb[0] >> 3; >+ uint8_t g0 = src_argb[1] >> 3; >+ uint8_t r0 = src_argb[2] >> 3; >+ uint8_t a0 = src_argb[3] >> 7; >+ *(uint16_t*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 10) | (a0 << 15); > } > } > >-void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToARGB4444Row_C(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_argb[0] >> 4; >- uint8 g0 = src_argb[1] >> 4; >- uint8 r0 = src_argb[2] >> 4; >- uint8 a0 = src_argb[3] >> 4; >- uint8 b1 = src_argb[4] >> 4; >- uint8 g1 = src_argb[5] >> 4; >- uint8 r1 = src_argb[6] >> 4; >- uint8 a1 = src_argb[7] >> 4; >- *(uint32*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12) | (b1 << 16) | >- (g1 << 20) | (r1 << 24) | (a1 << 28); >+ uint8_t b0 = src_argb[0] >> 4; >+ uint8_t g0 = src_argb[1] >> 4; >+ uint8_t r0 = src_argb[2] >> 4; >+ uint8_t a0 = src_argb[3] >> 4; >+ uint8_t b1 = src_argb[4] >> 4; >+ uint8_t g1 = src_argb[5] >> 4; >+ uint8_t r1 = src_argb[6] >> 4; >+ uint8_t a1 = src_argb[7] >> 4; >+ *(uint32_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12) | >+ (b1 << 16) | (g1 << 20) | (r1 << 24) | (a1 << 28); > dst_rgb += 4; > src_argb += 8; > } > if (width & 1) { >- uint8 b0 = src_argb[0] >> 4; >- uint8 g0 = src_argb[1] >> 4; >- uint8 r0 = src_argb[2] >> 4; >- uint8 a0 = src_argb[3] >> 4; >- *(uint16*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12); >+ uint8_t b0 = src_argb[0] >> 4; >+ uint8_t g0 = src_argb[1] >> 4; >+ uint8_t r0 = src_argb[2] >> 4; >+ uint8_t a0 = src_argb[3] >> 4; >+ *(uint16_t*)(dst_rgb) = b0 | (g0 << 4) | (r0 << 8) | (a0 << 12); >+ } >+} >+ >+void ABGRToAR30Row_C(const uint8_t* src_abgr, uint8_t* dst_ar30, int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ uint32_t b0 = (src_abgr[0] >> 6) | ((uint32_t)(src_abgr[0]) << 2); >+ uint32_t g0 = (src_abgr[1] >> 6) | ((uint32_t)(src_abgr[1]) << 2); >+ uint32_t r0 = (src_abgr[2] >> 6) | ((uint32_t)(src_abgr[2]) << 2); >+ uint32_t a0 = (src_abgr[3] >> 6); >+ *(uint32_t*)(dst_ar30) = r0 | (g0 << 10) | (b0 << 20) | (a0 << 30); >+ dst_ar30 += 4; >+ src_abgr += 4; > } > } > >-static __inline int RGBToY(uint8 r, uint8 g, uint8 b) { >+void ARGBToAR30Row_C(const uint8_t* src_argb, uint8_t* dst_ar30, int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ uint32_t b0 = (src_argb[0] >> 6) | ((uint32_t)(src_argb[0]) << 2); >+ uint32_t g0 = (src_argb[1] >> 6) | ((uint32_t)(src_argb[1]) << 2); >+ uint32_t r0 = (src_argb[2] >> 6) | ((uint32_t)(src_argb[2]) << 2); >+ uint32_t a0 = (src_argb[3] >> 6); >+ *(uint32_t*)(dst_ar30) = b0 | (g0 << 10) | (r0 << 20) | (a0 << 30); >+ dst_ar30 += 4; >+ src_argb += 4; >+ } >+} >+ >+static __inline int RGBToY(uint8_t r, uint8_t g, uint8_t b) { > return (66 * r + 129 * g + 25 * b + 0x1080) >> 8; > } > >-static __inline int RGBToU(uint8 r, uint8 g, uint8 b) { >+static __inline int RGBToU(uint8_t r, uint8_t g, uint8_t b) { > return (112 * b - 74 * g - 38 * r + 0x8080) >> 8; > } >-static __inline int RGBToV(uint8 r, uint8 g, uint8 b) { >+static __inline int RGBToV(uint8_t r, uint8_t g, uint8_t b) { > return (112 * r - 94 * g - 18 * b + 0x8080) >> 8; > } > > // ARGBToY_C and ARGBToUV_C >-#define MAKEROWY(NAME, R, G, B, BPP) \ >- void NAME##ToYRow_C(const uint8* src_argb0, uint8* dst_y, int width) { \ >- int x; \ >- for (x = 0; x < width; ++x) { \ >- dst_y[0] = RGBToY(src_argb0[R], src_argb0[G], src_argb0[B]); \ >- src_argb0 += BPP; \ >- dst_y += 1; \ >- } \ >- } \ >- void NAME##ToUVRow_C(const uint8* src_rgb0, int src_stride_rgb, \ >- uint8* dst_u, uint8* dst_v, int width) { \ >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; \ >- int x; \ >- for (x = 0; x < width - 1; x += 2) { \ >- uint8 ab = (src_rgb0[B] + src_rgb0[B + BPP] + src_rgb1[B] + \ >- src_rgb1[B + BPP]) >> \ >- 2; \ >- uint8 ag = (src_rgb0[G] + src_rgb0[G + BPP] + src_rgb1[G] + \ >- src_rgb1[G + BPP]) >> \ >- 2; \ >- uint8 ar = (src_rgb0[R] + src_rgb0[R + BPP] + src_rgb1[R] + \ >- src_rgb1[R + BPP]) >> \ >- 2; \ >- dst_u[0] = RGBToU(ar, ag, ab); \ >- dst_v[0] = RGBToV(ar, ag, ab); \ >- src_rgb0 += BPP * 2; \ >- src_rgb1 += BPP * 2; \ >- dst_u += 1; \ >- dst_v += 1; \ >- } \ >- if (width & 1) { \ >- uint8 ab = (src_rgb0[B] + src_rgb1[B]) >> 1; \ >- uint8 ag = (src_rgb0[G] + src_rgb1[G]) >> 1; \ >- uint8 ar = (src_rgb0[R] + src_rgb1[R]) >> 1; \ >- dst_u[0] = RGBToU(ar, ag, ab); \ >- dst_v[0] = RGBToV(ar, ag, ab); \ >- } \ >+#define MAKEROWY(NAME, R, G, B, BPP) \ >+ void NAME##ToYRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ >+ int x; \ >+ for (x = 0; x < width; ++x) { \ >+ dst_y[0] = RGBToY(src_argb0[R], src_argb0[G], src_argb0[B]); \ >+ src_argb0 += BPP; \ >+ dst_y += 1; \ >+ } \ >+ } \ >+ void NAME##ToUVRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ >+ uint8_t* dst_u, uint8_t* dst_v, int width) { \ >+ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ >+ int x; \ >+ for (x = 0; x < width - 1; x += 2) { \ >+ uint8_t ab = (src_rgb0[B] + src_rgb0[B + BPP] + src_rgb1[B] + \ >+ src_rgb1[B + BPP]) >> \ >+ 2; \ >+ uint8_t ag = (src_rgb0[G] + src_rgb0[G + BPP] + src_rgb1[G] + \ >+ src_rgb1[G + BPP]) >> \ >+ 2; \ >+ uint8_t ar = (src_rgb0[R] + src_rgb0[R + BPP] + src_rgb1[R] + \ >+ src_rgb1[R + BPP]) >> \ >+ 2; \ >+ dst_u[0] = RGBToU(ar, ag, ab); \ >+ dst_v[0] = RGBToV(ar, ag, ab); \ >+ src_rgb0 += BPP * 2; \ >+ src_rgb1 += BPP * 2; \ >+ dst_u += 1; \ >+ dst_v += 1; \ >+ } \ >+ if (width & 1) { \ >+ uint8_t ab = (src_rgb0[B] + src_rgb1[B]) >> 1; \ >+ uint8_t ag = (src_rgb0[G] + src_rgb1[G]) >> 1; \ >+ uint8_t ar = (src_rgb0[R] + src_rgb1[R]) >> 1; \ >+ dst_u[0] = RGBToU(ar, ag, ab); \ >+ dst_v[0] = RGBToV(ar, ag, ab); \ >+ } \ > } > > MAKEROWY(ARGB, 2, 1, 0, 4) >@@ -385,65 +465,65 @@ MAKEROWY(RAW, 0, 1, 2, 3) > // g -0.41869 * 255 = -106.76595 = -107 > // r 0.50000 * 255 = 127.5 = 127 > >-static __inline int RGBToYJ(uint8 r, uint8 g, uint8 b) { >+static __inline int RGBToYJ(uint8_t r, uint8_t g, uint8_t b) { > return (38 * r + 75 * g + 15 * b + 64) >> 7; > } > >-static __inline int RGBToUJ(uint8 r, uint8 g, uint8 b) { >+static __inline int RGBToUJ(uint8_t r, uint8_t g, uint8_t b) { > return (127 * b - 84 * g - 43 * r + 0x8080) >> 8; > } >-static __inline int RGBToVJ(uint8 r, uint8 g, uint8 b) { >+static __inline int RGBToVJ(uint8_t r, uint8_t g, uint8_t b) { > return (127 * r - 107 * g - 20 * b + 0x8080) >> 8; > } > > #define AVGB(a, b) (((a) + (b) + 1) >> 1) > > // ARGBToYJ_C and ARGBToUVJ_C >-#define MAKEROWYJ(NAME, R, G, B, BPP) \ >- void NAME##ToYJRow_C(const uint8* src_argb0, uint8* dst_y, int width) { \ >- int x; \ >- for (x = 0; x < width; ++x) { \ >- dst_y[0] = RGBToYJ(src_argb0[R], src_argb0[G], src_argb0[B]); \ >- src_argb0 += BPP; \ >- dst_y += 1; \ >- } \ >- } \ >- void NAME##ToUVJRow_C(const uint8* src_rgb0, int src_stride_rgb, \ >- uint8* dst_u, uint8* dst_v, int width) { \ >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; \ >- int x; \ >- for (x = 0; x < width - 1; x += 2) { \ >- uint8 ab = AVGB(AVGB(src_rgb0[B], src_rgb1[B]), \ >- AVGB(src_rgb0[B + BPP], src_rgb1[B + BPP])); \ >- uint8 ag = AVGB(AVGB(src_rgb0[G], src_rgb1[G]), \ >- AVGB(src_rgb0[G + BPP], src_rgb1[G + BPP])); \ >- uint8 ar = AVGB(AVGB(src_rgb0[R], src_rgb1[R]), \ >- AVGB(src_rgb0[R + BPP], src_rgb1[R + BPP])); \ >- dst_u[0] = RGBToUJ(ar, ag, ab); \ >- dst_v[0] = RGBToVJ(ar, ag, ab); \ >- src_rgb0 += BPP * 2; \ >- src_rgb1 += BPP * 2; \ >- dst_u += 1; \ >- dst_v += 1; \ >- } \ >- if (width & 1) { \ >- uint8 ab = AVGB(src_rgb0[B], src_rgb1[B]); \ >- uint8 ag = AVGB(src_rgb0[G], src_rgb1[G]); \ >- uint8 ar = AVGB(src_rgb0[R], src_rgb1[R]); \ >- dst_u[0] = RGBToUJ(ar, ag, ab); \ >- dst_v[0] = RGBToVJ(ar, ag, ab); \ >- } \ >+#define MAKEROWYJ(NAME, R, G, B, BPP) \ >+ void NAME##ToYJRow_C(const uint8_t* src_argb0, uint8_t* dst_y, int width) { \ >+ int x; \ >+ for (x = 0; x < width; ++x) { \ >+ dst_y[0] = RGBToYJ(src_argb0[R], src_argb0[G], src_argb0[B]); \ >+ src_argb0 += BPP; \ >+ dst_y += 1; \ >+ } \ >+ } \ >+ void NAME##ToUVJRow_C(const uint8_t* src_rgb0, int src_stride_rgb, \ >+ uint8_t* dst_u, uint8_t* dst_v, int width) { \ >+ const uint8_t* src_rgb1 = src_rgb0 + src_stride_rgb; \ >+ int x; \ >+ for (x = 0; x < width - 1; x += 2) { \ >+ uint8_t ab = AVGB(AVGB(src_rgb0[B], src_rgb1[B]), \ >+ AVGB(src_rgb0[B + BPP], src_rgb1[B + BPP])); \ >+ uint8_t ag = AVGB(AVGB(src_rgb0[G], src_rgb1[G]), \ >+ AVGB(src_rgb0[G + BPP], src_rgb1[G + BPP])); \ >+ uint8_t ar = AVGB(AVGB(src_rgb0[R], src_rgb1[R]), \ >+ AVGB(src_rgb0[R + BPP], src_rgb1[R + BPP])); \ >+ dst_u[0] = RGBToUJ(ar, ag, ab); \ >+ dst_v[0] = RGBToVJ(ar, ag, ab); \ >+ src_rgb0 += BPP * 2; \ >+ src_rgb1 += BPP * 2; \ >+ dst_u += 1; \ >+ dst_v += 1; \ >+ } \ >+ if (width & 1) { \ >+ uint8_t ab = AVGB(src_rgb0[B], src_rgb1[B]); \ >+ uint8_t ag = AVGB(src_rgb0[G], src_rgb1[G]); \ >+ uint8_t ar = AVGB(src_rgb0[R], src_rgb1[R]); \ >+ dst_u[0] = RGBToUJ(ar, ag, ab); \ >+ dst_v[0] = RGBToVJ(ar, ag, ab); \ >+ } \ > } > > MAKEROWYJ(ARGB, 2, 1, 0, 4) > #undef MAKEROWYJ > >-void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int width) { >+void RGB565ToYRow_C(const uint8_t* src_rgb565, uint8_t* dst_y, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_rgb565[0] & 0x1f; >- uint8 g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >- uint8 r = src_rgb565[1] >> 3; >+ uint8_t b = src_rgb565[0] & 0x1f; >+ uint8_t g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >+ uint8_t r = src_rgb565[1] >> 3; > b = (b << 3) | (b >> 2); > g = (g << 2) | (g >> 4); > r = (r << 3) | (r >> 2); >@@ -453,12 +533,12 @@ void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int width) { > } > } > >-void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int width) { >+void ARGB1555ToYRow_C(const uint8_t* src_argb1555, uint8_t* dst_y, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb1555[0] & 0x1f; >- uint8 g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >- uint8 r = (src_argb1555[1] & 0x7c) >> 2; >+ uint8_t b = src_argb1555[0] & 0x1f; >+ uint8_t g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >+ uint8_t r = (src_argb1555[1] & 0x7c) >> 2; > b = (b << 3) | (b >> 2); > g = (g << 3) | (g >> 2); > r = (r << 3) | (r >> 2); >@@ -468,12 +548,12 @@ void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int width) { > } > } > >-void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int width) { >+void ARGB4444ToYRow_C(const uint8_t* src_argb4444, uint8_t* dst_y, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 b = src_argb4444[0] & 0x0f; >- uint8 g = src_argb4444[0] >> 4; >- uint8 r = src_argb4444[1] & 0x0f; >+ uint8_t b = src_argb4444[0] & 0x0f; >+ uint8_t g = src_argb4444[0] >> 4; >+ uint8_t r = src_argb4444[1] & 0x0f; > b = (b << 4) | b; > g = (g << 4) | g; > r = (r << 4) | r; >@@ -483,29 +563,29 @@ void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int width) { > } > } > >-void RGB565ToUVRow_C(const uint8* src_rgb565, >+void RGB565ToUVRow_C(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* next_rgb565 = src_rgb565 + src_stride_rgb565; >+ const uint8_t* next_rgb565 = src_rgb565 + src_stride_rgb565; > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_rgb565[0] & 0x1f; >- uint8 g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >- uint8 r0 = src_rgb565[1] >> 3; >- uint8 b1 = src_rgb565[2] & 0x1f; >- uint8 g1 = (src_rgb565[2] >> 5) | ((src_rgb565[3] & 0x07) << 3); >- uint8 r1 = src_rgb565[3] >> 3; >- uint8 b2 = next_rgb565[0] & 0x1f; >- uint8 g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3); >- uint8 r2 = next_rgb565[1] >> 3; >- uint8 b3 = next_rgb565[2] & 0x1f; >- uint8 g3 = (next_rgb565[2] >> 5) | ((next_rgb565[3] & 0x07) << 3); >- uint8 r3 = next_rgb565[3] >> 3; >- uint8 b = (b0 + b1 + b2 + b3); // 565 * 4 = 787. >- uint8 g = (g0 + g1 + g2 + g3); >- uint8 r = (r0 + r1 + r2 + r3); >+ uint8_t b0 = src_rgb565[0] & 0x1f; >+ uint8_t g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >+ uint8_t r0 = src_rgb565[1] >> 3; >+ uint8_t b1 = src_rgb565[2] & 0x1f; >+ uint8_t g1 = (src_rgb565[2] >> 5) | ((src_rgb565[3] & 0x07) << 3); >+ uint8_t r1 = src_rgb565[3] >> 3; >+ uint8_t b2 = next_rgb565[0] & 0x1f; >+ uint8_t g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3); >+ uint8_t r2 = next_rgb565[1] >> 3; >+ uint8_t b3 = next_rgb565[2] & 0x1f; >+ uint8_t g3 = (next_rgb565[2] >> 5) | ((next_rgb565[3] & 0x07) << 3); >+ uint8_t r3 = next_rgb565[3] >> 3; >+ uint8_t b = (b0 + b1 + b2 + b3); // 565 * 4 = 787. >+ uint8_t g = (g0 + g1 + g2 + g3); >+ uint8_t r = (r0 + r1 + r2 + r3); > b = (b << 1) | (b >> 6); // 787 -> 888. > r = (r << 1) | (r >> 6); > dst_u[0] = RGBToU(r, g, b); >@@ -516,15 +596,15 @@ void RGB565ToUVRow_C(const uint8* src_rgb565, > dst_v += 1; > } > if (width & 1) { >- uint8 b0 = src_rgb565[0] & 0x1f; >- uint8 g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >- uint8 r0 = src_rgb565[1] >> 3; >- uint8 b2 = next_rgb565[0] & 0x1f; >- uint8 g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3); >- uint8 r2 = next_rgb565[1] >> 3; >- uint8 b = (b0 + b2); // 565 * 2 = 676. >- uint8 g = (g0 + g2); >- uint8 r = (r0 + r2); >+ uint8_t b0 = src_rgb565[0] & 0x1f; >+ uint8_t g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3); >+ uint8_t r0 = src_rgb565[1] >> 3; >+ uint8_t b2 = next_rgb565[0] & 0x1f; >+ uint8_t g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3); >+ uint8_t r2 = next_rgb565[1] >> 3; >+ uint8_t b = (b0 + b2); // 565 * 2 = 676. >+ uint8_t g = (g0 + g2); >+ uint8_t r = (r0 + r2); > b = (b << 2) | (b >> 4); // 676 -> 888 > g = (g << 1) | (g >> 6); > r = (r << 2) | (r >> 4); >@@ -533,29 +613,29 @@ void RGB565ToUVRow_C(const uint8* src_rgb565, > } > } > >-void ARGB1555ToUVRow_C(const uint8* src_argb1555, >+void ARGB1555ToUVRow_C(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* next_argb1555 = src_argb1555 + src_stride_argb1555; >+ const uint8_t* next_argb1555 = src_argb1555 + src_stride_argb1555; > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_argb1555[0] & 0x1f; >- uint8 g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >- uint8 r0 = (src_argb1555[1] & 0x7c) >> 2; >- uint8 b1 = src_argb1555[2] & 0x1f; >- uint8 g1 = (src_argb1555[2] >> 5) | ((src_argb1555[3] & 0x03) << 3); >- uint8 r1 = (src_argb1555[3] & 0x7c) >> 2; >- uint8 b2 = next_argb1555[0] & 0x1f; >- uint8 g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3); >- uint8 r2 = (next_argb1555[1] & 0x7c) >> 2; >- uint8 b3 = next_argb1555[2] & 0x1f; >- uint8 g3 = (next_argb1555[2] >> 5) | ((next_argb1555[3] & 0x03) << 3); >- uint8 r3 = (next_argb1555[3] & 0x7c) >> 2; >- uint8 b = (b0 + b1 + b2 + b3); // 555 * 4 = 777. >- uint8 g = (g0 + g1 + g2 + g3); >- uint8 r = (r0 + r1 + r2 + r3); >+ uint8_t b0 = src_argb1555[0] & 0x1f; >+ uint8_t g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >+ uint8_t r0 = (src_argb1555[1] & 0x7c) >> 2; >+ uint8_t b1 = src_argb1555[2] & 0x1f; >+ uint8_t g1 = (src_argb1555[2] >> 5) | ((src_argb1555[3] & 0x03) << 3); >+ uint8_t r1 = (src_argb1555[3] & 0x7c) >> 2; >+ uint8_t b2 = next_argb1555[0] & 0x1f; >+ uint8_t g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3); >+ uint8_t r2 = (next_argb1555[1] & 0x7c) >> 2; >+ uint8_t b3 = next_argb1555[2] & 0x1f; >+ uint8_t g3 = (next_argb1555[2] >> 5) | ((next_argb1555[3] & 0x03) << 3); >+ uint8_t r3 = (next_argb1555[3] & 0x7c) >> 2; >+ uint8_t b = (b0 + b1 + b2 + b3); // 555 * 4 = 777. >+ uint8_t g = (g0 + g1 + g2 + g3); >+ uint8_t r = (r0 + r1 + r2 + r3); > b = (b << 1) | (b >> 6); // 777 -> 888. > g = (g << 1) | (g >> 6); > r = (r << 1) | (r >> 6); >@@ -567,15 +647,15 @@ void ARGB1555ToUVRow_C(const uint8* src_argb1555, > dst_v += 1; > } > if (width & 1) { >- uint8 b0 = src_argb1555[0] & 0x1f; >- uint8 g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >- uint8 r0 = (src_argb1555[1] & 0x7c) >> 2; >- uint8 b2 = next_argb1555[0] & 0x1f; >- uint8 g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3); >- uint8 r2 = next_argb1555[1] >> 3; >- uint8 b = (b0 + b2); // 555 * 2 = 666. >- uint8 g = (g0 + g2); >- uint8 r = (r0 + r2); >+ uint8_t b0 = src_argb1555[0] & 0x1f; >+ uint8_t g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3); >+ uint8_t r0 = (src_argb1555[1] & 0x7c) >> 2; >+ uint8_t b2 = next_argb1555[0] & 0x1f; >+ uint8_t g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3); >+ uint8_t r2 = next_argb1555[1] >> 3; >+ uint8_t b = (b0 + b2); // 555 * 2 = 666. >+ uint8_t g = (g0 + g2); >+ uint8_t r = (r0 + r2); > b = (b << 2) | (b >> 4); // 666 -> 888. > g = (g << 2) | (g >> 4); > r = (r << 2) | (r >> 4); >@@ -584,29 +664,29 @@ void ARGB1555ToUVRow_C(const uint8* src_argb1555, > } > } > >-void ARGB4444ToUVRow_C(const uint8* src_argb4444, >+void ARGB4444ToUVRow_C(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* next_argb4444 = src_argb4444 + src_stride_argb4444; >+ const uint8_t* next_argb4444 = src_argb4444 + src_stride_argb4444; > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 b0 = src_argb4444[0] & 0x0f; >- uint8 g0 = src_argb4444[0] >> 4; >- uint8 r0 = src_argb4444[1] & 0x0f; >- uint8 b1 = src_argb4444[2] & 0x0f; >- uint8 g1 = src_argb4444[2] >> 4; >- uint8 r1 = src_argb4444[3] & 0x0f; >- uint8 b2 = next_argb4444[0] & 0x0f; >- uint8 g2 = next_argb4444[0] >> 4; >- uint8 r2 = next_argb4444[1] & 0x0f; >- uint8 b3 = next_argb4444[2] & 0x0f; >- uint8 g3 = next_argb4444[2] >> 4; >- uint8 r3 = next_argb4444[3] & 0x0f; >- uint8 b = (b0 + b1 + b2 + b3); // 444 * 4 = 666. >- uint8 g = (g0 + g1 + g2 + g3); >- uint8 r = (r0 + r1 + r2 + r3); >+ uint8_t b0 = src_argb4444[0] & 0x0f; >+ uint8_t g0 = src_argb4444[0] >> 4; >+ uint8_t r0 = src_argb4444[1] & 0x0f; >+ uint8_t b1 = src_argb4444[2] & 0x0f; >+ uint8_t g1 = src_argb4444[2] >> 4; >+ uint8_t r1 = src_argb4444[3] & 0x0f; >+ uint8_t b2 = next_argb4444[0] & 0x0f; >+ uint8_t g2 = next_argb4444[0] >> 4; >+ uint8_t r2 = next_argb4444[1] & 0x0f; >+ uint8_t b3 = next_argb4444[2] & 0x0f; >+ uint8_t g3 = next_argb4444[2] >> 4; >+ uint8_t r3 = next_argb4444[3] & 0x0f; >+ uint8_t b = (b0 + b1 + b2 + b3); // 444 * 4 = 666. >+ uint8_t g = (g0 + g1 + g2 + g3); >+ uint8_t r = (r0 + r1 + r2 + r3); > b = (b << 2) | (b >> 4); // 666 -> 888. > g = (g << 2) | (g >> 4); > r = (r << 2) | (r >> 4); >@@ -618,15 +698,15 @@ void ARGB4444ToUVRow_C(const uint8* src_argb4444, > dst_v += 1; > } > if (width & 1) { >- uint8 b0 = src_argb4444[0] & 0x0f; >- uint8 g0 = src_argb4444[0] >> 4; >- uint8 r0 = src_argb4444[1] & 0x0f; >- uint8 b2 = next_argb4444[0] & 0x0f; >- uint8 g2 = next_argb4444[0] >> 4; >- uint8 r2 = next_argb4444[1] & 0x0f; >- uint8 b = (b0 + b2); // 444 * 2 = 555. >- uint8 g = (g0 + g2); >- uint8 r = (r0 + r2); >+ uint8_t b0 = src_argb4444[0] & 0x0f; >+ uint8_t g0 = src_argb4444[0] >> 4; >+ uint8_t r0 = src_argb4444[1] & 0x0f; >+ uint8_t b2 = next_argb4444[0] & 0x0f; >+ uint8_t g2 = next_argb4444[0] >> 4; >+ uint8_t r2 = next_argb4444[1] & 0x0f; >+ uint8_t b = (b0 + b2); // 444 * 2 = 555. >+ uint8_t g = (g0 + g2); >+ uint8_t r = (r0 + r2); > b = (b << 3) | (b >> 2); // 555 -> 888. > g = (g << 3) | (g >> 2); > r = (r << 3) | (r >> 2); >@@ -635,15 +715,15 @@ void ARGB4444ToUVRow_C(const uint8* src_argb4444, > } > } > >-void ARGBToUV444Row_C(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_C(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 ab = src_argb[0]; >- uint8 ag = src_argb[1]; >- uint8 ar = src_argb[2]; >+ uint8_t ab = src_argb[0]; >+ uint8_t ag = src_argb[1]; >+ uint8_t ar = src_argb[2]; > dst_u[0] = RGBToU(ar, ag, ab); > dst_v[0] = RGBToV(ar, ag, ab); > src_argb += 4; >@@ -652,10 +732,10 @@ void ARGBToUV444Row_C(const uint8* src_argb, > } > } > >-void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBGrayRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width) { > int x; > for (x = 0; x < width; ++x) { >- uint8 y = RGBToYJ(src_argb[2], src_argb[1], src_argb[0]); >+ uint8_t y = RGBToYJ(src_argb[2], src_argb[1], src_argb[0]); > dst_argb[2] = dst_argb[1] = dst_argb[0] = y; > dst_argb[3] = src_argb[3]; > dst_argb += 4; >@@ -664,7 +744,7 @@ void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width) { > } > > // Convert a row of image to Sepia tone. >-void ARGBSepiaRow_C(uint8* dst_argb, int width) { >+void ARGBSepiaRow_C(uint8_t* dst_argb, int width) { > int x; > for (x = 0; x < width; ++x) { > int b = dst_argb[0]; >@@ -683,9 +763,9 @@ void ARGBSepiaRow_C(uint8* dst_argb, int width) { > > // Apply color matrix to a row of image. Matrix is signed. > // TODO(fbarchard): Consider adding rounding (+32). >-void ARGBColorMatrixRow_C(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { > int x; > for (x = 0; x < width; ++x) { >@@ -715,7 +795,9 @@ void ARGBColorMatrixRow_C(const uint8* src_argb, > } > > // Apply color table to a row of image. >-void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) { >+void ARGBColorTableRow_C(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width) { > int x; > for (x = 0; x < width; ++x) { > int b = dst_argb[0]; >@@ -731,7 +813,9 @@ void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) { > } > > // Apply color table to a row of image. >-void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) { >+void RGBColorTableRow_C(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width) { > int x; > for (x = 0; x < width; ++x) { > int b = dst_argb[0]; >@@ -744,7 +828,7 @@ void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) { > } > } > >-void ARGBQuantizeRow_C(uint8* dst_argb, >+void ARGBQuantizeRow_C(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, >@@ -764,21 +848,21 @@ void ARGBQuantizeRow_C(uint8* dst_argb, > #define REPEAT8(v) (v) | ((v) << 8) > #define SHADE(f, v) v* f >> 24 > >-void ARGBShadeRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >- const uint32 b_scale = REPEAT8(value & 0xff); >- const uint32 g_scale = REPEAT8((value >> 8) & 0xff); >- const uint32 r_scale = REPEAT8((value >> 16) & 0xff); >- const uint32 a_scale = REPEAT8(value >> 24); >+ uint32_t value) { >+ const uint32_t b_scale = REPEAT8(value & 0xff); >+ const uint32_t g_scale = REPEAT8((value >> 8) & 0xff); >+ const uint32_t r_scale = REPEAT8((value >> 16) & 0xff); >+ const uint32_t a_scale = REPEAT8(value >> 24); > > int i; > for (i = 0; i < width; ++i) { >- const uint32 b = REPEAT8(src_argb[0]); >- const uint32 g = REPEAT8(src_argb[1]); >- const uint32 r = REPEAT8(src_argb[2]); >- const uint32 a = REPEAT8(src_argb[3]); >+ const uint32_t b = REPEAT8(src_argb[0]); >+ const uint32_t g = REPEAT8(src_argb[1]); >+ const uint32_t r = REPEAT8(src_argb[2]); >+ const uint32_t a = REPEAT8(src_argb[3]); > dst_argb[0] = SHADE(b, b_scale); > dst_argb[1] = SHADE(g, g_scale); > dst_argb[2] = SHADE(r, r_scale); >@@ -793,20 +877,20 @@ void ARGBShadeRow_C(const uint8* src_argb, > #define REPEAT8(v) (v) | ((v) << 8) > #define SHADE(f, v) v* f >> 16 > >-void ARGBMultiplyRow_C(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int i; > for (i = 0; i < width; ++i) { >- const uint32 b = REPEAT8(src_argb0[0]); >- const uint32 g = REPEAT8(src_argb0[1]); >- const uint32 r = REPEAT8(src_argb0[2]); >- const uint32 a = REPEAT8(src_argb0[3]); >- const uint32 b_scale = src_argb1[0]; >- const uint32 g_scale = src_argb1[1]; >- const uint32 r_scale = src_argb1[2]; >- const uint32 a_scale = src_argb1[3]; >+ const uint32_t b = REPEAT8(src_argb0[0]); >+ const uint32_t g = REPEAT8(src_argb0[1]); >+ const uint32_t r = REPEAT8(src_argb0[2]); >+ const uint32_t a = REPEAT8(src_argb0[3]); >+ const uint32_t b_scale = src_argb1[0]; >+ const uint32_t g_scale = src_argb1[1]; >+ const uint32_t r_scale = src_argb1[2]; >+ const uint32_t a_scale = src_argb1[3]; > dst_argb[0] = SHADE(b, b_scale); > dst_argb[1] = SHADE(g, g_scale); > dst_argb[2] = SHADE(r, r_scale); >@@ -821,9 +905,9 @@ void ARGBMultiplyRow_C(const uint8* src_argb0, > > #define SHADE(f, v) clamp255(v + f) > >-void ARGBAddRow_C(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int i; > for (i = 0; i < width; ++i) { >@@ -848,9 +932,9 @@ void ARGBAddRow_C(const uint8* src_argb0, > > #define SHADE(f, v) clamp0(f - v) > >-void ARGBSubtractRow_C(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int i; > for (i = 0; i < width; ++i) { >@@ -874,10 +958,10 @@ void ARGBSubtractRow_C(const uint8* src_argb0, > #undef SHADE > > // Sobel functions which mimics SSSE3. >-void SobelXRow_C(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_C(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width) { > int i; > for (i = 0; i < width; ++i) { >@@ -891,13 +975,13 @@ void SobelXRow_C(const uint8* src_y0, > int b_diff = b - b_sub; > int c_diff = c - c_sub; > int sobel = Abs(a_diff + b_diff * 2 + c_diff); >- dst_sobelx[i] = (uint8)(clamp255(sobel)); >+ dst_sobelx[i] = (uint8_t)(clamp255(sobel)); > } > } > >-void SobelYRow_C(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_C(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width) { > int i; > for (i = 0; i < width; ++i) { >@@ -911,62 +995,62 @@ void SobelYRow_C(const uint8* src_y0, > int b_diff = b - b_sub; > int c_diff = c - c_sub; > int sobel = Abs(a_diff + b_diff * 2 + c_diff); >- dst_sobely[i] = (uint8)(clamp255(sobel)); >+ dst_sobely[i] = (uint8_t)(clamp255(sobel)); > } > } > >-void SobelRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > int i; > for (i = 0; i < width; ++i) { > int r = src_sobelx[i]; > int b = src_sobely[i]; > int s = clamp255(r + b); >- dst_argb[0] = (uint8)(s); >- dst_argb[1] = (uint8)(s); >- dst_argb[2] = (uint8)(s); >- dst_argb[3] = (uint8)(255u); >+ dst_argb[0] = (uint8_t)(s); >+ dst_argb[1] = (uint8_t)(s); >+ dst_argb[2] = (uint8_t)(s); >+ dst_argb[3] = (uint8_t)(255u); > dst_argb += 4; > } > } > >-void SobelToPlaneRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { > int i; > for (i = 0; i < width; ++i) { > int r = src_sobelx[i]; > int b = src_sobely[i]; > int s = clamp255(r + b); >- dst_y[i] = (uint8)(s); >+ dst_y[i] = (uint8_t)(s); > } > } > >-void SobelXYRow_C(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_C(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > int i; > for (i = 0; i < width; ++i) { > int r = src_sobelx[i]; > int b = src_sobely[i]; > int g = clamp255(r + b); >- dst_argb[0] = (uint8)(b); >- dst_argb[1] = (uint8)(g); >- dst_argb[2] = (uint8)(r); >- dst_argb[3] = (uint8)(255u); >+ dst_argb[0] = (uint8_t)(b); >+ dst_argb[1] = (uint8_t)(g); >+ dst_argb[2] = (uint8_t)(r); >+ dst_argb[3] = (uint8_t)(255u); > dst_argb += 4; > } > } > >-void J400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width) { >+void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) { > // Copy a Y to RGB. > int x; > for (x = 0; x < width; ++x) { >- uint8 y = src_y[0]; >+ uint8_t y = src_y[0]; > dst_argb[2] = dst_argb[1] = dst_argb[0] = y; > dst_argb[3] = 255u; > dst_argb += 4; >@@ -1223,12 +1307,14 @@ const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = { > #undef YG > > // C reference code that mimics the YUV assembly. >-static __inline void YuvPixel(uint8 y, >- uint8 u, >- uint8 v, >- uint8* b, >- uint8* g, >- uint8* r, >+// Reads 8 bit YUV and leaves result as 16 bit. >+ >+static __inline void YuvPixel(uint8_t y, >+ uint8_t u, >+ uint8_t v, >+ uint8_t* b, >+ uint8_t* g, >+ uint8_t* r, > const struct YuvConstants* yuvconstants) { > #if defined(__aarch64__) > int ub = -yuvconstants->kUVToRB[0]; >@@ -1259,10 +1345,117 @@ static __inline void YuvPixel(uint8 y, > int yg = yuvconstants->kYToRgb[0]; > #endif > >- uint32 y1 = (uint32)(y * 0x0101 * yg) >> 16; >- *b = Clamp((int32)(-(u * ub) + y1 + bb) >> 6); >- *g = Clamp((int32)(-(u * ug + v * vg) + y1 + bg) >> 6); >- *r = Clamp((int32)(-(v * vr) + y1 + br) >> 6); >+ uint32_t y1 = (uint32_t)(y * 0x0101 * yg) >> 16; >+ *b = Clamp((int32_t)(-(u * ub) + y1 + bb) >> 6); >+ *g = Clamp((int32_t)(-(u * ug + v * vg) + y1 + bg) >> 6); >+ *r = Clamp((int32_t)(-(v * vr) + y1 + br) >> 6); >+} >+ >+// Reads 8 bit YUV and leaves result as 16 bit. >+static __inline void YuvPixel8_16(uint8_t y, >+ uint8_t u, >+ uint8_t v, >+ int* b, >+ int* g, >+ int* r, >+ const struct YuvConstants* yuvconstants) { >+#if defined(__aarch64__) >+ int ub = -yuvconstants->kUVToRB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[1]; >+ int vr = -yuvconstants->kUVToRB[1]; >+ int bb = yuvconstants->kUVBiasBGR[0]; >+ int bg = yuvconstants->kUVBiasBGR[1]; >+ int br = yuvconstants->kUVBiasBGR[2]; >+ int yg = yuvconstants->kYToRgb[0] / 0x0101; >+#elif defined(__arm__) >+ int ub = -yuvconstants->kUVToRB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[4]; >+ int vr = -yuvconstants->kUVToRB[4]; >+ int bb = yuvconstants->kUVBiasBGR[0]; >+ int bg = yuvconstants->kUVBiasBGR[1]; >+ int br = yuvconstants->kUVBiasBGR[2]; >+ int yg = yuvconstants->kYToRgb[0] / 0x0101; >+#else >+ int ub = yuvconstants->kUVToB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[1]; >+ int vr = yuvconstants->kUVToR[1]; >+ int bb = yuvconstants->kUVBiasB[0]; >+ int bg = yuvconstants->kUVBiasG[0]; >+ int br = yuvconstants->kUVBiasR[0]; >+ int yg = yuvconstants->kYToRgb[0]; >+#endif >+ >+ uint32_t y1 = (uint32_t)(y * 0x0101 * yg) >> 16; >+ *b = (int)(-(u * ub) + y1 + bb); >+ *g = (int)(-(u * ug + v * vg) + y1 + bg); >+ *r = (int)(-(v * vr) + y1 + br); >+} >+ >+// C reference code that mimics the YUV 16 bit assembly. >+// Reads 10 bit YUV and leaves result as 16 bit. >+static __inline void YuvPixel16(int16_t y, >+ int16_t u, >+ int16_t v, >+ int* b, >+ int* g, >+ int* r, >+ const struct YuvConstants* yuvconstants) { >+#if defined(__aarch64__) >+ int ub = -yuvconstants->kUVToRB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[1]; >+ int vr = -yuvconstants->kUVToRB[1]; >+ int bb = yuvconstants->kUVBiasBGR[0]; >+ int bg = yuvconstants->kUVBiasBGR[1]; >+ int br = yuvconstants->kUVBiasBGR[2]; >+ int yg = yuvconstants->kYToRgb[0] / 0x0101; >+#elif defined(__arm__) >+ int ub = -yuvconstants->kUVToRB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[4]; >+ int vr = -yuvconstants->kUVToRB[4]; >+ int bb = yuvconstants->kUVBiasBGR[0]; >+ int bg = yuvconstants->kUVBiasBGR[1]; >+ int br = yuvconstants->kUVBiasBGR[2]; >+ int yg = yuvconstants->kYToRgb[0] / 0x0101; >+#else >+ int ub = yuvconstants->kUVToB[0]; >+ int ug = yuvconstants->kUVToG[0]; >+ int vg = yuvconstants->kUVToG[1]; >+ int vr = yuvconstants->kUVToR[1]; >+ int bb = yuvconstants->kUVBiasB[0]; >+ int bg = yuvconstants->kUVBiasG[0]; >+ int br = yuvconstants->kUVBiasR[0]; >+ int yg = yuvconstants->kYToRgb[0]; >+#endif >+ >+ uint32_t y1 = (uint32_t)((y << 6) * yg) >> 16; >+ u = clamp255(u >> 2); >+ v = clamp255(v >> 2); >+ *b = (int)(-(u * ub) + y1 + bb); >+ *g = (int)(-(u * ug + v * vg) + y1 + bg); >+ *r = (int)(-(v * vr) + y1 + br); >+} >+ >+// C reference code that mimics the YUV 10 bit assembly. >+// Reads 10 bit YUV and clamps down to 8 bit RGB. >+static __inline void YuvPixel10(uint16_t y, >+ uint16_t u, >+ uint16_t v, >+ uint8_t* b, >+ uint8_t* g, >+ uint8_t* r, >+ const struct YuvConstants* yuvconstants) { >+ int b16; >+ int g16; >+ int r16; >+ YuvPixel16(y, u, v, &b16, &g16, &r16, yuvconstants); >+ *b = Clamp(b16 >> 6); >+ *g = Clamp(g16 >> 6); >+ *r = Clamp(r16 >> 6); > } > > // Y contribution to R,G,B. Scale and bias. >@@ -1270,11 +1463,11 @@ static __inline void YuvPixel(uint8 y, > #define YGB -1160 /* 1.164 * 64 * -16 + 64 / 2 */ > > // C reference code that mimics the YUV assembly. >-static __inline void YPixel(uint8 y, uint8* b, uint8* g, uint8* r) { >- uint32 y1 = (uint32)(y * 0x0101 * YG) >> 16; >- *b = Clamp((int32)(y1 + YGB) >> 6); >- *g = Clamp((int32)(y1 + YGB) >> 6); >- *r = Clamp((int32)(y1 + YGB) >> 6); >+static __inline void YPixel(uint8_t y, uint8_t* b, uint8_t* g, uint8_t* r) { >+ uint32_t y1 = (uint32_t)(y * 0x0101 * YG) >> 16; >+ *b = Clamp((int32_t)(y1 + YGB) >> 6); >+ *g = Clamp((int32_t)(y1 + YGB) >> 6); >+ *r = Clamp((int32_t)(y1 + YGB) >> 6); > } > > #undef YG >@@ -1284,16 +1477,16 @@ static __inline void YPixel(uint8 y, uint8* b, uint8* g, uint8* r) { > (defined(__ARM_NEON__) || defined(__aarch64__) || defined(LIBYUV_NEON)) > // C mimic assembly. > // TODO(fbarchard): Remove subsampling from Neon. >-void I444ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I444ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >- uint8 u = (src_u[0] + src_u[1] + 1) >> 1; >- uint8 v = (src_v[0] + src_v[1] + 1) >> 1; >+ uint8_t u = (src_u[0] + src_u[1] + 1) >> 1; >+ uint8_t v = (src_v[0] + src_v[1] + 1) >> 1; > YuvPixel(src_y[0], u, v, rgb_buf + 0, rgb_buf + 1, rgb_buf + 2, > yuvconstants); > rgb_buf[3] = 255; >@@ -1312,10 +1505,10 @@ void I444ToARGBRow_C(const uint8* src_y, > } > } > #else >-void I444ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I444ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1332,10 +1525,10 @@ void I444ToARGBRow_C(const uint8* src_y, > #endif > > // Also used for 420 >-void I422ToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1358,11 +1551,105 @@ void I422ToARGBRow_C(const uint8* src_y, > } > } > >-void I422AlphaToARGBRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* rgb_buf, >+// 10 bit YUV to ARGB >+void I210ToARGBRow_C(const uint16_t* src_y, >+ const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ int x; >+ for (x = 0; x < width - 1; x += 2) { >+ YuvPixel10(src_y[0], src_u[0], src_v[0], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ rgb_buf[3] = 255; >+ YuvPixel10(src_y[1], src_u[0], src_v[0], rgb_buf + 4, rgb_buf + 5, >+ rgb_buf + 6, yuvconstants); >+ rgb_buf[7] = 255; >+ src_y += 2; >+ src_u += 1; >+ src_v += 1; >+ rgb_buf += 8; // Advance 2 pixels. >+ } >+ if (width & 1) { >+ YuvPixel10(src_y[0], src_u[0], src_v[0], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ rgb_buf[3] = 255; >+ } >+} >+ >+static void StoreAR30(uint8_t* rgb_buf, int b, int g, int r) { >+ uint32_t ar30; >+ b = b >> 4; // convert 10.6 to 10 bit. >+ g = g >> 4; >+ r = r >> 4; >+ b = Clamp10(b); >+ g = Clamp10(g); >+ r = Clamp10(r); >+ ar30 = b | ((uint32_t)g << 10) | ((uint32_t)r << 20) | 0xc0000000; >+ (*(uint32_t*)rgb_buf) = ar30; >+} >+ >+// 10 bit YUV to 10 bit AR30 >+void I210ToAR30Row_C(const uint16_t* src_y, >+ const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ int x; >+ int b; >+ int g; >+ int r; >+ for (x = 0; x < width - 1; x += 2) { >+ YuvPixel16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf, b, g, r); >+ YuvPixel16(src_y[1], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf + 4, b, g, r); >+ src_y += 2; >+ src_u += 1; >+ src_v += 1; >+ rgb_buf += 8; // Advance 2 pixels. >+ } >+ if (width & 1) { >+ YuvPixel16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf, b, g, r); >+ } >+} >+ >+// 8 bit YUV to 10 bit AR30 >+// Uses same code as 10 bit YUV bit shifts the 8 bit values up to 10 bits. >+void I422ToAR30Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ int x; >+ int b; >+ int g; >+ int r; >+ for (x = 0; x < width - 1; x += 2) { >+ YuvPixel8_16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf, b, g, r); >+ YuvPixel8_16(src_y[1], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf + 4, b, g, r); >+ src_y += 2; >+ src_u += 1; >+ src_v += 1; >+ rgb_buf += 8; // Advance 2 pixels. >+ } >+ if (width & 1) { >+ YuvPixel8_16(src_y[0], src_u[0], src_v[0], &b, &g, &r, yuvconstants); >+ StoreAR30(rgb_buf, b, g, r); >+ } >+} >+ >+void I422AlphaToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1386,10 +1673,10 @@ void I422AlphaToARGBRow_C(const uint8* src_y, > } > } > >-void I422ToRGB24Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1409,18 +1696,18 @@ void I422ToRGB24Row_C(const uint8* src_y, > } > } > >-void I422ToARGB4444Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { >- uint8 b0; >- uint8 g0; >- uint8 r0; >- uint8 b1; >- uint8 g1; >- uint8 r1; >+ uint8_t b0; >+ uint8_t g0; >+ uint8_t r0; >+ uint8_t b1; >+ uint8_t g1; >+ uint8_t r1; > int x; > for (x = 0; x < width - 1; x += 2) { > YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0, yuvconstants); >@@ -1431,8 +1718,8 @@ void I422ToARGB4444Row_C(const uint8* src_y, > b1 = b1 >> 4; > g1 = g1 >> 4; > r1 = r1 >> 4; >- *(uint32*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) | (b1 << 16) | >- (g1 << 20) | (r1 << 24) | 0xf000f000; >+ *(uint32_t*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) | (b1 << 16) | >+ (g1 << 20) | (r1 << 24) | 0xf000f000; > src_y += 2; > src_u += 1; > src_v += 1; >@@ -1443,22 +1730,22 @@ void I422ToARGB4444Row_C(const uint8* src_y, > b0 = b0 >> 4; > g0 = g0 >> 4; > r0 = r0 >> 4; >- *(uint16*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) | 0xf000; >+ *(uint16_t*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) | 0xf000; > } > } > >-void I422ToARGB1555Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { >- uint8 b0; >- uint8 g0; >- uint8 r0; >- uint8 b1; >- uint8 g1; >- uint8 r1; >+ uint8_t b0; >+ uint8_t g0; >+ uint8_t r0; >+ uint8_t b1; >+ uint8_t g1; >+ uint8_t r1; > int x; > for (x = 0; x < width - 1; x += 2) { > YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0, yuvconstants); >@@ -1469,8 +1756,8 @@ void I422ToARGB1555Row_C(const uint8* src_y, > b1 = b1 >> 3; > g1 = g1 >> 3; > r1 = r1 >> 3; >- *(uint32*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) | (b1 << 16) | >- (g1 << 21) | (r1 << 26) | 0x80008000; >+ *(uint32_t*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) | (b1 << 16) | >+ (g1 << 21) | (r1 << 26) | 0x80008000; > src_y += 2; > src_u += 1; > src_v += 1; >@@ -1481,22 +1768,22 @@ void I422ToARGB1555Row_C(const uint8* src_y, > b0 = b0 >> 3; > g0 = g0 >> 3; > r0 = r0 >> 3; >- *(uint16*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) | 0x8000; >+ *(uint16_t*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) | 0x8000; > } > } > >-void I422ToRGB565Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { >- uint8 b0; >- uint8 g0; >- uint8 r0; >- uint8 b1; >- uint8 g1; >- uint8 r1; >+ uint8_t b0; >+ uint8_t g0; >+ uint8_t r0; >+ uint8_t b1; >+ uint8_t g1; >+ uint8_t r1; > int x; > for (x = 0; x < width - 1; x += 2) { > YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0, yuvconstants); >@@ -1507,7 +1794,7 @@ void I422ToRGB565Row_C(const uint8* src_y, > b1 = b1 >> 3; > g1 = g1 >> 2; > r1 = r1 >> 3; >- *(uint32*)(dst_rgb565) = >+ *(uint32_t*)(dst_rgb565) = > b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27); > src_y += 2; > src_u += 1; >@@ -1519,13 +1806,13 @@ void I422ToRGB565Row_C(const uint8* src_y, > b0 = b0 >> 3; > g0 = g0 >> 2; > r0 = r0 >> 3; >- *(uint16*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11); >+ *(uint16_t*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11); > } > } > >-void NV12ToARGBRow_C(const uint8* src_y, >- const uint8* src_uv, >- uint8* rgb_buf, >+void NV12ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1547,9 +1834,9 @@ void NV12ToARGBRow_C(const uint8* src_y, > } > } > >-void NV21ToARGBRow_C(const uint8* src_y, >- const uint8* src_vu, >- uint8* rgb_buf, >+void NV21ToARGBRow_C(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1571,17 +1858,59 @@ void NV21ToARGBRow_C(const uint8* src_y, > } > } > >-void NV12ToRGB565Row_C(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ int x; >+ for (x = 0; x < width - 1; x += 2) { >+ YuvPixel(src_y[0], src_uv[0], src_uv[1], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ YuvPixel(src_y[1], src_uv[0], src_uv[1], rgb_buf + 3, rgb_buf + 4, >+ rgb_buf + 5, yuvconstants); >+ src_y += 2; >+ src_uv += 2; >+ rgb_buf += 6; // Advance 2 pixels. >+ } >+ if (width & 1) { >+ YuvPixel(src_y[0], src_uv[0], src_uv[1], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ } >+} >+ >+void NV21ToRGB24Row_C(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* rgb_buf, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ int x; >+ for (x = 0; x < width - 1; x += 2) { >+ YuvPixel(src_y[0], src_vu[1], src_vu[0], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ YuvPixel(src_y[1], src_vu[1], src_vu[0], rgb_buf + 3, rgb_buf + 4, >+ rgb_buf + 5, yuvconstants); >+ src_y += 2; >+ src_vu += 2; >+ rgb_buf += 6; // Advance 2 pixels. >+ } >+ if (width & 1) { >+ YuvPixel(src_y[0], src_vu[1], src_vu[0], rgb_buf + 0, rgb_buf + 1, >+ rgb_buf + 2, yuvconstants); >+ } >+} >+ >+void NV12ToRGB565Row_C(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { >- uint8 b0; >- uint8 g0; >- uint8 r0; >- uint8 b1; >- uint8 g1; >- uint8 r1; >+ uint8_t b0; >+ uint8_t g0; >+ uint8_t r0; >+ uint8_t b1; >+ uint8_t g1; >+ uint8_t r1; > int x; > for (x = 0; x < width - 1; x += 2) { > YuvPixel(src_y[0], src_uv[0], src_uv[1], &b0, &g0, &r0, yuvconstants); >@@ -1592,7 +1921,7 @@ void NV12ToRGB565Row_C(const uint8* src_y, > b1 = b1 >> 3; > g1 = g1 >> 2; > r1 = r1 >> 3; >- *(uint32*)(dst_rgb565) = >+ *(uint32_t*)(dst_rgb565) = > b0 | (g0 << 5) | (r0 << 11) | (b1 << 16) | (g1 << 21) | (r1 << 27); > src_y += 2; > src_uv += 2; >@@ -1603,12 +1932,12 @@ void NV12ToRGB565Row_C(const uint8* src_y, > b0 = b0 >> 3; > g0 = g0 >> 2; > r0 = r0 >> 3; >- *(uint16*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11); >+ *(uint16_t*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11); > } > } > >-void YUY2ToARGBRow_C(const uint8* src_yuy2, >- uint8* rgb_buf, >+void YUY2ToARGBRow_C(const uint8_t* src_yuy2, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1629,8 +1958,8 @@ void YUY2ToARGBRow_C(const uint8* src_yuy2, > } > } > >-void UYVYToARGBRow_C(const uint8* src_uyvy, >- uint8* rgb_buf, >+void UYVYToARGBRow_C(const uint8_t* src_uyvy, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1651,10 +1980,10 @@ void UYVYToARGBRow_C(const uint8* src_uyvy, > } > } > >-void I422ToRGBARow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToRGBARow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* rgb_buf, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -1677,7 +2006,7 @@ void I422ToRGBARow_C(const uint8* src_y, > } > } > >-void I400ToARGBRow_C(const uint8* src_y, uint8* rgb_buf, int width) { >+void I400ToARGBRow_C(const uint8_t* src_y, uint8_t* rgb_buf, int width) { > int x; > for (x = 0; x < width - 1; x += 2) { > YPixel(src_y[0], rgb_buf + 0, rgb_buf + 1, rgb_buf + 2); >@@ -1693,7 +2022,7 @@ void I400ToARGBRow_C(const uint8* src_y, uint8* rgb_buf, int width) { > } > } > >-void MirrorRow_C(const uint8* src, uint8* dst, int width) { >+void MirrorRow_C(const uint8_t* src, uint8_t* dst, int width) { > int x; > src += width - 1; > for (x = 0; x < width - 1; x += 2) { >@@ -1706,7 +2035,10 @@ void MirrorRow_C(const uint8* src, uint8* dst, int width) { > } > } > >-void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) { >+void MirrorUVRow_C(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width) { > int x; > src_uv += (width - 1) << 1; > for (x = 0; x < width - 1; x += 2) { >@@ -1722,10 +2054,10 @@ void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) { > } > } > >-void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_C(const uint8_t* src, uint8_t* dst, int width) { > int x; >- const uint32* src32 = (const uint32*)(src); >- uint32* dst32 = (uint32*)(dst); >+ const uint32_t* src32 = (const uint32_t*)(src); >+ uint32_t* dst32 = (uint32_t*)(dst); > src32 += width - 1; > for (x = 0; x < width - 1; x += 2) { > dst32[x] = src32[0]; >@@ -1737,7 +2069,10 @@ void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width) { > } > } > >-void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) { >+void SplitUVRow_C(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int width) { > int x; > for (x = 0; x < width - 1; x += 2) { > dst_u[x] = src_uv[0]; >@@ -1752,9 +2087,9 @@ void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) { > } > } > >-void MergeUVRow_C(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_C(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -1770,10 +2105,10 @@ void MergeUVRow_C(const uint8* src_u, > } > } > >-void SplitRGBRow_C(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_C(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width) { > int x; > for (x = 0; x < width; ++x) { >@@ -1784,10 +2119,10 @@ void SplitRGBRow_C(const uint8* src_rgb, > } > } > >-void MergeRGBRow_C(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_C(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width) { > int x; > for (x = 0; x < width; ++x) { >@@ -1798,9 +2133,14 @@ void MergeRGBRow_C(const uint8* src_r, > } > } > >-void MergeUVRow_16_C(const uint16* src_u, >- const uint16* src_v, >- uint16* dst_uv, >+// Use scale to convert lsb formats to msb, depending how many bits there are: >+// 128 = 9 bits >+// 64 = 10 bits >+// 16 = 12 bits >+// 1 = 16 bits >+void MergeUVRow_16_C(const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint16_t* dst_uv, > int scale, > int width) { > int x; >@@ -1817,8 +2157,8 @@ void MergeUVRow_16_C(const uint16* src_u, > } > } > >-void MultiplyRow_16_C(const uint16* src_y, >- uint16* dst_y, >+void MultiplyRow_16_C(const uint16_t* src_y, >+ uint16_t* dst_y, > int scale, > int width) { > int x; >@@ -1827,20 +2167,48 @@ void MultiplyRow_16_C(const uint16* src_y, > } > } > >-void CopyRow_C(const uint8* src, uint8* dst, int count) { >+// Use scale to convert lsb formats to msb, depending how many bits there are: >+// 32768 = 9 bits >+// 16384 = 10 bits >+// 4096 = 12 bits >+// 256 = 16 bits >+void Convert16To8Row_C(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width) { >+ int x; >+ for (x = 0; x < width; ++x) { >+ dst_y[x] = clamp255((src_y[x] * scale) >> 16); >+ } >+} >+ >+// Use scale to convert lsb formats to msb, depending how many bits there are: >+// 1024 = 10 bits >+void Convert8To16Row_C(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width) { >+ int x; >+ scale *= 0x0101; // replicates the byte. >+ for (x = 0; x < width; ++x) { >+ dst_y[x] = (src_y[x] * scale) >> 16; >+ } >+} >+ >+void CopyRow_C(const uint8_t* src, uint8_t* dst, int count) { > memcpy(dst, src, count); > } > >-void CopyRow_16_C(const uint16* src, uint16* dst, int count) { >+void CopyRow_16_C(const uint16_t* src, uint16_t* dst, int count) { > memcpy(dst, src, count * 2); > } > >-void SetRow_C(uint8* dst, uint8 v8, int width) { >+void SetRow_C(uint8_t* dst, uint8_t v8, int width) { > memset(dst, v8, width); > } > >-void ARGBSetRow_C(uint8* dst_argb, uint32 v32, int width) { >- uint32* d = (uint32*)(dst_argb); >+void ARGBSetRow_C(uint8_t* dst_argb, uint32_t v32, int width) { >+ uint32_t* d = (uint32_t*)(dst_argb); > int x; > for (x = 0; x < width; ++x) { > d[x] = v32; >@@ -1848,10 +2216,10 @@ void ARGBSetRow_C(uint8* dst_argb, uint32 v32, int width) { > } > > // Filter 2 rows of YUY2 UV's (422) into U and V (420). >-void YUY2ToUVRow_C(const uint8* src_yuy2, >+void YUY2ToUVRow_C(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > // Output a row of UV values, filtering 2 rows of YUY2. > int x; >@@ -1865,9 +2233,9 @@ void YUY2ToUVRow_C(const uint8* src_yuy2, > } > > // Copy row of YUY2 UV's (422) into U and V (422). >-void YUY2ToUV422Row_C(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_C(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > // Output a row of UV values. > int x; >@@ -1881,7 +2249,7 @@ void YUY2ToUV422Row_C(const uint8* src_yuy2, > } > > // Copy row of YUY2 Y's (422) into Y (420/422). >-void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int width) { >+void YUY2ToYRow_C(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { > // Output a row of Y values. > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -1895,10 +2263,10 @@ void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int width) { > } > > // Filter 2 rows of UYVY UV's (422) into U and V (420). >-void UYVYToUVRow_C(const uint8* src_uyvy, >+void UYVYToUVRow_C(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > // Output a row of UV values. > int x; >@@ -1912,9 +2280,9 @@ void UYVYToUVRow_C(const uint8* src_uyvy, > } > > // Copy row of UYVY UV's (422) into U and V (422). >-void UYVYToUV422Row_C(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_C(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > // Output a row of UV values. > int x; >@@ -1928,7 +2296,7 @@ void UYVYToUV422Row_C(const uint8* src_uyvy, > } > > // Copy row of UYVY Y's (422) into Y (420/422). >-void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int width) { >+void UYVYToYRow_C(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { > // Output a row of Y values. > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -1946,19 +2314,19 @@ void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int width) { > // Blend src_argb0 over src_argb1 and store to dst_argb. > // dst_argb may be src_argb0 or src_argb1. > // This code mimics the SSSE3 version for better testability. >-void ARGBBlendRow_C(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_C(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >- uint32 fb = src_argb0[0]; >- uint32 fg = src_argb0[1]; >- uint32 fr = src_argb0[2]; >- uint32 a = src_argb0[3]; >- uint32 bb = src_argb1[0]; >- uint32 bg = src_argb1[1]; >- uint32 br = src_argb1[2]; >+ uint32_t fb = src_argb0[0]; >+ uint32_t fg = src_argb0[1]; >+ uint32_t fr = src_argb0[2]; >+ uint32_t a = src_argb0[3]; >+ uint32_t bb = src_argb1[0]; >+ uint32_t bg = src_argb1[1]; >+ uint32_t br = src_argb1[2]; > dst_argb[0] = BLEND(fb, bb, a); > dst_argb[1] = BLEND(fg, bg, a); > dst_argb[2] = BLEND(fr, br, a); >@@ -1981,13 +2349,13 @@ void ARGBBlendRow_C(const uint8* src_argb0, > } > > if (width & 1) { >- uint32 fb = src_argb0[0]; >- uint32 fg = src_argb0[1]; >- uint32 fr = src_argb0[2]; >- uint32 a = src_argb0[3]; >- uint32 bb = src_argb1[0]; >- uint32 bg = src_argb1[1]; >- uint32 br = src_argb1[2]; >+ uint32_t fb = src_argb0[0]; >+ uint32_t fg = src_argb0[1]; >+ uint32_t fr = src_argb0[2]; >+ uint32_t a = src_argb0[3]; >+ uint32_t bb = src_argb1[0]; >+ uint32_t bg = src_argb1[1]; >+ uint32_t br = src_argb1[2]; > dst_argb[0] = BLEND(fb, bb, a); > dst_argb[1] = BLEND(fg, bg, a); > dst_argb[2] = BLEND(fr, br, a); >@@ -1997,10 +2365,10 @@ void ARGBBlendRow_C(const uint8* src_argb0, > #undef BLEND > > #define UBLEND(f, b, a) (((a)*f) + ((255 - a) * b) + 255) >> 8 >-void BlendPlaneRow_C(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_C(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -2021,13 +2389,13 @@ void BlendPlaneRow_C(const uint8* src0, > > // Multiply source RGB by alpha and store to destination. > // This code mimics the SSSE3 version for better testability. >-void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBAttenuateRow_C(const uint8_t* src_argb, uint8_t* dst_argb, int width) { > int i; > for (i = 0; i < width - 1; i += 2) { >- uint32 b = src_argb[0]; >- uint32 g = src_argb[1]; >- uint32 r = src_argb[2]; >- uint32 a = src_argb[3]; >+ uint32_t b = src_argb[0]; >+ uint32_t g = src_argb[1]; >+ uint32_t r = src_argb[2]; >+ uint32_t a = src_argb[3]; > dst_argb[0] = ATTENUATE(b, a); > dst_argb[1] = ATTENUATE(g, a); > dst_argb[2] = ATTENUATE(r, a); >@@ -2045,10 +2413,10 @@ void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) { > } > > if (width & 1) { >- const uint32 b = src_argb[0]; >- const uint32 g = src_argb[1]; >- const uint32 r = src_argb[2]; >- const uint32 a = src_argb[3]; >+ const uint32_t b = src_argb[0]; >+ const uint32_t g = src_argb[1]; >+ const uint32_t r = src_argb[2]; >+ const uint32_t a = src_argb[3]; > dst_argb[0] = ATTENUATE(b, a); > dst_argb[1] = ATTENUATE(g, a); > dst_argb[2] = ATTENUATE(r, a); >@@ -2064,7 +2432,7 @@ void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) { > // Reciprocal method is off by 1 on some values. ie 125 > // 8.8 fixed point inverse table with 1.0 in upper short and 1 / a in lower. > #define T(a) 0x01000000 + (0x10000 / a) >-const uint32 fixed_invtbl8[256] = { >+const uint32_t fixed_invtbl8[256] = { > 0x01000000, 0x0100ffff, T(0x02), T(0x03), T(0x04), T(0x05), T(0x06), > T(0x07), T(0x08), T(0x09), T(0x0a), T(0x0b), T(0x0c), T(0x0d), > T(0x0e), T(0x0f), T(0x10), T(0x11), T(0x12), T(0x13), T(0x14), >@@ -2104,14 +2472,16 @@ const uint32 fixed_invtbl8[256] = { > T(0xfc), T(0xfd), T(0xfe), 0x01000100}; > #undef T > >-void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBUnattenuateRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { > int i; > for (i = 0; i < width; ++i) { >- uint32 b = src_argb[0]; >- uint32 g = src_argb[1]; >- uint32 r = src_argb[2]; >- const uint32 a = src_argb[3]; >- const uint32 ia = fixed_invtbl8[a] & 0xffff; // 8.8 fixed point >+ uint32_t b = src_argb[0]; >+ uint32_t g = src_argb[1]; >+ uint32_t r = src_argb[2]; >+ const uint32_t a = src_argb[3]; >+ const uint32_t ia = fixed_invtbl8[a] & 0xffff; // 8.8 fixed point > b = (b * ia) >> 8; > g = (g * ia) >> 8; > r = (r * ia) >> 8; >@@ -2125,11 +2495,11 @@ void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) { > } > } > >-void ComputeCumulativeSumRow_C(const uint8* row, >- int32* cumsum, >- const int32* previous_cumsum, >+void ComputeCumulativeSumRow_C(const uint8_t* row, >+ int32_t* cumsum, >+ const int32_t* previous_cumsum, > int width) { >- int32 row_sum[4] = {0, 0, 0, 0}; >+ int32_t row_sum[4] = {0, 0, 0, 0}; > int x; > for (x = 0; x < width; ++x) { > row_sum[0] += row[x * 4 + 0]; >@@ -2143,19 +2513,19 @@ void ComputeCumulativeSumRow_C(const uint8* row, > } > } > >-void CumulativeSumToAverageRow_C(const int32* tl, >- const int32* bl, >+void CumulativeSumToAverageRow_C(const int32_t* tl, >+ const int32_t* bl, > int w, > int area, >- uint8* dst, >+ uint8_t* dst, > int count) { > float ooa = 1.0f / area; > int i; > for (i = 0; i < count; ++i) { >- dst[0] = (uint8)((bl[w + 0] + tl[0] - bl[0] - tl[w + 0]) * ooa); >- dst[1] = (uint8)((bl[w + 1] + tl[1] - bl[1] - tl[w + 1]) * ooa); >- dst[2] = (uint8)((bl[w + 2] + tl[2] - bl[2] - tl[w + 2]) * ooa); >- dst[3] = (uint8)((bl[w + 3] + tl[3] - bl[3] - tl[w + 3]) * ooa); >+ dst[0] = (uint8_t)((bl[w + 0] + tl[0] - bl[0] - tl[w + 0]) * ooa); >+ dst[1] = (uint8_t)((bl[w + 1] + tl[1] - bl[1] - tl[w + 1]) * ooa); >+ dst[2] = (uint8_t)((bl[w + 2] + tl[2] - bl[2] - tl[w + 2]) * ooa); >+ dst[3] = (uint8_t)((bl[w + 3] + tl[3] - bl[3] - tl[w + 3]) * ooa); > dst += 4; > tl += 4; > bl += 4; >@@ -2164,9 +2534,9 @@ void CumulativeSumToAverageRow_C(const int32* tl, > > // Copy pixels from rotated source to destination row with a slope. > LIBYUV_API >-void ARGBAffineRow_C(const uint8* src_argb, >+void ARGBAffineRow_C(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* uv_dudv, > int width) { > int i; >@@ -2177,8 +2547,8 @@ void ARGBAffineRow_C(const uint8* src_argb, > for (i = 0; i < width; ++i) { > int x = (int)(uv[0]); > int y = (int)(uv[1]); >- *(uint32*)(dst_argb) = >- *(const uint32*)(src_argb + y * src_argb_stride + x * 4); >+ *(uint32_t*)(dst_argb) = >+ *(const uint32_t*)(src_argb + y * src_argb_stride + x * 4); > dst_argb += 4; > uv[0] += uv_dudv[2]; > uv[1] += uv_dudv[3]; >@@ -2186,9 +2556,9 @@ void ARGBAffineRow_C(const uint8* src_argb, > } > > // Blend 2 rows into 1. >-static void HalfRow_C(const uint8* src_uv, >+static void HalfRow_C(const uint8_t* src_uv, > ptrdiff_t src_uv_stride, >- uint8* dst_uv, >+ uint8_t* dst_uv, > int width) { > int x; > for (x = 0; x < width; ++x) { >@@ -2196,9 +2566,9 @@ static void HalfRow_C(const uint8* src_uv, > } > } > >-static void HalfRow_16_C(const uint16* src_uv, >+static void HalfRow_16_C(const uint16_t* src_uv, > ptrdiff_t src_uv_stride, >- uint16* dst_uv, >+ uint16_t* dst_uv, > int width) { > int x; > for (x = 0; x < width; ++x) { >@@ -2207,14 +2577,14 @@ static void HalfRow_16_C(const uint16* src_uv, > } > > // C version 2x2 -> 2x1. >-void InterpolateRow_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int width, > int source_y_fraction) { > int y1_fraction = source_y_fraction; > int y0_fraction = 256 - y1_fraction; >- const uint8* src_ptr1 = src_ptr + src_stride; >+ const uint8_t* src_ptr1 = src_ptr + src_stride; > int x; > if (y1_fraction == 0) { > memcpy(dst_ptr, src_ptr, width); >@@ -2239,14 +2609,14 @@ void InterpolateRow_C(uint8* dst_ptr, > } > } > >-void InterpolateRow_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void InterpolateRow_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > ptrdiff_t src_stride, > int width, > int source_y_fraction) { > int y1_fraction = source_y_fraction; > int y0_fraction = 256 - y1_fraction; >- const uint16* src_ptr1 = src_ptr + src_stride; >+ const uint16_t* src_ptr1 = src_ptr + src_stride; > int x; > if (source_y_fraction == 0) { > memcpy(dst_ptr, src_ptr, width * 2); >@@ -2269,9 +2639,9 @@ void InterpolateRow_16_C(uint16* dst_ptr, > } > > // Use first 4 shuffler values to reorder ARGB channels. >-void ARGBShuffleRow_C(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > int index0 = shuffler[0]; > int index1 = shuffler[1]; >@@ -2281,10 +2651,10 @@ void ARGBShuffleRow_C(const uint8* src_argb, > int x; > for (x = 0; x < width; ++x) { > // To support in-place conversion. >- uint8 b = src_argb[index0]; >- uint8 g = src_argb[index1]; >- uint8 r = src_argb[index2]; >- uint8 a = src_argb[index3]; >+ uint8_t b = src_argb[index0]; >+ uint8_t g = src_argb[index1]; >+ uint8_t r = src_argb[index2]; >+ uint8_t a = src_argb[index3]; > dst_argb[0] = b; > dst_argb[1] = g; > dst_argb[2] = r; >@@ -2294,10 +2664,10 @@ void ARGBShuffleRow_C(const uint8* src_argb, > } > } > >-void I422ToYUY2Row_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+void I422ToYUY2Row_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -2318,10 +2688,10 @@ void I422ToYUY2Row_C(const uint8* src_y, > } > } > >-void I422ToUYVYRow_C(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+void I422ToUYVYRow_C(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width) { > int x; > for (x = 0; x < width - 1; x += 2) { >@@ -2342,8 +2712,8 @@ void I422ToUYVYRow_C(const uint8* src_y, > } > } > >-void ARGBPolynomialRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width) { > int i; >@@ -2373,10 +2743,10 @@ void ARGBPolynomialRow_C(const uint8* src_argb, > dr += poly[14] * r3; > da += poly[15] * a3; > >- dst_argb[0] = Clamp((int32)(db)); >- dst_argb[1] = Clamp((int32)(dg)); >- dst_argb[2] = Clamp((int32)(dr)); >- dst_argb[3] = Clamp((int32)(da)); >+ dst_argb[0] = Clamp((int32_t)(db)); >+ dst_argb[1] = Clamp((int32_t)(dg)); >+ dst_argb[2] = Clamp((int32_t)(dr)); >+ dst_argb[3] = Clamp((int32_t)(da)); > src_argb += 4; > dst_argb += 4; > } >@@ -2392,31 +2762,42 @@ void ARGBPolynomialRow_C(const uint8* src_argb, > // simply extract the low bits of the exponent and the high > // bits of the mantissa from our float and we're done. > >-void HalfFloatRow_C(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_C(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > int i; > float mult = 1.9259299444e-34f * scale; > for (i = 0; i < width; ++i) { > float value = src[i] * mult; >- dst[i] = (uint16)((*(uint32_t*)&value) >> 13); >+ dst[i] = (uint16_t)((*(uint32_t*)&value) >> 13); >+ } >+} >+ >+void ByteToFloatRow_C(const uint8_t* src, float* dst, float scale, int width) { >+ int i; >+ for (i = 0; i < width; ++i) { >+ float value = src[i] * scale; >+ dst[i] = value; > } > } > >-void ARGBLumaColorTableRow_C(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBLumaColorTableRow_C(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- const uint8* luma, >- uint32 lumacoeff) { >- uint32 bc = lumacoeff & 0xff; >- uint32 gc = (lumacoeff >> 8) & 0xff; >- uint32 rc = (lumacoeff >> 16) & 0xff; >+ const uint8_t* luma, >+ uint32_t lumacoeff) { >+ uint32_t bc = lumacoeff & 0xff; >+ uint32_t gc = (lumacoeff >> 8) & 0xff; >+ uint32_t rc = (lumacoeff >> 16) & 0xff; > > int i; > for (i = 0; i < width - 1; i += 2) { > // Luminance in rows, color values in columns. >- const uint8* luma0 = >+ const uint8_t* luma0 = > ((src_argb[0] * bc + src_argb[1] * gc + src_argb[2] * rc) & 0x7F00u) + > luma; >- const uint8* luma1; >+ const uint8_t* luma1; > dst_argb[0] = luma0[src_argb[0]]; > dst_argb[1] = luma0[src_argb[1]]; > dst_argb[2] = luma0[src_argb[2]]; >@@ -2433,7 +2814,7 @@ void ARGBLumaColorTableRow_C(const uint8* src_argb, > } > if (width & 1) { > // Luminance in rows, color values in columns. >- const uint8* luma0 = >+ const uint8_t* luma0 = > ((src_argb[0] * bc + src_argb[1] * gc + src_argb[2] * rc) & 0x7F00u) + > luma; > dst_argb[0] = luma0[src_argb[0]]; >@@ -2443,7 +2824,7 @@ void ARGBLumaColorTableRow_C(const uint8* src_argb, > } > } > >-void ARGBCopyAlphaRow_C(const uint8* src, uint8* dst, int width) { >+void ARGBCopyAlphaRow_C(const uint8_t* src, uint8_t* dst, int width) { > int i; > for (i = 0; i < width - 1; i += 2) { > dst[3] = src[3]; >@@ -2456,7 +2837,7 @@ void ARGBCopyAlphaRow_C(const uint8* src, uint8* dst, int width) { > } > } > >-void ARGBExtractAlphaRow_C(const uint8* src_argb, uint8* dst_a, int width) { >+void ARGBExtractAlphaRow_C(const uint8_t* src_argb, uint8_t* dst_a, int width) { > int i; > for (i = 0; i < width - 1; i += 2) { > dst_a[0] = src_argb[3]; >@@ -2469,7 +2850,7 @@ void ARGBExtractAlphaRow_C(const uint8* src_argb, uint8* dst_a, int width) { > } > } > >-void ARGBCopyYToAlphaRow_C(const uint8* src, uint8* dst, int width) { >+void ARGBCopyYToAlphaRow_C(const uint8_t* src, uint8_t* dst, int width) { > int i; > for (i = 0; i < width - 1; i += 2) { > dst[3] = src[0]; >@@ -2488,13 +2869,13 @@ void ARGBCopyYToAlphaRow_C(const uint8* src, uint8* dst, int width) { > #if !(defined(_MSC_VER) && defined(_M_IX86)) && \ > defined(HAS_I422TORGB565ROW_SSSE3) > // row_win.cc has asm version, but GCC uses 2 step wrapper. >-void I422ToRGB565Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2509,14 +2890,14 @@ void I422ToRGB565Row_SSSE3(const uint8* src_y, > #endif > > #if defined(HAS_I422TOARGB1555ROW_SSSE3) >-void I422ToARGB1555Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2531,14 +2912,14 @@ void I422ToARGB1555Row_SSSE3(const uint8* src_y, > #endif > > #if defined(HAS_I422TOARGB4444ROW_SSSE3) >-void I422ToARGB4444Row_SSSE3(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2553,13 +2934,13 @@ void I422ToARGB4444Row_SSSE3(const uint8* src_y, > #endif > > #if defined(HAS_NV12TORGB565ROW_SSSE3) >-void NV12ToRGB565Row_SSSE3(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB565Row_SSSE3(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > NV12ToARGBRow_SSSE3(src_y, src_uv, row, yuvconstants, twidth); >@@ -2573,13 +2954,13 @@ void NV12ToRGB565Row_SSSE3(const uint8* src_y, > #endif > > #if defined(HAS_I422TORGB565ROW_AVX2) >-void I422ToRGB565Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_AVX2(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2598,14 +2979,14 @@ void I422ToRGB565Row_AVX2(const uint8* src_y, > #endif > > #if defined(HAS_I422TOARGB1555ROW_AVX2) >-void I422ToARGB1555Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_AVX2(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2624,14 +3005,14 @@ void I422ToARGB1555Row_AVX2(const uint8* src_y, > #endif > > #if defined(HAS_I422TOARGB4444ROW_AVX2) >-void I422ToARGB4444Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_AVX2(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2650,14 +3031,14 @@ void I422ToARGB4444Row_AVX2(const uint8* src_y, > #endif > > #if defined(HAS_I422TORGB24ROW_AVX2) >-void I422ToRGB24Row_AVX2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > I422ToARGBRow_AVX2(src_y, src_u, src_v, row, yuvconstants, twidth); >@@ -2673,13 +3054,13 @@ void I422ToRGB24Row_AVX2(const uint8* src_y, > #endif > > #if defined(HAS_NV12TORGB565ROW_AVX2) >-void NV12ToRGB565Row_AVX2(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB565Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > // Row buffer for intermediate ARGB pixels. >- SIMD_ALIGNED(uint8 row[MAXTWIDTH * 4]); >+ SIMD_ALIGNED(uint8_t row[MAXTWIDTH * 4]); > while (width > 0) { > int twidth = width > MAXTWIDTH ? MAXTWIDTH : width; > NV12ToARGBRow_AVX2(src_y, src_uv, row, yuvconstants, twidth); >@@ -2729,7 +3110,7 @@ void ScaleSamples_C(const float* src, float* dst, float scale, int width) { > } > } > >-void GaussRow_C(const uint32* src, uint16* dst, int width) { >+void GaussRow_C(const uint32_t* src, uint16_t* dst, int width) { > int i; > for (i = 0; i < width; ++i) { > *dst++ = >@@ -2739,12 +3120,12 @@ void GaussRow_C(const uint32* src, uint16* dst, int width) { > } > > // filter 5 rows with 1, 4, 6, 4, 1 coefficients to produce 1 row. >-void GaussCol_C(const uint16* src0, >- const uint16* src1, >- const uint16* src2, >- const uint16* src3, >- const uint16* src4, >- uint32* dst, >+void GaussCol_C(const uint16_t* src0, >+ const uint16_t* src1, >+ const uint16_t* src2, >+ const uint16_t* src3, >+ const uint16_t* src4, >+ uint32_t* dst, > int width) { > int i; > for (i = 0; i < width; ++i) { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_dspr2.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_dspr2.cc >deleted file mode 100644 >index 11f78e0d2f1..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_dspr2.cc >+++ /dev/null >@@ -1,1721 +0,0 @@ >-/* >- * Copyright (c) 2012 The LibYuv 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 "libyuv/row.h" >- >-#ifdef __cplusplus >-namespace libyuv { >-extern "C" { >-#endif >- >-// The following are available on Mips platforms: >-#if !defined(LIBYUV_DISABLE_DSPR2) && defined(__mips__) && \ >- (_MIPS_SIM == _MIPS_SIM_ABI32) >- >-#ifdef HAS_COPYROW_MIPS >-void CopyRow_MIPS(const uint8* src, uint8* dst, int count) { >- __asm__ __volatile__( >- ".set noreorder \n" >- ".set noat \n" >- "slti $at, %[count], 8 \n" >- "bne $at ,$zero, $last8 \n" >- "xor $t8, %[src], %[dst] \n" >- "andi $t8, $t8, 0x3 \n" >- >- "bne $t8, $zero, unaligned \n" >- "negu $a3, %[dst] \n" >- // make dst/src aligned >- "andi $a3, $a3, 0x3 \n" >- "beq $a3, $zero, $chk16w \n" >- // word-aligned now count is the remining bytes count >- "subu %[count], %[count], $a3 \n" >- >- "lwr $t8, 0(%[src]) \n" >- "addu %[src], %[src], $a3 \n" >- "swr $t8, 0(%[dst]) \n" >- "addu %[dst], %[dst], $a3 \n" >- >- // Now the dst/src are mutually word-aligned with word-aligned addresses >- "$chk16w: \n" >- "andi $t8, %[count], 0x3f \n" // whole 64-B chunks? >- // t8 is the byte count after 64-byte chunks >- "beq %[count], $t8, chk8w \n" >- // There will be at most 1 32-byte chunk after it >- "subu $a3, %[count], $t8 \n" // the reminder >- // Here a3 counts bytes in 16w chunks >- "addu $a3, %[dst], $a3 \n" >- // Now a3 is the final dst after 64-byte chunks >- "addu $t0, %[dst], %[count] \n" >- // t0 is the "past the end" address >- >- // When in the loop we exercise "pref 30,x(a1)", the a1+x should not be >- // past >- // the "t0-32" address >- // This means: for x=128 the last "safe" a1 address is "t0-160" >- // Alternatively, for x=64 the last "safe" a1 address is "t0-96" >- // we will use "pref 30,128(a1)", so "t0-160" is the limit >- "subu $t9, $t0, 160 \n" >- // t9 is the "last safe pref 30,128(a1)" address >- "pref 0, 0(%[src]) \n" // first line of src >- "pref 0, 32(%[src]) \n" // second line of src >- "pref 0, 64(%[src]) \n" >- "pref 30, 32(%[dst]) \n" >- // In case the a1 > t9 don't use "pref 30" at all >- "sltu $v1, $t9, %[dst] \n" >- "bgtz $v1, $loop16w \n" >- "nop \n" >- // otherwise, start with using pref30 >- "pref 30, 64(%[dst]) \n" >- "$loop16w: \n" >- "pref 0, 96(%[src]) \n" >- "lw $t0, 0(%[src]) \n" >- "bgtz $v1, $skip_pref30_96 \n" // skip >- "lw $t1, 4(%[src]) \n" >- "pref 30, 96(%[dst]) \n" // continue >- "$skip_pref30_96: \n" >- "lw $t2, 8(%[src]) \n" >- "lw $t3, 12(%[src]) \n" >- "lw $t4, 16(%[src]) \n" >- "lw $t5, 20(%[src]) \n" >- "lw $t6, 24(%[src]) \n" >- "lw $t7, 28(%[src]) \n" >- "pref 0, 128(%[src]) \n" >- // bring the next lines of src, addr 128 >- "sw $t0, 0(%[dst]) \n" >- "sw $t1, 4(%[dst]) \n" >- "sw $t2, 8(%[dst]) \n" >- "sw $t3, 12(%[dst]) \n" >- "sw $t4, 16(%[dst]) \n" >- "sw $t5, 20(%[dst]) \n" >- "sw $t6, 24(%[dst]) \n" >- "sw $t7, 28(%[dst]) \n" >- "lw $t0, 32(%[src]) \n" >- "bgtz $v1, $skip_pref30_128 \n" // skip pref 30,128(a1) >- "lw $t1, 36(%[src]) \n" >- "pref 30, 128(%[dst]) \n" // set dest, addr 128 >- "$skip_pref30_128: \n" >- "lw $t2, 40(%[src]) \n" >- "lw $t3, 44(%[src]) \n" >- "lw $t4, 48(%[src]) \n" >- "lw $t5, 52(%[src]) \n" >- "lw $t6, 56(%[src]) \n" >- "lw $t7, 60(%[src]) \n" >- "pref 0, 160(%[src]) \n" >- // bring the next lines of src, addr 160 >- "sw $t0, 32(%[dst]) \n" >- "sw $t1, 36(%[dst]) \n" >- "sw $t2, 40(%[dst]) \n" >- "sw $t3, 44(%[dst]) \n" >- "sw $t4, 48(%[dst]) \n" >- "sw $t5, 52(%[dst]) \n" >- "sw $t6, 56(%[dst]) \n" >- "sw $t7, 60(%[dst]) \n" >- >- "addiu %[dst], %[dst], 64 \n" // adding 64 to dest >- "sltu $v1, $t9, %[dst] \n" >- "bne %[dst], $a3, $loop16w \n" >- " addiu %[src], %[src], 64 \n" // adding 64 to src >- "move %[count], $t8 \n" >- >- // Here we have src and dest word-aligned but less than 64-bytes to go >- >- "chk8w: \n" >- "pref 0, 0x0(%[src]) \n" >- "andi $t8, %[count], 0x1f \n" // 32-byte chunk? >- // the t8 is the reminder count past 32-bytes >- "beq %[count], $t8, chk1w \n" >- // count=t8,no 32-byte chunk >- " nop \n" >- >- "lw $t0, 0(%[src]) \n" >- "lw $t1, 4(%[src]) \n" >- "lw $t2, 8(%[src]) \n" >- "lw $t3, 12(%[src]) \n" >- "lw $t4, 16(%[src]) \n" >- "lw $t5, 20(%[src]) \n" >- "lw $t6, 24(%[src]) \n" >- "lw $t7, 28(%[src]) \n" >- "addiu %[src], %[src], 32 \n" >- >- "sw $t0, 0(%[dst]) \n" >- "sw $t1, 4(%[dst]) \n" >- "sw $t2, 8(%[dst]) \n" >- "sw $t3, 12(%[dst]) \n" >- "sw $t4, 16(%[dst]) \n" >- "sw $t5, 20(%[dst]) \n" >- "sw $t6, 24(%[dst]) \n" >- "sw $t7, 28(%[dst]) \n" >- "addiu %[dst], %[dst], 32 \n" >- >- "chk1w: \n" >- "andi %[count], $t8, 0x3 \n" >- // now count is the reminder past 1w chunks >- "beq %[count], $t8, $last8 \n" >- " subu $a3, $t8, %[count] \n" >- // a3 is count of bytes in 1w chunks >- "addu $a3, %[dst], $a3 \n" >- // now a3 is the dst address past the 1w chunks >- // copying in words (4-byte chunks) >- "$wordCopy_loop: \n" >- "lw $t3, 0(%[src]) \n" >- // the first t3 may be equal t0 ... optimize? >- "addiu %[src], %[src],4 \n" >- "addiu %[dst], %[dst],4 \n" >- "bne %[dst], $a3,$wordCopy_loop \n" >- " sw $t3, -4(%[dst]) \n" >- >- // For the last (<8) bytes >- "$last8: \n" >- "blez %[count], leave \n" >- " addu $a3, %[dst], %[count] \n" // a3 -last dst address >- "$last8loop: \n" >- "lb $v1, 0(%[src]) \n" >- "addiu %[src], %[src], 1 \n" >- "addiu %[dst], %[dst], 1 \n" >- "bne %[dst], $a3, $last8loop \n" >- " sb $v1, -1(%[dst]) \n" >- >- "leave: \n" >- " j $ra \n" >- " nop \n" >- >- // >- // UNALIGNED case >- // >- >- "unaligned: \n" >- // got here with a3="negu a1" >- "andi $a3, $a3, 0x3 \n" // a1 is word aligned? >- "beqz $a3, $ua_chk16w \n" >- " subu %[count], %[count], $a3 \n" >- // bytes left after initial a3 bytes >- "lwr $v1, 0(%[src]) \n" >- "lwl $v1, 3(%[src]) \n" >- "addu %[src], %[src], $a3 \n" // a3 may be 1, 2 or 3 >- "swr $v1, 0(%[dst]) \n" >- "addu %[dst], %[dst], $a3 \n" >- // below the dst will be word aligned (NOTE1) >- "$ua_chk16w: \n" >- "andi $t8, %[count], 0x3f \n" // whole 64-B chunks? >- // t8 is the byte count after 64-byte chunks >- "beq %[count], $t8, ua_chk8w \n" >- // if a2==t8, no 64-byte chunks >- // There will be at most 1 32-byte chunk after it >- "subu $a3, %[count], $t8 \n" // the reminder >- // Here a3 counts bytes in 16w chunks >- "addu $a3, %[dst], $a3 \n" >- // Now a3 is the final dst after 64-byte chunks >- "addu $t0, %[dst], %[count] \n" // t0 "past the end" >- "subu $t9, $t0, 160 \n" >- // t9 is the "last safe pref 30,128(a1)" address >- "pref 0, 0(%[src]) \n" // first line of src >- "pref 0, 32(%[src]) \n" // second line addr 32 >- "pref 0, 64(%[src]) \n" >- "pref 30, 32(%[dst]) \n" >- // safe, as we have at least 64 bytes ahead >- // In case the a1 > t9 don't use "pref 30" at all >- "sltu $v1, $t9, %[dst] \n" >- "bgtz $v1, $ua_loop16w \n" >- // skip "pref 30,64(a1)" for too short arrays >- " nop \n" >- // otherwise, start with using pref30 >- "pref 30, 64(%[dst]) \n" >- "$ua_loop16w: \n" >- "pref 0, 96(%[src]) \n" >- "lwr $t0, 0(%[src]) \n" >- "lwl $t0, 3(%[src]) \n" >- "lwr $t1, 4(%[src]) \n" >- "bgtz $v1, $ua_skip_pref30_96 \n" >- " lwl $t1, 7(%[src]) \n" >- "pref 30, 96(%[dst]) \n" >- // continue setting up the dest, addr 96 >- "$ua_skip_pref30_96: \n" >- "lwr $t2, 8(%[src]) \n" >- "lwl $t2, 11(%[src]) \n" >- "lwr $t3, 12(%[src]) \n" >- "lwl $t3, 15(%[src]) \n" >- "lwr $t4, 16(%[src]) \n" >- "lwl $t4, 19(%[src]) \n" >- "lwr $t5, 20(%[src]) \n" >- "lwl $t5, 23(%[src]) \n" >- "lwr $t6, 24(%[src]) \n" >- "lwl $t6, 27(%[src]) \n" >- "lwr $t7, 28(%[src]) \n" >- "lwl $t7, 31(%[src]) \n" >- "pref 0, 128(%[src]) \n" >- // bring the next lines of src, addr 128 >- "sw $t0, 0(%[dst]) \n" >- "sw $t1, 4(%[dst]) \n" >- "sw $t2, 8(%[dst]) \n" >- "sw $t3, 12(%[dst]) \n" >- "sw $t4, 16(%[dst]) \n" >- "sw $t5, 20(%[dst]) \n" >- "sw $t6, 24(%[dst]) \n" >- "sw $t7, 28(%[dst]) \n" >- "lwr $t0, 32(%[src]) \n" >- "lwl $t0, 35(%[src]) \n" >- "lwr $t1, 36(%[src]) \n" >- "bgtz $v1, ua_skip_pref30_128 \n" >- " lwl $t1, 39(%[src]) \n" >- "pref 30, 128(%[dst]) \n" >- // continue setting up the dest, addr 128 >- "ua_skip_pref30_128: \n" >- >- "lwr $t2, 40(%[src]) \n" >- "lwl $t2, 43(%[src]) \n" >- "lwr $t3, 44(%[src]) \n" >- "lwl $t3, 47(%[src]) \n" >- "lwr $t4, 48(%[src]) \n" >- "lwl $t4, 51(%[src]) \n" >- "lwr $t5, 52(%[src]) \n" >- "lwl $t5, 55(%[src]) \n" >- "lwr $t6, 56(%[src]) \n" >- "lwl $t6, 59(%[src]) \n" >- "lwr $t7, 60(%[src]) \n" >- "lwl $t7, 63(%[src]) \n" >- "pref 0, 160(%[src]) \n" >- // bring the next lines of src, addr 160 >- "sw $t0, 32(%[dst]) \n" >- "sw $t1, 36(%[dst]) \n" >- "sw $t2, 40(%[dst]) \n" >- "sw $t3, 44(%[dst]) \n" >- "sw $t4, 48(%[dst]) \n" >- "sw $t5, 52(%[dst]) \n" >- "sw $t6, 56(%[dst]) \n" >- "sw $t7, 60(%[dst]) \n" >- >- "addiu %[dst],%[dst],64 \n" // adding 64 to dest >- "sltu $v1,$t9,%[dst] \n" >- "bne %[dst],$a3,$ua_loop16w \n" >- " addiu %[src],%[src],64 \n" // adding 64 to src >- "move %[count],$t8 \n" >- >- // Here we have src and dest word-aligned but less than 64-bytes to go >- >- "ua_chk8w: \n" >- "pref 0, 0x0(%[src]) \n" >- "andi $t8, %[count], 0x1f \n" // 32-byte chunk? >- // the t8 is the reminder count >- "beq %[count], $t8, $ua_chk1w \n" >- // when count==t8, no 32-byte chunk >- >- "lwr $t0, 0(%[src]) \n" >- "lwl $t0, 3(%[src]) \n" >- "lwr $t1, 4(%[src]) \n" >- "lwl $t1, 7(%[src]) \n" >- "lwr $t2, 8(%[src]) \n" >- "lwl $t2, 11(%[src]) \n" >- "lwr $t3, 12(%[src]) \n" >- "lwl $t3, 15(%[src]) \n" >- "lwr $t4, 16(%[src]) \n" >- "lwl $t4, 19(%[src]) \n" >- "lwr $t5, 20(%[src]) \n" >- "lwl $t5, 23(%[src]) \n" >- "lwr $t6, 24(%[src]) \n" >- "lwl $t6, 27(%[src]) \n" >- "lwr $t7, 28(%[src]) \n" >- "lwl $t7, 31(%[src]) \n" >- "addiu %[src], %[src], 32 \n" >- >- "sw $t0, 0(%[dst]) \n" >- "sw $t1, 4(%[dst]) \n" >- "sw $t2, 8(%[dst]) \n" >- "sw $t3, 12(%[dst]) \n" >- "sw $t4, 16(%[dst]) \n" >- "sw $t5, 20(%[dst]) \n" >- "sw $t6, 24(%[dst]) \n" >- "sw $t7, 28(%[dst]) \n" >- "addiu %[dst], %[dst], 32 \n" >- >- "$ua_chk1w: \n" >- "andi %[count], $t8, 0x3 \n" >- // now count is the reminder past 1w chunks >- "beq %[count], $t8, ua_smallCopy \n" >- "subu $a3, $t8, %[count] \n" >- // a3 is count of bytes in 1w chunks >- "addu $a3, %[dst], $a3 \n" >- // now a3 is the dst address past the 1w chunks >- >- // copying in words (4-byte chunks) >- "$ua_wordCopy_loop: \n" >- "lwr $v1, 0(%[src]) \n" >- "lwl $v1, 3(%[src]) \n" >- "addiu %[src], %[src], 4 \n" >- "addiu %[dst], %[dst], 4 \n" >- // note: dst=a1 is word aligned here, see NOTE1 >- "bne %[dst], $a3, $ua_wordCopy_loop \n" >- " sw $v1,-4(%[dst]) \n" >- >- // Now less than 4 bytes (value in count) left to copy >- "ua_smallCopy: \n" >- "beqz %[count], leave \n" >- " addu $a3, %[dst], %[count] \n" // a3 = last dst address >- "$ua_smallCopy_loop: \n" >- "lb $v1, 0(%[src]) \n" >- "addiu %[src], %[src], 1 \n" >- "addiu %[dst], %[dst], 1 \n" >- "bne %[dst],$a3,$ua_smallCopy_loop \n" >- " sb $v1, -1(%[dst]) \n" >- >- "j $ra \n" >- " nop \n" >- ".set at \n" >- ".set reorder \n" >- : [dst] "+r"(dst), [src] "+r"(src) >- : [count] "r"(count) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "a3", "v1", >- "at"); >-} >-#endif // HAS_COPYROW_MIPS >- >-// DSPR2 functions >-#if !defined(LIBYUV_DISABLE_DSPR2) && defined(__mips_dsp) && \ >- (__mips_dsp_rev >= 2) && (_MIPS_SIM == _MIPS_SIM_ABI32) && \ >- (__mips_isa_rev < 6) >- >-void SplitUVRow_DSPR2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "srl $t4, %[width], 4 \n" // multiplies of 16 >- "blez $t4, 2f \n" >- " andi %[width], %[width], 0xf \n" // residual >- >- "1: \n" >- "addiu $t4, $t4, -1 \n" >- "lw $t0, 0(%[src_uv]) \n" // V1 | U1 | V0 | U0 >- "lw $t1, 4(%[src_uv]) \n" // V3 | U3 | V2 | U2 >- "lw $t2, 8(%[src_uv]) \n" // V5 | U5 | V4 | U4 >- "lw $t3, 12(%[src_uv]) \n" // V7 | U7 | V6 | U6 >- "lw $t5, 16(%[src_uv]) \n" // V9 | U9 | V8 | U8 >- "lw $t6, 20(%[src_uv]) \n" // V11 | U11 | V10 | >- // U10 >- "lw $t7, 24(%[src_uv]) \n" // V13 | U13 | V12 | >- // U12 >- "lw $t8, 28(%[src_uv]) \n" // V15 | U15 | V14 | >- // U14 >- "addiu %[src_uv], %[src_uv], 32 \n" >- "precrq.qb.ph $t9, $t1, $t0 \n" // V3 | V2 | V1 | V0 >- "precr.qb.ph $t0, $t1, $t0 \n" // U3 | U2 | U1 | U0 >- "precrq.qb.ph $t1, $t3, $t2 \n" // V7 | V6 | V5 | V4 >- "precr.qb.ph $t2, $t3, $t2 \n" // U7 | U6 | U5 | U4 >- "precrq.qb.ph $t3, $t6, $t5 \n" // V11 | V10 | V9 | V8 >- "precr.qb.ph $t5, $t6, $t5 \n" // U11 | U10 | U9 | U8 >- "precrq.qb.ph $t6, $t8, $t7 \n" // V15 | V14 | V13 | >- // V12 >- "precr.qb.ph $t7, $t8, $t7 \n" // U15 | U14 | U13 | >- // U12 >- "sw $t9, 0(%[dst_v]) \n" >- "sw $t0, 0(%[dst_u]) \n" >- "sw $t1, 4(%[dst_v]) \n" >- "sw $t2, 4(%[dst_u]) \n" >- "sw $t3, 8(%[dst_v]) \n" >- "sw $t5, 8(%[dst_u]) \n" >- "sw $t6, 12(%[dst_v]) \n" >- "sw $t7, 12(%[dst_u]) \n" >- "addiu %[dst_v], %[dst_v], 16 \n" >- "bgtz $t4, 1b \n" >- " addiu %[dst_u], %[dst_u], 16 \n" >- >- "beqz %[width], 3f \n" >- " nop \n" >- >- "2: \n" >- "lbu $t0, 0(%[src_uv]) \n" >- "lbu $t1, 1(%[src_uv]) \n" >- "addiu %[src_uv], %[src_uv], 2 \n" >- "addiu %[width], %[width], -1 \n" >- "sb $t0, 0(%[dst_u]) \n" >- "sb $t1, 0(%[dst_v]) \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "bgtz %[width], 2b \n" >- " addiu %[dst_v], %[dst_v], 1 \n" >- >- "3: \n" >- ".set pop \n" >- : [src_uv] "+r"(src_uv), [width] "+r"(width), [dst_u] "+r"(dst_u), >- [dst_v] "+r"(dst_v) >- : >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void MirrorRow_DSPR2(const uint8* src, uint8* dst, int width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "srl $t4, %[width], 4 \n" // multiplies of 16 >- "andi $t5, %[width], 0xf \n" >- "blez $t4, 2f \n" >- " addu %[src], %[src], %[width] \n" // src += width >- >- "1: \n" >- "lw $t0, -16(%[src]) \n" // |3|2|1|0| >- "lw $t1, -12(%[src]) \n" // |7|6|5|4| >- "lw $t2, -8(%[src]) \n" // |11|10|9|8| >- "lw $t3, -4(%[src]) \n" // |15|14|13|12| >- "wsbh $t0, $t0 \n" // |2|3|0|1| >- "wsbh $t1, $t1 \n" // |6|7|4|5| >- "wsbh $t2, $t2 \n" // |10|11|8|9| >- "wsbh $t3, $t3 \n" // |14|15|12|13| >- "rotr $t0, $t0, 16 \n" // |0|1|2|3| >- "rotr $t1, $t1, 16 \n" // |4|5|6|7| >- "rotr $t2, $t2, 16 \n" // |8|9|10|11| >- "rotr $t3, $t3, 16 \n" // |12|13|14|15| >- "addiu %[src], %[src], -16 \n" >- "addiu $t4, $t4, -1 \n" >- "sw $t3, 0(%[dst]) \n" // |15|14|13|12| >- "sw $t2, 4(%[dst]) \n" // |11|10|9|8| >- "sw $t1, 8(%[dst]) \n" // |7|6|5|4| >- "sw $t0, 12(%[dst]) \n" // |3|2|1|0| >- "bgtz $t4, 1b \n" >- " addiu %[dst], %[dst], 16 \n" >- "beqz $t5, 3f \n" >- " nop \n" >- >- "2: \n" >- "lbu $t0, -1(%[src]) \n" >- "addiu $t5, $t5, -1 \n" >- "addiu %[src], %[src], -1 \n" >- "sb $t0, 0(%[dst]) \n" >- "bgez $t5, 2b \n" >- " addiu %[dst], %[dst], 1 \n" >- >- "3: \n" >- ".set pop \n" >- : [src] "+r"(src), [dst] "+r"(dst) >- : [width] "r"(width) >- : "t0", "t1", "t2", "t3", "t4", "t5"); >-} >- >-void MirrorUVRow_DSPR2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- int x; >- int y; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "addu $t4, %[width], %[width] \n" >- "srl %[x], %[width], 4 \n" >- "andi %[y], %[width], 0xf \n" >- "blez %[x], 2f \n" >- " addu %[src_uv], %[src_uv], $t4 \n" >- >- "1: \n" >- "lw $t0, -32(%[src_uv]) \n" // |3|2|1|0| >- "lw $t1, -28(%[src_uv]) \n" // |7|6|5|4| >- "lw $t2, -24(%[src_uv]) \n" // |11|10|9|8| >- "lw $t3, -20(%[src_uv]) \n" // |15|14|13|12| >- "lw $t4, -16(%[src_uv]) \n" // |19|18|17|16| >- "lw $t6, -12(%[src_uv]) \n" // |23|22|21|20| >- "lw $t7, -8(%[src_uv]) \n" // |27|26|25|24| >- "lw $t8, -4(%[src_uv]) \n" // |31|30|29|28| >- >- "rotr $t0, $t0, 16 \n" // |1|0|3|2| >- "rotr $t1, $t1, 16 \n" // |5|4|7|6| >- "rotr $t2, $t2, 16 \n" // |9|8|11|10| >- "rotr $t3, $t3, 16 \n" // |13|12|15|14| >- "rotr $t4, $t4, 16 \n" // |17|16|19|18| >- "rotr $t6, $t6, 16 \n" // |21|20|23|22| >- "rotr $t7, $t7, 16 \n" // |25|24|27|26| >- "rotr $t8, $t8, 16 \n" // |29|28|31|30| >- "precr.qb.ph $t9, $t0, $t1 \n" // |0|2|4|6| >- "precrq.qb.ph $t5, $t0, $t1 \n" // |1|3|5|7| >- "precr.qb.ph $t0, $t2, $t3 \n" // |8|10|12|14| >- "precrq.qb.ph $t1, $t2, $t3 \n" // |9|11|13|15| >- "precr.qb.ph $t2, $t4, $t6 \n" // |16|18|20|22| >- "precrq.qb.ph $t3, $t4, $t6 \n" // |17|19|21|23| >- "precr.qb.ph $t4, $t7, $t8 \n" // |24|26|28|30| >- "precrq.qb.ph $t6, $t7, $t8 \n" // |25|27|29|31| >- "addiu %[src_uv], %[src_uv], -32 \n" >- "addiu %[x], %[x], -1 \n" >- "swr $t4, 0(%[dst_u]) \n" >- "swl $t4, 3(%[dst_u]) \n" // |30|28|26|24| >- "swr $t6, 0(%[dst_v]) \n" >- "swl $t6, 3(%[dst_v]) \n" // |31|29|27|25| >- "swr $t2, 4(%[dst_u]) \n" >- "swl $t2, 7(%[dst_u]) \n" // |22|20|18|16| >- "swr $t3, 4(%[dst_v]) \n" >- "swl $t3, 7(%[dst_v]) \n" // |23|21|19|17| >- "swr $t0, 8(%[dst_u]) \n" >- "swl $t0, 11(%[dst_u]) \n" // |14|12|10|8| >- "swr $t1, 8(%[dst_v]) \n" >- "swl $t1, 11(%[dst_v]) \n" // |15|13|11|9| >- "swr $t9, 12(%[dst_u]) \n" >- "swl $t9, 15(%[dst_u]) \n" // |6|4|2|0| >- "swr $t5, 12(%[dst_v]) \n" >- "swl $t5, 15(%[dst_v]) \n" // |7|5|3|1| >- "addiu %[dst_v], %[dst_v], 16 \n" >- "bgtz %[x], 1b \n" >- " addiu %[dst_u], %[dst_u], 16 \n" >- "beqz %[y], 3f \n" >- " nop \n" >- "b 2f \n" >- " nop \n" >- >- "2: \n" >- "lbu $t0, -2(%[src_uv]) \n" >- "lbu $t1, -1(%[src_uv]) \n" >- "addiu %[src_uv], %[src_uv], -2 \n" >- "addiu %[y], %[y], -1 \n" >- "sb $t0, 0(%[dst_u]) \n" >- "sb $t1, 0(%[dst_v]) \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "bgtz %[y], 2b \n" >- " addiu %[dst_v], %[dst_v], 1 \n" >- >- "3: \n" >- ".set pop \n" >- : [src_uv] "+r"(src_uv), [dst_u] "+r"(dst_u), [dst_v] "+r"(dst_v), >- [x] "=&r"(x), [y] "=&r"(y) >- : [width] "r"(width) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t7", "t8", "t9"); >-} >- >-void I422ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, >- int width) { >- int x; >- uint32 tmp_ub = yuvconstants->kUVToB[0]; >- uint32 tmp_ug = yuvconstants->kUVToG[0]; >- uint32 tmp_vg = yuvconstants->kUVToG[1]; >- uint32 tmp_vr = yuvconstants->kUVToR[1]; >- uint32 tmp_bb = yuvconstants->kUVBiasB[0]; >- uint32 tmp_bg = yuvconstants->kUVBiasG[0]; >- uint32 tmp_br = yuvconstants->kUVBiasR[0]; >- uint32 yg = yuvconstants->kYToRgb[0]; >- uint32 tmp_yg; >- uint32 tmp_mask = 0x7fff7fff; >- tmp_bb = ((uint)(tmp_bb & 0xffff) << 16) | (tmp_bb & 0xffff); >- tmp_bg = ((uint)(tmp_bg & 0xffff) << 16) | (tmp_bg & 0xffff); >- tmp_br = ((uint)(tmp_br & 0xffff) << 16) | (tmp_br & 0xffff); >- tmp_yg = ((uint)(yg & 0xffff) << 16) | (yg & 0xffff); >- tmp_ub = ~(((uint)(tmp_ub & 0xffff) << 16) | (tmp_ub & 0xffff)) + 0x00010001; >- tmp_ug = ((uint)(tmp_ug & 0xffff) << 16) | (tmp_ug & 0xffff); >- tmp_vg = ((uint)(tmp_vg & 0xffff) << 16) | (tmp_vg & 0xffff); >- tmp_vr = ~(((uint)(tmp_vr & 0xffff) << 16) | (tmp_vr & 0xffff)) + 0x00010001; >- yg = yg * 0x0101; >- >- for (x = 0; x < width - 1; x += 2) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- uint32 tmp_t6, tmp_t7, tmp_t8, tmp_t9; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lbu %[tmp_t7], 0(%[src_y]) \n" >- "lbu %[tmp_t1], 1(%[src_y]) \n" >- "mul %[tmp_t7], %[tmp_t7], %[yg] \n" >- "mul %[tmp_t1], %[tmp_t1], %[yg] \n" >- "lbu %[tmp_t2], 0(%[src_u]) \n" >- "lbu %[tmp_t3], 0(%[src_v]) \n" >- "replv.ph %[tmp_t2], %[tmp_t2] \n" >- "replv.ph %[tmp_t3], %[tmp_t3] \n" >- "mul.ph %[tmp_t4], %[tmp_t2], %[tmp_ub] \n" >- "mul.ph %[tmp_t5], %[tmp_t2], %[tmp_ug] \n" >- "mul.ph %[tmp_t6], %[tmp_t3], %[tmp_vr] \n" >- "mul.ph %[tmp_t3], %[tmp_t3], %[tmp_vg] \n" >- "srl %[tmp_t7], %[tmp_t7], 16 \n" >- "ins %[tmp_t1], %[tmp_t7], 0, 16 \n" >- "addq_s.ph %[tmp_t7], %[tmp_t1], %[tmp_bb] \n" >- "addq_s.ph %[tmp_t8], %[tmp_t1], %[tmp_bg] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t1], %[tmp_br] \n" >- "addq_s.ph %[tmp_t5], %[tmp_t5], %[tmp_t3] \n" >- "addq_s.ph %[tmp_t7], %[tmp_t7], %[tmp_t4] \n" >- "subq_s.ph %[tmp_t8], %[tmp_t8], %[tmp_t5] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t9], %[tmp_t6] \n" >- "shra.ph %[tmp_t7], %[tmp_t7], 6 \n" >- "shra.ph %[tmp_t8], %[tmp_t8], 6 \n" >- "shra.ph %[tmp_t9], %[tmp_t9], 6 \n" >- "shll_s.ph %[tmp_t7], %[tmp_t7], 7 \n" >- "shll_s.ph %[tmp_t8], %[tmp_t8], 7 \n" >- "shll_s.ph %[tmp_t9], %[tmp_t9], 7 \n" >- "precrqu_s.qb.ph %[tmp_t8], %[tmp_mask], %[tmp_t8] \n" >- "precrqu_s.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "precrq.ph.w %[tmp_t9], %[tmp_t8], %[tmp_t7] \n" >- "ins %[tmp_t7], %[tmp_t8], 16, 16 \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t9], %[tmp_t7] \n" >- "precrq.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "sw %[tmp_t8], 0(%[rgb_buf]) \n" >- "sw %[tmp_t7], 4(%[rgb_buf]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [tmp_t9] "=&r"(tmp_t9) >- : [src_y] "r"(src_y), [src_u] "r"(src_u), [src_v] "r"(src_v), >- [tmp_ub] "r"(tmp_ub), [tmp_ug] "r"(tmp_ug), [yg] "r"(yg), >- [tmp_vg] "r"(tmp_vg), [tmp_vr] "r"(tmp_vr), [tmp_bb] "r"(tmp_bb), >- [tmp_bg] "r"(tmp_bg), [tmp_br] "r"(tmp_br), [tmp_yg] "r"(tmp_yg), >- [rgb_buf] "r"(rgb_buf), [tmp_mask] "r"(tmp_mask)); >- src_y += 2; >- src_u += 1; >- src_v += 1; >- rgb_buf += 8; // Advance 4 pixels. >- } >-} >- >-// Bilinear filter 8x2 -> 8x1 >-void InterpolateRow_DSPR2(uint8* dst_ptr, >- const uint8* src_ptr, >- ptrdiff_t src_stride, >- int dst_width, >- int source_y_fraction) { >- int y0_fraction = 256 - source_y_fraction; >- const uint8* src_ptr1 = src_ptr + src_stride; >- >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "replv.ph $t0, %[y0_fraction] \n" >- "replv.ph $t1, %[source_y_fraction] \n" >- >- "1: \n" >- "lw $t2, 0(%[src_ptr]) \n" >- "lw $t3, 0(%[src_ptr1]) \n" >- "lw $t4, 4(%[src_ptr]) \n" >- "lw $t5, 4(%[src_ptr1]) \n" >- "muleu_s.ph.qbl $t6, $t2, $t0 \n" >- "muleu_s.ph.qbr $t7, $t2, $t0 \n" >- "muleu_s.ph.qbl $t8, $t3, $t1 \n" >- "muleu_s.ph.qbr $t9, $t3, $t1 \n" >- "muleu_s.ph.qbl $t2, $t4, $t0 \n" >- "muleu_s.ph.qbr $t3, $t4, $t0 \n" >- "muleu_s.ph.qbl $t4, $t5, $t1 \n" >- "muleu_s.ph.qbr $t5, $t5, $t1 \n" >- "addq.ph $t6, $t6, $t8 \n" >- "addq.ph $t7, $t7, $t9 \n" >- "addq.ph $t2, $t2, $t4 \n" >- "addq.ph $t3, $t3, $t5 \n" >- "shra_r.ph $t6, $t6, 8 \n" >- "shra_r.ph $t7, $t7, 8 \n" >- "shra_r.ph $t2, $t2, 8 \n" >- "shra_r.ph $t3, $t3, 8 \n" >- "precr.qb.ph $t6, $t6, $t7 \n" >- "precr.qb.ph $t2, $t2, $t3 \n" >- "addiu %[src_ptr], %[src_ptr], 8 \n" >- "addiu %[src_ptr1], %[src_ptr1], 8 \n" >- "addiu %[dst_width], %[dst_width], -8 \n" >- "sw $t6, 0(%[dst_ptr]) \n" >- "sw $t2, 4(%[dst_ptr]) \n" >- "bgtz %[dst_width], 1b \n" >- " addiu %[dst_ptr], %[dst_ptr], 8 \n" >- >- ".set pop \n" >- : [dst_ptr] "+r"(dst_ptr), [src_ptr1] "+r"(src_ptr1), >- [src_ptr] "+r"(src_ptr), [dst_width] "+r"(dst_width) >- : [source_y_fraction] "r"(source_y_fraction), >- [y0_fraction] "r"(y0_fraction), [src_stride] "r"(src_stride) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >-#include <stdio.h> >-void RGB24ToARGBRow_DSPR2(const uint8* src_rgb24, uint8* dst_argb, int width) { >- int x; >- uint32 tmp_mask = 0xff; >- uint32 tmp_t1; >- for (x = 0; x < (width - 1); ++x) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "ulw %[tmp_t1], 0(%[src_rgb24]) \n" >- "addiu %[dst_argb], %[dst_argb], 4 \n" >- "addiu %[src_rgb24], %[src_rgb24], 3 \n" >- "ins %[tmp_t1], %[tmp_mask], 24, 8 \n" >- "sw %[tmp_t1], -4(%[dst_argb]) \n" >- ".set pop \n" >- : [src_rgb24] "+r"(src_rgb24), [dst_argb] "+r"(dst_argb), >- [tmp_t1] "=&r"(tmp_t1) >- : [tmp_mask] "r"(tmp_mask) >- : "memory"); >- } >- uint8 b = src_rgb24[0]; >- uint8 g = src_rgb24[1]; >- uint8 r = src_rgb24[2]; >- dst_argb[0] = b; >- dst_argb[1] = g; >- dst_argb[2] = r; >- dst_argb[3] = 255u; >-} >- >-void RAWToARGBRow_DSPR2(const uint8* src_raw, uint8* dst_argb, int width) { >- int x; >- uint32 tmp_mask = 0xff; >- uint32 tmp_t1, tmp_t2; >- for (x = 0; x < (width - 1); ++x) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "ulw %[tmp_t1], 0(%[src_raw]) \n" >- "addiu %[dst_argb], %[dst_argb], 4 \n" >- "addiu %[src_raw], %[src_raw], 3 \n" >- "srl %[tmp_t2], %[tmp_t1], 16 \n" >- "ins %[tmp_t1], %[tmp_mask], 24, 8 \n" >- "ins %[tmp_t1], %[tmp_t1], 16, 8 \n" >- "ins %[tmp_t1], %[tmp_t2], 0, 8 \n" >- "sw %[tmp_t1], -4(%[dst_argb]) \n" >- ".set pop \n" >- : [src_raw] "+r"(src_raw), [dst_argb] "+r"(dst_argb), >- [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2) >- : [tmp_mask] "r"(tmp_mask) >- : "memory"); >- } >- uint8 r = src_raw[0]; >- uint8 g = src_raw[1]; >- uint8 b = src_raw[2]; >- dst_argb[0] = b; >- dst_argb[1] = g; >- dst_argb[2] = r; >- dst_argb[3] = 255u; >-} >- >-void RGB565ToARGBRow_DSPR2(const uint8* src_rgb565, >- uint8* dst_argb, >- int width) { >- int x; >- uint32 tmp_mask = 0xff; >- uint32 tmp_t1, tmp_t2, tmp_t3; >- for (x = 0; x < width; ++x) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lhu %[tmp_t1], 0(%[src_rgb565]) \n" >- "addiu %[dst_argb], %[dst_argb], 4 \n" >- "addiu %[src_rgb565], %[src_rgb565], 2 \n" >- "sll %[tmp_t2], %[tmp_t1], 8 \n" >- "ins %[tmp_t2], %[tmp_mask], 24,8 \n" >- "ins %[tmp_t2], %[tmp_t1], 3, 16 \n" >- "ins %[tmp_t2], %[tmp_t1], 5, 11 \n" >- "srl %[tmp_t3], %[tmp_t1], 9 \n" >- "ins %[tmp_t2], %[tmp_t3], 8, 2 \n" >- "ins %[tmp_t2], %[tmp_t1], 3, 5 \n" >- "srl %[tmp_t3], %[tmp_t1], 2 \n" >- "ins %[tmp_t2], %[tmp_t3], 0, 3 \n" >- "sw %[tmp_t2], -4(%[dst_argb]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [src_rgb565] "+r"(src_rgb565), >- [dst_argb] "+r"(dst_argb) >- : [tmp_mask] "r"(tmp_mask)); >- } >-} >- >-void ARGB1555ToARGBRow_DSPR2(const uint8* src_argb1555, >- uint8* dst_argb, >- int width) { >- int x; >- uint32 tmp_t1, tmp_t2, tmp_t3; >- for (x = 0; x < width; ++x) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lh %[tmp_t1], 0(%[src_argb1555]) \n" >- "addiu %[dst_argb], %[dst_argb], 4 \n" >- "addiu %[src_argb1555], %[src_argb1555], 2 \n" >- "sll %[tmp_t2], %[tmp_t1], 9 \n" >- "ins %[tmp_t2], %[tmp_t1], 4, 15 \n" >- "ins %[tmp_t2], %[tmp_t1], 6, 10 \n" >- "srl %[tmp_t3], %[tmp_t1], 7 \n" >- "ins %[tmp_t2], %[tmp_t3], 8, 3 \n" >- "ins %[tmp_t2], %[tmp_t1], 3, 5 \n" >- "srl %[tmp_t3], %[tmp_t1], 2 \n" >- "ins %[tmp_t2], %[tmp_t3], 0, 3 \n" >- "sw %[tmp_t2], -4(%[dst_argb]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [src_argb1555] "+r"(src_argb1555), >- [dst_argb] "+r"(dst_argb) >- :); >- } >-} >- >-void ARGB4444ToARGBRow_DSPR2(const uint8* src_argb4444, >- uint8* dst_argb, >- int width) { >- int x; >- uint32 tmp_t1; >- for (x = 0; x < width; ++x) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lh %[tmp_t1], 0(%[src_argb4444]) \n" >- "addiu %[dst_argb], %[dst_argb], 4 \n" >- "addiu %[src_argb4444], %[src_argb4444], 2 \n" >- "ins %[tmp_t1], %[tmp_t1], 16, 16 \n" >- "ins %[tmp_t1], %[tmp_t1], 12, 16 \n" >- "ins %[tmp_t1], %[tmp_t1], 8, 12 \n" >- "ins %[tmp_t1], %[tmp_t1], 4, 8 \n" >- "sw %[tmp_t1], -4(%[dst_argb]) \n" >- ".set pop \n" >- : [src_argb4444] "+r"(src_argb4444), [dst_argb] "+r"(dst_argb), >- [tmp_t1] "=&r"(tmp_t1)); >- } >-} >- >-void I444ToARGBRow_DSPR2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, >- int width) { >- int x; >- uint32 tmp_ub = yuvconstants->kUVToB[0]; >- uint32 tmp_ug = yuvconstants->kUVToG[0]; >- uint32 tmp_vg = yuvconstants->kUVToG[1]; >- uint32 tmp_vr = yuvconstants->kUVToR[1]; >- uint32 tmp_bb = yuvconstants->kUVBiasB[0]; >- uint32 tmp_bg = yuvconstants->kUVBiasG[0]; >- uint32 tmp_br = yuvconstants->kUVBiasR[0]; >- uint32 yg = yuvconstants->kYToRgb[0]; >- uint32 tmp_mask = 0x7fff7fff; >- uint32 tmp_yg; >- >- tmp_bb = ((uint)(tmp_bb & 0xffff) << 16) | (tmp_bb & 0xffff); >- tmp_bg = ((uint)(tmp_bg & 0xffff) << 16) | (tmp_bg & 0xffff); >- tmp_br = ((uint)(tmp_br & 0xffff) << 16) | (tmp_br & 0xffff); >- tmp_yg = ((uint)(yg & 0xffff) << 16) | (yg & 0xffff); >- tmp_ub = ~(((uint)(tmp_ub & 0xffff) << 16) | (tmp_ub & 0xffff)) + 0x00010001; >- tmp_ug = ((uint)(tmp_ug & 0xffff) << 16) | (tmp_ug & 0xffff); >- tmp_vg = ((uint)(tmp_vg & 0xffff) << 16) | (tmp_vg & 0xffff); >- tmp_vr = ~(((uint)(tmp_vr & 0xffff) << 16) | (tmp_vr & 0xffff)) + 0x00010001; >- yg = yg * 0x0101; >- >- for (x = 0; x < width - 1; x += 2) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- uint32 tmp_t6, tmp_t7, tmp_t8, tmp_t9; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lbu %[tmp_t7], 0(%[y_buf]) \n" >- "lbu %[tmp_t1], 1(%[y_buf]) \n" >- "mul %[tmp_t7], %[tmp_t7], %[yg] \n" >- "mul %[tmp_t1], %[tmp_t1], %[yg] \n" >- "lh %[tmp_t2], 0(%[u_buf]) \n" >- "lh %[tmp_t3], 0(%[v_buf]) \n" >- "preceu.ph.qbr %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t3], %[tmp_t3] \n" >- "mul.ph %[tmp_t4], %[tmp_t2], %[tmp_ub] \n" >- "mul.ph %[tmp_t5], %[tmp_t2], %[tmp_ug] \n" >- "mul.ph %[tmp_t6], %[tmp_t3], %[tmp_vr] \n" >- "mul.ph %[tmp_t3], %[tmp_t3], %[tmp_vg] \n" >- "srl %[tmp_t7], %[tmp_t7], 16 \n" >- "ins %[tmp_t1], %[tmp_t7], 0, 16 \n" >- "addq_s.ph %[tmp_t7], %[tmp_t1], %[tmp_bb] \n" >- "addq_s.ph %[tmp_t8], %[tmp_t1], %[tmp_bg] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t1], %[tmp_br] \n" >- "addq_s.ph %[tmp_t5], %[tmp_t5], %[tmp_t3] \n" >- "addq_s.ph %[tmp_t7], %[tmp_t7], %[tmp_t4] \n" >- "subq_s.ph %[tmp_t8], %[tmp_t8], %[tmp_t5] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t9], %[tmp_t6] \n" >- "shra.ph %[tmp_t7], %[tmp_t7], 6 \n" >- "shra.ph %[tmp_t8], %[tmp_t8], 6 \n" >- "shra.ph %[tmp_t9], %[tmp_t9], 6 \n" >- "shll_s.ph %[tmp_t7], %[tmp_t7], 7 \n" >- "shll_s.ph %[tmp_t8], %[tmp_t8], 7 \n" >- "shll_s.ph %[tmp_t9], %[tmp_t9], 7 \n" >- "precrqu_s.qb.ph %[tmp_t8], %[tmp_mask], %[tmp_t8] \n" >- "precrqu_s.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "precrq.ph.w %[tmp_t2], %[tmp_t8], %[tmp_t7] \n" >- "ins %[tmp_t7], %[tmp_t8], 16, 16 \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t2], %[tmp_t7] \n" >- "precrq.qb.ph %[tmp_t7], %[tmp_t2], %[tmp_t7] \n" >- "sw %[tmp_t8], 0(%[rgb_buf]) \n" >- "sw %[tmp_t7], 4(%[rgb_buf]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [tmp_t9] "=&r"(tmp_t9) >- : [y_buf] "r"(y_buf), [yg] "r"(yg), [u_buf] "r"(u_buf), >- [v_buf] "r"(v_buf), [tmp_ub] "r"(tmp_ub), [tmp_ug] "r"(tmp_ug), >- [tmp_vg] "r"(tmp_vg), [tmp_vr] "r"(tmp_vr), [tmp_bb] "r"(tmp_bb), >- [tmp_bg] "r"(tmp_bg), [tmp_br] "r"(tmp_br), [tmp_yg] "r"(tmp_yg), >- [rgb_buf] "r"(rgb_buf), [tmp_mask] "r"(tmp_mask)); >- y_buf += 2; >- u_buf += 2; >- v_buf += 2; >- rgb_buf += 8; // Advance 1 pixel. >- } >-} >- >-void I422ToARGB4444Row_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >- const struct YuvConstants* yuvconstants, >- int width) { >- int x; >- uint32 tmp_ub = yuvconstants->kUVToB[0]; >- uint32 tmp_ug = yuvconstants->kUVToG[0]; >- uint32 tmp_vg = yuvconstants->kUVToG[1]; >- uint32 tmp_vr = yuvconstants->kUVToR[1]; >- uint32 tmp_bb = yuvconstants->kUVBiasB[0]; >- uint32 tmp_bg = yuvconstants->kUVBiasG[0]; >- uint32 tmp_br = yuvconstants->kUVBiasR[0]; >- uint32 yg = yuvconstants->kYToRgb[0]; >- uint32 tmp_yg; >- uint32 tmp_mask = 0x7fff7fff; >- tmp_bb = ((uint)(tmp_bb & 0xffff) << 16) | (tmp_bb & 0xffff); >- tmp_bg = ((uint)(tmp_bg & 0xffff) << 16) | (tmp_bg & 0xffff); >- tmp_br = ((uint)(tmp_br & 0xffff) << 16) | (tmp_br & 0xffff); >- tmp_yg = ((uint)(yg & 0xffff) << 16) | (yg & 0xffff); >- tmp_ub = ~(((uint)(tmp_ub & 0xffff) << 16) | (tmp_ub & 0xffff)) + 0x00010001; >- tmp_ug = ((uint)(tmp_ug & 0xffff) << 16) | (tmp_ug & 0xffff); >- tmp_vg = ((uint)(tmp_vg & 0xffff) << 16) | (tmp_vg & 0xffff); >- tmp_vr = ~(((uint)(tmp_vr & 0xffff) << 16) | (tmp_vr & 0xffff)) + 0x00010001; >- yg = yg * 0x0101; >- >- for (x = 0; x < width - 1; x += 2) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- uint32 tmp_t6, tmp_t7, tmp_t8, tmp_t9; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lbu %[tmp_t7], 0(%[src_y]) \n" >- "lbu %[tmp_t1], 1(%[src_y]) \n" >- "mul %[tmp_t7], %[tmp_t7], %[yg] \n" >- "mul %[tmp_t1], %[tmp_t1], %[yg] \n" >- "lbu %[tmp_t2], 0(%[src_u]) \n" >- "lbu %[tmp_t3], 0(%[src_v]) \n" >- "replv.ph %[tmp_t2], %[tmp_t2] \n" >- "replv.ph %[tmp_t3], %[tmp_t3] \n" >- "mul.ph %[tmp_t4], %[tmp_t2], %[tmp_ub] \n" >- "mul.ph %[tmp_t5], %[tmp_t2], %[tmp_ug] \n" >- "mul.ph %[tmp_t6], %[tmp_t3], %[tmp_vr] \n" >- "mul.ph %[tmp_t3], %[tmp_t3], %[tmp_vg] \n" >- "srl %[tmp_t7], %[tmp_t7], 16 \n" >- "ins %[tmp_t1], %[tmp_t7], 0, 16 \n" >- "addq_s.ph %[tmp_t7], %[tmp_t1], %[tmp_bb] \n" >- "addq_s.ph %[tmp_t8], %[tmp_t1], %[tmp_bg] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t1], %[tmp_br] \n" >- "addq_s.ph %[tmp_t5], %[tmp_t5], %[tmp_t3] \n" >- "addq_s.ph %[tmp_t7], %[tmp_t7], %[tmp_t4] \n" >- "subq_s.ph %[tmp_t8], %[tmp_t8], %[tmp_t5] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t9], %[tmp_t6] \n" >- "shra.ph %[tmp_t7], %[tmp_t7], 6 \n" >- "shra.ph %[tmp_t8], %[tmp_t8], 6 \n" >- "shra.ph %[tmp_t9], %[tmp_t9], 6 \n" >- "shll_s.ph %[tmp_t7], %[tmp_t7], 7 \n" >- "shll_s.ph %[tmp_t8], %[tmp_t8], 7 \n" >- "shll_s.ph %[tmp_t9], %[tmp_t9], 7 \n" >- "precrqu_s.qb.ph %[tmp_t8], %[tmp_mask], %[tmp_t8] \n" >- "precrqu_s.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "precrq.ph.w %[tmp_t2], %[tmp_t8], %[tmp_t7] \n" >- "ins %[tmp_t7], %[tmp_t8], 16, 16 \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t2], %[tmp_t7] \n" >- "precrq.qb.ph %[tmp_t7], %[tmp_t2], %[tmp_t7] \n" >- "shrl.qb %[tmp_t1], %[tmp_t8], 4 \n" >- "shrl.qb %[tmp_t2], %[tmp_t7], 4 \n" >- "shrl.ph %[tmp_t8], %[tmp_t1], 4 \n" >- "shrl.ph %[tmp_t7], %[tmp_t2], 4 \n" >- "or %[tmp_t8], %[tmp_t8], %[tmp_t1] \n" >- "or %[tmp_t7], %[tmp_t7], %[tmp_t2] \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t7], %[tmp_t8] \n" >- "sw %[tmp_t8], 0(%[dst_argb4444]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [tmp_t9] "=&r"(tmp_t9) >- : [dst_argb4444] "r"(dst_argb4444), [yg] "r"(yg), [src_u] "r"(src_u), >- [src_v] "r"(src_v), [src_y] "r"(src_y), [tmp_ub] "r"(tmp_ub), >- [tmp_ug] "r"(tmp_ug), [tmp_vg] "r"(tmp_vg), [tmp_vr] "r"(tmp_vr), >- [tmp_bb] "r"(tmp_bb), [tmp_bg] "r"(tmp_bg), [tmp_br] "r"(tmp_br), >- [tmp_yg] "r"(tmp_yg), [tmp_mask] "r"(tmp_mask)); >- src_y += 2; >- src_u += 1; >- src_v += 1; >- dst_argb4444 += 4; // Advance 2 pixels. >- } >-} >- >-void I422ToARGB1555Row_DSPR2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >- const struct YuvConstants* yuvconstants, >- int width) { >- int x; >- uint32 tmp_ub = yuvconstants->kUVToB[0]; >- uint32 tmp_ug = yuvconstants->kUVToG[0]; >- uint32 tmp_vg = yuvconstants->kUVToG[1]; >- uint32 tmp_vr = yuvconstants->kUVToR[1]; >- uint32 tmp_bb = yuvconstants->kUVBiasB[0]; >- uint32 tmp_bg = yuvconstants->kUVBiasG[0]; >- uint32 tmp_br = yuvconstants->kUVBiasR[0]; >- uint32 yg = yuvconstants->kYToRgb[0]; >- uint32 tmp_yg; >- uint32 tmp_mask = 0x80008000; >- tmp_bb = ((uint)(tmp_bb & 0xffff) << 16) | (tmp_bb & 0xffff); >- tmp_bg = ((uint)(tmp_bg & 0xffff) << 16) | (tmp_bg & 0xffff); >- tmp_br = ((uint)(tmp_br & 0xffff) << 16) | (tmp_br & 0xffff); >- tmp_yg = ((uint)(yg & 0xffff) << 16) | (yg & 0xffff); >- tmp_ub = ~(((uint)(tmp_ub & 0xffff) << 16) | (tmp_ub & 0xffff)) + 0x00010001; >- tmp_ug = ((uint)(tmp_ug & 0xffff) << 16) | (tmp_ug & 0xffff); >- tmp_vg = ((uint)(tmp_vg & 0xffff) << 16) | (tmp_vg & 0xffff); >- tmp_vr = ~(((uint)(tmp_vr & 0xffff) << 16) | (tmp_vr & 0xffff)) + 0x00010001; >- yg = yg * 0x0101; >- >- for (x = 0; x < width - 1; x += 2) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- uint32 tmp_t6, tmp_t7, tmp_t8, tmp_t9; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lbu %[tmp_t7], 0(%[src_y]) \n" >- "lbu %[tmp_t1], 1(%[src_y]) \n" >- "mul %[tmp_t7], %[tmp_t7], %[yg] \n" >- "mul %[tmp_t1], %[tmp_t1], %[yg] \n" >- "lbu %[tmp_t2], 0(%[src_u]) \n" >- "lbu %[tmp_t3], 0(%[src_v]) \n" >- "replv.ph %[tmp_t2], %[tmp_t2] \n" >- "replv.ph %[tmp_t3], %[tmp_t3] \n" >- "mul.ph %[tmp_t4], %[tmp_t2], %[tmp_ub] \n" >- "mul.ph %[tmp_t5], %[tmp_t2], %[tmp_ug] \n" >- "mul.ph %[tmp_t6], %[tmp_t3], %[tmp_vr] \n" >- "mul.ph %[tmp_t3], %[tmp_t3], %[tmp_vg] \n" >- "srl %[tmp_t7], %[tmp_t7], 16 \n" >- "ins %[tmp_t1], %[tmp_t7], 0, 16 \n" >- "addq_s.ph %[tmp_t7], %[tmp_t1], %[tmp_bb] \n" >- "addq_s.ph %[tmp_t8], %[tmp_t1], %[tmp_bg] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t1], %[tmp_br] \n" >- "addq_s.ph %[tmp_t5], %[tmp_t5], %[tmp_t3] \n" >- "addq_s.ph %[tmp_t7], %[tmp_t7], %[tmp_t4] \n" >- "subq_s.ph %[tmp_t8], %[tmp_t8], %[tmp_t5] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t9], %[tmp_t6] \n" >- "shra.ph %[tmp_t7], %[tmp_t7], 6 \n" >- "shra.ph %[tmp_t8], %[tmp_t8], 6 \n" >- "shra.ph %[tmp_t9], %[tmp_t9], 6 \n" >- "shll_s.ph %[tmp_t7], %[tmp_t7], 7 \n" >- "shll_s.ph %[tmp_t8], %[tmp_t8], 7 \n" >- "shll_s.ph %[tmp_t9], %[tmp_t9], 7 \n" >- "precrqu_s.qb.ph %[tmp_t8], %[tmp_mask], %[tmp_t8] \n" >- "precrqu_s.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "precrq.ph.w %[tmp_t2], %[tmp_t8], %[tmp_t7] \n" >- "ins %[tmp_t7], %[tmp_t8], 16, 16 \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t2], %[tmp_t7] \n" >- "precrq.qb.ph %[tmp_t7], %[tmp_t2], %[tmp_t7] \n" >- "ins %[tmp_t3], %[tmp_t8], 7, 24 \n" >- "ins %[tmp_t3], %[tmp_t8], 10, 16 \n" >- "ins %[tmp_t3], %[tmp_t8], 13, 8 \n" >- "ins %[tmp_t4], %[tmp_t7], 7, 24 \n" >- "ins %[tmp_t4], %[tmp_t7], 10, 16 \n" >- "ins %[tmp_t4], %[tmp_t7], 13, 8 \n" >- "precrq.ph.w %[tmp_t8], %[tmp_t4], %[tmp_t3] \n" >- "or %[tmp_t8], %[tmp_t8], %[tmp_mask]\n" >- "sw %[tmp_t8], 0(%[dst_argb1555]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [tmp_t9] "=&r"(tmp_t9) >- : [dst_argb1555] "r"(dst_argb1555), [yg] "r"(yg), [src_u] "r"(src_u), >- [src_v] "r"(src_v), [src_y] "r"(src_y), [tmp_ub] "r"(tmp_ub), >- [tmp_ug] "r"(tmp_ug), [tmp_vg] "r"(tmp_vg), [tmp_vr] "r"(tmp_vr), >- [tmp_bb] "r"(tmp_bb), [tmp_bg] "r"(tmp_bg), [tmp_br] "r"(tmp_br), >- [tmp_yg] "r"(tmp_yg), [tmp_mask] "r"(tmp_mask)); >- src_y += 2; >- src_u += 1; >- src_v += 1; >- dst_argb1555 += 4; // Advance 2 pixels. >- } >-} >- >-void NV12ToARGBRow_DSPR2(const uint8* src_y, >- const uint8* src_uv, >- uint8* rgb_buf, >- const struct YuvConstants* yuvconstants, >- int width) { >- int x; >- uint32 tmp_ub = yuvconstants->kUVToB[0]; >- uint32 tmp_ug = yuvconstants->kUVToG[0]; >- uint32 tmp_vg = yuvconstants->kUVToG[1]; >- uint32 tmp_vr = yuvconstants->kUVToR[1]; >- uint32 tmp_bb = yuvconstants->kUVBiasB[0]; >- uint32 tmp_bg = yuvconstants->kUVBiasG[0]; >- uint32 tmp_br = yuvconstants->kUVBiasR[0]; >- uint32 yg = yuvconstants->kYToRgb[0]; >- uint32 tmp_mask = 0x7fff7fff; >- uint32 tmp_yg; >- tmp_bb = ((uint)(tmp_bb & 0xffff) << 16) | (tmp_bb & 0xffff); >- tmp_bg = ((uint)(tmp_bg & 0xffff) << 16) | (tmp_bg & 0xffff); >- tmp_br = ((uint)(tmp_br & 0xffff) << 16) | (tmp_br & 0xffff); >- tmp_yg = ((uint)(yg & 0xffff) << 16) | (yg & 0xffff); >- tmp_ub = ~(((uint)(tmp_ub & 0xffff) << 16) | (tmp_ub & 0xffff)) + 0x00010001; >- tmp_ug = ((uint)(tmp_ug & 0xffff) << 16) | (tmp_ug & 0xffff); >- tmp_vg = ((uint)(tmp_vg & 0xffff) << 16) | (tmp_vg & 0xffff); >- tmp_vr = ~(((uint)(tmp_vr & 0xffff) << 16) | (tmp_vr & 0xffff)) + 0x00010001; >- yg = yg * 0x0101; >- >- for (x = 0; x < width - 1; x += 2) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- uint32 tmp_t6, tmp_t7, tmp_t8, tmp_t9; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lbu %[tmp_t7], 0(%[src_y]) \n" >- "lbu %[tmp_t1], 1(%[src_y]) \n" >- "mul %[tmp_t7], %[tmp_t7], %[yg] \n" >- "mul %[tmp_t1], %[tmp_t1], %[yg] \n" >- "lbu %[tmp_t2], 0(%[src_uv]) \n" >- "lbu %[tmp_t3], 1(%[src_uv]) \n" >- "replv.ph %[tmp_t2], %[tmp_t2] \n" >- "replv.ph %[tmp_t3], %[tmp_t3] \n" >- "mul.ph %[tmp_t4], %[tmp_t2], %[tmp_ub] \n" >- "mul.ph %[tmp_t5], %[tmp_t2], %[tmp_ug] \n" >- "mul.ph %[tmp_t6], %[tmp_t3], %[tmp_vr] \n" >- "mul.ph %[tmp_t3], %[tmp_t3], %[tmp_vg] \n" >- "srl %[tmp_t7], %[tmp_t7], 16 \n" >- "ins %[tmp_t1], %[tmp_t7], 0, 16 \n" >- "addq_s.ph %[tmp_t7], %[tmp_t1], %[tmp_bb] \n" >- "addq_s.ph %[tmp_t8], %[tmp_t1], %[tmp_bg] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t1], %[tmp_br] \n" >- "addq_s.ph %[tmp_t5], %[tmp_t5], %[tmp_t3] \n" >- "addq_s.ph %[tmp_t7], %[tmp_t7], %[tmp_t4] \n" >- "subq_s.ph %[tmp_t8], %[tmp_t8], %[tmp_t5] \n" >- "addq_s.ph %[tmp_t9], %[tmp_t9], %[tmp_t6] \n" >- "shra.ph %[tmp_t7], %[tmp_t7], 6 \n" >- "shra.ph %[tmp_t8], %[tmp_t8], 6 \n" >- "shra.ph %[tmp_t9], %[tmp_t9], 6 \n" >- "shll_s.ph %[tmp_t7], %[tmp_t7], 7 \n" >- "shll_s.ph %[tmp_t8], %[tmp_t8], 7 \n" >- "shll_s.ph %[tmp_t9], %[tmp_t9], 7 \n" >- "precrqu_s.qb.ph %[tmp_t8], %[tmp_mask], %[tmp_t8] \n" >- "precrqu_s.qb.ph %[tmp_t7], %[tmp_t9], %[tmp_t7] \n" >- "precrq.ph.w %[tmp_t2], %[tmp_t8], %[tmp_t7] \n" >- "ins %[tmp_t7], %[tmp_t8], 16, 16 \n" >- "precr.qb.ph %[tmp_t8], %[tmp_t2], %[tmp_t7] \n" >- "precrq.qb.ph %[tmp_t7], %[tmp_t2], %[tmp_t7] \n" >- "sw %[tmp_t8], 0(%[rgb_buf]) \n" >- "sw %[tmp_t7], 4(%[rgb_buf]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [tmp_t9] "=&r"(tmp_t9) >- : [src_y] "r"(src_y), [src_uv] "r"(src_uv), [yg] "r"(yg), >- [tmp_ub] "r"(tmp_ub), [tmp_ug] "r"(tmp_ug), [tmp_vg] "r"(tmp_vg), >- [tmp_vr] "r"(tmp_vr), [tmp_bb] "r"(tmp_bb), [tmp_bg] "r"(tmp_bg), >- [tmp_br] "r"(tmp_br), [tmp_yg] "r"(tmp_yg), [rgb_buf] "r"(rgb_buf), >- [tmp_mask] "r"(tmp_mask)); >- >- src_y += 2; >- src_uv += 2; >- rgb_buf += 8; // Advance 2 pixels. >- } >-} >- >-void BGRAToUVRow_DSPR2(const uint8* src_rgb0, >- int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; >- int x; >- int const1 = 0xffda0000; >- int const2 = 0x0070ffb6; >- int const3 = 0x00700000; >- int const4 = 0xffeeffa2; >- int const5 = 0x100; >- for (x = 0; x < width - 1; x += 2) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_rgb0]) \n" >- "lw %[tmp_t2], 4(%[src_rgb0]) \n" >- "lw %[tmp_t3], 0(%[src_rgb1]) \n" >- "lw %[tmp_t4], 4(%[src_rgb1]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t6] \n" >- "addu.ph %[tmp_t7], %[tmp_t7], %[tmp_t8] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t2] \n" >- "addu.ph %[tmp_t3], %[tmp_t3], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t7] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t3] \n" >- "shrl.ph %[tmp_t5], %[tmp_t5], 2 \n" >- "shrl.ph %[tmp_t1], %[tmp_t1], 2 \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t5], %[const3] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t1], %[const4] \n" >- "extr_r.w %[tmp_t7], $ac0, 9 \n" >- "extr_r.w %[tmp_t8], $ac1, 9 \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "addiu %[dst_v], %[dst_v], 1 \n" >- "addiu %[src_rgb0], %[src_rgb0], 8 \n" >- "addiu %[src_rgb1], %[src_rgb1], 8 \n" >- "sb %[tmp_t7], -1(%[dst_u]) \n" >- "sb %[tmp_t8], -1(%[dst_v]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_rgb0] "+r"(src_rgb0), [src_rgb1] "+r"(src_rgb1), >- [dst_u] "+r"(dst_u), [dst_v] "+r"(dst_v) >- : [const1] "r"(const1), [const2] "r"(const2), [const3] "r"(const3), >- [const4] "r"(const4), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi"); >- } >-} >- >-void BGRAToYRow_DSPR2(const uint8* src_argb0, uint8* dst_y, int width) { >- int x; >- int const1 = 0x00420000; >- int const2 = 0x00190081; >- int const5 = 0x40; >- for (x = 0; x < width; x += 4) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_argb0]) \n" >- "lw %[tmp_t2], 4(%[src_argb0]) \n" >- "lw %[tmp_t3], 8(%[src_argb0]) \n" >- "lw %[tmp_t4], 12(%[src_argb0]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "mult $ac2, %[const5], %[const5] \n" >- "mult $ac3, %[const5], %[const5] \n" >- "dpa.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpa.w.ph $ac1, %[tmp_t6], %[const1] \n" >- "dpa.w.ph $ac2, %[tmp_t7], %[const1] \n" >- "dpa.w.ph $ac3, %[tmp_t8], %[const1] \n" >- "dpa.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpa.w.ph $ac1, %[tmp_t2], %[const2] \n" >- "dpa.w.ph $ac2, %[tmp_t3], %[const2] \n" >- "dpa.w.ph $ac3, %[tmp_t4], %[const2] \n" >- "extr_r.w %[tmp_t1], $ac0, 8 \n" >- "extr_r.w %[tmp_t2], $ac1, 8 \n" >- "extr_r.w %[tmp_t3], $ac2, 8 \n" >- "extr_r.w %[tmp_t4], $ac3, 8 \n" >- "addiu %[src_argb0],%[src_argb0], 16 \n" >- "addiu %[dst_y], %[dst_y], 4 \n" >- "sb %[tmp_t1], -4(%[dst_y]) \n" >- "sb %[tmp_t2], -3(%[dst_y]) \n" >- "sb %[tmp_t3], -2(%[dst_y]) \n" >- "sb %[tmp_t4], -1(%[dst_y]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_argb0] "+r"(src_argb0), [dst_y] "+r"(dst_y) >- : [const1] "r"(const1), [const2] "r"(const2), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", >- "$ac3hi"); >- } >-} >- >-void ABGRToUVRow_DSPR2(const uint8* src_rgb0, >- int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; >- int x; >- int const1 = 0xffb6ffda; >- int const2 = 0x00000070; >- int const3 = 0xffa20070; >- int const4 = 0x0000ffee; >- int const5 = 0x100; >- >- for (x = 0; x < width - 1; x += 2) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_rgb0]) \n" >- "lw %[tmp_t2], 4(%[src_rgb0]) \n" >- "lw %[tmp_t3], 0(%[src_rgb1]) \n" >- "lw %[tmp_t4], 4(%[src_rgb1]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t6] \n" >- "addu.ph %[tmp_t7], %[tmp_t7], %[tmp_t8] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t2] \n" >- "addu.ph %[tmp_t3], %[tmp_t3], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t7] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t3] \n" >- "shrl.ph %[tmp_t5], %[tmp_t5], 2 \n" >- "shrl.ph %[tmp_t1], %[tmp_t1], 2 \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t5], %[const3] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t1], %[const4] \n" >- "extr_r.w %[tmp_t7], $ac0, 9 \n" >- "extr_r.w %[tmp_t8], $ac1, 9 \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "addiu %[dst_v], %[dst_v], 1 \n" >- "addiu %[src_rgb0], %[src_rgb0], 8 \n" >- "addiu %[src_rgb1], %[src_rgb1], 8 \n" >- "sb %[tmp_t7], -1(%[dst_u]) \n" >- "sb %[tmp_t8], -1(%[dst_v]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_rgb0] "+r"(src_rgb0), [src_rgb1] "+r"(src_rgb1), >- [dst_u] "+r"(dst_u), [dst_v] "+r"(dst_v) >- : [const1] "r"(const1), [const2] "r"(const2), [const3] "r"(const3), >- [const4] "r"(const4), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi"); >- } >-} >- >-void ARGBToYRow_DSPR2(const uint8* src_argb0, uint8* dst_y, int width) { >- int x; >- int const1 = 0x00810019; >- int const2 = 0x00000042; >- int const5 = 0x40; >- for (x = 0; x < width; x += 4) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_argb0]) \n" >- "lw %[tmp_t2], 4(%[src_argb0]) \n" >- "lw %[tmp_t3], 8(%[src_argb0]) \n" >- "lw %[tmp_t4], 12(%[src_argb0]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "mult $ac2, %[const5], %[const5] \n" >- "mult $ac3, %[const5], %[const5] \n" >- "dpa.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpa.w.ph $ac1, %[tmp_t6], %[const1] \n" >- "dpa.w.ph $ac2, %[tmp_t7], %[const1] \n" >- "dpa.w.ph $ac3, %[tmp_t8], %[const1] \n" >- "dpa.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpa.w.ph $ac1, %[tmp_t2], %[const2] \n" >- "dpa.w.ph $ac2, %[tmp_t3], %[const2] \n" >- "dpa.w.ph $ac3, %[tmp_t4], %[const2] \n" >- "extr_r.w %[tmp_t1], $ac0, 8 \n" >- "extr_r.w %[tmp_t2], $ac1, 8 \n" >- "extr_r.w %[tmp_t3], $ac2, 8 \n" >- "extr_r.w %[tmp_t4], $ac3, 8 \n" >- "addiu %[dst_y], %[dst_y], 4 \n" >- "addiu %[src_argb0],%[src_argb0], 16 \n" >- "sb %[tmp_t1], -4(%[dst_y]) \n" >- "sb %[tmp_t2], -3(%[dst_y]) \n" >- "sb %[tmp_t3], -2(%[dst_y]) \n" >- "sb %[tmp_t4], -1(%[dst_y]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_argb0] "+r"(src_argb0), [dst_y] "+r"(dst_y) >- : [const1] "r"(const1), [const2] "r"(const2), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", >- "$ac3hi"); >- } >-} >- >-void ABGRToYRow_DSPR2(const uint8* src_argb0, uint8* dst_y, int width) { >- int x; >- int const1 = 0x00810042; >- int const2 = 0x00000019; >- int const5 = 0x40; >- for (x = 0; x < width; x += 4) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_argb0]) \n" >- "lw %[tmp_t2], 4(%[src_argb0]) \n" >- "lw %[tmp_t3], 8(%[src_argb0]) \n" >- "lw %[tmp_t4], 12(%[src_argb0]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "mult $ac2, %[const5], %[const5] \n" >- "mult $ac3, %[const5], %[const5] \n" >- "dpa.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpa.w.ph $ac1, %[tmp_t6], %[const1] \n" >- "dpa.w.ph $ac2, %[tmp_t7], %[const1] \n" >- "dpa.w.ph $ac3, %[tmp_t8], %[const1] \n" >- "dpa.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpa.w.ph $ac1, %[tmp_t2], %[const2] \n" >- "dpa.w.ph $ac2, %[tmp_t3], %[const2] \n" >- "dpa.w.ph $ac3, %[tmp_t4], %[const2] \n" >- "extr_r.w %[tmp_t1], $ac0, 8 \n" >- "extr_r.w %[tmp_t2], $ac1, 8 \n" >- "extr_r.w %[tmp_t3], $ac2, 8 \n" >- "extr_r.w %[tmp_t4], $ac3, 8 \n" >- "addiu %[src_argb0],%[src_argb0], 16 \n" >- "addiu %[dst_y], %[dst_y], 4 \n" >- "sb %[tmp_t1], -4(%[dst_y]) \n" >- "sb %[tmp_t2], -3(%[dst_y]) \n" >- "sb %[tmp_t3], -2(%[dst_y]) \n" >- "sb %[tmp_t4], -1(%[dst_y]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_argb0] "+r"(src_argb0), [dst_y] "+r"(dst_y) >- : [const1] "r"(const1), [const2] "r"(const2), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", >- "$ac3hi"); >- } >-} >- >-void RGBAToUVRow_DSPR2(const uint8* src_rgb0, >- int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; >- int x; >- int const1 = 0xffb60070; >- int const2 = 0x0000ffda; >- int const3 = 0xffa2ffee; >- int const4 = 0x00000070; >- int const5 = 0x100; >- >- for (x = 0; x < width - 1; x += 2) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "ulw %[tmp_t1], 0+1(%[src_rgb0]) \n" >- "ulw %[tmp_t2], 4+1(%[src_rgb0]) \n" >- "ulw %[tmp_t3], 0+1(%[src_rgb1]) \n" >- "ulw %[tmp_t4], 4+1(%[src_rgb1]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t6] \n" >- "addu.ph %[tmp_t7], %[tmp_t7], %[tmp_t8] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t2] \n" >- "addu.ph %[tmp_t3], %[tmp_t3], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t7] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t3] \n" >- "shrl.ph %[tmp_t5], %[tmp_t5], 2 \n" >- "shrl.ph %[tmp_t1], %[tmp_t1], 2 \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t5], %[const3] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t1], %[const4] \n" >- "extr_r.w %[tmp_t7], $ac0, 9 \n" >- "extr_r.w %[tmp_t8], $ac1, 9 \n" >- "addiu %[src_rgb0], %[src_rgb0], 8 \n" >- "addiu %[src_rgb1], %[src_rgb1], 8 \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "addiu %[dst_v], %[dst_v], 1 \n" >- "sb %[tmp_t7], -1(%[dst_u]) \n" >- "sb %[tmp_t8], -1(%[dst_v]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_rgb0] "+r"(src_rgb0), [src_rgb1] "+r"(src_rgb1), >- [dst_u] "+r"(dst_u), [dst_v] "+r"(dst_v) >- : [const1] "r"(const1), [const2] "r"(const2), [const3] "r"(const3), >- [const4] "r"(const4), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi"); >- } >-} >- >-void RGBAToYRow_DSPR2(const uint8* src_argb0, uint8* dst_y, int width) { >- int x; >- int const1 = 0x00420081; >- int const2 = 0x00190000; >- int const5 = 0x40; >- for (x = 0; x < width; x += 4) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_argb0]) \n" >- "lw %[tmp_t2], 4(%[src_argb0]) \n" >- "lw %[tmp_t3], 8(%[src_argb0]) \n" >- "lw %[tmp_t4], 12(%[src_argb0]) \n" >- "preceu.ph.qbl %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbr %[tmp_t4], %[tmp_t4] \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "mult $ac2, %[const5], %[const5] \n" >- "mult $ac3, %[const5], %[const5] \n" >- "dpa.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpa.w.ph $ac1, %[tmp_t6], %[const1] \n" >- "dpa.w.ph $ac2, %[tmp_t7], %[const1] \n" >- "dpa.w.ph $ac3, %[tmp_t8], %[const1] \n" >- "dpa.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpa.w.ph $ac1, %[tmp_t2], %[const2] \n" >- "dpa.w.ph $ac2, %[tmp_t3], %[const2] \n" >- "dpa.w.ph $ac3, %[tmp_t4], %[const2] \n" >- "extr_r.w %[tmp_t1], $ac0, 8 \n" >- "extr_r.w %[tmp_t2], $ac1, 8 \n" >- "extr_r.w %[tmp_t3], $ac2, 8 \n" >- "extr_r.w %[tmp_t4], $ac3, 8 \n" >- "addiu %[dst_y], %[dst_y], 4 \n" >- "addiu %[src_argb0],%[src_argb0], 16 \n" >- "sb %[tmp_t1], -4(%[dst_y]) \n" >- "sb %[tmp_t2], -3(%[dst_y]) \n" >- "sb %[tmp_t3], -2(%[dst_y]) \n" >- "sb %[tmp_t4], -1(%[dst_y]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_argb0] "+r"(src_argb0), [dst_y] "+r"(dst_y) >- : [const1] "r"(const1), [const2] "r"(const2), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi", "$ac2lo", "$ac2hi", "$ac3lo", >- "$ac3hi"); >- } >-} >- >-void ARGBToUVRow_DSPR2(const uint8* src_rgb0, >- int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >- int width) { >- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; >- int x; >- int const1 = 0xffb60070; >- int const2 = 0x0000ffda; >- int const3 = 0xffa2ffee; >- int const4 = 0x00000070; >- int const5 = 0x100; >- >- for (x = 0; x < width - 1; x += 2) { >- int tmp_t1, tmp_t2, tmp_t3, tmp_t4, tmp_t5; >- int tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t1], 0(%[src_rgb0]) \n" >- "lw %[tmp_t2], 4(%[src_rgb0]) \n" >- "lw %[tmp_t3], 0(%[src_rgb1]) \n" >- "lw %[tmp_t4], 4(%[src_rgb1]) \n" >- "preceu.ph.qbr %[tmp_t5], %[tmp_t1] \n" >- "preceu.ph.qbl %[tmp_t1], %[tmp_t1] \n" >- "preceu.ph.qbr %[tmp_t6], %[tmp_t2] \n" >- "preceu.ph.qbl %[tmp_t2], %[tmp_t2] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t3] \n" >- "preceu.ph.qbl %[tmp_t3], %[tmp_t3] \n" >- "preceu.ph.qbr %[tmp_t8], %[tmp_t4] \n" >- "preceu.ph.qbl %[tmp_t4], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t6] \n" >- "addu.ph %[tmp_t7], %[tmp_t7], %[tmp_t8] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t2] \n" >- "addu.ph %[tmp_t3], %[tmp_t3], %[tmp_t4] \n" >- "addu.ph %[tmp_t5], %[tmp_t5], %[tmp_t7] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t3] \n" >- "shrl.ph %[tmp_t5], %[tmp_t5], 2 \n" >- "shrl.ph %[tmp_t1], %[tmp_t1], 2 \n" >- "mult $ac0, %[const5], %[const5] \n" >- "mult $ac1, %[const5], %[const5] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t5], %[const1] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t5], %[const3] \n" >- "dpaq_s.w.ph $ac0, %[tmp_t1], %[const2] \n" >- "dpaq_s.w.ph $ac1, %[tmp_t1], %[const4] \n" >- "extr_r.w %[tmp_t7], $ac0, 9 \n" >- "extr_r.w %[tmp_t8], $ac1, 9 \n" >- "addiu %[src_rgb0], %[src_rgb0], 8 \n" >- "addiu %[src_rgb1], %[src_rgb1], 8 \n" >- "addiu %[dst_u], %[dst_u], 1 \n" >- "addiu %[dst_v], %[dst_v], 1 \n" >- "sb %[tmp_t7], -1(%[dst_u]) \n" >- "sb %[tmp_t8], -1(%[dst_v]) \n" >- ".set pop \n" >- : [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), >- [tmp_t3] "=&r"(tmp_t3), [tmp_t4] "=&r"(tmp_t4), >- [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), >- [src_rgb0] "+r"(src_rgb0), [src_rgb1] "+r"(src_rgb1), >- [dst_u] "+r"(dst_u), [dst_v] "+r"(dst_v) >- : [const1] "r"(const1), [const2] "r"(const2), [const3] "r"(const3), >- [const4] "r"(const4), [const5] "r"(const5) >- : "hi", "lo", "$ac1lo", "$ac1hi"); >- } >-} >- >-#endif // __mips_dsp_rev >= 2 >- >-#endif // defined(__mips__) >- >-#ifdef __cplusplus >-} // extern "C" >-} // namespace libyuv >-#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc >index b5c2e65c938..95845c2592f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc >@@ -22,80 +22,80 @@ extern "C" { > #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) > > // Constants for ARGB >-static vec8 kARGBToY = {13, 65, 33, 0, 13, 65, 33, 0, >- 13, 65, 33, 0, 13, 65, 33, 0}; >+static const vec8 kARGBToY = {13, 65, 33, 0, 13, 65, 33, 0, >+ 13, 65, 33, 0, 13, 65, 33, 0}; > > // JPeg full range. >-static vec8 kARGBToYJ = {15, 75, 38, 0, 15, 75, 38, 0, >- 15, 75, 38, 0, 15, 75, 38, 0}; >+static const vec8 kARGBToYJ = {15, 75, 38, 0, 15, 75, 38, 0, >+ 15, 75, 38, 0, 15, 75, 38, 0}; > #endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) > > #if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) > >-static vec8 kARGBToU = {112, -74, -38, 0, 112, -74, -38, 0, >- 112, -74, -38, 0, 112, -74, -38, 0}; >+static const vec8 kARGBToU = {112, -74, -38, 0, 112, -74, -38, 0, >+ 112, -74, -38, 0, 112, -74, -38, 0}; > >-static vec8 kARGBToUJ = {127, -84, -43, 0, 127, -84, -43, 0, >- 127, -84, -43, 0, 127, -84, -43, 0}; >+static const vec8 kARGBToUJ = {127, -84, -43, 0, 127, -84, -43, 0, >+ 127, -84, -43, 0, 127, -84, -43, 0}; > >-static vec8 kARGBToV = {-18, -94, 112, 0, -18, -94, 112, 0, >- -18, -94, 112, 0, -18, -94, 112, 0}; >+static const vec8 kARGBToV = {-18, -94, 112, 0, -18, -94, 112, 0, >+ -18, -94, 112, 0, -18, -94, 112, 0}; > >-static vec8 kARGBToVJ = {-20, -107, 127, 0, -20, -107, 127, 0, >- -20, -107, 127, 0, -20, -107, 127, 0}; >+static const vec8 kARGBToVJ = {-20, -107, 127, 0, -20, -107, 127, 0, >+ -20, -107, 127, 0, -20, -107, 127, 0}; > > // Constants for BGRA >-static vec8 kBGRAToY = {0, 33, 65, 13, 0, 33, 65, 13, >- 0, 33, 65, 13, 0, 33, 65, 13}; >+static const vec8 kBGRAToY = {0, 33, 65, 13, 0, 33, 65, 13, >+ 0, 33, 65, 13, 0, 33, 65, 13}; > >-static vec8 kBGRAToU = {0, -38, -74, 112, 0, -38, -74, 112, >- 0, -38, -74, 112, 0, -38, -74, 112}; >+static const vec8 kBGRAToU = {0, -38, -74, 112, 0, -38, -74, 112, >+ 0, -38, -74, 112, 0, -38, -74, 112}; > >-static vec8 kBGRAToV = {0, 112, -94, -18, 0, 112, -94, -18, >- 0, 112, -94, -18, 0, 112, -94, -18}; >+static const vec8 kBGRAToV = {0, 112, -94, -18, 0, 112, -94, -18, >+ 0, 112, -94, -18, 0, 112, -94, -18}; > > // Constants for ABGR >-static vec8 kABGRToY = {33, 65, 13, 0, 33, 65, 13, 0, >- 33, 65, 13, 0, 33, 65, 13, 0}; >+static const vec8 kABGRToY = {33, 65, 13, 0, 33, 65, 13, 0, >+ 33, 65, 13, 0, 33, 65, 13, 0}; > >-static vec8 kABGRToU = {-38, -74, 112, 0, -38, -74, 112, 0, >- -38, -74, 112, 0, -38, -74, 112, 0}; >+static const vec8 kABGRToU = {-38, -74, 112, 0, -38, -74, 112, 0, >+ -38, -74, 112, 0, -38, -74, 112, 0}; > >-static vec8 kABGRToV = {112, -94, -18, 0, 112, -94, -18, 0, >- 112, -94, -18, 0, 112, -94, -18, 0}; >+static const vec8 kABGRToV = {112, -94, -18, 0, 112, -94, -18, 0, >+ 112, -94, -18, 0, 112, -94, -18, 0}; > > // Constants for RGBA. >-static vec8 kRGBAToY = {0, 13, 65, 33, 0, 13, 65, 33, >- 0, 13, 65, 33, 0, 13, 65, 33}; >+static const vec8 kRGBAToY = {0, 13, 65, 33, 0, 13, 65, 33, >+ 0, 13, 65, 33, 0, 13, 65, 33}; > >-static vec8 kRGBAToU = {0, 112, -74, -38, 0, 112, -74, -38, >- 0, 112, -74, -38, 0, 112, -74, -38}; >+static const vec8 kRGBAToU = {0, 112, -74, -38, 0, 112, -74, -38, >+ 0, 112, -74, -38, 0, 112, -74, -38}; > >-static vec8 kRGBAToV = {0, -18, -94, 112, 0, -18, -94, 112, >- 0, -18, -94, 112, 0, -18, -94, 112}; >+static const vec8 kRGBAToV = {0, -18, -94, 112, 0, -18, -94, 112, >+ 0, -18, -94, 112, 0, -18, -94, 112}; > >-static uvec8 kAddY16 = {16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, >- 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u}; >+static const uvec8 kAddY16 = {16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, >+ 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u}; > > // 7 bit fixed point 0.5. >-static vec16 kAddYJ64 = {64, 64, 64, 64, 64, 64, 64, 64}; >+static const vec16 kAddYJ64 = {64, 64, 64, 64, 64, 64, 64, 64}; > >-static uvec8 kAddUV128 = {128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; >+static const uvec8 kAddUV128 = {128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; > >-static uvec16 kAddUVJ128 = {0x8080u, 0x8080u, 0x8080u, 0x8080u, >- 0x8080u, 0x8080u, 0x8080u, 0x8080u}; >+static const uvec16 kAddUVJ128 = {0x8080u, 0x8080u, 0x8080u, 0x8080u, >+ 0x8080u, 0x8080u, 0x8080u, 0x8080u}; > #endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) > > #ifdef HAS_RGB24TOARGBROW_SSSE3 > > // Shuffle table for converting RGB24 to ARGB. >-static uvec8 kShuffleMaskRGB24ToARGB = {0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, >- 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u}; >+static const uvec8 kShuffleMaskRGB24ToARGB = { >+ 0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u}; > > // Shuffle table for converting RAW to ARGB. >-static uvec8 kShuffleMaskRAWToARGB = {2u, 1u, 0u, 12u, 5u, 4u, 3u, 13u, >- 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u}; >+static const uvec8 kShuffleMaskRAWToARGB = {2u, 1u, 0u, 12u, 5u, 4u, 3u, 13u, >+ 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u}; > > // Shuffle table for converting RAW to RGB24. First 8. > static const uvec8 kShuffleMaskRAWToRGB24_0 = { >@@ -113,15 +113,15 @@ static const uvec8 kShuffleMaskRAWToRGB24_2 = { > 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u}; > > // Shuffle table for converting ARGB to RGB24. >-static uvec8 kShuffleMaskARGBToRGB24 = { >+static const uvec8 kShuffleMaskARGBToRGB24 = { > 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 10u, 12u, 13u, 14u, 128u, 128u, 128u, 128u}; > > // Shuffle table for converting ARGB to RAW. >-static uvec8 kShuffleMaskARGBToRAW = { >+static const uvec8 kShuffleMaskARGBToRAW = { > 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 8u, 14u, 13u, 12u, 128u, 128u, 128u, 128u}; > > // Shuffle table for converting ARGBToRGB24 for I422ToRGB24. First 8 + next 4 >-static uvec8 kShuffleMaskARGBToRGB24_0 = { >+static const uvec8 kShuffleMaskARGBToRGB24_0 = { > 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u}; > > // YUY2 shuf 16 Y to 32 Y. >@@ -152,392 +152,399 @@ static const lvec8 kShuffleNV21 = { > #endif // HAS_RGB24TOARGBROW_SSSE3 > > #ifdef HAS_J400TOARGBROW_SSE2 >-void J400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "pslld $0x18,%%xmm5 \n" >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklwd %%xmm0,%%xmm0 \n" >- "punpckhwd %%xmm1,%%xmm1 \n" >- "por %%xmm5,%%xmm0 \n" >- "por %%xmm5,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_y), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm5" >- ); >+void J400ToARGBRow_SSE2(const uint8_t* src_y, uint8_t* dst_argb, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "pslld $0x18,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm0 \n" >+ "lea 0x8(%0),%0 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklwd %%xmm0,%%xmm0 \n" >+ "punpckhwd %%xmm1,%%xmm1 \n" >+ "por %%xmm5,%%xmm0 \n" >+ "por %%xmm5,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm5"); > } > #endif // HAS_J400TOARGBROW_SSE2 > > #ifdef HAS_RGB24TOARGBROW_SSSE3 >-void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000 >- "pslld $0x18,%%xmm5 \n" >- "movdqa %3,%%xmm4 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x30,0) ",%0 \n" >- "movdqa %%xmm3,%%xmm2 \n" >- "palignr $0x8,%%xmm1,%%xmm2 \n" >- "pshufb %%xmm4,%%xmm2 \n" >- "por %%xmm5,%%xmm2 \n" >- "palignr $0xc,%%xmm0,%%xmm1 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" >- "por %%xmm5,%%xmm0 \n" >- "pshufb %%xmm4,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "por %%xmm5,%%xmm1 \n" >- "palignr $0x4,%%xmm3,%%xmm3 \n" >- "pshufb %%xmm4,%%xmm3 \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "por %%xmm5,%%xmm3 \n" >- "movdqu %%xmm3," MEMACCESS2(0x30,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_rgb24), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleMaskRGB24ToARGB) // %3 >- : "memory", "cc" , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+void RGB24ToARGBRow_SSSE3(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width) { >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" // 0xff000000 >+ "pslld $0x18,%%xmm5 \n" >+ "movdqa %3,%%xmm4 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm3 \n" >+ "lea 0x30(%0),%0 \n" >+ "movdqa %%xmm3,%%xmm2 \n" >+ "palignr $0x8,%%xmm1,%%xmm2 \n" >+ "pshufb %%xmm4,%%xmm2 \n" >+ "por %%xmm5,%%xmm2 \n" >+ "palignr $0xc,%%xmm0,%%xmm1 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "movdqu %%xmm2,0x20(%1) \n" >+ "por %%xmm5,%%xmm0 \n" >+ "pshufb %%xmm4,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "por %%xmm5,%%xmm1 \n" >+ "palignr $0x4,%%xmm3,%%xmm3 \n" >+ "pshufb %%xmm4,%%xmm3 \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "por %%xmm5,%%xmm3 \n" >+ "movdqu %%xmm3,0x30(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_rgb24), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleMaskRGB24ToARGB) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000 >- "pslld $0x18,%%xmm5 \n" >- "movdqa %3,%%xmm4 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x30,0) ",%0 \n" >- "movdqa %%xmm3,%%xmm2 \n" >- "palignr $0x8,%%xmm1,%%xmm2 \n" >- "pshufb %%xmm4,%%xmm2 \n" >- "por %%xmm5,%%xmm2 \n" >- "palignr $0xc,%%xmm0,%%xmm1 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" >- "por %%xmm5,%%xmm0 \n" >- "pshufb %%xmm4,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "por %%xmm5,%%xmm1 \n" >- "palignr $0x4,%%xmm3,%%xmm3 \n" >- "pshufb %%xmm4,%%xmm3 \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "por %%xmm5,%%xmm3 \n" >- "movdqu %%xmm3," MEMACCESS2(0x30,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_raw), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleMaskRAWToARGB) // %3 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+void RAWToARGBRow_SSSE3(const uint8_t* src_raw, uint8_t* dst_argb, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" // 0xff000000 >+ "pslld $0x18,%%xmm5 \n" >+ "movdqa %3,%%xmm4 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm3 \n" >+ "lea 0x30(%0),%0 \n" >+ "movdqa %%xmm3,%%xmm2 \n" >+ "palignr $0x8,%%xmm1,%%xmm2 \n" >+ "pshufb %%xmm4,%%xmm2 \n" >+ "por %%xmm5,%%xmm2 \n" >+ "palignr $0xc,%%xmm0,%%xmm1 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "movdqu %%xmm2,0x20(%1) \n" >+ "por %%xmm5,%%xmm0 \n" >+ "pshufb %%xmm4,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "por %%xmm5,%%xmm1 \n" >+ "palignr $0x4,%%xmm3,%%xmm3 \n" >+ "pshufb %%xmm4,%%xmm3 \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "por %%xmm5,%%xmm3 \n" >+ "movdqu %%xmm3,0x30(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_raw), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleMaskRAWToARGB) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void RAWToRGB24Row_SSSE3(const uint8* src_raw, uint8* dst_rgb24, int width) { >- asm volatile ( >- "movdqa %3,%%xmm3 \n" >- "movdqa %4,%%xmm4 \n" >- "movdqa %5,%%xmm5 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x4,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x8,0) ",%%xmm2 \n" >- "lea " MEMLEA(0x18,0) ",%0 \n" >- "pshufb %%xmm3,%%xmm0 \n" >- "pshufb %%xmm4,%%xmm1 \n" >- "pshufb %%xmm5,%%xmm2 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "movq %%xmm1," MEMACCESS2(0x8,1) " \n" >- "movq %%xmm2," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x18,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_raw), // %0 >- "+r"(dst_rgb24), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleMaskRAWToRGB24_0), // %3 >- "m"(kShuffleMaskRAWToRGB24_1), // %4 >- "m"(kShuffleMaskRAWToRGB24_2) // %5 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+void RAWToRGB24Row_SSSE3(const uint8_t* src_raw, >+ uint8_t* dst_rgb24, >+ int width) { >+ asm volatile( >+ "movdqa %3,%%xmm3 \n" >+ "movdqa %4,%%xmm4 \n" >+ "movdqa %5,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x4(%0),%%xmm1 \n" >+ "movdqu 0x8(%0),%%xmm2 \n" >+ "lea 0x18(%0),%0 \n" >+ "pshufb %%xmm3,%%xmm0 \n" >+ "pshufb %%xmm4,%%xmm1 \n" >+ "pshufb %%xmm5,%%xmm2 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x8(%1) \n" >+ "movq %%xmm2,0x10(%1) \n" >+ "lea 0x18(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_raw), // %0 >+ "+r"(dst_rgb24), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleMaskRAWToRGB24_0), // %3 >+ "m"(kShuffleMaskRAWToRGB24_1), // %4 >+ "m"(kShuffleMaskRAWToRGB24_2) // %5 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void RGB565ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "mov $0x1080108,%%eax \n" >- "movd %%eax,%%xmm5 \n" >- "pshufd $0x0,%%xmm5,%%xmm5 \n" >- "mov $0x20802080,%%eax \n" >- "movd %%eax,%%xmm6 \n" >- "pshufd $0x0,%%xmm6,%%xmm6 \n" >- "pcmpeqb %%xmm3,%%xmm3 \n" >- "psllw $0xb,%%xmm3 \n" >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psllw $0xa,%%xmm4 \n" >- "psrlw $0x5,%%xmm4 \n" >- "pcmpeqb %%xmm7,%%xmm7 \n" >- "psllw $0x8,%%xmm7 \n" >- "sub %0,%1 \n" >- "sub %0,%1 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "pand %%xmm3,%%xmm1 \n" >- "psllw $0xb,%%xmm2 \n" >- "pmulhuw %%xmm5,%%xmm1 \n" >- "pmulhuw %%xmm5,%%xmm2 \n" >- "psllw $0x8,%%xmm1 \n" >- "por %%xmm2,%%xmm1 \n" >- "pand %%xmm4,%%xmm0 \n" >- "pmulhuw %%xmm6,%%xmm0 \n" >- "por %%xmm7,%%xmm0 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "punpcklbw %%xmm0,%%xmm1 \n" >- "punpckhbw %%xmm0,%%xmm2 \n" >- MEMOPMEM(movdqu,xmm1,0x00,1,0,2) // movdqu %%xmm1,(%1,%0,2) >- MEMOPMEM(movdqu,xmm2,0x10,1,0,2) // movdqu %%xmm2,0x10(%1,%0,2) >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc", "eax", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+void RGB565ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "mov $0x1080108,%%eax \n" >+ "movd %%eax,%%xmm5 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "mov $0x20802080,%%eax \n" >+ "movd %%eax,%%xmm6 \n" >+ "pshufd $0x0,%%xmm6,%%xmm6 \n" >+ "pcmpeqb %%xmm3,%%xmm3 \n" >+ "psllw $0xb,%%xmm3 \n" >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psllw $0xa,%%xmm4 \n" >+ "psrlw $0x5,%%xmm4 \n" >+ "pcmpeqb %%xmm7,%%xmm7 \n" >+ "psllw $0x8,%%xmm7 \n" >+ "sub %0,%1 \n" >+ "sub %0,%1 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "pand %%xmm3,%%xmm1 \n" >+ "psllw $0xb,%%xmm2 \n" >+ "pmulhuw %%xmm5,%%xmm1 \n" >+ "pmulhuw %%xmm5,%%xmm2 \n" >+ "psllw $0x8,%%xmm1 \n" >+ "por %%xmm2,%%xmm1 \n" >+ "pand %%xmm4,%%xmm0 \n" >+ "pmulhuw %%xmm6,%%xmm0 \n" >+ "por %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "punpcklbw %%xmm0,%%xmm1 \n" >+ "punpckhbw %%xmm0,%%xmm2 \n" >+ "movdqu %%xmm1,0x00(%1,%0,2) \n" >+ "movdqu %%xmm2,0x10(%1,%0,2) \n" >+ "lea 0x10(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", >+ "xmm6", "xmm7"); > } > >-void ARGB1555ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "mov $0x1080108,%%eax \n" >- "movd %%eax,%%xmm5 \n" >- "pshufd $0x0,%%xmm5,%%xmm5 \n" >- "mov $0x42004200,%%eax \n" >- "movd %%eax,%%xmm6 \n" >- "pshufd $0x0,%%xmm6,%%xmm6 \n" >- "pcmpeqb %%xmm3,%%xmm3 \n" >- "psllw $0xb,%%xmm3 \n" >- "movdqa %%xmm3,%%xmm4 \n" >- "psrlw $0x6,%%xmm4 \n" >- "pcmpeqb %%xmm7,%%xmm7 \n" >- "psllw $0x8,%%xmm7 \n" >- "sub %0,%1 \n" >- "sub %0,%1 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "psllw $0x1,%%xmm1 \n" >- "psllw $0xb,%%xmm2 \n" >- "pand %%xmm3,%%xmm1 \n" >- "pmulhuw %%xmm5,%%xmm2 \n" >- "pmulhuw %%xmm5,%%xmm1 \n" >- "psllw $0x8,%%xmm1 \n" >- "por %%xmm2,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "pand %%xmm4,%%xmm0 \n" >- "psraw $0x8,%%xmm2 \n" >- "pmulhuw %%xmm6,%%xmm0 \n" >- "pand %%xmm7,%%xmm2 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "punpcklbw %%xmm0,%%xmm1 \n" >- "punpckhbw %%xmm0,%%xmm2 \n" >- MEMOPMEM(movdqu,xmm1,0x00,1,0,2) // movdqu %%xmm1,(%1,%0,2) >- MEMOPMEM(movdqu,xmm2,0x10,1,0,2) // movdqu %%xmm2,0x10(%1,%0,2) >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc", "eax", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+void ARGB1555ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "mov $0x1080108,%%eax \n" >+ "movd %%eax,%%xmm5 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "mov $0x42004200,%%eax \n" >+ "movd %%eax,%%xmm6 \n" >+ "pshufd $0x0,%%xmm6,%%xmm6 \n" >+ "pcmpeqb %%xmm3,%%xmm3 \n" >+ "psllw $0xb,%%xmm3 \n" >+ "movdqa %%xmm3,%%xmm4 \n" >+ "psrlw $0x6,%%xmm4 \n" >+ "pcmpeqb %%xmm7,%%xmm7 \n" >+ "psllw $0x8,%%xmm7 \n" >+ "sub %0,%1 \n" >+ "sub %0,%1 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "psllw $0x1,%%xmm1 \n" >+ "psllw $0xb,%%xmm2 \n" >+ "pand %%xmm3,%%xmm1 \n" >+ "pmulhuw %%xmm5,%%xmm2 \n" >+ "pmulhuw %%xmm5,%%xmm1 \n" >+ "psllw $0x8,%%xmm1 \n" >+ "por %%xmm2,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "pand %%xmm4,%%xmm0 \n" >+ "psraw $0x8,%%xmm2 \n" >+ "pmulhuw %%xmm6,%%xmm0 \n" >+ "pand %%xmm7,%%xmm2 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "punpcklbw %%xmm0,%%xmm1 \n" >+ "punpckhbw %%xmm0,%%xmm2 \n" >+ "movdqu %%xmm1,0x00(%1,%0,2) \n" >+ "movdqu %%xmm2,0x10(%1,%0,2) \n" >+ "lea 0x10(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", >+ "xmm6", "xmm7"); > } > >-void ARGB4444ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "mov $0xf0f0f0f,%%eax \n" >- "movd %%eax,%%xmm4 \n" >- "pshufd $0x0,%%xmm4,%%xmm4 \n" >- "movdqa %%xmm4,%%xmm5 \n" >- "pslld $0x4,%%xmm5 \n" >- "sub %0,%1 \n" >- "sub %0,%1 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "pand %%xmm4,%%xmm0 \n" >- "pand %%xmm5,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm3 \n" >- "psllw $0x4,%%xmm1 \n" >- "psrlw $0x4,%%xmm3 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm3,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm2,%%xmm0 \n" >- "punpckhbw %%xmm2,%%xmm1 \n" >- MEMOPMEM(movdqu,xmm0,0x00,1,0,2) // movdqu %%xmm0,(%1,%0,2) >- MEMOPMEM(movdqu,xmm1,0x10,1,0,2) // movdqu %%xmm1,0x10(%1,%0,2) >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc", "eax", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+void ARGB4444ToARGBRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "mov $0xf0f0f0f,%%eax \n" >+ "movd %%eax,%%xmm4 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ "movdqa %%xmm4,%%xmm5 \n" >+ "pslld $0x4,%%xmm5 \n" >+ "sub %0,%1 \n" >+ "sub %0,%1 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "pand %%xmm4,%%xmm0 \n" >+ "pand %%xmm5,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm3 \n" >+ "psllw $0x4,%%xmm1 \n" >+ "psrlw $0x4,%%xmm3 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm3,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm2,%%xmm0 \n" >+ "punpckhbw %%xmm2,%%xmm1 \n" >+ "movdqu %%xmm0,0x00(%1,%0,2) \n" >+ "movdqu %%xmm1,0x10(%1,%0,2) \n" >+ "lea 0x10(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void ARGBToRGB24Row_SSSE3(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "movdqa %3,%%xmm6 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "pshufb %%xmm6,%%xmm0 \n" >- "pshufb %%xmm6,%%xmm1 \n" >- "pshufb %%xmm6,%%xmm2 \n" >- "pshufb %%xmm6,%%xmm3 \n" >- "movdqa %%xmm1,%%xmm4 \n" >- "psrldq $0x4,%%xmm1 \n" >- "pslldq $0xc,%%xmm4 \n" >- "movdqa %%xmm2,%%xmm5 \n" >- "por %%xmm4,%%xmm0 \n" >- "pslldq $0x8,%%xmm5 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "por %%xmm5,%%xmm1 \n" >- "psrldq $0x8,%%xmm2 \n" >- "pslldq $0x4,%%xmm3 \n" >- "por %%xmm3,%%xmm2 \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x30,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleMaskARGBToRGB24) // %3 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+void ARGBToRGB24Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ >+ "movdqa %3,%%xmm6 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "pshufb %%xmm6,%%xmm0 \n" >+ "pshufb %%xmm6,%%xmm1 \n" >+ "pshufb %%xmm6,%%xmm2 \n" >+ "pshufb %%xmm6,%%xmm3 \n" >+ "movdqa %%xmm1,%%xmm4 \n" >+ "psrldq $0x4,%%xmm1 \n" >+ "pslldq $0xc,%%xmm4 \n" >+ "movdqa %%xmm2,%%xmm5 \n" >+ "por %%xmm4,%%xmm0 \n" >+ "pslldq $0x8,%%xmm5 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "por %%xmm5,%%xmm1 \n" >+ "psrldq $0x8,%%xmm2 \n" >+ "pslldq $0x4,%%xmm3 \n" >+ "por %%xmm3,%%xmm2 \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "movdqu %%xmm2,0x20(%1) \n" >+ "lea 0x30(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleMaskARGBToRGB24) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > >-void ARGBToRAWRow_SSSE3(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "movdqa %3,%%xmm6 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "pshufb %%xmm6,%%xmm0 \n" >- "pshufb %%xmm6,%%xmm1 \n" >- "pshufb %%xmm6,%%xmm2 \n" >- "pshufb %%xmm6,%%xmm3 \n" >- "movdqa %%xmm1,%%xmm4 \n" >- "psrldq $0x4,%%xmm1 \n" >- "pslldq $0xc,%%xmm4 \n" >- "movdqa %%xmm2,%%xmm5 \n" >- "por %%xmm4,%%xmm0 \n" >- "pslldq $0x8,%%xmm5 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "por %%xmm5,%%xmm1 \n" >- "psrldq $0x8,%%xmm2 \n" >- "pslldq $0x4,%%xmm3 \n" >- "por %%xmm3,%%xmm2 \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x30,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleMaskARGBToRAW) // %3 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+void ARGBToRAWRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ >+ "movdqa %3,%%xmm6 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "pshufb %%xmm6,%%xmm0 \n" >+ "pshufb %%xmm6,%%xmm1 \n" >+ "pshufb %%xmm6,%%xmm2 \n" >+ "pshufb %%xmm6,%%xmm3 \n" >+ "movdqa %%xmm1,%%xmm4 \n" >+ "psrldq $0x4,%%xmm1 \n" >+ "pslldq $0xc,%%xmm4 \n" >+ "movdqa %%xmm2,%%xmm5 \n" >+ "por %%xmm4,%%xmm0 \n" >+ "pslldq $0x8,%%xmm5 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "por %%xmm5,%%xmm1 \n" >+ "psrldq $0x8,%%xmm2 \n" >+ "pslldq $0x4,%%xmm3 \n" >+ "por %%xmm3,%%xmm2 \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "movdqu %%xmm2,0x20(%1) \n" >+ "lea 0x30(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleMaskARGBToRAW) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > >-void ARGBToRGB565Row_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "pcmpeqb %%xmm3,%%xmm3 \n" >- "psrld $0x1b,%%xmm3 \n" >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psrld $0x1a,%%xmm4 \n" >- "pslld $0x5,%%xmm4 \n" >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "pslld $0xb,%%xmm5 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "pslld $0x8,%%xmm0 \n" >- "psrld $0x3,%%xmm1 \n" >- "psrld $0x5,%%xmm2 \n" >- "psrad $0x10,%%xmm0 \n" >- "pand %%xmm3,%%xmm1 \n" >- "pand %%xmm4,%%xmm2 \n" >- "pand %%xmm5,%%xmm0 \n" >- "por %%xmm2,%%xmm1 \n" >- "por %%xmm1,%%xmm0 \n" >- "packssdw %%xmm0,%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+void ARGBToRGB565Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm3,%%xmm3 \n" >+ "psrld $0x1b,%%xmm3 \n" >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psrld $0x1a,%%xmm4 \n" >+ "pslld $0x5,%%xmm4 \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "pslld $0xb,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "pslld $0x8,%%xmm0 \n" >+ "psrld $0x3,%%xmm1 \n" >+ "psrld $0x5,%%xmm2 \n" >+ "psrad $0x10,%%xmm0 \n" >+ "pand %%xmm3,%%xmm1 \n" >+ "pand %%xmm4,%%xmm2 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "por %%xmm2,%%xmm1 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "packssdw %%xmm0,%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void ARGBToRGB565DitherRow_SSE2(const uint8* src, >- uint8* dst, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_SSE2(const uint8_t* src, >+ uint8_t* dst, >+ const uint32_t dither4, > int width) { > asm volatile( > "movd %3,%%xmm6 \n" >@@ -583,9 +590,9 @@ void ARGBToRGB565DitherRow_SSE2(const uint8* src, > } > > #ifdef HAS_ARGBTORGB565DITHERROW_AVX2 >-void ARGBToRGB565DitherRow_AVX2(const uint8* src, >- uint8* dst, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_AVX2(const uint8_t* src, >+ uint8_t* dst, >+ const uint32_t dither4, > int width) { > asm volatile( > "vbroadcastss %3,%%xmm6 \n" >@@ -628,153 +635,335 @@ void ARGBToRGB565DitherRow_AVX2(const uint8* src, > } > #endif // HAS_ARGBTORGB565DITHERROW_AVX2 > >-void ARGBToARGB1555Row_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psrld $0x1b,%%xmm4 \n" >- "movdqa %%xmm4,%%xmm5 \n" >- "pslld $0x5,%%xmm5 \n" >- "movdqa %%xmm4,%%xmm6 \n" >- "pslld $0xa,%%xmm6 \n" >- "pcmpeqb %%xmm7,%%xmm7 \n" >- "pslld $0xf,%%xmm7 \n" >+void ARGBToARGB1555Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psrld $0x1b,%%xmm4 \n" >+ "movdqa %%xmm4,%%xmm5 \n" >+ "pslld $0x5,%%xmm5 \n" >+ "movdqa %%xmm4,%%xmm6 \n" >+ "pslld $0xa,%%xmm6 \n" >+ "pcmpeqb %%xmm7,%%xmm7 \n" >+ "pslld $0xf,%%xmm7 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm3 \n" >- "psrad $0x10,%%xmm0 \n" >- "psrld $0x3,%%xmm1 \n" >- "psrld $0x6,%%xmm2 \n" >- "psrld $0x9,%%xmm3 \n" >- "pand %%xmm7,%%xmm0 \n" >- "pand %%xmm4,%%xmm1 \n" >- "pand %%xmm5,%%xmm2 \n" >- "pand %%xmm6,%%xmm3 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm3,%%xmm2 \n" >- "por %%xmm2,%%xmm0 \n" >- "packssdw %%xmm0,%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- :: "memory", "cc", >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm3 \n" >+ "psrad $0x10,%%xmm0 \n" >+ "psrld $0x3,%%xmm1 \n" >+ "psrld $0x6,%%xmm2 \n" >+ "psrld $0x9,%%xmm3 \n" >+ "pand %%xmm7,%%xmm0 \n" >+ "pand %%xmm4,%%xmm1 \n" >+ "pand %%xmm5,%%xmm2 \n" >+ "pand %%xmm6,%%xmm3 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm3,%%xmm2 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "packssdw %%xmm0,%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"); > } > >-void ARGBToARGB4444Row_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psllw $0xc,%%xmm4 \n" >- "movdqa %%xmm4,%%xmm3 \n" >- "psrlw $0x8,%%xmm3 \n" >+void ARGBToARGB4444Row_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psllw $0xc,%%xmm4 \n" >+ "movdqa %%xmm4,%%xmm3 \n" >+ "psrlw $0x8,%%xmm3 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pand %%xmm3,%%xmm0 \n" >- "pand %%xmm4,%%xmm1 \n" >- "psrlq $0x4,%%xmm0 \n" >- "psrlq $0x8,%%xmm1 \n" >- "por %%xmm1,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pand %%xmm3,%%xmm0 \n" >+ "pand %%xmm4,%%xmm1 \n" >+ "psrlq $0x4,%%xmm0 \n" >+ "psrlq $0x8,%%xmm1 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); > } > #endif // HAS_RGB24TOARGBROW_SSSE3 > >+/* >+ >+ARGBToAR30Row: >+ >+Red Blue >+With the 8 bit value in the upper bits of a short, vpmulhuw by (1024+4) will >+produce a 10 bit value in the low 10 bits of each 16 bit value. This is whats >+wanted for the blue channel. The red needs to be shifted 4 left, so multiply by >+(1024+4)*16 for red. >+ >+Alpha Green >+Alpha and Green are already in the high bits so vpand can zero out the other >+bits, keeping just 2 upper bits of alpha and 8 bit green. The same multiplier >+could be used for Green - (1024+4) putting the 10 bit green in the lsb. Alpha >+would be a simple multiplier to shift it into position. It wants a gap of 10 >+above the green. Green is 10 bits, so there are 6 bits in the low short. 4 >+more are needed, so a multiplier of 4 gets the 2 bits into the upper 16 bits, >+and then a shift of 4 is a multiply of 16, so (4*16) = 64. Then shift the >+result left 10 to position the A and G channels. >+*/ >+ >+// Shuffle table for converting RAW to RGB24. Last 8. >+static const uvec8 kShuffleRB30 = {128u, 0u, 128u, 2u, 128u, 4u, 128u, 6u, >+ 128u, 8u, 128u, 10u, 128u, 12u, 128u, 14u}; >+ >+static const uvec8 kShuffleBR30 = {128u, 2u, 128u, 0u, 128u, 6u, 128u, 4u, >+ 128u, 10u, 128u, 8u, 128u, 14u, 128u, 12u}; >+ >+static const uint32_t kMulRB10 = 1028 * 16 * 65536 + 1028; >+static const uint32_t kMaskRB10 = 0x3ff003ff; >+static const uint32_t kMaskAG10 = 0xc000ff00; >+static const uint32_t kMulAG10 = 64 * 65536 + 1028; >+ >+void ARGBToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "movdqa %3,%%xmm2 \n" // shuffler for RB >+ "movd %4,%%xmm3 \n" // multipler for RB >+ "movd %5,%%xmm4 \n" // mask for R10 B10 >+ "movd %6,%%xmm5 \n" // mask for AG >+ "movd %7,%%xmm6 \n" // multipler for AG >+ "pshufd $0x0,%%xmm3,%%xmm3 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "pshufd $0x0,%%xmm6,%%xmm6 \n" >+ "sub %0,%1 \n" >+ >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" // fetch 4 ARGB pixels >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pshufb %%xmm2,%%xmm1 \n" // R0B0 >+ "pand %%xmm5,%%xmm0 \n" // A0G0 >+ "pmulhuw %%xmm3,%%xmm1 \n" // X2 R16 X4 B10 >+ "pmulhuw %%xmm6,%%xmm0 \n" // X10 A2 X10 G10 >+ "pand %%xmm4,%%xmm1 \n" // X2 R10 X10 B10 >+ "pslld $10,%%xmm0 \n" // A2 x10 G10 x10 >+ "por %%xmm1,%%xmm0 \n" // A2 R10 G10 B10 >+ "movdqu %%xmm0,(%1,%0) \n" // store 4 AR30 pixels >+ "add $0x10,%0 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleRB30), // %3 >+ "m"(kMulRB10), // %4 >+ "m"(kMaskRB10), // %5 >+ "m"(kMaskAG10), // %6 >+ "m"(kMulAG10) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); >+} >+ >+void ABGRToAR30Row_SSSE3(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "movdqa %3,%%xmm2 \n" // shuffler for RB >+ "movd %4,%%xmm3 \n" // multipler for RB >+ "movd %5,%%xmm4 \n" // mask for R10 B10 >+ "movd %6,%%xmm5 \n" // mask for AG >+ "movd %7,%%xmm6 \n" // multipler for AG >+ "pshufd $0x0,%%xmm3,%%xmm3 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "pshufd $0x0,%%xmm6,%%xmm6 \n" >+ "sub %0,%1 \n" >+ >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" // fetch 4 ABGR pixels >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pshufb %%xmm2,%%xmm1 \n" // R0B0 >+ "pand %%xmm5,%%xmm0 \n" // A0G0 >+ "pmulhuw %%xmm3,%%xmm1 \n" // X2 R16 X4 B10 >+ "pmulhuw %%xmm6,%%xmm0 \n" // X10 A2 X10 G10 >+ "pand %%xmm4,%%xmm1 \n" // X2 R10 X10 B10 >+ "pslld $10,%%xmm0 \n" // A2 x10 G10 x10 >+ "por %%xmm1,%%xmm0 \n" // A2 R10 G10 B10 >+ "movdqu %%xmm0,(%1,%0) \n" // store 4 AR30 pixels >+ "add $0x10,%0 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleBR30), // %3 reversed shuffler >+ "m"(kMulRB10), // %4 >+ "m"(kMaskRB10), // %5 >+ "m"(kMaskAG10), // %6 >+ "m"(kMulAG10) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); >+} >+ >+#ifdef HAS_ARGBTOAR30ROW_AVX2 >+void ARGBToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "vbroadcastf128 %3,%%ymm2 \n" // shuffler for RB >+ "vbroadcastss %4,%%ymm3 \n" // multipler for RB >+ "vbroadcastss %5,%%ymm4 \n" // mask for R10 B10 >+ "vbroadcastss %6,%%ymm5 \n" // mask for AG >+ "vbroadcastss %7,%%ymm6 \n" // multipler for AG >+ "sub %0,%1 \n" >+ >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" // fetch 8 ARGB pixels >+ "vpshufb %%ymm2,%%ymm0,%%ymm1 \n" // R0B0 >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" // A0G0 >+ "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" // X2 R16 X4 B10 >+ "vpmulhuw %%ymm6,%%ymm0,%%ymm0 \n" // X10 A2 X10 G10 >+ "vpand %%ymm4,%%ymm1,%%ymm1 \n" // X2 R10 X10 B10 >+ "vpslld $10,%%ymm0,%%ymm0 \n" // A2 x10 G10 x10 >+ "vpor %%ymm1,%%ymm0,%%ymm0 \n" // A2 R10 G10 B10 >+ "vmovdqu %%ymm0,(%1,%0) \n" // store 8 AR30 pixels >+ "add $0x20,%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleRB30), // %3 >+ "m"(kMulRB10), // %4 >+ "m"(kMaskRB10), // %5 >+ "m"(kMaskAG10), // %6 >+ "m"(kMulAG10) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); >+} >+#endif >+ >+#ifdef HAS_ABGRTOAR30ROW_AVX2 >+void ABGRToAR30Row_AVX2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "vbroadcastf128 %3,%%ymm2 \n" // shuffler for RB >+ "vbroadcastss %4,%%ymm3 \n" // multipler for RB >+ "vbroadcastss %5,%%ymm4 \n" // mask for R10 B10 >+ "vbroadcastss %6,%%ymm5 \n" // mask for AG >+ "vbroadcastss %7,%%ymm6 \n" // multipler for AG >+ "sub %0,%1 \n" >+ >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" // fetch 8 ABGR pixels >+ "vpshufb %%ymm2,%%ymm0,%%ymm1 \n" // R0B0 >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" // A0G0 >+ "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" // X2 R16 X4 B10 >+ "vpmulhuw %%ymm6,%%ymm0,%%ymm0 \n" // X10 A2 X10 G10 >+ "vpand %%ymm4,%%ymm1,%%ymm1 \n" // X2 R10 X10 B10 >+ "vpslld $10,%%ymm0,%%ymm0 \n" // A2 x10 G10 x10 >+ "vpor %%ymm1,%%ymm0,%%ymm0 \n" // A2 R10 G10 B10 >+ "vmovdqu %%ymm0,(%1,%0) \n" // store 8 AR30 pixels >+ "add $0x20,%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleBR30), // %3 reversed shuffler >+ "m"(kMulRB10), // %4 >+ "m"(kMaskRB10), // %5 >+ "m"(kMaskAG10), // %6 >+ "m"(kMulAG10) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); >+} >+#endif >+ > #ifdef HAS_ARGBTOYROW_SSSE3 > // Convert 16 ARGB pixels (64 bytes) to 16 Y values. >-void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width) { >- asm volatile ( >- "movdqa %3,%%xmm4 \n" >- "movdqa %4,%%xmm5 \n" >+void ARGBToYRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width) { >+ asm volatile( >+ "movdqa %3,%%xmm4 \n" >+ "movdqa %4,%%xmm5 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm3,%%xmm2 \n" >- "psrlw $0x7,%%xmm0 \n" >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kARGBToY), // %3 >- "m"(kAddY16) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm3,%%xmm2 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kARGBToY), // %3 >+ "m"(kAddY16) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBTOYROW_SSSE3 > > #ifdef HAS_ARGBTOYJROW_SSSE3 > // Convert 16 ARGB pixels (64 bytes) to 16 YJ values. > // Same as ARGBToYRow but different coefficients, no add 16, but do rounding. >-void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width) { >- asm volatile ( >- "movdqa %3,%%xmm4 \n" >- "movdqa %4,%%xmm5 \n" >+void ARGBToYJRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_y, int width) { >+ asm volatile( >+ "movdqa %3,%%xmm4 \n" >+ "movdqa %4,%%xmm5 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm3,%%xmm2 \n" >- "paddw %%xmm5,%%xmm0 \n" >- "paddw %%xmm5,%%xmm2 \n" >- "psrlw $0x7,%%xmm0 \n" >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kARGBToYJ), // %3 >- "m"(kAddYJ64) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm3,%%xmm2 \n" >+ "paddw %%xmm5,%%xmm0 \n" >+ "paddw %%xmm5,%%xmm2 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kARGBToYJ), // %3 >+ "m"(kAddYJ64) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBTOYJROW_SSSE3 > >@@ -783,153 +972,149 @@ void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width) { > static const lvec32 kPermdARGBToY_AVX = {0, 4, 1, 5, 2, 6, 3, 7}; > > // Convert 32 ARGB pixels (128 bytes) to 32 Y values. >-void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int width) { >- asm volatile ( >- "vbroadcastf128 %3,%%ymm4 \n" >- "vbroadcastf128 %4,%%ymm5 \n" >- "vmovdqu %5,%%ymm6 \n" >+void ARGBToYRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width) { >+ asm volatile( >+ "vbroadcastf128 %3,%%ymm4 \n" >+ "vbroadcastf128 %4,%%ymm5 \n" >+ "vmovdqu %5,%%ymm6 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" >- "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" >- "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "lea " MEMLEA(0x80,0) ",%0 \n" >- "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. >- "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" >- "vpsrlw $0x7,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x7,%%ymm2,%%ymm2 \n" >- "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >- "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. >- "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" // add 16 for Y >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kARGBToY), // %3 >- "m"(kAddY16), // %4 >- "m"(kPermdARGBToY_AVX) // %5 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x40(%0),%%ymm2 \n" >+ "vmovdqu 0x60(%0),%%ymm3 \n" >+ "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "lea 0x80(%0),%0 \n" >+ "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. >+ "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" >+ "vpsrlw $0x7,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x7,%%ymm2,%%ymm2 \n" >+ "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >+ "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. >+ "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" // add 16 for Y >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kARGBToY), // %3 >+ "m"(kAddY16), // %4 >+ "m"(kPermdARGBToY_AVX) // %5 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_ARGBTOYROW_AVX2 > > #ifdef HAS_ARGBTOYJROW_AVX2 > // Convert 32 ARGB pixels (128 bytes) to 32 Y values. >-void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int width) { >- asm volatile ( >- "vbroadcastf128 %3,%%ymm4 \n" >- "vbroadcastf128 %4,%%ymm5 \n" >- "vmovdqu %5,%%ymm6 \n" >+void ARGBToYJRow_AVX2(const uint8_t* src_argb, uint8_t* dst_y, int width) { >+ asm volatile( >+ "vbroadcastf128 %3,%%ymm4 \n" >+ "vbroadcastf128 %4,%%ymm5 \n" >+ "vmovdqu %5,%%ymm6 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" >- "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" >- "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "lea " MEMLEA(0x80,0) ",%0 \n" >- "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. >- "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" >- "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" // Add .5 for rounding. >- "vpaddw %%ymm5,%%ymm2,%%ymm2 \n" >- "vpsrlw $0x7,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x7,%%ymm2,%%ymm2 \n" >- "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >- "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kARGBToYJ), // %3 >- "m"(kAddYJ64), // %4 >- "m"(kPermdARGBToY_AVX) // %5 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x40(%0),%%ymm2 \n" >+ "vmovdqu 0x60(%0),%%ymm3 \n" >+ "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "lea 0x80(%0),%0 \n" >+ "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. >+ "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" >+ "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" // Add .5 for rounding. >+ "vpaddw %%ymm5,%%ymm2,%%ymm2 \n" >+ "vpsrlw $0x7,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x7,%%ymm2,%%ymm2 \n" >+ "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >+ "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kARGBToYJ), // %3 >+ "m"(kAddYJ64), // %4 >+ "m"(kPermdARGBToY_AVX) // %5 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_ARGBTOYJROW_AVX2 > > #ifdef HAS_ARGBTOUVROW_SSSE3 >-void ARGBToUVRow_SSSE3(const uint8* src_argb0, >+void ARGBToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %5,%%xmm3 \n" >- "movdqa %6,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %5,%%xmm3 \n" >+ "movdqa %6,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm7 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm7 \n" >- "shufps $0x88,%%xmm6,%%xmm2 \n" >- "shufps $0xdd,%%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm2,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm1 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm1 \n" >- "packsswb %%xmm1,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movlps %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_argb)), // %4 >- "m"(kARGBToV), // %5 >- "m"(kARGBToU), // %6 >- "m"(kAddUV128) // %7 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x20(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "movdqu 0x30(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ >+ "lea 0x40(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm7 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm7 \n" >+ "shufps $0x88,%%xmm6,%%xmm2 \n" >+ "shufps $0xdd,%%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm2,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm1 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm1 \n" >+ "packsswb %%xmm1,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movlps %%xmm0,(%1) \n" >+ "movhps %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_argb)), // %4 >+ "m"(kARGBToV), // %5 >+ "m"(kARGBToU), // %6 >+ "m"(kAddUV128) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); > } > #endif // HAS_ARGBTOUVROW_SSSE3 > >@@ -938,643 +1123,644 @@ void ARGBToUVRow_SSSE3(const uint8* src_argb0, > static const lvec8 kShufARGBToUV_AVX = { > 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, > 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15}; >-void ARGBToUVRow_AVX2(const uint8* src_argb0, >+void ARGBToUVRow_AVX2(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vbroadcastf128 %5,%%ymm5 \n" >- "vbroadcastf128 %6,%%ymm6 \n" >- "vbroadcastf128 %7,%%ymm7 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vbroadcastf128 %5,%%ymm5 \n" >+ "vbroadcastf128 %6,%%ymm6 \n" >+ "vbroadcastf128 %7,%%ymm7 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" >- "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" >- VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 >- VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) >- VMEMOPREG(vpavgb,0x40,0,4,1,ymm2,ymm2) >- VMEMOPREG(vpavgb,0x60,0,4,1,ymm3,ymm3) >- "lea " MEMLEA(0x80,0) ",%0 \n" >- "vshufps $0x88,%%ymm1,%%ymm0,%%ymm4 \n" >- "vshufps $0xdd,%%ymm1,%%ymm0,%%ymm0 \n" >- "vpavgb %%ymm4,%%ymm0,%%ymm0 \n" >- "vshufps $0x88,%%ymm3,%%ymm2,%%ymm4 \n" >- "vshufps $0xdd,%%ymm3,%%ymm2,%%ymm2 \n" >- "vpavgb %%ymm4,%%ymm2,%%ymm2 \n" >- >- "vpmaddubsw %%ymm7,%%ymm0,%%ymm1 \n" >- "vpmaddubsw %%ymm7,%%ymm2,%%ymm3 \n" >- "vpmaddubsw %%ymm6,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm6,%%ymm2,%%ymm2 \n" >- "vphaddw %%ymm3,%%ymm1,%%ymm1 \n" >- "vphaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpsraw $0x8,%%ymm1,%%ymm1 \n" >- "vpsraw $0x8,%%ymm0,%%ymm0 \n" >- "vpacksswb %%ymm0,%%ymm1,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpshufb %8,%%ymm0,%%ymm0 \n" >- "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" >- >- "vextractf128 $0x0,%%ymm0," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,1,ymm0,0x0,1,2,1) // vextractf128 $1,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_argb)), // %4 >- "m"(kAddUV128), // %5 >- "m"(kARGBToV), // %6 >- "m"(kARGBToU), // %7 >- "m"(kShufARGBToUV_AVX) // %8 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >-} >-#endif // HAS_ARGBTOUVROW_AVX2 >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x40(%0),%%ymm2 \n" >+ "vmovdqu 0x60(%0),%%ymm3 \n" >+ "vpavgb 0x00(%0,%4,1),%%ymm0,%%ymm0 \n" >+ "vpavgb 0x20(%0,%4,1),%%ymm1,%%ymm1 \n" >+ "vpavgb 0x40(%0,%4,1),%%ymm2,%%ymm2 \n" >+ "vpavgb 0x60(%0,%4,1),%%ymm3,%%ymm3 \n" >+ "lea 0x80(%0),%0 \n" >+ "vshufps $0x88,%%ymm1,%%ymm0,%%ymm4 \n" >+ "vshufps $0xdd,%%ymm1,%%ymm0,%%ymm0 \n" >+ "vpavgb %%ymm4,%%ymm0,%%ymm0 \n" >+ "vshufps $0x88,%%ymm3,%%ymm2,%%ymm4 \n" >+ "vshufps $0xdd,%%ymm3,%%ymm2,%%ymm2 \n" >+ "vpavgb %%ymm4,%%ymm2,%%ymm2 \n" >+ >+ "vpmaddubsw %%ymm7,%%ymm0,%%ymm1 \n" >+ "vpmaddubsw %%ymm7,%%ymm2,%%ymm3 \n" >+ "vpmaddubsw %%ymm6,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm6,%%ymm2,%%ymm2 \n" >+ "vphaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vphaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpsraw $0x8,%%ymm1,%%ymm1 \n" >+ "vpsraw $0x8,%%ymm0,%%ymm0 \n" >+ "vpacksswb %%ymm0,%%ymm1,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpshufb %8,%%ymm0,%%ymm0 \n" >+ "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" > >-#ifdef HAS_ARGBTOUVJROW_AVX2 >-void ARGBToUVJRow_AVX2(const uint8* src_argb0, >- int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ "vextractf128 $0x0,%%ymm0,(%1) \n" >+ "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_argb)), // %4 >+ "m"(kAddUV128), // %5 >+ "m"(kARGBToV), // %6 >+ "m"(kARGBToU), // %7 >+ "m"(kShufARGBToUV_AVX) // %8 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); >+} >+#endif // HAS_ARGBTOUVROW_AVX2 >+ >+#ifdef HAS_ARGBTOUVJROW_AVX2 >+void ARGBToUVJRow_AVX2(const uint8_t* src_argb0, >+ int src_stride_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vbroadcastf128 %5,%%ymm5 \n" >- "vbroadcastf128 %6,%%ymm6 \n" >- "vbroadcastf128 %7,%%ymm7 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vbroadcastf128 %5,%%ymm5 \n" >+ "vbroadcastf128 %6,%%ymm6 \n" >+ "vbroadcastf128 %7,%%ymm7 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" >- "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" >- VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 >- VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) >- VMEMOPREG(vpavgb,0x40,0,4,1,ymm2,ymm2) >- VMEMOPREG(vpavgb,0x60,0,4,1,ymm3,ymm3) >- "lea " MEMLEA(0x80,0) ",%0 \n" >- "vshufps $0x88,%%ymm1,%%ymm0,%%ymm4 \n" >- "vshufps $0xdd,%%ymm1,%%ymm0,%%ymm0 \n" >- "vpavgb %%ymm4,%%ymm0,%%ymm0 \n" >- "vshufps $0x88,%%ymm3,%%ymm2,%%ymm4 \n" >- "vshufps $0xdd,%%ymm3,%%ymm2,%%ymm2 \n" >- "vpavgb %%ymm4,%%ymm2,%%ymm2 \n" >- >- "vpmaddubsw %%ymm7,%%ymm0,%%ymm1 \n" >- "vpmaddubsw %%ymm7,%%ymm2,%%ymm3 \n" >- "vpmaddubsw %%ymm6,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm6,%%ymm2,%%ymm2 \n" >- "vphaddw %%ymm3,%%ymm1,%%ymm1 \n" >- "vphaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm5,%%ymm1,%%ymm1 \n" >- "vpsraw $0x8,%%ymm1,%%ymm1 \n" >- "vpsraw $0x8,%%ymm0,%%ymm0 \n" >- "vpacksswb %%ymm0,%%ymm1,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpshufb %8,%%ymm0,%%ymm0 \n" >- >- "vextractf128 $0x0,%%ymm0," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,1,ymm0,0x0,1,2,1) // vextractf128 $1,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_argb)), // %4 >- "m"(kAddUVJ128), // %5 >- "m"(kARGBToVJ), // %6 >- "m"(kARGBToUJ), // %7 >- "m"(kShufARGBToUV_AVX) // %8 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x40(%0),%%ymm2 \n" >+ "vmovdqu 0x60(%0),%%ymm3 \n" >+ "vpavgb 0x00(%0,%4,1),%%ymm0,%%ymm0 \n" >+ "vpavgb 0x20(%0,%4,1),%%ymm1,%%ymm1 \n" >+ "vpavgb 0x40(%0,%4,1),%%ymm2,%%ymm2 \n" >+ "vpavgb 0x60(%0,%4,1),%%ymm3,%%ymm3 \n" >+ "lea 0x80(%0),%0 \n" >+ "vshufps $0x88,%%ymm1,%%ymm0,%%ymm4 \n" >+ "vshufps $0xdd,%%ymm1,%%ymm0,%%ymm0 \n" >+ "vpavgb %%ymm4,%%ymm0,%%ymm0 \n" >+ "vshufps $0x88,%%ymm3,%%ymm2,%%ymm4 \n" >+ "vshufps $0xdd,%%ymm3,%%ymm2,%%ymm2 \n" >+ "vpavgb %%ymm4,%%ymm2,%%ymm2 \n" >+ >+ "vpmaddubsw %%ymm7,%%ymm0,%%ymm1 \n" >+ "vpmaddubsw %%ymm7,%%ymm2,%%ymm3 \n" >+ "vpmaddubsw %%ymm6,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm6,%%ymm2,%%ymm2 \n" >+ "vphaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vphaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpsraw $0x8,%%ymm1,%%ymm1 \n" >+ "vpsraw $0x8,%%ymm0,%%ymm0 \n" >+ "vpacksswb %%ymm0,%%ymm1,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpshufb %8,%%ymm0,%%ymm0 \n" >+ >+ "vextractf128 $0x0,%%ymm0,(%1) \n" >+ "vextractf128 $0x1,%%ymm0,0x0(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_argb)), // %4 >+ "m"(kAddUVJ128), // %5 >+ "m"(kARGBToVJ), // %6 >+ "m"(kARGBToUJ), // %7 >+ "m"(kShufARGBToUV_AVX) // %8 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBTOUVJROW_AVX2 > > #ifdef HAS_ARGBTOUVJROW_SSSE3 >-void ARGBToUVJRow_SSSE3(const uint8* src_argb0, >+void ARGBToUVJRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %5,%%xmm3 \n" >- "movdqa %6,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %5,%%xmm3 \n" >+ "movdqa %6,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm7 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm7 \n" >- "shufps $0x88,%%xmm6,%%xmm2 \n" >- "shufps $0xdd,%%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm2,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm1 \n" >- "paddw %%xmm5,%%xmm0 \n" >- "paddw %%xmm5,%%xmm1 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm1 \n" >- "packsswb %%xmm1,%%xmm0 \n" >- "movlps %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_argb)), // %4 >- "m"(kARGBToVJ), // %5 >- "m"(kARGBToUJ), // %6 >- "m"(kAddUVJ128) // %7 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x20(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "movdqu 0x30(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ >+ "lea 0x40(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm7 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm7 \n" >+ "shufps $0x88,%%xmm6,%%xmm2 \n" >+ "shufps $0xdd,%%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm2,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm1 \n" >+ "paddw %%xmm5,%%xmm0 \n" >+ "paddw %%xmm5,%%xmm1 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm1 \n" >+ "packsswb %%xmm1,%%xmm0 \n" >+ "movlps %%xmm0,(%1) \n" >+ "movhps %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_argb)), // %4 >+ "m"(kARGBToVJ), // %5 >+ "m"(kARGBToUJ), // %6 >+ "m"(kAddUVJ128) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); > } > #endif // HAS_ARGBTOUVJROW_SSSE3 > > #ifdef HAS_ARGBTOUV444ROW_SSSE3 >-void ARGBToUV444Row_SSSE3(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %4,%%xmm3 \n" >- "movdqa %5,%%xmm4 \n" >- "movdqa %6,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %4,%%xmm3 \n" >+ "movdqa %5,%%xmm4 \n" >+ "movdqa %6,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm6 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm2 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm2 \n" >- "packsswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- "pmaddubsw %%xmm3,%%xmm0 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm2 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm2 \n" >- "packsswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- MEMOPMEM(movdqu,xmm0,0x00,1,2,1) // movdqu %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "m"(kARGBToV), // %4 >- "m"(kARGBToU), // %5 >- "m"(kAddUV128) // %6 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm6 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm2 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm2 \n" >+ "packsswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "pmaddubsw %%xmm3,%%xmm0 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm2 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm2 \n" >+ "packsswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "lea 0x40(%0),%0 \n" >+ "movdqu %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "m"(kARGBToV), // %4 >+ "m"(kARGBToU), // %5 >+ "m"(kAddUV128) // %6 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6"); > } > #endif // HAS_ARGBTOUV444ROW_SSSE3 > >-void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int width) { >- asm volatile ( >- "movdqa %4,%%xmm5 \n" >- "movdqa %3,%%xmm4 \n" >+void BGRAToYRow_SSSE3(const uint8_t* src_bgra, uint8_t* dst_y, int width) { >+ asm volatile( >+ "movdqa %4,%%xmm5 \n" >+ "movdqa %3,%%xmm4 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm3,%%xmm2 \n" >- "psrlw $0x7,%%xmm0 \n" >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_bgra), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kBGRAToY), // %3 >- "m"(kAddY16) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm3,%%xmm2 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_bgra), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kBGRAToY), // %3 >+ "m"(kAddY16) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void BGRAToUVRow_SSSE3(const uint8* src_bgra0, >+void BGRAToUVRow_SSSE3(const uint8_t* src_bgra0, > int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %5,%%xmm3 \n" >- "movdqa %6,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %5,%%xmm3 \n" >+ "movdqa %6,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm7 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm7 \n" >- "shufps $0x88,%%xmm6,%%xmm2 \n" >- "shufps $0xdd,%%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm2,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm1 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm1 \n" >- "packsswb %%xmm1,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movlps %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_bgra0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_bgra)), // %4 >- "m"(kBGRAToV), // %5 >- "m"(kBGRAToU), // %6 >- "m"(kAddUV128) // %7 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x20(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "movdqu 0x30(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ >+ "lea 0x40(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm7 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm7 \n" >+ "shufps $0x88,%%xmm6,%%xmm2 \n" >+ "shufps $0xdd,%%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm2,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm1 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm1 \n" >+ "packsswb %%xmm1,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movlps %%xmm0,(%1) \n" >+ "movhps %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_bgra0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_bgra)), // %4 >+ "m"(kBGRAToV), // %5 >+ "m"(kBGRAToU), // %6 >+ "m"(kAddUV128) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); > } > >-void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int width) { >- asm volatile ( >- "movdqa %4,%%xmm5 \n" >- "movdqa %3,%%xmm4 \n" >+void ABGRToYRow_SSSE3(const uint8_t* src_abgr, uint8_t* dst_y, int width) { >+ asm volatile( >+ "movdqa %4,%%xmm5 \n" >+ "movdqa %3,%%xmm4 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm3,%%xmm2 \n" >- "psrlw $0x7,%%xmm0 \n" >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_abgr), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kABGRToY), // %3 >- "m"(kAddY16) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm3,%%xmm2 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_abgr), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kABGRToY), // %3 >+ "m"(kAddY16) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int width) { >- asm volatile ( >- "movdqa %4,%%xmm5 \n" >- "movdqa %3,%%xmm4 \n" >+void RGBAToYRow_SSSE3(const uint8_t* src_rgba, uint8_t* dst_y, int width) { >+ asm volatile( >+ "movdqa %4,%%xmm5 \n" >+ "movdqa %3,%%xmm4 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "phaddw %%xmm3,%%xmm2 \n" >- "psrlw $0x7,%%xmm0 \n" >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_rgba), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : "m"(kRGBAToY), // %3 >- "m"(kAddY16) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "phaddw %%xmm3,%%xmm2 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_rgba), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "m"(kRGBAToY), // %3 >+ "m"(kAddY16) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void ABGRToUVRow_SSSE3(const uint8* src_abgr0, >+void ABGRToUVRow_SSSE3(const uint8_t* src_abgr0, > int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %5,%%xmm3 \n" >- "movdqa %6,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %5,%%xmm3 \n" >+ "movdqa %6,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm7 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm7 \n" >- "shufps $0x88,%%xmm6,%%xmm2 \n" >- "shufps $0xdd,%%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm2,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm1 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm1 \n" >- "packsswb %%xmm1,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movlps %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_abgr0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_abgr)), // %4 >- "m"(kABGRToV), // %5 >- "m"(kABGRToU), // %6 >- "m"(kAddUV128) // %7 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x20(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "movdqu 0x30(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ >+ "lea 0x40(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm7 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm7 \n" >+ "shufps $0x88,%%xmm6,%%xmm2 \n" >+ "shufps $0xdd,%%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm2,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm1 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm1 \n" >+ "packsswb %%xmm1,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movlps %%xmm0,(%1) \n" >+ "movhps %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_abgr0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_abgr)), // %4 >+ "m"(kABGRToV), // %5 >+ "m"(kABGRToU), // %6 >+ "m"(kAddUV128) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); > } > >-void RGBAToUVRow_SSSE3(const uint8* src_rgba0, >+void RGBAToUVRow_SSSE3(const uint8_t* src_rgba0, > int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "movdqa %5,%%xmm3 \n" >- "movdqa %6,%%xmm4 \n" >- "movdqa %7,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %5,%%xmm3 \n" >+ "movdqa %6,%%xmm4 \n" >+ "movdqa %7,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm7 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm7 \n" >- "shufps $0x88,%%xmm6,%%xmm2 \n" >- "shufps $0xdd,%%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "phaddw %%xmm2,%%xmm0 \n" >- "phaddw %%xmm6,%%xmm1 \n" >- "psraw $0x8,%%xmm0 \n" >- "psraw $0x8,%%xmm1 \n" >- "packsswb %%xmm1,%%xmm0 \n" >- "paddb %%xmm5,%%xmm0 \n" >- "movlps %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_rgba0), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+rm"(width) // %3 >- : "r"((intptr_t)(src_stride_rgba)), // %4 >- "m"(kRGBAToV), // %5 >- "m"(kRGBAToU), // %6 >- "m"(kAddUV128) // %7 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x20(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm6 \n" >+ "movdqu 0x30(%0,%4,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ >+ "lea 0x40(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm7 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm7 \n" >+ "shufps $0x88,%%xmm6,%%xmm2 \n" >+ "shufps $0xdd,%%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "phaddw %%xmm2,%%xmm0 \n" >+ "phaddw %%xmm6,%%xmm1 \n" >+ "psraw $0x8,%%xmm0 \n" >+ "psraw $0x8,%%xmm1 \n" >+ "packsswb %%xmm1,%%xmm0 \n" >+ "paddb %%xmm5,%%xmm0 \n" >+ "movlps %%xmm0,(%1) \n" >+ "movhps %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_rgba0), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+rm"(width) // %3 >+ : "r"((intptr_t)(src_stride_rgba)), // %4 >+ "m"(kRGBAToV), // %5 >+ "m"(kRGBAToU), // %6 >+ "m"(kAddUV128) // %7 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"); > } > > #if defined(HAS_I422TOARGBROW_SSSE3) || defined(HAS_I422TOARGBROW_AVX2) > > // Read 8 UV from 444 >-#define READYUV444 \ >- "movq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(movq, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ >- "punpcklbw %%xmm1,%%xmm0 \n" \ >- "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "punpcklbw %%xmm4,%%xmm4 \n" \ >- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" >+#define READYUV444 \ >+ "movq (%[u_buf]),%%xmm0 \n" \ >+ "movq 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x8(%[u_buf]),%[u_buf] \n" \ >+ "punpcklbw %%xmm1,%%xmm0 \n" \ >+ "movq (%[y_buf]),%%xmm4 \n" \ >+ "punpcklbw %%xmm4,%%xmm4 \n" \ >+ "lea 0x8(%[y_buf]),%[y_buf] \n" > > // Read 4 UV from 422, upsample to 8 UV >-#define READYUV422 \ >- "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x4, [u_buf]) ",%[u_buf] \n" \ >- "punpcklbw %%xmm1,%%xmm0 \n" \ >- "punpcklwd %%xmm0,%%xmm0 \n" \ >- "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "punpcklbw %%xmm4,%%xmm4 \n" \ >- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" >+#define READYUV422 \ >+ "movd (%[u_buf]),%%xmm0 \n" \ >+ "movd 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x4(%[u_buf]),%[u_buf] \n" \ >+ "punpcklbw %%xmm1,%%xmm0 \n" \ >+ "punpcklwd %%xmm0,%%xmm0 \n" \ >+ "movq (%[y_buf]),%%xmm4 \n" \ >+ "punpcklbw %%xmm4,%%xmm4 \n" \ >+ "lea 0x8(%[y_buf]),%[y_buf] \n" >+ >+// Read 4 UV from 422 10 bit, upsample to 8 UV >+// TODO(fbarchard): Consider shufb to replace pack/unpack >+// TODO(fbarchard): Consider pmulhuw to replace psraw >+// TODO(fbarchard): Consider pmullw to replace psllw and allow different bits. >+#define READYUV210 \ >+ "movq (%[u_buf]),%%xmm0 \n" \ >+ "movq 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x8(%[u_buf]),%[u_buf] \n" \ >+ "punpcklwd %%xmm1,%%xmm0 \n" \ >+ "psraw $0x2,%%xmm0 \n" \ >+ "packuswb %%xmm0,%%xmm0 \n" \ >+ "punpcklwd %%xmm0,%%xmm0 \n" \ >+ "movdqu (%[y_buf]),%%xmm4 \n" \ >+ "psllw $0x6,%%xmm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" > > // Read 4 UV from 422, upsample to 8 UV. With 8 Alpha. >-#define READYUVA422 \ >- "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x4, [u_buf]) ",%[u_buf] \n" \ >- "punpcklbw %%xmm1,%%xmm0 \n" \ >- "punpcklwd %%xmm0,%%xmm0 \n" \ >- "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "punpcklbw %%xmm4,%%xmm4 \n" \ >- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" \ >- "movq " MEMACCESS([a_buf]) ",%%xmm5 \n" \ >- "lea " MEMLEA(0x8, [a_buf]) ",%[a_buf] \n" >+#define READYUVA422 \ >+ "movd (%[u_buf]),%%xmm0 \n" \ >+ "movd 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x4(%[u_buf]),%[u_buf] \n" \ >+ "punpcklbw %%xmm1,%%xmm0 \n" \ >+ "punpcklwd %%xmm0,%%xmm0 \n" \ >+ "movq (%[y_buf]),%%xmm4 \n" \ >+ "punpcklbw %%xmm4,%%xmm4 \n" \ >+ "lea 0x8(%[y_buf]),%[y_buf] \n" \ >+ "movq (%[a_buf]),%%xmm5 \n" \ >+ "lea 0x8(%[a_buf]),%[a_buf] \n" > > // Read 4 UV from NV12, upsample to 8 UV >-#define READNV12 \ >- "movq " MEMACCESS([uv_buf]) ",%%xmm0 \n" \ >- "lea " MEMLEA(0x8, [uv_buf]) ",%[uv_buf] \n" \ >- "punpcklwd %%xmm0,%%xmm0 \n" \ >- "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "punpcklbw %%xmm4,%%xmm4 \n" \ >- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" >+#define READNV12 \ >+ "movq (%[uv_buf]),%%xmm0 \n" \ >+ "lea 0x8(%[uv_buf]),%[uv_buf] \n" \ >+ "punpcklwd %%xmm0,%%xmm0 \n" \ >+ "movq (%[y_buf]),%%xmm4 \n" \ >+ "punpcklbw %%xmm4,%%xmm4 \n" \ >+ "lea 0x8(%[y_buf]),%[y_buf] \n" > > // Read 4 VU from NV21, upsample to 8 UV >-#define READNV21 \ >- "movq " MEMACCESS([vu_buf]) ",%%xmm0 \n" \ >- "lea " MEMLEA(0x8, [vu_buf]) ",%[vu_buf] \n" \ >- "pshufb %[kShuffleNV21], %%xmm0 \n" \ >- "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "punpcklbw %%xmm4,%%xmm4 \n" \ >- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" >+#define READNV21 \ >+ "movq (%[vu_buf]),%%xmm0 \n" \ >+ "lea 0x8(%[vu_buf]),%[vu_buf] \n" \ >+ "pshufb %[kShuffleNV21], %%xmm0 \n" \ >+ "movq (%[y_buf]),%%xmm4 \n" \ >+ "punpcklbw %%xmm4,%%xmm4 \n" \ >+ "lea 0x8(%[y_buf]),%[y_buf] \n" > > // Read 4 YUY2 with 8 Y and update 4 UV to 8 UV. >-#define READYUY2 \ >- "movdqu " MEMACCESS([yuy2_buf]) ",%%xmm4 \n" \ >- "pshufb %[kShuffleYUY2Y], %%xmm4 \n" \ >- "movdqu " MEMACCESS([yuy2_buf]) ",%%xmm0 \n" \ >- "pshufb %[kShuffleYUY2UV], %%xmm0 \n" \ >- "lea " MEMLEA(0x10, [yuy2_buf]) ",%[yuy2_buf] \n" >+#define READYUY2 \ >+ "movdqu (%[yuy2_buf]),%%xmm4 \n" \ >+ "pshufb %[kShuffleYUY2Y], %%xmm4 \n" \ >+ "movdqu (%[yuy2_buf]),%%xmm0 \n" \ >+ "pshufb %[kShuffleYUY2UV], %%xmm0 \n" \ >+ "lea 0x10(%[yuy2_buf]),%[yuy2_buf] \n" > > // Read 4 UYVY with 8 Y and update 4 UV to 8 UV. >-#define READUYVY \ >- "movdqu " MEMACCESS([uyvy_buf]) ",%%xmm4 \n" \ >- "pshufb %[kShuffleUYVYY], %%xmm4 \n" \ >- "movdqu " MEMACCESS([uyvy_buf]) ",%%xmm0 \n" \ >- "pshufb %[kShuffleUYVYUV], %%xmm0 \n" \ >- "lea " MEMLEA(0x10, [uyvy_buf]) ",%[uyvy_buf] \n" >+#define READUYVY \ >+ "movdqu (%[uyvy_buf]),%%xmm4 \n" \ >+ "pshufb %[kShuffleUYVYY], %%xmm4 \n" \ >+ "movdqu (%[uyvy_buf]),%%xmm0 \n" \ >+ "pshufb %[kShuffleUYVYUV], %%xmm0 \n" \ >+ "lea 0x10(%[uyvy_buf]),%[uyvy_buf] \n" > > #if defined(__x86_64__) >-#define YUVTORGB_SETUP(yuvconstants) \ >- "movdqa " MEMACCESS([yuvconstants]) ",%%xmm8 \n" \ >- "movdqa " MEMACCESS2(32, [yuvconstants]) ",%%xmm9 \n" \ >- "movdqa " MEMACCESS2(64, [yuvconstants]) ",%%xmm10 \n" \ >- "movdqa " MEMACCESS2(96, [yuvconstants]) ",%%xmm11 \n" \ >- "movdqa " MEMACCESS2(128, [yuvconstants]) ",%%xmm12 \n" \ >- "movdqa " MEMACCESS2(160, [yuvconstants]) ",%%xmm13 \n" \ >- "movdqa " MEMACCESS2(192, [yuvconstants]) ",%%xmm14 \n" >+#define YUVTORGB_SETUP(yuvconstants) \ >+ "movdqa (%[yuvconstants]),%%xmm8 \n" \ >+ "movdqa 32(%[yuvconstants]),%%xmm9 \n" \ >+ "movdqa 64(%[yuvconstants]),%%xmm10 \n" \ >+ "movdqa 96(%[yuvconstants]),%%xmm11 \n" \ >+ "movdqa 128(%[yuvconstants]),%%xmm12 \n" \ >+ "movdqa 160(%[yuvconstants]),%%xmm13 \n" \ >+ "movdqa 192(%[yuvconstants]),%%xmm14 \n" > // Convert 8 pixels: 8 UV and 8 Y >-#define YUVTORGB(yuvconstants) \ >+#define YUVTORGB16(yuvconstants) \ > "movdqa %%xmm0,%%xmm1 \n" \ > "movdqa %%xmm0,%%xmm2 \n" \ > "movdqa %%xmm0,%%xmm3 \n" \ >@@ -1590,72 +1776,95 @@ void RGBAToUVRow_SSSE3(const uint8* src_rgba0, > "pmulhuw %%xmm14,%%xmm4 \n" \ > "paddsw %%xmm4,%%xmm0 \n" \ > "paddsw %%xmm4,%%xmm1 \n" \ >- "paddsw %%xmm4,%%xmm2 \n" \ >- "psraw $0x6,%%xmm0 \n" \ >- "psraw $0x6,%%xmm1 \n" \ >- "psraw $0x6,%%xmm2 \n" \ >- "packuswb %%xmm0,%%xmm0 \n" \ >- "packuswb %%xmm1,%%xmm1 \n" \ >- "packuswb %%xmm2,%%xmm2 \n" >+ "paddsw %%xmm4,%%xmm2 \n" > #define YUVTORGB_REGS \ > "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", > > #else > #define YUVTORGB_SETUP(yuvconstants) > // Convert 8 pixels: 8 UV and 8 Y >-#define YUVTORGB(yuvconstants) \ >- "movdqa %%xmm0,%%xmm1 \n" \ >- "movdqa %%xmm0,%%xmm2 \n" \ >- "movdqa %%xmm0,%%xmm3 \n" \ >- "movdqa " MEMACCESS2(96, [yuvconstants]) ",%%xmm0 \n" \ >- "pmaddubsw " MEMACCESS([yuvconstants]) ",%%xmm1 \n" \ >- "psubw %%xmm1,%%xmm0 \n" \ >- "movdqa " MEMACCESS2(128, [yuvconstants]) ",%%xmm1 \n" \ >- "pmaddubsw " MEMACCESS2(32, [yuvconstants]) ",%%xmm2 \n" \ >- "psubw %%xmm2,%%xmm1 \n" \ >- "movdqa " MEMACCESS2(160, [yuvconstants]) ",%%xmm2 \n" \ >- "pmaddubsw " MEMACCESS2(64, [yuvconstants]) ",%%xmm3 \n" \ >- "psubw %%xmm3,%%xmm2 \n" \ >- "pmulhuw " MEMACCESS2(192, [yuvconstants]) ",%%xmm4 \n" \ >- "paddsw %%xmm4,%%xmm0 \n" \ >- "paddsw %%xmm4,%%xmm1 \n" \ >- "paddsw %%xmm4,%%xmm2 \n" \ >- "psraw $0x6,%%xmm0 \n" \ >- "psraw $0x6,%%xmm1 \n" \ >- "psraw $0x6,%%xmm2 \n" \ >- "packuswb %%xmm0,%%xmm0 \n" \ >- "packuswb %%xmm1,%%xmm1 \n" \ >- "packuswb %%xmm2,%%xmm2 \n" >+#define YUVTORGB16(yuvconstants) \ >+ "movdqa %%xmm0,%%xmm1 \n" \ >+ "movdqa %%xmm0,%%xmm2 \n" \ >+ "movdqa %%xmm0,%%xmm3 \n" \ >+ "movdqa 96(%[yuvconstants]),%%xmm0 \n" \ >+ "pmaddubsw (%[yuvconstants]),%%xmm1 \n" \ >+ "psubw %%xmm1,%%xmm0 \n" \ >+ "movdqa 128(%[yuvconstants]),%%xmm1 \n" \ >+ "pmaddubsw 32(%[yuvconstants]),%%xmm2 \n" \ >+ "psubw %%xmm2,%%xmm1 \n" \ >+ "movdqa 160(%[yuvconstants]),%%xmm2 \n" \ >+ "pmaddubsw 64(%[yuvconstants]),%%xmm3 \n" \ >+ "psubw %%xmm3,%%xmm2 \n" \ >+ "pmulhuw 192(%[yuvconstants]),%%xmm4 \n" \ >+ "paddsw %%xmm4,%%xmm0 \n" \ >+ "paddsw %%xmm4,%%xmm1 \n" \ >+ "paddsw %%xmm4,%%xmm2 \n" > #define YUVTORGB_REGS > #endif > >+#define YUVTORGB(yuvconstants) \ >+ YUVTORGB16(yuvconstants) \ >+ "psraw $0x6,%%xmm0 \n" \ >+ "psraw $0x6,%%xmm1 \n" \ >+ "psraw $0x6,%%xmm2 \n" \ >+ "packuswb %%xmm0,%%xmm0 \n" \ >+ "packuswb %%xmm1,%%xmm1 \n" \ >+ "packuswb %%xmm2,%%xmm2 \n" >+ > // Store 8 ARGB values. >-#define STOREARGB \ >- "punpcklbw %%xmm1,%%xmm0 \n" \ >- "punpcklbw %%xmm5,%%xmm2 \n" \ >- "movdqa %%xmm0,%%xmm1 \n" \ >- "punpcklwd %%xmm2,%%xmm0 \n" \ >- "punpckhwd %%xmm2,%%xmm1 \n" \ >- "movdqu %%xmm0," MEMACCESS([dst_argb]) " \n" \ >- "movdqu %%xmm1," MEMACCESS2(0x10, [dst_argb]) " \n" \ >- "lea " MEMLEA(0x20, [dst_argb]) ", %[dst_argb] \n" >+#define STOREARGB \ >+ "punpcklbw %%xmm1,%%xmm0 \n" \ >+ "punpcklbw %%xmm5,%%xmm2 \n" \ >+ "movdqa %%xmm0,%%xmm1 \n" \ >+ "punpcklwd %%xmm2,%%xmm0 \n" \ >+ "punpckhwd %%xmm2,%%xmm1 \n" \ >+ "movdqu %%xmm0,(%[dst_argb]) \n" \ >+ "movdqu %%xmm1,0x10(%[dst_argb]) \n" \ >+ "lea 0x20(%[dst_argb]), %[dst_argb] \n" > > // Store 8 RGBA values. >-#define STORERGBA \ >- "pcmpeqb %%xmm5,%%xmm5 \n" \ >- "punpcklbw %%xmm2,%%xmm1 \n" \ >- "punpcklbw %%xmm0,%%xmm5 \n" \ >- "movdqa %%xmm5,%%xmm0 \n" \ >- "punpcklwd %%xmm1,%%xmm5 \n" \ >- "punpckhwd %%xmm1,%%xmm0 \n" \ >- "movdqu %%xmm5," MEMACCESS([dst_rgba]) " \n" \ >- "movdqu %%xmm0," MEMACCESS2(0x10, [dst_rgba]) " \n" \ >- "lea " MEMLEA(0x20, [dst_rgba]) ",%[dst_rgba] \n" >- >-void OMITFP I444ToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+#define STORERGBA \ >+ "pcmpeqb %%xmm5,%%xmm5 \n" \ >+ "punpcklbw %%xmm2,%%xmm1 \n" \ >+ "punpcklbw %%xmm0,%%xmm5 \n" \ >+ "movdqa %%xmm5,%%xmm0 \n" \ >+ "punpcklwd %%xmm1,%%xmm5 \n" \ >+ "punpckhwd %%xmm1,%%xmm0 \n" \ >+ "movdqu %%xmm5,(%[dst_rgba]) \n" \ >+ "movdqu %%xmm0,0x10(%[dst_rgba]) \n" \ >+ "lea 0x20(%[dst_rgba]),%[dst_rgba] \n" >+ >+// Store 8 AR30 values. >+#define STOREAR30 \ >+ "psraw $0x4,%%xmm0 \n" \ >+ "psraw $0x4,%%xmm1 \n" \ >+ "psraw $0x4,%%xmm2 \n" \ >+ "pminsw %%xmm7,%%xmm0 \n" \ >+ "pminsw %%xmm7,%%xmm1 \n" \ >+ "pminsw %%xmm7,%%xmm2 \n" \ >+ "pmaxsw %%xmm6,%%xmm0 \n" \ >+ "pmaxsw %%xmm6,%%xmm1 \n" \ >+ "pmaxsw %%xmm6,%%xmm2 \n" \ >+ "psllw $0x4,%%xmm2 \n" \ >+ "movdqa %%xmm0,%%xmm3 \n" \ >+ "punpcklwd %%xmm2,%%xmm0 \n" \ >+ "punpckhwd %%xmm2,%%xmm3 \n" \ >+ "movdqa %%xmm1,%%xmm2 \n" \ >+ "punpcklwd %%xmm5,%%xmm1 \n" \ >+ "punpckhwd %%xmm5,%%xmm2 \n" \ >+ "pslld $0xa,%%xmm1 \n" \ >+ "pslld $0xa,%%xmm2 \n" \ >+ "por %%xmm1,%%xmm0 \n" \ >+ "por %%xmm2,%%xmm3 \n" \ >+ "movdqu %%xmm0,(%[dst_ar30]) \n" \ >+ "movdqu %%xmm3,0x10(%[dst_ar30]) \n" \ >+ "lea 0x20(%[dst_ar30]), %[dst_ar30] \n" >+ >+void OMITFP I444ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -1676,15 +1885,15 @@ void OMITFP I444ToARGBRow_SSSE3(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } > >-void OMITFP I422ToRGB24Row_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_rgb24, >+void OMITFP I422ToRGB24Row_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -1705,9 +1914,9 @@ void OMITFP I422ToRGB24Row_SSSE3(const uint8* y_buf, > "pshufb %%xmm5,%%xmm0 \n" > "pshufb %%xmm6,%%xmm1 \n" > "palignr $0xc,%%xmm0,%%xmm1 \n" >- "movq %%xmm0," MEMACCESS([dst_rgb24]) "\n" >- "movdqu %%xmm1," MEMACCESS2(0x8,[dst_rgb24]) "\n" >- "lea " MEMLEA(0x18,[dst_rgb24]) ",%[dst_rgb24] \n" >+ "movq %%xmm0,(%[dst_rgb24]) \n" >+ "movdqu %%xmm1,0x8(%[dst_rgb24]) \n" >+ "lea 0x18(%[dst_rgb24]),%[dst_rgb24] \n" > "subl $0x8,%[width] \n" > "jg 1b \n" > : [y_buf]"+r"(y_buf), // %[y_buf] >@@ -1722,15 +1931,15 @@ void OMITFP I422ToRGB24Row_SSSE3(const uint8* y_buf, > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleMaskARGBToRGB24_0]"m"(kShuffleMaskARGBToRGB24_0), > [kShuffleMaskARGBToRGB24]"m"(kShuffleMaskARGBToRGB24) >- : "memory", "cc", NACL_R14 YUVTORGB_REGS >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" > ); > } > >-void OMITFP I422ToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+void OMITFP I422ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -1751,17 +1960,116 @@ void OMITFP I422ToARGBRow_SSSE3(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS >+ : "memory", "cc", YUVTORGB_REGS >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >+ ); >+} >+ >+void OMITFP I422ToAR30Row_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" // AR30 constants >+ "psrlw $14,%%xmm5 \n" >+ "psllw $4,%%xmm5 \n" // 2 alpha bits >+ "pxor %%xmm6,%%xmm6 \n" >+ "pcmpeqb %%xmm7,%%xmm7 \n" // 0 for min >+ "psrlw $6,%%xmm7 \n" // 1023 for max >+ >+ LABELALIGN >+ "1: \n" >+ READYUV422 >+ YUVTORGB16(yuvconstants) >+ STOREAR30 >+ "sub $0x8,%[width] \n" >+ "jg 1b \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [dst_ar30]"+r"(dst_ar30), // %[dst_ar30] >+ [width]"+rm"(width) // %[width] >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >+ ); >+} >+ >+// 10 bit YUV to ARGB >+void OMITFP I210ToARGBRow_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ READYUV210 >+ YUVTORGB(yuvconstants) >+ STOREARGB >+ "sub $0x8,%[width] \n" >+ "jg 1b \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [dst_argb]"+r"(dst_argb), // %[dst_argb] >+ [width]"+rm"(width) // %[width] >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } > >+// 10 bit YUV to AR30 >+void OMITFP I210ToAR30Row_SSSE3(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $14,%%xmm5 \n" >+ "psllw $4,%%xmm5 \n" // 2 alpha bits >+ "pxor %%xmm6,%%xmm6 \n" >+ "pcmpeqb %%xmm7,%%xmm7 \n" // 0 for min >+ "psrlw $6,%%xmm7 \n" // 1023 for max >+ >+ LABELALIGN >+ "1: \n" >+ READYUV210 >+ YUVTORGB16(yuvconstants) >+ STOREAR30 >+ "sub $0x8,%[width] \n" >+ "jg 1b \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [dst_ar30]"+r"(dst_ar30), // %[dst_ar30] >+ [width]"+rm"(width) // %[width] >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >+ ); >+} >+ > #ifdef HAS_I422ALPHATOARGBROW_SSSE3 >-void OMITFP I422AlphaToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void OMITFP I422AlphaToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -1787,16 +2095,16 @@ void OMITFP I422AlphaToARGBRow_SSSE3(const uint8* y_buf, > [width]"+rm"(width) // %[width] > #endif > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on > } > #endif // HAS_I422ALPHATOARGBROW_SSSE3 > >-void OMITFP NV12ToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* uv_buf, >- uint8* dst_argb, >+void OMITFP NV12ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -1816,15 +2124,15 @@ void OMITFP NV12ToARGBRow_SSSE3(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", YUVTORGB_REGS // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on > } > >-void OMITFP NV21ToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* vu_buf, >- uint8* dst_argb, >+void OMITFP NV21ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -1845,14 +2153,14 @@ void OMITFP NV21ToARGBRow_SSSE3(const uint8* y_buf, > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleNV21]"m"(kShuffleNV21) >- : "memory", "cc", YUVTORGB_REGS // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on > } > >-void OMITFP YUY2ToARGBRow_SSSE3(const uint8* yuy2_buf, >- uint8* dst_argb, >+void OMITFP YUY2ToARGBRow_SSSE3(const uint8_t* yuy2_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -1873,14 +2181,14 @@ void OMITFP YUY2ToARGBRow_SSSE3(const uint8* yuy2_buf, > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleYUY2Y]"m"(kShuffleYUY2Y), > [kShuffleYUY2UV]"m"(kShuffleYUY2UV) >- : "memory", "cc", YUVTORGB_REGS // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on > } > >-void OMITFP UYVYToARGBRow_SSSE3(const uint8* uyvy_buf, >- uint8* dst_argb, >+void OMITFP UYVYToARGBRow_SSSE3(const uint8_t* uyvy_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -1901,16 +2209,16 @@ void OMITFP UYVYToARGBRow_SSSE3(const uint8* uyvy_buf, > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleUYVYY]"m"(kShuffleUYVYY), > [kShuffleUYVYUV]"m"(kShuffleUYVYUV) >- : "memory", "cc", YUVTORGB_REGS // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on > } > >-void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_rgba, >+void OMITFP I422ToRGBARow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -1931,7 +2239,7 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, > [dst_rgba]"+r"(dst_rgba), // %[dst_rgba] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS >+ : "memory", "cc", YUVTORGB_REGS > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } >@@ -1939,96 +2247,113 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, > #endif // HAS_I422TOARGBROW_SSSE3 > > // Read 16 UV from 444 >-#define READYUV444_AVX2 \ >- "vmovdqu " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(vmovdqu, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x10, [u_buf]) ",%[u_buf] \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" \ >- "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >- "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >- "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >- "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" >+#define READYUV444_AVX2 \ >+ "vmovdqu (%[u_buf]),%%xmm0 \n" \ >+ "vmovdqu 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x10(%[u_buf]),%[u_buf] \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" \ >+ "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%xmm4 \n" \ >+ "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >+ "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" > > // Read 8 UV from 422, upsample to 16 UV. >-#define READYUV422_AVX2 \ >- "vmovq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(vmovq, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ >- "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >- "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >- "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >- "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" >+#define READYUV422_AVX2 \ >+ "vmovq (%[u_buf]),%%xmm0 \n" \ >+ "vmovq 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x8(%[u_buf]),%[u_buf] \n" \ >+ "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%xmm4 \n" \ >+ "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >+ "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" >+ >+// Read 8 UV from 210 10 bit, upsample to 16 UV >+// TODO(fbarchard): Consider vshufb to replace pack/unpack >+// TODO(fbarchard): Consider vunpcklpd to combine the 2 registers into 1. >+#define READYUV210_AVX2 \ >+ "vmovdqu (%[u_buf]),%%xmm0 \n" \ >+ "vmovdqu 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x10(%[u_buf]),%[u_buf] \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" \ >+ "vpunpcklwd %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vpsraw $0x2,%%ymm0,%%ymm0 \n" \ >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%ymm4 \n" \ >+ "vpsllw $0x6,%%ymm4,%%ymm4 \n" \ >+ "lea 0x20(%[y_buf]),%[y_buf] \n" > > // Read 8 UV from 422, upsample to 16 UV. With 16 Alpha. >-#define READYUVA422_AVX2 \ >- "vmovq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ >- MEMOPREG(vmovq, 0x00, [u_buf], [v_buf], 1, xmm1) \ >- "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ >- "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >- "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >- "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >- "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" \ >- "vmovdqu " MEMACCESS([a_buf]) ",%%xmm5 \n" \ >- "vpermq $0xd8,%%ymm5,%%ymm5 \n" \ >- "lea " MEMLEA(0x10, [a_buf]) ",%[a_buf] \n" >+#define READYUVA422_AVX2 \ >+ "vmovq (%[u_buf]),%%xmm0 \n" \ >+ "vmovq 0x00(%[u_buf],%[v_buf],1),%%xmm1 \n" \ >+ "lea 0x8(%[u_buf]),%[u_buf] \n" \ >+ "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%xmm4 \n" \ >+ "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >+ "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" \ >+ "vmovdqu (%[a_buf]),%%xmm5 \n" \ >+ "vpermq $0xd8,%%ymm5,%%ymm5 \n" \ >+ "lea 0x10(%[a_buf]),%[a_buf] \n" > > // Read 8 UV from NV12, upsample to 16 UV. >-#define READNV12_AVX2 \ >- "vmovdqu " MEMACCESS([uv_buf]) ",%%xmm0 \n" \ >- "lea " MEMLEA(0x10, [uv_buf]) ",%[uv_buf] \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >- "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >- "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >- "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" >+#define READNV12_AVX2 \ >+ "vmovdqu (%[uv_buf]),%%xmm0 \n" \ >+ "lea 0x10(%[uv_buf]),%[uv_buf] \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%xmm4 \n" \ >+ "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >+ "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" > > // Read 8 VU from NV21, upsample to 16 UV. >-#define READNV21_AVX2 \ >- "vmovdqu " MEMACCESS([vu_buf]) ",%%xmm0 \n" \ >- "lea " MEMLEA(0x10, [vu_buf]) ",%[vu_buf] \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpshufb %[kShuffleNV21], %%ymm0, %%ymm0 \n" \ >- "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ >- "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >- "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >- "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" >+#define READNV21_AVX2 \ >+ "vmovdqu (%[vu_buf]),%%xmm0 \n" \ >+ "lea 0x10(%[vu_buf]),%[vu_buf] \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpshufb %[kShuffleNV21], %%ymm0, %%ymm0 \n" \ >+ "vmovdqu (%[y_buf]),%%xmm4 \n" \ >+ "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ >+ "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ >+ "lea 0x10(%[y_buf]),%[y_buf] \n" > > // Read 8 YUY2 with 16 Y and upsample 8 UV to 16 UV. >-#define READYUY2_AVX2 \ >- "vmovdqu " MEMACCESS([yuy2_buf]) ",%%ymm4 \n" \ >- "vpshufb %[kShuffleYUY2Y], %%ymm4, %%ymm4 \n" \ >- "vmovdqu " MEMACCESS([yuy2_buf]) ",%%ymm0 \n" \ >- "vpshufb %[kShuffleYUY2UV], %%ymm0, %%ymm0 \n" \ >- "lea " MEMLEA(0x20, [yuy2_buf]) ",%[yuy2_buf] \n" >+#define READYUY2_AVX2 \ >+ "vmovdqu (%[yuy2_buf]),%%ymm4 \n" \ >+ "vpshufb %[kShuffleYUY2Y], %%ymm4, %%ymm4 \n" \ >+ "vmovdqu (%[yuy2_buf]),%%ymm0 \n" \ >+ "vpshufb %[kShuffleYUY2UV], %%ymm0, %%ymm0 \n" \ >+ "lea 0x20(%[yuy2_buf]),%[yuy2_buf] \n" > > // Read 8 UYVY with 16 Y and upsample 8 UV to 16 UV. >-#define READUYVY_AVX2 \ >- "vmovdqu " MEMACCESS([uyvy_buf]) ",%%ymm4 \n" \ >- "vpshufb %[kShuffleUYVYY], %%ymm4, %%ymm4 \n" \ >- "vmovdqu " MEMACCESS([uyvy_buf]) ",%%ymm0 \n" \ >- "vpshufb %[kShuffleUYVYUV], %%ymm0, %%ymm0 \n" \ >- "lea " MEMLEA(0x20, [uyvy_buf]) ",%[uyvy_buf] \n" >+#define READUYVY_AVX2 \ >+ "vmovdqu (%[uyvy_buf]),%%ymm4 \n" \ >+ "vpshufb %[kShuffleUYVYY], %%ymm4, %%ymm4 \n" \ >+ "vmovdqu (%[uyvy_buf]),%%ymm0 \n" \ >+ "vpshufb %[kShuffleUYVYUV], %%ymm0, %%ymm0 \n" \ >+ "lea 0x20(%[uyvy_buf]),%[uyvy_buf] \n" > > #if defined(__x86_64__) >-#define YUVTORGB_SETUP_AVX2(yuvconstants) \ >- "vmovdqa " MEMACCESS([yuvconstants]) ",%%ymm8 \n" \ >- "vmovdqa " MEMACCESS2(32, [yuvconstants]) ",%%ymm9 \n" \ >- "vmovdqa " MEMACCESS2(64, [yuvconstants]) ",%%ymm10 \n" \ >- "vmovdqa " MEMACCESS2(96, [yuvconstants]) ",%%ymm11 \n" \ >- "vmovdqa " MEMACCESS2(128, [yuvconstants]) ",%%ymm12 \n" \ >- "vmovdqa " MEMACCESS2(160, [yuvconstants]) ",%%ymm13 \n" \ >- "vmovdqa " MEMACCESS2(192, [yuvconstants]) ",%%ymm14 \n" >- >-#define YUVTORGB_AVX2(yuvconstants) \ >+#define YUVTORGB_SETUP_AVX2(yuvconstants) \ >+ "vmovdqa (%[yuvconstants]),%%ymm8 \n" \ >+ "vmovdqa 32(%[yuvconstants]),%%ymm9 \n" \ >+ "vmovdqa 64(%[yuvconstants]),%%ymm10 \n" \ >+ "vmovdqa 96(%[yuvconstants]),%%ymm11 \n" \ >+ "vmovdqa 128(%[yuvconstants]),%%ymm12 \n" \ >+ "vmovdqa 160(%[yuvconstants]),%%ymm13 \n" \ >+ "vmovdqa 192(%[yuvconstants]),%%ymm14 \n" >+ >+#define YUVTORGB16_AVX2(yuvconstants) \ > "vpmaddubsw %%ymm10,%%ymm0,%%ymm2 \n" \ > "vpmaddubsw %%ymm9,%%ymm0,%%ymm1 \n" \ > "vpmaddubsw %%ymm8,%%ymm0,%%ymm0 \n" \ >@@ -2038,13 +2363,7 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, > "vpmulhuw %%ymm14,%%ymm4,%%ymm4 \n" \ > "vpaddsw %%ymm4,%%ymm0,%%ymm0 \n" \ > "vpaddsw %%ymm4,%%ymm1,%%ymm1 \n" \ >- "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" \ >- "vpsraw $0x6,%%ymm0,%%ymm0 \n" \ >- "vpsraw $0x6,%%ymm1,%%ymm1 \n" \ >- "vpsraw $0x6,%%ymm2,%%ymm2 \n" \ >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" \ >- "vpackuswb %%ymm2,%%ymm2,%%ymm2 \n" >+ "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" > > #define YUVTORGB_REGS_AVX2 \ > "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", >@@ -2052,48 +2371,78 @@ void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, > #else // Convert 16 pixels: 16 UV and 16 Y. > > #define YUVTORGB_SETUP_AVX2(yuvconstants) >-#define YUVTORGB_AVX2(yuvconstants) \ >- "vpmaddubsw " MEMACCESS2(64, [yuvconstants]) ",%%ymm0,%%ymm2 \n" \ >- "vpmaddubsw " MEMACCESS2(32, [yuvconstants]) ",%%ymm0,%%ymm1 \n" \ >- "vpmaddubsw " MEMACCESS([yuvconstants]) ",%%ymm0,%%ymm0 \n" \ >- "vmovdqu " MEMACCESS2(160, [yuvconstants]) ",%%ymm3 \n" \ >- "vpsubw %%ymm2,%%ymm3,%%ymm2 \n" \ >- "vmovdqu " MEMACCESS2(128, [yuvconstants]) ",%%ymm3 \n" \ >- "vpsubw %%ymm1,%%ymm3,%%ymm1 \n" \ >- "vmovdqu " MEMACCESS2(96, [yuvconstants]) ",%%ymm3 \n" \ >- "vpsubw %%ymm0,%%ymm3,%%ymm0 \n" \ >- "vpmulhuw " MEMACCESS2(192, [yuvconstants]) ",%%ymm4,%%ymm4 \n" \ >- "vpaddsw %%ymm4,%%ymm0,%%ymm0 \n" \ >- "vpaddsw %%ymm4,%%ymm1,%%ymm1 \n" \ >- "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" \ >- "vpsraw $0x6,%%ymm0,%%ymm0 \n" \ >- "vpsraw $0x6,%%ymm1,%%ymm1 \n" \ >- "vpsraw $0x6,%%ymm2,%%ymm2 \n" \ >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" \ >- "vpackuswb %%ymm2,%%ymm2,%%ymm2 \n" >+#define YUVTORGB16_AVX2(yuvconstants) \ >+ "vpmaddubsw 64(%[yuvconstants]),%%ymm0,%%ymm2 \n" \ >+ "vpmaddubsw 32(%[yuvconstants]),%%ymm0,%%ymm1 \n" \ >+ "vpmaddubsw (%[yuvconstants]),%%ymm0,%%ymm0 \n" \ >+ "vmovdqu 160(%[yuvconstants]),%%ymm3 \n" \ >+ "vpsubw %%ymm2,%%ymm3,%%ymm2 \n" \ >+ "vmovdqu 128(%[yuvconstants]),%%ymm3 \n" \ >+ "vpsubw %%ymm1,%%ymm3,%%ymm1 \n" \ >+ "vmovdqu 96(%[yuvconstants]),%%ymm3 \n" \ >+ "vpsubw %%ymm0,%%ymm3,%%ymm0 \n" \ >+ "vpmulhuw 192(%[yuvconstants]),%%ymm4,%%ymm4 \n" \ >+ "vpaddsw %%ymm4,%%ymm0,%%ymm0 \n" \ >+ "vpaddsw %%ymm4,%%ymm1,%%ymm1 \n" \ >+ "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" > #define YUVTORGB_REGS_AVX2 > #endif > >+#define YUVTORGB_AVX2(yuvconstants) \ >+ YUVTORGB16_AVX2(yuvconstants) \ >+ "vpsraw $0x6,%%ymm0,%%ymm0 \n" \ >+ "vpsraw $0x6,%%ymm1,%%ymm1 \n" \ >+ "vpsraw $0x6,%%ymm2,%%ymm2 \n" \ >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ >+ "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" \ >+ "vpackuswb %%ymm2,%%ymm2,%%ymm2 \n" >+ > // Store 16 ARGB values. >-#define STOREARGB_AVX2 \ >- "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >- "vpunpcklbw %%ymm5,%%ymm2,%%ymm2 \n" \ >- "vpermq $0xd8,%%ymm2,%%ymm2 \n" \ >- "vpunpcklwd %%ymm2,%%ymm0,%%ymm1 \n" \ >- "vpunpckhwd %%ymm2,%%ymm0,%%ymm0 \n" \ >- "vmovdqu %%ymm1," MEMACCESS([dst_argb]) " \n" \ >- "vmovdqu %%ymm0," MEMACCESS2(0x20, [dst_argb]) " \n" \ >- "lea " MEMLEA(0x40, [dst_argb]) ", %[dst_argb] \n" >+#define STOREARGB_AVX2 \ >+ "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpunpcklbw %%ymm5,%%ymm2,%%ymm2 \n" \ >+ "vpermq $0xd8,%%ymm2,%%ymm2 \n" \ >+ "vpunpcklwd %%ymm2,%%ymm0,%%ymm1 \n" \ >+ "vpunpckhwd %%ymm2,%%ymm0,%%ymm0 \n" \ >+ "vmovdqu %%ymm1,(%[dst_argb]) \n" \ >+ "vmovdqu %%ymm0,0x20(%[dst_argb]) \n" \ >+ "lea 0x40(%[dst_argb]), %[dst_argb] \n" >+ >+// Store 16 AR30 values. >+#define STOREAR30_AVX2 \ >+ "vpsraw $0x4,%%ymm0,%%ymm0 \n" \ >+ "vpsraw $0x4,%%ymm1,%%ymm1 \n" \ >+ "vpsraw $0x4,%%ymm2,%%ymm2 \n" \ >+ "vpminsw %%ymm7,%%ymm0,%%ymm0 \n" \ >+ "vpminsw %%ymm7,%%ymm1,%%ymm1 \n" \ >+ "vpminsw %%ymm7,%%ymm2,%%ymm2 \n" \ >+ "vpmaxsw %%ymm6,%%ymm0,%%ymm0 \n" \ >+ "vpmaxsw %%ymm6,%%ymm1,%%ymm1 \n" \ >+ "vpmaxsw %%ymm6,%%ymm2,%%ymm2 \n" \ >+ "vpsllw $0x4,%%ymm2,%%ymm2 \n" \ >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" \ >+ "vpermq $0xd8,%%ymm2,%%ymm2 \n" \ >+ "vpunpckhwd %%ymm2,%%ymm0,%%ymm3 \n" \ >+ "vpunpcklwd %%ymm2,%%ymm0,%%ymm0 \n" \ >+ "vpunpckhwd %%ymm5,%%ymm1,%%ymm2 \n" \ >+ "vpunpcklwd %%ymm5,%%ymm1,%%ymm1 \n" \ >+ "vpslld $0xa,%%ymm1,%%ymm1 \n" \ >+ "vpslld $0xa,%%ymm2,%%ymm2 \n" \ >+ "vpor %%ymm1,%%ymm0,%%ymm0 \n" \ >+ "vpor %%ymm2,%%ymm3,%%ymm3 \n" \ >+ "vmovdqu %%ymm0,(%[dst_ar30]) \n" \ >+ "vmovdqu %%ymm3,0x20(%[dst_ar30]) \n" \ >+ "lea 0x40(%[dst_ar30]), %[dst_ar30] \n" > > #ifdef HAS_I444TOARGBROW_AVX2 > // 16 pixels > // 16 UV values with 16 Y producing 16 ARGB (64 bytes). >-void OMITFP I444ToARGBRow_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+void OMITFP I444ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -2115,7 +2464,7 @@ void OMITFP I444ToARGBRow_AVX2(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } >@@ -2124,10 +2473,10 @@ void OMITFP I444ToARGBRow_AVX2(const uint8* y_buf, > #if defined(HAS_I422TOARGBROW_AVX2) > // 16 pixels > // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). >-void OMITFP I422ToARGBRow_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+void OMITFP I422ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -2150,84 +2499,74 @@ void OMITFP I422ToARGBRow_AVX2(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } > #endif // HAS_I422TOARGBROW_AVX2 > >-#if defined(HAS_I422ALPHATOARGBROW_AVX2) >+#if defined(HAS_I422TOAR30ROW_AVX2) > // 16 pixels >-// 8 UV values upsampled to 16 UV, mixed with 16 Y and 16 A producing 16 ARGB. >-void OMITFP I422AlphaToARGBRow_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >- const struct YuvConstants* yuvconstants, >- int width) { >- // clang-format off >+// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 AR30 (64 bytes). >+void OMITFP I422ToAR30Row_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width) { > asm volatile ( > YUVTORGB_SETUP_AVX2(yuvconstants) > "sub %[u_buf],%[v_buf] \n" >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" // AR30 constants >+ "vpsrlw $14,%%ymm5,%%ymm5 \n" >+ "vpsllw $4,%%ymm5,%%ymm5 \n" // 2 alpha bits >+ "vpxor %%ymm6,%%ymm6,%%ymm6 \n" // 0 for min >+ "vpcmpeqb %%ymm7,%%ymm7,%%ymm7 \n" // 1023 for max >+ "vpsrlw $6,%%ymm7,%%ymm7 \n" > > LABELALIGN > "1: \n" >- READYUVA422_AVX2 >- YUVTORGB_AVX2(yuvconstants) >- STOREARGB_AVX2 >- "subl $0x10,%[width] \n" >+ READYUV422_AVX2 >+ YUVTORGB16_AVX2(yuvconstants) >+ STOREAR30_AVX2 >+ "sub $0x10,%[width] \n" > "jg 1b \n" >+ > "vzeroupper \n" > : [y_buf]"+r"(y_buf), // %[y_buf] > [u_buf]"+r"(u_buf), // %[u_buf] > [v_buf]"+r"(v_buf), // %[v_buf] >- [a_buf]"+r"(a_buf), // %[a_buf] >- [dst_argb]"+r"(dst_argb), // %[dst_argb] >-#if defined(__i386__) >- [width]"+m"(width) // %[width] >-#else >+ [dst_ar30]"+r"(dst_ar30), // %[dst_ar30] > [width]"+rm"(width) // %[width] >-#endif > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >+ : "memory", "cc", YUVTORGB_REGS_AVX2 >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" > ); >- // clang-format on > } >-#endif // HAS_I422ALPHATOARGBROW_AVX2 >+#endif // HAS_I422TOAR30ROW_AVX2 > >-#if defined(HAS_I422TORGBAROW_AVX2) >+#if defined(HAS_I210TOARGBROW_AVX2) > // 16 pixels >-// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 RGBA (64 bytes). >-void OMITFP I422ToRGBARow_AVX2(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). >+void OMITFP I210ToARGBRow_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( > YUVTORGB_SETUP_AVX2(yuvconstants) > "sub %[u_buf],%[v_buf] \n" >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" > > LABELALIGN > "1: \n" >- READYUV422_AVX2 >+ READYUV210_AVX2 > YUVTORGB_AVX2(yuvconstants) >- >- // Step 3: Weave into RGBA >- "vpunpcklbw %%ymm2,%%ymm1,%%ymm1 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpunpcklbw %%ymm0,%%ymm5,%%ymm2 \n" >- "vpermq $0xd8,%%ymm2,%%ymm2 \n" >- "vpunpcklwd %%ymm1,%%ymm2,%%ymm0 \n" >- "vpunpckhwd %%ymm1,%%ymm2,%%ymm1 \n" >- "vmovdqu %%ymm0," MEMACCESS([dst_argb]) "\n" >- "vmovdqu %%ymm1," MEMACCESS2(0x20,[dst_argb]) "\n" >- "lea " MEMLEA(0x40,[dst_argb]) ",%[dst_argb] \n" >+ STOREARGB_AVX2 > "sub $0x10,%[width] \n" > "jg 1b \n" >+ > "vzeroupper \n" > : [y_buf]"+r"(y_buf), // %[y_buf] > [u_buf]"+r"(u_buf), // %[u_buf] >@@ -2235,18 +2574,143 @@ void OMITFP I422ToRGBARow_AVX2(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > } >-#endif // HAS_I422TORGBAROW_AVX2 >+#endif // HAS_I210TOARGBROW_AVX2 > >-#if defined(HAS_NV12TOARGBROW_AVX2) >-// 16 pixels. >+#if defined(HAS_I210TOAR30ROW_AVX2) >+// 16 pixels >+// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 AR30 (64 bytes). >+void OMITFP I210ToAR30Row_AVX2(const uint16_t* y_buf, >+ const uint16_t* u_buf, >+ const uint16_t* v_buf, >+ uint8_t* dst_ar30, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP_AVX2(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" // AR30 constants >+ "vpsrlw $14,%%ymm5,%%ymm5 \n" >+ "vpsllw $4,%%ymm5,%%ymm5 \n" // 2 alpha bits >+ "vpxor %%ymm6,%%ymm6,%%ymm6 \n" // 0 for min >+ "vpcmpeqb %%ymm7,%%ymm7,%%ymm7 \n" // 1023 for max >+ "vpsrlw $6,%%ymm7,%%ymm7 \n" >+ >+ LABELALIGN >+ "1: \n" >+ READYUV210_AVX2 >+ YUVTORGB16_AVX2(yuvconstants) >+ STOREAR30_AVX2 >+ "sub $0x10,%[width] \n" >+ "jg 1b \n" >+ >+ "vzeroupper \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [dst_ar30]"+r"(dst_ar30), // %[dst_ar30] >+ [width]"+rm"(width) // %[width] >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS_AVX2 >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >+ ); >+} >+#endif // HAS_I210TOAR30ROW_AVX2 >+ >+#if defined(HAS_I422ALPHATOARGBROW_AVX2) >+// 16 pixels >+// 8 UV values upsampled to 16 UV, mixed with 16 Y and 16 A producing 16 ARGB. >+void OMITFP I422AlphaToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ // clang-format off >+ asm volatile ( >+ YUVTORGB_SETUP_AVX2(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ >+ LABELALIGN >+ "1: \n" >+ READYUVA422_AVX2 >+ YUVTORGB_AVX2(yuvconstants) >+ STOREARGB_AVX2 >+ "subl $0x10,%[width] \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [a_buf]"+r"(a_buf), // %[a_buf] >+ [dst_argb]"+r"(dst_argb), // %[dst_argb] >+#if defined(__i386__) >+ [width]"+m"(width) // %[width] >+#else >+ [width]"+rm"(width) // %[width] >+#endif >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS_AVX2 >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >+ ); >+ // clang-format on >+} >+#endif // HAS_I422ALPHATOARGBROW_AVX2 >+ >+#if defined(HAS_I422TORGBAROW_AVX2) >+// 16 pixels >+// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 RGBA (64 bytes). >+void OMITFP I422ToRGBARow_AVX2(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP_AVX2(yuvconstants) >+ "sub %[u_buf],%[v_buf] \n" >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ READYUV422_AVX2 >+ YUVTORGB_AVX2(yuvconstants) >+ >+ // Step 3: Weave into RGBA >+ "vpunpcklbw %%ymm2,%%ymm1,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpunpcklbw %%ymm0,%%ymm5,%%ymm2 \n" >+ "vpermq $0xd8,%%ymm2,%%ymm2 \n" >+ "vpunpcklwd %%ymm1,%%ymm2,%%ymm0 \n" >+ "vpunpckhwd %%ymm1,%%ymm2,%%ymm1 \n" >+ "vmovdqu %%ymm0,(%[dst_argb]) \n" >+ "vmovdqu %%ymm1,0x20(%[dst_argb]) \n" >+ "lea 0x40(%[dst_argb]),%[dst_argb] \n" >+ "sub $0x10,%[width] \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : [y_buf]"+r"(y_buf), // %[y_buf] >+ [u_buf]"+r"(u_buf), // %[u_buf] >+ [v_buf]"+r"(v_buf), // %[v_buf] >+ [dst_argb]"+r"(dst_argb), // %[dst_argb] >+ [width]"+rm"(width) // %[width] >+ : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >+ : "memory", "cc", YUVTORGB_REGS_AVX2 >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >+ ); >+} >+#endif // HAS_I422TORGBAROW_AVX2 >+ >+#if defined(HAS_NV12TOARGBROW_AVX2) >+// 16 pixels. > // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). >-void OMITFP NV12ToARGBRow_AVX2(const uint8* y_buf, >- const uint8* uv_buf, >- uint8* dst_argb, >+void OMITFP NV12ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -2267,7 +2731,7 @@ void OMITFP NV12ToARGBRow_AVX2(const uint8* y_buf, > [dst_argb]"+r"(dst_argb), // %[dst_argb] > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] >- : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on >@@ -2277,9 +2741,9 @@ void OMITFP NV12ToARGBRow_AVX2(const uint8* y_buf, > #if defined(HAS_NV21TOARGBROW_AVX2) > // 16 pixels. > // 8 VU values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). >-void OMITFP NV21ToARGBRow_AVX2(const uint8* y_buf, >- const uint8* vu_buf, >- uint8* dst_argb, >+void OMITFP NV21ToARGBRow_AVX2(const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -2301,7 +2765,7 @@ void OMITFP NV21ToARGBRow_AVX2(const uint8* y_buf, > [width]"+rm"(width) // %[width] > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleNV21]"m"(kShuffleNV21) >- : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on >@@ -2311,8 +2775,8 @@ void OMITFP NV21ToARGBRow_AVX2(const uint8* y_buf, > #if defined(HAS_YUY2TOARGBROW_AVX2) > // 16 pixels. > // 8 YUY2 values with 16 Y and 8 UV producing 16 ARGB (64 bytes). >-void OMITFP YUY2ToARGBRow_AVX2(const uint8* yuy2_buf, >- uint8* dst_argb, >+void OMITFP YUY2ToARGBRow_AVX2(const uint8_t* yuy2_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -2334,7 +2798,7 @@ void OMITFP YUY2ToARGBRow_AVX2(const uint8* yuy2_buf, > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleYUY2Y]"m"(kShuffleYUY2Y), > [kShuffleYUY2UV]"m"(kShuffleYUY2UV) >- : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on >@@ -2344,8 +2808,8 @@ void OMITFP YUY2ToARGBRow_AVX2(const uint8* yuy2_buf, > #if defined(HAS_UYVYTOARGBROW_AVX2) > // 16 pixels. > // 8 UYVY values with 16 Y and 8 UV producing 16 ARGB (64 bytes). >-void OMITFP UYVYToARGBRow_AVX2(const uint8* uyvy_buf, >- uint8* dst_argb, >+void OMITFP UYVYToARGBRow_AVX2(const uint8_t* uyvy_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > // clang-format off >@@ -2367,7 +2831,7 @@ void OMITFP UYVYToARGBRow_AVX2(const uint8* uyvy_buf, > : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] > [kShuffleUYVYY]"m"(kShuffleUYVYY), > [kShuffleUYVYUV]"m"(kShuffleUYVYUV) >- : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. >+ : "memory", "cc", YUVTORGB_REGS_AVX2 > "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" > ); > // clang-format on >@@ -2375,381 +2839,367 @@ void OMITFP UYVYToARGBRow_AVX2(const uint8* uyvy_buf, > #endif // HAS_UYVYTOARGBROW_AVX2 > > #ifdef HAS_I400TOARGBROW_SSE2 >-void I400ToARGBRow_SSE2(const uint8* y_buf, uint8* dst_argb, int width) { >- asm volatile ( >- "mov $0x4a354a35,%%eax \n" // 4a35 = 18997 = 1.164 >- "movd %%eax,%%xmm2 \n" >- "pshufd $0x0,%%xmm2,%%xmm2 \n" >- "mov $0x04880488,%%eax \n" // 0488 = 1160 = 1.164 * 16 >- "movd %%eax,%%xmm3 \n" >- "pshufd $0x0,%%xmm3,%%xmm3 \n" >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "pslld $0x18,%%xmm4 \n" >+void I400ToARGBRow_SSE2(const uint8_t* y_buf, uint8_t* dst_argb, int width) { >+ asm volatile( >+ "mov $0x4a354a35,%%eax \n" // 4a35 = 18997 = 1.164 >+ "movd %%eax,%%xmm2 \n" >+ "pshufd $0x0,%%xmm2,%%xmm2 \n" >+ "mov $0x04880488,%%eax \n" // 0488 = 1160 = 1.164 * >+ // 16 >+ "movd %%eax,%%xmm3 \n" >+ "pshufd $0x0,%%xmm3,%%xmm3 \n" >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "pslld $0x18,%%xmm4 \n" > >- LABELALIGN >- "1: \n" >- // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164 >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "pmulhuw %%xmm2,%%xmm0 \n" >- "psubusw %%xmm3,%%xmm0 \n" >- "psrlw $6, %%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- >- // Step 2: Weave into ARGB >- "punpcklbw %%xmm0,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklwd %%xmm0,%%xmm0 \n" >- "punpckhwd %%xmm1,%%xmm1 \n" >- "por %%xmm4,%%xmm0 \n" >- "por %%xmm4,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(y_buf), // %0 >- "+r"(dst_argb), // %1 >- "+rm"(width) // %2 >- : >- : "memory", "cc", "eax" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" >- ); >+ LABELALIGN >+ "1: \n" >+ // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164 >+ "movq (%0),%%xmm0 \n" >+ "lea 0x8(%0),%0 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "psubusw %%xmm3,%%xmm0 \n" >+ "psrlw $6, %%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ >+ // Step 2: Weave into ARGB >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklwd %%xmm0,%%xmm0 \n" >+ "punpckhwd %%xmm1,%%xmm1 \n" >+ "por %%xmm4,%%xmm0 \n" >+ "por %%xmm4,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(y_buf), // %0 >+ "+r"(dst_argb), // %1 >+ "+rm"(width) // %2 >+ : >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); > } > #endif // HAS_I400TOARGBROW_SSE2 > > #ifdef HAS_I400TOARGBROW_AVX2 > // 16 pixels of Y converted to 16 pixels of ARGB (64 bytes). > // note: vpunpcklbw mutates and vpackuswb unmutates. >-void I400ToARGBRow_AVX2(const uint8* y_buf, uint8* dst_argb, int width) { >- asm volatile ( >- "mov $0x4a354a35,%%eax \n" // 0488 = 1160 = 1.164 * 16 >- "vmovd %%eax,%%xmm2 \n" >- "vbroadcastss %%xmm2,%%ymm2 \n" >- "mov $0x4880488,%%eax \n" // 4a35 = 18997 = 1.164 >- "vmovd %%eax,%%xmm3 \n" >- "vbroadcastss %%xmm3,%%ymm3 \n" >- "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpslld $0x18,%%ymm4,%%ymm4 \n" >+void I400ToARGBRow_AVX2(const uint8_t* y_buf, uint8_t* dst_argb, int width) { >+ asm volatile( >+ "mov $0x4a354a35,%%eax \n" // 0488 = 1160 = 1.164 * >+ // 16 >+ "vmovd %%eax,%%xmm2 \n" >+ "vbroadcastss %%xmm2,%%ymm2 \n" >+ "mov $0x4880488,%%eax \n" // 4a35 = 18997 = 1.164 >+ "vmovd %%eax,%%xmm3 \n" >+ "vbroadcastss %%xmm3,%%ymm3 \n" >+ "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpslld $0x18,%%ymm4,%%ymm4 \n" > >- LABELALIGN >- "1: \n" >- // Step 1: Scale Y contribution to 16 G values. G = (y - 16) * 1.164 >- "vmovdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpunpcklbw %%ymm0,%%ymm0,%%ymm0 \n" >- "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpsubusw %%ymm3,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x6,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpunpcklbw %%ymm0,%%ymm0,%%ymm1 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpunpcklwd %%ymm1,%%ymm1,%%ymm0 \n" >- "vpunpckhwd %%ymm1,%%ymm1,%%ymm1 \n" >- "vpor %%ymm4,%%ymm0,%%ymm0 \n" >- "vpor %%ymm4,%%ymm1,%%ymm1 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(y_buf), // %0 >- "+r"(dst_argb), // %1 >- "+rm"(width) // %2 >- : >- : "memory", "cc", "eax" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" >- ); >+ LABELALIGN >+ "1: \n" >+ // Step 1: Scale Y contribution to 16 G values. G = (y - 16) * 1.164 >+ "vmovdqu (%0),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpunpcklbw %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpsubusw %%ymm3,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x6,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpunpcklbw %%ymm0,%%ymm0,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpunpcklwd %%ymm1,%%ymm1,%%ymm0 \n" >+ "vpunpckhwd %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpor %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpor %%ymm4,%%ymm1,%%ymm1 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm1,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(y_buf), // %0 >+ "+r"(dst_argb), // %1 >+ "+rm"(width) // %2 >+ : >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); > } > #endif // HAS_I400TOARGBROW_AVX2 > > #ifdef HAS_MIRRORROW_SSSE3 > // Shuffle table for reversing the bytes. >-static uvec8 kShuffleMirror = {15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, >- 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; >+static const uvec8 kShuffleMirror = {15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, >+ 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; > >-void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width) { >+void MirrorRow_SSSE3(const uint8_t* src, uint8_t* dst, int width) { > intptr_t temp_width = (intptr_t)(width); >- asm volatile ( >- "movdqa %3,%%xmm5 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- MEMOPREG(movdqu,-0x10,0,2,1,xmm0) // movdqu -0x10(%0,%2),%%xmm0 >- "pshufb %%xmm5,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(temp_width) // %2 >- : "m"(kShuffleMirror) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm5" >- ); >+ "movdqa %3,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu -0x10(%0,%2,1),%%xmm0 \n" >+ "pshufb %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(temp_width) // %2 >+ : "m"(kShuffleMirror) // %3 >+ : "memory", "cc", "xmm0", "xmm5"); > } > #endif // HAS_MIRRORROW_SSSE3 > > #ifdef HAS_MIRRORROW_AVX2 >-void MirrorRow_AVX2(const uint8* src, uint8* dst, int width) { >+void MirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { > intptr_t temp_width = (intptr_t)(width); >- asm volatile ( >- "vbroadcastf128 %3,%%ymm5 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- MEMOPREG(vmovdqu,-0x20,0,2,1,ymm0) // vmovdqu -0x20(%0,%2),%%ymm0 >- "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" >- "vpermq $0x4e,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(temp_width) // %2 >- : "m"(kShuffleMirror) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm5" >- ); >+ "vbroadcastf128 %3,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu -0x20(%0,%2,1),%%ymm0 \n" >+ "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpermq $0x4e,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(temp_width) // %2 >+ : "m"(kShuffleMirror) // %3 >+ : "memory", "cc", "xmm0", "xmm5"); > } > #endif // HAS_MIRRORROW_AVX2 > > #ifdef HAS_MIRRORUVROW_SSSE3 > // Shuffle table for reversing the bytes of UV channels. >-static uvec8 kShuffleMirrorUV = {14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, >- 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u}; >-void MirrorUVRow_SSSE3(const uint8* src, >- uint8* dst_u, >- uint8* dst_v, >+static const uvec8 kShuffleMirrorUV = {14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, >+ 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u}; >+void MirrorUVRow_SSSE3(const uint8_t* src, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > intptr_t temp_width = (intptr_t)(width); >- asm volatile ( >- "movdqa %4,%%xmm1 \n" >- "lea " MEMLEA4(-0x10,0,3,2) ",%0 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "movdqa %4,%%xmm1 \n" >+ "lea -0x10(%0,%3,2),%0 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(-0x10,0) ",%0 \n" >- "pshufb %%xmm1,%%xmm0 \n" >- "movlpd %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movhpd,xmm0,0x00,1,2,1) // movhpd %%xmm0,(%1,%2) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $8,%3 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(temp_width) // %3 >- : "m"(kShuffleMirrorUV) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "lea -0x10(%0),%0 \n" >+ "pshufb %%xmm1,%%xmm0 \n" >+ "movlpd %%xmm0,(%1) \n" >+ "movhpd %%xmm0,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $8,%3 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(temp_width) // %3 >+ : "m"(kShuffleMirrorUV) // %4 >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_MIRRORUVROW_SSSE3 > > #ifdef HAS_ARGBMIRRORROW_SSE2 > >-void ARGBMirrorRow_SSE2(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { > intptr_t temp_width = (intptr_t)(width); >- asm volatile ( >- "lea " MEMLEA4(-0x10,0,2,4) ",%0 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "pshufd $0x1b,%%xmm0,%%xmm0 \n" >- "lea " MEMLEA(-0x10,0) ",%0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(temp_width) // %2 >- : >- : "memory", "cc" >- , "xmm0" >- ); >+ "lea -0x10(%0,%2,4),%0 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "pshufd $0x1b,%%xmm0,%%xmm0 \n" >+ "lea -0x10(%0),%0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(temp_width) // %2 >+ : >+ : "memory", "cc", "xmm0"); > } > #endif // HAS_ARGBMIRRORROW_SSE2 > > #ifdef HAS_ARGBMIRRORROW_AVX2 > // Shuffle table for reversing the bytes. > static const ulvec32 kARGBShuffleMirror_AVX2 = {7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; >-void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { > intptr_t temp_width = (intptr_t)(width); >- asm volatile ( >- "vmovdqu %3,%%ymm5 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- VMEMOPREG(vpermd,-0x20,0,2,4,ymm5,ymm0) // vpermd -0x20(%0,%2,4),ymm5,ymm0 >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(temp_width) // %2 >- : "m"(kARGBShuffleMirror_AVX2) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm5" >- ); >+ "vmovdqu %3,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vpermd -0x20(%0,%2,4),%%ymm5,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(temp_width) // %2 >+ : "m"(kARGBShuffleMirror_AVX2) // %3 >+ : "memory", "cc", "xmm0", "xmm5"); > } > #endif // HAS_ARGBMIRRORROW_AVX2 > > #ifdef HAS_SPLITUVROW_AVX2 >-void SplitUVRow_AVX2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_AVX2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm2 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm3 \n" >- "vpand %%ymm5,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm3,%%ymm2,%%ymm2 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm2,%%ymm2 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- MEMOPMEM(vmovdqu,ymm2,0x00,1,2,1) // vmovdqu %%ymm2,(%1,%2) >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_uv), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm2 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm3 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm3,%%ymm2,%%ymm2 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm2,%%ymm2 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm2,0x00(%1,%2,1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_uv), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SPLITUVROW_AVX2 > > #ifdef HAS_SPLITUVROW_SSE2 >-void SplitUVRow_SSE2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_SSE2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "movdqa %%xmm1,%%xmm3 \n" >- "pand %%xmm5,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "psrlw $0x8,%%xmm2 \n" >- "psrlw $0x8,%%xmm3 \n" >- "packuswb %%xmm3,%%xmm2 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movdqu,xmm2,0x00,1,2,1) // movdqu %%xmm2,(%1,%2) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_uv), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "movdqa %%xmm1,%%xmm3 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "psrlw $0x8,%%xmm2 \n" >+ "psrlw $0x8,%%xmm3 \n" >+ "packuswb %%xmm3,%%xmm2 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm2,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_uv), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SPLITUVROW_SSE2 > > #ifdef HAS_MERGEUVROW_AVX2 >-void MergeUVRow_AVX2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_AVX2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- MEMOPREG(vmovdqu,0x00,0,1,1,ymm1) // vmovdqu (%0,%1,1),%%ymm1 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "vpunpcklbw %%ymm1,%%ymm0,%%ymm2 \n" >- "vpunpckhbw %%ymm1,%%ymm0,%%ymm0 \n" >- "vextractf128 $0x0,%%ymm2," MEMACCESS(2) " \n" >- "vextractf128 $0x0,%%ymm0," MEMACCESS2(0x10,2) "\n" >- "vextractf128 $0x1,%%ymm2," MEMACCESS2(0x20,2) "\n" >- "vextractf128 $0x1,%%ymm0," MEMACCESS2(0x30,2) "\n" >- "lea " MEMLEA(0x40,2) ",%2 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_u), // %0 >- "+r"(src_v), // %1 >- "+r"(dst_uv), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2" >- ); >+ "sub %0,%1 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x00(%0,%1,1),%%ymm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "vpunpcklbw %%ymm1,%%ymm0,%%ymm2 \n" >+ "vpunpckhbw %%ymm1,%%ymm0,%%ymm0 \n" >+ "vextractf128 $0x0,%%ymm2,(%2) \n" >+ "vextractf128 $0x0,%%ymm0,0x10(%2) \n" >+ "vextractf128 $0x1,%%ymm2,0x20(%2) \n" >+ "vextractf128 $0x1,%%ymm0,0x30(%2) \n" >+ "lea 0x40(%2),%2 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_u), // %0 >+ "+r"(src_v), // %1 >+ "+r"(dst_uv), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } > #endif // HAS_MERGEUVROW_AVX2 > > #ifdef HAS_MERGEUVROW_SSE2 >-void MergeUVRow_SSE2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_SSE2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >+ asm volatile( > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "punpcklbw %%xmm1,%%xmm0 \n" >- "punpckhbw %%xmm1,%%xmm2 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "movdqu %%xmm2," MEMACCESS2(0x10,2) " \n" >- "lea " MEMLEA(0x20,2) ",%2 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_u), // %0 >- "+r"(src_v), // %1 >- "+r"(dst_uv), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2" >- ); >+ "sub %0,%1 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%1,1),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "punpcklbw %%xmm1,%%xmm0 \n" >+ "punpckhbw %%xmm1,%%xmm2 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "movdqu %%xmm2,0x10(%2) \n" >+ "lea 0x20(%2),%2 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_u), // %0 >+ "+r"(src_v), // %1 >+ "+r"(dst_uv), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } > #endif // HAS_MERGEUVROW_SSE2 > >@@ -2759,9 +3209,9 @@ void MergeUVRow_SSE2(const uint8* src_u, > // 16 = 12 bits > // 1 = 16 bits > #ifdef HAS_MERGEUVROW_16_AVX2 >-void MergeUVRow_16_AVX2(const uint16* src_u, >- const uint16* src_v, >- uint16* dst_uv, >+void MergeUVRow_16_AVX2(const uint16_t* src_u, >+ const uint16_t* src_v, >+ uint16_t* dst_uv, > int scale, > int width) { > // clang-format off >@@ -2800,9 +3250,14 @@ void MergeUVRow_16_AVX2(const uint16* src_u, > } > #endif // HAS_MERGEUVROW_AVX2 > >+// Use scale to convert lsb formats to msb, depending how many bits there are: >+// 128 = 9 bits >+// 64 = 10 bits >+// 16 = 12 bits >+// 1 = 16 bits > #ifdef HAS_MULTIPLYROW_16_AVX2 >-void MultiplyRow_16_AVX2(const uint16* src_y, >- uint16* dst_y, >+void MultiplyRow_16_AVX2(const uint16_t* src_y, >+ uint16_t* dst_y, > int scale, > int width) { > // clang-format off >@@ -2834,367 +3289,507 @@ void MultiplyRow_16_AVX2(const uint16* src_y, > } > #endif // HAS_MULTIPLYROW_16_AVX2 > >-#ifdef HAS_SPLITRGBROW_SSSE3 >- >-// Shuffle table for converting RGB to Planar. >-static uvec8 kShuffleMaskRGBToR0 = {0u, 3u, 6u, 9u, 12u, 15u, >- 128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToR1 = {128u, 128u, 128u, 128u, 128u, 128u, >- 2u, 5u, 8u, 11u, 14u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToR2 = {128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u, 128u, 1u, >- 4u, 7u, 10u, 13u}; >- >-static uvec8 kShuffleMaskRGBToG0 = {1u, 4u, 7u, 10u, 13u, 128u, >- 128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToG1 = {128u, 128u, 128u, 128u, 128u, 0u, >- 3u, 6u, 9u, 12u, 15u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToG2 = {128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u, 128u, 2u, >- 5u, 8u, 11u, 14u}; >- >-static uvec8 kShuffleMaskRGBToB0 = {2u, 5u, 8u, 11u, 14u, 128u, >- 128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToB1 = {128u, 128u, 128u, 128u, 128u, 1u, >- 4u, 7u, 10u, 13u, 128u, 128u, >- 128u, 128u, 128u, 128u}; >-static uvec8 kShuffleMaskRGBToB2 = {128u, 128u, 128u, 128u, 128u, 128u, >- 128u, 128u, 128u, 128u, 0u, 3u, >- 6u, 9u, 12u, 15u}; >- >-void SplitRGBRow_SSSE3(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >- int width) { >+// Use scale to convert lsb formats to msb, depending how many bits there are: >+// 32768 = 9 bits >+// 16384 = 10 bits >+// 4096 = 12 bits >+// 256 = 16 bits >+void Convert16To8Row_SSSE3(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width) { >+ // clang-format off > asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "pshufb %5, %%xmm0 \n" >- "pshufb %6, %%xmm1 \n" >- "pshufb %7, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "pshufb %8, %%xmm0 \n" >- "pshufb %9, %%xmm1 \n" >- "pshufb %10, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "pshufb %11, %%xmm0 \n" >- "pshufb %12, %%xmm1 \n" >- "pshufb %13, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(3) " \n" >- "lea " MEMLEA(0x10,3) ",%3 \n" >- "lea " MEMLEA(0x30,0) ",%0 \n" >- "sub $0x10,%4 \n" >- "jg 1b \n" >- : "+r"(src_rgb), // %0 >- "+r"(dst_r), // %1 >- "+r"(dst_g), // %2 >- "+r"(dst_b), // %3 >- "+r"(width) // %4 >- : "m"(kShuffleMaskRGBToR0), // %5 >- "m"(kShuffleMaskRGBToR1), // %6 >- "m"(kShuffleMaskRGBToR2), // %7 >- "m"(kShuffleMaskRGBToG0), // %8 >- "m"(kShuffleMaskRGBToG1), // %9 >- "m"(kShuffleMaskRGBToG2), // %10 >- "m"(kShuffleMaskRGBToB0), // %11 >- "m"(kShuffleMaskRGBToB1), // %12 >- "m"(kShuffleMaskRGBToB2) // %13 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2" >- ); >-} >-#endif // HAS_SPLITRGBROW_SSSE3 >- >-#ifdef HAS_MERGERGBROW_SSSE3 >+ "movd %3,%%xmm2 \n" >+ "punpcklwd %%xmm2,%%xmm2 \n" >+ "pshufd $0x0,%%xmm2,%%xmm2 \n" >+ >+ // 32 pixels per loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "add $0x20,%0 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "add $0x10,%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "r"(scale) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+ // clang-format on >+} > >-// Shuffle table for converting RGB to Planar. >-static uvec8 kShuffleMaskRToRGB0 = {0u, 128u, 128u, 1u, 128u, 128u, >- 2u, 128u, 128u, 3u, 128u, 128u, >- 4u, 128u, 128u, 5u}; >-static uvec8 kShuffleMaskGToRGB0 = {128u, 0u, 128u, 128u, 1u, 128u, >- 128u, 2u, 128u, 128u, 3u, 128u, >- 128u, 4u, 128u, 128u}; >-static uvec8 kShuffleMaskBToRGB0 = {128u, 128u, 0u, 128u, 128u, 1u, >- 128u, 128u, 2u, 128u, 128u, 3u, >- 128u, 128u, 4u, 128u}; >- >-static uvec8 kShuffleMaskGToRGB1 = {5u, 128u, 128u, 6u, 128u, 128u, >- 7u, 128u, 128u, 8u, 128u, 128u, >- 9u, 128u, 128u, 10u}; >-static uvec8 kShuffleMaskBToRGB1 = {128u, 5u, 128u, 128u, 6u, 128u, >- 128u, 7u, 128u, 128u, 8u, 128u, >- 128u, 9u, 128u, 128u}; >-static uvec8 kShuffleMaskRToRGB1 = {128u, 128u, 6u, 128u, 128u, 7u, >- 128u, 128u, 8u, 128u, 128u, 9u, >- 128u, 128u, 10u, 128u}; >- >-static uvec8 kShuffleMaskBToRGB2 = {10u, 128u, 128u, 11u, 128u, 128u, >- 12u, 128u, 128u, 13u, 128u, 128u, >- 14u, 128u, 128u, 15u}; >-static uvec8 kShuffleMaskRToRGB2 = {128u, 11u, 128u, 128u, 12u, 128u, >- 128u, 13u, 128u, 128u, 14u, 128u, >- 128u, 15u, 128u, 128u}; >-static uvec8 kShuffleMaskGToRGB2 = {128u, 128u, 11u, 128u, 128u, 12u, >- 128u, 128u, 13u, 128u, 128u, 14u, >- 128u, 128u, 15u, 128u}; >- >-void MergeRGBRow_SSSE3(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >- int width) { >+#ifdef HAS_CONVERT16TO8ROW_AVX2 >+void Convert16To8Row_AVX2(const uint16_t* src_y, >+ uint8_t* dst_y, >+ int scale, >+ int width) { >+ // clang-format off > asm volatile ( >+ "vmovd %3,%%xmm2 \n" >+ "vpunpcklwd %%xmm2,%%xmm2,%%xmm2 \n" >+ "vbroadcastss %%xmm2,%%ymm2 \n" >+ >+ // 32 pixels per loop. > LABELALIGN > "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "movdqu " MEMACCESS(2) ",%%xmm2 \n" >- "pshufb %5, %%xmm0 \n" >- "pshufb %6, %%xmm1 \n" >- "pshufb %7, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(3) " \n" >- >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "movdqu " MEMACCESS(2) ",%%xmm2 \n" >- "pshufb %8, %%xmm0 \n" >- "pshufb %9, %%xmm1 \n" >- "pshufb %10, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS2(16, 3) " \n" >- >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "movdqu " MEMACCESS(2) ",%%xmm2 \n" >- "pshufb %11, %%xmm0 \n" >- "pshufb %12, %%xmm1 \n" >- "pshufb %13, %%xmm2 \n" >- "por %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS2(32, 3) " \n" >- >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "lea " MEMLEA(0x30,3) ",%3 \n" >- "sub $0x10,%4 \n" >- "jg 1b \n" >- : "+r"(src_r), // %0 >- "+r"(src_g), // %1 >- "+r"(src_b), // %2 >- "+r"(dst_rgb), // %3 >- "+r"(width) // %4 >- : "m"(kShuffleMaskRToRGB0), // %5 >- "m"(kShuffleMaskGToRGB0), // %6 >- "m"(kShuffleMaskBToRGB0), // %7 >- "m"(kShuffleMaskRToRGB1), // %8 >- "m"(kShuffleMaskGToRGB1), // %9 >- "m"(kShuffleMaskBToRGB1), // %10 >- "m"(kShuffleMaskRToRGB2), // %11 >- "m"(kShuffleMaskGToRGB2), // %12 >- "m"(kShuffleMaskBToRGB2) // %13 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2" >- ); >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "add $0x40,%0 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm2,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" // mutates >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "add $0x20,%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_y), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "r"(scale) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+ // clang-format on >+} >+#endif // HAS_CONVERT16TO8ROW_AVX2 >+ >+// Use scale to convert to lsb formats depending how many bits there are: >+// 512 = 9 bits >+// 1024 = 10 bits >+// 4096 = 12 bits >+// TODO(fbarchard): reduce to SSE2 >+void Convert8To16Row_SSE2(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width) { >+ // clang-format off >+ asm volatile ( >+ "movd %3,%%xmm2 \n" >+ "punpcklwd %%xmm2,%%xmm2 \n" >+ "pshufd $0x0,%%xmm2,%%xmm2 \n" >+ >+ // 32 pixels per loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "punpckhbw %%xmm1,%%xmm1 \n" >+ "add $0x10,%0 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "add $0x20,%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "r"(scale) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+ // clang-format on > } >-#endif // HAS_MERGERGBROW_SSSE3 > >-#ifdef HAS_COPYROW_SSE2 >-void CopyRow_SSE2(const uint8* src, uint8* dst, int count) { >+#ifdef HAS_CONVERT8TO16ROW_AVX2 >+void Convert8To16Row_AVX2(const uint8_t* src_y, >+ uint16_t* dst_y, >+ int scale, >+ int width) { >+ // clang-format off > asm volatile ( >- "test $0xf,%0 \n" >- "jne 2f \n" >- "test $0xf,%1 \n" >- "jne 2f \n" >+ "vmovd %3,%%xmm2 \n" >+ "vpunpcklwd %%xmm2,%%xmm2,%%xmm2 \n" >+ "vbroadcastss %%xmm2,%%ymm2 \n" > >+ // 32 pixels per loop. > LABELALIGN > "1: \n" >- "movdqa " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqa %%xmm0," MEMACCESS(1) " \n" >- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "add $0x20,%0 \n" >+ "vpunpckhbw %%ymm0,%%ymm0,%%ymm1 \n" >+ "vpunpcklbw %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm2,%%ymm1,%%ymm1 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm1,0x20(%1) \n" >+ "add $0x40,%1 \n" > "sub $0x20,%2 \n" > "jg 1b \n" >- "jmp 9f \n" >+ "vzeroupper \n" >+ : "+r"(src_y), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : "r"(scale) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+ // clang-format on >+} >+#endif // HAS_CONVERT8TO16ROW_AVX2 > >- LABELALIGN >- "2: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 2b \n" >- "9: \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(count) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+#ifdef HAS_SPLITRGBROW_SSSE3 >+ >+// Shuffle table for converting RGB to Planar. >+static const uvec8 kShuffleMaskRGBToR0 = {0u, 3u, 6u, 9u, 12u, 15u, >+ 128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToR1 = {128u, 128u, 128u, 128u, 128u, 128u, >+ 2u, 5u, 8u, 11u, 14u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToR2 = {128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u, 128u, 1u, >+ 4u, 7u, 10u, 13u}; >+ >+static const uvec8 kShuffleMaskRGBToG0 = {1u, 4u, 7u, 10u, 13u, 128u, >+ 128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToG1 = {128u, 128u, 128u, 128u, 128u, 0u, >+ 3u, 6u, 9u, 12u, 15u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToG2 = {128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u, 128u, 2u, >+ 5u, 8u, 11u, 14u}; >+ >+static const uvec8 kShuffleMaskRGBToB0 = {2u, 5u, 8u, 11u, 14u, 128u, >+ 128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToB1 = {128u, 128u, 128u, 128u, 128u, 1u, >+ 4u, 7u, 10u, 13u, 128u, 128u, >+ 128u, 128u, 128u, 128u}; >+static const uvec8 kShuffleMaskRGBToB2 = {128u, 128u, 128u, 128u, 128u, 128u, >+ 128u, 128u, 128u, 128u, 0u, 3u, >+ 6u, 9u, 12u, 15u}; >+ >+void SplitRGBRow_SSSE3(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, >+ int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "pshufb %5, %%xmm0 \n" >+ "pshufb %6, %%xmm1 \n" >+ "pshufb %7, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "pshufb %8, %%xmm0 \n" >+ "pshufb %9, %%xmm1 \n" >+ "pshufb %10, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "pshufb %11, %%xmm0 \n" >+ "pshufb %12, %%xmm1 \n" >+ "pshufb %13, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%3) \n" >+ "lea 0x10(%3),%3 \n" >+ "lea 0x30(%0),%0 \n" >+ "sub $0x10,%4 \n" >+ "jg 1b \n" >+ : "+r"(src_rgb), // %0 >+ "+r"(dst_r), // %1 >+ "+r"(dst_g), // %2 >+ "+r"(dst_b), // %3 >+ "+r"(width) // %4 >+ : "m"(kShuffleMaskRGBToR0), // %5 >+ "m"(kShuffleMaskRGBToR1), // %6 >+ "m"(kShuffleMaskRGBToR2), // %7 >+ "m"(kShuffleMaskRGBToG0), // %8 >+ "m"(kShuffleMaskRGBToG1), // %9 >+ "m"(kShuffleMaskRGBToG2), // %10 >+ "m"(kShuffleMaskRGBToB0), // %11 >+ "m"(kShuffleMaskRGBToB1), // %12 >+ "m"(kShuffleMaskRGBToB2) // %13 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+} >+#endif // HAS_SPLITRGBROW_SSSE3 >+ >+#ifdef HAS_MERGERGBROW_SSSE3 >+ >+// Shuffle table for converting RGB to Planar. >+static const uvec8 kShuffleMaskRToRGB0 = {0u, 128u, 128u, 1u, 128u, 128u, >+ 2u, 128u, 128u, 3u, 128u, 128u, >+ 4u, 128u, 128u, 5u}; >+static const uvec8 kShuffleMaskGToRGB0 = {128u, 0u, 128u, 128u, 1u, 128u, >+ 128u, 2u, 128u, 128u, 3u, 128u, >+ 128u, 4u, 128u, 128u}; >+static const uvec8 kShuffleMaskBToRGB0 = {128u, 128u, 0u, 128u, 128u, 1u, >+ 128u, 128u, 2u, 128u, 128u, 3u, >+ 128u, 128u, 4u, 128u}; >+ >+static const uvec8 kShuffleMaskGToRGB1 = {5u, 128u, 128u, 6u, 128u, 128u, >+ 7u, 128u, 128u, 8u, 128u, 128u, >+ 9u, 128u, 128u, 10u}; >+static const uvec8 kShuffleMaskBToRGB1 = {128u, 5u, 128u, 128u, 6u, 128u, >+ 128u, 7u, 128u, 128u, 8u, 128u, >+ 128u, 9u, 128u, 128u}; >+static const uvec8 kShuffleMaskRToRGB1 = {128u, 128u, 6u, 128u, 128u, 7u, >+ 128u, 128u, 8u, 128u, 128u, 9u, >+ 128u, 128u, 10u, 128u}; >+ >+static const uvec8 kShuffleMaskBToRGB2 = {10u, 128u, 128u, 11u, 128u, 128u, >+ 12u, 128u, 128u, 13u, 128u, 128u, >+ 14u, 128u, 128u, 15u}; >+static const uvec8 kShuffleMaskRToRGB2 = {128u, 11u, 128u, 128u, 12u, 128u, >+ 128u, 13u, 128u, 128u, 14u, 128u, >+ 128u, 15u, 128u, 128u}; >+static const uvec8 kShuffleMaskGToRGB2 = {128u, 128u, 11u, 128u, 128u, 12u, >+ 128u, 128u, 13u, 128u, 128u, 14u, >+ 128u, 128u, 15u, 128u}; >+ >+void MergeRGBRow_SSSE3(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, >+ int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "movdqu (%2),%%xmm2 \n" >+ "pshufb %5, %%xmm0 \n" >+ "pshufb %6, %%xmm1 \n" >+ "pshufb %7, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%3) \n" >+ >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "movdqu (%2),%%xmm2 \n" >+ "pshufb %8, %%xmm0 \n" >+ "pshufb %9, %%xmm1 \n" >+ "pshufb %10, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,16(%3) \n" >+ >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "movdqu (%2),%%xmm2 \n" >+ "pshufb %11, %%xmm0 \n" >+ "pshufb %12, %%xmm1 \n" >+ "pshufb %13, %%xmm2 \n" >+ "por %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,32(%3) \n" >+ >+ "lea 0x10(%0),%0 \n" >+ "lea 0x10(%1),%1 \n" >+ "lea 0x10(%2),%2 \n" >+ "lea 0x30(%3),%3 \n" >+ "sub $0x10,%4 \n" >+ "jg 1b \n" >+ : "+r"(src_r), // %0 >+ "+r"(src_g), // %1 >+ "+r"(src_b), // %2 >+ "+r"(dst_rgb), // %3 >+ "+r"(width) // %4 >+ : "m"(kShuffleMaskRToRGB0), // %5 >+ "m"(kShuffleMaskGToRGB0), // %6 >+ "m"(kShuffleMaskBToRGB0), // %7 >+ "m"(kShuffleMaskRToRGB1), // %8 >+ "m"(kShuffleMaskGToRGB1), // %9 >+ "m"(kShuffleMaskBToRGB1), // %10 >+ "m"(kShuffleMaskRToRGB2), // %11 >+ "m"(kShuffleMaskGToRGB2), // %12 >+ "m"(kShuffleMaskBToRGB2) // %13 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+} >+#endif // HAS_MERGERGBROW_SSSE3 >+ >+#ifdef HAS_COPYROW_SSE2 >+void CopyRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "test $0xf,%0 \n" >+ "jne 2f \n" >+ "test $0xf,%1 \n" >+ "jne 2f \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqa (%0),%%xmm0 \n" >+ "movdqa 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqa %%xmm0,(%1) \n" >+ "movdqa %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "jmp 9f \n" >+ >+ LABELALIGN >+ "2: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 2b \n" >+ >+ LABELALIGN "9: \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_COPYROW_SSE2 > > #ifdef HAS_COPYROW_AVX >-void CopyRow_AVX(const uint8* src, uint8* dst, int count) { >- asm volatile ( >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x40,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(count) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+void CopyRow_AVX(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm1,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x40,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_COPYROW_AVX > > #ifdef HAS_COPYROW_ERMS > // Multiple of 1. >-void CopyRow_ERMS(const uint8* src, uint8* dst, int width) { >+void CopyRow_ERMS(const uint8_t* src, uint8_t* dst, int width) { > size_t width_tmp = (size_t)(width); >- asm volatile("rep movsb " MEMMOVESTRING(0, 1) " \n" >- : "+S"(src), // %0 >- "+D"(dst), // %1 >- "+c"(width_tmp) // %2 >- : >- : "memory", "cc"); >+ asm volatile( >+ >+ "rep movsb \n" >+ : "+S"(src), // %0 >+ "+D"(dst), // %1 >+ "+c"(width_tmp) // %2 >+ : >+ : "memory", "cc"); > } > #endif // HAS_COPYROW_ERMS > > #ifdef HAS_ARGBCOPYALPHAROW_SSE2 > // width in pixels >-void ARGBCopyAlphaRow_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "pcmpeqb %%xmm0,%%xmm0 \n" >- "pslld $0x18,%%xmm0 \n" >- "pcmpeqb %%xmm1,%%xmm1 \n" >- "psrld $0x8,%%xmm1 \n" >+void ARGBCopyAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm0,%%xmm0 \n" >+ "pslld $0x18,%%xmm0 \n" >+ "pcmpeqb %%xmm1,%%xmm1 \n" >+ "psrld $0x8,%%xmm1 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm4 \n" >- "movdqu " MEMACCESS2(0x10,1) ",%%xmm5 \n" >- "pand %%xmm0,%%xmm2 \n" >- "pand %%xmm0,%%xmm3 \n" >- "pand %%xmm1,%%xmm4 \n" >- "pand %%xmm1,%%xmm5 \n" >- "por %%xmm4,%%xmm2 \n" >- "por %%xmm5,%%xmm3 \n" >- "movdqu %%xmm2," MEMACCESS(1) " \n" >- "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm2 \n" >+ "movdqu 0x10(%0),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqu (%1),%%xmm4 \n" >+ "movdqu 0x10(%1),%%xmm5 \n" >+ "pand %%xmm0,%%xmm2 \n" >+ "pand %%xmm0,%%xmm3 \n" >+ "pand %%xmm1,%%xmm4 \n" >+ "pand %%xmm1,%%xmm5 \n" >+ "por %%xmm4,%%xmm2 \n" >+ "por %%xmm5,%%xmm3 \n" >+ "movdqu %%xmm2,(%1) \n" >+ "movdqu %%xmm3,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBCOPYALPHAROW_SSE2 > > #ifdef HAS_ARGBCOPYALPHAROW_AVX2 > // width in pixels >-void ARGBCopyAlphaRow_AVX2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpsrld $0x8,%%ymm0,%%ymm0 \n" >+void ARGBCopyAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpsrld $0x8,%%ymm0,%%ymm0 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm2 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n" >- "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n" >- "vmovdqu %%ymm1," MEMACCESS(1) " \n" >- "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm1 \n" >+ "vmovdqu 0x20(%0),%%ymm2 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpblendvb %%ymm0,(%1),%%ymm1,%%ymm1 \n" >+ "vpblendvb %%ymm0,0x20(%1),%%ymm2,%%ymm2 \n" >+ "vmovdqu %%ymm1,(%1) \n" >+ "vmovdqu %%ymm2,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } > #endif // HAS_ARGBCOPYALPHAROW_AVX2 > > #ifdef HAS_ARGBEXTRACTALPHAROW_SSE2 > // width in pixels >-void ARGBExtractAlphaRow_SSE2(const uint8* src_argb, uint8* dst_a, int width) { >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ", %%xmm0 \n" >- "movdqu " MEMACCESS2(0x10, 0) ", %%xmm1 \n" >- "lea " MEMLEA(0x20, 0) ", %0 \n" >- "psrld $0x18, %%xmm0 \n" >- "psrld $0x18, %%xmm1 \n" >- "packssdw %%xmm1, %%xmm0 \n" >- "packuswb %%xmm0, %%xmm0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8, 1) ", %1 \n" >- "sub $0x8, %2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_a), // %1 >- "+rm"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+void ARGBExtractAlphaRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0), %%xmm0 \n" >+ "movdqu 0x10(%0), %%xmm1 \n" >+ "lea 0x20(%0), %0 \n" >+ "psrld $0x18, %%xmm0 \n" >+ "psrld $0x18, %%xmm1 \n" >+ "packssdw %%xmm1, %%xmm0 \n" >+ "packuswb %%xmm0, %%xmm0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1), %1 \n" >+ "sub $0x8, %2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_a), // %1 >+ "+rm"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_ARGBEXTRACTALPHAROW_SSE2 > >@@ -3203,657 +3798,636 @@ static const uvec8 kShuffleAlphaShort_AVX2 = { > 3u, 128u, 128u, 128u, 7u, 128u, 128u, 128u, > 11u, 128u, 128u, 128u, 15u, 128u, 128u, 128u}; > >-void ARGBExtractAlphaRow_AVX2(const uint8* src_argb, uint8* dst_a, int width) { >- asm volatile ( >- "vmovdqa %3,%%ymm4 \n" >- "vbroadcastf128 %4,%%ymm5 \n" >+void ARGBExtractAlphaRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width) { >+ asm volatile( >+ "vmovdqa %3,%%ymm4 \n" >+ "vbroadcastf128 %4,%%ymm5 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ", %%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20, 0) ", %%ymm1 \n" >- "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" // vpsrld $0x18, %%ymm0 >- "vpshufb %%ymm5,%%ymm1,%%ymm1 \n" >- "vmovdqu " MEMACCESS2(0x40, 0) ", %%ymm2 \n" >- "vmovdqu " MEMACCESS2(0x60, 0) ", %%ymm3 \n" >- "lea " MEMLEA(0x80, 0) ", %0 \n" >- "vpackssdw %%ymm1, %%ymm0, %%ymm0 \n" // mutates >- "vpshufb %%ymm5,%%ymm2,%%ymm2 \n" >- "vpshufb %%ymm5,%%ymm3,%%ymm3 \n" >- "vpackssdw %%ymm3, %%ymm2, %%ymm2 \n" // mutates >- "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >- "vpermd %%ymm0,%%ymm4,%%ymm0 \n" // unmutate. >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20, %2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_a), // %1 >- "+rm"(width) // %2 >- : "m"(kPermdARGBToY_AVX), // %3 >- "m"(kShuffleAlphaShort_AVX2) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0), %%ymm0 \n" >+ "vmovdqu 0x20(%0), %%ymm1 \n" >+ "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" // vpsrld $0x18, %%ymm0 >+ "vpshufb %%ymm5,%%ymm1,%%ymm1 \n" >+ "vmovdqu 0x40(%0), %%ymm2 \n" >+ "vmovdqu 0x60(%0), %%ymm3 \n" >+ "lea 0x80(%0), %0 \n" >+ "vpackssdw %%ymm1, %%ymm0, %%ymm0 \n" // mutates >+ "vpshufb %%ymm5,%%ymm2,%%ymm2 \n" >+ "vpshufb %%ymm5,%%ymm3,%%ymm3 \n" >+ "vpackssdw %%ymm3, %%ymm2, %%ymm2 \n" // mutates >+ "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. >+ "vpermd %%ymm0,%%ymm4,%%ymm0 \n" // unmutate. >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20, %2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_a), // %1 >+ "+rm"(width) // %2 >+ : "m"(kPermdARGBToY_AVX), // %3 >+ "m"(kShuffleAlphaShort_AVX2) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBEXTRACTALPHAROW_AVX2 > > #ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2 > // width in pixels >-void ARGBCopyYToAlphaRow_SSE2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "pcmpeqb %%xmm0,%%xmm0 \n" >- "pslld $0x18,%%xmm0 \n" >- "pcmpeqb %%xmm1,%%xmm1 \n" >- "psrld $0x8,%%xmm1 \n" >+void ARGBCopyYToAlphaRow_SSE2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm0,%%xmm0 \n" >+ "pslld $0x18,%%xmm0 \n" >+ "pcmpeqb %%xmm1,%%xmm1 \n" >+ "psrld $0x8,%%xmm1 \n" > >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm2 \n" >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "punpcklbw %%xmm2,%%xmm2 \n" >- "punpckhwd %%xmm2,%%xmm3 \n" >- "punpcklwd %%xmm2,%%xmm2 \n" >- "movdqu " MEMACCESS(1) ",%%xmm4 \n" >- "movdqu " MEMACCESS2(0x10,1) ",%%xmm5 \n" >- "pand %%xmm0,%%xmm2 \n" >- "pand %%xmm0,%%xmm3 \n" >- "pand %%xmm1,%%xmm4 \n" >- "pand %%xmm1,%%xmm5 \n" >- "por %%xmm4,%%xmm2 \n" >- "por %%xmm5,%%xmm3 \n" >- "movdqu %%xmm2," MEMACCESS(1) " \n" >- "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm2 \n" >+ "lea 0x8(%0),%0 \n" >+ "punpcklbw %%xmm2,%%xmm2 \n" >+ "punpckhwd %%xmm2,%%xmm3 \n" >+ "punpcklwd %%xmm2,%%xmm2 \n" >+ "movdqu (%1),%%xmm4 \n" >+ "movdqu 0x10(%1),%%xmm5 \n" >+ "pand %%xmm0,%%xmm2 \n" >+ "pand %%xmm0,%%xmm3 \n" >+ "pand %%xmm1,%%xmm4 \n" >+ "pand %%xmm1,%%xmm5 \n" >+ "por %%xmm4,%%xmm2 \n" >+ "por %%xmm5,%%xmm3 \n" >+ "movdqu %%xmm2,(%1) \n" >+ "movdqu %%xmm3,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBCOPYYTOALPHAROW_SSE2 > > #ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2 > // width in pixels >-void ARGBCopyYToAlphaRow_AVX2(const uint8* src, uint8* dst, int width) { >- asm volatile ( >- "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpsrld $0x8,%%ymm0,%%ymm0 \n" >+void ARGBCopyYToAlphaRow_AVX2(const uint8_t* src, uint8_t* dst, int width) { >+ asm volatile( >+ "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpsrld $0x8,%%ymm0,%%ymm0 \n" > >- LABELALIGN >- "1: \n" >- "vpmovzxbd " MEMACCESS(0) ",%%ymm1 \n" >- "vpmovzxbd " MEMACCESS2(0x8,0) ",%%ymm2 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "vpslld $0x18,%%ymm1,%%ymm1 \n" >- "vpslld $0x18,%%ymm2,%%ymm2 \n" >- "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n" >- "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n" >- "vmovdqu %%ymm1," MEMACCESS(1) " \n" >- "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2" >- ); >+ LABELALIGN >+ "1: \n" >+ "vpmovzxbd (%0),%%ymm1 \n" >+ "vpmovzxbd 0x8(%0),%%ymm2 \n" >+ "lea 0x10(%0),%0 \n" >+ "vpslld $0x18,%%ymm1,%%ymm1 \n" >+ "vpslld $0x18,%%ymm2,%%ymm2 \n" >+ "vpblendvb %%ymm0,(%1),%%ymm1,%%ymm1 \n" >+ "vpblendvb %%ymm0,0x20(%1),%%ymm2,%%ymm2 \n" >+ "vmovdqu %%ymm1,(%1) \n" >+ "vmovdqu %%ymm2,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } > #endif // HAS_ARGBCOPYYTOALPHAROW_AVX2 > > #ifdef HAS_SETROW_X86 >-void SetRow_X86(uint8* dst, uint8 v8, int width) { >+void SetRow_X86(uint8_t* dst, uint8_t v8, int width) { > size_t width_tmp = (size_t)(width >> 2); >- const uint32 v32 = v8 * 0x01010101u; // Duplicate byte to all bytes. >- asm volatile("rep stosl " MEMSTORESTRING(eax, 0) " \n" >- : "+D"(dst), // %0 >- "+c"(width_tmp) // %1 >- : "a"(v32) // %2 >- : "memory", "cc"); >+ const uint32_t v32 = v8 * 0x01010101u; // Duplicate byte to all bytes. >+ asm volatile( >+ >+ "rep stosl \n" >+ : "+D"(dst), // %0 >+ "+c"(width_tmp) // %1 >+ : "a"(v32) // %2 >+ : "memory", "cc"); > } > >-void SetRow_ERMS(uint8* dst, uint8 v8, int width) { >+void SetRow_ERMS(uint8_t* dst, uint8_t v8, int width) { > size_t width_tmp = (size_t)(width); >- asm volatile("rep stosb " MEMSTORESTRING(al, 0) " \n" >- : "+D"(dst), // %0 >- "+c"(width_tmp) // %1 >- : "a"(v8) // %2 >- : "memory", "cc"); >+ asm volatile( >+ >+ "rep stosb \n" >+ : "+D"(dst), // %0 >+ "+c"(width_tmp) // %1 >+ : "a"(v8) // %2 >+ : "memory", "cc"); > } > >-void ARGBSetRow_X86(uint8* dst_argb, uint32 v32, int width) { >+void ARGBSetRow_X86(uint8_t* dst_argb, uint32_t v32, int width) { > size_t width_tmp = (size_t)(width); >- asm volatile("rep stosl " MEMSTORESTRING(eax, 0) " \n" >- : "+D"(dst_argb), // %0 >- "+c"(width_tmp) // %1 >- : "a"(v32) // %2 >- : "memory", "cc"); >+ asm volatile( >+ >+ "rep stosl \n" >+ : "+D"(dst_argb), // %0 >+ "+c"(width_tmp) // %1 >+ : "a"(v32) // %2 >+ : "memory", "cc"); > } > #endif // HAS_SETROW_X86 > > #ifdef HAS_YUY2TOYROW_SSE2 >-void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >+void YUY2ToYRow_SSE2(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pand %%xmm5,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > >-void YUY2ToUVRow_SSE2(const uint8* src_yuy2, >+void YUY2ToUVRow_SSE2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "pavgb %%xmm3,%%xmm1 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pand %%xmm5,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : "r"((intptr_t)(stride_yuy2)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "pavgb %%xmm3,%%xmm1 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : "r"((intptr_t)(stride_yuy2)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > >-void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_SSE2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pand %%xmm5,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > >-void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int width) { >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+void UYVYToYRow_SSE2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > >-void UYVYToUVRow_SSE2(const uint8* src_uyvy, >+void UYVYToUVRow_SSE2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "pavgb %%xmm3,%%xmm1 \n" >- "pand %%xmm5,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pand %%xmm5,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : "r"((intptr_t)(stride_uyvy)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "pavgb %%xmm3,%%xmm1 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : "r"((intptr_t)(stride_uyvy)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > >-void UYVYToUV422Row_SSE2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_SSE2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrlw $0x8,%%xmm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrlw $0x8,%%xmm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pand %%xmm5,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pand %%xmm5,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x00(%1,%2,1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > #endif // HAS_YUY2TOYROW_SSE2 > > #ifdef HAS_YUY2TOYROW_AVX2 >-void YUY2ToYRow_AVX2(const uint8* src_yuy2, uint8* dst_y, int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+void YUY2ToYRow_AVX2(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > >-void YUY2ToUVRow_AVX2(const uint8* src_yuy2, >+void YUY2ToUVRow_AVX2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 >- VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm1 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : "r"((intptr_t)(stride_yuy2)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vpavgb 0x00(%0,%4,1),%%ymm0,%%ymm0 \n" >+ "vpavgb 0x20(%0,%4,1),%%ymm1,%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm1 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vextractf128 $0x0,%%ymm1,(%1) \n" >+ "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : "r"((intptr_t)(stride_yuy2)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > >-void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_AVX2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm1 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_yuy2), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm1 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vextractf128 $0x0,%%ymm1,(%1) \n" >+ "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_yuy2), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } >- >-void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int width) { >- asm volatile ( >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_y), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm5" >- ); >+ >+void UYVYToYRow_AVX2(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_y), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } >-void UYVYToUVRow_AVX2(const uint8* src_uyvy, >+void UYVYToUVRow_AVX2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 >- VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm1 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : "r"((intptr_t)(stride_uyvy)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vpavgb 0x00(%0,%4,1),%%ymm0,%%ymm0 \n" >+ "vpavgb 0x20(%0,%4,1),%%ymm1,%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm1 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vextractf128 $0x0,%%ymm1,(%1) \n" >+ "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : "r"((intptr_t)(stride_uyvy)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > >-void UYVYToUV422Row_AVX2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_AVX2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >- "sub %1,%2 \n" >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrlw $0x8,%%ymm5,%%ymm5 \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm1 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm1,%%ymm1 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" >- VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x20,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_uyvy), // %0 >- "+r"(dst_u), // %1 >- "+r"(dst_v), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm1 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm1,%%ymm1 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vextractf128 $0x0,%%ymm1,(%1) \n" >+ "vextractf128 $0x0,%%ymm0,0x00(%1,%2,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x20,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_uyvy), // %0 >+ "+r"(dst_u), // %1 >+ "+r"(dst_v), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > #endif // HAS_YUY2TOYROW_AVX2 > > #ifdef HAS_ARGBBLENDROW_SSSE3 > // Shuffle table for isolating alpha. >-static uvec8 kShuffleAlpha = {3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80, >- 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80}; >+static const uvec8 kShuffleAlpha = {3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80, >+ 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80}; > > // Blend 8 pixels at a time >-void ARGBBlendRow_SSSE3(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_SSSE3(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- "pcmpeqb %%xmm7,%%xmm7 \n" >- "psrlw $0xf,%%xmm7 \n" >- "pcmpeqb %%xmm6,%%xmm6 \n" >- "psrlw $0x8,%%xmm6 \n" >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psllw $0x8,%%xmm5 \n" >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "pslld $0x18,%%xmm4 \n" >- "sub $0x4,%3 \n" >- "jl 49f \n" >- >- // 4 pixel loop. >- LABELALIGN >- "40: \n" >- "movdqu " MEMACCESS(0) ",%%xmm3 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm3,%%xmm0 \n" >- "pxor %%xmm4,%%xmm3 \n" >- "movdqu " MEMACCESS(1) ",%%xmm2 \n" >- "pshufb %4,%%xmm3 \n" >- "pand %%xmm6,%%xmm2 \n" >- "paddw %%xmm7,%%xmm3 \n" >- "pmullw %%xmm3,%%xmm2 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "psrlw $0x8,%%xmm1 \n" >- "por %%xmm4,%%xmm0 \n" >- "pmullw %%xmm3,%%xmm1 \n" >- "psrlw $0x8,%%xmm2 \n" >- "paddusb %%xmm2,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jge 40b \n" >- >- "49: \n" >- "add $0x3,%3 \n" >- "jl 99f \n" >- >- // 1 pixel loop. >- "91: \n" >- "movd " MEMACCESS(0) ",%%xmm3 \n" >- "lea " MEMLEA(0x4,0) ",%0 \n" >- "movdqa %%xmm3,%%xmm0 \n" >- "pxor %%xmm4,%%xmm3 \n" >- "movd " MEMACCESS(1) ",%%xmm2 \n" >- "pshufb %4,%%xmm3 \n" >- "pand %%xmm6,%%xmm2 \n" >- "paddw %%xmm7,%%xmm3 \n" >- "pmullw %%xmm3,%%xmm2 \n" >- "movd " MEMACCESS(1) ",%%xmm1 \n" >- "lea " MEMLEA(0x4,1) ",%1 \n" >- "psrlw $0x8,%%xmm1 \n" >- "por %%xmm4,%%xmm0 \n" >- "pmullw %%xmm3,%%xmm1 \n" >- "psrlw $0x8,%%xmm2 \n" >- "paddusb %%xmm2,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movd %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x4,2) ",%2 \n" >- "sub $0x1,%3 \n" >- "jge 91b \n" >- "99: \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : "m"(kShuffleAlpha) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ "pcmpeqb %%xmm7,%%xmm7 \n" >+ "psrlw $0xf,%%xmm7 \n" >+ "pcmpeqb %%xmm6,%%xmm6 \n" >+ "psrlw $0x8,%%xmm6 \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psllw $0x8,%%xmm5 \n" >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "pslld $0x18,%%xmm4 \n" >+ "sub $0x4,%3 \n" >+ "jl 49f \n" >+ >+ // 4 pixel loop. >+ LABELALIGN >+ "40: \n" >+ "movdqu (%0),%%xmm3 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqa %%xmm3,%%xmm0 \n" >+ "pxor %%xmm4,%%xmm3 \n" >+ "movdqu (%1),%%xmm2 \n" >+ "pshufb %4,%%xmm3 \n" >+ "pand %%xmm6,%%xmm2 \n" >+ "paddw %%xmm7,%%xmm3 \n" >+ "pmullw %%xmm3,%%xmm2 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "lea 0x10(%1),%1 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "por %%xmm4,%%xmm0 \n" >+ "pmullw %%xmm3,%%xmm1 \n" >+ "psrlw $0x8,%%xmm2 \n" >+ "paddusb %%xmm2,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jge 40b \n" >+ >+ "49: \n" >+ "add $0x3,%3 \n" >+ "jl 99f \n" >+ >+ // 1 pixel loop. >+ "91: \n" >+ "movd (%0),%%xmm3 \n" >+ "lea 0x4(%0),%0 \n" >+ "movdqa %%xmm3,%%xmm0 \n" >+ "pxor %%xmm4,%%xmm3 \n" >+ "movd (%1),%%xmm2 \n" >+ "pshufb %4,%%xmm3 \n" >+ "pand %%xmm6,%%xmm2 \n" >+ "paddw %%xmm7,%%xmm3 \n" >+ "pmullw %%xmm3,%%xmm2 \n" >+ "movd (%1),%%xmm1 \n" >+ "lea 0x4(%1),%1 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "por %%xmm4,%%xmm0 \n" >+ "pmullw %%xmm3,%%xmm1 \n" >+ "psrlw $0x8,%%xmm2 \n" >+ "paddusb %%xmm2,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movd %%xmm0,(%2) \n" >+ "lea 0x4(%2),%2 \n" >+ "sub $0x1,%3 \n" >+ "jge 91b \n" >+ "99: \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : "m"(kShuffleAlpha) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBBLENDROW_SSSE3 > >@@ -3863,10 +4437,10 @@ void ARGBBlendRow_SSSE3(const uint8* src_argb0, > // =((A2*C2)+(B2*(255-C2))+255)/256 > // signed version of math > // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 >-void BlendPlaneRow_SSSE3(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_SSSE3(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width) { > asm volatile( > "pcmpeqb %%xmm5,%%xmm5 \n" >@@ -3915,10 +4489,10 @@ void BlendPlaneRow_SSSE3(const uint8* src0, > // =((A2*C2)+(B2*(255-C2))+255)/256 > // signed version of math > // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 >-void BlendPlaneRow_AVX2(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+void BlendPlaneRow_AVX2(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width) { > asm volatile( > "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >@@ -3972,50 +4546,50 @@ void BlendPlaneRow_AVX2(const uint8* src0, > > #ifdef HAS_ARGBATTENUATEROW_SSSE3 > // Shuffle table duplicating alpha >-static uvec8 kShuffleAlpha0 = {3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, >- 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u}; >-static uvec8 kShuffleAlpha1 = {11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u, >- 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u}; >+static const uvec8 kShuffleAlpha0 = {3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, >+ 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u}; >+static const uvec8 kShuffleAlpha1 = {11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u, >+ 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u}; > // Attenuate 4 pixels at a time. >-void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) { >- asm volatile ( >- "pcmpeqb %%xmm3,%%xmm3 \n" >- "pslld $0x18,%%xmm3 \n" >- "movdqa %3,%%xmm4 \n" >- "movdqa %4,%%xmm5 \n" >+void ARGBAttenuateRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { >+ asm volatile( >+ "pcmpeqb %%xmm3,%%xmm3 \n" >+ "pslld $0x18,%%xmm3 \n" >+ "movdqa %3,%%xmm4 \n" >+ "movdqa %4,%%xmm5 \n" > >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "punpcklbw %%xmm1,%%xmm1 \n" >- "pmulhuw %%xmm1,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "pshufb %%xmm5,%%xmm1 \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" >- "punpckhbw %%xmm2,%%xmm2 \n" >- "pmulhuw %%xmm2,%%xmm1 \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "pand %%xmm3,%%xmm2 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "por %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleAlpha0), // %3 >- "m"(kShuffleAlpha1) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "movdqu (%0),%%xmm1 \n" >+ "punpcklbw %%xmm1,%%xmm1 \n" >+ "pmulhuw %%xmm1,%%xmm0 \n" >+ "movdqu (%0),%%xmm1 \n" >+ "pshufb %%xmm5,%%xmm1 \n" >+ "movdqu (%0),%%xmm2 \n" >+ "punpckhbw %%xmm2,%%xmm2 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "movdqu (%0),%%xmm2 \n" >+ "lea 0x10(%0),%0 \n" >+ "pand %%xmm3,%%xmm2 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "por %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleAlpha0), // %3 >+ "m"(kShuffleAlpha1) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBATTENUATEROW_SSSE3 > >@@ -4025,87 +4599,85 @@ static const uvec8 kShuffleAlpha_AVX2 = {6u, 7u, 6u, 7u, 6u, 7u, > 128u, 128u, 14u, 15u, 14u, 15u, > 14u, 15u, 128u, 128u}; > // Attenuate 8 pixels at a time. >-void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width) { >- asm volatile ( >- "vbroadcastf128 %3,%%ymm4 \n" >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpslld $0x18,%%ymm5,%%ymm5 \n" >- "sub %0,%1 \n" >+void ARGBAttenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { >+ asm volatile( >+ "vbroadcastf128 %3,%%ymm4 \n" >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpslld $0x18,%%ymm5,%%ymm5 \n" >+ "sub %0,%1 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm6 \n" >- "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" >- "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" >- "vpshufb %%ymm4,%%ymm0,%%ymm2 \n" >- "vpshufb %%ymm4,%%ymm1,%%ymm3 \n" >- "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >- "vpand %%ymm5,%%ymm6,%%ymm6 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpor %%ymm6,%%ymm0,%%ymm0 \n" >- MEMOPMEM(vmovdqu,ymm0,0x00,0,1,1) // vmovdqu %%ymm0,(%0,%1) >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "m"(kShuffleAlpha_AVX2) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm6 \n" >+ "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" >+ "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" >+ "vpshufb %%ymm4,%%ymm0,%%ymm2 \n" >+ "vpshufb %%ymm4,%%ymm1,%%ymm3 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vpand %%ymm5,%%ymm6,%%ymm6 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpor %%ymm6,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,0x00(%0,%1,1) \n" >+ "lea 0x20(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "m"(kShuffleAlpha_AVX2) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_ARGBATTENUATEROW_AVX2 > > #ifdef HAS_ARGBUNATTENUATEROW_SSE2 > // Unattenuate 4 pixels at a time. >-void ARGBUnattenuateRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBUnattenuateRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > uintptr_t alpha; >- asm volatile ( >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movzb " MEMACCESS2(0x03,0) ",%3 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2 >- "movzb " MEMACCESS2(0x07,0) ",%3 \n" >- MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3 >- "pshuflw $0x40,%%xmm2,%%xmm2 \n" >- "pshuflw $0x40,%%xmm3,%%xmm3 \n" >- "movlhps %%xmm3,%%xmm2 \n" >- "pmulhuw %%xmm2,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "movzb " MEMACCESS2(0x0b,0) ",%3 \n" >- "punpckhbw %%xmm1,%%xmm1 \n" >- MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2 >- "movzb " MEMACCESS2(0x0f,0) ",%3 \n" >- MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3 >- "pshuflw $0x40,%%xmm2,%%xmm2 \n" >- "pshuflw $0x40,%%xmm3,%%xmm3 \n" >- "movlhps %%xmm3,%%xmm2 \n" >- "pmulhuw %%xmm2,%%xmm1 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width), // %2 >- "=&r"(alpha) // %3 >- : "r"(fixed_invtbl8) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ asm volatile( >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movzb 0x03(%0),%3 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "movd 0x00(%4,%3,4),%%xmm2 \n" >+ "movzb 0x07(%0),%3 \n" >+ "movd 0x00(%4,%3,4),%%xmm3 \n" >+ "pshuflw $0x40,%%xmm2,%%xmm2 \n" >+ "pshuflw $0x40,%%xmm3,%%xmm3 \n" >+ "movlhps %%xmm3,%%xmm2 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "movdqu (%0),%%xmm1 \n" >+ "movzb 0x0b(%0),%3 \n" >+ "punpckhbw %%xmm1,%%xmm1 \n" >+ "movd 0x00(%4,%3,4),%%xmm2 \n" >+ "movzb 0x0f(%0),%3 \n" >+ "movd 0x00(%4,%3,4),%%xmm3 \n" >+ "pshuflw $0x40,%%xmm2,%%xmm2 \n" >+ "pshuflw $0x40,%%xmm3,%%xmm3 \n" >+ "movlhps %%xmm3,%%xmm2 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width), // %2 >+ "=&r"(alpha) // %3 >+ : "r"(fixed_invtbl8) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBUNATTENUATEROW_SSE2 > >@@ -4114,114 +4686,111 @@ void ARGBUnattenuateRow_SSE2(const uint8* src_argb, > static const uvec8 kUnattenShuffleAlpha_AVX2 = { > 0u, 1u, 0u, 1u, 0u, 1u, 6u, 7u, 8u, 9u, 8u, 9u, 8u, 9u, 14u, 15u}; > // Unattenuate 8 pixels at a time. >-void ARGBUnattenuateRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > uintptr_t alpha; >- asm volatile ( >- "sub %0,%1 \n" >- "vbroadcastf128 %5,%%ymm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "vbroadcastf128 %5,%%ymm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- // replace VPGATHER >- "movzb " MEMACCESS2(0x03,0) ",%3 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm0) // vmovd 0x0(%4,%3,4),%%xmm0 >- "movzb " MEMACCESS2(0x07,0) ",%3 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm1) // vmovd 0x0(%4,%3,4),%%xmm1 >- "movzb " MEMACCESS2(0x0b,0) ",%3 \n" >- "vpunpckldq %%xmm1,%%xmm0,%%xmm6 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm2) // vmovd 0x0(%4,%3,4),%%xmm2 >- "movzb " MEMACCESS2(0x0f,0) ",%3 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm3) // vmovd 0x0(%4,%3,4),%%xmm3 >- "movzb " MEMACCESS2(0x13,0) ",%3 \n" >- "vpunpckldq %%xmm3,%%xmm2,%%xmm7 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm0) // vmovd 0x0(%4,%3,4),%%xmm0 >- "movzb " MEMACCESS2(0x17,0) ",%3 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm1) // vmovd 0x0(%4,%3,4),%%xmm1 >- "movzb " MEMACCESS2(0x1b,0) ",%3 \n" >- "vpunpckldq %%xmm1,%%xmm0,%%xmm0 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm2) // vmovd 0x0(%4,%3,4),%%xmm2 >- "movzb " MEMACCESS2(0x1f,0) ",%3 \n" >- MEMOPREG(vmovd,0x00,4,3,4,xmm3) // vmovd 0x0(%4,%3,4),%%xmm3 >- "vpunpckldq %%xmm3,%%xmm2,%%xmm2 \n" >- "vpunpcklqdq %%xmm7,%%xmm6,%%xmm3 \n" >- "vpunpcklqdq %%xmm2,%%xmm0,%%xmm0 \n" >- "vinserti128 $0x1,%%xmm0,%%ymm3,%%ymm3 \n" >- // end of VPGATHER >- >- "vmovdqu " MEMACCESS(0) ",%%ymm6 \n" >- "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" >- "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" >- "vpunpcklwd %%ymm3,%%ymm3,%%ymm2 \n" >- "vpunpckhwd %%ymm3,%%ymm3,%%ymm3 \n" >- "vpshufb %%ymm5,%%ymm2,%%ymm2 \n" >- "vpshufb %%ymm5,%%ymm3,%%ymm3 \n" >- "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- MEMOPMEM(vmovdqu,ymm0,0x00,0,1,1) // vmovdqu %%ymm0,(%0,%1) >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width), // %2 >- "=&r"(alpha) // %3 >- : "r"(fixed_invtbl8), // %4 >- "m"(kUnattenShuffleAlpha_AVX2) // %5 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ // replace VPGATHER >+ "movzb 0x03(%0),%3 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm0 \n" >+ "movzb 0x07(%0),%3 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm1 \n" >+ "movzb 0x0b(%0),%3 \n" >+ "vpunpckldq %%xmm1,%%xmm0,%%xmm6 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm2 \n" >+ "movzb 0x0f(%0),%3 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm3 \n" >+ "movzb 0x13(%0),%3 \n" >+ "vpunpckldq %%xmm3,%%xmm2,%%xmm7 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm0 \n" >+ "movzb 0x17(%0),%3 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm1 \n" >+ "movzb 0x1b(%0),%3 \n" >+ "vpunpckldq %%xmm1,%%xmm0,%%xmm0 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm2 \n" >+ "movzb 0x1f(%0),%3 \n" >+ "vmovd 0x00(%4,%3,4),%%xmm3 \n" >+ "vpunpckldq %%xmm3,%%xmm2,%%xmm2 \n" >+ "vpunpcklqdq %%xmm7,%%xmm6,%%xmm3 \n" >+ "vpunpcklqdq %%xmm2,%%xmm0,%%xmm0 \n" >+ "vinserti128 $0x1,%%xmm0,%%ymm3,%%ymm3 \n" >+ // end of VPGATHER >+ >+ "vmovdqu (%0),%%ymm6 \n" >+ "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" >+ "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" >+ "vpunpcklwd %%ymm3,%%ymm3,%%ymm2 \n" >+ "vpunpckhwd %%ymm3,%%ymm3,%%ymm3 \n" >+ "vpshufb %%ymm5,%%ymm2,%%ymm2 \n" >+ "vpshufb %%ymm5,%%ymm3,%%ymm3 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,0x00(%0,%1,1) \n" >+ "lea 0x20(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width), // %2 >+ "=&r"(alpha) // %3 >+ : "r"(fixed_invtbl8), // %4 >+ "m"(kUnattenShuffleAlpha_AVX2) // %5 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBUNATTENUATEROW_AVX2 > > #ifdef HAS_ARGBGRAYROW_SSSE3 > // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels >-void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) { >- asm volatile ( >- "movdqa %3,%%xmm4 \n" >- "movdqa %4,%%xmm5 \n" >+void ARGBGrayRow_SSSE3(const uint8_t* src_argb, uint8_t* dst_argb, int width) { >+ asm volatile( >+ "movdqa %3,%%xmm4 \n" >+ "movdqa %4,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "paddw %%xmm5,%%xmm0 \n" >- "psrlw $0x7,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm3 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "psrld $0x18,%%xmm2 \n" >- "psrld $0x18,%%xmm3 \n" >- "packuswb %%xmm3,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm3 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "punpcklbw %%xmm2,%%xmm3 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklwd %%xmm3,%%xmm0 \n" >- "punpckhwd %%xmm3,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "m"(kARGBToYJ), // %3 >- "m"(kAddYJ64) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "paddw %%xmm5,%%xmm0 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movdqu (%0),%%xmm2 \n" >+ "movdqu 0x10(%0),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "psrld $0x18,%%xmm2 \n" >+ "psrld $0x18,%%xmm3 \n" >+ "packuswb %%xmm3,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm3 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "punpcklbw %%xmm2,%%xmm3 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklwd %%xmm3,%%xmm0 \n" >+ "punpckhwd %%xmm3,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "m"(kARGBToYJ), // %3 >+ "m"(kAddYJ64) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBGRAYROW_SSSE3 > >@@ -4230,428 +4799,415 @@ void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) { > // g = (r * 45 + g * 88 + b * 22) >> 7 > // r = (r * 50 + g * 98 + b * 24) >> 7 > // Constant for ARGB color to sepia tone >-static vec8 kARGBToSepiaB = {17, 68, 35, 0, 17, 68, 35, 0, >- 17, 68, 35, 0, 17, 68, 35, 0}; >+static const vec8 kARGBToSepiaB = {17, 68, 35, 0, 17, 68, 35, 0, >+ 17, 68, 35, 0, 17, 68, 35, 0}; > >-static vec8 kARGBToSepiaG = {22, 88, 45, 0, 22, 88, 45, 0, >- 22, 88, 45, 0, 22, 88, 45, 0}; >+static const vec8 kARGBToSepiaG = {22, 88, 45, 0, 22, 88, 45, 0, >+ 22, 88, 45, 0, 22, 88, 45, 0}; > >-static vec8 kARGBToSepiaR = {24, 98, 50, 0, 24, 98, 50, 0, >- 24, 98, 50, 0, 24, 98, 50, 0}; >+static const vec8 kARGBToSepiaR = {24, 98, 50, 0, 24, 98, 50, 0, >+ 24, 98, 50, 0, 24, 98, 50, 0}; > > // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels. >-void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) { >- asm volatile ( >- "movdqa %2,%%xmm2 \n" >- "movdqa %3,%%xmm3 \n" >- "movdqa %4,%%xmm4 \n" >+void ARGBSepiaRow_SSSE3(uint8_t* dst_argb, int width) { >+ asm volatile( >+ "movdqa %2,%%xmm2 \n" >+ "movdqa %3,%%xmm3 \n" >+ "movdqa %4,%%xmm4 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" >- "pmaddubsw %%xmm2,%%xmm0 \n" >- "pmaddubsw %%xmm2,%%xmm6 \n" >- "phaddw %%xmm6,%%xmm0 \n" >- "psrlw $0x7,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm5 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm5 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "phaddw %%xmm1,%%xmm5 \n" >- "psrlw $0x7,%%xmm5 \n" >- "packuswb %%xmm5,%%xmm5 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm5 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm5 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "phaddw %%xmm1,%%xmm5 \n" >- "psrlw $0x7,%%xmm5 \n" >- "packuswb %%xmm5,%%xmm5 \n" >- "movdqu " MEMACCESS(0) ",%%xmm6 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "psrld $0x18,%%xmm6 \n" >- "psrld $0x18,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "punpcklbw %%xmm6,%%xmm5 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklwd %%xmm5,%%xmm0 \n" >- "punpckhwd %%xmm5,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(0) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "sub $0x8,%1 \n" >- "jg 1b \n" >- : "+r"(dst_argb), // %0 >- "+r"(width) // %1 >- : "m"(kARGBToSepiaB), // %2 >- "m"(kARGBToSepiaG), // %3 >- "m"(kARGBToSepiaR) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm6 \n" >+ "pmaddubsw %%xmm2,%%xmm0 \n" >+ "pmaddubsw %%xmm2,%%xmm6 \n" >+ "phaddw %%xmm6,%%xmm0 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movdqu (%0),%%xmm5 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm5 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "phaddw %%xmm1,%%xmm5 \n" >+ "psrlw $0x7,%%xmm5 \n" >+ "packuswb %%xmm5,%%xmm5 \n" >+ "punpcklbw %%xmm5,%%xmm0 \n" >+ "movdqu (%0),%%xmm5 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm5 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "phaddw %%xmm1,%%xmm5 \n" >+ "psrlw $0x7,%%xmm5 \n" >+ "packuswb %%xmm5,%%xmm5 \n" >+ "movdqu (%0),%%xmm6 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "psrld $0x18,%%xmm6 \n" >+ "psrld $0x18,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "punpcklbw %%xmm6,%%xmm5 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklwd %%xmm5,%%xmm0 \n" >+ "punpckhwd %%xmm5,%%xmm1 \n" >+ "movdqu %%xmm0,(%0) \n" >+ "movdqu %%xmm1,0x10(%0) \n" >+ "lea 0x20(%0),%0 \n" >+ "sub $0x8,%1 \n" >+ "jg 1b \n" >+ : "+r"(dst_argb), // %0 >+ "+r"(width) // %1 >+ : "m"(kARGBToSepiaB), // %2 >+ "m"(kARGBToSepiaG), // %3 >+ "m"(kARGBToSepiaR) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_ARGBSEPIAROW_SSSE3 > > #ifdef HAS_ARGBCOLORMATRIXROW_SSSE3 > // Tranform 8 ARGB pixels (32 bytes) with color matrix. > // Same as Sepia except matrix is provided. >-void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { >- asm volatile ( >- "movdqu " MEMACCESS(3) ",%%xmm5 \n" >- "pshufd $0x00,%%xmm5,%%xmm2 \n" >- "pshufd $0x55,%%xmm5,%%xmm3 \n" >- "pshufd $0xaa,%%xmm5,%%xmm4 \n" >- "pshufd $0xff,%%xmm5,%%xmm5 \n" >+ asm volatile( >+ "movdqu (%3),%%xmm5 \n" >+ "pshufd $0x00,%%xmm5,%%xmm2 \n" >+ "pshufd $0x55,%%xmm5,%%xmm3 \n" >+ "pshufd $0xaa,%%xmm5,%%xmm4 \n" >+ "pshufd $0xff,%%xmm5,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" >- "pmaddubsw %%xmm2,%%xmm0 \n" >- "pmaddubsw %%xmm2,%%xmm7 \n" >- "movdqu " MEMACCESS(0) ",%%xmm6 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "pmaddubsw %%xmm3,%%xmm6 \n" >- "pmaddubsw %%xmm3,%%xmm1 \n" >- "phaddsw %%xmm7,%%xmm0 \n" >- "phaddsw %%xmm1,%%xmm6 \n" >- "psraw $0x6,%%xmm0 \n" >- "psraw $0x6,%%xmm6 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "punpcklbw %%xmm6,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm7 \n" >- "phaddsw %%xmm7,%%xmm1 \n" >- "movdqu " MEMACCESS(0) ",%%xmm6 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" >- "pmaddubsw %%xmm5,%%xmm6 \n" >- "pmaddubsw %%xmm5,%%xmm7 \n" >- "phaddsw %%xmm7,%%xmm6 \n" >- "psraw $0x6,%%xmm1 \n" >- "psraw $0x6,%%xmm6 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "punpcklbw %%xmm6,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm6 \n" >- "punpcklwd %%xmm1,%%xmm0 \n" >- "punpckhwd %%xmm1,%%xmm6 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm6," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(matrix_argb) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm7 \n" >+ "pmaddubsw %%xmm2,%%xmm0 \n" >+ "pmaddubsw %%xmm2,%%xmm7 \n" >+ "movdqu (%0),%%xmm6 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "pmaddubsw %%xmm3,%%xmm6 \n" >+ "pmaddubsw %%xmm3,%%xmm1 \n" >+ "phaddsw %%xmm7,%%xmm0 \n" >+ "phaddsw %%xmm1,%%xmm6 \n" >+ "psraw $0x6,%%xmm0 \n" >+ "psraw $0x6,%%xmm6 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "punpcklbw %%xmm6,%%xmm0 \n" >+ "movdqu (%0),%%xmm1 \n" >+ "movdqu 0x10(%0),%%xmm7 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm7 \n" >+ "phaddsw %%xmm7,%%xmm1 \n" >+ "movdqu (%0),%%xmm6 \n" >+ "movdqu 0x10(%0),%%xmm7 \n" >+ "pmaddubsw %%xmm5,%%xmm6 \n" >+ "pmaddubsw %%xmm5,%%xmm7 \n" >+ "phaddsw %%xmm7,%%xmm6 \n" >+ "psraw $0x6,%%xmm1 \n" >+ "psraw $0x6,%%xmm6 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "punpcklbw %%xmm6,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm6 \n" >+ "punpcklwd %%xmm1,%%xmm0 \n" >+ "punpckhwd %%xmm1,%%xmm6 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm6,0x10(%1) \n" >+ "lea 0x20(%0),%0 \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(matrix_argb) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBCOLORMATRIXROW_SSSE3 > > #ifdef HAS_ARGBQUANTIZEROW_SSE2 > // Quantize 4 ARGB pixels (16 bytes). >-void ARGBQuantizeRow_SSE2(uint8* dst_argb, >+void ARGBQuantizeRow_SSE2(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, > int width) { >- asm volatile ( >- "movd %2,%%xmm2 \n" >- "movd %3,%%xmm3 \n" >- "movd %4,%%xmm4 \n" >- "pshuflw $0x40,%%xmm2,%%xmm2 \n" >- "pshufd $0x44,%%xmm2,%%xmm2 \n" >- "pshuflw $0x40,%%xmm3,%%xmm3 \n" >- "pshufd $0x44,%%xmm3,%%xmm3 \n" >- "pshuflw $0x40,%%xmm4,%%xmm4 \n" >- "pshufd $0x44,%%xmm4,%%xmm4 \n" >- "pxor %%xmm5,%%xmm5 \n" >- "pcmpeqb %%xmm6,%%xmm6 \n" >- "pslld $0x18,%%xmm6 \n" >- >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "pmulhuw %%xmm2,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm1 \n" >- "punpckhbw %%xmm5,%%xmm1 \n" >- "pmulhuw %%xmm2,%%xmm1 \n" >- "pmullw %%xmm3,%%xmm0 \n" >- "movdqu " MEMACCESS(0) ",%%xmm7 \n" >- "pmullw %%xmm3,%%xmm1 \n" >- "pand %%xmm6,%%xmm7 \n" >- "paddw %%xmm4,%%xmm0 \n" >- "paddw %%xmm4,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "por %%xmm7,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(0) " \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "sub $0x4,%1 \n" >- "jg 1b \n" >- : "+r"(dst_argb), // %0 >- "+r"(width) // %1 >- : "r"(scale), // %2 >- "r"(interval_size), // %3 >- "r"(interval_offset) // %4 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ "movd %2,%%xmm2 \n" >+ "movd %3,%%xmm3 \n" >+ "movd %4,%%xmm4 \n" >+ "pshuflw $0x40,%%xmm2,%%xmm2 \n" >+ "pshufd $0x44,%%xmm2,%%xmm2 \n" >+ "pshuflw $0x40,%%xmm3,%%xmm3 \n" >+ "pshufd $0x44,%%xmm3,%%xmm3 \n" >+ "pshuflw $0x40,%%xmm4,%%xmm4 \n" >+ "pshufd $0x44,%%xmm4,%%xmm4 \n" >+ "pxor %%xmm5,%%xmm5 \n" >+ "pcmpeqb %%xmm6,%%xmm6 \n" >+ "pslld $0x18,%%xmm6 \n" >+ >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "punpcklbw %%xmm5,%%xmm0 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "movdqu (%0),%%xmm1 \n" >+ "punpckhbw %%xmm5,%%xmm1 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "pmullw %%xmm3,%%xmm0 \n" >+ "movdqu (%0),%%xmm7 \n" >+ "pmullw %%xmm3,%%xmm1 \n" >+ "pand %%xmm6,%%xmm7 \n" >+ "paddw %%xmm4,%%xmm0 \n" >+ "paddw %%xmm4,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "por %%xmm7,%%xmm0 \n" >+ "movdqu %%xmm0,(%0) \n" >+ "lea 0x10(%0),%0 \n" >+ "sub $0x4,%1 \n" >+ "jg 1b \n" >+ : "+r"(dst_argb), // %0 >+ "+r"(width) // %1 >+ : "r"(scale), // %2 >+ "r"(interval_size), // %3 >+ "r"(interval_offset) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBQUANTIZEROW_SSE2 > > #ifdef HAS_ARGBSHADEROW_SSE2 > // Shade 4 pixels at a time by specified value. >-void ARGBShadeRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >- asm volatile ( >- "movd %3,%%xmm2 \n" >- "punpcklbw %%xmm2,%%xmm2 \n" >- "punpcklqdq %%xmm2,%%xmm2 \n" >+ uint32_t value) { >+ asm volatile( >+ "movd %3,%%xmm2 \n" >+ "punpcklbw %%xmm2,%%xmm2 \n" >+ "punpcklqdq %%xmm2,%%xmm2 \n" > >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "punpckhbw %%xmm1,%%xmm1 \n" >- "pmulhuw %%xmm2,%%xmm0 \n" >- "pmulhuw %%xmm2,%%xmm1 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(value) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2" >- ); >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "punpckhbw %%xmm1,%%xmm1 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "pmulhuw %%xmm2,%%xmm1 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(value) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } > #endif // HAS_ARGBSHADEROW_SSE2 > > #ifdef HAS_ARGBMULTIPLYROW_SSE2 > // Multiply 2 rows of ARGB pixels together, 4 pixels at a time. >-void ARGBMultiplyRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- "pxor %%xmm5,%%xmm5 \n" >+ asm volatile( > >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm2 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "movdqu %%xmm0,%%xmm1 \n" >- "movdqu %%xmm2,%%xmm3 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "punpckhbw %%xmm1,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm2 \n" >- "punpckhbw %%xmm5,%%xmm3 \n" >- "pmulhuw %%xmm2,%%xmm0 \n" >- "pmulhuw %%xmm3,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ "pxor %%xmm5,%%xmm5 \n" >+ >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqu (%1),%%xmm2 \n" >+ "lea 0x10(%1),%1 \n" >+ "movdqu %%xmm0,%%xmm1 \n" >+ "movdqu %%xmm2,%%xmm3 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "punpckhbw %%xmm1,%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "punpckhbw %%xmm5,%%xmm3 \n" >+ "pmulhuw %%xmm2,%%xmm0 \n" >+ "pmulhuw %%xmm3,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_ARGBMULTIPLYROW_SSE2 > > #ifdef HAS_ARGBMULTIPLYROW_AVX2 > // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. >-void ARGBMultiplyRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ asm volatile( > >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "vmovdqu " MEMACCESS(1) ",%%ymm3 \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "vpunpcklbw %%ymm1,%%ymm1,%%ymm0 \n" >- "vpunpckhbw %%ymm1,%%ymm1,%%ymm1 \n" >- "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" >- "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" >- "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x20,2) ",%2 \n" >- "sub $0x8,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >+ "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "vmovdqu (%1),%%ymm3 \n" >+ "lea 0x20(%1),%1 \n" >+ "vpunpcklbw %%ymm1,%%ymm1,%%ymm0 \n" >+ "vpunpckhbw %%ymm1,%%ymm1,%%ymm1 \n" >+ "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" >+ "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" >+ "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%2) \n" >+ "lea 0x20(%2),%2 \n" >+ "sub $0x8,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc" > #if defined(__AVX2__) >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >+ , >+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" > #endif >- ); >+ ); > } > #endif // HAS_ARGBMULTIPLYROW_AVX2 > > #ifdef HAS_ARGBADDROW_SSE2 > // Add 2 rows of ARGB pixels together, 4 pixels at a time. >-void ARGBAddRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+ asm volatile( >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "lea 0x10(%1),%1 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_ARGBADDROW_SSE2 > > #ifdef HAS_ARGBADDROW_AVX2 > // Add 2 rows of ARGB pixels together, 4 pixels at a time. >-void ARGBAddRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "vpaddusb " MEMACCESS(1) ",%%ymm0,%%ymm0 \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "vmovdqu %%ymm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x20,2) ",%2 \n" >- "sub $0x8,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0" >- ); >+ asm volatile( >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "lea 0x20(%0),%0 \n" >+ "vpaddusb (%1),%%ymm0,%%ymm0 \n" >+ "lea 0x20(%1),%1 \n" >+ "vmovdqu %%ymm0,(%2) \n" >+ "lea 0x20(%2),%2 \n" >+ "sub $0x8,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0"); > } > #endif // HAS_ARGBADDROW_AVX2 > > #ifdef HAS_ARGBSUBTRACTROW_SSE2 > // Subtract 2 rows of ARGB pixels, 4 pixels at a time. >-void ARGBSubtractRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqu " MEMACCESS(1) ",%%xmm1 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "psubusb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0", "xmm1" >- ); >+ asm volatile( >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqu (%1),%%xmm1 \n" >+ "lea 0x10(%1),%1 \n" >+ "psubusb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_ARGBSUBTRACTROW_SSE2 > > #ifdef HAS_ARGBSUBTRACTROW_AVX2 > // Subtract 2 rows of ARGB pixels, 8 pixels at a time. >-void ARGBSubtractRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "vpsubusb " MEMACCESS(1) ",%%ymm0,%%ymm0 \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "vmovdqu %%ymm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x20,2) ",%2 \n" >- "sub $0x8,%3 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb0), // %0 >- "+r"(src_argb1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0" >- ); >+ asm volatile( >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "lea 0x20(%0),%0 \n" >+ "vpsubusb (%1),%%ymm0,%%ymm0 \n" >+ "lea 0x20(%1),%1 \n" >+ "vmovdqu %%ymm0,(%2) \n" >+ "lea 0x20(%2),%2 \n" >+ "sub $0x8,%3 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb0), // %0 >+ "+r"(src_argb1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0"); > } > #endif // HAS_ARGBSUBTRACTROW_AVX2 > >@@ -4660,55 +5216,53 @@ void ARGBSubtractRow_AVX2(const uint8* src_argb0, > // -1 0 1 > // -2 0 2 > // -1 0 1 >-void SobelXRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >- "sub %0,%2 \n" >- "sub %0,%3 \n" >- "pxor %%xmm5,%%xmm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "sub %0,%2 \n" >+ "sub %0,%3 \n" >+ "pxor %%xmm5,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- "movq " MEMACCESS2(0x2,0) ",%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpcklbw %%xmm5,%%xmm1 \n" >- "psubw %%xmm1,%%xmm0 \n" >- MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1 >- MEMOPREG(movq,0x02,0,1,1,xmm2) // movq 0x2(%0,%1,1),%%xmm2 >- "punpcklbw %%xmm5,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm2 \n" >- "psubw %%xmm2,%%xmm1 \n" >- MEMOPREG(movq,0x00,0,2,1,xmm2) // movq (%0,%2,1),%%xmm2 >- MEMOPREG(movq,0x02,0,2,1,xmm3) // movq 0x2(%0,%2,1),%%xmm3 >- "punpcklbw %%xmm5,%%xmm2 \n" >- "punpcklbw %%xmm5,%%xmm3 \n" >- "psubw %%xmm3,%%xmm2 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm1,%%xmm0 \n" >- "paddw %%xmm1,%%xmm0 \n" >- "pxor %%xmm1,%%xmm1 \n" >- "psubw %%xmm0,%%xmm1 \n" >- "pmaxsw %%xmm1,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- MEMOPMEM(movq,xmm0,0x00,0,3,1) // movq %%xmm0,(%0,%3,1) >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "sub $0x8,%4 \n" >- "jg 1b \n" >- : "+r"(src_y0), // %0 >- "+r"(src_y1), // %1 >- "+r"(src_y2), // %2 >- "+r"(dst_sobelx), // %3 >- "+r"(width) // %4 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm0 \n" >+ "movq 0x2(%0),%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm0 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "psubw %%xmm1,%%xmm0 \n" >+ "movq 0x00(%0,%1,1),%%xmm1 \n" >+ "movq 0x02(%0,%1,1),%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "psubw %%xmm2,%%xmm1 \n" >+ "movq 0x00(%0,%2,1),%%xmm2 \n" >+ "movq 0x02(%0,%2,1),%%xmm3 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm3 \n" >+ "psubw %%xmm3,%%xmm2 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm1,%%xmm0 \n" >+ "paddw %%xmm1,%%xmm0 \n" >+ "pxor %%xmm1,%%xmm1 \n" >+ "psubw %%xmm0,%%xmm1 \n" >+ "pmaxsw %%xmm1,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,0x00(%0,%3,1) \n" >+ "lea 0x8(%0),%0 \n" >+ "sub $0x8,%4 \n" >+ "jg 1b \n" >+ : "+r"(src_y0), // %0 >+ "+r"(src_y1), // %1 >+ "+r"(src_y2), // %2 >+ "+r"(dst_sobelx), // %3 >+ "+r"(width) // %4 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SOBELXROW_SSE2 > >@@ -4717,52 +5271,50 @@ void SobelXRow_SSE2(const uint8* src_y0, > // -1 -2 -1 > // 0 0 0 > // 1 2 1 >-void SobelYRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >- "sub %0,%2 \n" >- "pxor %%xmm5,%%xmm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "sub %0,%2 \n" >+ "pxor %%xmm5,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1 >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpcklbw %%xmm5,%%xmm1 \n" >- "psubw %%xmm1,%%xmm0 \n" >- "movq " MEMACCESS2(0x1,0) ",%%xmm1 \n" >- MEMOPREG(movq,0x01,0,1,1,xmm2) // movq 0x1(%0,%1,1),%%xmm2 >- "punpcklbw %%xmm5,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm2 \n" >- "psubw %%xmm2,%%xmm1 \n" >- "movq " MEMACCESS2(0x2,0) ",%%xmm2 \n" >- MEMOPREG(movq,0x02,0,1,1,xmm3) // movq 0x2(%0,%1,1),%%xmm3 >- "punpcklbw %%xmm5,%%xmm2 \n" >- "punpcklbw %%xmm5,%%xmm3 \n" >- "psubw %%xmm3,%%xmm2 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm1,%%xmm0 \n" >- "paddw %%xmm1,%%xmm0 \n" >- "pxor %%xmm1,%%xmm1 \n" >- "psubw %%xmm0,%%xmm1 \n" >- "pmaxsw %%xmm1,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- MEMOPMEM(movq,xmm0,0x00,0,2,1) // movq %%xmm0,(%0,%2,1) >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "sub $0x8,%3 \n" >- "jg 1b \n" >- : "+r"(src_y0), // %0 >- "+r"(src_y1), // %1 >- "+r"(dst_sobely), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm0 \n" >+ "movq 0x00(%0,%1,1),%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm0 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "psubw %%xmm1,%%xmm0 \n" >+ "movq 0x1(%0),%%xmm1 \n" >+ "movq 0x01(%0,%1,1),%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "psubw %%xmm2,%%xmm1 \n" >+ "movq 0x2(%0),%%xmm2 \n" >+ "movq 0x02(%0,%1,1),%%xmm3 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm3 \n" >+ "psubw %%xmm3,%%xmm2 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm1,%%xmm0 \n" >+ "paddw %%xmm1,%%xmm0 \n" >+ "pxor %%xmm1,%%xmm1 \n" >+ "psubw %%xmm0,%%xmm1 \n" >+ "pmaxsw %%xmm1,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,0x00(%0,%2,1) \n" >+ "lea 0x8(%0),%0 \n" >+ "sub $0x8,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_y0), // %0 >+ "+r"(src_y1), // %1 >+ "+r"(dst_sobely), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SOBELYROW_SSE2 > >@@ -4772,83 +5324,79 @@ void SobelYRow_SSE2(const uint8* src_y0, > // R = Sobel > // G = Sobel > // B = Sobel >-void SobelRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "pslld $0x18,%%xmm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "pslld $0x18,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "punpcklbw %%xmm0,%%xmm2 \n" >- "punpckhbw %%xmm0,%%xmm0 \n" >- "movdqa %%xmm2,%%xmm1 \n" >- "punpcklwd %%xmm2,%%xmm1 \n" >- "punpckhwd %%xmm2,%%xmm2 \n" >- "por %%xmm5,%%xmm1 \n" >- "por %%xmm5,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm3 \n" >- "punpcklwd %%xmm0,%%xmm3 \n" >- "punpckhwd %%xmm0,%%xmm0 \n" >- "por %%xmm5,%%xmm3 \n" >- "por %%xmm5,%%xmm0 \n" >- "movdqu %%xmm1," MEMACCESS(2) " \n" >- "movdqu %%xmm2," MEMACCESS2(0x10,2) " \n" >- "movdqu %%xmm3," MEMACCESS2(0x20,2) " \n" >- "movdqu %%xmm0," MEMACCESS2(0x30,2) " \n" >- "lea " MEMLEA(0x40,2) ",%2 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_sobelx), // %0 >- "+r"(src_sobely), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%1,1),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "punpcklbw %%xmm0,%%xmm2 \n" >+ "punpckhbw %%xmm0,%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm1 \n" >+ "punpcklwd %%xmm2,%%xmm1 \n" >+ "punpckhwd %%xmm2,%%xmm2 \n" >+ "por %%xmm5,%%xmm1 \n" >+ "por %%xmm5,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm3 \n" >+ "punpcklwd %%xmm0,%%xmm3 \n" >+ "punpckhwd %%xmm0,%%xmm0 \n" >+ "por %%xmm5,%%xmm3 \n" >+ "por %%xmm5,%%xmm0 \n" >+ "movdqu %%xmm1,(%2) \n" >+ "movdqu %%xmm2,0x10(%2) \n" >+ "movdqu %%xmm3,0x20(%2) \n" >+ "movdqu %%xmm0,0x30(%2) \n" >+ "lea 0x40(%2),%2 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_sobelx), // %0 >+ "+r"(src_sobely), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SOBELROW_SSE2 > > #ifdef HAS_SOBELTOPLANEROW_SSE2 > // Adds Sobel X and Sobel Y and stores Sobel into a plane. >-void SobelToPlaneRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "pslld $0x18,%%xmm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "pslld $0x18,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_sobelx), // %0 >- "+r"(src_sobely), // %1 >- "+r"(dst_y), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%1,1),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_sobelx), // %0 >+ "+r"(src_sobely), // %1 >+ "+r"(dst_y), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1"); > } > #endif // HAS_SOBELTOPLANEROW_SSE2 > >@@ -4858,1179 +5406,1123 @@ void SobelToPlaneRow_SSE2(const uint8* src_sobelx, > // R = Sobel X > // G = Sobel > // B = Sobel Y >-void SobelXYRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { >- asm volatile ( >- "sub %0,%1 \n" >- "pcmpeqb %%xmm5,%%xmm5 \n" >+ asm volatile( >+ "sub %0,%1 \n" >+ "pcmpeqb %%xmm5,%%xmm5 \n" > >- // 8 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "paddusb %%xmm1,%%xmm2 \n" >- "movdqa %%xmm0,%%xmm3 \n" >- "punpcklbw %%xmm5,%%xmm3 \n" >- "punpckhbw %%xmm5,%%xmm0 \n" >- "movdqa %%xmm1,%%xmm4 \n" >- "punpcklbw %%xmm2,%%xmm4 \n" >- "punpckhbw %%xmm2,%%xmm1 \n" >- "movdqa %%xmm4,%%xmm6 \n" >- "punpcklwd %%xmm3,%%xmm6 \n" >- "punpckhwd %%xmm3,%%xmm4 \n" >- "movdqa %%xmm1,%%xmm7 \n" >- "punpcklwd %%xmm0,%%xmm7 \n" >- "punpckhwd %%xmm0,%%xmm1 \n" >- "movdqu %%xmm6," MEMACCESS(2) " \n" >- "movdqu %%xmm4," MEMACCESS2(0x10,2) " \n" >- "movdqu %%xmm7," MEMACCESS2(0x20,2) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x30,2) " \n" >- "lea " MEMLEA(0x40,2) ",%2 \n" >- "sub $0x10,%3 \n" >- "jg 1b \n" >- : "+r"(src_sobelx), // %0 >- "+r"(src_sobely), // %1 >- "+r"(dst_argb), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ // 8 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%1,1),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "paddusb %%xmm1,%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm3 \n" >+ "punpcklbw %%xmm5,%%xmm3 \n" >+ "punpckhbw %%xmm5,%%xmm0 \n" >+ "movdqa %%xmm1,%%xmm4 \n" >+ "punpcklbw %%xmm2,%%xmm4 \n" >+ "punpckhbw %%xmm2,%%xmm1 \n" >+ "movdqa %%xmm4,%%xmm6 \n" >+ "punpcklwd %%xmm3,%%xmm6 \n" >+ "punpckhwd %%xmm3,%%xmm4 \n" >+ "movdqa %%xmm1,%%xmm7 \n" >+ "punpcklwd %%xmm0,%%xmm7 \n" >+ "punpckhwd %%xmm0,%%xmm1 \n" >+ "movdqu %%xmm6,(%2) \n" >+ "movdqu %%xmm4,0x10(%2) \n" >+ "movdqu %%xmm7,0x20(%2) \n" >+ "movdqu %%xmm1,0x30(%2) \n" >+ "lea 0x40(%2),%2 \n" >+ "sub $0x10,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_sobelx), // %0 >+ "+r"(src_sobely), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_SOBELXYROW_SSE2 > > #ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2 > // Creates a table of cumulative sums where each value is a sum of all values > // above and to the left of the value, inclusive of the value. >-void ComputeCumulativeSumRow_SSE2(const uint8* row, >- int32* cumsum, >- const int32* previous_cumsum, >+void ComputeCumulativeSumRow_SSE2(const uint8_t* row, >+ int32_t* cumsum, >+ const int32_t* previous_cumsum, > int width) { >- asm volatile ( >- "pxor %%xmm0,%%xmm0 \n" >- "pxor %%xmm1,%%xmm1 \n" >- "sub $0x4,%3 \n" >- "jl 49f \n" >- "test $0xf,%1 \n" >- "jne 49f \n" >- >- // 4 pixel loop. >- LABELALIGN >- "40: \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm2,%%xmm4 \n" >- "punpcklbw %%xmm1,%%xmm2 \n" >- "movdqa %%xmm2,%%xmm3 \n" >- "punpcklwd %%xmm1,%%xmm2 \n" >- "punpckhwd %%xmm1,%%xmm3 \n" >- "punpckhbw %%xmm1,%%xmm4 \n" >- "movdqa %%xmm4,%%xmm5 \n" >- "punpcklwd %%xmm1,%%xmm4 \n" >- "punpckhwd %%xmm1,%%xmm5 \n" >- "paddd %%xmm2,%%xmm0 \n" >- "movdqu " MEMACCESS(2) ",%%xmm2 \n" >- "paddd %%xmm0,%%xmm2 \n" >- "paddd %%xmm3,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,2) ",%%xmm3 \n" >- "paddd %%xmm0,%%xmm3 \n" >- "paddd %%xmm4,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x20,2) ",%%xmm4 \n" >- "paddd %%xmm0,%%xmm4 \n" >- "paddd %%xmm5,%%xmm0 \n" >- "movdqu " MEMACCESS2(0x30,2) ",%%xmm5 \n" >- "lea " MEMLEA(0x40,2) ",%2 \n" >- "paddd %%xmm0,%%xmm5 \n" >- "movdqu %%xmm2," MEMACCESS(1) " \n" >- "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" >- "movdqu %%xmm4," MEMACCESS2(0x20,1) " \n" >- "movdqu %%xmm5," MEMACCESS2(0x30,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x4,%3 \n" >- "jge 40b \n" >- >- "49: \n" >- "add $0x3,%3 \n" >- "jl 19f \n" >- >- // 1 pixel loop. >- LABELALIGN >- "10: \n" >- "movd " MEMACCESS(0) ",%%xmm2 \n" >- "lea " MEMLEA(0x4,0) ",%0 \n" >- "punpcklbw %%xmm1,%%xmm2 \n" >- "punpcklwd %%xmm1,%%xmm2 \n" >- "paddd %%xmm2,%%xmm0 \n" >- "movdqu " MEMACCESS(2) ",%%xmm2 \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "paddd %%xmm0,%%xmm2 \n" >- "movdqu %%xmm2," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x1,%3 \n" >- "jge 10b \n" >- >- "19: \n" >- : "+r"(row), // %0 >- "+r"(cumsum), // %1 >- "+r"(previous_cumsum), // %2 >- "+r"(width) // %3 >- : >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "pxor %%xmm0,%%xmm0 \n" >+ "pxor %%xmm1,%%xmm1 \n" >+ "sub $0x4,%3 \n" >+ "jl 49f \n" >+ "test $0xf,%1 \n" >+ "jne 49f \n" >+ >+ // 4 pixel loop. >+ LABELALIGN >+ "40: \n" >+ "movdqu (%0),%%xmm2 \n" >+ "lea 0x10(%0),%0 \n" >+ "movdqa %%xmm2,%%xmm4 \n" >+ "punpcklbw %%xmm1,%%xmm2 \n" >+ "movdqa %%xmm2,%%xmm3 \n" >+ "punpcklwd %%xmm1,%%xmm2 \n" >+ "punpckhwd %%xmm1,%%xmm3 \n" >+ "punpckhbw %%xmm1,%%xmm4 \n" >+ "movdqa %%xmm4,%%xmm5 \n" >+ "punpcklwd %%xmm1,%%xmm4 \n" >+ "punpckhwd %%xmm1,%%xmm5 \n" >+ "paddd %%xmm2,%%xmm0 \n" >+ "movdqu (%2),%%xmm2 \n" >+ "paddd %%xmm0,%%xmm2 \n" >+ "paddd %%xmm3,%%xmm0 \n" >+ "movdqu 0x10(%2),%%xmm3 \n" >+ "paddd %%xmm0,%%xmm3 \n" >+ "paddd %%xmm4,%%xmm0 \n" >+ "movdqu 0x20(%2),%%xmm4 \n" >+ "paddd %%xmm0,%%xmm4 \n" >+ "paddd %%xmm5,%%xmm0 \n" >+ "movdqu 0x30(%2),%%xmm5 \n" >+ "lea 0x40(%2),%2 \n" >+ "paddd %%xmm0,%%xmm5 \n" >+ "movdqu %%xmm2,(%1) \n" >+ "movdqu %%xmm3,0x10(%1) \n" >+ "movdqu %%xmm4,0x20(%1) \n" >+ "movdqu %%xmm5,0x30(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x4,%3 \n" >+ "jge 40b \n" >+ >+ "49: \n" >+ "add $0x3,%3 \n" >+ "jl 19f \n" >+ >+ // 1 pixel loop. >+ LABELALIGN >+ "10: \n" >+ "movd (%0),%%xmm2 \n" >+ "lea 0x4(%0),%0 \n" >+ "punpcklbw %%xmm1,%%xmm2 \n" >+ "punpcklwd %%xmm1,%%xmm2 \n" >+ "paddd %%xmm2,%%xmm0 \n" >+ "movdqu (%2),%%xmm2 \n" >+ "lea 0x10(%2),%2 \n" >+ "paddd %%xmm0,%%xmm2 \n" >+ "movdqu %%xmm2,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x1,%3 \n" >+ "jge 10b \n" >+ >+ "19: \n" >+ : "+r"(row), // %0 >+ "+r"(cumsum), // %1 >+ "+r"(previous_cumsum), // %2 >+ "+r"(width) // %3 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_COMPUTECUMULATIVESUMROW_SSE2 > > #ifdef HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 >-void CumulativeSumToAverageRow_SSE2(const int32* topleft, >- const int32* botleft, >+void CumulativeSumToAverageRow_SSE2(const int32_t* topleft, >+ const int32_t* botleft, > int width, > int area, >- uint8* dst, >+ uint8_t* dst, > int count) { >- asm volatile ( >- "movd %5,%%xmm5 \n" >- "cvtdq2ps %%xmm5,%%xmm5 \n" >- "rcpss %%xmm5,%%xmm4 \n" >- "pshufd $0x0,%%xmm4,%%xmm4 \n" >- "sub $0x4,%3 \n" >- "jl 49f \n" >- "cmpl $0x80,%5 \n" >- "ja 40f \n" >- >- "pshufd $0x0,%%xmm5,%%xmm5 \n" >- "pcmpeqb %%xmm6,%%xmm6 \n" >- "psrld $0x10,%%xmm6 \n" >- "cvtdq2ps %%xmm6,%%xmm6 \n" >- "addps %%xmm6,%%xmm5 \n" >- "mulps %%xmm4,%%xmm5 \n" >- "cvtps2dq %%xmm5,%%xmm5 \n" >- "packssdw %%xmm5,%%xmm5 \n" >- >- // 4 pixel small loop. >- LABELALIGN >- "4: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 >- MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1 >- MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2 >- MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3 >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "psubd " MEMACCESS(1) ",%%xmm0 \n" >- "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n" >- "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n" >- "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n" >- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 >- MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1 >- MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2 >- MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3 >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "packssdw %%xmm1,%%xmm0 \n" >- "packssdw %%xmm3,%%xmm2 \n" >- "pmulhuw %%xmm5,%%xmm0 \n" >- "pmulhuw %%xmm5,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jge 4b \n" >- "jmp 49f \n" >- >- // 4 pixel loop \n" >- LABELALIGN >- "40: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" >- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" >- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 >- MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1 >- MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2 >- MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3 >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "psubd " MEMACCESS(1) ",%%xmm0 \n" >- "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n" >- "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n" >- "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n" >- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 >- MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1 >- MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2 >- MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3 >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "cvtdq2ps %%xmm0,%%xmm0 \n" >- "cvtdq2ps %%xmm1,%%xmm1 \n" >- "mulps %%xmm4,%%xmm0 \n" >- "mulps %%xmm4,%%xmm1 \n" >- "cvtdq2ps %%xmm2,%%xmm2 \n" >- "cvtdq2ps %%xmm3,%%xmm3 \n" >- "mulps %%xmm4,%%xmm2 \n" >- "mulps %%xmm4,%%xmm3 \n" >- "cvtps2dq %%xmm0,%%xmm0 \n" >- "cvtps2dq %%xmm1,%%xmm1 \n" >- "cvtps2dq %%xmm2,%%xmm2 \n" >- "cvtps2dq %%xmm3,%%xmm3 \n" >- "packssdw %%xmm1,%%xmm0 \n" >- "packssdw %%xmm3,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jge 40b \n" >- >- "49: \n" >- "add $0x3,%3 \n" >- "jl 19f \n" >- >- // 1 pixel loop \n" >- LABELALIGN >- "10: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "psubd " MEMACCESS(1) ",%%xmm0 \n" >- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "cvtdq2ps %%xmm0,%%xmm0 \n" >- "mulps %%xmm4,%%xmm0 \n" >- "cvtps2dq %%xmm0,%%xmm0 \n" >- "packssdw %%xmm0,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movd %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x4,2) ",%2 \n" >- "sub $0x1,%3 \n" >- "jge 10b \n" >- "19: \n" >- : "+r"(topleft), // %0 >- "+r"(botleft), // %1 >- "+r"(dst), // %2 >- "+rm"(count) // %3 >- : "r"((intptr_t)(width)), // %4 >- "rm"(area) // %5 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ asm volatile( >+ "movd %5,%%xmm5 \n" >+ "cvtdq2ps %%xmm5,%%xmm5 \n" >+ "rcpss %%xmm5,%%xmm4 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ "sub $0x4,%3 \n" >+ "jl 49f \n" >+ "cmpl $0x80,%5 \n" >+ "ja 40f \n" >+ >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "pcmpeqb %%xmm6,%%xmm6 \n" >+ "psrld $0x10,%%xmm6 \n" >+ "cvtdq2ps %%xmm6,%%xmm6 \n" >+ "addps %%xmm6,%%xmm5 \n" >+ "mulps %%xmm4,%%xmm5 \n" >+ "cvtps2dq %%xmm5,%%xmm5 \n" >+ "packssdw %%xmm5,%%xmm5 \n" >+ >+ // 4 pixel small loop. >+ LABELALIGN >+ "4: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "psubd 0x00(%0,%4,4),%%xmm0 \n" >+ "psubd 0x10(%0,%4,4),%%xmm1 \n" >+ "psubd 0x20(%0,%4,4),%%xmm2 \n" >+ "psubd 0x30(%0,%4,4),%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "psubd (%1),%%xmm0 \n" >+ "psubd 0x10(%1),%%xmm1 \n" >+ "psubd 0x20(%1),%%xmm2 \n" >+ "psubd 0x30(%1),%%xmm3 \n" >+ "paddd 0x00(%1,%4,4),%%xmm0 \n" >+ "paddd 0x10(%1,%4,4),%%xmm1 \n" >+ "paddd 0x20(%1,%4,4),%%xmm2 \n" >+ "paddd 0x30(%1,%4,4),%%xmm3 \n" >+ "lea 0x40(%1),%1 \n" >+ "packssdw %%xmm1,%%xmm0 \n" >+ "packssdw %%xmm3,%%xmm2 \n" >+ "pmulhuw %%xmm5,%%xmm0 \n" >+ "pmulhuw %%xmm5,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jge 4b \n" >+ "jmp 49f \n" >+ >+ // 4 pixel loop >+ LABELALIGN >+ "40: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x20(%0),%%xmm2 \n" >+ "movdqu 0x30(%0),%%xmm3 \n" >+ "psubd 0x00(%0,%4,4),%%xmm0 \n" >+ "psubd 0x10(%0,%4,4),%%xmm1 \n" >+ "psubd 0x20(%0,%4,4),%%xmm2 \n" >+ "psubd 0x30(%0,%4,4),%%xmm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "psubd (%1),%%xmm0 \n" >+ "psubd 0x10(%1),%%xmm1 \n" >+ "psubd 0x20(%1),%%xmm2 \n" >+ "psubd 0x30(%1),%%xmm3 \n" >+ "paddd 0x00(%1,%4,4),%%xmm0 \n" >+ "paddd 0x10(%1,%4,4),%%xmm1 \n" >+ "paddd 0x20(%1,%4,4),%%xmm2 \n" >+ "paddd 0x30(%1,%4,4),%%xmm3 \n" >+ "lea 0x40(%1),%1 \n" >+ "cvtdq2ps %%xmm0,%%xmm0 \n" >+ "cvtdq2ps %%xmm1,%%xmm1 \n" >+ "mulps %%xmm4,%%xmm0 \n" >+ "mulps %%xmm4,%%xmm1 \n" >+ "cvtdq2ps %%xmm2,%%xmm2 \n" >+ "cvtdq2ps %%xmm3,%%xmm3 \n" >+ "mulps %%xmm4,%%xmm2 \n" >+ "mulps %%xmm4,%%xmm3 \n" >+ "cvtps2dq %%xmm0,%%xmm0 \n" >+ "cvtps2dq %%xmm1,%%xmm1 \n" >+ "cvtps2dq %%xmm2,%%xmm2 \n" >+ "cvtps2dq %%xmm3,%%xmm3 \n" >+ "packssdw %%xmm1,%%xmm0 \n" >+ "packssdw %%xmm3,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jge 40b \n" >+ >+ "49: \n" >+ "add $0x3,%3 \n" >+ "jl 19f \n" >+ >+ // 1 pixel loop >+ LABELALIGN >+ "10: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "psubd 0x00(%0,%4,4),%%xmm0 \n" >+ "lea 0x10(%0),%0 \n" >+ "psubd (%1),%%xmm0 \n" >+ "paddd 0x00(%1,%4,4),%%xmm0 \n" >+ "lea 0x10(%1),%1 \n" >+ "cvtdq2ps %%xmm0,%%xmm0 \n" >+ "mulps %%xmm4,%%xmm0 \n" >+ "cvtps2dq %%xmm0,%%xmm0 \n" >+ "packssdw %%xmm0,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movd %%xmm0,(%2) \n" >+ "lea 0x4(%2),%2 \n" >+ "sub $0x1,%3 \n" >+ "jge 10b \n" >+ "19: \n" >+ : "+r"(topleft), // %0 >+ "+r"(botleft), // %1 >+ "+r"(dst), // %2 >+ "+rm"(count) // %3 >+ : "r"((intptr_t)(width)), // %4 >+ "rm"(area) // %5 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 > > #ifdef HAS_ARGBAFFINEROW_SSE2 > // Copy ARGB pixels from source image with slope to a row of destination. > LIBYUV_API >-void ARGBAffineRow_SSE2(const uint8* src_argb, >+void ARGBAffineRow_SSE2(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* src_dudv, > int width) { > intptr_t src_argb_stride_temp = src_argb_stride; > intptr_t temp; >- asm volatile ( >- "movq " MEMACCESS(3) ",%%xmm2 \n" >- "movq " MEMACCESS2(0x08,3) ",%%xmm7 \n" >- "shl $0x10,%1 \n" >- "add $0x4,%1 \n" >- "movd %1,%%xmm5 \n" >- "sub $0x4,%4 \n" >- "jl 49f \n" >- >- "pshufd $0x44,%%xmm7,%%xmm7 \n" >- "pshufd $0x0,%%xmm5,%%xmm5 \n" >- "movdqa %%xmm2,%%xmm0 \n" >- "addps %%xmm7,%%xmm0 \n" >- "movlhps %%xmm0,%%xmm2 \n" >- "movdqa %%xmm7,%%xmm4 \n" >- "addps %%xmm4,%%xmm4 \n" >- "movdqa %%xmm2,%%xmm3 \n" >- "addps %%xmm4,%%xmm3 \n" >- "addps %%xmm4,%%xmm4 \n" >- >- // 4 pixel loop \n" >- LABELALIGN >- "40: \n" >- "cvttps2dq %%xmm2,%%xmm0 \n" // x, y float to int first 2 >- "cvttps2dq %%xmm3,%%xmm1 \n" // x, y float to int next 2 >- "packssdw %%xmm1,%%xmm0 \n" // x, y as 8 shorts >- "pmaddwd %%xmm5,%%xmm0 \n" // off = x * 4 + y * stride >- "movd %%xmm0,%k1 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- "movd %%xmm0,%k5 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1 >- MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6 >- "punpckldq %%xmm6,%%xmm1 \n" >- "addps %%xmm4,%%xmm2 \n" >- "movq %%xmm1," MEMACCESS(2) " \n" >- "movd %%xmm0,%k1 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- "movd %%xmm0,%k5 \n" >- MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0 >- MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6 >- "punpckldq %%xmm6,%%xmm0 \n" >- "addps %%xmm4,%%xmm3 \n" >- "movq %%xmm0," MEMACCESS2(0x08,2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%4 \n" >- "jge 40b \n" >- >- "49: \n" >- "add $0x3,%4 \n" >- "jl 19f \n" >- >- // 1 pixel loop \n" >- LABELALIGN >- "10: \n" >- "cvttps2dq %%xmm2,%%xmm0 \n" >- "packssdw %%xmm0,%%xmm0 \n" >- "pmaddwd %%xmm5,%%xmm0 \n" >- "addps %%xmm7,%%xmm2 \n" >- "movd %%xmm0,%k1 \n" >- MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0 >- "movd %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x04,2) ",%2 \n" >- "sub $0x1,%4 \n" >- "jge 10b \n" >- "19: \n" >- : "+r"(src_argb), // %0 >- "+r"(src_argb_stride_temp), // %1 >- "+r"(dst_argb), // %2 >- "+r"(src_dudv), // %3 >- "+rm"(width), // %4 >- "=&r"(temp) // %5 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ "movq (%3),%%xmm2 \n" >+ "movq 0x08(%3),%%xmm7 \n" >+ "shl $0x10,%1 \n" >+ "add $0x4,%1 \n" >+ "movd %1,%%xmm5 \n" >+ "sub $0x4,%4 \n" >+ "jl 49f \n" >+ >+ "pshufd $0x44,%%xmm7,%%xmm7 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "movdqa %%xmm2,%%xmm0 \n" >+ "addps %%xmm7,%%xmm0 \n" >+ "movlhps %%xmm0,%%xmm2 \n" >+ "movdqa %%xmm7,%%xmm4 \n" >+ "addps %%xmm4,%%xmm4 \n" >+ "movdqa %%xmm2,%%xmm3 \n" >+ "addps %%xmm4,%%xmm3 \n" >+ "addps %%xmm4,%%xmm4 \n" >+ >+ // 4 pixel loop >+ LABELALIGN >+ "40: \n" >+ "cvttps2dq %%xmm2,%%xmm0 \n" // x,y float->int first 2 >+ "cvttps2dq %%xmm3,%%xmm1 \n" // x,y float->int next 2 >+ "packssdw %%xmm1,%%xmm0 \n" // x, y as 8 shorts >+ "pmaddwd %%xmm5,%%xmm0 \n" // off = x*4 + y*stride >+ "movd %%xmm0,%k1 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ "movd %%xmm0,%k5 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ "movd 0x00(%0,%1,1),%%xmm1 \n" >+ "movd 0x00(%0,%5,1),%%xmm6 \n" >+ "punpckldq %%xmm6,%%xmm1 \n" >+ "addps %%xmm4,%%xmm2 \n" >+ "movq %%xmm1,(%2) \n" >+ "movd %%xmm0,%k1 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ "movd %%xmm0,%k5 \n" >+ "movd 0x00(%0,%1,1),%%xmm0 \n" >+ "movd 0x00(%0,%5,1),%%xmm6 \n" >+ "punpckldq %%xmm6,%%xmm0 \n" >+ "addps %%xmm4,%%xmm3 \n" >+ "movq %%xmm0,0x08(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%4 \n" >+ "jge 40b \n" >+ >+ "49: \n" >+ "add $0x3,%4 \n" >+ "jl 19f \n" >+ >+ // 1 pixel loop >+ LABELALIGN >+ "10: \n" >+ "cvttps2dq %%xmm2,%%xmm0 \n" >+ "packssdw %%xmm0,%%xmm0 \n" >+ "pmaddwd %%xmm5,%%xmm0 \n" >+ "addps %%xmm7,%%xmm2 \n" >+ "movd %%xmm0,%k1 \n" >+ "movd 0x00(%0,%1,1),%%xmm0 \n" >+ "movd %%xmm0,(%2) \n" >+ "lea 0x04(%2),%2 \n" >+ "sub $0x1,%4 \n" >+ "jge 10b \n" >+ "19: \n" >+ : "+r"(src_argb), // %0 >+ "+r"(src_argb_stride_temp), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(src_dudv), // %3 >+ "+rm"(width), // %4 >+ "=&r"(temp) // %5 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBAFFINEROW_SSE2 > > #ifdef HAS_INTERPOLATEROW_SSSE3 > // Bilinear filter 16x2 -> 16x1 >-void InterpolateRow_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >- asm volatile ( >- "sub %1,%0 \n" >- "cmp $0x0,%3 \n" >- "je 100f \n" >- "cmp $0x80,%3 \n" >- "je 50f \n" >- >- "movd %3,%%xmm0 \n" >- "neg %3 \n" >- "add $0x100,%3 \n" >- "movd %3,%%xmm5 \n" >- "punpcklbw %%xmm0,%%xmm5 \n" >- "punpcklwd %%xmm5,%%xmm5 \n" >- "pshufd $0x0,%%xmm5,%%xmm5 \n" >- "mov $0x80808080,%%eax \n" >- "movd %%eax,%%xmm4 \n" >- "pshufd $0x0,%%xmm4,%%xmm4 \n" >- >- // General purpose row blend. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,1,4,1,xmm2) >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm2,%%xmm0 \n" >- "punpckhbw %%xmm2,%%xmm1 \n" >- "psubb %%xmm4,%%xmm0 \n" >- "psubb %%xmm4,%%xmm1 \n" >- "movdqa %%xmm5,%%xmm2 \n" >- "movdqa %%xmm5,%%xmm3 \n" >- "pmaddubsw %%xmm0,%%xmm2 \n" >- "pmaddubsw %%xmm1,%%xmm3 \n" >- "paddw %%xmm4,%%xmm2 \n" >- "paddw %%xmm4,%%xmm3 \n" >- "psrlw $0x8,%%xmm2 \n" >- "psrlw $0x8,%%xmm3 \n" >- "packuswb %%xmm3,%%xmm2 \n" >- MEMOPMEM(movdqu,xmm2,0x00,1,0,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "jmp 99f \n" >+ asm volatile( >+ "sub %1,%0 \n" >+ "cmp $0x0,%3 \n" >+ "je 100f \n" >+ "cmp $0x80,%3 \n" >+ "je 50f \n" >+ >+ "movd %3,%%xmm0 \n" >+ "neg %3 \n" >+ "add $0x100,%3 \n" >+ "movd %3,%%xmm5 \n" >+ "punpcklbw %%xmm0,%%xmm5 \n" >+ "punpcklwd %%xmm5,%%xmm5 \n" >+ "pshufd $0x0,%%xmm5,%%xmm5 \n" >+ "mov $0x80808080,%%eax \n" >+ "movd %%eax,%%xmm4 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ >+ // General purpose row blend. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%1),%%xmm0 \n" >+ "movdqu 0x00(%1,%4,1),%%xmm2 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm2,%%xmm0 \n" >+ "punpckhbw %%xmm2,%%xmm1 \n" >+ "psubb %%xmm4,%%xmm0 \n" >+ "psubb %%xmm4,%%xmm1 \n" >+ "movdqa %%xmm5,%%xmm2 \n" >+ "movdqa %%xmm5,%%xmm3 \n" >+ "pmaddubsw %%xmm0,%%xmm2 \n" >+ "pmaddubsw %%xmm1,%%xmm3 \n" >+ "paddw %%xmm4,%%xmm2 \n" >+ "paddw %%xmm4,%%xmm3 \n" >+ "psrlw $0x8,%%xmm2 \n" >+ "psrlw $0x8,%%xmm3 \n" >+ "packuswb %%xmm3,%%xmm2 \n" >+ "movdqu %%xmm2,0x00(%1,%0,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "jmp 99f \n" > >- // Blend 50 / 50. >- LABELALIGN >- "50: \n" >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,1,4,1,xmm1) >- "pavgb %%xmm1,%%xmm0 \n" >- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 50b \n" >- "jmp 99f \n" >- >- // Blend 100 / 0 - Copy row unchanged. >- LABELALIGN >- "100: \n" >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 100b \n" >- >- "99: \n" >- : "+r"(dst_ptr), // %0 >- "+r"(src_ptr), // %1 >- "+rm"(dst_width), // %2 >- "+r"(source_y_fraction) // %3 >- : "r"((intptr_t)(src_stride)) // %4 >- : "memory", "cc", "eax", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ // Blend 50 / 50. >+ LABELALIGN >+ "50: \n" >+ "movdqu (%1),%%xmm0 \n" >+ "movdqu 0x00(%1,%4,1),%%xmm1 \n" >+ "pavgb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,0x00(%1,%0,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 50b \n" >+ "jmp 99f \n" >+ >+ // Blend 100 / 0 - Copy row unchanged. >+ LABELALIGN >+ "100: \n" >+ "movdqu (%1),%%xmm0 \n" >+ "movdqu %%xmm0,0x00(%1,%0,1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 100b \n" >+ >+ "99: \n" >+ : "+r"(dst_ptr), // %0 >+ "+r"(src_ptr), // %1 >+ "+rm"(dst_width), // %2 >+ "+r"(source_y_fraction) // %3 >+ : "r"((intptr_t)(src_stride)) // %4 >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_INTERPOLATEROW_SSSE3 > > #ifdef HAS_INTERPOLATEROW_AVX2 > // Bilinear filter 32x2 -> 32x1 >-void InterpolateRow_AVX2(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_AVX2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >- asm volatile ( >- "cmp $0x0,%3 \n" >- "je 100f \n" >- "sub %1,%0 \n" >- "cmp $0x80,%3 \n" >- "je 50f \n" >- >- "vmovd %3,%%xmm0 \n" >- "neg %3 \n" >- "add $0x100,%3 \n" >- "vmovd %3,%%xmm5 \n" >- "vpunpcklbw %%xmm0,%%xmm5,%%xmm5 \n" >- "vpunpcklwd %%xmm5,%%xmm5,%%xmm5 \n" >- "vbroadcastss %%xmm5,%%ymm5 \n" >- "mov $0x80808080,%%eax \n" >- "vmovd %%eax,%%xmm4 \n" >- "vbroadcastss %%xmm4,%%ymm4 \n" >- >- // General purpose row blend. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(1) ",%%ymm0 \n" >- MEMOPREG(vmovdqu,0x00,1,4,1,ymm2) >- "vpunpckhbw %%ymm2,%%ymm0,%%ymm1 \n" >- "vpunpcklbw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpsubb %%ymm4,%%ymm1,%%ymm1 \n" >- "vpsubb %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm1,%%ymm5,%%ymm1 \n" >- "vpmaddubsw %%ymm0,%%ymm5,%%ymm0 \n" >- "vpaddw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpaddw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- MEMOPMEM(vmovdqu,ymm0,0x00,1,0,1) >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "jmp 99f \n" >+ asm volatile( >+ "cmp $0x0,%3 \n" >+ "je 100f \n" >+ "sub %1,%0 \n" >+ "cmp $0x80,%3 \n" >+ "je 50f \n" >+ >+ "vmovd %3,%%xmm0 \n" >+ "neg %3 \n" >+ "add $0x100,%3 \n" >+ "vmovd %3,%%xmm5 \n" >+ "vpunpcklbw %%xmm0,%%xmm5,%%xmm5 \n" >+ "vpunpcklwd %%xmm5,%%xmm5,%%xmm5 \n" >+ "vbroadcastss %%xmm5,%%ymm5 \n" >+ "mov $0x80808080,%%eax \n" >+ "vmovd %%eax,%%xmm4 \n" >+ "vbroadcastss %%xmm4,%%ymm4 \n" > >- // Blend 50 / 50. >- LABELALIGN >- "50: \n" >- "vmovdqu " MEMACCESS(1) ",%%ymm0 \n" >- VMEMOPREG(vpavgb,0x00,1,4,1,ymm0,ymm0) // vpavgb (%1,%4,1),%%ymm0,%%ymm0 >- MEMOPMEM(vmovdqu,ymm0,0x00,1,0,1) >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 50b \n" >- "jmp 99f \n" >+ // General purpose row blend. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%1),%%ymm0 \n" >+ "vmovdqu 0x00(%1,%4,1),%%ymm2 \n" >+ "vpunpckhbw %%ymm2,%%ymm0,%%ymm1 \n" >+ "vpunpcklbw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpsubb %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpsubb %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm1,%%ymm5,%%ymm1 \n" >+ "vpmaddubsw %%ymm0,%%ymm5,%%ymm0 \n" >+ "vpaddw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpaddw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,0x00(%1,%0,1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "jmp 99f \n" > >- // Blend 100 / 0 - Copy row unchanged. >- LABELALIGN >- "100: \n" >- "rep movsb " MEMMOVESTRING(1,0) " \n" >- "jmp 999f \n" >+ // Blend 50 / 50. >+ LABELALIGN >+ "50: \n" >+ "vmovdqu (%1),%%ymm0 \n" >+ "vpavgb 0x00(%1,%4,1),%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,0x00(%1,%0,1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 50b \n" >+ "jmp 99f \n" >+ >+ // Blend 100 / 0 - Copy row unchanged. >+ LABELALIGN >+ "100: \n" >+ "rep movsb \n" >+ "jmp 999f \n" > >- "99: \n" >- "vzeroupper \n" >- "999: \n" >- : "+D"(dst_ptr), // %0 >- "+S"(src_ptr), // %1 >- "+cm"(dst_width), // %2 >- "+r"(source_y_fraction) // %3 >- : "r"((intptr_t)(src_stride)) // %4 >- : "memory", "cc", "eax", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm4", "xmm5" >- ); >+ "99: \n" >+ "vzeroupper \n" >+ "999: \n" >+ : "+D"(dst_ptr), // %0 >+ "+S"(src_ptr), // %1 >+ "+cm"(dst_width), // %2 >+ "+r"(source_y_fraction) // %3 >+ : "r"((intptr_t)(src_stride)) // %4 >+ : "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm4", "xmm5"); > } > #endif // HAS_INTERPOLATEROW_AVX2 > > #ifdef HAS_ARGBSHUFFLEROW_SSSE3 > // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-void ARGBShuffleRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { >- asm volatile ( >- "movdqu " MEMACCESS(3) ",%%xmm5 \n" >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pshufb %%xmm5,%%xmm0 \n" >- "pshufb %%xmm5,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(shuffler) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm5" >- ); >+ asm volatile( >+ >+ "movdqu (%3),%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pshufb %%xmm5,%%xmm0 \n" >+ "pshufb %%xmm5,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(shuffler) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > #endif // HAS_ARGBSHUFFLEROW_SSSE3 > > #ifdef HAS_ARGBSHUFFLEROW_AVX2 > // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-void ARGBShuffleRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { >- asm volatile ( >- "vbroadcastf128 " MEMACCESS(3) ",%%ymm5 \n" >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" >- "vpshufb %%ymm5,%%ymm1,%%ymm1 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(shuffler) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm5" >- ); >+ asm volatile( >+ >+ "vbroadcastf128 (%3),%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpshufb %%ymm5,%%ymm1,%%ymm1 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm1,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(shuffler) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm5"); > } > #endif // HAS_ARGBSHUFFLEROW_AVX2 > >-#ifdef HAS_ARGBSHUFFLEROW_SSE2 >-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-void ARGBShuffleRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >- int width) { >- uintptr_t pixel_temp; >- asm volatile ( >- "pxor %%xmm5,%%xmm5 \n" >- "mov " MEMACCESS(4) ",%k2 \n" >- "cmp $0x3000102,%k2 \n" >- "je 3012f \n" >- "cmp $0x10203,%k2 \n" >- "je 123f \n" >- "cmp $0x30201,%k2 \n" >- "je 321f \n" >- "cmp $0x2010003,%k2 \n" >- "je 2103f \n" >+#ifdef HAS_I422TOYUY2ROW_SSE2 >+void I422ToYUY2Row_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, >+ int width) { >+ asm volatile( > >- LABELALIGN >- "1: \n" >- "movzb " MEMACCESS(4) ",%2 \n" >- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 >- "mov %b2," MEMACCESS(1) " \n" >- "movzb " MEMACCESS2(0x1,4) ",%2 \n" >- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 >- "mov %b2," MEMACCESS2(0x1,1) " \n" >- "movzb " MEMACCESS2(0x2,4) ",%2 \n" >- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 >- "mov %b2," MEMACCESS2(0x2,1) " \n" >- "movzb " MEMACCESS2(0x3,4) ",%2 \n" >- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 >- "mov %b2," MEMACCESS2(0x3,1) " \n" >- "lea " MEMLEA(0x4,0) ",%0 \n" >- "lea " MEMLEA(0x4,1) ",%1 \n" >- "sub $0x1,%3 \n" >- "jg 1b \n" >- "jmp 99f \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "123: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpckhbw %%xmm5,%%xmm1 \n" >- "pshufhw $0x1b,%%xmm0,%%xmm0 \n" >- "pshuflw $0x1b,%%xmm0,%%xmm0 \n" >- "pshufhw $0x1b,%%xmm1,%%xmm1 \n" >- "pshuflw $0x1b,%%xmm1,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%3 \n" >- "jg 123b \n" >- "jmp 99f \n" >+ LABELALIGN >+ "1: \n" >+ "movq (%1),%%xmm2 \n" >+ "movq 0x00(%1,%2,1),%%xmm1 \n" >+ "add $0x8,%1 \n" >+ "punpcklbw %%xmm1,%%xmm2 \n" >+ "movdqu (%0),%%xmm0 \n" >+ "add $0x10,%0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm2,%%xmm0 \n" >+ "punpckhbw %%xmm2,%%xmm1 \n" >+ "movdqu %%xmm0,(%3) \n" >+ "movdqu %%xmm1,0x10(%3) \n" >+ "lea 0x20(%3),%3 \n" >+ "sub $0x10,%4 \n" >+ "jg 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_u), // %1 >+ "+r"(src_v), // %2 >+ "+r"(dst_yuy2), // %3 >+ "+rm"(width) // %4 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); >+} >+#endif // HAS_I422TOYUY2ROW_SSE2 > >- LABELALIGN >- "321: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpckhbw %%xmm5,%%xmm1 \n" >- "pshufhw $0x39,%%xmm0,%%xmm0 \n" >- "pshuflw $0x39,%%xmm0,%%xmm0 \n" >- "pshufhw $0x39,%%xmm1,%%xmm1 \n" >- "pshuflw $0x39,%%xmm1,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%3 \n" >- "jg 321b \n" >- "jmp 99f \n" >+#ifdef HAS_I422TOUYVYROW_SSE2 >+void I422ToUYVYRow_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, >+ int width) { >+ asm volatile( > >- LABELALIGN >- "2103: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpckhbw %%xmm5,%%xmm1 \n" >- "pshufhw $0x93,%%xmm0,%%xmm0 \n" >- "pshuflw $0x93,%%xmm0,%%xmm0 \n" >- "pshufhw $0x93,%%xmm1,%%xmm1 \n" >- "pshuflw $0x93,%%xmm1,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%3 \n" >- "jg 2103b \n" >- "jmp 99f \n" >+ "sub %1,%2 \n" > >- LABELALIGN >- "3012: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpckhbw %%xmm5,%%xmm1 \n" >- "pshufhw $0xc6,%%xmm0,%%xmm0 \n" >- "pshuflw $0xc6,%%xmm0,%%xmm0 \n" >- "pshufhw $0xc6,%%xmm1,%%xmm1 \n" >- "pshuflw $0xc6,%%xmm1,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%3 \n" >- "jg 3012b \n" >- >- "99: \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "=&d"(pixel_temp), // %2 >- "+r"(width) // %3 >- : "r"(shuffler) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm5" >- ); >+ LABELALIGN >+ "1: \n" >+ "movq (%1),%%xmm2 \n" >+ "movq 0x00(%1,%2,1),%%xmm1 \n" >+ "add $0x8,%1 \n" >+ "punpcklbw %%xmm1,%%xmm2 \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqa %%xmm2,%%xmm1 \n" >+ "add $0x10,%0 \n" >+ "punpcklbw %%xmm0,%%xmm1 \n" >+ "punpckhbw %%xmm0,%%xmm2 \n" >+ "movdqu %%xmm1,(%3) \n" >+ "movdqu %%xmm2,0x10(%3) \n" >+ "lea 0x20(%3),%3 \n" >+ "sub $0x10,%4 \n" >+ "jg 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_u), // %1 >+ "+r"(src_v), // %2 >+ "+r"(dst_uyvy), // %3 >+ "+rm"(width) // %4 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } >-#endif // HAS_ARGBSHUFFLEROW_SSE2 >+#endif // HAS_I422TOUYVYROW_SSE2 > >-#ifdef HAS_I422TOYUY2ROW_SSE2 >-void I422ToYUY2Row_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+#ifdef HAS_I422TOYUY2ROW_AVX2 >+void I422ToYUY2Row_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width) { >- asm volatile ( >- "sub %1,%2 \n" >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(1) ",%%xmm2 \n" >- MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3 >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "punpcklbw %%xmm3,%%xmm2 \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm2,%%xmm0 \n" >- "punpckhbw %%xmm2,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(3) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,3) " \n" >- "lea " MEMLEA(0x20,3) ",%3 \n" >- "sub $0x10,%4 \n" >- "jg 1b \n" >- : "+r"(src_y), // %0 >- "+r"(src_u), // %1 >- "+r"(src_v), // %2 >- "+r"(dst_frame), // %3 >- "+rm"(width) // %4 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3" >- ); >+ asm volatile( >+ >+ "sub %1,%2 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vpmovzxbw (%1),%%ymm1 \n" >+ "vpmovzxbw 0x00(%1,%2,1),%%ymm2 \n" >+ "add $0x10,%1 \n" >+ "vpsllw $0x8,%%ymm2,%%ymm2 \n" >+ "vpor %%ymm1,%%ymm2,%%ymm2 \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "add $0x20,%0 \n" >+ "vpunpcklbw %%ymm2,%%ymm0,%%ymm1 \n" >+ "vpunpckhbw %%ymm2,%%ymm0,%%ymm2 \n" >+ "vextractf128 $0x0,%%ymm1,(%3) \n" >+ "vextractf128 $0x0,%%ymm2,0x10(%3) \n" >+ "vextractf128 $0x1,%%ymm1,0x20(%3) \n" >+ "vextractf128 $0x1,%%ymm2,0x30(%3) \n" >+ "lea 0x40(%3),%3 \n" >+ "sub $0x20,%4 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_u), // %1 >+ "+r"(src_v), // %2 >+ "+r"(dst_yuy2), // %3 >+ "+rm"(width) // %4 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } >-#endif // HAS_I422TOYUY2ROW_SSE2 >+#endif // HAS_I422TOYUY2ROW_AVX2 > >-#ifdef HAS_I422TOUYVYROW_SSE2 >-void I422ToUYVYRow_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+#ifdef HAS_I422TOUYVYROW_AVX2 >+void I422ToUYVYRow_AVX2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width) { >- asm volatile ( >- "sub %1,%2 \n" >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(1) ",%%xmm2 \n" >- MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3 >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "punpcklbw %%xmm3,%%xmm2 \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqa %%xmm2,%%xmm1 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "punpcklbw %%xmm0,%%xmm1 \n" >- "punpckhbw %%xmm0,%%xmm2 \n" >- "movdqu %%xmm1," MEMACCESS(3) " \n" >- "movdqu %%xmm2," MEMACCESS2(0x10,3) " \n" >- "lea " MEMLEA(0x20,3) ",%3 \n" >- "sub $0x10,%4 \n" >- "jg 1b \n" >- : "+r"(src_y), // %0 >- "+r"(src_u), // %1 >- "+r"(src_v), // %2 >- "+r"(dst_frame), // %3 >- "+rm"(width) // %4 >- : >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3" >- ); >+ asm volatile( >+ >+ "sub %1,%2 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vpmovzxbw (%1),%%ymm1 \n" >+ "vpmovzxbw 0x00(%1,%2,1),%%ymm2 \n" >+ "add $0x10,%1 \n" >+ "vpsllw $0x8,%%ymm2,%%ymm2 \n" >+ "vpor %%ymm1,%%ymm2,%%ymm2 \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "add $0x20,%0 \n" >+ "vpunpcklbw %%ymm0,%%ymm2,%%ymm1 \n" >+ "vpunpckhbw %%ymm0,%%ymm2,%%ymm2 \n" >+ "vextractf128 $0x0,%%ymm1,(%3) \n" >+ "vextractf128 $0x0,%%ymm2,0x10(%3) \n" >+ "vextractf128 $0x1,%%ymm1,0x20(%3) \n" >+ "vextractf128 $0x1,%%ymm2,0x30(%3) \n" >+ "lea 0x40(%3),%3 \n" >+ "sub $0x20,%4 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_u), // %1 >+ "+r"(src_v), // %2 >+ "+r"(dst_uyvy), // %3 >+ "+rm"(width) // %4 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2"); > } >-#endif // HAS_I422TOUYVYROW_SSE2 >+#endif // HAS_I422TOUYVYROW_AVX2 > > #ifdef HAS_ARGBPOLYNOMIALROW_SSE2 >-void ARGBPolynomialRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width) { >- asm volatile ( >- "pxor %%xmm3,%%xmm3 \n" >+ asm volatile( > >- // 2 pixel loop. >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "punpcklbw %%xmm3,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm4 \n" >- "punpcklwd %%xmm3,%%xmm0 \n" >- "punpckhwd %%xmm3,%%xmm4 \n" >- "cvtdq2ps %%xmm0,%%xmm0 \n" >- "cvtdq2ps %%xmm4,%%xmm4 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "movdqa %%xmm4,%%xmm5 \n" >- "mulps " MEMACCESS2(0x10,3) ",%%xmm0 \n" >- "mulps " MEMACCESS2(0x10,3) ",%%xmm4 \n" >- "addps " MEMACCESS(3) ",%%xmm0 \n" >- "addps " MEMACCESS(3) ",%%xmm4 \n" >- "movdqa %%xmm1,%%xmm2 \n" >- "movdqa %%xmm5,%%xmm6 \n" >- "mulps %%xmm1,%%xmm2 \n" >- "mulps %%xmm5,%%xmm6 \n" >- "mulps %%xmm2,%%xmm1 \n" >- "mulps %%xmm6,%%xmm5 \n" >- "mulps " MEMACCESS2(0x20,3) ",%%xmm2 \n" >- "mulps " MEMACCESS2(0x20,3) ",%%xmm6 \n" >- "mulps " MEMACCESS2(0x30,3) ",%%xmm1 \n" >- "mulps " MEMACCESS2(0x30,3) ",%%xmm5 \n" >- "addps %%xmm2,%%xmm0 \n" >- "addps %%xmm6,%%xmm4 \n" >- "addps %%xmm1,%%xmm0 \n" >- "addps %%xmm5,%%xmm4 \n" >- "cvttps2dq %%xmm0,%%xmm0 \n" >- "cvttps2dq %%xmm4,%%xmm4 \n" >- "packuswb %%xmm4,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x2,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(poly) // %3 >- : "memory", "cc" >- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ "pxor %%xmm3,%%xmm3 \n" >+ >+ // 2 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm0 \n" >+ "lea 0x8(%0),%0 \n" >+ "punpcklbw %%xmm3,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm4 \n" >+ "punpcklwd %%xmm3,%%xmm0 \n" >+ "punpckhwd %%xmm3,%%xmm4 \n" >+ "cvtdq2ps %%xmm0,%%xmm0 \n" >+ "cvtdq2ps %%xmm4,%%xmm4 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "movdqa %%xmm4,%%xmm5 \n" >+ "mulps 0x10(%3),%%xmm0 \n" >+ "mulps 0x10(%3),%%xmm4 \n" >+ "addps (%3),%%xmm0 \n" >+ "addps (%3),%%xmm4 \n" >+ "movdqa %%xmm1,%%xmm2 \n" >+ "movdqa %%xmm5,%%xmm6 \n" >+ "mulps %%xmm1,%%xmm2 \n" >+ "mulps %%xmm5,%%xmm6 \n" >+ "mulps %%xmm2,%%xmm1 \n" >+ "mulps %%xmm6,%%xmm5 \n" >+ "mulps 0x20(%3),%%xmm2 \n" >+ "mulps 0x20(%3),%%xmm6 \n" >+ "mulps 0x30(%3),%%xmm1 \n" >+ "mulps 0x30(%3),%%xmm5 \n" >+ "addps %%xmm2,%%xmm0 \n" >+ "addps %%xmm6,%%xmm4 \n" >+ "addps %%xmm1,%%xmm0 \n" >+ "addps %%xmm5,%%xmm4 \n" >+ "cvttps2dq %%xmm0,%%xmm0 \n" >+ "cvttps2dq %%xmm4,%%xmm4 \n" >+ "packuswb %%xmm4,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x2,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(poly) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > #endif // HAS_ARGBPOLYNOMIALROW_SSE2 > > #ifdef HAS_ARGBPOLYNOMIALROW_AVX2 >-void ARGBPolynomialRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBPolynomialRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width) { >- asm volatile ( >- "vbroadcastf128 " MEMACCESS(3) ",%%ymm4 \n" >- "vbroadcastf128 " MEMACCESS2(0x10,3) ",%%ymm5 \n" >- "vbroadcastf128 " MEMACCESS2(0x20,3) ",%%ymm6 \n" >- "vbroadcastf128 " MEMACCESS2(0x30,3) ",%%ymm7 \n" >+ asm volatile( >+ "vbroadcastf128 (%3),%%ymm4 \n" >+ "vbroadcastf128 0x10(%3),%%ymm5 \n" >+ "vbroadcastf128 0x20(%3),%%ymm6 \n" >+ "vbroadcastf128 0x30(%3),%%ymm7 \n" > >- // 2 pixel loop. >- LABELALIGN >- "1: \n" >- "vpmovzxbd " MEMACCESS(0) ",%%ymm0 \n" // 2 ARGB pixels >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "vcvtdq2ps %%ymm0,%%ymm0 \n" // X 8 floats >- "vmulps %%ymm0,%%ymm0,%%ymm2 \n" // X * X >- "vmulps %%ymm7,%%ymm0,%%ymm3 \n" // C3 * X >- "vfmadd132ps %%ymm5,%%ymm4,%%ymm0 \n" // result = C0 + C1 * X >- "vfmadd231ps %%ymm6,%%ymm2,%%ymm0 \n" // result += C2 * X * X >- "vfmadd231ps %%ymm3,%%ymm2,%%ymm0 \n" // result += C3 * X * X * X >- "vcvttps2dq %%ymm0,%%ymm0 \n" >- "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%xmm0,%%xmm0,%%xmm0 \n" >- "vmovq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x2,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(width) // %2 >- : "r"(poly) // %3 >- : "memory", "cc", >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ // 2 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vpmovzxbd (%0),%%ymm0 \n" // 2 ARGB pixels >+ "lea 0x8(%0),%0 \n" >+ "vcvtdq2ps %%ymm0,%%ymm0 \n" // X 8 floats >+ "vmulps %%ymm0,%%ymm0,%%ymm2 \n" // X * X >+ "vmulps %%ymm7,%%ymm0,%%ymm3 \n" // C3 * X >+ "vfmadd132ps %%ymm5,%%ymm4,%%ymm0 \n" // result = C0 + C1 * X >+ "vfmadd231ps %%ymm6,%%ymm2,%%ymm0 \n" // result += C2 * X * X >+ "vfmadd231ps %%ymm3,%%ymm2,%%ymm0 \n" // result += C3 * X * X * >+ // X >+ "vcvttps2dq %%ymm0,%%ymm0 \n" >+ "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%xmm0,%%xmm0,%%xmm0 \n" >+ "vmovq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x2,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(width) // %2 >+ : "r"(poly) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > #endif // HAS_ARGBPOLYNOMIALROW_AVX2 > > #ifdef HAS_HALFFLOATROW_SSE2 > static float kScaleBias = 1.9259299444e-34f; >-void HalfFloatRow_SSE2(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_SSE2(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > scale *= kScaleBias; >- asm volatile ( >- "pshufd $0x0,%3,%%xmm4 \n" >- "pxor %%xmm5,%%xmm5 \n" >- "sub %0,%1 \n" >+ asm volatile( >+ "movd %3,%%xmm4 \n" >+ "pshufd $0x0,%%xmm4,%%xmm4 \n" >+ "pxor %%xmm5,%%xmm5 \n" >+ "sub %0,%1 \n" > >- // 16 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm2 \n" // 8 shorts >- "add $0x10,%0 \n" >- "movdqa %%xmm2,%%xmm3 \n" >- "punpcklwd %%xmm5,%%xmm2 \n" // 8 ints in xmm2/1 >- "cvtdq2ps %%xmm2,%%xmm2 \n" // 8 floats >- "punpckhwd %%xmm5,%%xmm3 \n" >- "cvtdq2ps %%xmm3,%%xmm3 \n" >- "mulps %%xmm4,%%xmm2 \n" >- "mulps %%xmm4,%%xmm3 \n" >- "psrld $0xd,%%xmm2 \n" >- "psrld $0xd,%%xmm3 \n" >- "packssdw %%xmm3,%%xmm2 \n" >- MEMOPMEM(movdqu,xmm2,-0x10,0,1,1) >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >-#if defined(__x86_64__) >- : "x"(scale) // %3 >-#else >- : "m"(scale) // %3 >-#endif >- : "memory", "cc", >- "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm2 \n" // 8 shorts >+ "add $0x10,%0 \n" >+ "movdqa %%xmm2,%%xmm3 \n" >+ "punpcklwd %%xmm5,%%xmm2 \n" // 8 ints in xmm2/1 >+ "cvtdq2ps %%xmm2,%%xmm2 \n" // 8 floats >+ "punpckhwd %%xmm5,%%xmm3 \n" >+ "cvtdq2ps %%xmm3,%%xmm3 \n" >+ "mulps %%xmm4,%%xmm2 \n" >+ "mulps %%xmm4,%%xmm3 \n" >+ "psrld $0xd,%%xmm2 \n" >+ "psrld $0xd,%%xmm3 \n" >+ "packssdw %%xmm3,%%xmm2 \n" >+ "movdqu %%xmm2,-0x10(%0,%1,1) \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "m"(scale) // %3 >+ : "memory", "cc", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_HALFFLOATROW_SSE2 > > #ifdef HAS_HALFFLOATROW_AVX2 >-void HalfFloatRow_AVX2(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_AVX2(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > scale *= kScaleBias; >- asm volatile ( >- "vbroadcastss %3, %%ymm4 \n" >- "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >- "sub %0,%1 \n" >+ asm volatile( >+ "vbroadcastss %3, %%ymm4 \n" >+ "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ "sub %0,%1 \n" > >- // 16 pixel loop. >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm2 \n" // 16 shorts >- "add $0x20,%0 \n" >- "vpunpckhwd %%ymm5,%%ymm2,%%ymm3 \n" // mutates >- "vpunpcklwd %%ymm5,%%ymm2,%%ymm2 \n" >- "vcvtdq2ps %%ymm3,%%ymm3 \n" >- "vcvtdq2ps %%ymm2,%%ymm2 \n" >- "vmulps %%ymm3,%%ymm4,%%ymm3 \n" >- "vmulps %%ymm2,%%ymm4,%%ymm2 \n" >- "vpsrld $0xd,%%ymm3,%%ymm3 \n" >- "vpsrld $0xd,%%ymm2,%%ymm2 \n" >- "vpackssdw %%ymm3, %%ymm2, %%ymm2 \n" // unmutates >- MEMOPMEM(vmovdqu,ymm2,-0x20,0,1,1) >- "sub $0x10,%2 \n" >- "jg 1b \n" >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm2 \n" // 16 shorts >+ "add $0x20,%0 \n" >+ "vpunpckhwd %%ymm5,%%ymm2,%%ymm3 \n" // mutates >+ "vpunpcklwd %%ymm5,%%ymm2,%%ymm2 \n" >+ "vcvtdq2ps %%ymm3,%%ymm3 \n" >+ "vcvtdq2ps %%ymm2,%%ymm2 \n" >+ "vmulps %%ymm3,%%ymm4,%%ymm3 \n" >+ "vmulps %%ymm2,%%ymm4,%%ymm2 \n" >+ "vpsrld $0xd,%%ymm3,%%ymm3 \n" >+ "vpsrld $0xd,%%ymm2,%%ymm2 \n" >+ "vpackssdw %%ymm3, %%ymm2, %%ymm2 \n" // unmutates >+ "vmovdqu %%ymm2,-0x20(%0,%1,1) \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" > >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 > #if defined(__x86_64__) >- : "x"(scale) // %3 >+ : "x"(scale) // %3 > #else >- : "m"(scale) // %3 >+ : "m"(scale) // %3 > #endif >- : "memory", "cc", >- "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ : "memory", "cc", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_HALFFLOATROW_AVX2 > > #ifdef HAS_HALFFLOATROW_F16C >-void HalfFloatRow_F16C(const uint16* src, uint16* dst, float scale, int width) { >- asm volatile ( >- "vbroadcastss %3, %%ymm4 \n" >- "sub %0,%1 \n" >+void HalfFloatRow_F16C(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { >+ asm volatile( >+ "vbroadcastss %3, %%ymm4 \n" >+ "sub %0,%1 \n" > >- // 16 pixel loop. >- LABELALIGN >- "1: \n" >- "vpmovzxwd " MEMACCESS(0) ",%%ymm2 \n" // 16 shorts -> 16 ints >- "vpmovzxwd " MEMACCESS2(0x10,0) ",%%ymm3 \n" >- "vcvtdq2ps %%ymm2,%%ymm2 \n" >- "vcvtdq2ps %%ymm3,%%ymm3 \n" >- "vmulps %%ymm2,%%ymm4,%%ymm2 \n" >- "vmulps %%ymm3,%%ymm4,%%ymm3 \n" >- "vcvtps2ph $3, %%ymm2, %%xmm2 \n" >- "vcvtps2ph $3, %%ymm3, %%xmm3 \n" >- MEMOPMEM(vmovdqu,xmm2,0x00,0,1,1) >- MEMOPMEM(vmovdqu,xmm3,0x10,0,1,1) >- "add $0x20,%0 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vpmovzxwd (%0),%%ymm2 \n" // 16 shorts -> 16 ints >+ "vpmovzxwd 0x10(%0),%%ymm3 \n" >+ "vcvtdq2ps %%ymm2,%%ymm2 \n" >+ "vcvtdq2ps %%ymm3,%%ymm3 \n" >+ "vmulps %%ymm2,%%ymm4,%%ymm2 \n" >+ "vmulps %%ymm3,%%ymm4,%%ymm3 \n" >+ "vcvtps2ph $3, %%ymm2, %%xmm2 \n" >+ "vcvtps2ph $3, %%ymm3, %%xmm3 \n" >+ "vmovdqu %%xmm2,0x00(%0,%1,1) \n" >+ "vmovdqu %%xmm3,0x10(%0,%1,1) \n" >+ "add $0x20,%0 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 > #if defined(__x86_64__) >- : "x"(scale) // %3 >+ : "x"(scale) // %3 > #else >- : "m"(scale) // %3 >+ : "m"(scale) // %3 > #endif >- : "memory", "cc", >- "xmm2", "xmm3", "xmm4" >- ); >+ : "memory", "cc", "xmm2", "xmm3", "xmm4"); > } > #endif // HAS_HALFFLOATROW_F16C > > #ifdef HAS_HALFFLOATROW_F16C >-void HalfFloat1Row_F16C(const uint16* src, uint16* dst, float, int width) { >- asm volatile ( >- "sub %0,%1 \n" >- // 16 pixel loop. >- LABELALIGN >- "1: \n" >- "vpmovzxwd " MEMACCESS(0) ",%%ymm2 \n" // 16 shorts -> 16 ints >- "vpmovzxwd " MEMACCESS2(0x10,0) ",%%ymm3 \n" >- "vcvtdq2ps %%ymm2,%%ymm2 \n" >- "vcvtdq2ps %%ymm3,%%ymm3 \n" >- "vcvtps2ph $3, %%ymm2, %%xmm2 \n" >- "vcvtps2ph $3, %%ymm3, %%xmm3 \n" >- MEMOPMEM(vmovdqu,xmm2,0x00,0,1,1) >- MEMOPMEM(vmovdqu,xmm3,0x10,0,1,1) >- "add $0x20,%0 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src), // %0 >- "+r"(dst), // %1 >- "+r"(width) // %2 >- : >- : "memory", "cc", >- "xmm2", "xmm3" >- ); >+void HalfFloat1Row_F16C(const uint16_t* src, uint16_t* dst, float, int width) { >+ asm volatile( >+ "sub %0,%1 \n" >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "vpmovzxwd (%0),%%ymm2 \n" // 16 shorts -> 16 ints >+ "vpmovzxwd 0x10(%0),%%ymm3 \n" >+ "vcvtdq2ps %%ymm2,%%ymm2 \n" >+ "vcvtdq2ps %%ymm3,%%ymm3 \n" >+ "vcvtps2ph $3, %%ymm2, %%xmm2 \n" >+ "vcvtps2ph $3, %%ymm3, %%xmm3 \n" >+ "vmovdqu %%xmm2,0x00(%0,%1,1) \n" >+ "vmovdqu %%xmm3,0x10(%0,%1,1) \n" >+ "add $0x20,%0 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : >+ : "memory", "cc", "xmm2", "xmm3"); > } > #endif // HAS_HALFFLOATROW_F16C > > #ifdef HAS_ARGBCOLORTABLEROW_X86 > // Tranform ARGB pixels with color table. >-void ARGBColorTableRow_X86(uint8* dst_argb, >- const uint8* table_argb, >+void ARGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, > int width) { > uintptr_t pixel_temp; >- asm volatile ( >- // 1 pixel loop. >- LABELALIGN >- "1: \n" >- "movzb " MEMACCESS(0) ",%1 \n" >- "lea " MEMLEA(0x4,0) ",%0 \n" >- MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x4,0) " \n" >- "movzb " MEMACCESS2(-0x3,0) ",%1 \n" >- MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x3,0) " \n" >- "movzb " MEMACCESS2(-0x2,0) ",%1 \n" >- MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x2,0) " \n" >- "movzb " MEMACCESS2(-0x1,0) ",%1 \n" >- MEMOPARG(movzb,0x03,3,1,4,1) " \n" // movzb 0x3(%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x1,0) " \n" >- "dec %2 \n" >- "jg 1b \n" >- : "+r"(dst_argb), // %0 >- "=&d"(pixel_temp), // %1 >- "+r"(width) // %2 >- : "r"(table_argb) // %3 >- : "memory", "cc"); >+ asm volatile( >+ // 1 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movzb (%0),%1 \n" >+ "lea 0x4(%0),%0 \n" >+ "movzb 0x00(%3,%1,4),%1 \n" >+ "mov %b1,-0x4(%0) \n" >+ "movzb -0x3(%0),%1 \n" >+ "movzb 0x01(%3,%1,4),%1 \n" >+ "mov %b1,-0x3(%0) \n" >+ "movzb -0x2(%0),%1 \n" >+ "movzb 0x02(%3,%1,4),%1 \n" >+ "mov %b1,-0x2(%0) \n" >+ "movzb -0x1(%0),%1 \n" >+ "movzb 0x03(%3,%1,4),%1 \n" >+ "mov %b1,-0x1(%0) \n" >+ "dec %2 \n" >+ "jg 1b \n" >+ : "+r"(dst_argb), // %0 >+ "=&d"(pixel_temp), // %1 >+ "+r"(width) // %2 >+ : "r"(table_argb) // %3 >+ : "memory", "cc"); > } > #endif // HAS_ARGBCOLORTABLEROW_X86 > > #ifdef HAS_RGBCOLORTABLEROW_X86 > // Tranform RGB pixels with color table. >-void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width) { >+void RGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, >+ int width) { > uintptr_t pixel_temp; >- asm volatile ( >- // 1 pixel loop. >- LABELALIGN >- "1: \n" >- "movzb " MEMACCESS(0) ",%1 \n" >- "lea " MEMLEA(0x4,0) ",%0 \n" >- MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x4,0) " \n" >- "movzb " MEMACCESS2(-0x3,0) ",%1 \n" >- MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x3,0) " \n" >- "movzb " MEMACCESS2(-0x2,0) ",%1 \n" >- MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1 >- "mov %b1," MEMACCESS2(-0x2,0) " \n" >- "dec %2 \n" >- "jg 1b \n" >- : "+r"(dst_argb), // %0 >- "=&d"(pixel_temp), // %1 >- "+r"(width) // %2 >- : "r"(table_argb) // %3 >- : "memory", "cc"); >+ asm volatile( >+ // 1 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movzb (%0),%1 \n" >+ "lea 0x4(%0),%0 \n" >+ "movzb 0x00(%3,%1,4),%1 \n" >+ "mov %b1,-0x4(%0) \n" >+ "movzb -0x3(%0),%1 \n" >+ "movzb 0x01(%3,%1,4),%1 \n" >+ "mov %b1,-0x3(%0) \n" >+ "movzb -0x2(%0),%1 \n" >+ "movzb 0x02(%3,%1,4),%1 \n" >+ "mov %b1,-0x2(%0) \n" >+ "dec %2 \n" >+ "jg 1b \n" >+ : "+r"(dst_argb), // %0 >+ "=&d"(pixel_temp), // %1 >+ "+r"(width) // %2 >+ : "r"(table_argb) // %3 >+ : "memory", "cc"); > } > #endif // HAS_RGBCOLORTABLEROW_X86 > > #ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3 > // Tranform RGB pixels with luma table. >-void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBLumaColorTableRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- const uint8* luma, >- uint32 lumacoeff) { >+ const uint8_t* luma, >+ uint32_t lumacoeff) { > uintptr_t pixel_temp; > uintptr_t table_temp; >- asm volatile ( >- "movd %6,%%xmm3 \n" >- "pshufd $0x0,%%xmm3,%%xmm3 \n" >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psllw $0x8,%%xmm4 \n" >- "pxor %%xmm5,%%xmm5 \n" >+ asm volatile( >+ "movd %6,%%xmm3 \n" >+ "pshufd $0x0,%%xmm3,%%xmm3 \n" >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psllw $0x8,%%xmm4 \n" >+ "pxor %%xmm5,%%xmm5 \n" > >- // 4 pixel loop. >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(2) ",%%xmm0 \n" >- "pmaddubsw %%xmm3,%%xmm0 \n" >- "phaddw %%xmm0,%%xmm0 \n" >- "pand %%xmm4,%%xmm0 \n" >- "punpcklwd %%xmm5,%%xmm0 \n" >- "movd %%xmm0,%k1 \n" // 32 bit offset >- "add %5,%1 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- >- "movzb " MEMACCESS(2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS(3) " \n" >- "movzb " MEMACCESS2(0x1,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x1,3) " \n" >- "movzb " MEMACCESS2(0x2,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x2,3) " \n" >- "movzb " MEMACCESS2(0x3,2) ",%0 \n" >- "mov %b0," MEMACCESS2(0x3,3) " \n" >- >- "movd %%xmm0,%k1 \n" // 32 bit offset >- "add %5,%1 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- >- "movzb " MEMACCESS2(0x4,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x4,3) " \n" >- "movzb " MEMACCESS2(0x5,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x5,3) " \n" >- "movzb " MEMACCESS2(0x6,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x6,3) " \n" >- "movzb " MEMACCESS2(0x7,2) ",%0 \n" >- "mov %b0," MEMACCESS2(0x7,3) " \n" >- >- "movd %%xmm0,%k1 \n" // 32 bit offset >- "add %5,%1 \n" >- "pshufd $0x39,%%xmm0,%%xmm0 \n" >- >- "movzb " MEMACCESS2(0x8,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x8,3) " \n" >- "movzb " MEMACCESS2(0x9,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0x9,3) " \n" >- "movzb " MEMACCESS2(0xa,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0xa,3) " \n" >- "movzb " MEMACCESS2(0xb,2) ",%0 \n" >- "mov %b0," MEMACCESS2(0xb,3) " \n" >- >- "movd %%xmm0,%k1 \n" // 32 bit offset >- "add %5,%1 \n" >- >- "movzb " MEMACCESS2(0xc,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0xc,3) " \n" >- "movzb " MEMACCESS2(0xd,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0xd,3) " \n" >- "movzb " MEMACCESS2(0xe,2) ",%0 \n" >- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 >- "mov %b0," MEMACCESS2(0xe,3) " \n" >- "movzb " MEMACCESS2(0xf,2) ",%0 \n" >- "mov %b0," MEMACCESS2(0xf,3) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "lea " MEMLEA(0x10,3) ",%3 \n" >- "sub $0x4,%4 \n" >- "jg 1b \n" >- : "=&d"(pixel_temp), // %0 >- "=&a"(table_temp), // %1 >- "+r"(src_argb), // %2 >- "+r"(dst_argb), // %3 >- "+rm"(width) // %4 >- : "r"(luma), // %5 >- "rm"(lumacoeff) // %6 >- : "memory", "cc", "xmm0", "xmm3", "xmm4", "xmm5" >- ); >+ // 4 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%2),%%xmm0 \n" >+ "pmaddubsw %%xmm3,%%xmm0 \n" >+ "phaddw %%xmm0,%%xmm0 \n" >+ "pand %%xmm4,%%xmm0 \n" >+ "punpcklwd %%xmm5,%%xmm0 \n" >+ "movd %%xmm0,%k1 \n" // 32 bit offset >+ "add %5,%1 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ >+ "movzb (%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,(%3) \n" >+ "movzb 0x1(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x1(%3) \n" >+ "movzb 0x2(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x2(%3) \n" >+ "movzb 0x3(%2),%0 \n" >+ "mov %b0,0x3(%3) \n" >+ >+ "movd %%xmm0,%k1 \n" // 32 bit offset >+ "add %5,%1 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ >+ "movzb 0x4(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x4(%3) \n" >+ "movzb 0x5(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x5(%3) \n" >+ "movzb 0x6(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x6(%3) \n" >+ "movzb 0x7(%2),%0 \n" >+ "mov %b0,0x7(%3) \n" >+ >+ "movd %%xmm0,%k1 \n" // 32 bit offset >+ "add %5,%1 \n" >+ "pshufd $0x39,%%xmm0,%%xmm0 \n" >+ >+ "movzb 0x8(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x8(%3) \n" >+ "movzb 0x9(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0x9(%3) \n" >+ "movzb 0xa(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0xa(%3) \n" >+ "movzb 0xb(%2),%0 \n" >+ "mov %b0,0xb(%3) \n" >+ >+ "movd %%xmm0,%k1 \n" // 32 bit offset >+ "add %5,%1 \n" >+ >+ "movzb 0xc(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0xc(%3) \n" >+ "movzb 0xd(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0xd(%3) \n" >+ "movzb 0xe(%2),%0 \n" >+ "movzb 0x00(%1,%0,1),%0 \n" >+ "mov %b0,0xe(%3) \n" >+ "movzb 0xf(%2),%0 \n" >+ "mov %b0,0xf(%3) \n" >+ "lea 0x10(%2),%2 \n" >+ "lea 0x10(%3),%3 \n" >+ "sub $0x4,%4 \n" >+ "jg 1b \n" >+ : "=&d"(pixel_temp), // %0 >+ "=&a"(table_temp), // %1 >+ "+r"(src_argb), // %2 >+ "+r"(dst_argb), // %3 >+ "+rm"(width) // %4 >+ : "r"(luma), // %5 >+ "rm"(lumacoeff) // %6 >+ : "memory", "cc", "xmm0", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_ARGBLUMACOLORTABLEROW_SSSE3 > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_msa.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_msa.cc >index 5cc23450a52..66666cefcd9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_msa.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_msa.cc >@@ -37,17 +37,17 @@ extern "C" { > } > > // Load YUV 422 pixel data >-#define READYUV422(psrc_y, psrc_u, psrc_v, out_y, out_u, out_v) \ >- { \ >- uint64 y_m; \ >- uint32 u_m, v_m; \ >- v4i32 zero_m = {0}; \ >- y_m = LD(psrc_y); \ >- u_m = LW(psrc_u); \ >- v_m = LW(psrc_v); \ >- out_y = (v16u8)__msa_insert_d((v2i64)zero_m, 0, (int64)y_m); \ >- out_u = (v16u8)__msa_insert_w(zero_m, 0, (int32)u_m); \ >- out_v = (v16u8)__msa_insert_w(zero_m, 0, (int32)v_m); \ >+#define READYUV422(psrc_y, psrc_u, psrc_v, out_y, out_u, out_v) \ >+ { \ >+ uint64_t y_m; \ >+ uint32_t u_m, v_m; \ >+ v4i32 zero_m = {0}; \ >+ y_m = LD(psrc_y); \ >+ u_m = LW(psrc_u); \ >+ v_m = LW(psrc_v); \ >+ out_y = (v16u8)__msa_insert_d((v2i64)zero_m, 0, (int64_t)y_m); \ >+ out_u = (v16u8)__msa_insert_w(zero_m, 0, (int32_t)u_m); \ >+ out_v = (v16u8)__msa_insert_w(zero_m, 0, (int32_t)v_m); \ > } > > // Clip input vector elements between 0 to 255 >@@ -275,17 +275,17 @@ extern "C" { > // Load I444 pixel data > #define READI444(psrc_y, psrc_u, psrc_v, out_y, out_u, out_v) \ > { \ >- uint64 y_m, u_m, v_m; \ >+ uint64_t y_m, u_m, v_m; \ > v2i64 zero_m = {0}; \ > y_m = LD(psrc_y); \ > u_m = LD(psrc_u); \ > v_m = LD(psrc_v); \ >- out_y = (v16u8)__msa_insert_d(zero_m, 0, (int64)y_m); \ >- out_u = (v16u8)__msa_insert_d(zero_m, 0, (int64)u_m); \ >- out_v = (v16u8)__msa_insert_d(zero_m, 0, (int64)v_m); \ >+ out_y = (v16u8)__msa_insert_d(zero_m, 0, (int64_t)y_m); \ >+ out_u = (v16u8)__msa_insert_d(zero_m, 0, (int64_t)u_m); \ >+ out_v = (v16u8)__msa_insert_d(zero_m, 0, (int64_t)v_m); \ > } > >-void MirrorRow_MSA(const uint8* src, uint8* dst, int width) { >+void MirrorRow_MSA(const uint8_t* src, uint8_t* dst, int width) { > int x; > v16u8 src0, src1, src2, src3; > v16u8 dst0, dst1, dst2, dst3; >@@ -302,7 +302,7 @@ void MirrorRow_MSA(const uint8* src, uint8* dst, int width) { > } > } > >-void ARGBMirrorRow_MSA(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_MSA(const uint8_t* src, uint8_t* dst, int width) { > int x; > v16u8 src0, src1, src2, src3; > v16u8 dst0, dst1, dst2, dst3; >@@ -319,10 +319,10 @@ void ARGBMirrorRow_MSA(const uint8* src, uint8* dst, int width) { > } > } > >-void I422ToYUY2Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width) { > int x; > v16u8 src_u0, src_v0, src_y0, src_y1, vec_uv0, vec_uv1; >@@ -343,10 +343,10 @@ void I422ToYUY2Row_MSA(const uint8* src_y, > } > } > >-void I422ToUYVYRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width) { > int x; > v16u8 src_u0, src_v0, src_y0, src_y1, vec_uv0, vec_uv1; >@@ -367,10 +367,10 @@ void I422ToUYVYRow_MSA(const uint8* src_y, > } > } > >-void I422ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -390,18 +390,18 @@ void I422ToARGBRow_MSA(const uint8* src_y, > src1 = (v16u8)__msa_ilvr_b((v16i8)src2, (v16i8)src1); > YUVTORGB(src0, src1, vec_ubvr, vec_ugvg, vec_bb, vec_bg, vec_br, vec_yg, > vec0, vec1, vec2); >- STOREARGB(vec0, vec1, vec2, alpha, rgb_buf); >+ STOREARGB(vec0, vec1, vec2, alpha, dst_argb); > src_y += 8; > src_u += 4; > src_v += 4; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void I422ToRGBARow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToRGBARow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -421,23 +421,23 @@ void I422ToRGBARow_MSA(const uint8* src_y, > src1 = (v16u8)__msa_ilvr_b((v16i8)src2, (v16i8)src1); > YUVTORGB(src0, src1, vec_ubvr, vec_ugvg, vec_bb, vec_bg, vec_br, vec_yg, > vec0, vec1, vec2); >- STOREARGB(alpha, vec0, vec1, vec2, rgb_buf); >+ STOREARGB(alpha, vec0, vec1, vec2, dst_argb); > src_y += 8; > src_u += 4; > src_v += 4; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void I422AlphaToARGBRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* rgb_buf, >+void I422AlphaToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >- int64 data_a; >+ int64_t data_a; > v16u8 src0, src1, src2, src3; > v8i16 vec0, vec1, vec2; > v4i32 vec_ub, vec_vr, vec_ug, vec_vg, vec_bb, vec_bg, vec_br, vec_yg; >@@ -457,23 +457,23 @@ void I422AlphaToARGBRow_MSA(const uint8* src_y, > YUVTORGB(src0, src1, vec_ubvr, vec_ugvg, vec_bb, vec_bg, vec_br, vec_yg, > vec0, vec1, vec2); > src3 = (v16u8)__msa_ilvr_b((v16i8)src3, (v16i8)src3); >- STOREARGB(vec0, vec1, vec2, src3, rgb_buf); >+ STOREARGB(vec0, vec1, vec2, src3, dst_argb); > src_y += 8; > src_u += 4; > src_v += 4; > src_a += 8; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void I422ToRGB24Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I422ToRGB24Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, >- int32 width) { >+ int32_t width) { > int x; >- int64 data_u, data_v; >+ int64_t data_u, data_v; > v16u8 src0, src1, src2, src3, src4, dst0, dst1, dst2; > v8i16 vec0, vec1, vec2, vec3, vec4, vec5; > v4i32 vec_ub, vec_vr, vec_ug, vec_vg, vec_bb, vec_bg, vec_br, vec_yg; >@@ -510,20 +510,20 @@ void I422ToRGB24Row_MSA(const uint8* src_y, > dst0 = (v16u8)__msa_vshf_b(shuffler0, (v16i8)reg3, (v16i8)reg0); > dst1 = (v16u8)__msa_vshf_b(shuffler1, (v16i8)reg3, (v16i8)reg1); > dst2 = (v16u8)__msa_vshf_b(shuffler2, (v16i8)reg3, (v16i8)reg2); >- ST_UB2(dst0, dst1, rgb_buf, 16); >- ST_UB(dst2, (rgb_buf + 32)); >+ ST_UB2(dst0, dst1, dst_argb, 16); >+ ST_UB(dst2, (dst_argb + 32)); > src_y += 16; > src_u += 8; > src_v += 8; >- rgb_buf += 48; >+ dst_argb += 48; > } > } > > // TODO(fbarchard): Consider AND instead of shift to isolate 5 upper bits of R. >-void I422ToRGB565Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -558,10 +558,10 @@ void I422ToRGB565Row_MSA(const uint8* src_y, > } > > // TODO(fbarchard): Consider AND instead of shift to isolate 4 upper bits of G. >-void I422ToARGB4444Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -598,10 +598,10 @@ void I422ToARGB4444Row_MSA(const uint8* src_y, > } > } > >-void I422ToARGB1555Row_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -638,7 +638,7 @@ void I422ToARGB1555Row_MSA(const uint8* src_y, > } > } > >-void YUY2ToYRow_MSA(const uint8* src_yuy2, uint8* dst_y, int width) { >+void YUY2ToYRow_MSA(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; > >@@ -652,12 +652,12 @@ void YUY2ToYRow_MSA(const uint8* src_yuy2, uint8* dst_y, int width) { > } > } > >-void YUY2ToUVRow_MSA(const uint8* src_yuy2, >+void YUY2ToUVRow_MSA(const uint8_t* src_yuy2, > int src_stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_yuy2_next = src_yuy2 + src_stride_yuy2; >+ const uint8_t* src_yuy2_next = src_yuy2 + src_stride_yuy2; > int x; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v16u8 vec0, vec1, dst0, dst1; >@@ -682,9 +682,9 @@ void YUY2ToUVRow_MSA(const uint8* src_yuy2, > } > } > >-void YUY2ToUV422Row_MSA(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_MSA(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -703,7 +703,7 @@ void YUY2ToUV422Row_MSA(const uint8* src_yuy2, > } > } > >-void UYVYToYRow_MSA(const uint8* src_uyvy, uint8* dst_y, int width) { >+void UYVYToYRow_MSA(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; > >@@ -717,12 +717,12 @@ void UYVYToYRow_MSA(const uint8* src_uyvy, uint8* dst_y, int width) { > } > } > >-void UYVYToUVRow_MSA(const uint8* src_uyvy, >+void UYVYToUVRow_MSA(const uint8_t* src_uyvy, > int src_stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_uyvy_next = src_uyvy + src_stride_uyvy; >+ const uint8_t* src_uyvy_next = src_uyvy + src_stride_uyvy; > int x; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v16u8 vec0, vec1, dst0, dst1; >@@ -747,9 +747,9 @@ void UYVYToUVRow_MSA(const uint8* src_uyvy, > } > } > >-void UYVYToUV422Row_MSA(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_MSA(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -768,7 +768,7 @@ void UYVYToUV422Row_MSA(const uint8* src_uyvy, > } > } > >-void ARGBToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void ARGBToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, vec0, vec1, vec2, vec3, dst0; > v8u16 reg0, reg1, reg2, reg3, reg4, reg5; >@@ -814,13 +814,13 @@ void ARGBToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void ARGBToUVRow_MSA(const uint8* src_argb0, >+void ARGBToUVRow_MSA(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* src_argb0_next = src_argb0 + src_stride_argb; >+ const uint8_t* src_argb0_next = src_argb0 + src_stride_argb; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v16u8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; > v8u16 reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8, reg9; >@@ -932,7 +932,7 @@ void ARGBToUVRow_MSA(const uint8* src_argb0, > } > } > >-void ARGBToRGB24Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToRGB24Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1, dst2; > v16i8 shuffler0 = {0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18, 20}; >@@ -956,7 +956,7 @@ void ARGBToRGB24Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToRAWRow_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToRAWRow_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1, dst2; > v16i8 shuffler0 = {2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, 18, 17, 16, 22}; >@@ -980,7 +980,7 @@ void ARGBToRAWRow_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToRGB565Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToRGB565Row_MSA(const uint8_t* src_argb, uint8_t* dst_rgb, int width) { > int x; > v16u8 src0, src1, dst0; > v16u8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; >@@ -1014,7 +1014,9 @@ void ARGBToRGB565Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToARGB1555Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToARGB1555Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width) { > int x; > v16u8 src0, src1, dst0; > v16u8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; >@@ -1054,7 +1056,9 @@ void ARGBToARGB1555Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToARGB4444Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { >+void ARGBToARGB4444Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ int width) { > int x; > v16u8 src0, src1; > v16u8 vec0, vec1; >@@ -1077,11 +1081,11 @@ void ARGBToARGB4444Row_MSA(const uint8* src_argb, uint8* dst_rgb, int width) { > } > } > >-void ARGBToUV444Row_MSA(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >- int32 width) { >- int32 x; >+void ARGBToUV444Row_MSA(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, >+ int32_t width) { >+ int32_t x; > v16u8 src0, src1, src2, src3, reg0, reg1, reg2, reg3, dst0, dst1; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; > v8u16 vec8, vec9, vec10, vec11; >@@ -1149,9 +1153,9 @@ void ARGBToUV444Row_MSA(const uint8* src_argb, > } > } > >-void ARGBMultiplyRow_MSA(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, dst0; >@@ -1188,9 +1192,9 @@ void ARGBMultiplyRow_MSA(const uint8* src_argb0, > } > } > >-void ARGBAddRow_MSA(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -1209,9 +1213,9 @@ void ARGBAddRow_MSA(const uint8* src_argb0, > } > } > >-void ARGBSubtractRow_MSA(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -1230,7 +1234,9 @@ void ARGBSubtractRow_MSA(const uint8* src_argb0, > } > } > >-void ARGBAttenuateRow_MSA(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBAttenuateRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { > int x; > v16u8 src0, src1, dst0, dst1; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; >@@ -1295,9 +1301,9 @@ void ARGBAttenuateRow_MSA(const uint8* src_argb, uint8* dst_argb, int width) { > } > } > >-void ARGBToRGB565DitherRow_MSA(const uint8* src_argb, >- uint8* dst_rgb, >- uint32 dither4, >+void ARGBToRGB565DitherRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ uint32_t dither4, > int width) { > int x; > v16u8 src0, src1, dst0, vec0, vec1; >@@ -1339,15 +1345,15 @@ void ARGBToRGB565DitherRow_MSA(const uint8* src_argb, > } > } > >-void ARGBShuffleRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > int x; > v16u8 src0, src1, dst0, dst1; > v16i8 vec0; > v16i8 shuffler_vec = {0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12}; >- int32 val = LW((int32*)shuffler); >+ int32_t val = LW((int32_t*)shuffler); > > vec0 = (v16i8)__msa_fill_w(val); > shuffler_vec += vec0; >@@ -1363,10 +1369,10 @@ void ARGBShuffleRow_MSA(const uint8* src_argb, > } > } > >-void ARGBShadeRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >+ uint32_t value) { > int x; > v16u8 src0, dst0; > v8u16 vec0, vec1; >@@ -1402,7 +1408,7 @@ void ARGBShadeRow_MSA(const uint8* src_argb, > } > } > >-void ARGBGrayRow_MSA(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBGrayRow_MSA(const uint8_t* src_argb, uint8_t* dst_argb, int width) { > int x; > v16u8 src0, src1, vec0, vec1, dst0, dst1; > v8u16 reg0; >@@ -1427,7 +1433,7 @@ void ARGBGrayRow_MSA(const uint8* src_argb, uint8* dst_argb, int width) { > } > } > >-void ARGBSepiaRow_MSA(uint8* dst_argb, int width) { >+void ARGBSepiaRow_MSA(uint8_t* dst_argb, int width) { > int x; > v16u8 src0, src1, dst0, dst1, vec0, vec1, vec2, vec3, vec4, vec5; > v8u16 reg0, reg1, reg2; >@@ -1468,8 +1474,8 @@ void ARGBSepiaRow_MSA(uint8* dst_argb, int width) { > } > } > >-void ARGB4444ToARGBRow_MSA(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_MSA(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1; >@@ -1497,8 +1503,8 @@ void ARGB4444ToARGBRow_MSA(const uint8* src_argb4444, > } > } > >-void ARGB1555ToARGBRow_MSA(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_MSA(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > int x; > v8u16 src0, src1; >@@ -1547,7 +1553,9 @@ void ARGB1555ToARGBRow_MSA(const uint8* src_argb1555, > } > } > >-void RGB565ToARGBRow_MSA(const uint8* src_rgb565, uint8* dst_argb, int width) { >+void RGB565ToARGBRow_MSA(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width) { > int x; > v8u16 src0, src1, vec0, vec1, vec2, vec3, vec4, vec5; > v8u16 reg0, reg1, reg2, reg3, reg4, reg5; >@@ -1592,7 +1600,9 @@ void RGB565ToARGBRow_MSA(const uint8* src_rgb565, uint8* dst_argb, int width) { > } > } > >-void RGB24ToARGBRow_MSA(const uint8* src_rgb24, uint8* dst_argb, int width) { >+void RGB24ToARGBRow_MSA(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width) { > int x; > v16u8 src0, src1, src2; > v16u8 vec0, vec1, vec2; >@@ -1617,7 +1627,7 @@ void RGB24ToARGBRow_MSA(const uint8* src_rgb24, uint8* dst_argb, int width) { > } > } > >-void RAWToARGBRow_MSA(const uint8* src_raw, uint8* dst_argb, int width) { >+void RAWToARGBRow_MSA(const uint8_t* src_raw, uint8_t* dst_argb, int width) { > int x; > v16u8 src0, src1, src2; > v16u8 vec0, vec1, vec2; >@@ -1642,7 +1652,9 @@ void RAWToARGBRow_MSA(const uint8* src_raw, uint8* dst_argb, int width) { > } > } > >-void ARGB1555ToYRow_MSA(const uint8* src_argb1555, uint8* dst_y, int width) { >+void ARGB1555ToYRow_MSA(const uint8_t* src_argb1555, >+ uint8_t* dst_y, >+ int width) { > int x; > v8u16 src0, src1, vec0, vec1, vec2, vec3, vec4, vec5; > v8u16 reg0, reg1, reg2, reg3, reg4, reg5; >@@ -1699,7 +1711,7 @@ void ARGB1555ToYRow_MSA(const uint8* src_argb1555, uint8* dst_y, int width) { > } > } > >-void RGB565ToYRow_MSA(const uint8* src_rgb565, uint8* dst_y, int width) { >+void RGB565ToYRow_MSA(const uint8_t* src_rgb565, uint8_t* dst_y, int width) { > int x; > v8u16 src0, src1, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; > v8u16 reg0, reg1, reg2, reg3, reg4, reg5; >@@ -1762,7 +1774,7 @@ void RGB565ToYRow_MSA(const uint8* src_rgb565, uint8* dst_y, int width) { > } > } > >-void RGB24ToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void RGB24ToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, reg0, reg1, reg2, reg3, dst0; > v8u16 vec0, vec1, vec2, vec3; >@@ -1803,7 +1815,7 @@ void RGB24ToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void RAWToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void RAWToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, reg0, reg1, reg2, reg3, dst0; > v8u16 vec0, vec1, vec2, vec3; >@@ -1844,14 +1856,14 @@ void RAWToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void ARGB1555ToUVRow_MSA(const uint8* src_argb1555, >+void ARGB1555ToUVRow_MSA(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint16* s = (const uint16*)src_argb1555; >- const uint16* t = (const uint16*)(src_argb1555 + src_stride_argb1555); >+ const uint16_t* s = (const uint16_t*)src_argb1555; >+ const uint16_t* t = (const uint16_t*)(src_argb1555 + src_stride_argb1555); > int64_t res0, res1; > v8u16 src0, src1, src2, src3, reg0, reg1, reg2, reg3; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5, vec6; >@@ -1925,14 +1937,14 @@ void ARGB1555ToUVRow_MSA(const uint8* src_argb1555, > } > } > >-void RGB565ToUVRow_MSA(const uint8* src_rgb565, >+void RGB565ToUVRow_MSA(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint16* s = (const uint16*)src_rgb565; >- const uint16* t = (const uint16*)(src_rgb565 + src_stride_rgb565); >+ const uint16_t* s = (const uint16_t*)src_rgb565; >+ const uint16_t* t = (const uint16_t*)(src_rgb565 + src_stride_rgb565); > int64_t res0, res1; > v8u16 src0, src1, src2, src3, reg0, reg1, reg2, reg3; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5; >@@ -2005,15 +2017,15 @@ void RGB565ToUVRow_MSA(const uint8* src_rgb565, > } > } > >-void RGB24ToUVRow_MSA(const uint8* src_rgb0, >+void RGB24ToUVRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >- int64 res0, res1; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; >+ int64_t res0, res1; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v16u8 inp0, inp1, inp2, inp3, inp4, inp5; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; >@@ -2110,15 +2122,15 @@ void RGB24ToUVRow_MSA(const uint8* src_rgb0, > } > } > >-void RAWToUVRow_MSA(const uint8* src_rgb0, >+void RAWToUVRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >- int64 res0, res1; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; >+ int64_t res0, res1; > v16u8 inp0, inp1, inp2, inp3, inp4, inp5; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v8u16 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; >@@ -2215,13 +2227,13 @@ void RAWToUVRow_MSA(const uint8* src_rgb0, > } > } > >-void NV12ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* rgb_buf, >+void NV12ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >- uint64 val0, val1; >+ uint64_t val0, val1; > v16u8 src0, src1, res0, res1, dst0, dst1; > v8i16 vec0, vec1, vec2; > v4i32 vec_ub, vec_vr, vec_ug, vec_vg, vec_bb, vec_bg, vec_br, vec_yg; >@@ -2245,20 +2257,20 @@ void NV12ToARGBRow_MSA(const uint8* src_y, > res1 = (v16u8)__msa_ilvev_b((v16i8)alpha, (v16i8)vec1); > dst0 = (v16u8)__msa_ilvr_b((v16i8)res1, (v16i8)res0); > dst1 = (v16u8)__msa_ilvl_b((v16i8)res1, (v16i8)res0); >- ST_UB2(dst0, dst1, rgb_buf, 16); >+ ST_UB2(dst0, dst1, dst_argb, 16); > src_y += 8; > src_uv += 8; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void NV12ToRGB565Row_MSA(const uint8* src_y, >- const uint8* src_uv, >- uint8* rgb_buf, >+void NV12ToRGB565Row_MSA(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > int x; >- uint64 val0, val1; >+ uint64_t val0, val1; > v16u8 src0, src1, dst0; > v8i16 vec0, vec1, vec2; > v4i32 vec_ub, vec_vr, vec_ug, vec_vg, vec_bb, vec_bg, vec_br, vec_yg; >@@ -2281,20 +2293,20 @@ void NV12ToRGB565Row_MSA(const uint8* src_y, > vec1 = (vec1 >> 2) << 5; > vec2 = (vec2 >> 3) << 11; > dst0 = (v16u8)(vec0 | vec1 | vec2); >- ST_UB(dst0, rgb_buf); >+ ST_UB(dst0, dst_rgb565); > src_y += 8; > src_uv += 8; >- rgb_buf += 16; >+ dst_rgb565 += 16; > } > } > >-void NV21ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_vu, >- uint8* rgb_buf, >+void NV21ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >- uint64 val0, val1; >+ uint64_t val0, val1; > v16u8 src0, src1, res0, res1, dst0, dst1; > v8i16 vec0, vec1, vec2; > v4i32 vec_ub, vec_vr, vec_ug, vec_vg, vec_bb, vec_bg, vec_br, vec_yg; >@@ -2320,16 +2332,16 @@ void NV21ToARGBRow_MSA(const uint8* src_y, > res1 = (v16u8)__msa_ilvev_b((v16i8)alpha, (v16i8)vec1); > dst0 = (v16u8)__msa_ilvr_b((v16i8)res1, (v16i8)res0); > dst1 = (v16u8)__msa_ilvl_b((v16i8)res1, (v16i8)res0); >- ST_UB2(dst0, dst1, rgb_buf, 16); >+ ST_UB2(dst0, dst1, dst_argb, 16); > src_y += 8; > src_vu += 8; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void SobelRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, vec0, dst0, dst1, dst2, dst3; >@@ -2355,9 +2367,9 @@ void SobelRow_MSA(const uint8* src_sobelx, > } > } > >-void SobelToPlaneRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -2376,9 +2388,9 @@ void SobelToPlaneRow_MSA(const uint8* src_sobelx, > } > } > >-void SobelXYRow_MSA(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_MSA(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, vec0, vec1, vec2; >@@ -2404,7 +2416,7 @@ void SobelXYRow_MSA(const uint8* src_sobelx, > } > } > >-void ARGBToYJRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void ARGBToYJRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0; > v16u8 const_0x4B0F = (v16u8)__msa_fill_h(0x4B0F); >@@ -2424,7 +2436,7 @@ void ARGBToYJRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void BGRAToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void BGRAToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0; > v16u8 const_0x4200 = (v16u8)__msa_fill_h(0x4200); >@@ -2444,7 +2456,7 @@ void BGRAToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void ABGRToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void ABGRToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0; > v16u8 const_0x8142 = (v16u8)__msa_fill_h(0x8142); >@@ -2464,7 +2476,7 @@ void ABGRToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void RGBAToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { >+void RGBAToYRow_MSA(const uint8_t* src_argb0, uint8_t* dst_y, int width) { > int x; > v16u8 src0, src1, src2, src3, dst0; > v16u8 const_0x1900 = (v16u8)__msa_fill_h(0x1900); >@@ -2484,14 +2496,14 @@ void RGBAToYRow_MSA(const uint8* src_argb0, uint8* dst_y, int width) { > } > } > >-void ARGBToUVJRow_MSA(const uint8* src_rgb0, >+void ARGBToUVJRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7; > v16u8 vec0, vec1, vec2, vec3; > v16u8 dst0, dst1; >@@ -2554,14 +2566,14 @@ void ARGBToUVJRow_MSA(const uint8* src_rgb0, > } > } > >-void BGRAToUVRow_MSA(const uint8* src_rgb0, >+void BGRAToUVRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; > v16u8 dst0, dst1, vec0, vec1, vec2, vec3; > v16i8 shuffler0 = {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29}; > v16i8 shuffler1 = {2, 3, 6, 7, 10, 11, 14, 15, >@@ -2587,14 +2599,14 @@ void BGRAToUVRow_MSA(const uint8* src_rgb0, > } > } > >-void ABGRToUVRow_MSA(const uint8* src_rgb0, >+void ABGRToUVRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; > v16u8 src0, src1, src2, src3; > v16u8 dst0, dst1; > v16i8 shuffler0 = {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29}; >@@ -2621,14 +2633,14 @@ void ABGRToUVRow_MSA(const uint8* src_rgb0, > } > } > >-void RGBAToUVRow_MSA(const uint8* src_rgb0, >+void RGBAToUVRow_MSA(const uint8_t* src_rgb0, > int src_stride_rgb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; >- const uint8* s = src_rgb0; >- const uint8* t = src_rgb0 + src_stride_rgb; >+ const uint8_t* s = src_rgb0; >+ const uint8_t* t = src_rgb0 + src_stride_rgb; > v16u8 dst0, dst1, vec0, vec1, vec2, vec3; > v16i8 shuffler0 = {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25, 28, 29}; > v16i8 shuffler1 = {2, 3, 6, 7, 10, 11, 14, 15, >@@ -2654,10 +2666,10 @@ void RGBAToUVRow_MSA(const uint8* src_rgb0, > } > } > >-void I444ToARGBRow_MSA(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* rgb_buf, >+void I444ToARGBRow_MSA(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -2714,15 +2726,15 @@ void I444ToARGBRow_MSA(const uint8* src_y, > vec1 = (v8u16)__msa_ilvev_b((v16i8)alpha, (v16i8)vec2); > dst0 = (v16u8)__msa_ilvr_h((v8i16)vec1, (v8i16)vec0); > dst1 = (v16u8)__msa_ilvl_h((v8i16)vec1, (v8i16)vec0); >- ST_UB2(dst0, dst1, rgb_buf, 16); >+ ST_UB2(dst0, dst1, dst_argb, 16); > src_y += 8; > src_u += 8; > src_v += 8; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void I400ToARGBRow_MSA(const uint8* src_y, uint8* rgb_buf, int width) { >+void I400ToARGBRow_MSA(const uint8_t* src_y, uint8_t* dst_argb, int width) { > int x; > v16u8 src0, res0, res1, res2, res3, res4, dst0, dst1, dst2, dst3; > v8i16 vec0, vec1; >@@ -2768,13 +2780,13 @@ void I400ToARGBRow_MSA(const uint8* src_y, uint8* rgb_buf, int width) { > dst1 = (v16u8)__msa_ilvl_b((v16i8)res3, (v16i8)res1); > dst2 = (v16u8)__msa_ilvr_b((v16i8)res4, (v16i8)res2); > dst3 = (v16u8)__msa_ilvl_b((v16i8)res4, (v16i8)res2); >- ST_UB4(dst0, dst1, dst2, dst3, rgb_buf, 16); >+ ST_UB4(dst0, dst1, dst2, dst3, dst_argb, 16); > src_y += 16; >- rgb_buf += 64; >+ dst_argb += 64; > } > } > >-void J400ToARGBRow_MSA(const uint8* src_y, uint8* dst_argb, int width) { >+void J400ToARGBRow_MSA(const uint8_t* src_y, uint8_t* dst_argb, int width) { > int x; > v16u8 src0, vec0, vec1, vec2, vec3, dst0, dst1, dst2, dst3; > v16u8 alpha = (v16u8)__msa_ldi_b(ALPHA_VAL); >@@ -2795,8 +2807,8 @@ void J400ToARGBRow_MSA(const uint8* src_y, uint8* dst_argb, int width) { > } > } > >-void YUY2ToARGBRow_MSA(const uint8* src_yuy2, >- uint8* rgb_buf, >+void YUY2ToARGBRow_MSA(const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -2817,14 +2829,14 @@ void YUY2ToARGBRow_MSA(const uint8* src_yuy2, > src2 = (v16u8)__msa_pckod_b((v16i8)src0, (v16i8)src0); > YUVTORGB(src1, src2, vec_ubvr, vec_ugvg, vec_bb, vec_bg, vec_br, vec_yg, > vec0, vec1, vec2); >- STOREARGB(vec0, vec1, vec2, alpha, rgb_buf); >+ STOREARGB(vec0, vec1, vec2, alpha, dst_argb); > src_yuy2 += 16; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void UYVYToARGBRow_MSA(const uint8* src_uyvy, >- uint8* rgb_buf, >+void UYVYToARGBRow_MSA(const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > int x; >@@ -2845,22 +2857,22 @@ void UYVYToARGBRow_MSA(const uint8* src_uyvy, > src2 = (v16u8)__msa_pckev_b((v16i8)src0, (v16i8)src0); > YUVTORGB(src1, src2, vec_ubvr, vec_ugvg, vec_bb, vec_bg, vec_br, vec_yg, > vec0, vec1, vec2); >- STOREARGB(vec0, vec1, vec2, alpha, rgb_buf); >+ STOREARGB(vec0, vec1, vec2, alpha, dst_argb); > src_uyvy += 16; >- rgb_buf += 32; >+ dst_argb += 32; > } > } > >-void InterpolateRow_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int width, >- int32 source_y_fraction) { >- int32 y1_fraction = source_y_fraction; >- int32 y0_fraction = 256 - y1_fraction; >- uint16 y_fractions; >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ int32_t source_y_fraction) { >+ int32_t y1_fraction = source_y_fraction; >+ int32_t y0_fraction = 256 - y1_fraction; >+ uint16_t y_fractions; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; > v8u16 vec0, vec1, vec2, vec3, y_frac; >@@ -2886,7 +2898,7 @@ void InterpolateRow_MSA(uint8* dst_ptr, > return; > } > >- y_fractions = (uint16)(y0_fraction + (y1_fraction << 8)); >+ y_fractions = (uint16_t)(y0_fraction + (y1_fraction << 8)); > y_frac = (v8u16)__msa_fill_h(y_fractions); > > for (x = 0; x < width; x += 32) { >@@ -2915,7 +2927,7 @@ void InterpolateRow_MSA(uint8* dst_ptr, > } > } > >-void ARGBSetRow_MSA(uint8* dst_argb, uint32 v32, int width) { >+void ARGBSetRow_MSA(uint8_t* dst_argb, uint32_t v32, int width) { > int x; > v4i32 dst0 = __builtin_msa_fill_w(v32); > >@@ -2925,7 +2937,7 @@ void ARGBSetRow_MSA(uint8* dst_argb, uint32 v32, int width) { > } > } > >-void RAWToRGB24Row_MSA(const uint8* src_raw, uint8* dst_rgb24, int width) { >+void RAWToRGB24Row_MSA(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { > int x; > v16u8 src0, src1, src2, src3, src4, dst0, dst1, dst2; > v16i8 shuffler0 = {2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, 17}; >@@ -2950,9 +2962,9 @@ void RAWToRGB24Row_MSA(const uint8* src_raw, uint8* dst_rgb24, int width) { > } > } > >-void MergeUVRow_MSA(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_MSA(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > int x; > v16u8 src0, src1, dst0, dst1; >@@ -2969,7 +2981,9 @@ void MergeUVRow_MSA(const uint8* src_u, > } > } > >-void ARGBExtractAlphaRow_MSA(const uint8* src_argb, uint8* dst_a, int width) { >+void ARGBExtractAlphaRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width) { > int i; > v16u8 src0, src1, src2, src3, vec0, vec1, dst0; > >@@ -2987,9 +3001,9 @@ void ARGBExtractAlphaRow_MSA(const uint8* src_argb, uint8* dst_a, int width) { > } > } > >-void ARGBBlendRow_MSA(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_MSA(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1; >@@ -3052,7 +3066,7 @@ void ARGBBlendRow_MSA(const uint8* src_argb0, > } > } > >-void ARGBQuantizeRow_MSA(uint8* dst_argb, >+void ARGBQuantizeRow_MSA(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, >@@ -3158,11 +3172,11 @@ void ARGBQuantizeRow_MSA(uint8* dst_argb, > } > } > >-void ARGBColorMatrixRow_MSA(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_MSA(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { >- int32 x; >+ int32_t x; > v16i8 src0; > v16u8 src1, src2, dst0, dst1; > v8i16 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; >@@ -3267,9 +3281,9 @@ void ARGBColorMatrixRow_MSA(const uint8* src_argb, > } > } > >-void SplitUVRow_MSA(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_MSA(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; > v16u8 src0, src1, src2, src3, dst0, dst1, dst2, dst3; >@@ -3291,7 +3305,7 @@ void SplitUVRow_MSA(const uint8* src_uv, > } > } > >-void SetRow_MSA(uint8* dst, uint8 v8, int width) { >+void SetRow_MSA(uint8_t* dst, uint8_t v8, int width) { > int x; > v16u8 dst0 = (v16u8)__msa_fill_b(v8); > >@@ -3301,9 +3315,9 @@ void SetRow_MSA(uint8* dst, uint8 v8, int width) { > } > } > >-void MirrorUVRow_MSA(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_MSA(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > int x; > v16u8 src0, src1, src2, src3; >@@ -3330,11 +3344,11 @@ void MirrorUVRow_MSA(const uint8* src_uv, > } > } > >-void SobelXRow_MSA(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >- int32 width) { >+void SobelXRow_MSA(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, >+ int32_t width) { > int x; > v16u8 src0, src1, src2, src3, src4, src5, dst0; > v8i16 vec0, vec1, vec2, vec3, vec4, vec5; >@@ -3384,10 +3398,10 @@ void SobelXRow_MSA(const uint8* src_y0, > } > } > >-void SobelYRow_MSA(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >- int32 width) { >+void SobelYRow_MSA(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, >+ int32_t width) { > int x; > v16u8 src0, src1, dst0; > v8i16 vec0, vec1, vec2, vec3, vec4, vec5, vec6; >@@ -3429,7 +3443,10 @@ void SobelYRow_MSA(const uint8* src_y0, > } > } > >-void HalfFloatRow_MSA(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_MSA(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > int i; > v8u16 src0, src1, src2, src3, dst0, dst1, dst2, dst3; > v4u32 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon.cc >index 1af828622cd..8b6c1952072 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon.cc >@@ -106,10 +106,10 @@ extern "C" { > "vqshrun.s16 d22, q9, #6 \n" /* R */ \ > "vqshrun.s16 d21, q0, #6 \n" /* G */ > >-void I444ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -132,10 +132,10 @@ void I444ToARGBRow_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void I422ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -158,11 +158,11 @@ void I422ToARGBRow_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void I422AlphaToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* dst_argb, >+void I422AlphaToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -186,18 +186,17 @@ void I422AlphaToARGBRow_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void I422ToRGBARow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( > YUVTORGB_SETUP > "1: \n" READYUV422 YUVTORGB > "subs %4, %4, #8 \n" >- "vmov.u8 d19, #255 \n" // d19 modified by >- // YUVTORGB >+ "vmov.u8 d19, #255 \n" // YUVTORGB modified d19 > "vst4.8 {d19, d20, d21, d22}, [%3]! \n" > "bgt 1b \n" > : "+r"(src_y), // %0 >@@ -213,10 +212,10 @@ void I422ToRGBARow_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void I422ToRGB24Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -245,10 +244,10 @@ void I422ToRGB24Row_NEON(const uint8* src_y, > "vsri.16 q0, q8, #5 \n" /* RG */ \ > "vsri.16 q0, q9, #11 \n" /* RGB */ > >-void I422ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -279,10 +278,10 @@ void I422ToRGB565Row_NEON(const uint8* src_y, > "vsri.16 q0, q9, #6 \n" /* ARG */ \ > "vsri.16 q0, q10, #11 \n" /* ARGB */ > >-void I422ToARGB1555Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -291,7 +290,6 @@ void I422ToARGB1555Row_NEON(const uint8* src_y, > "subs %4, %4, #8 \n" > "vmov.u8 d23, #255 \n" ARGBTOARGB1555 > "vst1.8 {q0}, [%3]! \n" // store 8 pixels >- // ARGB1555. > "bgt 1b \n" > : "+r"(src_y), // %0 > "+r"(src_u), // %1 >@@ -315,21 +313,21 @@ void I422ToARGB1555Row_NEON(const uint8* src_y, > "vorr d1, d22, d23 \n" /* RA */ \ > "vzip.u8 d0, d1 \n" /* BGRA */ > >-void I422ToARGB4444Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( > YUVTORGB_SETUP >- "vmov.u8 d4, #0x0f \n" // bits to clear with >- // vbic. >- "1: \n" READYUV422 YUVTORGB >+ "vmov.u8 d4, #0x0f \n" // vbic bits to clear >+ "1: \n" >+ >+ READYUV422 YUVTORGB > "subs %4, %4, #8 \n" > "vmov.u8 d23, #255 \n" ARGBTOARGB4444 > "vst1.8 {q0}, [%3]! \n" // store 8 pixels >- // ARGB4444. > "bgt 1b \n" > : "+r"(src_y), // %0 > "+r"(src_u), // %1 >@@ -344,7 +342,7 @@ void I422ToARGB4444Row_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { >+void I400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) { > asm volatile( > YUVTORGB_SETUP > "vmov.u8 d23, #255 \n" >@@ -363,7 +361,7 @@ void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { > "q12", "q13", "q14", "q15"); > } > >-void J400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { >+void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) { > asm volatile( > "vmov.u8 d23, #255 \n" > "1: \n" >@@ -380,9 +378,9 @@ void J400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { > : "cc", "memory", "d20", "d21", "d22", "d23"); > } > >-void NV12ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile(YUVTORGB_SETUP >@@ -403,9 +401,9 @@ void NV12ToARGBRow_NEON(const uint8* src_y, > "q10", "q11", "q12", "q13", "q14", "q15"); > } > >-void NV21ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile(YUVTORGB_SETUP >@@ -426,9 +424,63 @@ void NV21ToARGBRow_NEON(const uint8* src_y, > "q10", "q11", "q12", "q13", "q14", "q15"); > } > >-void NV12ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile( >+ >+ YUVTORGB_SETUP >+ >+ "1: \n" >+ >+ READNV12 YUVTORGB >+ "subs %3, %3, #8 \n" >+ "vst3.8 {d20, d21, d22}, [%2]! \n" >+ "bgt 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_uv), // %1 >+ "+r"(dst_rgb24), // %2 >+ "+r"(width) // %3 >+ : [kUVToRB] "r"(&yuvconstants->kUVToRB), >+ [kUVToG] "r"(&yuvconstants->kUVToG), >+ [kUVBiasBGR] "r"(&yuvconstants->kUVBiasBGR), >+ [kYToRgb] "r"(&yuvconstants->kYToRgb) >+ : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q8", "q9", "q10", "q11", >+ "q12", "q13", "q14", "q15"); >+} >+ >+void NV21ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile( >+ >+ YUVTORGB_SETUP >+ >+ "1: \n" >+ >+ READNV21 YUVTORGB >+ "subs %3, %3, #8 \n" >+ "vst3.8 {d20, d21, d22}, [%2]! \n" >+ "bgt 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_vu), // %1 >+ "+r"(dst_rgb24), // %2 >+ "+r"(width) // %3 >+ : [kUVToRB] "r"(&yuvconstants->kUVToRB), >+ [kUVToG] "r"(&yuvconstants->kUVToG), >+ [kUVBiasBGR] "r"(&yuvconstants->kUVBiasBGR), >+ [kYToRgb] "r"(&yuvconstants->kYToRgb) >+ : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q8", "q9", "q10", "q11", >+ "q12", "q13", "q14", "q15"); >+} >+ >+void NV12ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -449,8 +501,8 @@ void NV12ToRGB565Row_NEON(const uint8* src_y, > "q12", "q13", "q14", "q15"); > } > >-void YUY2ToARGBRow_NEON(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile(YUVTORGB_SETUP >@@ -470,8 +522,8 @@ void YUY2ToARGBRow_NEON(const uint8* src_yuy2, > "q10", "q11", "q12", "q13", "q14", "q15"); > } > >-void UYVYToARGBRow_NEON(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile(YUVTORGB_SETUP >@@ -492,9 +544,9 @@ void UYVYToARGBRow_NEON(const uint8* src_uyvy, > } > > // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v. >-void SplitUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -513,9 +565,9 @@ void SplitUVRow_NEON(const uint8* src_uv, > } > > // Reads 16 U's and V's and writes out 16 pairs of UV. >-void MergeUVRow_NEON(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_NEON(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > asm volatile( > "1: \n" >@@ -534,10 +586,10 @@ void MergeUVRow_NEON(const uint8* src_u, > } > > // Reads 16 packed RGB and write to planar dst_r, dst_g, dst_b. >-void SplitRGBRow_NEON(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_NEON(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width) { > asm volatile( > "1: \n" >@@ -559,10 +611,10 @@ void SplitRGBRow_NEON(const uint8* src_rgb, > } > > // Reads 16 planar R's, G's and B's and writes out 16 packed RGB at a time >-void MergeRGBRow_NEON(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_NEON(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width) { > asm volatile( > "1: \n" >@@ -584,7 +636,7 @@ void MergeRGBRow_NEON(const uint8* src_r, > } > > // Copy multiple of 32. vld4.8 allow unaligned and is fastest on a15. >-void CopyRow_NEON(const uint8* src, uint8* dst, int count) { >+void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > "1: \n" > "vld1.8 {d0, d1, d2, d3}, [%0]! \n" // load 32 >@@ -593,14 +645,14 @@ void CopyRow_NEON(const uint8* src, uint8* dst, int count) { > "bgt 1b \n" > : "+r"(src), // %0 > "+r"(dst), // %1 >- "+r"(count) // %2 // Output registers >+ "+r"(width) // %2 // Output registers > : // Input registers > : "cc", "memory", "q0", "q1" // Clobber List > ); > } > >-// SetRow writes 'count' bytes using an 8 bit value repeated. >-void SetRow_NEON(uint8* dst, uint8 v8, int count) { >+// SetRow writes 'width' bytes using an 8 bit value repeated. >+void SetRow_NEON(uint8_t* dst, uint8_t v8, int width) { > asm volatile( > "vdup.8 q0, %2 \n" // duplicate 16 bytes > "1: \n" >@@ -608,13 +660,13 @@ void SetRow_NEON(uint8* dst, uint8 v8, int count) { > "vst1.8 {q0}, [%0]! \n" // store > "bgt 1b \n" > : "+r"(dst), // %0 >- "+r"(count) // %1 >+ "+r"(width) // %1 > : "r"(v8) // %2 > : "cc", "memory", "q0"); > } > >-// ARGBSetRow writes 'count' pixels using an 32 bit value repeated. >-void ARGBSetRow_NEON(uint8* dst, uint32 v32, int count) { >+// ARGBSetRow writes 'width' pixels using an 32 bit value repeated. >+void ARGBSetRow_NEON(uint8_t* dst, uint32_t v32, int width) { > asm volatile( > "vdup.u32 q0, %2 \n" // duplicate 4 ints > "1: \n" >@@ -622,12 +674,12 @@ void ARGBSetRow_NEON(uint8* dst, uint32 v32, int count) { > "vst1.8 {q0}, [%0]! \n" // store > "bgt 1b \n" > : "+r"(dst), // %0 >- "+r"(count) // %1 >+ "+r"(width) // %1 > : "r"(v32) // %2 > : "cc", "memory", "q0"); > } > >-void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { >+void MirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > // Start at end of source row. > "mov r3, #-16 \n" >@@ -648,9 +700,9 @@ void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { > : "cc", "memory", "r3", "q0"); > } > >-void MirrorUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > // Start at end of source row. >@@ -673,7 +725,7 @@ void MirrorUVRow_NEON(const uint8* src_uv, > : "cc", "memory", "r12", "q0"); > } > >-void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > // Start at end of source row. > "mov r3, #-16 \n" >@@ -694,7 +746,9 @@ void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) { > : "cc", "memory", "r3", "q0"); > } > >-void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int width) { >+void RGB24ToARGBRow_NEON(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > "vmov.u8 d4, #255 \n" // Alpha > "1: \n" >@@ -710,7 +764,7 @@ void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int width) { > ); > } > >-void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int width) { >+void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width) { > asm volatile( > "vmov.u8 d4, #255 \n" // Alpha > "1: \n" >@@ -727,7 +781,7 @@ void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int width) { > ); > } > >-void RAWToRGB24Row_NEON(const uint8* src_raw, uint8* dst_rgb24, int width) { >+void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { > asm volatile( > "1: \n" > "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RAW. >@@ -756,7 +810,9 @@ void RAWToRGB24Row_NEON(const uint8* src_raw, uint8* dst_rgb24, int width) { > "vorr.u8 d2, d1, d5 \n" /* R */ \ > "vorr.u8 d1, d4, d6 \n" /* G */ > >-void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int width) { >+void RGB565ToARGBRow_NEON(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > "vmov.u8 d3, #255 \n" // Alpha > "1: \n" >@@ -800,8 +856,8 @@ void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int width) { > "vorr.u8 d2, d1, d5 \n" /* R */ \ > "vorr.u8 d1, d4, d6 \n" /* G */ > >-void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "vmov.u8 d3, #255 \n" // Alpha >@@ -829,8 +885,8 @@ void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, > "vorr.u8 q1, q1, q2 \n" /* G,A GGGGGGGG */ \ > "vswp.u8 d1, d2 \n" /* B,R,G,A -> B,G,R,A */ > >-void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "vmov.u8 d3, #255 \n" // Alpha >@@ -848,7 +904,9 @@ void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, > ); > } > >-void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int width) { >+void ARGBToRGB24Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb24, >+ int width) { > asm volatile( > "1: \n" > "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. >@@ -864,7 +922,7 @@ void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int width) { > ); > } > >-void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int width) { >+void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width) { > asm volatile( > "1: \n" > "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB. >@@ -880,7 +938,7 @@ void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int width) { > ); > } > >-void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int width) { >+void YUY2ToYRow_NEON(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { > asm volatile( > "1: \n" > "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of YUY2. >@@ -895,7 +953,7 @@ void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int width) { > ); > } > >-void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int width) { >+void UYVYToYRow_NEON(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { > asm volatile( > "1: \n" > "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of UYVY. >@@ -910,9 +968,9 @@ void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int width) { > ); > } > >-void YUY2ToUV422Row_NEON(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -930,9 +988,9 @@ void YUY2ToUV422Row_NEON(const uint8* src_yuy2, > ); > } > >-void UYVYToUV422Row_NEON(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -950,10 +1008,10 @@ void UYVYToUV422Row_NEON(const uint8* src_uyvy, > ); > } > >-void YUY2ToUVRow_NEON(const uint8* src_yuy2, >+void YUY2ToUVRow_NEON(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "add %1, %0, %1 \n" // stride + src_yuy2 >@@ -977,10 +1035,10 @@ void YUY2ToUVRow_NEON(const uint8* src_yuy2, > ); > } > >-void UYVYToUVRow_NEON(const uint8* src_uyvy, >+void UYVYToUVRow_NEON(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "add %1, %0, %1 \n" // stride + src_uyvy >@@ -1005,9 +1063,9 @@ void UYVYToUVRow_NEON(const uint8* src_uyvy, > } > > // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-void ARGBShuffleRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > asm volatile( > "vld1.8 {q2}, [%3] \n" // shuffler >@@ -1026,10 +1084,10 @@ void ARGBShuffleRow_NEON(const uint8* src_argb, > ); > } > >-void I422ToYUY2Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width) { > asm volatile( > "1: \n" >@@ -1048,10 +1106,10 @@ void I422ToYUY2Row_NEON(const uint8* src_y, > : "cc", "memory", "d0", "d1", "d2", "d3"); > } > >-void I422ToUYVYRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width) { > asm volatile( > "1: \n" >@@ -1070,7 +1128,9 @@ void I422ToUYVYRow_NEON(const uint8* src_y, > : "cc", "memory", "d0", "d1", "d2", "d3"); > } > >-void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int width) { >+void ARGBToRGB565Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb565, >+ int width) { > asm volatile( > "1: \n" > "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB. >@@ -1085,9 +1145,9 @@ void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int width) { > : "cc", "memory", "q0", "q8", "q9", "q10", "q11"); > } > >-void ARGBToRGB565DitherRow_NEON(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width) { > asm volatile( > "vdup.32 d2, %2 \n" // dither4 >@@ -1107,8 +1167,8 @@ void ARGBToRGB565DitherRow_NEON(const uint8* src_argb, > : "cc", "memory", "q0", "q1", "q8", "q9", "q10", "q11"); > } > >-void ARGBToARGB1555Row_NEON(const uint8* src_argb, >- uint8* dst_argb1555, >+void ARGBToARGB1555Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb1555, > int width) { > asm volatile( > "1: \n" >@@ -1124,8 +1184,8 @@ void ARGBToARGB1555Row_NEON(const uint8* src_argb, > : "cc", "memory", "q0", "q8", "q9", "q10", "q11"); > } > >-void ARGBToARGB4444Row_NEON(const uint8* src_argb, >- uint8* dst_argb4444, >+void ARGBToARGB4444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb4444, > int width) { > asm volatile( > "vmov.u8 d4, #0x0f \n" // bits to clear with >@@ -1143,7 +1203,7 @@ void ARGBToARGB4444Row_NEON(const uint8* src_argb, > : "cc", "memory", "q0", "q8", "q9", "q10", "q11"); > } > >-void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { >+void ARGBToYRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient >@@ -1166,7 +1226,9 @@ void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { > : "cc", "memory", "q0", "q1", "q2", "q12", "q13"); > } > >-void ARGBExtractAlphaRow_NEON(const uint8* src_argb, uint8* dst_a, int width) { >+void ARGBExtractAlphaRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width) { > asm volatile( > "1: \n" > "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels >@@ -1182,7 +1244,7 @@ void ARGBExtractAlphaRow_NEON(const uint8* src_argb, uint8* dst_a, int width) { > ); > } > >-void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { >+void ARGBToYJRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient > "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient >@@ -1204,9 +1266,9 @@ void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { > } > > // 8x1 pixels. >-void ARGBToUV444Row_NEON(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "vmov.u8 d24, #112 \n" // UB / VR 0.875 >@@ -1260,10 +1322,10 @@ void ARGBToUV444Row_NEON(const uint8* src_argb, > // clang-format on > > // TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr. >-void ARGBToUVRow_NEON(const uint8* src_argb, >+void ARGBToUVRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_argb >@@ -1306,10 +1368,10 @@ void ARGBToUVRow_NEON(const uint8* src_argb, > } > > // TODO(fbarchard): Subsample match C code. >-void ARGBToUVJRow_NEON(const uint8* src_argb, >+void ARGBToUVJRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_argb >@@ -1351,10 +1413,10 @@ void ARGBToUVJRow_NEON(const uint8* src_argb, > ); > } > >-void BGRAToUVRow_NEON(const uint8* src_bgra, >+void BGRAToUVRow_NEON(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_bgra >@@ -1396,10 +1458,10 @@ void BGRAToUVRow_NEON(const uint8* src_bgra, > ); > } > >-void ABGRToUVRow_NEON(const uint8* src_abgr, >+void ABGRToUVRow_NEON(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_abgr >@@ -1441,10 +1503,10 @@ void ABGRToUVRow_NEON(const uint8* src_abgr, > ); > } > >-void RGBAToUVRow_NEON(const uint8* src_rgba, >+void RGBAToUVRow_NEON(const uint8_t* src_rgba, > int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_rgba >@@ -1486,10 +1548,10 @@ void RGBAToUVRow_NEON(const uint8* src_rgba, > ); > } > >-void RGB24ToUVRow_NEON(const uint8* src_rgb24, >+void RGB24ToUVRow_NEON(const uint8_t* src_rgb24, > int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_rgb24 >@@ -1531,10 +1593,10 @@ void RGB24ToUVRow_NEON(const uint8* src_rgb24, > ); > } > >-void RAWToUVRow_NEON(const uint8* src_raw, >+void RAWToUVRow_NEON(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile ( > "add %1, %0, %1 \n" // src_stride + src_raw >@@ -1577,10 +1639,10 @@ void RAWToUVRow_NEON(const uint8* src_raw, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void RGB565ToUVRow_NEON(const uint8* src_rgb565, >+void RGB565ToUVRow_NEON(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "add %1, %0, %1 \n" // src_stride + src_argb >@@ -1643,10 +1705,10 @@ void RGB565ToUVRow_NEON(const uint8* src_rgb565, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, >+void ARGB1555ToUVRow_NEON(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "add %1, %0, %1 \n" // src_stride + src_argb >@@ -1709,10 +1771,10 @@ void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, >+void ARGB4444ToUVRow_NEON(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "add %1, %0, %1 \n" // src_stride + src_argb >@@ -1774,7 +1836,7 @@ void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, > "q9", "q10", "q11", "q12", "q13", "q14", "q15"); > } > >-void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int width) { >+void RGB565ToYRow_NEON(const uint8_t* src_rgb565, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient >@@ -1798,7 +1860,9 @@ void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int width) { > : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"); > } > >-void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int width) { >+void ARGB1555ToYRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_y, >+ int width) { > asm volatile( > "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient >@@ -1822,7 +1886,9 @@ void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int width) { > : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"); > } > >-void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int width) { >+void ARGB4444ToYRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_y, >+ int width) { > asm volatile( > "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient >@@ -1846,7 +1912,7 @@ void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int width) { > : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"); > } > >-void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int width) { >+void BGRAToYRow_NEON(const uint8_t* src_bgra, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient > "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient >@@ -1869,7 +1935,7 @@ void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int width) { > : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"); > } > >-void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int width) { >+void ABGRToYRow_NEON(const uint8_t* src_abgr, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient > "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient >@@ -1892,7 +1958,7 @@ void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int width) { > : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"); > } > >-void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int width) { >+void RGBAToYRow_NEON(const uint8_t* src_rgba, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient >@@ -1915,7 +1981,7 @@ void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int width) { > : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"); > } > >-void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int width) { >+void RGB24ToYRow_NEON(const uint8_t* src_rgb24, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient > "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient >@@ -1938,7 +2004,7 @@ void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int width) { > : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"); > } > >-void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int width) { >+void RAWToYRow_NEON(const uint8_t* src_raw, uint8_t* dst_y, int width) { > asm volatile( > "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient > "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient >@@ -1962,8 +2028,8 @@ void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int width) { > } > > // Bilinear filter 16x2 -> 16x1 >-void InterpolateRow_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >@@ -2021,9 +2087,9 @@ void InterpolateRow_NEON(uint8* dst_ptr, > } > > // dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr >-void ARGBBlendRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "subs %3, #8 \n" >@@ -2081,7 +2147,9 @@ void ARGBBlendRow_NEON(const uint8* src_argb0, > } > > // Attenuate 8 pixels at a time. >-void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBAttenuateRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > // Attenuate 8 pixels. > "1: \n" >@@ -2104,7 +2172,7 @@ void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { > > // Quantize 8 ARGB pixels (32 bytes). > // dst = (dst * scale >> 16) * interval_size + interval_offset; >-void ARGBQuantizeRow_NEON(uint8* dst_argb, >+void ARGBQuantizeRow_NEON(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, >@@ -2147,10 +2215,10 @@ void ARGBQuantizeRow_NEON(uint8* dst_argb, > // Shade 8 pixels at a time by specified value. > // NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8. > // Rounding in vqrdmulh does +1 to high if high bit of low s16 is set. >-void ARGBShadeRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >+ uint32_t value) { > asm volatile( > "vdup.u32 q0, %3 \n" // duplicate scale value. > "vzip.u8 d0, d1 \n" // d0 aarrggbb. >@@ -2184,7 +2252,7 @@ void ARGBShadeRow_NEON(const uint8* src_argb, > // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels > // Similar to ARGBToYJ but stores ARGB. > // C code is (15 * b + 75 * g + 38 * r + 64) >> 7; >-void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBGrayRow_NEON(const uint8_t* src_argb, uint8_t* dst_argb, int width) { > asm volatile( > "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient > "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient >@@ -2211,7 +2279,7 @@ void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { > // b = (r * 35 + g * 68 + b * 17) >> 7 > // g = (r * 45 + g * 88 + b * 22) >> 7 > // r = (r * 50 + g * 98 + b * 24) >> 7 >-void ARGBSepiaRow_NEON(uint8* dst_argb, int width) { >+void ARGBSepiaRow_NEON(uint8_t* dst_argb, int width) { > asm volatile( > "vmov.u8 d20, #17 \n" // BB coefficient > "vmov.u8 d21, #68 \n" // BG coefficient >@@ -2249,9 +2317,9 @@ void ARGBSepiaRow_NEON(uint8* dst_argb, int width) { > // Tranform 8 ARGB pixels (32 bytes) with color matrix. > // TODO(fbarchard): Was same as Sepia except matrix is provided. This function > // needs to saturate. Consider doing a non-saturating version. >-void ARGBColorMatrixRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { > asm volatile( > "vld1.8 {q2}, [%3] \n" // load 3 ARGB vectors. >@@ -2308,9 +2376,9 @@ void ARGBColorMatrixRow_NEON(const uint8* src_argb, > } > > // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. >-void ARGBMultiplyRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2337,9 +2405,9 @@ void ARGBMultiplyRow_NEON(const uint8* src_argb0, > } > > // Add 2 rows of ARGB pixels together, 8 pixels at a time. >-void ARGBAddRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2360,9 +2428,9 @@ void ARGBAddRow_NEON(const uint8* src_argb0, > } > > // Subtract 2 rows of ARGB pixels, 8 pixels at a time. >-void ARGBSubtractRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2387,9 +2455,9 @@ void ARGBSubtractRow_NEON(const uint8* src_argb0, > // R = Sobel > // G = Sobel > // B = Sobel >-void SobelRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "vmov.u8 d3, #255 \n" // alpha >@@ -2412,9 +2480,9 @@ void SobelRow_NEON(const uint8* src_sobelx, > } > > // Adds Sobel X and Sobel Y and stores Sobel into plane. >-void SobelToPlaneRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { > asm volatile( > // 16 pixel loop. >@@ -2438,9 +2506,9 @@ void SobelToPlaneRow_NEON(const uint8* src_sobelx, > // R = Sobel X > // G = Sobel > // B = Sobel Y >-void SobelXYRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "vmov.u8 d3, #255 \n" // alpha >@@ -2464,10 +2532,10 @@ void SobelXYRow_NEON(const uint8* src_sobelx, > // -1 0 1 > // -2 0 2 > // -1 0 1 >-void SobelXRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width) { > asm volatile( > "1: \n" >@@ -2503,9 +2571,9 @@ void SobelXRow_NEON(const uint8* src_y0, > // -1 -2 -1 > // 0 0 0 > // 1 2 1 >-void SobelYRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width) { > asm volatile( > "1: \n" >@@ -2536,7 +2604,10 @@ void SobelYRow_NEON(const uint8* src_y0, > ); > } > >-void HalfFloat1Row_NEON(const uint16* src, uint16* dst, float, int width) { >+void HalfFloat1Row_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float /*unused*/, >+ int width) { > asm volatile( > "vdup.32 q0, %3 \n" > >@@ -2561,7 +2632,10 @@ void HalfFloat1Row_NEON(const uint16* src, uint16* dst, float, int width) { > } > > // TODO(fbarchard): multiply by element. >-void HalfFloatRow_NEON(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > asm volatile( > "vdup.32 q0, %3 \n" > >@@ -2585,6 +2659,32 @@ void HalfFloatRow_NEON(const uint16* src, uint16* dst, float scale, int width) { > : "cc", "memory", "q0", "q1", "q2", "q3"); > } > >+void ByteToFloatRow_NEON(const uint8_t* src, >+ float* dst, >+ float scale, >+ int width) { >+ asm volatile( >+ "vdup.32 q0, %3 \n" >+ >+ "1: \n" >+ "vld1.8 {d2}, [%0]! \n" // load 8 bytes >+ "subs %2, %2, #8 \n" // 8 pixels per loop >+ "vmovl.u8 q1, d2 \n" // 8 shorts >+ "vmovl.u16 q2, d2 \n" // 8 ints >+ "vmovl.u16 q3, d3 \n" >+ "vcvt.f32.u32 q2, q2 \n" // 8 floats >+ "vcvt.f32.u32 q3, q3 \n" >+ "vmul.f32 q2, q2, d0[0] \n" // scale >+ "vmul.f32 q3, q3, d0[0] \n" >+ "vst1.8 {q2, q3}, [%1]! \n" // store 8 floats >+ "bgt 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "r"(scale) // %3 >+ : "cc", "memory", "q0", "q1", "q2", "q3"); >+} >+ > #endif // !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__).. > > #ifdef __cplusplus >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc >index 5616d8a5b5f..24b4520babc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc >@@ -112,10 +112,10 @@ extern "C" { > ".8h, #6 \n" /* G */ \ > "sqshrun " #vR ".8b, " #vR ".8h, #6 \n" /* R */ > >-void I444ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I444ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -141,10 +141,10 @@ void I444ToARGBRow_NEON(const uint8* src_y, > ); > } > >-void I422ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+void I422ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -170,11 +170,11 @@ void I422ToARGBRow_NEON(const uint8* src_y, > ); > } > >-void I422AlphaToARGBRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- const uint8* src_a, >- uint8* dst_argb, >+void I422AlphaToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ const uint8_t* src_a, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -201,10 +201,10 @@ void I422AlphaToARGBRow_NEON(const uint8* src_y, > ); > } > >-void I422ToRGBARow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgba, >+void I422ToRGBARow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -230,10 +230,10 @@ void I422ToRGBARow_NEON(const uint8* src_y, > ); > } > >-void I422ToRGB24Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb24, >+void I422ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -265,10 +265,10 @@ void I422ToRGB24Row_NEON(const uint8* src_y, > "sri v0.8h, v21.8h, #5 \n" /* RG */ \ > "sri v0.8h, v20.8h, #11 \n" /* RGB */ > >-void I422ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_rgb565, >+void I422ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -301,10 +301,10 @@ void I422ToRGB565Row_NEON(const uint8* src_y, > "sri v0.8h, v21.8h, #6 \n" /* ARG */ \ > "sri v0.8h, v20.8h, #11 \n" /* ARGB */ > >-void I422ToARGB1555Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb1555, >+void I422ToARGB1555Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb1555, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -339,10 +339,10 @@ void I422ToARGB1555Row_NEON(const uint8* src_y, > "orr v1.8b, v22.8b, v23.8b \n" /* RA */ \ > "zip1 v0.16b, v0.16b, v1.16b \n" /* BGRA */ > >-void I422ToARGB4444Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb4444, >+void I422ToARGB4444Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb4444, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -370,7 +370,7 @@ void I422ToARGB4444Row_NEON(const uint8* src_y, > ); > } > >-void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { >+void I400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) { > asm volatile ( > YUVTORGB_SETUP > "movi v23.8b, #255 \n" >@@ -392,7 +392,7 @@ void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { > ); > } > >-void J400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { >+void J400ToARGBRow_NEON(const uint8_t* src_y, uint8_t* dst_argb, int width) { > asm volatile( > "movi v23.8b, #255 \n" > "1: \n" >@@ -409,9 +409,9 @@ void J400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int width) { > : "cc", "memory", "v20", "v21", "v22", "v23"); > } > >-void NV12ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_argb, >+void NV12ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -436,9 +436,9 @@ void NV12ToARGBRow_NEON(const uint8* src_y, > ); > } > >-void NV21ToARGBRow_NEON(const uint8* src_y, >- const uint8* src_vu, >- uint8* dst_argb, >+void NV21ToARGBRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -463,9 +463,61 @@ void NV21ToARGBRow_NEON(const uint8* src_y, > ); > } > >-void NV12ToRGB565Row_NEON(const uint8* src_y, >- const uint8* src_uv, >- uint8* dst_rgb565, >+void NV12ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP >+ "1: \n" >+ READNV12 >+ YUVTORGB(v22, v21, v20) >+ "subs %w3, %w3, #8 \n" >+ "st3 {v20.8b,v21.8b,v22.8b}, [%2], #24 \n" >+ "b.gt 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_uv), // %1 >+ "+r"(dst_rgb24), // %2 >+ "+r"(width) // %3 >+ : [kUVToRB]"r"(&yuvconstants->kUVToRB), >+ [kUVToG]"r"(&yuvconstants->kUVToG), >+ [kUVBiasBGR]"r"(&yuvconstants->kUVBiasBGR), >+ [kYToRgb]"r"(&yuvconstants->kYToRgb) >+ : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20", >+ "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30" >+ ); >+} >+ >+void NV21ToRGB24Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_vu, >+ uint8_t* dst_rgb24, >+ const struct YuvConstants* yuvconstants, >+ int width) { >+ asm volatile ( >+ YUVTORGB_SETUP >+ "1: \n" >+ READNV21 >+ YUVTORGB(v22, v21, v20) >+ "subs %w3, %w3, #8 \n" >+ "st3 {v20.8b,v21.8b,v22.8b}, [%2], #24 \n" >+ "b.gt 1b \n" >+ : "+r"(src_y), // %0 >+ "+r"(src_vu), // %1 >+ "+r"(dst_rgb24), // %2 >+ "+r"(width) // %3 >+ : [kUVToRB]"r"(&yuvconstants->kUVToRB), >+ [kUVToG]"r"(&yuvconstants->kUVToG), >+ [kUVBiasBGR]"r"(&yuvconstants->kUVBiasBGR), >+ [kYToRgb]"r"(&yuvconstants->kYToRgb) >+ : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20", >+ "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30" >+ ); >+} >+ >+void NV12ToRGB565Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_uv, >+ uint8_t* dst_rgb565, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile( >@@ -488,8 +540,8 @@ void NV12ToRGB565Row_NEON(const uint8* src_y, > "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30"); > } > >-void YUY2ToARGBRow_NEON(const uint8* src_yuy2, >- uint8* dst_argb, >+void YUY2ToARGBRow_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -513,8 +565,8 @@ void YUY2ToARGBRow_NEON(const uint8* src_yuy2, > ); > } > >-void UYVYToARGBRow_NEON(const uint8* src_uyvy, >- uint8* dst_argb, >+void UYVYToARGBRow_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > asm volatile ( >@@ -539,9 +591,9 @@ void UYVYToARGBRow_NEON(const uint8* src_uyvy, > } > > // Reads 16 pairs of UV and write even values to dst_u and odd to dst_v. >-void SplitUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void SplitUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -560,9 +612,9 @@ void SplitUVRow_NEON(const uint8* src_uv, > } > > // Reads 16 U's and V's and writes out 16 pairs of UV. >-void MergeUVRow_NEON(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+void MergeUVRow_NEON(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > asm volatile( > "1: \n" >@@ -581,10 +633,10 @@ void MergeUVRow_NEON(const uint8* src_u, > } > > // Reads 16 packed RGB and write to planar dst_r, dst_g, dst_b. >-void SplitRGBRow_NEON(const uint8* src_rgb, >- uint8* dst_r, >- uint8* dst_g, >- uint8* dst_b, >+void SplitRGBRow_NEON(const uint8_t* src_rgb, >+ uint8_t* dst_r, >+ uint8_t* dst_g, >+ uint8_t* dst_b, > int width) { > asm volatile( > "1: \n" >@@ -605,10 +657,10 @@ void SplitRGBRow_NEON(const uint8* src_rgb, > } > > // Reads 16 planar R's, G's and B's and writes out 16 packed RGB at a time >-void MergeRGBRow_NEON(const uint8* src_r, >- const uint8* src_g, >- const uint8* src_b, >- uint8* dst_rgb, >+void MergeRGBRow_NEON(const uint8_t* src_r, >+ const uint8_t* src_g, >+ const uint8_t* src_b, >+ uint8_t* dst_rgb, > int width) { > asm volatile( > "1: \n" >@@ -629,7 +681,7 @@ void MergeRGBRow_NEON(const uint8* src_r, > } > > // Copy multiple of 32. >-void CopyRow_NEON(const uint8* src, uint8* dst, int count) { >+void CopyRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > "1: \n" > "ldp q0, q1, [%0], #32 \n" >@@ -638,14 +690,14 @@ void CopyRow_NEON(const uint8* src, uint8* dst, int count) { > "b.gt 1b \n" > : "+r"(src), // %0 > "+r"(dst), // %1 >- "+r"(count) // %2 // Output registers >+ "+r"(width) // %2 // Output registers > : // Input registers > : "cc", "memory", "v0", "v1" // Clobber List > ); > } > >-// SetRow writes 'count' bytes using an 8 bit value repeated. >-void SetRow_NEON(uint8* dst, uint8 v8, int count) { >+// SetRow writes 'width' bytes using an 8 bit value repeated. >+void SetRow_NEON(uint8_t* dst, uint8_t v8, int width) { > asm volatile( > "dup v0.16b, %w2 \n" // duplicate 16 bytes > "1: \n" >@@ -653,12 +705,12 @@ void SetRow_NEON(uint8* dst, uint8 v8, int count) { > "st1 {v0.16b}, [%0], #16 \n" // store > "b.gt 1b \n" > : "+r"(dst), // %0 >- "+r"(count) // %1 >+ "+r"(width) // %1 > : "r"(v8) // %2 > : "cc", "memory", "v0"); > } > >-void ARGBSetRow_NEON(uint8* dst, uint32 v32, int count) { >+void ARGBSetRow_NEON(uint8_t* dst, uint32_t v32, int width) { > asm volatile( > "dup v0.4s, %w2 \n" // duplicate 4 ints > "1: \n" >@@ -666,12 +718,12 @@ void ARGBSetRow_NEON(uint8* dst, uint32 v32, int count) { > "st1 {v0.16b}, [%0], #16 \n" // store > "b.gt 1b \n" > : "+r"(dst), // %0 >- "+r"(count) // %1 >+ "+r"(width) // %1 > : "r"(v32) // %2 > : "cc", "memory", "v0"); > } > >-void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { >+void MirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > // Start at end of source row. > "add %0, %0, %w2, sxtw \n" >@@ -690,9 +742,9 @@ void MirrorRow_NEON(const uint8* src, uint8* dst, int width) { > : "cc", "memory", "v0"); > } > >-void MirrorUVRow_NEON(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+void MirrorUVRow_NEON(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > // Start at end of source row. >@@ -714,7 +766,7 @@ void MirrorUVRow_NEON(const uint8* src_uv, > : "cc", "memory", "v0", "v1"); > } > >-void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) { >+void ARGBMirrorRow_NEON(const uint8_t* src, uint8_t* dst, int width) { > asm volatile( > // Start at end of source row. > "add %0, %0, %w2, sxtw #2 \n" >@@ -733,7 +785,9 @@ void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) { > : "cc", "memory", "v0"); > } > >-void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int width) { >+void RGB24ToARGBRow_NEON(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > "movi v4.8b, #255 \n" // Alpha > "1: \n" >@@ -749,7 +803,7 @@ void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int width) { > ); > } > >-void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int width) { >+void RAWToARGBRow_NEON(const uint8_t* src_raw, uint8_t* dst_argb, int width) { > asm volatile( > "movi v5.8b, #255 \n" // Alpha > "1: \n" >@@ -767,7 +821,7 @@ void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int width) { > ); > } > >-void RAWToRGB24Row_NEON(const uint8* src_raw, uint8* dst_rgb24, int width) { >+void RAWToRGB24Row_NEON(const uint8_t* src_raw, uint8_t* dst_rgb24, int width) { > asm volatile( > "1: \n" > "ld3 {v0.8b,v1.8b,v2.8b}, [%0], #24 \n" // read r g b >@@ -797,7 +851,9 @@ void RAWToRGB24Row_NEON(const uint8* src_raw, uint8* dst_rgb24, int width) { > "orr v0.16b, v0.16b, v2.16b \n" /* R,B */ \ > "dup v2.2D, v0.D[1] \n" /* R */ > >-void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int width) { >+void RGB565ToARGBRow_NEON(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > "movi v3.8b, #255 \n" // Alpha > "1: \n" >@@ -851,8 +907,8 @@ void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int width) { > "orr v2.16b, v1.16b, v3.16b \n" /* R */ \ > "dup v1.2D, v0.D[1] \n" /* G */ > >-void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, >- uint8* dst_argb, >+void ARGB1555ToARGBRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "movi v3.8b, #255 \n" // Alpha >@@ -883,8 +939,8 @@ void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, > "dup v0.2D, v2.D[1] \n" \ > "dup v1.2D, v3.D[1] \n" > >-void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, >- uint8* dst_argb, >+void ARGB4444ToARGBRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "1: \n" >@@ -902,7 +958,9 @@ void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, > ); > } > >-void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int width) { >+void ARGBToRGB24Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb24, >+ int width) { > asm volatile( > "1: \n" > "ld4 {v1.8b,v2.8b,v3.8b,v4.8b}, [%0], #32 \n" // load 8 ARGB >@@ -918,7 +976,7 @@ void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int width) { > ); > } > >-void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int width) { >+void ARGBToRAWRow_NEON(const uint8_t* src_argb, uint8_t* dst_raw, int width) { > asm volatile( > "1: \n" > "ld4 {v1.8b,v2.8b,v3.8b,v4.8b}, [%0], #32 \n" // load b g r a >@@ -935,7 +993,7 @@ void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int width) { > ); > } > >-void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int width) { >+void YUY2ToYRow_NEON(const uint8_t* src_yuy2, uint8_t* dst_y, int width) { > asm volatile( > "1: \n" > "ld2 {v0.16b,v1.16b}, [%0], #32 \n" // load 16 pixels of YUY2. >@@ -950,7 +1008,7 @@ void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int width) { > ); > } > >-void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int width) { >+void UYVYToYRow_NEON(const uint8_t* src_uyvy, uint8_t* dst_y, int width) { > asm volatile( > "1: \n" > "ld2 {v0.16b,v1.16b}, [%0], #32 \n" // load 16 pixels of UYVY. >@@ -965,9 +1023,9 @@ void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int width) { > ); > } > >-void YUY2ToUV422Row_NEON(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+void YUY2ToUV422Row_NEON(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -985,9 +1043,9 @@ void YUY2ToUV422Row_NEON(const uint8* src_yuy2, > ); > } > >-void UYVYToUV422Row_NEON(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+void UYVYToUV422Row_NEON(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "1: \n" >@@ -1005,12 +1063,12 @@ void UYVYToUV422Row_NEON(const uint8* src_uyvy, > ); > } > >-void YUY2ToUVRow_NEON(const uint8* src_yuy2, >+void YUY2ToUVRow_NEON(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_yuy2b = src_yuy2 + stride_yuy2; >+ const uint8_t* src_yuy2b = src_yuy2 + stride_yuy2; > asm volatile( > "1: \n" > "ld4 {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n" // load 16 pixels >@@ -1032,12 +1090,12 @@ void YUY2ToUVRow_NEON(const uint8* src_yuy2, > ); > } > >-void UYVYToUVRow_NEON(const uint8* src_uyvy, >+void UYVYToUVRow_NEON(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_uyvyb = src_uyvy + stride_uyvy; >+ const uint8_t* src_uyvyb = src_uyvy + stride_uyvy; > asm volatile( > "1: \n" > "ld4 {v0.8b,v1.8b,v2.8b,v3.8b}, [%0], #32 \n" // load 16 pixels >@@ -1060,9 +1118,9 @@ void UYVYToUVRow_NEON(const uint8* src_uyvy, > } > > // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-void ARGBShuffleRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+void ARGBShuffleRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > asm volatile( > "ld1 {v2.16b}, [%3] \n" // shuffler >@@ -1080,10 +1138,10 @@ void ARGBShuffleRow_NEON(const uint8* src_argb, > ); > } > >-void I422ToYUY2Row_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_yuy2, >+void I422ToYUY2Row_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_yuy2, > int width) { > asm volatile( > "1: \n" >@@ -1103,10 +1161,10 @@ void I422ToYUY2Row_NEON(const uint8* src_y, > : "cc", "memory", "v0", "v1", "v2", "v3"); > } > >-void I422ToUYVYRow_NEON(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uyvy, >+void I422ToUYVYRow_NEON(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uyvy, > int width) { > asm volatile( > "1: \n" >@@ -1126,7 +1184,9 @@ void I422ToUYVYRow_NEON(const uint8* src_y, > : "cc", "memory", "v0", "v1", "v2", "v3"); > } > >-void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int width) { >+void ARGBToRGB565Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb565, >+ int width) { > asm volatile( > "1: \n" > "ld4 {v20.8b,v21.8b,v22.8b,v23.8b}, [%0], #32 \n" // load 8 pixels >@@ -1141,9 +1201,9 @@ void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int width) { > : "cc", "memory", "v0", "v20", "v21", "v22", "v23"); > } > >-void ARGBToRGB565DitherRow_NEON(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+void ARGBToRGB565DitherRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width) { > asm volatile( > "dup v1.4s, %w2 \n" // dither4 >@@ -1162,8 +1222,8 @@ void ARGBToRGB565DitherRow_NEON(const uint8* src_argb, > : "cc", "memory", "v0", "v1", "v20", "v21", "v22", "v23"); > } > >-void ARGBToARGB1555Row_NEON(const uint8* src_argb, >- uint8* dst_argb1555, >+void ARGBToARGB1555Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb1555, > int width) { > asm volatile( > "1: \n" >@@ -1180,8 +1240,8 @@ void ARGBToARGB1555Row_NEON(const uint8* src_argb, > : "cc", "memory", "v0", "v20", "v21", "v22", "v23"); > } > >-void ARGBToARGB4444Row_NEON(const uint8* src_argb, >- uint8* dst_argb4444, >+void ARGBToARGB4444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb4444, > int width) { > asm volatile( > "movi v4.16b, #0x0f \n" // bits to clear with >@@ -1200,7 +1260,7 @@ void ARGBToARGB4444Row_NEON(const uint8* src_argb, > : "cc", "memory", "v0", "v1", "v4", "v20", "v21", "v22", "v23"); > } > >-void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { >+void ARGBToYRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #13 \n" // B * 0.1016 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1223,7 +1283,9 @@ void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"); > } > >-void ARGBExtractAlphaRow_NEON(const uint8* src_argb, uint8* dst_a, int width) { >+void ARGBExtractAlphaRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_a, >+ int width) { > asm volatile( > "1: \n" > "ld4 {v0.16b,v1.16b,v2.16b,v3.16b}, [%0], #64 \n" // load row 16 >@@ -1239,7 +1301,7 @@ void ARGBExtractAlphaRow_NEON(const uint8* src_argb, uint8* dst_a, int width) { > ); > } > >-void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { >+void ARGBToYJRow_NEON(const uint8_t* src_argb, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #15 \n" // B * 0.11400 coefficient > "movi v5.8b, #75 \n" // G * 0.58700 coefficient >@@ -1261,9 +1323,9 @@ void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int width) { > } > > // 8x1 pixels. >-void ARGBToUV444Row_NEON(const uint8* src_argb, >- uint8* dst_u, >- uint8* dst_v, >+void ARGBToUV444Row_NEON(const uint8_t* src_argb, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > asm volatile( > "movi v24.8b, #112 \n" // UB / VR 0.875 >@@ -1328,12 +1390,12 @@ void ARGBToUV444Row_NEON(const uint8* src_argb, > // TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr. > // TODO(fbarchard): consider ptrdiff_t for all strides. > >-void ARGBToUVRow_NEON(const uint8* src_argb, >+void ARGBToUVRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_argb_1 = src_argb + src_stride_argb; >+ const uint8_t* src_argb_1 = src_argb + src_stride_argb; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1368,12 +1430,12 @@ void ARGBToUVRow_NEON(const uint8* src_argb, > } > > // TODO(fbarchard): Subsample match C code. >-void ARGBToUVJRow_NEON(const uint8* src_argb, >+void ARGBToUVJRow_NEON(const uint8_t* src_argb, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_argb_1 = src_argb + src_stride_argb; >+ const uint8_t* src_argb_1 = src_argb + src_stride_argb; > asm volatile ( > "movi v20.8h, #63, lsl #0 \n" // UB/VR coeff (0.500) / 2 > "movi v21.8h, #42, lsl #0 \n" // UG coeff (-0.33126) / 2 >@@ -1411,12 +1473,12 @@ void ARGBToUVJRow_NEON(const uint8* src_argb, > ); > } > >-void BGRAToUVRow_NEON(const uint8* src_bgra, >+void BGRAToUVRow_NEON(const uint8_t* src_bgra, > int src_stride_bgra, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_bgra_1 = src_bgra + src_stride_bgra; >+ const uint8_t* src_bgra_1 = src_bgra + src_stride_bgra; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1449,12 +1511,12 @@ void BGRAToUVRow_NEON(const uint8* src_bgra, > ); > } > >-void ABGRToUVRow_NEON(const uint8* src_abgr, >+void ABGRToUVRow_NEON(const uint8_t* src_abgr, > int src_stride_abgr, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_abgr_1 = src_abgr + src_stride_abgr; >+ const uint8_t* src_abgr_1 = src_abgr + src_stride_abgr; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1487,12 +1549,12 @@ void ABGRToUVRow_NEON(const uint8* src_abgr, > ); > } > >-void RGBAToUVRow_NEON(const uint8* src_rgba, >+void RGBAToUVRow_NEON(const uint8_t* src_rgba, > int src_stride_rgba, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_rgba_1 = src_rgba + src_stride_rgba; >+ const uint8_t* src_rgba_1 = src_rgba + src_stride_rgba; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1525,12 +1587,12 @@ void RGBAToUVRow_NEON(const uint8* src_rgba, > ); > } > >-void RGB24ToUVRow_NEON(const uint8* src_rgb24, >+void RGB24ToUVRow_NEON(const uint8_t* src_rgb24, > int src_stride_rgb24, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_rgb24_1 = src_rgb24 + src_stride_rgb24; >+ const uint8_t* src_rgb24_1 = src_rgb24 + src_stride_rgb24; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1563,12 +1625,12 @@ void RGB24ToUVRow_NEON(const uint8* src_rgb24, > ); > } > >-void RAWToUVRow_NEON(const uint8* src_raw, >+void RAWToUVRow_NEON(const uint8_t* src_raw, > int src_stride_raw, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_raw_1 = src_raw + src_stride_raw; >+ const uint8_t* src_raw_1 = src_raw + src_stride_raw; > asm volatile ( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1602,12 +1664,12 @@ void RAWToUVRow_NEON(const uint8* src_raw, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void RGB565ToUVRow_NEON(const uint8* src_rgb565, >+void RGB565ToUVRow_NEON(const uint8_t* src_rgb565, > int src_stride_rgb565, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_rgb565_1 = src_rgb565 + src_stride_rgb565; >+ const uint8_t* src_rgb565_1 = src_rgb565 + src_stride_rgb565; > asm volatile( > "movi v22.8h, #56, lsl #0 \n" // UB / VR coeff (0.875) / > // 2 >@@ -1673,12 +1735,12 @@ void RGB565ToUVRow_NEON(const uint8* src_rgb565, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, >+void ARGB1555ToUVRow_NEON(const uint8_t* src_argb1555, > int src_stride_argb1555, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_argb1555_1 = src_argb1555 + src_stride_argb1555; >+ const uint8_t* src_argb1555_1 = src_argb1555 + src_stride_argb1555; > asm volatile( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1738,12 +1800,12 @@ void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, > } > > // 16x2 pixels -> 8x1. width is number of argb pixels. e.g. 16. >-void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, >+void ARGB4444ToUVRow_NEON(const uint8_t* src_argb4444, > int src_stride_argb4444, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { >- const uint8* src_argb4444_1 = src_argb4444 + src_stride_argb4444; >+ const uint8_t* src_argb4444_1 = src_argb4444 + src_stride_argb4444; > asm volatile( > RGBTOUV_SETUP_REG > "1: \n" >@@ -1804,7 +1866,7 @@ void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, > ); > } > >-void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int width) { >+void RGB565ToYRow_NEON(const uint8_t* src_rgb565, uint8_t* dst_y, int width) { > asm volatile( > "movi v24.8b, #13 \n" // B * 0.1016 coefficient > "movi v25.8b, #65 \n" // G * 0.5078 coefficient >@@ -1829,7 +1891,9 @@ void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int width) { > "v27"); > } > >-void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int width) { >+void ARGB1555ToYRow_NEON(const uint8_t* src_argb1555, >+ uint8_t* dst_y, >+ int width) { > asm volatile( > "movi v4.8b, #13 \n" // B * 0.1016 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1853,7 +1917,9 @@ void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"); > } > >-void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int width) { >+void ARGB4444ToYRow_NEON(const uint8_t* src_argb4444, >+ uint8_t* dst_y, >+ int width) { > asm volatile( > "movi v24.8b, #13 \n" // B * 0.1016 coefficient > "movi v25.8b, #65 \n" // G * 0.5078 coefficient >@@ -1877,7 +1943,7 @@ void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v24", "v25", "v26", "v27"); > } > >-void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int width) { >+void BGRAToYRow_NEON(const uint8_t* src_bgra, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #33 \n" // R * 0.2578 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1900,7 +1966,7 @@ void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16"); > } > >-void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int width) { >+void ABGRToYRow_NEON(const uint8_t* src_abgr, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #33 \n" // R * 0.2578 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1923,7 +1989,7 @@ void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16"); > } > >-void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int width) { >+void RGBAToYRow_NEON(const uint8_t* src_rgba, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #13 \n" // B * 0.1016 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1946,7 +2012,7 @@ void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16"); > } > >-void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int width) { >+void RGB24ToYRow_NEON(const uint8_t* src_rgb24, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #13 \n" // B * 0.1016 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1969,7 +2035,7 @@ void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int width) { > : "cc", "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16"); > } > >-void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int width) { >+void RAWToYRow_NEON(const uint8_t* src_raw, uint8_t* dst_y, int width) { > asm volatile( > "movi v4.8b, #33 \n" // R * 0.2578 coefficient > "movi v5.8b, #65 \n" // G * 0.5078 coefficient >@@ -1993,14 +2059,14 @@ void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int width) { > } > > // Bilinear filter 16x2 -> 16x1 >-void InterpolateRow_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void InterpolateRow_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { > int y1_fraction = source_y_fraction; > int y0_fraction = 256 - y1_fraction; >- const uint8* src_ptr1 = src_ptr + src_stride; >+ const uint8_t* src_ptr1 = src_ptr + src_stride; > asm volatile( > "cmp %w4, #0 \n" > "b.eq 100f \n" >@@ -2053,9 +2119,9 @@ void InterpolateRow_NEON(uint8* dst_ptr, > } > > // dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr >-void ARGBBlendRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBBlendRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "subs %w3, %w3, #8 \n" >@@ -2121,7 +2187,9 @@ void ARGBBlendRow_NEON(const uint8* src_argb0, > } > > // Attenuate 8 pixels at a time. >-void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBAttenuateRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ int width) { > asm volatile( > // Attenuate 8 pixels. > "1: \n" >@@ -2145,7 +2213,7 @@ void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { > > // Quantize 8 ARGB pixels (32 bytes). > // dst = (dst * scale >> 16) * interval_size + interval_offset; >-void ARGBQuantizeRow_NEON(uint8* dst_argb, >+void ARGBQuantizeRow_NEON(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, >@@ -2188,10 +2256,10 @@ void ARGBQuantizeRow_NEON(uint8* dst_argb, > // Shade 8 pixels at a time by specified value. > // NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8. > // Rounding in vqrdmulh does +1 to high if high bit of low s16 is set. >-void ARGBShadeRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >+void ARGBShadeRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >+ uint32_t value) { > asm volatile( > "dup v0.4s, %w3 \n" // duplicate scale value. > "zip1 v0.8b, v0.8b, v0.8b \n" // v0.8b aarrggbb. >@@ -2225,7 +2293,7 @@ void ARGBShadeRow_NEON(const uint8* src_argb, > // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels > // Similar to ARGBToYJ but stores ARGB. > // C code is (15 * b + 75 * g + 38 * r + 64) >> 7; >-void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { >+void ARGBGrayRow_NEON(const uint8_t* src_argb, uint8_t* dst_argb, int width) { > asm volatile( > "movi v24.8b, #15 \n" // B * 0.11400 coefficient > "movi v25.8b, #75 \n" // G * 0.58700 coefficient >@@ -2253,7 +2321,7 @@ void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) { > // g = (r * 45 + g * 88 + b * 22) >> 7 > // r = (r * 50 + g * 98 + b * 24) >> 7 > >-void ARGBSepiaRow_NEON(uint8* dst_argb, int width) { >+void ARGBSepiaRow_NEON(uint8_t* dst_argb, int width) { > asm volatile( > "movi v20.8b, #17 \n" // BB coefficient > "movi v21.8b, #68 \n" // BG coefficient >@@ -2291,9 +2359,9 @@ void ARGBSepiaRow_NEON(uint8* dst_argb, int width) { > // Tranform 8 ARGB pixels (32 bytes) with color matrix. > // TODO(fbarchard): Was same as Sepia except matrix is provided. This function > // needs to saturate. Consider doing a non-saturating version. >-void ARGBColorMatrixRow_NEON(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+void ARGBColorMatrixRow_NEON(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { > asm volatile( > "ld1 {v2.16b}, [%3] \n" // load 3 ARGB vectors. >@@ -2351,9 +2419,9 @@ void ARGBColorMatrixRow_NEON(const uint8* src_argb, > > // TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable. > // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. >-void ARGBMultiplyRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBMultiplyRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2380,9 +2448,9 @@ void ARGBMultiplyRow_NEON(const uint8* src_argb0, > } > > // Add 2 rows of ARGB pixels together, 8 pixels at a time. >-void ARGBAddRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBAddRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2405,9 +2473,9 @@ void ARGBAddRow_NEON(const uint8* src_argb0, > } > > // Subtract 2 rows of ARGB pixels, 8 pixels at a time. >-void ARGBSubtractRow_NEON(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+void ARGBSubtractRow_NEON(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > asm volatile( > // 8 pixel loop. >@@ -2434,9 +2502,9 @@ void ARGBSubtractRow_NEON(const uint8* src_argb0, > // R = Sobel > // G = Sobel > // B = Sobel >-void SobelRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "movi v3.8b, #255 \n" // alpha >@@ -2459,9 +2527,9 @@ void SobelRow_NEON(const uint8* src_sobelx, > } > > // Adds Sobel X and Sobel Y and stores Sobel into plane. >-void SobelToPlaneRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+void SobelToPlaneRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { > asm volatile( > // 16 pixel loop. >@@ -2485,9 +2553,9 @@ void SobelToPlaneRow_NEON(const uint8* src_sobelx, > // R = Sobel X > // G = Sobel > // B = Sobel Y >-void SobelXYRow_NEON(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+void SobelXYRow_NEON(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > asm volatile( > "movi v3.8b, #255 \n" // alpha >@@ -2511,10 +2579,10 @@ void SobelXYRow_NEON(const uint8* src_sobelx, > // -1 0 1 > // -2 0 2 > // -1 0 1 >-void SobelXRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+void SobelXRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width) { > asm volatile( > "1: \n" >@@ -2550,9 +2618,9 @@ void SobelXRow_NEON(const uint8* src_y0, > // -1 -2 -1 > // 0 0 0 > // 1 2 1 >-void SobelYRow_NEON(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+void SobelYRow_NEON(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width) { > asm volatile( > "1: \n" >@@ -2584,7 +2652,10 @@ void SobelYRow_NEON(const uint8* src_y0, > } > > // Caveat - rounds float to half float whereas scaling version truncates. >-void HalfFloat1Row_NEON(const uint16* src, uint16* dst, float, int width) { >+void HalfFloat1Row_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float /*unused*/, >+ int width) { > asm volatile( > "1: \n" > "ld1 {v1.16b}, [%0], #16 \n" // load 8 shorts >@@ -2604,7 +2675,10 @@ void HalfFloat1Row_NEON(const uint16* src, uint16* dst, float, int width) { > : "cc", "memory", "v1", "v2", "v3"); > } > >-void HalfFloatRow_NEON(const uint16* src, uint16* dst, float scale, int width) { >+void HalfFloatRow_NEON(const uint16_t* src, >+ uint16_t* dst, >+ float scale, >+ int width) { > asm volatile( > "1: \n" > "ld1 {v1.16b}, [%0], #16 \n" // load 8 shorts >@@ -2626,6 +2700,30 @@ void HalfFloatRow_NEON(const uint16* src, uint16* dst, float scale, int width) { > : "cc", "memory", "v1", "v2", "v3"); > } > >+void ByteToFloatRow_NEON(const uint8_t* src, >+ float* dst, >+ float scale, >+ int width) { >+ asm volatile( >+ "1: \n" >+ "ld1 {v1.8b}, [%0], #8 \n" // load 8 bytes >+ "subs %w2, %w2, #8 \n" // 8 pixels per loop >+ "uxtl v1.8h, v1.8b \n" // 8 shorts >+ "uxtl v2.4s, v1.4h \n" // 8 ints >+ "uxtl2 v3.4s, v1.8h \n" >+ "scvtf v2.4s, v2.4s \n" // 8 floats >+ "scvtf v3.4s, v3.4s \n" >+ "fmul v2.4s, v2.4s, %3.s[0] \n" // scale >+ "fmul v3.4s, v3.4s, %3.s[0] \n" >+ "st1 {v2.16b, v3.16b}, [%1], #32 \n" // store 8 floats >+ "b.gt 1b \n" >+ : "+r"(src), // %0 >+ "+r"(dst), // %1 >+ "+r"(width) // %2 >+ : "w"(scale) // %3 >+ : "cc", "memory", "v1", "v2", "v3"); >+} >+ > float ScaleMaxSamples_NEON(const float* src, > float* dst, > float scale, >@@ -2702,12 +2800,12 @@ void ScaleSamples_NEON(const float* src, float* dst, float scale, int width) { > } > > // filter 5 rows with 1, 4, 6, 4, 1 coefficients to produce 1 row. >-void GaussCol_NEON(const uint16* src0, >- const uint16* src1, >- const uint16* src2, >- const uint16* src3, >- const uint16* src4, >- uint32* dst, >+void GaussCol_NEON(const uint16_t* src0, >+ const uint16_t* src1, >+ const uint16_t* src2, >+ const uint16_t* src3, >+ const uint16_t* src4, >+ uint32_t* dst, > int width) { > asm volatile( > "movi v6.8h, #4 \n" // constant 4 >@@ -2742,10 +2840,10 @@ void GaussCol_NEON(const uint16* src0, > } > > // filter 5 rows with 1, 4, 6, 4, 1 coefficients to produce 1 row. >-void GaussRow_NEON(const uint32* src, uint16* dst, int width) { >- const uint32* src1 = src + 1; >- const uint32* src2 = src + 2; >- const uint32* src3 = src + 3; >+void GaussRow_NEON(const uint32_t* src, uint16_t* dst, int width) { >+ const uint32_t* src1 = src + 1; >+ const uint32_t* src2 = src + 2; >+ const uint32_t* src3 = src + 3; > asm volatile( > "movi v6.4s, #4 \n" // constant 4 > "movi v7.4s, #6 \n" // constant 6 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_win.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_win.cc >index 03a7e9506da..5500d7f5a64 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_win.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/row_win.cc >@@ -28,27 +28,27 @@ extern "C" { > #if defined(_M_X64) > > // Read 4 UV from 422, upsample to 8 UV. >-#define READYUV422 \ >- xmm0 = _mm_cvtsi32_si128(*(uint32*)u_buf); \ >- xmm1 = _mm_cvtsi32_si128(*(uint32*)(u_buf + offset)); \ >- xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \ >- xmm0 = _mm_unpacklo_epi16(xmm0, xmm0); \ >- u_buf += 4; \ >- xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \ >- xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \ >+#define READYUV422 \ >+ xmm0 = _mm_cvtsi32_si128(*(uint32_t*)u_buf); \ >+ xmm1 = _mm_cvtsi32_si128(*(uint32_t*)(u_buf + offset)); \ >+ xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \ >+ xmm0 = _mm_unpacklo_epi16(xmm0, xmm0); \ >+ u_buf += 4; \ >+ xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \ >+ xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \ > y_buf += 8; > > // Read 4 UV from 422, upsample to 8 UV. With 8 Alpha. >-#define READYUVA422 \ >- xmm0 = _mm_cvtsi32_si128(*(uint32*)u_buf); \ >- xmm1 = _mm_cvtsi32_si128(*(uint32*)(u_buf + offset)); \ >- xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \ >- xmm0 = _mm_unpacklo_epi16(xmm0, xmm0); \ >- u_buf += 4; \ >- xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \ >- xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \ >- y_buf += 8; \ >- xmm5 = _mm_loadl_epi64((__m128i*)a_buf); \ >+#define READYUVA422 \ >+ xmm0 = _mm_cvtsi32_si128(*(uint32_t*)u_buf); \ >+ xmm1 = _mm_cvtsi32_si128(*(uint32_t*)(u_buf + offset)); \ >+ xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \ >+ xmm0 = _mm_unpacklo_epi16(xmm0, xmm0); \ >+ u_buf += 4; \ >+ xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \ >+ xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \ >+ y_buf += 8; \ >+ xmm5 = _mm_loadl_epi64((__m128i*)a_buf); \ > a_buf += 8; > > // Convert 8 pixels: 8 UV and 8 Y. >@@ -84,15 +84,15 @@ extern "C" { > dst_argb += 32; > > #if defined(HAS_I422TOARGBROW_SSSE3) >-void I422ToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+void I422ToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __m128i xmm0, xmm1, xmm2, xmm4; > const __m128i xmm5 = _mm_set1_epi8(-1); >- const ptrdiff_t offset = (uint8*)v_buf - (uint8*)u_buf; >+ const ptrdiff_t offset = (uint8_t*)v_buf - (uint8_t*)u_buf; > while (width > 0) { > READYUV422 > YUVTORGB(yuvconstants) >@@ -103,15 +103,15 @@ void I422ToARGBRow_SSSE3(const uint8* y_buf, > #endif > > #if defined(HAS_I422ALPHATOARGBROW_SSSE3) >-void I422AlphaToARGBRow_SSSE3(const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+void I422AlphaToARGBRow_SSSE3(const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __m128i xmm0, xmm1, xmm2, xmm4, xmm5; >- const ptrdiff_t offset = (uint8*)v_buf - (uint8*)u_buf; >+ const ptrdiff_t offset = (uint8_t*)v_buf - (uint8_t*)u_buf; > while (width > 0) { > READYUVA422 > YUVTORGB(yuvconstants) >@@ -255,8 +255,8 @@ static const lvec8 kShuffleNV21 = { > }; > > // Duplicates gray value 3 times and fills in alpha opaque. >-__declspec(naked) void J400ToARGBRow_SSE2(const uint8* src_y, >- uint8* dst_argb, >+__declspec(naked) void J400ToARGBRow_SSE2(const uint8_t* src_y, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_y >@@ -285,8 +285,8 @@ __declspec(naked) void J400ToARGBRow_SSE2(const uint8* src_y, > > #ifdef HAS_J400TOARGBROW_AVX2 > // Duplicates gray value 3 times and fills in alpha opaque. >-__declspec(naked) void J400ToARGBRow_AVX2(const uint8* src_y, >- uint8* dst_argb, >+__declspec(naked) void J400ToARGBRow_AVX2(const uint8_t* src_y, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_y >@@ -316,8 +316,8 @@ __declspec(naked) void J400ToARGBRow_AVX2(const uint8* src_y, > } > #endif // HAS_J400TOARGBROW_AVX2 > >-__declspec(naked) void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, >- uint8* dst_argb, >+__declspec(naked) void RGB24ToARGBRow_SSSE3(const uint8_t* src_rgb24, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_rgb24 >@@ -355,8 +355,8 @@ __declspec(naked) void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, > } > } > >-__declspec(naked) void RAWToARGBRow_SSSE3(const uint8* src_raw, >- uint8* dst_argb, >+__declspec(naked) void RAWToARGBRow_SSSE3(const uint8_t* src_raw, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_raw >@@ -394,8 +394,8 @@ __declspec(naked) void RAWToARGBRow_SSSE3(const uint8* src_raw, > } > } > >-__declspec(naked) void RAWToRGB24Row_SSSE3(const uint8* src_raw, >- uint8* dst_rgb24, >+__declspec(naked) void RAWToRGB24Row_SSSE3(const uint8_t* src_raw, >+ uint8_t* dst_rgb24, > int width) { > __asm { > mov eax, [esp + 4] // src_raw >@@ -430,8 +430,8 @@ __declspec(naked) void RAWToRGB24Row_SSSE3(const uint8* src_raw, > // v * (256 + 8) > // G shift of 5 is incorporated, so shift is 5 + 8 and 5 + 3 > // 20 instructions. >-__declspec(naked) void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, >- uint8* dst_argb, >+__declspec(naked) void RGB565ToARGBRow_SSE2(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x01080108 // generate multiplier to repeat 5 bits >@@ -486,8 +486,8 @@ __declspec(naked) void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, > // v * 256 + v * 8 > // v * (256 + 8) > // G shift of 5 is incorporated, so shift is 5 + 8 and 5 + 3 >-__declspec(naked) void RGB565ToARGBRow_AVX2(const uint8* src_rgb565, >- uint8* dst_argb, >+__declspec(naked) void RGB565ToARGBRow_AVX2(const uint8_t* src_rgb565, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x01080108 // generate multiplier to repeat 5 bits >@@ -537,8 +537,8 @@ __declspec(naked) void RGB565ToARGBRow_AVX2(const uint8* src_rgb565, > #endif // HAS_RGB565TOARGBROW_AVX2 > > #ifdef HAS_ARGB1555TOARGBROW_AVX2 >-__declspec(naked) void ARGB1555ToARGBRow_AVX2(const uint8* src_argb1555, >- uint8* dst_argb, >+__declspec(naked) void ARGB1555ToARGBRow_AVX2(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x01080108 // generate multiplier to repeat 5 bits >@@ -589,8 +589,8 @@ __declspec(naked) void ARGB1555ToARGBRow_AVX2(const uint8* src_argb1555, > #endif // HAS_ARGB1555TOARGBROW_AVX2 > > #ifdef HAS_ARGB4444TOARGBROW_AVX2 >-__declspec(naked) void ARGB4444ToARGBRow_AVX2(const uint8* src_argb4444, >- uint8* dst_argb, >+__declspec(naked) void ARGB4444ToARGBRow_AVX2(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x0f0f0f0f // generate mask 0x0f0f0f0f >@@ -627,8 +627,8 @@ __declspec(naked) void ARGB4444ToARGBRow_AVX2(const uint8* src_argb4444, > #endif // HAS_ARGB4444TOARGBROW_AVX2 > > // 24 instructions >-__declspec(naked) void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, >- uint8* dst_argb, >+__declspec(naked) void ARGB1555ToARGBRow_SSE2(const uint8_t* src_argb1555, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x01080108 // generate multiplier to repeat 5 bits >@@ -680,8 +680,8 @@ __declspec(naked) void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, > } > > // 18 instructions. >-__declspec(naked) void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, >- uint8* dst_argb, >+__declspec(naked) void ARGB4444ToARGBRow_SSE2(const uint8_t* src_argb4444, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, 0x0f0f0f0f // generate mask 0x0f0f0f0f >@@ -718,8 +718,8 @@ __declspec(naked) void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, > } > } > >-__declspec(naked) void ARGBToRGB24Row_SSSE3(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToRGB24Row_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -757,8 +757,8 @@ __declspec(naked) void ARGBToRGB24Row_SSSE3(const uint8* src_argb, > } > } > >-__declspec(naked) void ARGBToRAWRow_SSSE3(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToRAWRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -796,8 +796,8 @@ __declspec(naked) void ARGBToRAWRow_SSSE3(const uint8* src_argb, > } > } > >-__declspec(naked) void ARGBToRGB565Row_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToRGB565Row_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -834,9 +834,9 @@ __declspec(naked) void ARGBToRGB565Row_SSE2(const uint8* src_argb, > } > } > >-__declspec(naked) void ARGBToRGB565DitherRow_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+__declspec(naked) void ARGBToRGB565DitherRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width) { > __asm { > >@@ -881,9 +881,9 @@ __declspec(naked) void ARGBToRGB565DitherRow_SSE2(const uint8* src_argb, > } > > #ifdef HAS_ARGBTORGB565DITHERROW_AVX2 >-__declspec(naked) void ARGBToRGB565DitherRow_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >- const uint32 dither4, >+__declspec(naked) void ARGBToRGB565DitherRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, >+ const uint32_t dither4, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -925,8 +925,8 @@ __declspec(naked) void ARGBToRGB565DitherRow_AVX2(const uint8* src_argb, > #endif // HAS_ARGBTORGB565DITHERROW_AVX2 > > // TODO(fbarchard): Improve sign extension/packing. >-__declspec(naked) void ARGBToARGB1555Row_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToARGB1555Row_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -967,8 +967,8 @@ __declspec(naked) void ARGBToARGB1555Row_SSE2(const uint8* src_argb, > } > } > >-__declspec(naked) void ARGBToARGB4444Row_SSE2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToARGB4444Row_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -998,8 +998,8 @@ __declspec(naked) void ARGBToARGB4444Row_SSE2(const uint8* src_argb, > } > > #ifdef HAS_ARGBTORGB565ROW_AVX2 >-__declspec(naked) void ARGBToRGB565Row_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToRGB565Row_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -1036,8 +1036,8 @@ __declspec(naked) void ARGBToRGB565Row_AVX2(const uint8* src_argb, > #endif // HAS_ARGBTORGB565ROW_AVX2 > > #ifdef HAS_ARGBTOARGB1555ROW_AVX2 >-__declspec(naked) void ARGBToARGB1555Row_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToARGB1555Row_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -1077,8 +1077,8 @@ __declspec(naked) void ARGBToARGB1555Row_AVX2(const uint8* src_argb, > #endif // HAS_ARGBTOARGB1555ROW_AVX2 > > #ifdef HAS_ARGBTOARGB4444ROW_AVX2 >-__declspec(naked) void ARGBToARGB4444Row_AVX2(const uint8* src_argb, >- uint8* dst_rgb, >+__declspec(naked) void ARGBToARGB4444Row_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_rgb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -1109,8 +1109,8 @@ __declspec(naked) void ARGBToARGB4444Row_AVX2(const uint8* src_argb, > #endif // HAS_ARGBTOARGB4444ROW_AVX2 > > // Convert 16 ARGB pixels (64 bytes) to 16 Y values. >-__declspec(naked) void ARGBToYRow_SSSE3(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void ARGBToYRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1145,8 +1145,8 @@ __declspec(naked) void ARGBToYRow_SSSE3(const uint8* src_argb, > > // Convert 16 ARGB pixels (64 bytes) to 16 YJ values. > // Same as ARGBToYRow but different coefficients, no add 16, but do rounding. >-__declspec(naked) void ARGBToYJRow_SSSE3(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void ARGBToYJRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1185,8 +1185,8 @@ __declspec(naked) void ARGBToYJRow_SSSE3(const uint8* src_argb, > static const lvec32 kPermdARGBToY_AVX = {0, 4, 1, 5, 2, 6, 3, 7}; > > // Convert 32 ARGB pixels (128 bytes) to 32 Y values. >-__declspec(naked) void ARGBToYRow_AVX2(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void ARGBToYRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1225,8 +1225,8 @@ __declspec(naked) void ARGBToYRow_AVX2(const uint8* src_argb, > > #ifdef HAS_ARGBTOYJROW_AVX2 > // Convert 32 ARGB pixels (128 bytes) to 32 Y values. >-__declspec(naked) void ARGBToYJRow_AVX2(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void ARGBToYJRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1265,8 +1265,8 @@ __declspec(naked) void ARGBToYJRow_AVX2(const uint8* src_argb, > } > #endif // HAS_ARGBTOYJROW_AVX2 > >-__declspec(naked) void BGRAToYRow_SSSE3(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void BGRAToYRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1299,8 +1299,8 @@ __declspec(naked) void BGRAToYRow_SSSE3(const uint8* src_argb, > } > } > >-__declspec(naked) void ABGRToYRow_SSSE3(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void ABGRToYRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1333,8 +1333,8 @@ __declspec(naked) void ABGRToYRow_SSSE3(const uint8* src_argb, > } > } > >-__declspec(naked) void RGBAToYRow_SSSE3(const uint8* src_argb, >- uint8* dst_y, >+__declspec(naked) void RGBAToYRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -1367,10 +1367,10 @@ __declspec(naked) void RGBAToYRow_SSSE3(const uint8* src_argb, > } > } > >-__declspec(naked) void ARGBToUVRow_SSSE3(const uint8* src_argb0, >+__declspec(naked) void ARGBToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1439,10 +1439,10 @@ __declspec(naked) void ARGBToUVRow_SSSE3(const uint8* src_argb0, > } > } > >-__declspec(naked) void ARGBToUVJRow_SSSE3(const uint8* src_argb0, >+__declspec(naked) void ARGBToUVJRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1513,10 +1513,10 @@ __declspec(naked) void ARGBToUVJRow_SSSE3(const uint8* src_argb0, > } > > #ifdef HAS_ARGBTOUVROW_AVX2 >-__declspec(naked) void ARGBToUVRow_AVX2(const uint8* src_argb0, >+__declspec(naked) void ARGBToUVRow_AVX2(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1581,10 +1581,10 @@ __declspec(naked) void ARGBToUVRow_AVX2(const uint8* src_argb0, > #endif // HAS_ARGBTOUVROW_AVX2 > > #ifdef HAS_ARGBTOUVJROW_AVX2 >-__declspec(naked) void ARGBToUVJRow_AVX2(const uint8* src_argb0, >+__declspec(naked) void ARGBToUVJRow_AVX2(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1649,9 +1649,9 @@ __declspec(naked) void ARGBToUVJRow_AVX2(const uint8* src_argb0, > } > #endif // HAS_ARGBTOUVJROW_AVX2 > >-__declspec(naked) void ARGBToUV444Row_SSSE3(const uint8* src_argb0, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void ARGBToUV444Row_SSSE3(const uint8_t* src_argb0, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -1707,10 +1707,10 @@ __declspec(naked) void ARGBToUV444Row_SSSE3(const uint8* src_argb0, > } > } > >-__declspec(naked) void BGRAToUVRow_SSSE3(const uint8* src_argb0, >+__declspec(naked) void BGRAToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1779,10 +1779,10 @@ __declspec(naked) void BGRAToUVRow_SSSE3(const uint8* src_argb0, > } > } > >-__declspec(naked) void ABGRToUVRow_SSSE3(const uint8* src_argb0, >+__declspec(naked) void ABGRToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -1851,10 +1851,10 @@ __declspec(naked) void ABGRToUVRow_SSSE3(const uint8* src_argb0, > } > } > >-__declspec(naked) void RGBAToUVRow_SSSE3(const uint8* src_argb0, >+__declspec(naked) void RGBAToUVRow_SSSE3(const uint8_t* src_argb0, > int src_stride_argb, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -2065,10 +2065,10 @@ __declspec(naked) void RGBAToUVRow_SSSE3(const uint8* src_argb0, > // 16 pixels > // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). > __declspec(naked) void I422ToARGBRow_AVX2( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2105,11 +2105,11 @@ __declspec(naked) void I422ToARGBRow_AVX2( > // 16 pixels > // 8 UV values upsampled to 16 UV, mixed with 16 Y and 16 A producing 16 ARGB. > __declspec(naked) void I422AlphaToARGBRow_AVX2( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2148,10 +2148,10 @@ __declspec(naked) void I422AlphaToARGBRow_AVX2( > // 16 pixels > // 16 UV values with 16 Y producing 16 ARGB (64 bytes). > __declspec(naked) void I444ToARGBRow_AVX2( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2187,9 +2187,9 @@ __declspec(naked) void I444ToARGBRow_AVX2( > // 16 pixels. > // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). > __declspec(naked) void NV12ToARGBRow_AVX2( >- const uint8* y_buf, >- const uint8* uv_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2222,9 +2222,9 @@ __declspec(naked) void NV12ToARGBRow_AVX2( > // 16 pixels. > // 8 VU values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). > __declspec(naked) void NV21ToARGBRow_AVX2( >- const uint8* y_buf, >- const uint8* vu_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2257,8 +2257,8 @@ __declspec(naked) void NV21ToARGBRow_AVX2( > // 16 pixels. > // 8 YUY2 values with 16 Y and 8 UV producing 16 ARGB (64 bytes). > __declspec(naked) void YUY2ToARGBRow_AVX2( >- const uint8* src_yuy2, >- uint8* dst_argb, >+ const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2288,8 +2288,8 @@ __declspec(naked) void YUY2ToARGBRow_AVX2( > // 16 pixels. > // 8 UYVY values with 16 Y and 8 UV producing 16 ARGB (64 bytes). > __declspec(naked) void UYVYToARGBRow_AVX2( >- const uint8* src_uyvy, >- uint8* dst_argb, >+ const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2319,10 +2319,10 @@ __declspec(naked) void UYVYToARGBRow_AVX2( > // 16 pixels > // 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 RGBA (64 bytes). > __declspec(naked) void I422ToRGBARow_AVX2( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2551,10 +2551,10 @@ __declspec(naked) void I422ToRGBARow_AVX2( > // 8 pixels. > // 8 UV values, mixed with 8 Y producing 8 ARGB (32 bytes). > __declspec(naked) void I444ToARGBRow_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2588,10 +2588,10 @@ __declspec(naked) void I444ToARGBRow_SSSE3( > // 8 pixels. > // 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 RGB24 (24 bytes). > __declspec(naked) void I422ToRGB24Row_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_rgb24, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgb24, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2626,10 +2626,10 @@ __declspec(naked) void I422ToRGB24Row_SSSE3( > // 8 pixels > // 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 RGB565 (16 bytes). > __declspec(naked) void I422ToRGB565Row_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* rgb565_buf, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* rgb565_buf, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2669,10 +2669,10 @@ __declspec(naked) void I422ToRGB565Row_SSSE3( > // 8 pixels. > // 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes). > __declspec(naked) void I422ToARGBRow_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2706,11 +2706,11 @@ __declspec(naked) void I422ToARGBRow_SSSE3( > // 8 pixels. > // 4 UV values upsampled to 8 UV, mixed with 8 Y and 8 A producing 8 ARGB. > __declspec(naked) void I422AlphaToARGBRow_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- const uint8* a_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ const uint8_t* a_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2746,9 +2746,9 @@ __declspec(naked) void I422AlphaToARGBRow_SSSE3( > // 8 pixels. > // 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes). > __declspec(naked) void NV12ToARGBRow_SSSE3( >- const uint8* y_buf, >- const uint8* uv_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* uv_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2778,9 +2778,9 @@ __declspec(naked) void NV12ToARGBRow_SSSE3( > // 8 pixels. > // 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes). > __declspec(naked) void NV21ToARGBRow_SSSE3( >- const uint8* y_buf, >- const uint8* vu_buf, >- uint8* dst_argb, >+ const uint8_t* y_buf, >+ const uint8_t* vu_buf, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2810,8 +2810,8 @@ __declspec(naked) void NV21ToARGBRow_SSSE3( > // 8 pixels. > // 4 YUY2 values with 8 Y and 4 UV producing 8 ARGB (32 bytes). > __declspec(naked) void YUY2ToARGBRow_SSSE3( >- const uint8* src_yuy2, >- uint8* dst_argb, >+ const uint8_t* src_yuy2, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2838,8 +2838,8 @@ __declspec(naked) void YUY2ToARGBRow_SSSE3( > // 8 pixels. > // 4 UYVY values with 8 Y and 4 UV producing 8 ARGB (32 bytes). > __declspec(naked) void UYVYToARGBRow_SSSE3( >- const uint8* src_uyvy, >- uint8* dst_argb, >+ const uint8_t* src_uyvy, >+ uint8_t* dst_argb, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2864,10 +2864,10 @@ __declspec(naked) void UYVYToARGBRow_SSSE3( > } > > __declspec(naked) void I422ToRGBARow_SSSE3( >- const uint8* y_buf, >- const uint8* u_buf, >- const uint8* v_buf, >- uint8* dst_rgba, >+ const uint8_t* y_buf, >+ const uint8_t* u_buf, >+ const uint8_t* v_buf, >+ uint8_t* dst_rgba, > const struct YuvConstants* yuvconstants, > int width) { > __asm { >@@ -2900,8 +2900,8 @@ __declspec(naked) void I422ToRGBARow_SSSE3( > > #ifdef HAS_I400TOARGBROW_SSE2 > // 8 pixels of Y converted to 8 pixels of ARGB (32 bytes). >-__declspec(naked) void I400ToARGBRow_SSE2(const uint8* y_buf, >- uint8* rgb_buf, >+__declspec(naked) void I400ToARGBRow_SSE2(const uint8_t* y_buf, >+ uint8_t* rgb_buf, > int width) { > __asm { > mov eax, 0x4a354a35 // 4a35 = 18997 = round(1.164 * 64 * 256) >@@ -2947,8 +2947,8 @@ __declspec(naked) void I400ToARGBRow_SSE2(const uint8* y_buf, > #ifdef HAS_I400TOARGBROW_AVX2 > // 16 pixels of Y converted to 16 pixels of ARGB (64 bytes). > // note: vpunpcklbw mutates and vpackuswb unmutates. >-__declspec(naked) void I400ToARGBRow_AVX2(const uint8* y_buf, >- uint8* rgb_buf, >+__declspec(naked) void I400ToARGBRow_AVX2(const uint8_t* y_buf, >+ uint8_t* rgb_buf, > int width) { > __asm { > mov eax, 0x4a354a35 // 4a35 = 18997 = round(1.164 * 64 * 256) >@@ -3000,8 +3000,8 @@ static const uvec8 kShuffleMirror = {15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, > 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; > > // TODO(fbarchard): Replace lea with -16 offset. >-__declspec(naked) void MirrorRow_SSSE3(const uint8* src, >- uint8* dst, >+__declspec(naked) void MirrorRow_SSSE3(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src >@@ -3022,7 +3022,9 @@ __declspec(naked) void MirrorRow_SSSE3(const uint8* src, > #endif // HAS_MIRRORROW_SSSE3 > > #ifdef HAS_MIRRORROW_AVX2 >-__declspec(naked) void MirrorRow_AVX2(const uint8* src, uint8* dst, int width) { >+__declspec(naked) void MirrorRow_AVX2(const uint8_t* src, >+ uint8_t* dst, >+ int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >@@ -3048,9 +3050,9 @@ __declspec(naked) void MirrorRow_AVX2(const uint8* src, uint8* dst, int width) { > static const uvec8 kShuffleMirrorUV = {14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, > 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u}; > >-__declspec(naked) void MirrorUVRow_SSSE3(const uint8* src, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void MirrorUVRow_SSSE3(const uint8_t* src, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3079,8 +3081,8 @@ __declspec(naked) void MirrorUVRow_SSSE3(const uint8* src, > #endif // HAS_MIRRORUVROW_SSSE3 > > #ifdef HAS_ARGBMIRRORROW_SSE2 >-__declspec(naked) void ARGBMirrorRow_SSE2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBMirrorRow_SSE2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src >@@ -3105,8 +3107,8 @@ __declspec(naked) void ARGBMirrorRow_SSE2(const uint8* src, > // Shuffle table for reversing the bytes. > static const ulvec32 kARGBShuffleMirror_AVX2 = {7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u}; > >-__declspec(naked) void ARGBMirrorRow_AVX2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBMirrorRow_AVX2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src >@@ -3127,9 +3129,9 @@ __declspec(naked) void ARGBMirrorRow_AVX2(const uint8* src, > #endif // HAS_ARGBMIRRORROW_AVX2 > > #ifdef HAS_SPLITUVROW_SSE2 >-__declspec(naked) void SplitUVRow_SSE2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void SplitUVRow_SSE2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3167,9 +3169,9 @@ __declspec(naked) void SplitUVRow_SSE2(const uint8* src_uv, > #endif // HAS_SPLITUVROW_SSE2 > > #ifdef HAS_SPLITUVROW_AVX2 >-__declspec(naked) void SplitUVRow_AVX2(const uint8* src_uv, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void SplitUVRow_AVX2(const uint8_t* src_uv, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3207,9 +3209,9 @@ __declspec(naked) void SplitUVRow_AVX2(const uint8* src_uv, > #endif // HAS_SPLITUVROW_AVX2 > > #ifdef HAS_MERGEUVROW_SSE2 >-__declspec(naked) void MergeUVRow_SSE2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+__declspec(naked) void MergeUVRow_SSE2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > __asm { > push edi >@@ -3239,9 +3241,9 @@ __declspec(naked) void MergeUVRow_SSE2(const uint8* src_u, > #endif // HAS_MERGEUVROW_SSE2 > > #ifdef HAS_MERGEUVROW_AVX2 >-__declspec(naked) void MergeUVRow_AVX2(const uint8* src_u, >- const uint8* src_v, >- uint8* dst_uv, >+__declspec(naked) void MergeUVRow_AVX2(const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_uv, > int width) { > __asm { > push edi >@@ -3273,12 +3275,14 @@ __declspec(naked) void MergeUVRow_AVX2(const uint8* src_u, > #endif // HAS_MERGEUVROW_AVX2 > > #ifdef HAS_COPYROW_SSE2 >-// CopyRow copys 'count' bytes using a 16 byte load/store, 32 bytes at time. >-__declspec(naked) void CopyRow_SSE2(const uint8* src, uint8* dst, int count) { >+// CopyRow copys 'width' bytes using a 16 byte load/store, 32 bytes at time. >+__declspec(naked) void CopyRow_SSE2(const uint8_t* src, >+ uint8_t* dst, >+ int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > test eax, 15 > jne convertloopu > test edx, 15 >@@ -3310,12 +3314,14 @@ __declspec(naked) void CopyRow_SSE2(const uint8* src, uint8* dst, int count) { > #endif // HAS_COPYROW_SSE2 > > #ifdef HAS_COPYROW_AVX >-// CopyRow copys 'count' bytes using a 32 byte load/store, 64 bytes at time. >-__declspec(naked) void CopyRow_AVX(const uint8* src, uint8* dst, int count) { >+// CopyRow copys 'width' bytes using a 32 byte load/store, 64 bytes at time. >+__declspec(naked) void CopyRow_AVX(const uint8_t* src, >+ uint8_t* dst, >+ int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > > convertloop: > vmovdqu ymm0, [eax] >@@ -3334,13 +3340,15 @@ __declspec(naked) void CopyRow_AVX(const uint8* src, uint8* dst, int count) { > #endif // HAS_COPYROW_AVX > > // Multiple of 1. >-__declspec(naked) void CopyRow_ERMS(const uint8* src, uint8* dst, int count) { >+__declspec(naked) void CopyRow_ERMS(const uint8_t* src, >+ uint8_t* dst, >+ int width) { > __asm { > mov eax, esi > mov edx, edi > mov esi, [esp + 4] // src > mov edi, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > rep movsb > mov edi, edx > mov esi, eax >@@ -3350,13 +3358,13 @@ __declspec(naked) void CopyRow_ERMS(const uint8* src, uint8* dst, int count) { > > #ifdef HAS_ARGBCOPYALPHAROW_SSE2 > // width in pixels >-__declspec(naked) void ARGBCopyAlphaRow_SSE2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBCopyAlphaRow_SSE2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > pcmpeqb xmm0, xmm0 // generate mask 0xff000000 > pslld xmm0, 24 > pcmpeqb xmm1, xmm1 // generate mask 0x00ffffff >@@ -3387,13 +3395,13 @@ __declspec(naked) void ARGBCopyAlphaRow_SSE2(const uint8* src, > > #ifdef HAS_ARGBCOPYALPHAROW_AVX2 > // width in pixels >-__declspec(naked) void ARGBCopyAlphaRow_AVX2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBCopyAlphaRow_AVX2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > vpcmpeqb ymm0, ymm0, ymm0 > vpsrld ymm0, ymm0, 8 // generate mask 0x00ffffff > >@@ -3417,8 +3425,8 @@ __declspec(naked) void ARGBCopyAlphaRow_AVX2(const uint8* src, > > #ifdef HAS_ARGBEXTRACTALPHAROW_SSE2 > // width in pixels >-__declspec(naked) void ARGBExtractAlphaRow_SSE2(const uint8* src_argb, >- uint8* dst_a, >+__declspec(naked) void ARGBExtractAlphaRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_a, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -3445,8 +3453,8 @@ __declspec(naked) void ARGBExtractAlphaRow_SSE2(const uint8* src_argb, > > #ifdef HAS_ARGBEXTRACTALPHAROW_AVX2 > // width in pixels >-__declspec(naked) void ARGBExtractAlphaRow_AVX2(const uint8* src_argb, >- uint8* dst_a, >+__declspec(naked) void ARGBExtractAlphaRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_a, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -3481,13 +3489,13 @@ __declspec(naked) void ARGBExtractAlphaRow_AVX2(const uint8* src_argb, > > #ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2 > // width in pixels >-__declspec(naked) void ARGBCopyYToAlphaRow_SSE2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBCopyYToAlphaRow_SSE2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > pcmpeqb xmm0, xmm0 // generate mask 0xff000000 > pslld xmm0, 24 > pcmpeqb xmm1, xmm1 // generate mask 0x00ffffff >@@ -3520,13 +3528,13 @@ __declspec(naked) void ARGBCopyYToAlphaRow_SSE2(const uint8* src, > > #ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2 > // width in pixels >-__declspec(naked) void ARGBCopyYToAlphaRow_AVX2(const uint8* src, >- uint8* dst, >+__declspec(naked) void ARGBCopyYToAlphaRow_AVX2(const uint8_t* src, >+ uint8_t* dst, > int width) { > __asm { > mov eax, [esp + 4] // src > mov edx, [esp + 8] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > vpcmpeqb ymm0, ymm0, ymm0 > vpsrld ymm0, ymm0, 8 // generate mask 0x00ffffff > >@@ -3551,16 +3559,16 @@ __declspec(naked) void ARGBCopyYToAlphaRow_AVX2(const uint8* src, > #endif // HAS_ARGBCOPYYTOALPHAROW_AVX2 > > #ifdef HAS_SETROW_X86 >-// Write 'count' bytes using an 8 bit value repeated. >-// Count should be multiple of 4. >-__declspec(naked) void SetRow_X86(uint8* dst, uint8 v8, int count) { >+// Write 'width' bytes using an 8 bit value repeated. >+// width should be multiple of 4. >+__declspec(naked) void SetRow_X86(uint8_t* dst, uint8_t v8, int width) { > __asm { > movzx eax, byte ptr [esp + 8] // v8 > mov edx, 0x01010101 // Duplicate byte to all bytes. > mul edx // overwrites edx with upper part of result. > mov edx, edi > mov edi, [esp + 4] // dst >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > shr ecx, 2 > rep stosd > mov edi, edx >@@ -3568,26 +3576,28 @@ __declspec(naked) void SetRow_X86(uint8* dst, uint8 v8, int count) { > } > } > >-// Write 'count' bytes using an 8 bit value repeated. >-__declspec(naked) void SetRow_ERMS(uint8* dst, uint8 v8, int count) { >+// Write 'width' bytes using an 8 bit value repeated. >+__declspec(naked) void SetRow_ERMS(uint8_t* dst, uint8_t v8, int width) { > __asm { > mov edx, edi > mov edi, [esp + 4] // dst > mov eax, [esp + 8] // v8 >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > rep stosb > mov edi, edx > ret > } > } > >-// Write 'count' 32 bit values. >-__declspec(naked) void ARGBSetRow_X86(uint8* dst_argb, uint32 v32, int count) { >+// Write 'width' 32 bit values. >+__declspec(naked) void ARGBSetRow_X86(uint8_t* dst_argb, >+ uint32_t v32, >+ int width) { > __asm { > mov edx, edi > mov edi, [esp + 4] // dst > mov eax, [esp + 8] // v32 >- mov ecx, [esp + 12] // count >+ mov ecx, [esp + 12] // width > rep stosd > mov edi, edx > ret >@@ -3596,8 +3606,8 @@ __declspec(naked) void ARGBSetRow_X86(uint8* dst_argb, uint32 v32, int count) { > #endif // HAS_SETROW_X86 > > #ifdef HAS_YUY2TOYROW_AVX2 >-__declspec(naked) void YUY2ToYRow_AVX2(const uint8* src_yuy2, >- uint8* dst_y, >+__declspec(naked) void YUY2ToYRow_AVX2(const uint8_t* src_yuy2, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] // src_yuy2 >@@ -3623,10 +3633,10 @@ __declspec(naked) void YUY2ToYRow_AVX2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void YUY2ToUVRow_AVX2(const uint8* src_yuy2, >+__declspec(naked) void YUY2ToUVRow_AVX2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -3669,9 +3679,9 @@ __declspec(naked) void YUY2ToUVRow_AVX2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void YUY2ToUV422Row_AVX2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3709,8 +3719,8 @@ __declspec(naked) void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void UYVYToYRow_AVX2(const uint8* src_uyvy, >- uint8* dst_y, >+__declspec(naked) void UYVYToYRow_AVX2(const uint8_t* src_uyvy, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] // src_uyvy >@@ -3734,10 +3744,10 @@ __declspec(naked) void UYVYToYRow_AVX2(const uint8* src_uyvy, > } > } > >-__declspec(naked) void UYVYToUVRow_AVX2(const uint8* src_uyvy, >+__declspec(naked) void UYVYToUVRow_AVX2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -3780,9 +3790,9 @@ __declspec(naked) void UYVYToUVRow_AVX2(const uint8* src_uyvy, > } > } > >-__declspec(naked) void UYVYToUV422Row_AVX2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void UYVYToUV422Row_AVX2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3822,8 +3832,8 @@ __declspec(naked) void UYVYToUV422Row_AVX2(const uint8* src_uyvy, > #endif // HAS_YUY2TOYROW_AVX2 > > #ifdef HAS_YUY2TOYROW_SSE2 >-__declspec(naked) void YUY2ToYRow_SSE2(const uint8* src_yuy2, >- uint8* dst_y, >+__declspec(naked) void YUY2ToYRow_SSE2(const uint8_t* src_yuy2, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] // src_yuy2 >@@ -3847,10 +3857,10 @@ __declspec(naked) void YUY2ToYRow_SSE2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void YUY2ToUVRow_SSE2(const uint8* src_yuy2, >+__declspec(naked) void YUY2ToUVRow_SSE2(const uint8_t* src_yuy2, > int stride_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -3892,9 +3902,9 @@ __declspec(naked) void YUY2ToUVRow_SSE2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void YUY2ToUV422Row_SSE2(const uint8_t* src_yuy2, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -3929,8 +3939,8 @@ __declspec(naked) void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, > } > } > >-__declspec(naked) void UYVYToYRow_SSE2(const uint8* src_uyvy, >- uint8* dst_y, >+__declspec(naked) void UYVYToYRow_SSE2(const uint8_t* src_uyvy, >+ uint8_t* dst_y, > int width) { > __asm { > mov eax, [esp + 4] // src_uyvy >@@ -3952,10 +3962,10 @@ __declspec(naked) void UYVYToYRow_SSE2(const uint8* src_uyvy, > } > } > >-__declspec(naked) void UYVYToUVRow_SSE2(const uint8* src_uyvy, >+__declspec(naked) void UYVYToUVRow_SSE2(const uint8_t* src_uyvy, > int stride_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push esi >@@ -3997,9 +4007,9 @@ __declspec(naked) void UYVYToUVRow_SSE2(const uint8* src_uyvy, > } > } > >-__declspec(naked) void UYVYToUV422Row_SSE2(const uint8* src_uyvy, >- uint8* dst_u, >- uint8* dst_v, >+__declspec(naked) void UYVYToUV422Row_SSE2(const uint8_t* src_uyvy, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int width) { > __asm { > push edi >@@ -4041,10 +4051,10 @@ __declspec(naked) void UYVYToUV422Row_SSE2(const uint8* src_uyvy, > // =((A2*C2)+(B2*(255-C2))+255)/256 > // signed version of math > // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 >-__declspec(naked) void BlendPlaneRow_SSSE3(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+__declspec(naked) void BlendPlaneRow_SSSE3(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width) { > __asm { > push esi >@@ -4098,10 +4108,10 @@ __declspec(naked) void BlendPlaneRow_SSSE3(const uint8* src0, > // =((A2*C2)+(B2*(255-C2))+255)/256 > // signed version of math > // =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 >-__declspec(naked) void BlendPlaneRow_AVX2(const uint8* src0, >- const uint8* src1, >- const uint8* alpha, >- uint8* dst, >+__declspec(naked) void BlendPlaneRow_AVX2(const uint8_t* src0, >+ const uint8_t* src1, >+ const uint8_t* alpha, >+ uint8_t* dst, > int width) { > __asm { > push esi >@@ -4162,9 +4172,9 @@ static const uvec8 kShuffleAlpha = {3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80, > 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80}; > > // Blend 8 pixels at a time. >-__declspec(naked) void ARGBBlendRow_SSSE3(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBBlendRow_SSSE3(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4253,8 +4263,8 @@ static const uvec8 kShuffleAlpha1 = { > 11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u, > 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u, > }; >-__declspec(naked) void ARGBAttenuateRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBAttenuateRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb0 >@@ -4298,8 +4308,8 @@ __declspec(naked) void ARGBAttenuateRow_SSSE3(const uint8* src_argb, > static const uvec8 kShuffleAlpha_AVX2 = {6u, 7u, 6u, 7u, 6u, 7u, > 128u, 128u, 14u, 15u, 14u, 15u, > 14u, 15u, 128u, 128u}; >-__declspec(naked) void ARGBAttenuateRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBAttenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb0 >@@ -4336,8 +4346,8 @@ __declspec(naked) void ARGBAttenuateRow_AVX2(const uint8* src_argb, > > #ifdef HAS_ARGBUNATTENUATEROW_SSE2 > // Unattenuate 4 pixels at a time. >-__declspec(naked) void ARGBUnattenuateRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBUnattenuateRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > push ebx >@@ -4392,8 +4402,8 @@ static const uvec8 kUnattenShuffleAlpha_AVX2 = { > // TODO(fbarchard): Enable USE_GATHER for future hardware if faster. > // USE_GATHER is not on by default, due to being a slow instruction. > #ifdef USE_GATHER >-__declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] // src_argb0 >@@ -4426,8 +4436,8 @@ __declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8* src_argb, > } > } > #else // USE_GATHER >-__declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > >@@ -4495,8 +4505,8 @@ __declspec(naked) void ARGBUnattenuateRow_AVX2(const uint8* src_argb, > > #ifdef HAS_ARGBGRAYROW_SSSE3 > // Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels. >-__declspec(naked) void ARGBGrayRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBGrayRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -4552,7 +4562,7 @@ static const vec8 kARGBToSepiaR = {24, 98, 50, 0, 24, 98, 50, 0, > 24, 98, 50, 0, 24, 98, 50, 0}; > > // Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels. >-__declspec(naked) void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) { >+__declspec(naked) void ARGBSepiaRow_SSSE3(uint8_t* dst_argb, int width) { > __asm { > mov eax, [esp + 4] /* dst_argb */ > mov ecx, [esp + 8] /* width */ >@@ -4608,9 +4618,9 @@ __declspec(naked) void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) { > // Same as Sepia except matrix is provided. > // TODO(fbarchard): packuswbs only use half of the reg. To make RGBA, combine R > // and B into a high and low, then G/A, unpackl/hbw and then unpckl/hwd. >-__declspec(naked) void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const int8* matrix_argb, >+__declspec(naked) void ARGBColorMatrixRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const int8_t* matrix_argb, > int width) { > __asm { > mov eax, [esp + 4] /* src_argb */ >@@ -4670,7 +4680,7 @@ __declspec(naked) void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, > > #ifdef HAS_ARGBQUANTIZEROW_SSE2 > // Quantize 4 ARGB pixels (16 bytes). >-__declspec(naked) void ARGBQuantizeRow_SSE2(uint8* dst_argb, >+__declspec(naked) void ARGBQuantizeRow_SSE2(uint8_t* dst_argb, > int scale, > int interval_size, > int interval_offset, >@@ -4717,10 +4727,10 @@ __declspec(naked) void ARGBQuantizeRow_SSE2(uint8* dst_argb, > > #ifdef HAS_ARGBSHADEROW_SSE2 > // Shade 4 pixels at a time by specified value. >-__declspec(naked) void ARGBShadeRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBShadeRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- uint32 value) { >+ uint32_t value) { > __asm { > mov eax, [esp + 4] // src_argb > mov edx, [esp + 8] // dst_argb >@@ -4752,9 +4762,9 @@ __declspec(naked) void ARGBShadeRow_SSE2(const uint8* src_argb, > > #ifdef HAS_ARGBMULTIPLYROW_SSE2 > // Multiply 2 rows of ARGB pixels together, 4 pixels at a time. >-__declspec(naked) void ARGBMultiplyRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBMultiplyRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4792,9 +4802,9 @@ __declspec(naked) void ARGBMultiplyRow_SSE2(const uint8* src_argb0, > #ifdef HAS_ARGBADDROW_SSE2 > // Add 2 rows of ARGB pixels together, 4 pixels at a time. > // TODO(fbarchard): Port this to posix, neon and other math functions. >-__declspec(naked) void ARGBAddRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBAddRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4841,9 +4851,9 @@ __declspec(naked) void ARGBAddRow_SSE2(const uint8* src_argb0, > > #ifdef HAS_ARGBSUBTRACTROW_SSE2 > // Subtract 2 rows of ARGB pixels together, 4 pixels at a time. >-__declspec(naked) void ARGBSubtractRow_SSE2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBSubtractRow_SSE2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4871,9 +4881,9 @@ __declspec(naked) void ARGBSubtractRow_SSE2(const uint8* src_argb0, > > #ifdef HAS_ARGBMULTIPLYROW_AVX2 > // Multiply 2 rows of ARGB pixels together, 8 pixels at a time. >-__declspec(naked) void ARGBMultiplyRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBMultiplyRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4909,9 +4919,9 @@ __declspec(naked) void ARGBMultiplyRow_AVX2(const uint8* src_argb0, > > #ifdef HAS_ARGBADDROW_AVX2 > // Add 2 rows of ARGB pixels together, 8 pixels at a time. >-__declspec(naked) void ARGBAddRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBAddRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4939,9 +4949,9 @@ __declspec(naked) void ARGBAddRow_AVX2(const uint8* src_argb0, > > #ifdef HAS_ARGBSUBTRACTROW_AVX2 > // Subtract 2 rows of ARGB pixels together, 8 pixels at a time. >-__declspec(naked) void ARGBSubtractRow_AVX2(const uint8* src_argb0, >- const uint8* src_argb1, >- uint8* dst_argb, >+__declspec(naked) void ARGBSubtractRow_AVX2(const uint8_t* src_argb0, >+ const uint8_t* src_argb1, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -4972,10 +4982,10 @@ __declspec(naked) void ARGBSubtractRow_AVX2(const uint8* src_argb0, > // -1 0 1 > // -2 0 2 > // -1 0 1 >-__declspec(naked) void SobelXRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- const uint8* src_y2, >- uint8* dst_sobelx, >+__declspec(naked) void SobelXRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ const uint8_t* src_y2, >+ uint8_t* dst_sobelx, > int width) { > __asm { > push esi >@@ -5030,9 +5040,9 @@ __declspec(naked) void SobelXRow_SSE2(const uint8* src_y0, > // -1 -2 -1 > // 0 0 0 > // 1 2 1 >-__declspec(naked) void SobelYRow_SSE2(const uint8* src_y0, >- const uint8* src_y1, >- uint8* dst_sobely, >+__declspec(naked) void SobelYRow_SSE2(const uint8_t* src_y0, >+ const uint8_t* src_y1, >+ uint8_t* dst_sobely, > int width) { > __asm { > push esi >@@ -5084,9 +5094,9 @@ __declspec(naked) void SobelYRow_SSE2(const uint8* src_y0, > // R = Sobel > // G = Sobel > // B = Sobel >-__declspec(naked) void SobelRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+__declspec(naked) void SobelRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -5132,9 +5142,9 @@ __declspec(naked) void SobelRow_SSE2(const uint8* src_sobelx, > > #ifdef HAS_SOBELTOPLANEROW_SSE2 > // Adds Sobel X and Sobel Y and stores Sobel into a plane. >-__declspec(naked) void SobelToPlaneRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_y, >+__declspec(naked) void SobelToPlaneRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_y, > int width) { > __asm { > push esi >@@ -5166,9 +5176,9 @@ __declspec(naked) void SobelToPlaneRow_SSE2(const uint8* src_sobelx, > // R = Sobel X > // G = Sobel > // B = Sobel Y >-__declspec(naked) void SobelXYRow_SSE2(const uint8* src_sobelx, >- const uint8* src_sobely, >- uint8* dst_argb, >+__declspec(naked) void SobelXYRow_SSE2(const uint8_t* src_sobelx, >+ const uint8_t* src_sobely, >+ uint8_t* dst_argb, > int width) { > __asm { > push esi >@@ -5225,11 +5235,11 @@ __declspec(naked) void SobelXYRow_SSE2(const uint8* src_sobelx, > // count is number of averaged pixels to produce. > // Does 4 pixels at a time. > // This function requires alignment on accumulation buffer pointers. >-void CumulativeSumToAverageRow_SSE2(const int32* topleft, >- const int32* botleft, >+void CumulativeSumToAverageRow_SSE2(const int32_t* topleft, >+ const int32_t* botleft, > int width, > int area, >- uint8* dst, >+ uint8_t* dst, > int count) { > __asm { > mov eax, topleft // eax topleft >@@ -5375,9 +5385,9 @@ void CumulativeSumToAverageRow_SSE2(const int32* topleft, > #ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2 > // Creates a table of cumulative sums where each value is a sum of all values > // above and to the left of the value. >-void ComputeCumulativeSumRow_SSE2(const uint8* row, >- int32* cumsum, >- const int32* previous_cumsum, >+void ComputeCumulativeSumRow_SSE2(const uint8_t* row, >+ int32_t* cumsum, >+ const int32_t* previous_cumsum, > int width) { > __asm { > mov eax, row >@@ -5460,9 +5470,9 @@ void ComputeCumulativeSumRow_SSE2(const uint8* row, > > #ifdef HAS_ARGBAFFINEROW_SSE2 > // Copy ARGB pixels from source image with slope to a row of destination. >-__declspec(naked) LIBYUV_API void ARGBAffineRow_SSE2(const uint8* src_argb, >+__declspec(naked) LIBYUV_API void ARGBAffineRow_SSE2(const uint8_t* src_argb, > int src_argb_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > const float* uv_dudv, > int width) { > __asm { >@@ -5546,8 +5556,8 @@ __declspec(naked) LIBYUV_API void ARGBAffineRow_SSE2(const uint8* src_argb, > > #ifdef HAS_INTERPOLATEROW_AVX2 > // Bilinear filter 32x2 -> 32x1 >-__declspec(naked) void InterpolateRow_AVX2(uint8* dst_ptr, >- const uint8* src_ptr, >+__declspec(naked) void InterpolateRow_AVX2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >@@ -5623,8 +5633,8 @@ __declspec(naked) void InterpolateRow_AVX2(uint8* dst_ptr, > > // Bilinear filter 16x2 -> 16x1 > // TODO(fbarchard): Consider allowing 256 using memcpy. >-__declspec(naked) void InterpolateRow_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+__declspec(naked) void InterpolateRow_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >@@ -5705,9 +5715,9 @@ __declspec(naked) void InterpolateRow_SSSE3(uint8* dst_ptr, > } > > // For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. >-__declspec(naked) void ARGBShuffleRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+__declspec(naked) void ARGBShuffleRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -5732,9 +5742,9 @@ __declspec(naked) void ARGBShuffleRow_SSSE3(const uint8* src_argb, > } > > #ifdef HAS_ARGBSHUFFLEROW_AVX2 >-__declspec(naked) void ARGBShuffleRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >+__declspec(naked) void ARGBShuffleRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, >+ const uint8_t* shuffler, > int width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -5761,133 +5771,16 @@ __declspec(naked) void ARGBShuffleRow_AVX2(const uint8* src_argb, > } > #endif // HAS_ARGBSHUFFLEROW_AVX2 > >-__declspec(naked) void ARGBShuffleRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >- const uint8* shuffler, >- int width) { >- __asm { >- push ebx >- push esi >- mov eax, [esp + 8 + 4] // src_argb >- mov edx, [esp + 8 + 8] // dst_argb >- mov esi, [esp + 8 + 12] // shuffler >- mov ecx, [esp + 8 + 16] // width >- pxor xmm5, xmm5 >- >- mov ebx, [esi] // shuffler >- cmp ebx, 0x03000102 >- je shuf_3012 >- cmp ebx, 0x00010203 >- je shuf_0123 >- cmp ebx, 0x00030201 >- je shuf_0321 >- cmp ebx, 0x02010003 >- je shuf_2103 >- >- // TODO(fbarchard): Use one source pointer and 3 offsets. >- shuf_any1: >- movzx ebx, byte ptr [esi] >- movzx ebx, byte ptr [eax + ebx] >- mov [edx], bl >- movzx ebx, byte ptr [esi + 1] >- movzx ebx, byte ptr [eax + ebx] >- mov [edx + 1], bl >- movzx ebx, byte ptr [esi + 2] >- movzx ebx, byte ptr [eax + ebx] >- mov [edx + 2], bl >- movzx ebx, byte ptr [esi + 3] >- movzx ebx, byte ptr [eax + ebx] >- mov [edx + 3], bl >- lea eax, [eax + 4] >- lea edx, [edx + 4] >- sub ecx, 1 >- jg shuf_any1 >- jmp shuf99 >- >- shuf_0123: >- movdqu xmm0, [eax] >- lea eax, [eax + 16] >- movdqa xmm1, xmm0 >- punpcklbw xmm0, xmm5 >- punpckhbw xmm1, xmm5 >- pshufhw xmm0, xmm0, 01Bh // 1B = 00011011 = 0x0123 = BGRAToARGB >- pshuflw xmm0, xmm0, 01Bh >- pshufhw xmm1, xmm1, 01Bh >- pshuflw xmm1, xmm1, 01Bh >- packuswb xmm0, xmm1 >- movdqu [edx], xmm0 >- lea edx, [edx + 16] >- sub ecx, 4 >- jg shuf_0123 >- jmp shuf99 >- >- shuf_0321: >- movdqu xmm0, [eax] >- lea eax, [eax + 16] >- movdqa xmm1, xmm0 >- punpcklbw xmm0, xmm5 >- punpckhbw xmm1, xmm5 >- pshufhw xmm0, xmm0, 039h // 39 = 00111001 = 0x0321 = RGBAToARGB >- pshuflw xmm0, xmm0, 039h >- pshufhw xmm1, xmm1, 039h >- pshuflw xmm1, xmm1, 039h >- packuswb xmm0, xmm1 >- movdqu [edx], xmm0 >- lea edx, [edx + 16] >- sub ecx, 4 >- jg shuf_0321 >- jmp shuf99 >- >- shuf_2103: >- movdqu xmm0, [eax] >- lea eax, [eax + 16] >- movdqa xmm1, xmm0 >- punpcklbw xmm0, xmm5 >- punpckhbw xmm1, xmm5 >- pshufhw xmm0, xmm0, 093h // 93 = 10010011 = 0x2103 = ARGBToRGBA >- pshuflw xmm0, xmm0, 093h >- pshufhw xmm1, xmm1, 093h >- pshuflw xmm1, xmm1, 093h >- packuswb xmm0, xmm1 >- movdqu [edx], xmm0 >- lea edx, [edx + 16] >- sub ecx, 4 >- jg shuf_2103 >- jmp shuf99 >- >- shuf_3012: >- movdqu xmm0, [eax] >- lea eax, [eax + 16] >- movdqa xmm1, xmm0 >- punpcklbw xmm0, xmm5 >- punpckhbw xmm1, xmm5 >- pshufhw xmm0, xmm0, 0C6h // C6 = 11000110 = 0x3012 = ABGRToARGB >- pshuflw xmm0, xmm0, 0C6h >- pshufhw xmm1, xmm1, 0C6h >- pshuflw xmm1, xmm1, 0C6h >- packuswb xmm0, xmm1 >- movdqu [edx], xmm0 >- lea edx, [edx + 16] >- sub ecx, 4 >- jg shuf_3012 >- >- shuf99: >- pop esi >- pop ebx >- ret >- } >-} >- > // YUY2 - Macro-pixel = 2 image pixels > // Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4.... > > // UYVY - Macro-pixel = 2 image pixels > // U0Y0V0Y1 > >-__declspec(naked) void I422ToYUY2Row_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+__declspec(naked) void I422ToYUY2Row_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width) { > __asm { > push esi >@@ -5921,10 +5814,10 @@ __declspec(naked) void I422ToYUY2Row_SSE2(const uint8* src_y, > } > } > >-__declspec(naked) void I422ToUYVYRow_SSE2(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_frame, >+__declspec(naked) void I422ToUYVYRow_SSE2(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_frame, > int width) { > __asm { > push esi >@@ -5959,8 +5852,8 @@ __declspec(naked) void I422ToUYVYRow_SSE2(const uint8* src_y, > } > > #ifdef HAS_ARGBPOLYNOMIALROW_SSE2 >-__declspec(naked) void ARGBPolynomialRow_SSE2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBPolynomialRow_SSE2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width) { > __asm { >@@ -6018,8 +5911,8 @@ __declspec(naked) void ARGBPolynomialRow_SSE2(const uint8* src_argb, > #endif // HAS_ARGBPOLYNOMIALROW_SSE2 > > #ifdef HAS_ARGBPOLYNOMIALROW_AVX2 >-__declspec(naked) void ARGBPolynomialRow_AVX2(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBPolynomialRow_AVX2(const uint8_t* src_argb, >+ uint8_t* dst_argb, > const float* poly, > int width) { > __asm { >@@ -6058,8 +5951,8 @@ __declspec(naked) void ARGBPolynomialRow_AVX2(const uint8* src_argb, > > #ifdef HAS_HALFFLOATROW_SSE2 > static float kExpBias = 1.9259299444e-34f; >-__declspec(naked) void HalfFloatRow_SSE2(const uint16* src, >- uint16* dst, >+__declspec(naked) void HalfFloatRow_SSE2(const uint16_t* src, >+ uint16_t* dst, > float scale, > int width) { > __asm { >@@ -6095,8 +5988,8 @@ __declspec(naked) void HalfFloatRow_SSE2(const uint16* src, > #endif // HAS_HALFFLOATROW_SSE2 > > #ifdef HAS_HALFFLOATROW_AVX2 >-__declspec(naked) void HalfFloatRow_AVX2(const uint16* src, >- uint16* dst, >+__declspec(naked) void HalfFloatRow_AVX2(const uint16_t* src, >+ uint16_t* dst, > float scale, > int width) { > __asm { >@@ -6133,8 +6026,8 @@ __declspec(naked) void HalfFloatRow_AVX2(const uint16* src, > #endif // HAS_HALFFLOATROW_AVX2 > > #ifdef HAS_HALFFLOATROW_F16C >-__declspec(naked) void HalfFloatRow_F16C(const uint16* src, >- uint16* dst, >+__declspec(naked) void HalfFloatRow_F16C(const uint16_t* src, >+ uint16_t* dst, > float scale, > int width) { > __asm { >@@ -6167,8 +6060,8 @@ __declspec(naked) void HalfFloatRow_F16C(const uint16* src, > > #ifdef HAS_ARGBCOLORTABLEROW_X86 > // Tranform ARGB pixels with color table. >-__declspec(naked) void ARGBColorTableRow_X86(uint8* dst_argb, >- const uint8* table_argb, >+__declspec(naked) void ARGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, > int width) { > __asm { > push esi >@@ -6201,8 +6094,8 @@ __declspec(naked) void ARGBColorTableRow_X86(uint8* dst_argb, > > #ifdef HAS_RGBCOLORTABLEROW_X86 > // Tranform RGB pixels with color table. >-__declspec(naked) void RGBColorTableRow_X86(uint8* dst_argb, >- const uint8* table_argb, >+__declspec(naked) void RGBColorTableRow_X86(uint8_t* dst_argb, >+ const uint8_t* table_argb, > int width) { > __asm { > push esi >@@ -6233,11 +6126,11 @@ __declspec(naked) void RGBColorTableRow_X86(uint8* dst_argb, > > #ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3 > // Tranform RGB pixels with luma table. >-__declspec(naked) void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, >- uint8* dst_argb, >+__declspec(naked) void ARGBLumaColorTableRow_SSSE3(const uint8_t* src_argb, >+ uint8_t* dst_argb, > int width, >- const uint8* luma, >- uint32 lumacoeff) { >+ const uint8_t* luma, >+ uint32_t lumacoeff) { > __asm { > push esi > push edi >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale.cc >index 9104acb95fc..2cfa1c6cb1c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale.cc >@@ -39,12 +39,12 @@ static void ScalePlaneDown2(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width) = >+ void (*ScaleRowDown2)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width) = > filtering == kFilterNone > ? ScaleRowDown2_C > : (filtering == kFilterLinear ? ScaleRowDown2Linear_C >@@ -103,13 +103,6 @@ static void ScalePlaneDown2(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN2_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_ptr, 4) && >- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- ScaleRowDown2 = filtering ? ScaleRowDown2Box_DSPR2 : ScaleRowDown2_DSPR2; >- } >-#endif > #if defined(HAS_SCALEROWDOWN2_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ScaleRowDown2 = >@@ -143,12 +136,12 @@ static void ScalePlaneDown2_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown2)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width) = >+ void (*ScaleRowDown2)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width) = > filtering == kFilterNone > ? ScaleRowDown2_16_C > : (filtering == kFilterLinear ? ScaleRowDown2Linear_16_C >@@ -176,14 +169,6 @@ static void ScalePlaneDown2_16(int src_width, > : ScaleRowDown2Box_16_SSE2); > } > #endif >-#if defined(HAS_SCALEROWDOWN2_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_ptr, 4) && >- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- ScaleRowDown2 = >- filtering ? ScaleRowDown2Box_16_DSPR2 : ScaleRowDown2_16_DSPR2; >- } >-#endif > > if (filtering == kFilterLinear) { > src_stride = 0; >@@ -206,12 +191,12 @@ static void ScalePlaneDown4(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown4)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width) = >+ void (*ScaleRowDown4)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width) = > filtering ? ScaleRowDown4Box_C : ScaleRowDown4_C; > int row_stride = src_stride << 2; > (void)src_width; >@@ -247,13 +232,6 @@ static void ScalePlaneDown4(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN4_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(row_stride, 4) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- ScaleRowDown4 = filtering ? ScaleRowDown4Box_DSPR2 : ScaleRowDown4_DSPR2; >- } >-#endif > #if defined(HAS_SCALEROWDOWN4_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > ScaleRowDown4 = >@@ -280,12 +258,12 @@ static void ScalePlaneDown4_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown4)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width) = >+ void (*ScaleRowDown4)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width) = > filtering ? ScaleRowDown4Box_16_C : ScaleRowDown4_16_C; > int row_stride = src_stride << 2; > (void)src_width; >@@ -306,14 +284,6 @@ static void ScalePlaneDown4_16(int src_width, > filtering ? ScaleRowDown4Box_16_SSE2 : ScaleRowDown4_16_SSE2; > } > #endif >-#if defined(HAS_SCALEROWDOWN4_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(row_stride, 4) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- ScaleRowDown4 = >- filtering ? ScaleRowDown4Box_16_DSPR2 : ScaleRowDown4_16_DSPR2; >- } >-#endif > > if (filtering == kFilterLinear) { > src_stride = 0; >@@ -332,14 +302,14 @@ static void ScalePlaneDown34(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown34_0)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width); >- void (*ScaleRowDown34_1)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width); >+ void (*ScaleRowDown34_0)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width); >+ void (*ScaleRowDown34_1)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width); > const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride; > (void)src_width; > (void)src_height; >@@ -411,19 +381,6 @@ static void ScalePlaneDown34(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN34_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 24 == 0) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- if (!filtering) { >- ScaleRowDown34_0 = ScaleRowDown34_DSPR2; >- ScaleRowDown34_1 = ScaleRowDown34_DSPR2; >- } else { >- ScaleRowDown34_0 = ScaleRowDown34_0_Box_DSPR2; >- ScaleRowDown34_1 = ScaleRowDown34_1_Box_DSPR2; >- } >- } >-#endif > > for (y = 0; y < dst_height - 2; y += 3) { > ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width); >@@ -454,14 +411,14 @@ static void ScalePlaneDown34_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown34_0)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width); >- void (*ScaleRowDown34_1)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width); >+ void (*ScaleRowDown34_0)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width); >+ void (*ScaleRowDown34_1)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width); > const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride; > (void)src_width; > (void)src_height; >@@ -495,19 +452,6 @@ static void ScalePlaneDown34_16(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN34_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 24 == 0) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- if (!filtering) { >- ScaleRowDown34_0 = ScaleRowDown34_16_DSPR2; >- ScaleRowDown34_1 = ScaleRowDown34_16_DSPR2; >- } else { >- ScaleRowDown34_0 = ScaleRowDown34_0_Box_16_DSPR2; >- ScaleRowDown34_1 = ScaleRowDown34_1_Box_16_DSPR2; >- } >- } >-#endif > > for (y = 0; y < dst_height - 2; y += 3) { > ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width); >@@ -553,14 +497,14 @@ static void ScalePlaneDown38(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown38_3)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width); >- void (*ScaleRowDown38_2)(const uint8* src_ptr, ptrdiff_t src_stride, >- uint8* dst_ptr, int dst_width); >+ void (*ScaleRowDown38_3)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width); >+ void (*ScaleRowDown38_2)(const uint8_t* src_ptr, ptrdiff_t src_stride, >+ uint8_t* dst_ptr, int dst_width); > const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride; > assert(dst_width % 3 == 0); > (void)src_width; >@@ -612,19 +556,6 @@ static void ScalePlaneDown38(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN38_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 12 == 0) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- if (!filtering) { >- ScaleRowDown38_3 = ScaleRowDown38_DSPR2; >- ScaleRowDown38_2 = ScaleRowDown38_DSPR2; >- } else { >- ScaleRowDown38_3 = ScaleRowDown38_3_Box_DSPR2; >- ScaleRowDown38_2 = ScaleRowDown38_2_Box_DSPR2; >- } >- } >-#endif > #if defined(HAS_SCALEROWDOWN38_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > if (!filtering) { >@@ -675,14 +606,14 @@ static void ScalePlaneDown38_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > int y; >- void (*ScaleRowDown38_3)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width); >- void (*ScaleRowDown38_2)(const uint16* src_ptr, ptrdiff_t src_stride, >- uint16* dst_ptr, int dst_width); >+ void (*ScaleRowDown38_3)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width); >+ void (*ScaleRowDown38_2)(const uint16_t* src_ptr, ptrdiff_t src_stride, >+ uint16_t* dst_ptr, int dst_width); > const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride; > (void)src_width; > (void)src_height; >@@ -716,19 +647,6 @@ static void ScalePlaneDown38_16(int src_width, > } > } > #endif >-#if defined(HAS_SCALEROWDOWN38_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && (dst_width % 12 == 0) && >- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) && >- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) { >- if (!filtering) { >- ScaleRowDown38_3 = ScaleRowDown38_16_DSPR2; >- ScaleRowDown38_2 = ScaleRowDown38_16_DSPR2; >- } else { >- ScaleRowDown38_3 = ScaleRowDown38_3_Box_16_DSPR2; >- ScaleRowDown38_2 = ScaleRowDown38_2_Box_16_DSPR2; >- } >- } >-#endif > > for (y = 0; y < dst_height - 2; y += 3) { > ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width); >@@ -755,8 +673,8 @@ static void ScalePlaneDown38_16(int src_width, > > #define MIN1(x) ((x) < 1 ? 1 : (x)) > >-static __inline uint32 SumPixels(int iboxwidth, const uint16* src_ptr) { >- uint32 sum = 0u; >+static __inline uint32_t SumPixels(int iboxwidth, const uint16_t* src_ptr) { >+ uint32_t sum = 0u; > int x; > assert(iboxwidth > 0); > for (x = 0; x < iboxwidth; ++x) { >@@ -765,8 +683,8 @@ static __inline uint32 SumPixels(int iboxwidth, const uint16* src_ptr) { > return sum; > } > >-static __inline uint32 SumPixels_16(int iboxwidth, const uint32* src_ptr) { >- uint32 sum = 0u; >+static __inline uint32_t SumPixels_16(int iboxwidth, const uint32_t* src_ptr) { >+ uint32_t sum = 0u; > int x; > assert(iboxwidth > 0); > for (x = 0; x < iboxwidth; ++x) { >@@ -779,8 +697,8 @@ static void ScaleAddCols2_C(int dst_width, > int boxheight, > int x, > int dx, >- const uint16* src_ptr, >- uint8* dst_ptr) { >+ const uint16_t* src_ptr, >+ uint8_t* dst_ptr) { > int i; > int scaletbl[2]; > int minboxwidth = dx >> 16; >@@ -801,8 +719,8 @@ static void ScaleAddCols2_16_C(int dst_width, > int boxheight, > int x, > int dx, >- const uint32* src_ptr, >- uint16* dst_ptr) { >+ const uint32_t* src_ptr, >+ uint16_t* dst_ptr) { > int i; > int scaletbl[2]; > int minboxwidth = dx >> 16; >@@ -823,8 +741,8 @@ static void ScaleAddCols0_C(int dst_width, > int boxheight, > int x, > int dx, >- const uint16* src_ptr, >- uint8* dst_ptr) { >+ const uint16_t* src_ptr, >+ uint8_t* dst_ptr) { > int scaleval = 65536 / boxheight; > int i; > (void)dx; >@@ -838,8 +756,8 @@ static void ScaleAddCols1_C(int dst_width, > int boxheight, > int x, > int dx, >- const uint16* src_ptr, >- uint8* dst_ptr) { >+ const uint16_t* src_ptr, >+ uint8_t* dst_ptr) { > int boxwidth = MIN1(dx >> 16); > int scaleval = 65536 / (boxwidth * boxheight); > int i; >@@ -854,8 +772,8 @@ static void ScaleAddCols1_16_C(int dst_width, > int boxheight, > int x, > int dx, >- const uint32* src_ptr, >- uint16* dst_ptr) { >+ const uint32_t* src_ptr, >+ uint16_t* dst_ptr) { > int boxwidth = MIN1(dx >> 16); > int scaleval = 65536 / (boxwidth * boxheight); > int i; >@@ -878,8 +796,8 @@ static void ScalePlaneBox(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr) { >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr) { > int j, k; > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; >@@ -891,14 +809,14 @@ static void ScalePlaneBox(int src_width, > &dx, &dy); > src_width = Abs(src_width); > { >- // Allocate a row buffer of uint16. >+ // Allocate a row buffer of uint16_t. > align_buffer_64(row16, src_width * 2); > void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx, >- const uint16* src_ptr, uint8* dst_ptr) = >+ const uint16_t* src_ptr, uint8_t* dst_ptr) = > (dx & 0xffff) ? ScaleAddCols2_C > : ((dx != 0x10000) ? ScaleAddCols1_C : ScaleAddCols0_C); >- void (*ScaleAddRow)(const uint8* src_ptr, uint16* dst_ptr, int src_width) = >- ScaleAddRow_C; >+ void (*ScaleAddRow)(const uint8_t* src_ptr, uint16_t* dst_ptr, >+ int src_width) = ScaleAddRow_C; > #if defined(HAS_SCALEADDROW_SSE2) > if (TestCpuFlag(kCpuHasSSE2)) { > ScaleAddRow = ScaleAddRow_Any_SSE2; >@@ -931,19 +849,11 @@ static void ScalePlaneBox(int src_width, > } > } > #endif >-#if defined(HAS_SCALEADDROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- ScaleAddRow = ScaleAddRow_Any_DSPR2; >- if (IS_ALIGNED(src_width, 16)) { >- ScaleAddRow = ScaleAddRow_DSPR2; >- } >- } >-#endif > > for (j = 0; j < dst_height; ++j) { > int boxheight; > int iy = y >> 16; >- const uint8* src = src_ptr + iy * src_stride; >+ const uint8_t* src = src_ptr + iy * src_stride; > y += dy; > if (y > max_y) { > y = max_y; >@@ -951,10 +861,10 @@ static void ScalePlaneBox(int src_width, > boxheight = MIN1((y >> 16) - iy); > memset(row16, 0, src_width * 2); > for (k = 0; k < boxheight; ++k) { >- ScaleAddRow(src, (uint16*)(row16), src_width); >+ ScaleAddRow(src, (uint16_t*)(row16), src_width); > src += src_stride; > } >- ScaleAddCols(dst_width, boxheight, x, dx, (uint16*)(row16), dst_ptr); >+ ScaleAddCols(dst_width, boxheight, x, dx, (uint16_t*)(row16), dst_ptr); > dst_ptr += dst_stride; > } > free_aligned_buffer_64(row16); >@@ -967,8 +877,8 @@ static void ScalePlaneBox_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr) { >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr) { > int j, k; > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; >@@ -980,13 +890,13 @@ static void ScalePlaneBox_16(int src_width, > &dx, &dy); > src_width = Abs(src_width); > { >- // Allocate a row buffer of uint32. >+ // Allocate a row buffer of uint32_t. > align_buffer_64(row32, src_width * 4); > void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx, >- const uint32* src_ptr, uint16* dst_ptr) = >+ const uint32_t* src_ptr, uint16_t* dst_ptr) = > (dx & 0xffff) ? ScaleAddCols2_16_C : ScaleAddCols1_16_C; >- void (*ScaleAddRow)(const uint16* src_ptr, uint32* dst_ptr, int src_width) = >- ScaleAddRow_16_C; >+ void (*ScaleAddRow)(const uint16_t* src_ptr, uint32_t* dst_ptr, >+ int src_width) = ScaleAddRow_16_C; > > #if defined(HAS_SCALEADDROW_16_SSE2) > if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(src_width, 16)) { >@@ -997,7 +907,7 @@ static void ScalePlaneBox_16(int src_width, > for (j = 0; j < dst_height; ++j) { > int boxheight; > int iy = y >> 16; >- const uint16* src = src_ptr + iy * src_stride; >+ const uint16_t* src = src_ptr + iy * src_stride; > y += dy; > if (y > max_y) { > y = max_y; >@@ -1005,10 +915,10 @@ static void ScalePlaneBox_16(int src_width, > boxheight = MIN1((y >> 16) - iy); > memset(row32, 0, src_width * 4); > for (k = 0; k < boxheight; ++k) { >- ScaleAddRow(src, (uint32*)(row32), src_width); >+ ScaleAddRow(src, (uint32_t*)(row32), src_width); > src += src_stride; > } >- ScaleAddCols(dst_width, boxheight, x, dx, (uint32*)(row32), dst_ptr); >+ ScaleAddCols(dst_width, boxheight, x, dx, (uint32_t*)(row32), dst_ptr); > dst_ptr += dst_stride; > } > free_aligned_buffer_64(row32); >@@ -1022,8 +932,8 @@ void ScalePlaneBilinearDown(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; >@@ -1036,10 +946,10 @@ void ScalePlaneBilinearDown(int src_width, > > const int max_y = (src_height - 1) << 16; > int j; >- void (*ScaleFilterCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width, >- int x, int dx) = >+ void (*ScaleFilterCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, >+ int dst_width, int x, int dx) = > (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C; >- void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr, >+ void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, >@@ -1070,14 +980,6 @@ void ScalePlaneBilinearDown(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- InterpolateRow = InterpolateRow_Any_DSPR2; >- if (IS_ALIGNED(src_width, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -1114,7 +1016,7 @@ void ScalePlaneBilinearDown(int src_width, > > for (j = 0; j < dst_height; ++j) { > int yi = y >> 16; >- const uint8* src = src_ptr + yi * src_stride; >+ const uint8_t* src = src_ptr + yi * src_stride; > if (filtering == kFilterLinear) { > ScaleFilterCols(dst_ptr, src, dst_width, x, dx); > } else { >@@ -1137,8 +1039,8 @@ void ScalePlaneBilinearDown_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; >@@ -1151,10 +1053,10 @@ void ScalePlaneBilinearDown_16(int src_width, > > const int max_y = (src_height - 1) << 16; > int j; >- void (*ScaleFilterCols)(uint16 * dst_ptr, const uint16* src_ptr, >+ void (*ScaleFilterCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, > int dst_width, int x, int dx) = > (src_width >= 32768) ? ScaleFilterCols64_16_C : ScaleFilterCols_16_C; >- void (*InterpolateRow)(uint16 * dst_ptr, const uint16* src_ptr, >+ void (*InterpolateRow)(uint16_t * dst_ptr, const uint16_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_16_C; > ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, >@@ -1193,14 +1095,6 @@ void ScalePlaneBilinearDown_16(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- InterpolateRow = InterpolateRow_Any_16_DSPR2; >- if (IS_ALIGNED(src_width, 4)) { >- InterpolateRow = InterpolateRow_16_DSPR2; >- } >- } >-#endif > > #if defined(HAS_SCALEFILTERCOLS_16_SSSE3) > if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) { >@@ -1213,13 +1107,13 @@ void ScalePlaneBilinearDown_16(int src_width, > > for (j = 0; j < dst_height; ++j) { > int yi = y >> 16; >- const uint16* src = src_ptr + yi * src_stride; >+ const uint16_t* src = src_ptr + yi * src_stride; > if (filtering == kFilterLinear) { > ScaleFilterCols(dst_ptr, src, dst_width, x, dx); > } else { > int yf = (y >> 8) & 255; >- InterpolateRow((uint16*)row, src, src_stride, src_width, yf); >- ScaleFilterCols(dst_ptr, (uint16*)row, dst_width, x, dx); >+ InterpolateRow((uint16_t*)row, src, src_stride, src_width, yf); >+ ScaleFilterCols(dst_ptr, (uint16_t*)row, dst_width, x, dx); > } > dst_ptr += dst_stride; > y += dy; >@@ -1237,8 +1131,8 @@ void ScalePlaneBilinearUp(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr, >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr, > enum FilterMode filtering) { > int j; > // Initial source x/y coordinate and step values as 16.16 fixed point. >@@ -1247,11 +1141,11 @@ void ScalePlaneBilinearUp(int src_width, > int dx = 0; > int dy = 0; > const int max_y = (src_height - 1) << 16; >- void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr, >+ void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; >- void (*ScaleFilterCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width, >- int x, int dx) = >+ void (*ScaleFilterCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, >+ int dst_width, int x, int dx) = > filtering ? ScaleFilterCols_C : ScaleCols_C; > ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, > &dx, &dy); >@@ -1281,14 +1175,6 @@ void ScalePlaneBilinearUp(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- InterpolateRow = InterpolateRow_Any_DSPR2; >- if (IS_ALIGNED(dst_width, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >- } >-#endif > > if (filtering && src_width >= 32768) { > ScaleFilterCols = ScaleFilterCols64_C; >@@ -1328,13 +1214,13 @@ void ScalePlaneBilinearUp(int src_width, > } > { > int yi = y >> 16; >- const uint8* src = src_ptr + yi * src_stride; >+ const uint8_t* src = src_ptr + yi * src_stride; > > // Allocate 2 row buffers. > const int kRowSize = (dst_width + 31) & ~31; > align_buffer_64(row, kRowSize * 2); > >- uint8* rowptr = row; >+ uint8_t* rowptr = row; > int rowstride = kRowSize; > int lasty = yi; > >@@ -1380,8 +1266,8 @@ void ScalePlaneBilinearUp_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr, >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr, > enum FilterMode filtering) { > int j; > // Initial source x/y coordinate and step values as 16.16 fixed point. >@@ -1390,10 +1276,10 @@ void ScalePlaneBilinearUp_16(int src_width, > int dx = 0; > int dy = 0; > const int max_y = (src_height - 1) << 16; >- void (*InterpolateRow)(uint16 * dst_ptr, const uint16* src_ptr, >+ void (*InterpolateRow)(uint16_t * dst_ptr, const uint16_t* src_ptr, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_16_C; >- void (*ScaleFilterCols)(uint16 * dst_ptr, const uint16* src_ptr, >+ void (*ScaleFilterCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, > int dst_width, int x, int dx) = > filtering ? ScaleFilterCols_16_C : ScaleCols_16_C; > ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, >@@ -1432,14 +1318,6 @@ void ScalePlaneBilinearUp_16(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2)) { >- InterpolateRow = InterpolateRow_Any_16_DSPR2; >- if (IS_ALIGNED(dst_width, 4)) { >- InterpolateRow = InterpolateRow_16_DSPR2; >- } >- } >-#endif > > if (filtering && src_width >= 32768) { > ScaleFilterCols = ScaleFilterCols64_16_C; >@@ -1463,13 +1341,13 @@ void ScalePlaneBilinearUp_16(int src_width, > } > { > int yi = y >> 16; >- const uint16* src = src_ptr + yi * src_stride; >+ const uint16_t* src = src_ptr + yi * src_stride; > > // Allocate 2 row buffers. > const int kRowSize = (dst_width + 31) & ~31; > align_buffer_64(row, kRowSize * 4); > >- uint16* rowptr = (uint16*)row; >+ uint16_t* rowptr = (uint16_t*)row; > int rowstride = kRowSize; > int lasty = yi; > >@@ -1520,11 +1398,11 @@ static void ScalePlaneSimple(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_ptr, >- uint8* dst_ptr) { >+ const uint8_t* src_ptr, >+ uint8_t* dst_ptr) { > int i; >- void (*ScaleCols)(uint8 * dst_ptr, const uint8* src_ptr, int dst_width, int x, >- int dx) = ScaleCols_C; >+ void (*ScaleCols)(uint8_t * dst_ptr, const uint8_t* src_ptr, int dst_width, >+ int x, int dx) = ScaleCols_C; > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; > int y = 0; >@@ -1556,10 +1434,10 @@ static void ScalePlaneSimple_16(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_ptr, >- uint16* dst_ptr) { >+ const uint16_t* src_ptr, >+ uint16_t* dst_ptr) { > int i; >- void (*ScaleCols)(uint16 * dst_ptr, const uint16* src_ptr, int dst_width, >+ void (*ScaleCols)(uint16_t * dst_ptr, const uint16_t* src_ptr, int dst_width, > int x, int dx) = ScaleCols_16_C; > // Initial source x/y coordinate and step values as 16.16 fixed point. > int x = 0; >@@ -1590,11 +1468,11 @@ static void ScalePlaneSimple_16(int src_width, > // This function dispatches to a specialized scaler based on scale factor. > > LIBYUV_API >-void ScalePlane(const uint8* src, >+void ScalePlane(const uint8_t* src, > int src_stride, > int src_width, > int src_height, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int dst_width, > int dst_height, >@@ -1673,11 +1551,11 @@ void ScalePlane(const uint8* src, > } > > LIBYUV_API >-void ScalePlane_16(const uint16* src, >+void ScalePlane_16(const uint16_t* src, > int src_stride, > int src_width, > int src_height, >- uint16* dst, >+ uint16_t* dst, > int dst_stride, > int dst_width, > int dst_height, >@@ -1759,19 +1637,19 @@ void ScalePlane_16(const uint16* src, > // This function in turn calls a scaling function for each plane. > > LIBYUV_API >-int I420Scale(const uint8* src_y, >+int I420Scale(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, > int src_width, > int src_height, >- uint8* dst_y, >+ uint8_t* dst_y, > int dst_stride_y, >- uint8* dst_u, >+ uint8_t* dst_u, > int dst_stride_u, >- uint8* dst_v, >+ uint8_t* dst_v, > int dst_stride_v, > int dst_width, > int dst_height, >@@ -1796,19 +1674,19 @@ int I420Scale(const uint8* src_y, > } > > LIBYUV_API >-int I420Scale_16(const uint16* src_y, >+int I420Scale_16(const uint16_t* src_y, > int src_stride_y, >- const uint16* src_u, >+ const uint16_t* src_u, > int src_stride_u, >- const uint16* src_v, >+ const uint16_t* src_v, > int src_stride_v, > int src_width, > int src_height, >- uint16* dst_y, >+ uint16_t* dst_y, > int dst_stride_y, >- uint16* dst_u, >+ uint16_t* dst_u, > int dst_stride_u, >- uint16* dst_v, >+ uint16_t* dst_v, > int dst_stride_v, > int dst_width, > int dst_height, >@@ -1834,17 +1712,17 @@ int I420Scale_16(const uint16* src_y, > > // Deprecated api > LIBYUV_API >-int Scale(const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >+int Scale(const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, > int src_stride_y, > int src_stride_u, > int src_stride_v, > int src_width, > int src_height, >- uint8* dst_y, >- uint8* dst_u, >- uint8* dst_v, >+ uint8_t* dst_y, >+ uint8_t* dst_u, >+ uint8_t* dst_v, > int dst_stride_y, > int dst_stride_u, > int dst_stride_v, >@@ -1857,43 +1735,6 @@ int Scale(const uint8* src_y, > dst_height, interpolate ? kFilterBox : kFilterNone); > } > >-// Deprecated api >-LIBYUV_API >-int ScaleOffset(const uint8* src, >- int src_width, >- int src_height, >- uint8* dst, >- int dst_width, >- int dst_height, >- int dst_yoffset, >- LIBYUV_BOOL interpolate) { >- // Chroma requires offset to multiple of 2. >- int dst_yoffset_even = dst_yoffset & ~1; >- int src_halfwidth = SUBSAMPLE(src_width, 1, 1); >- int src_halfheight = SUBSAMPLE(src_height, 1, 1); >- int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1); >- int dst_halfheight = SUBSAMPLE(dst_height, 1, 1); >- int aheight = dst_height - dst_yoffset_even * 2; // actual output height >- const uint8* src_y = src; >- const uint8* src_u = src + src_width * src_height; >- const uint8* src_v = >- src + src_width * src_height + src_halfwidth * src_halfheight; >- uint8* dst_y = dst + dst_yoffset_even * dst_width; >- uint8* dst_u = >- dst + dst_width * dst_height + (dst_yoffset_even >> 1) * dst_halfwidth; >- uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight + >- (dst_yoffset_even >> 1) * dst_halfwidth; >- if (!src || src_width <= 0 || src_height <= 0 || !dst || dst_width <= 0 || >- dst_height <= 0 || dst_yoffset_even < 0 || >- dst_yoffset_even >= dst_height) { >- return -1; >- } >- return I420Scale(src_y, src_width, src_u, src_halfwidth, src_v, src_halfwidth, >- src_width, src_height, dst_y, dst_width, dst_u, >- dst_halfwidth, dst_v, dst_halfwidth, dst_width, aheight, >- interpolate ? kFilterBox : kFilterNone); >-} >- > #ifdef __cplusplus > } // extern "C" > } // namespace libyuv >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_any.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_any.cc >index c4d6626ab72..53ad1364049 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_any.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_any.cc >@@ -19,15 +19,15 @@ extern "C" { > #endif > > // Definition for ScaleFilterCols, ScaleARGBCols and ScaleARGBFilterCols >-#define CANY(NAMEANY, TERP_SIMD, TERP_C, BPP, MASK) \ >- void NAMEANY(uint8* dst_ptr, const uint8* src_ptr, int dst_width, int x, \ >- int dx) { \ >- int r = dst_width & MASK; \ >- int n = dst_width & ~MASK; \ >- if (n > 0) { \ >- TERP_SIMD(dst_ptr, src_ptr, n, x, dx); \ >- } \ >- TERP_C(dst_ptr + n * BPP, src_ptr, r, x + n * dx, dx); \ >+#define CANY(NAMEANY, TERP_SIMD, TERP_C, BPP, MASK) \ >+ void NAMEANY(uint8_t* dst_ptr, const uint8_t* src_ptr, int dst_width, int x, \ >+ int dx) { \ >+ int r = dst_width & MASK; \ >+ int n = dst_width & ~MASK; \ >+ if (n > 0) { \ >+ TERP_SIMD(dst_ptr, src_ptr, n, x, dx); \ >+ } \ >+ TERP_C(dst_ptr + n * BPP, src_ptr, r, x + n * dx, dx); \ > } > > #ifdef HAS_SCALEFILTERCOLS_NEON >@@ -60,31 +60,31 @@ CANY(ScaleARGBFilterCols_Any_MSA, > > // Fixed scale down. > // Mask may be non-power of 2, so use MOD >-#define SDANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, FACTOR, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, ptrdiff_t src_stride, uint8* dst_ptr, \ >- int dst_width) { \ >- int r = (int)((unsigned int)dst_width % (MASK + 1)); /* NOLINT */ \ >- int n = dst_width - r; \ >- if (n > 0) { \ >- SCALEROWDOWN_SIMD(src_ptr, src_stride, dst_ptr, n); \ >- } \ >- SCALEROWDOWN_C(src_ptr + (n * FACTOR) * BPP, src_stride, \ >- dst_ptr + n * BPP, r); \ >+#define SDANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, FACTOR, BPP, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst_ptr, \ >+ int dst_width) { \ >+ int r = (int)((unsigned int)dst_width % (MASK + 1)); /* NOLINT */ \ >+ int n = dst_width - r; \ >+ if (n > 0) { \ >+ SCALEROWDOWN_SIMD(src_ptr, src_stride, dst_ptr, n); \ >+ } \ >+ SCALEROWDOWN_C(src_ptr + (n * FACTOR) * BPP, src_stride, \ >+ dst_ptr + n * BPP, r); \ > } > > // Fixed scale down for odd source width. Used by I420Blend subsampling. > // Since dst_width is (width + 1) / 2, this function scales one less pixel > // and copies the last pixel. >-#define SDODD(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, FACTOR, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, ptrdiff_t src_stride, uint8* dst_ptr, \ >- int dst_width) { \ >- int r = (int)((unsigned int)(dst_width - 1) % (MASK + 1)); /* NOLINT */ \ >- int n = (dst_width - 1) - r; \ >- if (n > 0) { \ >- SCALEROWDOWN_SIMD(src_ptr, src_stride, dst_ptr, n); \ >- } \ >- SCALEROWDOWN_C(src_ptr + (n * FACTOR) * BPP, src_stride, \ >- dst_ptr + n * BPP, r + 1); \ >+#define SDODD(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, FACTOR, BPP, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, ptrdiff_t src_stride, uint8_t* dst_ptr, \ >+ int dst_width) { \ >+ int r = (int)((unsigned int)(dst_width - 1) % (MASK + 1)); /* NOLINT */ \ >+ int n = (dst_width - 1) - r; \ >+ if (n > 0) { \ >+ SCALEROWDOWN_SIMD(src_ptr, src_stride, dst_ptr, n); \ >+ } \ >+ SCALEROWDOWN_C(src_ptr + (n * FACTOR) * BPP, src_stride, \ >+ dst_ptr + n * BPP, r + 1); \ > } > > #ifdef HAS_SCALEROWDOWN2_SSSE3 >@@ -385,16 +385,16 @@ SDANY(ScaleARGBRowDown2Box_Any_MSA, > #undef SDANY > > // Scale down by even scale factor. >-#define SDAANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, BPP, MASK) \ >- void NAMEANY(const uint8* src_ptr, ptrdiff_t src_stride, int src_stepx, \ >- uint8* dst_ptr, int dst_width) { \ >- int r = dst_width & MASK; \ >- int n = dst_width & ~MASK; \ >- if (n > 0) { \ >- SCALEROWDOWN_SIMD(src_ptr, src_stride, src_stepx, dst_ptr, n); \ >- } \ >- SCALEROWDOWN_C(src_ptr + (n * src_stepx) * BPP, src_stride, src_stepx, \ >- dst_ptr + n * BPP, r); \ >+#define SDAANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, BPP, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, ptrdiff_t src_stride, int src_stepx, \ >+ uint8_t* dst_ptr, int dst_width) { \ >+ int r = dst_width & MASK; \ >+ int n = dst_width & ~MASK; \ >+ if (n > 0) { \ >+ SCALEROWDOWN_SIMD(src_ptr, src_stride, src_stepx, dst_ptr, n); \ >+ } \ >+ SCALEROWDOWN_C(src_ptr + (n * src_stepx) * BPP, src_stride, src_stepx, \ >+ dst_ptr + n * BPP, r); \ > } > > #ifdef HAS_SCALEARGBROWDOWNEVEN_SSE2 >@@ -435,13 +435,13 @@ SDAANY(ScaleARGBRowDownEvenBox_Any_MSA, > #endif > > // Add rows box filter scale down. >-#define SAANY(NAMEANY, SCALEADDROW_SIMD, SCALEADDROW_C, MASK) \ >- void NAMEANY(const uint8* src_ptr, uint16* dst_ptr, int src_width) { \ >- int n = src_width & ~MASK; \ >- if (n > 0) { \ >- SCALEADDROW_SIMD(src_ptr, dst_ptr, n); \ >- } \ >- SCALEADDROW_C(src_ptr + n, dst_ptr + n, src_width & MASK); \ >+#define SAANY(NAMEANY, SCALEADDROW_SIMD, SCALEADDROW_C, MASK) \ >+ void NAMEANY(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width) { \ >+ int n = src_width & ~MASK; \ >+ if (n > 0) { \ >+ SCALEADDROW_SIMD(src_ptr, dst_ptr, n); \ >+ } \ >+ SCALEADDROW_C(src_ptr + n, dst_ptr + n, src_width & MASK); \ > } > > #ifdef HAS_SCALEADDROW_SSE2 >@@ -456,9 +456,6 @@ SAANY(ScaleAddRow_Any_NEON, ScaleAddRow_NEON, ScaleAddRow_C, 15) > #ifdef HAS_SCALEADDROW_MSA > SAANY(ScaleAddRow_Any_MSA, ScaleAddRow_MSA, ScaleAddRow_C, 15) > #endif >-#ifdef HAS_SCALEADDROW_DSPR2 >-SAANY(ScaleAddRow_Any_DSPR2, ScaleAddRow_DSPR2, ScaleAddRow_C, 15) >-#endif > #undef SAANY > > #ifdef __cplusplus >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc >index c3ec7d6bb67..53a22e8b41e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc >@@ -36,8 +36,8 @@ static void ScaleARGBDown2(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, >@@ -45,8 +45,8 @@ static void ScaleARGBDown2(int src_width, > enum FilterMode filtering) { > int j; > int row_stride = src_stride * (dy >> 16); >- void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride, >- uint8* dst_argb, int dst_width) = >+ void (*ScaleARGBRowDown2)(const uint8_t* src_argb, ptrdiff_t src_stride, >+ uint8_t* dst_argb, int dst_width) = > filtering == kFilterNone > ? ScaleARGBRowDown2_C > : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_C >@@ -131,8 +131,8 @@ static void ScaleARGBDown4Box(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, >@@ -142,8 +142,8 @@ static void ScaleARGBDown4Box(int src_width, > const int kRowSize = (dst_width * 2 * 4 + 31) & ~31; > align_buffer_64(row, kRowSize * 2); > int row_stride = src_stride * (dy >> 16); >- void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride, >- uint8* dst_argb, int dst_width) = >+ void (*ScaleARGBRowDown2)(const uint8_t* src_argb, ptrdiff_t src_stride, >+ uint8_t* dst_argb, int dst_width) = > ScaleARGBRowDown2Box_C; > // Advance to odd row, even column. > src_argb += (y >> 16) * src_stride + (x >> 16) * 4; >@@ -189,8 +189,8 @@ static void ScaleARGBDownEven(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, >@@ -199,8 +199,8 @@ static void ScaleARGBDownEven(int src_width, > int j; > int col_step = dx >> 16; > int row_stride = (dy >> 16) * src_stride; >- void (*ScaleARGBRowDownEven)(const uint8* src_argb, ptrdiff_t src_stride, >- int src_step, uint8* dst_argb, int dst_width) = >+ void (*ScaleARGBRowDownEven)(const uint8_t* src_argb, ptrdiff_t src_stride, >+ int src_step, uint8_t* dst_argb, int dst_width) = > filtering ? ScaleARGBRowDownEvenBox_C : ScaleARGBRowDownEven_C; > (void)src_width; > (void)src_height; >@@ -255,23 +255,23 @@ static void ScaleARGBBilinearDown(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, > int dy, > enum FilterMode filtering) { > int j; >- void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb, >+ void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; >- void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb, >+ void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, > int dst_width, int x, int dx) = > (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C; >- int64 xlast = x + (int64)(dst_width - 1) * dx; >- int64 xl = (dx >= 0) ? x : xlast; >- int64 xr = (dx >= 0) ? xlast : x; >+ int64_t xlast = x + (int64_t)(dst_width - 1) * dx; >+ int64_t xl = (dx >= 0) ? x : xlast; >+ int64_t xr = (dx >= 0) ? xlast : x; > int clip_src_width; > xl = (xl >> 16) & ~3; // Left edge aligned. > xr = (xr >> 16) + 1; // Right most pixel used. Bilinear uses 2 pixels. >@@ -306,15 +306,6 @@ static void ScaleARGBBilinearDown(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) && >- IS_ALIGNED(src_stride, 4)) { >- InterpolateRow = InterpolateRow_Any_DSPR2; >- if (IS_ALIGNED(clip_src_width, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -355,7 +346,7 @@ static void ScaleARGBBilinearDown(int src_width, > } > for (j = 0; j < dst_height; ++j) { > int yi = y >> 16; >- const uint8* src = src_argb + yi * src_stride; >+ const uint8_t* src = src_argb + yi * src_stride; > if (filtering == kFilterLinear) { > ScaleARGBFilterCols(dst_argb, src, dst_width, x, dx); > } else { >@@ -380,18 +371,18 @@ static void ScaleARGBBilinearUp(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, > int dy, > enum FilterMode filtering) { > int j; >- void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb, >+ void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; >- void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb, >+ void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, > int dst_width, int x, int dx) = > filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C; > const int max_y = (src_height - 1) << 16; >@@ -419,12 +410,6 @@ static void ScaleARGBBilinearUp(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_argb, 4) && >- IS_ALIGNED(dst_stride, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -494,13 +479,13 @@ static void ScaleARGBBilinearUp(int src_width, > > { > int yi = y >> 16; >- const uint8* src = src_argb + yi * src_stride; >+ const uint8_t* src = src_argb + yi * src_stride; > > // Allocate 2 rows of ARGB. > const int kRowSize = (dst_width * 4 + 31) & ~31; > align_buffer_64(row, kRowSize * 2); > >- uint8* rowptr = row; >+ uint8_t* rowptr = row; > int rowstride = kRowSize; > int lasty = yi; > >@@ -550,18 +535,18 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > int src_stride_u, > int src_stride_v, > int dst_stride_argb, >- const uint8* src_y, >- const uint8* src_u, >- const uint8* src_v, >- uint8* dst_argb, >+ const uint8_t* src_y, >+ const uint8_t* src_u, >+ const uint8_t* src_v, >+ uint8_t* dst_argb, > int x, > int dx, > int y, > int dy, > enum FilterMode filtering) { > int j; >- void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf, >- const uint8* v_buf, uint8* rgb_buf, int width) = >+ void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, >+ const uint8_t* v_buf, uint8_t* rgb_buf, int width) = > I422ToARGBRow_C; > #if defined(HAS_I422TOARGBROW_SSSE3) > if (TestCpuFlag(kCpuHasSSSE3)) { >@@ -587,15 +572,6 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > } > } > #endif >-#if defined(HAS_I422TOARGBROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_width, 4) && >- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && >- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && >- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && >- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { >- I422ToARGBRow = I422ToARGBRow_DSPR2; >- } >-#endif > #if defined(HAS_I422TOARGBROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > I422ToARGBRow = I422ToARGBRow_Any_MSA; >@@ -605,7 +581,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > } > #endif > >- void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb, >+ void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > #if defined(HAS_INTERPOLATEROW_SSSE3) >@@ -632,12 +608,6 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_argb, 4) && >- IS_ALIGNED(dst_stride_argb, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -647,7 +617,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > } > #endif > >- void (*ScaleARGBFilterCols)(uint8 * dst_argb, const uint8* src_argb, >+ void (*ScaleARGBFilterCols)(uint8_t * dst_argb, const uint8_t* src_argb, > int dst_width, int x, int dx) = > filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C; > if (src_width >= 32768) { >@@ -712,9 +682,9 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > const int kYShift = 1; // Shift Y by 1 to convert Y plane to UV coordinate. > int yi = y >> 16; > int uv_yi = yi >> kYShift; >- const uint8* src_row_y = src_y + yi * src_stride_y; >- const uint8* src_row_u = src_u + uv_yi * src_stride_u; >- const uint8* src_row_v = src_v + uv_yi * src_stride_v; >+ const uint8_t* src_row_y = src_y + yi * src_stride_y; >+ const uint8_t* src_row_u = src_u + uv_yi * src_stride_u; >+ const uint8_t* src_row_v = src_v + uv_yi * src_stride_v; > > // Allocate 2 rows of ARGB. > const int kRowSize = (dst_width * 4 + 31) & ~31; >@@ -723,7 +693,7 @@ static void ScaleYUVToARGBBilinearUp(int src_width, > // Allocate 1 row of ARGB for source conversion. > align_buffer_64(argb_row, src_width * 4); > >- uint8* rowptr = row; >+ uint8_t* rowptr = row; > int rowstride = kRowSize; > int lasty = yi; > >@@ -795,15 +765,15 @@ static void ScaleARGBSimple(int src_width, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int dx, > int y, > int dy) { > int j; >- void (*ScaleARGBCols)(uint8 * dst_argb, const uint8* src_argb, int dst_width, >- int x, int dx) = >+ void (*ScaleARGBCols)(uint8_t * dst_argb, const uint8_t* src_argb, >+ int dst_width, int x, int dx) = > (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C; > (void)src_height; > #if defined(HAS_SCALEARGBCOLS_SSE2) >@@ -847,11 +817,11 @@ static void ScaleARGBSimple(int src_width, > // ScaleARGB a ARGB. > // This function in turn calls a scaling function > // suitable for handling the desired resolutions. >-static void ScaleARGB(const uint8* src, >+static void ScaleARGB(const uint8_t* src, > int src_stride, > int src_width, > int src_height, >- uint8* dst, >+ uint8_t* dst, > int dst_stride, > int dst_width, > int dst_height, >@@ -880,13 +850,13 @@ static void ScaleARGB(const uint8* src, > &dx, &dy); > src_width = Abs(src_width); > if (clip_x) { >- int64 clipf = (int64)(clip_x)*dx; >+ int64_t clipf = (int64_t)(clip_x)*dx; > x += (clipf & 0xffff); > src += (clipf >> 16) * 4; > dst += clip_x * 4; > } > if (clip_y) { >- int64 clipf = (int64)(clip_y)*dy; >+ int64_t clipf = (int64_t)(clip_y)*dy; > y += (clipf & 0xffff); > src += (clipf >> 16) * src_stride; > dst += clip_y * dst_stride; >@@ -952,11 +922,11 @@ static void ScaleARGB(const uint8* src, > } > > LIBYUV_API >-int ARGBScaleClip(const uint8* src_argb, >+int ARGBScaleClip(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -980,11 +950,11 @@ int ARGBScaleClip(const uint8* src_argb, > > // Scale an ARGB image. > LIBYUV_API >-int ARGBScale(const uint8* src_argb, >+int ARGBScale(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -1001,18 +971,18 @@ int ARGBScale(const uint8* src_argb, > > // Scale with YUV conversion to ARGB and clipping. > LIBYUV_API >-int YUVToARGBScaleClip(const uint8* src_y, >+int YUVToARGBScaleClip(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint32 src_fourcc, >+ uint32_t src_fourcc, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- uint32 dst_fourcc, >+ uint32_t dst_fourcc, > int dst_width, > int dst_height, > int clip_x, >@@ -1020,7 +990,7 @@ int YUVToARGBScaleClip(const uint8* src_y, > int clip_width, > int clip_height, > enum FilterMode filtering) { >- uint8* argb_buffer = (uint8*)malloc(src_width * src_height * 4); >+ uint8_t* argb_buffer = (uint8_t*)malloc(src_width * src_height * 4); > int r; > (void)src_fourcc; // TODO(fbarchard): implement and/or assert. > (void)dst_fourcc; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_common.cc >index fefb027bf76..b28d7da41fc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_common.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_common.cc >@@ -28,9 +28,9 @@ static __inline int Abs(int v) { > } > > // CPU agnostic row functions >-void ScaleRowDown2_C(const uint8* src_ptr, >+void ScaleRowDown2_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -45,9 +45,9 @@ void ScaleRowDown2_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown2_16_C(const uint16* src_ptr, >+void ScaleRowDown2_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -62,11 +62,11 @@ void ScaleRowDown2_16_C(const uint16* src_ptr, > } > } > >-void ScaleRowDown2Linear_C(const uint8* src_ptr, >+void ScaleRowDown2Linear_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { >- const uint8* s = src_ptr; >+ const uint8_t* s = src_ptr; > int x; > (void)src_stride; > for (x = 0; x < dst_width - 1; x += 2) { >@@ -80,11 +80,11 @@ void ScaleRowDown2Linear_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown2Linear_16_C(const uint16* src_ptr, >+void ScaleRowDown2Linear_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { >- const uint16* s = src_ptr; >+ const uint16_t* s = src_ptr; > int x; > (void)src_stride; > for (x = 0; x < dst_width - 1; x += 2) { >@@ -98,12 +98,12 @@ void ScaleRowDown2Linear_16_C(const uint16* src_ptr, > } > } > >-void ScaleRowDown2Box_C(const uint8* src_ptr, >+void ScaleRowDown2Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > for (x = 0; x < dst_width - 1; x += 2) { > dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; >@@ -117,12 +117,12 @@ void ScaleRowDown2Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown2Box_Odd_C(const uint8* src_ptr, >+void ScaleRowDown2Box_Odd_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > dst_width -= 1; > for (x = 0; x < dst_width - 1; x += 2) { >@@ -141,12 +141,12 @@ void ScaleRowDown2Box_Odd_C(const uint8* src_ptr, > dst[0] = (s[0] + t[0] + 1) >> 1; > } > >-void ScaleRowDown2Box_16_C(const uint16* src_ptr, >+void ScaleRowDown2Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { >- const uint16* s = src_ptr; >- const uint16* t = src_ptr + src_stride; >+ const uint16_t* s = src_ptr; >+ const uint16_t* t = src_ptr + src_stride; > int x; > for (x = 0; x < dst_width - 1; x += 2) { > dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; >@@ -160,9 +160,9 @@ void ScaleRowDown2Box_16_C(const uint16* src_ptr, > } > } > >-void ScaleRowDown4_C(const uint8* src_ptr, >+void ScaleRowDown4_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -177,9 +177,9 @@ void ScaleRowDown4_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown4_16_C(const uint16* src_ptr, >+void ScaleRowDown4_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -194,9 +194,9 @@ void ScaleRowDown4_16_C(const uint16* src_ptr, > } > } > >-void ScaleRowDown4Box_C(const uint8* src_ptr, >+void ScaleRowDown4Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > intptr_t stride = src_stride; > int x; >@@ -232,9 +232,9 @@ void ScaleRowDown4Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown4Box_16_C(const uint16* src_ptr, >+void ScaleRowDown4Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > intptr_t stride = src_stride; > int x; >@@ -270,9 +270,9 @@ void ScaleRowDown4Box_16_C(const uint16* src_ptr, > } > } > >-void ScaleRowDown34_C(const uint8* src_ptr, >+void ScaleRowDown34_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -286,9 +286,9 @@ void ScaleRowDown34_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown34_16_C(const uint16* src_ptr, >+void ScaleRowDown34_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -303,21 +303,21 @@ void ScaleRowDown34_16_C(const uint16* src_ptr, > } > > // Filter rows 0 and 1 together, 3 : 1 >-void ScaleRowDown34_0_Box_C(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > assert((dst_width % 3 == 0) && (dst_width > 0)); > for (x = 0; x < dst_width; x += 3) { >- uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >- uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >- uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >- uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >- uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >- uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; >+ uint8_t a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >+ uint8_t a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >+ uint8_t a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >+ uint8_t b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >+ uint8_t b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >+ uint8_t b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; > d[0] = (a0 * 3 + b0 + 2) >> 2; > d[1] = (a1 * 3 + b1 + 2) >> 2; > d[2] = (a2 * 3 + b2 + 2) >> 2; >@@ -327,21 +327,21 @@ void ScaleRowDown34_0_Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown34_0_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* d, >+ uint16_t* d, > int dst_width) { >- const uint16* s = src_ptr; >- const uint16* t = src_ptr + src_stride; >+ const uint16_t* s = src_ptr; >+ const uint16_t* t = src_ptr + src_stride; > int x; > assert((dst_width % 3 == 0) && (dst_width > 0)); > for (x = 0; x < dst_width; x += 3) { >- uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >- uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >- uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >- uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >- uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >- uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; >+ uint16_t a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >+ uint16_t a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >+ uint16_t a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >+ uint16_t b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >+ uint16_t b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >+ uint16_t b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; > d[0] = (a0 * 3 + b0 + 2) >> 2; > d[1] = (a1 * 3 + b1 + 2) >> 2; > d[2] = (a2 * 3 + b2 + 2) >> 2; >@@ -352,21 +352,21 @@ void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr, > } > > // Filter rows 1 and 2 together, 1 : 1 >-void ScaleRowDown34_1_Box_C(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > assert((dst_width % 3 == 0) && (dst_width > 0)); > for (x = 0; x < dst_width; x += 3) { >- uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >- uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >- uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >- uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >- uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >- uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; >+ uint8_t a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >+ uint8_t a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >+ uint8_t a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >+ uint8_t b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >+ uint8_t b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >+ uint8_t b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; > d[0] = (a0 + b0 + 1) >> 1; > d[1] = (a1 + b1 + 1) >> 1; > d[2] = (a2 + b2 + 1) >> 1; >@@ -376,21 +376,21 @@ void ScaleRowDown34_1_Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown34_1_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* d, >+ uint16_t* d, > int dst_width) { >- const uint16* s = src_ptr; >- const uint16* t = src_ptr + src_stride; >+ const uint16_t* s = src_ptr; >+ const uint16_t* t = src_ptr + src_stride; > int x; > assert((dst_width % 3 == 0) && (dst_width > 0)); > for (x = 0; x < dst_width; x += 3) { >- uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >- uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >- uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >- uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >- uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >- uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; >+ uint16_t a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; >+ uint16_t a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; >+ uint16_t a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; >+ uint16_t b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; >+ uint16_t b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; >+ uint16_t b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; > d[0] = (a0 + b0 + 1) >> 1; > d[1] = (a1 + b1 + 1) >> 1; > d[2] = (a2 + b2 + 1) >> 1; >@@ -401,8 +401,8 @@ void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr, > } > > // Scales a single row of pixels using point sampling. >-void ScaleCols_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleCols_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -419,8 +419,8 @@ void ScaleCols_C(uint8* dst_ptr, > } > } > >-void ScaleCols_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleCols_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -438,8 +438,8 @@ void ScaleCols_16_C(uint16* dst_ptr, > } > > // Scales a single row of pixels up by 2x using point sampling. >-void ScaleColsUp2_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleColsUp2_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -456,8 +456,8 @@ void ScaleColsUp2_C(uint8* dst_ptr, > } > } > >-void ScaleColsUp2_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleColsUp2_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -477,15 +477,15 @@ void ScaleColsUp2_16_C(uint16* dst_ptr, > // (1-f)a + fb can be replaced with a + f(b-a) > #if defined(__arm__) || defined(__aarch64__) > #define BLENDER(a, b, f) \ >- (uint8)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) >+ (uint8_t)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) > #else > // Intel uses 7 bit math with rounding. > #define BLENDER(a, b, f) \ >- (uint8)((int)(a) + (((int)((f) >> 9) * ((int)(b) - (int)(a)) + 0x40) >> 7)) >+ (uint8_t)((int)(a) + (((int)((f) >> 9) * ((int)(b) - (int)(a)) + 0x40) >> 7)) > #endif > >-void ScaleFilterCols_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -511,15 +511,15 @@ void ScaleFilterCols_C(uint8* dst_ptr, > } > } > >-void ScaleFilterCols64_C(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols64_C(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x32, > int dx) { >- int64 x = (int64)(x32); >+ int64_t x = (int64_t)(x32); > int j; > for (j = 0; j < dst_width - 1; j += 2) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int a = src_ptr[xi]; > int b = src_ptr[xi + 1]; > dst_ptr[0] = BLENDER(a, b, x & 0xffff); >@@ -532,7 +532,7 @@ void ScaleFilterCols64_C(uint8* dst_ptr, > dst_ptr += 2; > } > if (dst_width & 1) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int a = src_ptr[xi]; > int b = src_ptr[xi + 1]; > dst_ptr[0] = BLENDER(a, b, x & 0xffff); >@@ -540,12 +540,12 @@ void ScaleFilterCols64_C(uint8* dst_ptr, > } > #undef BLENDER > >-// Same as 8 bit arm blender but return is cast to uint16 >+// Same as 8 bit arm blender but return is cast to uint16_t > #define BLENDER(a, b, f) \ >- (uint16)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) >+ (uint16_t)((int)(a) + ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) > >-void ScaleFilterCols_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleFilterCols_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -571,15 +571,15 @@ void ScaleFilterCols_16_C(uint16* dst_ptr, > } > } > >-void ScaleFilterCols64_16_C(uint16* dst_ptr, >- const uint16* src_ptr, >+void ScaleFilterCols64_16_C(uint16_t* dst_ptr, >+ const uint16_t* src_ptr, > int dst_width, > int x32, > int dx) { >- int64 x = (int64)(x32); >+ int64_t x = (int64_t)(x32); > int j; > for (j = 0; j < dst_width - 1; j += 2) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int a = src_ptr[xi]; > int b = src_ptr[xi + 1]; > dst_ptr[0] = BLENDER(a, b, x & 0xffff); >@@ -592,7 +592,7 @@ void ScaleFilterCols64_16_C(uint16* dst_ptr, > dst_ptr += 2; > } > if (dst_width & 1) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int a = src_ptr[xi]; > int b = src_ptr[xi + 1]; > dst_ptr[0] = BLENDER(a, b, x & 0xffff); >@@ -600,9 +600,9 @@ void ScaleFilterCols64_16_C(uint16* dst_ptr, > } > #undef BLENDER > >-void ScaleRowDown38_C(const uint8* src_ptr, >+void ScaleRowDown38_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -616,9 +616,9 @@ void ScaleRowDown38_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown38_16_C(const uint16* src_ptr, >+void ScaleRowDown38_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -633,9 +633,9 @@ void ScaleRowDown38_16_C(const uint16* src_ptr, > } > > // 8x3 -> 3x1 >-void ScaleRowDown38_3_Box_C(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > intptr_t stride = src_stride; > int i; >@@ -663,9 +663,9 @@ void ScaleRowDown38_3_Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown38_3_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int dst_width) { > intptr_t stride = src_stride; > int i; >@@ -694,9 +694,9 @@ void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr, > } > > // 8x2 -> 3x1 >-void ScaleRowDown38_2_Box_C(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_C(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > intptr_t stride = src_stride; > int i; >@@ -719,9 +719,9 @@ void ScaleRowDown38_2_Box_C(const uint8* src_ptr, > } > } > >-void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr, >+void ScaleRowDown38_2_Box_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int dst_width) { > intptr_t stride = src_stride; > int i; >@@ -744,7 +744,7 @@ void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr, > } > } > >-void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width) { >+void ScaleAddRow_C(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width) { > int x; > assert(src_width > 0); > for (x = 0; x < src_width - 1; x += 2) { >@@ -758,7 +758,9 @@ void ScaleAddRow_C(const uint8* src_ptr, uint16* dst_ptr, int src_width) { > } > } > >-void ScaleAddRow_16_C(const uint16* src_ptr, uint32* dst_ptr, int src_width) { >+void ScaleAddRow_16_C(const uint16_t* src_ptr, >+ uint32_t* dst_ptr, >+ int src_width) { > int x; > assert(src_width > 0); > for (x = 0; x < src_width - 1; x += 2) { >@@ -772,12 +774,12 @@ void ScaleAddRow_16_C(const uint16* src_ptr, uint32* dst_ptr, int src_width) { > } > } > >-void ScaleARGBRowDown2_C(const uint8* src_argb, >+void ScaleARGBRowDown2_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int x; > (void)src_stride; > for (x = 0; x < dst_width - 1; x += 2) { >@@ -791,9 +793,9 @@ void ScaleARGBRowDown2_C(const uint8* src_argb, > } > } > >-void ScaleARGBRowDown2Linear_C(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > int x; > (void)src_stride; >@@ -807,9 +809,9 @@ void ScaleARGBRowDown2Linear_C(const uint8* src_argb, > } > } > >-void ScaleARGBRowDown2Box_C(const uint8* src_argb, >+void ScaleARGBRowDown2Box_C(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > int x; > for (x = 0; x < dst_width; ++x) { >@@ -830,13 +832,13 @@ void ScaleARGBRowDown2Box_C(const uint8* src_argb, > } > } > >-void ScaleARGBRowDownEven_C(const uint8* src_argb, >+void ScaleARGBRowDownEven_C(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > (void)src_stride; > int x; > for (x = 0; x < dst_width - 1; x += 2) { >@@ -850,10 +852,10 @@ void ScaleARGBRowDownEven_C(const uint8* src_argb, > } > } > >-void ScaleARGBRowDownEvenBox_C(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_C(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > int x; > for (x = 0; x < dst_width; ++x) { >@@ -875,13 +877,13 @@ void ScaleARGBRowDownEvenBox_C(const uint8* src_argb, > } > > // Scales a single row of pixels using point sampling. >-void ScaleARGBCols_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > for (j = 0; j < dst_width - 1; j += 2) { > dst[0] = src[x >> 16]; >@@ -895,14 +897,14 @@ void ScaleARGBCols_C(uint8* dst_argb, > } > } > >-void ScaleARGBCols64_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols64_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x32, > int dx) { >- int64 x = (int64)(x32); >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ int64_t x = (int64_t)(x32); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > for (j = 0; j < dst_width - 1; j += 2) { > dst[0] = src[x >> 16]; >@@ -917,13 +919,13 @@ void ScaleARGBCols64_C(uint8* dst_argb, > } > > // Scales a single row of pixels up by 2x using point sampling. >-void ScaleARGBColsUp2_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBColsUp2_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > (void)x; > (void)dx; >@@ -941,24 +943,24 @@ void ScaleARGBColsUp2_C(uint8* dst_argb, > // Mimics SSSE3 blender > #define BLENDER1(a, b, f) ((a) * (0x7f ^ f) + (b)*f) >> 7 > #define BLENDERC(a, b, f, s) \ >- (uint32)(BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s) >+ (uint32_t)(BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s) > #define BLENDER(a, b, f) \ > BLENDERC(a, b, f, 24) | BLENDERC(a, b, f, 16) | BLENDERC(a, b, f, 8) | \ > BLENDERC(a, b, f, 0) > >-void ScaleARGBFilterCols_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > for (j = 0; j < dst_width - 1; j += 2) { > int xi = x >> 16; > int xf = (x >> 9) & 0x7f; >- uint32 a = src[xi]; >- uint32 b = src[xi + 1]; >+ uint32_t a = src[xi]; >+ uint32_t b = src[xi + 1]; > dst[0] = BLENDER(a, b, xf); > x += dx; > xi = x >> 16; >@@ -972,26 +974,26 @@ void ScaleARGBFilterCols_C(uint8* dst_argb, > if (dst_width & 1) { > int xi = x >> 16; > int xf = (x >> 9) & 0x7f; >- uint32 a = src[xi]; >- uint32 b = src[xi + 1]; >+ uint32_t a = src[xi]; >+ uint32_t b = src[xi + 1]; > dst[0] = BLENDER(a, b, xf); > } > } > >-void ScaleARGBFilterCols64_C(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols64_C(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x32, > int dx) { >- int64 x = (int64)(x32); >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ int64_t x = (int64_t)(x32); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > for (j = 0; j < dst_width - 1; j += 2) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int xf = (x >> 9) & 0x7f; >- uint32 a = src[xi]; >- uint32 b = src[xi + 1]; >+ uint32_t a = src[xi]; >+ uint32_t b = src[xi + 1]; > dst[0] = BLENDER(a, b, xf); > x += dx; > xi = x >> 16; >@@ -1003,10 +1005,10 @@ void ScaleARGBFilterCols64_C(uint8* dst_argb, > dst += 2; > } > if (dst_width & 1) { >- int64 xi = x >> 16; >+ int64_t xi = x >> 16; > int xf = (x >> 9) & 0x7f; >- uint32 a = src[xi]; >- uint32 b = src[xi + 1]; >+ uint32_t a = src[xi]; >+ uint32_t b = src[xi + 1]; > dst[0] = BLENDER(a, b, xf); > } > } >@@ -1020,8 +1022,8 @@ void ScalePlaneVertical(int src_height, > int dst_height, > int src_stride, > int dst_stride, >- const uint8* src_argb, >- uint8* dst_argb, >+ const uint8_t* src_argb, >+ uint8_t* dst_argb, > int x, > int y, > int dy, >@@ -1029,7 +1031,7 @@ void ScalePlaneVertical(int src_height, > enum FilterMode filtering) { > // TODO(fbarchard): Allow higher bpp. > int dst_width_bytes = dst_width * bpp; >- void (*InterpolateRow)(uint8 * dst_argb, const uint8* src_argb, >+ void (*InterpolateRow)(uint8_t * dst_argb, const uint8_t* src_argb, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_C; > const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; >@@ -1063,16 +1065,6 @@ void ScalePlaneVertical(int src_height, > } > } > #endif >-#if defined(HAS_INTERPOLATEROW_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) && >- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst_argb, 4) && >- IS_ALIGNED(dst_stride, 4)) { >- InterpolateRow = InterpolateRow_Any_DSPR2; >- if (IS_ALIGNED(dst_width_bytes, 4)) { >- InterpolateRow = InterpolateRow_DSPR2; >- } >- } >-#endif > #if defined(HAS_INTERPOLATEROW_MSA) > if (TestCpuFlag(kCpuHasMSA)) { > InterpolateRow = InterpolateRow_Any_MSA; >@@ -1100,8 +1092,8 @@ void ScalePlaneVertical_16(int src_height, > int dst_height, > int src_stride, > int dst_stride, >- const uint16* src_argb, >- uint16* dst_argb, >+ const uint16_t* src_argb, >+ uint16_t* dst_argb, > int x, > int y, > int dy, >@@ -1109,7 +1101,7 @@ void ScalePlaneVertical_16(int src_height, > enum FilterMode filtering) { > // TODO(fbarchard): Allow higher wpp. > int dst_width_words = dst_width * wpp; >- void (*InterpolateRow)(uint16 * dst_argb, const uint16* src_argb, >+ void (*InterpolateRow)(uint16_t * dst_argb, const uint16_t* src_argb, > ptrdiff_t src_stride, int dst_width, > int source_y_fraction) = InterpolateRow_16_C; > const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; >@@ -1150,16 +1142,6 @@ void ScalePlaneVertical_16(int src_height, > InterpolateRow = InterpolateRow_16_NEON; > } > } >-#endif >-#if defined(HAS_INTERPOLATEROW_16_DSPR2) >- if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_argb, 4) && >- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(dst_argb, 4) && >- IS_ALIGNED(dst_stride, 4)) { >- InterpolateRow = InterpolateRow_Any_16_DSPR2; >- if (IS_ALIGNED(dst_width_bytes, 4)) { >- InterpolateRow = InterpolateRow_16_DSPR2; >- } >- } > #endif > for (j = 0; j < dst_height; ++j) { > int yi; >@@ -1222,12 +1204,12 @@ enum FilterMode ScaleFilterReduce(int src_width, > > // Divide num by div and return as 16.16 fixed point result. > int FixedDiv_C(int num, int div) { >- return (int)(((int64)(num) << 16) / div); >+ return (int)(((int64_t)(num) << 16) / div); > } > > // Divide num by div and return as 16.16 fixed point result. > int FixedDiv1_C(int num, int div) { >- return (int)((((int64)(num) << 16) - 0x00010001) / (div - 1)); >+ return (int)((((int64_t)(num) << 16) - 0x00010001) / (div - 1)); > } > > #define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s) >@@ -1308,18 +1290,18 @@ void ScaleSlope(int src_width, > > // Read 8x2 upsample with filtering and write 16x1. > // actually reads an extra pixel, so 9x2. >-void ScaleRowUp2_16_C(const uint16* src_ptr, >+void ScaleRowUp2_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { >- const uint16* src2 = src_ptr + src_stride; >+ const uint16_t* src2 = src_ptr + src_stride; > > int x; > for (x = 0; x < dst_width - 1; x += 2) { >- uint16 p0 = src_ptr[0]; >- uint16 p1 = src_ptr[1]; >- uint16 p2 = src2[0]; >- uint16 p3 = src2[1]; >+ uint16_t p0 = src_ptr[0]; >+ uint16_t p1 = src_ptr[1]; >+ uint16_t p2 = src2[0]; >+ uint16_t p3 = src2[1]; > dst[0] = (p0 * 9 + p1 * 3 + p2 * 3 + p3 + 8) >> 4; > dst[1] = (p0 * 3 + p1 * 9 + p2 + p3 * 3 + 8) >> 4; > ++src_ptr; >@@ -1327,10 +1309,10 @@ void ScaleRowUp2_16_C(const uint16* src_ptr, > dst += 2; > } > if (dst_width & 1) { >- uint16 p0 = src_ptr[0]; >- uint16 p1 = src_ptr[1]; >- uint16 p2 = src2[0]; >- uint16 p3 = src2[1]; >+ uint16_t p0 = src_ptr[0]; >+ uint16_t p1 = src_ptr[1]; >+ uint16_t p2 = src2[0]; >+ uint16_t p3 = src2[1]; > dst[0] = (p0 * 9 + p1 * 3 + p2 * 3 + p3 + 8) >> 4; > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_dspr2.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_dspr2.cc >deleted file mode 100644 >index ddedcbf46c2..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_dspr2.cc >+++ /dev/null >@@ -1,668 +0,0 @@ >-/* >- * Copyright 2012 The LibYuv 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 "libyuv/basic_types.h" >-#include "libyuv/row.h" >- >-#ifdef __cplusplus >-namespace libyuv { >-extern "C" { >-#endif >- >-// This module is for GCC MIPS DSPR2 >-#if !defined(LIBYUV_DISABLE_DSPR2) && defined(__mips_dsp) && \ >- (__mips_dsp_rev >= 2) && (_MIPS_SIM == _MIPS_SIM_ABI32) >- >-void ScaleRowDown2_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "srl $t9, %[dst_width], 4 \n" // iterations -> by 16 >- "beqz $t9, 2f \n" >- " nop \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4| >- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8| >- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12| >- "lw $t4, 16(%[src_ptr]) \n" // |19|18|17|16| >- "lw $t5, 20(%[src_ptr]) \n" // |23|22|21|20| >- "lw $t6, 24(%[src_ptr]) \n" // |27|26|25|24| >- "lw $t7, 28(%[src_ptr]) \n" // |31|30|29|28| >- // TODO(fbarchard): Use odd pixels instead of even. >- "precrq.qb.ph $t8, $t1, $t0 \n" // |7|5|3|1| >- "precrq.qb.ph $t0, $t3, $t2 \n" // |15|13|11|9| >- "precrq.qb.ph $t1, $t5, $t4 \n" // |23|21|19|17| >- "precrq.qb.ph $t2, $t7, $t6 \n" // |31|29|27|25| >- "addiu %[src_ptr], %[src_ptr], 32 \n" >- "addiu $t9, $t9, -1 \n" >- "sw $t8, 0(%[dst]) \n" >- "sw $t0, 4(%[dst]) \n" >- "sw $t1, 8(%[dst]) \n" >- "sw $t2, 12(%[dst]) \n" >- "bgtz $t9, 1b \n" >- " addiu %[dst], %[dst], 16 \n" >- >- "2: \n" >- "andi $t9, %[dst_width], 0xf \n" // residue >- "beqz $t9, 3f \n" >- " nop \n" >- >- "21: \n" >- "lbu $t0, 1(%[src_ptr]) \n" >- "addiu %[src_ptr], %[src_ptr], 2 \n" >- "addiu $t9, $t9, -1 \n" >- "sb $t0, 0(%[dst]) \n" >- "bgtz $t9, 21b \n" >- " addiu %[dst], %[dst], 1 \n" >- >- "3: \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst) >- : [dst_width] "r"(dst_width) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void ScaleRowDown2Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- const uint8* t = src_ptr + src_stride; >- >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "srl $t9, %[dst_width], 3 \n" // iterations -> step 8 >- "bltz $t9, 2f \n" >- " nop \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4| >- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8| >- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12| >- "lw $t4, 0(%[t]) \n" // |19|18|17|16| >- "lw $t5, 4(%[t]) \n" // |23|22|21|20| >- "lw $t6, 8(%[t]) \n" // |27|26|25|24| >- "lw $t7, 12(%[t]) \n" // |31|30|29|28| >- "addiu $t9, $t9, -1 \n" >- "srl $t8, $t0, 16 \n" // |X|X|3|2| >- "ins $t0, $t4, 16, 16 \n" // |17|16|1|0| >- "ins $t4, $t8, 0, 16 \n" // |19|18|3|2| >- "raddu.w.qb $t0, $t0 \n" // |17+16+1+0| >- "raddu.w.qb $t4, $t4 \n" // |19+18+3+2| >- "shra_r.w $t0, $t0, 2 \n" // |t0+2|>>2 >- "shra_r.w $t4, $t4, 2 \n" // |t4+2|>>2 >- "srl $t8, $t1, 16 \n" // |X|X|7|6| >- "ins $t1, $t5, 16, 16 \n" // |21|20|5|4| >- "ins $t5, $t8, 0, 16 \n" // |22|23|7|6| >- "raddu.w.qb $t1, $t1 \n" // |21+20+5+4| >- "raddu.w.qb $t5, $t5 \n" // |23+22+7+6| >- "shra_r.w $t1, $t1, 2 \n" // |t1+2|>>2 >- "shra_r.w $t5, $t5, 2 \n" // |t5+2|>>2 >- "srl $t8, $t2, 16 \n" // |X|X|11|10| >- "ins $t2, $t6, 16, 16 \n" // |25|24|9|8| >- "ins $t6, $t8, 0, 16 \n" // |27|26|11|10| >- "raddu.w.qb $t2, $t2 \n" // |25+24+9+8| >- "raddu.w.qb $t6, $t6 \n" // |27+26+11+10| >- "shra_r.w $t2, $t2, 2 \n" // |t2+2|>>2 >- "shra_r.w $t6, $t6, 2 \n" // |t5+2|>>2 >- "srl $t8, $t3, 16 \n" // |X|X|15|14| >- "ins $t3, $t7, 16, 16 \n" // |29|28|13|12| >- "ins $t7, $t8, 0, 16 \n" // |31|30|15|14| >- "raddu.w.qb $t3, $t3 \n" // |29+28+13+12| >- "raddu.w.qb $t7, $t7 \n" // |31+30+15+14| >- "shra_r.w $t3, $t3, 2 \n" // |t3+2|>>2 >- "shra_r.w $t7, $t7, 2 \n" // |t7+2|>>2 >- "addiu %[src_ptr], %[src_ptr], 16 \n" >- "addiu %[t], %[t], 16 \n" >- "sb $t0, 0(%[dst]) \n" >- "sb $t4, 1(%[dst]) \n" >- "sb $t1, 2(%[dst]) \n" >- "sb $t5, 3(%[dst]) \n" >- "sb $t2, 4(%[dst]) \n" >- "sb $t6, 5(%[dst]) \n" >- "sb $t3, 6(%[dst]) \n" >- "sb $t7, 7(%[dst]) \n" >- "bgtz $t9, 1b \n" >- " addiu %[dst], %[dst], 8 \n" >- >- "2: \n" >- "andi $t9, %[dst_width], 0x7 \n" // x = residue >- "beqz $t9, 3f \n" >- " nop \n" >- >- "21: \n" >- "lwr $t1, 0(%[src_ptr]) \n" >- "lwl $t1, 3(%[src_ptr]) \n" >- "lwr $t2, 0(%[t]) \n" >- "lwl $t2, 3(%[t]) \n" >- "srl $t8, $t1, 16 \n" >- "ins $t1, $t2, 16, 16 \n" >- "ins $t2, $t8, 0, 16 \n" >- "raddu.w.qb $t1, $t1 \n" >- "raddu.w.qb $t2, $t2 \n" >- "shra_r.w $t1, $t1, 2 \n" >- "shra_r.w $t2, $t2, 2 \n" >- "sb $t1, 0(%[dst]) \n" >- "sb $t2, 1(%[dst]) \n" >- "addiu %[src_ptr], %[src_ptr], 4 \n" >- "addiu $t9, $t9, -2 \n" >- "addiu %[t], %[t], 4 \n" >- "bgtz $t9, 21b \n" >- " addiu %[dst], %[dst], 2 \n" >- >- "3: \n" >- ".set pop \n" >- >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst), [t] "+r"(t) >- : [dst_width] "r"(dst_width) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void ScaleRowDown4_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "srl $t9, %[dst_width], 3 \n" >- "beqz $t9, 2f \n" >- " nop \n" >- >- "1: \n" >- "lw $t1, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t2, 4(%[src_ptr]) \n" // |7|6|5|4| >- "lw $t3, 8(%[src_ptr]) \n" // |11|10|9|8| >- "lw $t4, 12(%[src_ptr]) \n" // |15|14|13|12| >- "lw $t5, 16(%[src_ptr]) \n" // |19|18|17|16| >- "lw $t6, 20(%[src_ptr]) \n" // |23|22|21|20| >- "lw $t7, 24(%[src_ptr]) \n" // |27|26|25|24| >- "lw $t8, 28(%[src_ptr]) \n" // |31|30|29|28| >- "precr.qb.ph $t1, $t2, $t1 \n" // |6|4|2|0| >- "precr.qb.ph $t2, $t4, $t3 \n" // |14|12|10|8| >- "precr.qb.ph $t5, $t6, $t5 \n" // |22|20|18|16| >- "precr.qb.ph $t6, $t8, $t7 \n" // |30|28|26|24| >- "precrq.qb.ph $t1, $t2, $t1 \n" // |14|10|6|2| >- "precrq.qb.ph $t5, $t6, $t5 \n" // |30|26|22|18| >- "addiu %[src_ptr], %[src_ptr], 32 \n" >- "addiu $t9, $t9, -1 \n" >- "sw $t1, 0(%[dst]) \n" >- "sw $t5, 4(%[dst]) \n" >- "bgtz $t9, 1b \n" >- " addiu %[dst], %[dst], 8 \n" >- >- "2: \n" >- "andi $t9, %[dst_width], 7 \n" // residue >- "beqz $t9, 3f \n" >- " nop \n" >- >- "21: \n" >- "lbu $t1, 2(%[src_ptr]) \n" >- "addiu %[src_ptr], %[src_ptr], 4 \n" >- "addiu $t9, $t9, -1 \n" >- "sb $t1, 0(%[dst]) \n" >- "bgtz $t9, 21b \n" >- " addiu %[dst], %[dst], 1 \n" >- >- "3: \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst) >- : [dst_width] "r"(dst_width) >- : "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void ScaleRowDown4Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- intptr_t stride = src_stride; >- const uint8* s1 = src_ptr + stride; >- const uint8* s2 = s1 + stride; >- const uint8* s3 = s2 + stride; >- >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "srl $t9, %[dst_width], 1 \n" >- "andi $t8, %[dst_width], 1 \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t1, 0(%[s1]) \n" // |7|6|5|4| >- "lw $t2, 0(%[s2]) \n" // |11|10|9|8| >- "lw $t3, 0(%[s3]) \n" // |15|14|13|12| >- "lw $t4, 4(%[src_ptr]) \n" // |19|18|17|16| >- "lw $t5, 4(%[s1]) \n" // |23|22|21|20| >- "lw $t6, 4(%[s2]) \n" // |27|26|25|24| >- "lw $t7, 4(%[s3]) \n" // |31|30|29|28| >- "raddu.w.qb $t0, $t0 \n" // |3 + 2 + 1 + 0| >- "raddu.w.qb $t1, $t1 \n" // |7 + 6 + 5 + 4| >- "raddu.w.qb $t2, $t2 \n" // |11 + 10 + 9 + 8| >- "raddu.w.qb $t3, $t3 \n" // |15 + 14 + 13 + 12| >- "raddu.w.qb $t4, $t4 \n" // |19 + 18 + 17 + 16| >- "raddu.w.qb $t5, $t5 \n" // |23 + 22 + 21 + 20| >- "raddu.w.qb $t6, $t6 \n" // |27 + 26 + 25 + 24| >- "raddu.w.qb $t7, $t7 \n" // |31 + 30 + 29 + 28| >- "add $t0, $t0, $t1 \n" >- "add $t1, $t2, $t3 \n" >- "add $t0, $t0, $t1 \n" >- "add $t4, $t4, $t5 \n" >- "add $t6, $t6, $t7 \n" >- "add $t4, $t4, $t6 \n" >- "shra_r.w $t0, $t0, 4 \n" >- "shra_r.w $t4, $t4, 4 \n" >- "sb $t0, 0(%[dst]) \n" >- "sb $t4, 1(%[dst]) \n" >- "addiu %[src_ptr], %[src_ptr], 8 \n" >- "addiu %[s1], %[s1], 8 \n" >- "addiu %[s2], %[s2], 8 \n" >- "addiu %[s3], %[s3], 8 \n" >- "addiu $t9, $t9, -1 \n" >- "bgtz $t9, 1b \n" >- " addiu %[dst], %[dst], 2 \n" >- "beqz $t8, 2f \n" >- " nop \n" >- >- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t1, 0(%[s1]) \n" // |7|6|5|4| >- "lw $t2, 0(%[s2]) \n" // |11|10|9|8| >- "lw $t3, 0(%[s3]) \n" // |15|14|13|12| >- "raddu.w.qb $t0, $t0 \n" // |3 + 2 + 1 + 0| >- "raddu.w.qb $t1, $t1 \n" // |7 + 6 + 5 + 4| >- "raddu.w.qb $t2, $t2 \n" // |11 + 10 + 9 + 8| >- "raddu.w.qb $t3, $t3 \n" // |15 + 14 + 13 + 12| >- "add $t0, $t0, $t1 \n" >- "add $t1, $t2, $t3 \n" >- "add $t0, $t0, $t1 \n" >- "shra_r.w $t0, $t0, 4 \n" >- "sb $t0, 0(%[dst]) \n" >- >- "2: \n" >- ".set pop \n" >- >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst), [s1] "+r"(s1), [s2] "+r"(s2), >- [s3] "+r"(s3) >- : [dst_width] "r"(dst_width) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void ScaleRowDown34_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "1: \n" >- "lw $t1, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t2, 4(%[src_ptr]) \n" // |7|6|5|4| >- "lw $t3, 8(%[src_ptr]) \n" // |11|10|9|8| >- "lw $t4, 12(%[src_ptr]) \n" // |15|14|13|12| >- "lw $t5, 16(%[src_ptr]) \n" // |19|18|17|16| >- "lw $t6, 20(%[src_ptr]) \n" // |23|22|21|20| >- "lw $t7, 24(%[src_ptr]) \n" // |27|26|25|24| >- "lw $t8, 28(%[src_ptr]) \n" // |31|30|29|28| >- "precrq.qb.ph $t0, $t2, $t4 \n" // |7|5|15|13| >- "precrq.qb.ph $t9, $t6, $t8 \n" // |23|21|31|30| >- "addiu %[dst_width], %[dst_width], -24 \n" >- "ins $t1, $t1, 8, 16 \n" // |3|1|0|X| >- "ins $t4, $t0, 8, 16 \n" // |X|15|13|12| >- "ins $t5, $t5, 8, 16 \n" // |19|17|16|X| >- "ins $t8, $t9, 8, 16 \n" // |X|31|29|28| >- "addiu %[src_ptr], %[src_ptr], 32 \n" >- "packrl.ph $t0, $t3, $t0 \n" // |9|8|7|5| >- "packrl.ph $t9, $t7, $t9 \n" // |25|24|23|21| >- "prepend $t1, $t2, 8 \n" // |4|3|1|0| >- "prepend $t3, $t4, 24 \n" // |15|13|12|11| >- "prepend $t5, $t6, 8 \n" // |20|19|17|16| >- "prepend $t7, $t8, 24 \n" // |31|29|28|27| >- "sw $t1, 0(%[dst]) \n" >- "sw $t0, 4(%[dst]) \n" >- "sw $t3, 8(%[dst]) \n" >- "sw $t5, 12(%[dst]) \n" >- "sw $t9, 16(%[dst]) \n" >- "sw $t7, 20(%[dst]) \n" >- "bnez %[dst_width], 1b \n" >- " addiu %[dst], %[dst], 24 \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst), [dst_width] "+r"(dst_width) >- : >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"); >-} >- >-void ScaleRowDown34_0_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* d, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "repl.ph $t3, 3 \n" // 0x00030003 >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0| >- "lwx $t1, %[src_stride](%[src_ptr]) \n" // |T3|T2|T1|T0| >- "rotr $t2, $t0, 8 \n" // |S0|S3|S2|S1| >- "rotr $t6, $t1, 8 \n" // |T0|T3|T2|T1| >- "muleu_s.ph.qbl $t4, $t2, $t3 \n" // |S0*3|S3*3| >- "muleu_s.ph.qbl $t5, $t6, $t3 \n" // |T0*3|T3*3| >- "andi $t0, $t2, 0xFFFF \n" // |0|0|S2|S1| >- "andi $t1, $t6, 0xFFFF \n" // |0|0|T2|T1| >- "raddu.w.qb $t0, $t0 \n" >- "raddu.w.qb $t1, $t1 \n" >- "shra_r.w $t0, $t0, 1 \n" >- "shra_r.w $t1, $t1, 1 \n" >- "preceu.ph.qbr $t2, $t2 \n" // |0|S2|0|S1| >- "preceu.ph.qbr $t6, $t6 \n" // |0|T2|0|T1| >- "rotr $t2, $t2, 16 \n" // |0|S1|0|S2| >- "rotr $t6, $t6, 16 \n" // |0|T1|0|T2| >- "addu.ph $t2, $t2, $t4 \n" >- "addu.ph $t6, $t6, $t5 \n" >- "sll $t5, $t0, 1 \n" >- "add $t0, $t5, $t0 \n" >- "shra_r.ph $t2, $t2, 2 \n" >- "shra_r.ph $t6, $t6, 2 \n" >- "shll.ph $t4, $t2, 1 \n" >- "addq.ph $t4, $t4, $t2 \n" >- "addu $t0, $t0, $t1 \n" >- "addiu %[src_ptr], %[src_ptr], 4 \n" >- "shra_r.w $t0, $t0, 2 \n" >- "addu.ph $t6, $t6, $t4 \n" >- "shra_r.ph $t6, $t6, 2 \n" >- "srl $t1, $t6, 16 \n" >- "addiu %[dst_width], %[dst_width], -3 \n" >- "sb $t1, 0(%[d]) \n" >- "sb $t0, 1(%[d]) \n" >- "sb $t6, 2(%[d]) \n" >- "bgtz %[dst_width], 1b \n" >- " addiu %[d], %[d], 3 \n" >- "3: \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [src_stride] "+r"(src_stride), [d] "+r"(d), >- [dst_width] "+r"(dst_width) >- : >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6"); >-} >- >-void ScaleRowDown34_1_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* d, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "repl.ph $t2, 3 \n" // 0x00030003 >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0| >- "lwx $t1, %[src_stride](%[src_ptr]) \n" // |T3|T2|T1|T0| >- "rotr $t4, $t0, 8 \n" // |S0|S3|S2|S1| >- "rotr $t6, $t1, 8 \n" // |T0|T3|T2|T1| >- "muleu_s.ph.qbl $t3, $t4, $t2 \n" // |S0*3|S3*3| >- "muleu_s.ph.qbl $t5, $t6, $t2 \n" // |T0*3|T3*3| >- "andi $t0, $t4, 0xFFFF \n" // |0|0|S2|S1| >- "andi $t1, $t6, 0xFFFF \n" // |0|0|T2|T1| >- "raddu.w.qb $t0, $t0 \n" >- "raddu.w.qb $t1, $t1 \n" >- "shra_r.w $t0, $t0, 1 \n" >- "shra_r.w $t1, $t1, 1 \n" >- "preceu.ph.qbr $t4, $t4 \n" // |0|S2|0|S1| >- "preceu.ph.qbr $t6, $t6 \n" // |0|T2|0|T1| >- "rotr $t4, $t4, 16 \n" // |0|S1|0|S2| >- "rotr $t6, $t6, 16 \n" // |0|T1|0|T2| >- "addu.ph $t4, $t4, $t3 \n" >- "addu.ph $t6, $t6, $t5 \n" >- "shra_r.ph $t6, $t6, 2 \n" >- "shra_r.ph $t4, $t4, 2 \n" >- "addu.ph $t6, $t6, $t4 \n" >- "addiu %[src_ptr], %[src_ptr], 4 \n" >- "shra_r.ph $t6, $t6, 1 \n" >- "addu $t0, $t0, $t1 \n" >- "addiu %[dst_width], %[dst_width], -3 \n" >- "shra_r.w $t0, $t0, 1 \n" >- "srl $t1, $t6, 16 \n" >- "sb $t1, 0(%[d]) \n" >- "sb $t0, 1(%[d]) \n" >- "sb $t6, 2(%[d]) \n" >- "bgtz %[dst_width], 1b \n" >- " addiu %[d], %[d], 3 \n" >- "3: \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [src_stride] "+r"(src_stride), [d] "+r"(d), >- [dst_width] "+r"(dst_width) >- : >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6"); >-} >- >-void ScaleRowDown38_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst, >- int dst_width) { >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0| >- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4| >- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8| >- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12| >- "lw $t4, 16(%[src_ptr]) \n" // |19|18|17|16| >- "lw $t5, 20(%[src_ptr]) \n" // |23|22|21|20| >- "lw $t6, 24(%[src_ptr]) \n" // |27|26|25|24| >- "lw $t7, 28(%[src_ptr]) \n" // |31|30|29|28| >- "wsbh $t0, $t0 \n" // |2|3|0|1| >- "wsbh $t6, $t6 \n" // |26|27|24|25| >- "srl $t0, $t0, 8 \n" // |X|2|3|0| >- "srl $t3, $t3, 16 \n" // |X|X|15|14| >- "srl $t5, $t5, 16 \n" // |X|X|23|22| >- "srl $t7, $t7, 16 \n" // |X|X|31|30| >- "ins $t1, $t2, 24, 8 \n" // |8|6|5|4| >- "ins $t6, $t5, 0, 8 \n" // |26|27|24|22| >- "ins $t1, $t0, 0, 16 \n" // |8|6|3|0| >- "ins $t6, $t7, 24, 8 \n" // |30|27|24|22| >- "prepend $t2, $t3, 24 \n" // |X|15|14|11| >- "ins $t4, $t4, 16, 8 \n" // |19|16|17|X| >- "ins $t4, $t2, 0, 16 \n" // |19|16|14|11| >- "addiu %[src_ptr], %[src_ptr], 32 \n" >- "addiu %[dst_width], %[dst_width], -12 \n" >- "addiu $t8,%[dst_width], -12 \n" >- "sw $t1, 0(%[dst]) \n" >- "sw $t4, 4(%[dst]) \n" >- "sw $t6, 8(%[dst]) \n" >- "bgez $t8, 1b \n" >- " addiu %[dst], %[dst], 12 \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst] "+r"(dst), [dst_width] "+r"(dst_width) >- : >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8"); >-} >- >-void ScaleRowDown38_2_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst_ptr, >- int dst_width) { >- intptr_t stride = src_stride; >- const uint8* t = src_ptr + stride; >- const int c = 0x2AAA; >- >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0| >- "lw $t1, 4(%[src_ptr]) \n" // |S7|S6|S5|S4| >- "lw $t2, 0(%[t]) \n" // |T3|T2|T1|T0| >- "lw $t3, 4(%[t]) \n" // |T7|T6|T5|T4| >- "rotr $t1, $t1, 16 \n" // |S5|S4|S7|S6| >- "packrl.ph $t4, $t1, $t3 \n" // |S7|S6|T7|T6| >- "packrl.ph $t5, $t3, $t1 \n" // |T5|T4|S5|S4| >- "raddu.w.qb $t4, $t4 \n" // S7+S6+T7+T6 >- "raddu.w.qb $t5, $t5 \n" // T5+T4+S5+S4 >- "precrq.qb.ph $t6, $t0, $t2 \n" // |S3|S1|T3|T1| >- "precrq.qb.ph $t6, $t6, $t6 \n" // |S3|T3|S3|T3| >- "srl $t4, $t4, 2 \n" // t4 / 4 >- "srl $t6, $t6, 16 \n" // |0|0|S3|T3| >- "raddu.w.qb $t6, $t6 \n" // 0+0+S3+T3 >- "addu $t6, $t5, $t6 \n" >- "mul $t6, $t6, %[c] \n" // t6 * 0x2AAA >- "sll $t0, $t0, 8 \n" // |S2|S1|S0|0| >- "sll $t2, $t2, 8 \n" // |T2|T1|T0|0| >- "raddu.w.qb $t0, $t0 \n" // S2+S1+S0+0 >- "raddu.w.qb $t2, $t2 \n" // T2+T1+T0+0 >- "addu $t0, $t0, $t2 \n" >- "mul $t0, $t0, %[c] \n" // t0 * 0x2AAA >- "addiu %[src_ptr], %[src_ptr], 8 \n" >- "addiu %[t], %[t], 8 \n" >- "addiu %[dst_width], %[dst_width], -3 \n" >- "addiu %[dst_ptr], %[dst_ptr], 3 \n" >- "srl $t6, $t6, 16 \n" >- "srl $t0, $t0, 16 \n" >- "sb $t4, -1(%[dst_ptr]) \n" >- "sb $t6, -2(%[dst_ptr]) \n" >- "bgtz %[dst_width], 1b \n" >- " sb $t0, -3(%[dst_ptr]) \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst_ptr] "+r"(dst_ptr), [t] "+r"(t), >- [dst_width] "+r"(dst_width) >- : [c] "r"(c) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6"); >-} >- >-void ScaleRowDown38_3_Box_DSPR2(const uint8* src_ptr, >- ptrdiff_t src_stride, >- uint8* dst_ptr, >- int dst_width) { >- intptr_t stride = src_stride; >- const uint8* s1 = src_ptr + stride; >- stride += stride; >- const uint8* s2 = src_ptr + stride; >- const int c1 = 0x1C71; >- const int c2 = 0x2AAA; >- >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- >- "1: \n" >- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0| >- "lw $t1, 4(%[src_ptr]) \n" // |S7|S6|S5|S4| >- "lw $t2, 0(%[s1]) \n" // |T3|T2|T1|T0| >- "lw $t3, 4(%[s1]) \n" // |T7|T6|T5|T4| >- "lw $t4, 0(%[s2]) \n" // |R3|R2|R1|R0| >- "lw $t5, 4(%[s2]) \n" // |R7|R6|R5|R4| >- "rotr $t1, $t1, 16 \n" // |S5|S4|S7|S6| >- "packrl.ph $t6, $t1, $t3 \n" // |S7|S6|T7|T6| >- "raddu.w.qb $t6, $t6 \n" // S7+S6+T7+T6 >- "packrl.ph $t7, $t3, $t1 \n" // |T5|T4|S5|S4| >- "raddu.w.qb $t7, $t7 \n" // T5+T4+S5+S4 >- "sll $t8, $t5, 16 \n" // |R5|R4|0|0| >- "raddu.w.qb $t8, $t8 \n" // R5+R4 >- "addu $t7, $t7, $t8 \n" >- "srl $t8, $t5, 16 \n" // |0|0|R7|R6| >- "raddu.w.qb $t8, $t8 \n" // R7 + R6 >- "addu $t6, $t6, $t8 \n" >- "mul $t6, $t6, %[c2] \n" // t6 * 0x2AAA >- "precrq.qb.ph $t8, $t0, $t2 \n" // |S3|S1|T3|T1| >- "precrq.qb.ph $t8, $t8, $t4 \n" // |S3|T3|R3|R1| >- "srl $t8, $t8, 8 \n" // |0|S3|T3|R3| >- "raddu.w.qb $t8, $t8 \n" // S3 + T3 + R3 >- "addu $t7, $t7, $t8 \n" >- "mul $t7, $t7, %[c1] \n" // t7 * 0x1C71 >- "sll $t0, $t0, 8 \n" // |S2|S1|S0|0| >- "sll $t2, $t2, 8 \n" // |T2|T1|T0|0| >- "sll $t4, $t4, 8 \n" // |R2|R1|R0|0| >- "raddu.w.qb $t0, $t0 \n" >- "raddu.w.qb $t2, $t2 \n" >- "raddu.w.qb $t4, $t4 \n" >- "addu $t0, $t0, $t2 \n" >- "addu $t0, $t0, $t4 \n" >- "mul $t0, $t0, %[c1] \n" // t0 * 0x1C71 >- "addiu %[src_ptr], %[src_ptr], 8 \n" >- "addiu %[s1], %[s1], 8 \n" >- "addiu %[s2], %[s2], 8 \n" >- "addiu %[dst_width], %[dst_width], -3 \n" >- "addiu %[dst_ptr], %[dst_ptr], 3 \n" >- "srl $t6, $t6, 16 \n" >- "srl $t7, $t7, 16 \n" >- "srl $t0, $t0, 16 \n" >- "sb $t6, -1(%[dst_ptr]) \n" >- "sb $t7, -2(%[dst_ptr]) \n" >- "bgtz %[dst_width], 1b \n" >- " sb $t0, -3(%[dst_ptr]) \n" >- ".set pop \n" >- : [src_ptr] "+r"(src_ptr), [dst_ptr] "+r"(dst_ptr), [s1] "+r"(s1), >- [s2] "+r"(s2), [dst_width] "+r"(dst_width) >- : [c1] "r"(c1), [c2] "r"(c2) >- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8"); >-} >- >-void ScaleAddRow_DSPR2(const uint8* src_ptr, uint16* dst_ptr, int src_width) { >- int x; >- for (x = 0; x < ((src_width - 1)); x += 8) { >- uint32 tmp_t1, tmp_t2, tmp_t3, tmp_t4; >- uint32 tmp_t5, tmp_t6, tmp_t7, tmp_t8; >- __asm__ __volatile__( >- ".set push \n" >- ".set noreorder \n" >- "lw %[tmp_t5], 0(%[src_ptr]) \n" >- "lw %[tmp_t6], 4(%[src_ptr]) \n" >- "lw %[tmp_t1], 0(%[dst_ptr]) \n" >- "lw %[tmp_t2], 4(%[dst_ptr]) \n" >- "lw %[tmp_t3], 8(%[dst_ptr]) \n" >- "lw %[tmp_t4], 12(%[dst_ptr]) \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t5] \n" >- "preceu.ph.qbl %[tmp_t8], %[tmp_t5] \n" >- "addu.ph %[tmp_t1], %[tmp_t1], %[tmp_t7] \n" >- "addu.ph %[tmp_t2], %[tmp_t2], %[tmp_t8] \n" >- "preceu.ph.qbr %[tmp_t7], %[tmp_t6] \n" >- "preceu.ph.qbl %[tmp_t8], %[tmp_t6] \n" >- "addu.ph %[tmp_t3], %[tmp_t3], %[tmp_t7] \n" >- "addu.ph %[tmp_t4], %[tmp_t4], %[tmp_t8] \n" >- "sw %[tmp_t1], 0(%[dst_ptr]) \n" >- "sw %[tmp_t2], 4(%[dst_ptr]) \n" >- "sw %[tmp_t3], 8(%[dst_ptr]) \n" >- "sw %[tmp_t4], 12(%[dst_ptr]) \n" >- ".set pop \n" >- : >- [tmp_t1] "=&r"(tmp_t1), [tmp_t2] "=&r"(tmp_t2), [tmp_t3] "=&r"(tmp_t3), >- [tmp_t4] "=&r"(tmp_t4), [tmp_t5] "=&r"(tmp_t5), [tmp_t6] "=&r"(tmp_t6), >- [tmp_t7] "=&r"(tmp_t7), [tmp_t8] "=&r"(tmp_t8), [src_ptr] "+r"(src_ptr) >- : [dst_ptr] "r"(dst_ptr)); >- src_ptr += 8; >- dst_ptr += 8; >- } >- >- if ((src_width)&7) { >- for (x = 0; x < ((src_width - 1) & 7); x += 1) { >- dst_ptr[0] += src_ptr[0]; >- src_ptr += 1; >- dst_ptr += 1; >- } >- } >-} >- >-#endif // defined(__mips_dsp) && (__mips_dsp_rev >= 2) >- >-#ifdef __cplusplus >-} // extern "C" >-} // namespace libyuv >-#endif >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc >index f0ac56fcb06..312236d2df8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc >@@ -21,462 +21,458 @@ extern "C" { > (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) > > // Offsets for source bytes 0 to 9 >-static uvec8 kShuf0 = {0, 1, 3, 4, 5, 7, 8, 9, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf0 = {0, 1, 3, 4, 5, 7, 8, 9, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12. >-static uvec8 kShuf1 = {3, 4, 5, 7, 8, 9, 11, 12, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf1 = {3, 4, 5, 7, 8, 9, 11, 12, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. >-static uvec8 kShuf2 = {5, 7, 8, 9, 11, 12, 13, 15, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf2 = {5, 7, 8, 9, 11, 12, 13, 15, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 0 to 10 >-static uvec8 kShuf01 = {0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10}; >+static const uvec8 kShuf01 = {0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10}; > > // Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13. >-static uvec8 kShuf11 = {2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13}; >+static const uvec8 kShuf11 = {2, 3, 4, 5, 5, 6, 6, 7, >+ 8, 9, 9, 10, 10, 11, 12, 13}; > > // Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. >-static uvec8 kShuf21 = {5, 6, 6, 7, 8, 9, 9, 10, >- 10, 11, 12, 13, 13, 14, 14, 15}; >+static const uvec8 kShuf21 = {5, 6, 6, 7, 8, 9, 9, 10, >+ 10, 11, 12, 13, 13, 14, 14, 15}; > > // Coefficients for source bytes 0 to 10 >-static uvec8 kMadd01 = {3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2}; >+static const uvec8 kMadd01 = {3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2}; > > // Coefficients for source bytes 10 to 21 >-static uvec8 kMadd11 = {1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1}; >+static const uvec8 kMadd11 = {1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1}; > > // Coefficients for source bytes 21 to 31 >-static uvec8 kMadd21 = {2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3}; >+static const uvec8 kMadd21 = {2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3}; > > // Coefficients for source bytes 21 to 31 >-static vec16 kRound34 = {2, 2, 2, 2, 2, 2, 2, 2}; >+static const vec16 kRound34 = {2, 2, 2, 2, 2, 2, 2, 2}; > >-static uvec8 kShuf38a = {0, 3, 6, 8, 11, 14, 128, 128, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf38a = {0, 3, 6, 8, 11, 14, 128, 128, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > >-static uvec8 kShuf38b = {128, 128, 128, 128, 128, 128, 0, 3, >- 6, 8, 11, 14, 128, 128, 128, 128}; >+static const uvec8 kShuf38b = {128, 128, 128, 128, 128, 128, 0, 3, >+ 6, 8, 11, 14, 128, 128, 128, 128}; > > // Arrange words 0,3,6 into 0,1,2 >-static uvec8 kShufAc = {0, 1, 6, 7, 12, 13, 128, 128, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAc = {0, 1, 6, 7, 12, 13, 128, 128, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Arrange words 0,3,6 into 3,4,5 >-static uvec8 kShufAc3 = {128, 128, 128, 128, 128, 128, 0, 1, >- 6, 7, 12, 13, 128, 128, 128, 128}; >+static const uvec8 kShufAc3 = {128, 128, 128, 128, 128, 128, 0, 1, >+ 6, 7, 12, 13, 128, 128, 128, 128}; > > // Scaling values for boxes of 3x3 and 2x3 >-static uvec16 kScaleAc33 = {65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, >- 65536 / 9, 65536 / 6, 0, 0}; >+static const uvec16 kScaleAc33 = {65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, >+ 65536 / 9, 65536 / 6, 0, 0}; > > // Arrange first value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb0 = {0, 128, 3, 128, 6, 128, 8, 128, >- 11, 128, 14, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb0 = {0, 128, 3, 128, 6, 128, 8, 128, >+ 11, 128, 14, 128, 128, 128, 128, 128}; > > // Arrange second value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb1 = {1, 128, 4, 128, 7, 128, 9, 128, >- 12, 128, 15, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb1 = {1, 128, 4, 128, 7, 128, 9, 128, >+ 12, 128, 15, 128, 128, 128, 128, 128}; > > // Arrange third value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb2 = {2, 128, 5, 128, 128, 128, 10, 128, >- 13, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb2 = {2, 128, 5, 128, 128, 128, 10, 128, >+ 13, 128, 128, 128, 128, 128, 128, 128}; > > // Scaling values for boxes of 3x2 and 2x2 >-static uvec16 kScaleAb2 = {65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, >- 65536 / 3, 65536 / 2, 0, 0}; >+static const uvec16 kScaleAb2 = {65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, >+ 65536 / 3, 65536 / 2, 0, 0}; > > // GCC versions of row functions are verbatim conversions from Visual C. > // Generated using gcc disassembly on Visual C object file: > // objdump -D yuvscaler.obj >yuvscaler.txt > >-void ScaleRowDown2_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "psrlw $0x8,%%xmm0 \n" >- "psrlw $0x8,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1" >- ); >+ asm volatile( >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "psrlw $0x8,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > >-void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Linear_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psrlw $0xf,%%xmm4 \n" >- "packuswb %%xmm4,%%xmm4 \n" >- "pxor %%xmm5,%%xmm5 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10, 0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pavgw %%xmm5,%%xmm0 \n" >- "pavgw %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psrlw $0xf,%%xmm4 \n" >+ "packuswb %%xmm4,%%xmm4 \n" >+ "pxor %%xmm5,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pavgw %%xmm5,%%xmm0 \n" >+ "pavgw %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm4", "xmm5"); > } > >-void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown2Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- asm volatile ( >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psrlw $0xf,%%xmm4 \n" >- "packuswb %%xmm4,%%xmm4 \n" >- "pxor %%xmm5,%%xmm5 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm3,%%xmm1 \n" >- "psrlw $0x1,%%xmm0 \n" >- "psrlw $0x1,%%xmm1 \n" >- "pavgw %%xmm5,%%xmm0 \n" >- "pavgw %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ asm volatile( >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psrlw $0xf,%%xmm4 \n" >+ "packuswb %%xmm4,%%xmm4 \n" >+ "pxor %%xmm5,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%3,1),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm3,%%xmm1 \n" >+ "psrlw $0x1,%%xmm0 \n" >+ "psrlw $0x1,%%xmm1 \n" >+ "pavgw %%xmm5,%%xmm0 \n" >+ "pavgw %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > > #ifdef HAS_SCALEROWDOWN2_AVX2 >-void ScaleRowDown2_AVX2(const uint8* src_ptr, >+void ScaleRowDown2_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > >-void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Linear_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >- "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >- >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20, 0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" >- "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >+ "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm4", "xmm5"); > } > >-void ScaleRowDown2Box_AVX2(const uint8* src_ptr, >+void ScaleRowDown2Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- asm volatile ( >- "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >- "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >- >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- MEMOPREG(vmovdqu,0x00,0,3,1,ymm2) // vmovdqu (%0,%3,1),%%ymm2 >- MEMOPREG(vmovdqu,0x20,0,3,1,ymm3) // vmovdqu 0x20(%0,%3,1),%%ymm3 >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >- "vpsrlw $0x1,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x1,%%ymm1,%%ymm1 \n" >- "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" >- "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+ asm volatile( >+ "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >+ "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x00(%0,%3,1),%%ymm2 \n" >+ "vmovdqu 0x20(%0,%3,1),%%ymm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vpsrlw $0x1,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x1,%%ymm1,%%ymm1 \n" >+ "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SCALEROWDOWN2_AVX2 > >-void ScaleRowDown4_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- "pcmpeqb %%xmm5,%%xmm5 \n" >- "psrld $0x18,%%xmm5 \n" >- "pslld $0x10,%%xmm5 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pand %%xmm5,%%xmm0 \n" >- "pand %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm0 \n" >- "psrlw $0x8,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm5" >- ); >+ asm volatile( >+ "pcmpeqb %%xmm5,%%xmm5 \n" >+ "psrld $0x18,%%xmm5 \n" >+ "pslld $0x10,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pand %%xmm5,%%xmm0 \n" >+ "pand %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm0 \n" >+ "psrlw $0x8,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm5"); > } > >-void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown4Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > intptr_t stridex3; >- asm volatile ( >- "pcmpeqb %%xmm4,%%xmm4 \n" >- "psrlw $0xf,%%xmm4 \n" >- "movdqa %%xmm4,%%xmm5 \n" >- "packuswb %%xmm4,%%xmm4 \n" >- "psllw $0x3,%%xmm5 \n" >- "lea " MEMLEA4(0x00,4,4,2) ",%3 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 >- "pmaddubsw %%xmm4,%%xmm0 \n" >- "pmaddubsw %%xmm4,%%xmm1 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm3,%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,4,2,xmm2) // movdqu (%0,%4,2),%%xmm2 >- MEMOPREG(movdqu,0x10,0,4,2,xmm3) // movdqu 0x10(%0,%4,2),%%xmm3 >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm3,%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pmaddubsw %%xmm4,%%xmm2 \n" >- "pmaddubsw %%xmm4,%%xmm3 \n" >- "paddw %%xmm2,%%xmm0 \n" >- "paddw %%xmm3,%%xmm1 \n" >- "phaddw %%xmm1,%%xmm0 \n" >- "paddw %%xmm5,%%xmm0 \n" >- "psrlw $0x4,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x8,1) ",%1 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width), // %2 >- "=&r"(stridex3) // %3 >- : "r"((intptr_t)(src_stride)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "pcmpeqb %%xmm4,%%xmm4 \n" >+ "psrlw $0xf,%%xmm4 \n" >+ "movdqa %%xmm4,%%xmm5 \n" >+ "packuswb %%xmm4,%%xmm4 \n" >+ "psllw $0x3,%%xmm5 \n" >+ "lea 0x00(%4,%4,2),%3 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x00(%0,%4,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%4,1),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm0 \n" >+ "pmaddubsw %%xmm4,%%xmm1 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm3,%%xmm1 \n" >+ "movdqu 0x00(%0,%4,2),%%xmm2 \n" >+ "movdqu 0x10(%0,%4,2),%%xmm3 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm3,%%xmm1 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%3,1),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "pmaddubsw %%xmm4,%%xmm2 \n" >+ "pmaddubsw %%xmm4,%%xmm3 \n" >+ "paddw %%xmm2,%%xmm0 \n" >+ "paddw %%xmm3,%%xmm1 \n" >+ "phaddw %%xmm1,%%xmm0 \n" >+ "paddw %%xmm5,%%xmm0 \n" >+ "psrlw $0x4,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,(%1) \n" >+ "lea 0x8(%1),%1 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width), // %2 >+ "=&r"(stridex3) // %3 >+ : "r"((intptr_t)(src_stride)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > > #ifdef HAS_SCALEROWDOWN4_AVX2 >-void ScaleRowDown4_AVX2(const uint8* src_ptr, >+void ScaleRowDown4_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >- "vpsrld $0x18,%%ymm5,%%ymm5 \n" >- "vpslld $0x10,%%ymm5,%%ymm5 \n" >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpand %%ymm5,%%ymm0,%%ymm0 \n" >- "vpand %%ymm5,%%ymm1,%%ymm1 \n" >- "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm5" >- ); >+ asm volatile( >+ "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" >+ "vpsrld $0x18,%%ymm5,%%ymm5 \n" >+ "vpslld $0x10,%%ymm5,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpand %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpand %%ymm5,%%ymm1,%%ymm1 \n" >+ "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x8,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm5"); > } > >-void ScaleRowDown4Box_AVX2(const uint8* src_ptr, >+void ScaleRowDown4Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- asm volatile ( >- "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >- "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >- "vpsllw $0x3,%%ymm4,%%ymm5 \n" >- "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >- >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" >- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" >- MEMOPREG(vmovdqu,0x00,0,3,1,ymm2) // vmovdqu (%0,%3,1),%%ymm2 >- MEMOPREG(vmovdqu,0x20,0,3,1,ymm3) // vmovdqu 0x20(%0,%3,1),%%ymm3 >- "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >- "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >- MEMOPREG(vmovdqu,0x00,0,3,2,ymm2) // vmovdqu (%0,%3,2),%%ymm2 >- MEMOPREG(vmovdqu,0x20,0,3,2,ymm3) // vmovdqu 0x20(%0,%3,2),%%ymm3 >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >- MEMOPREG(vmovdqu,0x00,0,4,1,ymm2) // vmovdqu (%0,%4,1),%%ymm2 >- MEMOPREG(vmovdqu,0x20,0,4,1,ymm3) // vmovdqu 0x20(%0,%4,1),%%ymm3 >- "lea " MEMLEA(0x40,0) ",%0 \n" >- "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >- "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >- "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >- "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" >- "vpsrlw $0x4,%%ymm0,%%ymm0 \n" >- "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >- "vpermq $0xd8,%%ymm0,%%ymm0 \n" >- "vmovdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)), // %3 >- "r"((intptr_t)(src_stride * 3)) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" >+ "vpsrlw $0xf,%%ymm4,%%ymm4 \n" >+ "vpsllw $0x3,%%ymm4,%%ymm5 \n" >+ "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm0 \n" >+ "vmovdqu 0x20(%0),%%ymm1 \n" >+ "vmovdqu 0x00(%0,%3,1),%%ymm2 \n" >+ "vmovdqu 0x20(%0,%3,1),%%ymm3 \n" >+ "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" >+ "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vmovdqu 0x00(%0,%3,2),%%ymm2 \n" >+ "vmovdqu 0x20(%0,%3,2),%%ymm3 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vmovdqu 0x00(%0,%4,1),%%ymm2 \n" >+ "vmovdqu 0x20(%0,%4,1),%%ymm3 \n" >+ "lea 0x40(%0),%0 \n" >+ "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" >+ "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" >+ "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" >+ "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" >+ "vpsrlw $0x4,%%ymm0,%%ymm0 \n" >+ "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" >+ "vpermq $0xd8,%%ymm0,%%ymm0 \n" >+ "vmovdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)), // %3 >+ "r"((intptr_t)(src_stride * 3)) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > #endif // HAS_SCALEROWDOWN4_AVX2 > >-void ScaleRowDown34_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -488,33 +484,34 @@ void ScaleRowDown34_SSSE3(const uint8* src_ptr, > "m"(kShuf1), // %1 > "m"(kShuf2) // %2 > ); >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm2 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqa %%xmm2,%%xmm1 \n" >- "palignr $0x8,%%xmm0,%%xmm1 \n" >- "pshufb %%xmm3,%%xmm0 \n" >- "pshufb %%xmm4,%%xmm1 \n" >- "pshufb %%xmm5,%%xmm2 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "movq %%xmm1," MEMACCESS2(0x8,1) " \n" >- "movq %%xmm2," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x18,1) ",%1 \n" >- "sub $0x18,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm2 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqa %%xmm2,%%xmm1 \n" >+ "palignr $0x8,%%xmm0,%%xmm1 \n" >+ "pshufb %%xmm3,%%xmm0 \n" >+ "pshufb %%xmm4,%%xmm1 \n" >+ "pshufb %%xmm5,%%xmm2 \n" >+ "movq %%xmm0,(%1) \n" >+ "movq %%xmm1,0x8(%1) \n" >+ "movq %%xmm2,0x10(%1) \n" >+ "lea 0x18(%1),%1 \n" >+ "sub $0x18,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"); > } > >-void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movdqa %0,%%xmm2 \n" // kShuf01 >@@ -534,53 +531,53 @@ void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, > "m"(kMadd11), // %1 > "m"(kRound34) // %2 > ); >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm7) // movdqu (%0,%3),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm5,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS(1) " \n" >- "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3),%%xmm7 >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm3,%%xmm6 \n" >- "pmaddubsw %%xmm0,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS2(0x8,1) " \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x10,0,3,1,xmm7) // movdqu 0x10(%0,%3),%%xmm7 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm4,%%xmm6 \n" >- "pmaddubsw %4,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x18,1) ",%1 \n" >- "sub $0x18,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)), // %3 >- "m"(kMadd21) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm6 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm5,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,(%1) \n" >+ "movdqu 0x8(%0),%%xmm6 \n" >+ "movdqu 0x8(%0,%3,1),%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm3,%%xmm6 \n" >+ "pmaddubsw %%xmm0,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,0x8(%1) \n" >+ "movdqu 0x10(%0),%%xmm6 \n" >+ "movdqu 0x10(%0,%3,1),%%xmm7 \n" >+ "lea 0x20(%0),%0 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm4,%%xmm6 \n" >+ "pmaddubsw %4,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,0x10(%1) \n" >+ "lea 0x18(%1),%1 \n" >+ "sub $0x18,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)), // %3 >+ "m"(kMadd21) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > >-void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movdqa %0,%%xmm2 \n" // kShuf01 >@@ -601,88 +598,87 @@ void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, > "m"(kRound34) // %2 > ); > >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm7) // movdqu (%0,%3,1),%%xmm7 >- "pavgb %%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm2,%%xmm6 \n" >- "pmaddubsw %%xmm5,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS(1) " \n" >- "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3,1),%%xmm7 >- "pavgb %%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm3,%%xmm6 \n" >- "pmaddubsw %%xmm0,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS2(0x8,1) " \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" >- MEMOPREG(movdqu,0x10,0,3,1,xmm7) // movdqu 0x10(%0,%3,1),%%xmm7 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pavgb %%xmm6,%%xmm7 \n" >- "pavgb %%xmm7,%%xmm6 \n" >- "pshufb %%xmm4,%%xmm6 \n" >- "pmaddubsw %4,%%xmm6 \n" >- "paddsw %%xmm1,%%xmm6 \n" >- "psrlw $0x2,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movq %%xmm6," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x18,1) ",%1 \n" >- "sub $0x18,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)), // %3 >- "m"(kMadd21) // %4 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm6 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm7 \n" >+ "pavgb %%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm2,%%xmm6 \n" >+ "pmaddubsw %%xmm5,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,(%1) \n" >+ "movdqu 0x8(%0),%%xmm6 \n" >+ "movdqu 0x8(%0,%3,1),%%xmm7 \n" >+ "pavgb %%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm3,%%xmm6 \n" >+ "pmaddubsw %%xmm0,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,0x8(%1) \n" >+ "movdqu 0x10(%0),%%xmm6 \n" >+ "movdqu 0x10(%0,%3,1),%%xmm7 \n" >+ "lea 0x20(%0),%0 \n" >+ "pavgb %%xmm6,%%xmm7 \n" >+ "pavgb %%xmm7,%%xmm6 \n" >+ "pshufb %%xmm4,%%xmm6 \n" >+ "pmaddubsw %4,%%xmm6 \n" >+ "paddsw %%xmm1,%%xmm6 \n" >+ "psrlw $0x2,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movq %%xmm6,0x10(%1) \n" >+ "lea 0x18(%1),%1 \n" >+ "sub $0x18,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)), // %3 >+ "m"(kMadd21) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > >-void ScaleRowDown38_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; >- asm volatile ( >- "movdqa %3,%%xmm4 \n" >- "movdqa %4,%%xmm5 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "pshufb %%xmm5,%%xmm1 \n" >- "paddusb %%xmm1,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(1) " \n" >- "movhlps %%xmm0,%%xmm1 \n" >- "movd %%xmm1," MEMACCESS2(0x8,1) " \n" >- "lea " MEMLEA(0xc,1) ",%1 \n" >- "sub $0xc,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "m"(kShuf38a), // %3 >- "m"(kShuf38b) // %4 >- : "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" >- ); >+ asm volatile( >+ "movdqa %3,%%xmm4 \n" >+ "movdqa %4,%%xmm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "pshufb %%xmm5,%%xmm1 \n" >+ "paddusb %%xmm1,%%xmm0 \n" >+ "movq %%xmm0,(%1) \n" >+ "movhlps %%xmm0,%%xmm1 \n" >+ "movd %%xmm1,0x8(%1) \n" >+ "lea 0xc(%1),%1 \n" >+ "sub $0xc,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "m"(kShuf38a), // %3 >+ "m"(kShuf38b) // %4 >+ : "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5"); > } > >-void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movdqa %0,%%xmm2 \n" >@@ -695,40 +691,39 @@ void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, > "m"(kShufAb2), // %2 > "m"(kScaleAb2) // %3 > ); >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm1) // movdqu (%0,%3,1),%%xmm1 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "pavgb %%xmm1,%%xmm0 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "pshufb %%xmm2,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm6 \n" >- "pshufb %%xmm3,%%xmm6 \n" >- "paddusw %%xmm6,%%xmm1 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "paddusw %%xmm0,%%xmm1 \n" >- "pmulhuw %%xmm5,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movd %%xmm1," MEMACCESS(1) " \n" >- "psrlq $0x10,%%xmm1 \n" >- "movd %%xmm1," MEMACCESS2(0x2,1) " \n" >- "lea " MEMLEA(0x6,1) ",%1 \n" >- "sub $0x6,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm1 \n" >+ "lea 0x10(%0),%0 \n" >+ "pavgb %%xmm1,%%xmm0 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "pshufb %%xmm2,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm6 \n" >+ "pshufb %%xmm3,%%xmm6 \n" >+ "paddusw %%xmm6,%%xmm1 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "paddusw %%xmm0,%%xmm1 \n" >+ "pmulhuw %%xmm5,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movd %%xmm1,(%1) \n" >+ "psrlq $0x10,%%xmm1 \n" >+ "movd %%xmm1,0x2(%1) \n" >+ "lea 0x6(%1),%1 \n" >+ "sub $0x6,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > >-void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, >+void ScaleRowDown38_3_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movdqa %0,%%xmm2 \n" >@@ -740,529 +735,533 @@ void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, > "m"(kShufAc3), // %1 > "m"(kScaleAc33) // %2 > ); >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm6) // movdqu (%0,%3,1),%%xmm6 >- "movhlps %%xmm0,%%xmm1 \n" >- "movhlps %%xmm6,%%xmm7 \n" >- "punpcklbw %%xmm5,%%xmm0 \n" >- "punpcklbw %%xmm5,%%xmm1 \n" >- "punpcklbw %%xmm5,%%xmm6 \n" >- "punpcklbw %%xmm5,%%xmm7 \n" >- "paddusw %%xmm6,%%xmm0 \n" >- "paddusw %%xmm7,%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,3,2,xmm6) // movdqu (%0,%3,2),%%xmm6 >- "lea " MEMLEA(0x10,0) ",%0 \n" >- "movhlps %%xmm6,%%xmm7 \n" >- "punpcklbw %%xmm5,%%xmm6 \n" >- "punpcklbw %%xmm5,%%xmm7 \n" >- "paddusw %%xmm6,%%xmm0 \n" >- "paddusw %%xmm7,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm6 \n" >- "psrldq $0x2,%%xmm0 \n" >- "paddusw %%xmm0,%%xmm6 \n" >- "psrldq $0x2,%%xmm0 \n" >- "paddusw %%xmm0,%%xmm6 \n" >- "pshufb %%xmm2,%%xmm6 \n" >- "movdqa %%xmm1,%%xmm7 \n" >- "psrldq $0x2,%%xmm1 \n" >- "paddusw %%xmm1,%%xmm7 \n" >- "psrldq $0x2,%%xmm1 \n" >- "paddusw %%xmm1,%%xmm7 \n" >- "pshufb %%xmm3,%%xmm7 \n" >- "paddusw %%xmm7,%%xmm6 \n" >- "pmulhuw %%xmm4,%%xmm6 \n" >- "packuswb %%xmm6,%%xmm6 \n" >- "movd %%xmm6," MEMACCESS(1) " \n" >- "psrlq $0x10,%%xmm6 \n" >- "movd %%xmm6," MEMACCESS2(0x2,1) " \n" >- "lea " MEMLEA(0x6,1) ",%1 \n" >- "sub $0x6,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm6 \n" >+ "movhlps %%xmm0,%%xmm1 \n" >+ "movhlps %%xmm6,%%xmm7 \n" >+ "punpcklbw %%xmm5,%%xmm0 \n" >+ "punpcklbw %%xmm5,%%xmm1 \n" >+ "punpcklbw %%xmm5,%%xmm6 \n" >+ "punpcklbw %%xmm5,%%xmm7 \n" >+ "paddusw %%xmm6,%%xmm0 \n" >+ "paddusw %%xmm7,%%xmm1 \n" >+ "movdqu 0x00(%0,%3,2),%%xmm6 \n" >+ "lea 0x10(%0),%0 \n" >+ "movhlps %%xmm6,%%xmm7 \n" >+ "punpcklbw %%xmm5,%%xmm6 \n" >+ "punpcklbw %%xmm5,%%xmm7 \n" >+ "paddusw %%xmm6,%%xmm0 \n" >+ "paddusw %%xmm7,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm6 \n" >+ "psrldq $0x2,%%xmm0 \n" >+ "paddusw %%xmm0,%%xmm6 \n" >+ "psrldq $0x2,%%xmm0 \n" >+ "paddusw %%xmm0,%%xmm6 \n" >+ "pshufb %%xmm2,%%xmm6 \n" >+ "movdqa %%xmm1,%%xmm7 \n" >+ "psrldq $0x2,%%xmm1 \n" >+ "paddusw %%xmm1,%%xmm7 \n" >+ "psrldq $0x2,%%xmm1 \n" >+ "paddusw %%xmm1,%%xmm7 \n" >+ "pshufb %%xmm3,%%xmm7 \n" >+ "paddusw %%xmm7,%%xmm6 \n" >+ "pmulhuw %%xmm4,%%xmm6 \n" >+ "packuswb %%xmm6,%%xmm6 \n" >+ "movd %%xmm6,(%1) \n" >+ "psrlq $0x10,%%xmm6 \n" >+ "movd %%xmm6,0x2(%1) \n" >+ "lea 0x6(%1),%1 \n" >+ "sub $0x6,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > > // Reads 16xN bytes and produces 16 shorts at a time. >-void ScaleAddRow_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width) { >- asm volatile ( >- "pxor %%xmm5,%%xmm5 \n" >- >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm3 \n" >- "lea " MEMLEA(0x10,0) ",%0 \n" // src_ptr += 16 >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,1) ",%%xmm1 \n" >- "movdqa %%xmm3,%%xmm2 \n" >- "punpcklbw %%xmm5,%%xmm2 \n" >- "punpckhbw %%xmm5,%%xmm3 \n" >- "paddusw %%xmm2,%%xmm0 \n" >- "paddusw %%xmm3,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" >- "lea " MEMLEA(0x20,1) ",%1 \n" >- "sub $0x10,%2 \n" >- "jg 1b \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(src_width) // %2 >- : >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+void ScaleAddRow_SSE2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int src_width) { >+ asm volatile( >+ >+ "pxor %%xmm5,%%xmm5 \n" >+ >+ // 16 pixel loop. >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm3 \n" >+ "lea 0x10(%0),%0 \n" // src_ptr += 16 >+ "movdqu (%1),%%xmm0 \n" >+ "movdqu 0x10(%1),%%xmm1 \n" >+ "movdqa %%xmm3,%%xmm2 \n" >+ "punpcklbw %%xmm5,%%xmm2 \n" >+ "punpckhbw %%xmm5,%%xmm3 \n" >+ "paddusw %%xmm2,%%xmm0 \n" >+ "paddusw %%xmm3,%%xmm1 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "movdqu %%xmm1,0x10(%1) \n" >+ "lea 0x20(%1),%1 \n" >+ "sub $0x10,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(src_width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > > #ifdef HAS_SCALEADDROW_AVX2 > // Reads 32 bytes and accumulates to 32 shorts at a time. >-void ScaleAddRow_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width) { >- asm volatile ( >- "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >- >- LABELALIGN >- "1: \n" >- "vmovdqu " MEMACCESS(0) ",%%ymm3 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" // src_ptr += 32 >- "vpermq $0xd8,%%ymm3,%%ymm3 \n" >- "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" >- "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" >- "vpaddusw " MEMACCESS(1) ",%%ymm2,%%ymm0 \n" >- "vpaddusw " MEMACCESS2(0x20,1) ",%%ymm3,%%ymm1 \n" >- "vmovdqu %%ymm0," MEMACCESS(1) " \n" >- "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" >- "lea " MEMLEA(0x40,1) ",%1 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- "vzeroupper \n" >- : "+r"(src_ptr), // %0 >- "+r"(dst_ptr), // %1 >- "+r"(src_width) // %2 >- : >- : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" >- ); >+void ScaleAddRow_AVX2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, >+ int src_width) { >+ asm volatile( >+ >+ "vpxor %%ymm5,%%ymm5,%%ymm5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "vmovdqu (%0),%%ymm3 \n" >+ "lea 0x20(%0),%0 \n" // src_ptr += 32 >+ "vpermq $0xd8,%%ymm3,%%ymm3 \n" >+ "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" >+ "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" >+ "vpaddusw (%1),%%ymm2,%%ymm0 \n" >+ "vpaddusw 0x20(%1),%%ymm3,%%ymm1 \n" >+ "vmovdqu %%ymm0,(%1) \n" >+ "vmovdqu %%ymm1,0x20(%1) \n" >+ "lea 0x40(%1),%1 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ "vzeroupper \n" >+ : "+r"(src_ptr), // %0 >+ "+r"(dst_ptr), // %1 >+ "+r"(src_width) // %2 >+ : >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"); > } > #endif // HAS_SCALEADDROW_AVX2 > > // Constant for making pixels signed to avoid pmaddubsw > // saturation. >-static uvec8 kFsub80 = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, >- 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; >+static const uvec8 kFsub80 = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, >+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; > > // Constant for making pixels unsigned and adding .5 for rounding. >-static uvec16 kFadd40 = {0x4040, 0x4040, 0x4040, 0x4040, >- 0x4040, 0x4040, 0x4040, 0x4040}; >+static const uvec16 kFadd40 = {0x4040, 0x4040, 0x4040, 0x4040, >+ 0x4040, 0x4040, 0x4040, 0x4040}; > > // Bilinear column filtering. SSSE3 version. >-void ScaleFilterCols_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { > intptr_t x0, x1, temp_pixel; >- asm volatile ( >- "movd %6,%%xmm2 \n" >- "movd %7,%%xmm3 \n" >- "movl $0x04040000,%k2 \n" >- "movd %k2,%%xmm5 \n" >- "pcmpeqb %%xmm6,%%xmm6 \n" >- "psrlw $0x9,%%xmm6 \n" // 0x007f007f >- "pcmpeqb %%xmm7,%%xmm7 \n" >- "psrlw $15,%%xmm7 \n" // 0x00010001 >- >- "pextrw $0x1,%%xmm2,%k3 \n" >- "subl $0x2,%5 \n" >- "jl 29f \n" >- "movdqa %%xmm2,%%xmm0 \n" >- "paddd %%xmm3,%%xmm0 \n" >- "punpckldq %%xmm0,%%xmm2 \n" >- "punpckldq %%xmm3,%%xmm3 \n" >- "paddd %%xmm3,%%xmm3 \n" >- "pextrw $0x3,%%xmm2,%k4 \n" >- >- LABELALIGN >- "2: \n" >- "movdqa %%xmm2,%%xmm1 \n" >- "paddd %%xmm3,%%xmm2 \n" >- MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2 >- "movd %k2,%%xmm0 \n" >- "psrlw $0x9,%%xmm1 \n" >- MEMOPARG(movzwl,0x00,1,4,1,k2) // movzwl (%1,%4,1),%k2 >- "movd %k2,%%xmm4 \n" >- "pshufb %%xmm5,%%xmm1 \n" >- "punpcklwd %%xmm4,%%xmm0 \n" >- "psubb %8,%%xmm0 \n" // make pixels signed. >- "pxor %%xmm6,%%xmm1 \n" // 128 - f = (f ^ 127 ) + 1 >- "paddusb %%xmm7,%%xmm1 \n" >- "pmaddubsw %%xmm0,%%xmm1 \n" >- "pextrw $0x1,%%xmm2,%k3 \n" >- "pextrw $0x3,%%xmm2,%k4 \n" >- "paddw %9,%%xmm1 \n" // make pixels unsigned. >- "psrlw $0x7,%%xmm1 \n" >- "packuswb %%xmm1,%%xmm1 \n" >- "movd %%xmm1,%k2 \n" >- "mov %w2," MEMACCESS(0) " \n" >- "lea " MEMLEA(0x2,0) ",%0 \n" >- "subl $0x2,%5 \n" >- "jge 2b \n" >- >- LABELALIGN >- "29: \n" >- "addl $0x1,%5 \n" >- "jl 99f \n" >- MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2 >- "movd %k2,%%xmm0 \n" >- "psrlw $0x9,%%xmm2 \n" >- "pshufb %%xmm5,%%xmm2 \n" >- "psubb %8,%%xmm0 \n" // make pixels signed. >- "pxor %%xmm6,%%xmm2 \n" >- "paddusb %%xmm7,%%xmm2 \n" >- "pmaddubsw %%xmm0,%%xmm2 \n" >- "paddw %9,%%xmm2 \n" // make pixels unsigned. >- "psrlw $0x7,%%xmm2 \n" >- "packuswb %%xmm2,%%xmm2 \n" >- "movd %%xmm2,%k2 \n" >- "mov %b2," MEMACCESS(0) " \n" >- "99: \n" >- : "+r"(dst_ptr), // %0 >- "+r"(src_ptr), // %1 >- "=&a"(temp_pixel), // %2 >- "=&r"(x0), // %3 >- "=&r"(x1), // %4 >+ asm volatile( >+ "movd %6,%%xmm2 \n" >+ "movd %7,%%xmm3 \n" >+ "movl $0x04040000,%k2 \n" >+ "movd %k2,%%xmm5 \n" >+ "pcmpeqb %%xmm6,%%xmm6 \n" >+ "psrlw $0x9,%%xmm6 \n" // 0x007f007f >+ "pcmpeqb %%xmm7,%%xmm7 \n" >+ "psrlw $15,%%xmm7 \n" // 0x00010001 >+ >+ "pextrw $0x1,%%xmm2,%k3 \n" >+ "subl $0x2,%5 \n" >+ "jl 29f \n" >+ "movdqa %%xmm2,%%xmm0 \n" >+ "paddd %%xmm3,%%xmm0 \n" >+ "punpckldq %%xmm0,%%xmm2 \n" >+ "punpckldq %%xmm3,%%xmm3 \n" >+ "paddd %%xmm3,%%xmm3 \n" >+ "pextrw $0x3,%%xmm2,%k4 \n" >+ >+ LABELALIGN >+ "2: \n" >+ "movdqa %%xmm2,%%xmm1 \n" >+ "paddd %%xmm3,%%xmm2 \n" >+ "movzwl 0x00(%1,%3,1),%k2 \n" >+ "movd %k2,%%xmm0 \n" >+ "psrlw $0x9,%%xmm1 \n" >+ "movzwl 0x00(%1,%4,1),%k2 \n" >+ "movd %k2,%%xmm4 \n" >+ "pshufb %%xmm5,%%xmm1 \n" >+ "punpcklwd %%xmm4,%%xmm0 \n" >+ "psubb %8,%%xmm0 \n" // make pixels signed. >+ "pxor %%xmm6,%%xmm1 \n" // 128 - f = (f ^ 127 ) + >+ // 1 >+ "paddusb %%xmm7,%%xmm1 \n" >+ "pmaddubsw %%xmm0,%%xmm1 \n" >+ "pextrw $0x1,%%xmm2,%k3 \n" >+ "pextrw $0x3,%%xmm2,%k4 \n" >+ "paddw %9,%%xmm1 \n" // make pixels unsigned. >+ "psrlw $0x7,%%xmm1 \n" >+ "packuswb %%xmm1,%%xmm1 \n" >+ "movd %%xmm1,%k2 \n" >+ "mov %w2,(%0) \n" >+ "lea 0x2(%0),%0 \n" >+ "subl $0x2,%5 \n" >+ "jge 2b \n" >+ >+ LABELALIGN >+ "29: \n" >+ "addl $0x1,%5 \n" >+ "jl 99f \n" >+ "movzwl 0x00(%1,%3,1),%k2 \n" >+ "movd %k2,%%xmm0 \n" >+ "psrlw $0x9,%%xmm2 \n" >+ "pshufb %%xmm5,%%xmm2 \n" >+ "psubb %8,%%xmm0 \n" // make pixels signed. >+ "pxor %%xmm6,%%xmm2 \n" >+ "paddusb %%xmm7,%%xmm2 \n" >+ "pmaddubsw %%xmm0,%%xmm2 \n" >+ "paddw %9,%%xmm2 \n" // make pixels unsigned. >+ "psrlw $0x7,%%xmm2 \n" >+ "packuswb %%xmm2,%%xmm2 \n" >+ "movd %%xmm2,%k2 \n" >+ "mov %b2,(%0) \n" >+ "99: \n" >+ : "+r"(dst_ptr), // %0 >+ "+r"(src_ptr), // %1 >+ "=&a"(temp_pixel), // %2 >+ "=&r"(x0), // %3 >+ "=&r"(x1), // %4 > #if defined(__x86_64__) >- "+rm"(dst_width) // %5 >+ "+rm"(dst_width) // %5 > #else >- "+m"(dst_width) // %5 >+ "+m"(dst_width) // %5 > #endif >- : "rm"(x), // %6 >- "rm"(dx), // %7 >+ : "rm"(x), // %6 >+ "rm"(dx), // %7 > #if defined(__x86_64__) >- "x"(kFsub80), // %8 >- "x"(kFadd40) // %9 >+ "x"(kFsub80), // %8 >+ "x"(kFadd40) // %9 > #else >- "m"(kFsub80), // %8 >- "m"(kFadd40) // %9 >+ "m"(kFsub80), // %8 >+ "m"(kFadd40) // %9 > #endif >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" >- ); >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", >+ "xmm7"); > } > > // Reads 4 pixels, duplicates them and writes 8 pixels. > // Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned. >-void ScaleColsUp2_SSE2(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleColsUp2_SSE2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { > (void)x; > (void)dx; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpcklbw %%xmm0,%%xmm0 \n" >- "punpckhbw %%xmm1,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(0) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "sub $0x20,%2 \n" >- "jg 1b \n" >- >- : "+r"(dst_ptr), // %0 >- "+r"(src_ptr), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%1),%%xmm0 \n" >+ "lea 0x10(%1),%1 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpcklbw %%xmm0,%%xmm0 \n" >+ "punpckhbw %%xmm1,%%xmm1 \n" >+ "movdqu %%xmm0,(%0) \n" >+ "movdqu %%xmm1,0x10(%0) \n" >+ "lea 0x20(%0),%0 \n" >+ "sub $0x20,%2 \n" >+ "jg 1b \n" >+ >+ : "+r"(dst_ptr), // %0 >+ "+r"(src_ptr), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > >-void ScaleARGBRowDown2_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "shufps $0xdd,%%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > >-void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm2 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", "xmm0", "xmm1" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "lea 0x20(%0),%0 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm2 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > >-void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, >+void ScaleARGBRowDown2Box_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(0) ",%%xmm0 \n" >- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" >- MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 >- MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "pavgb %%xmm3,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm2 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(1) " \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "sub $0x4,%2 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(dst_width) // %2 >- : "r"((intptr_t)(src_stride)) // %3 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%0),%%xmm0 \n" >+ "movdqu 0x10(%0),%%xmm1 \n" >+ "movdqu 0x00(%0,%3,1),%%xmm2 \n" >+ "movdqu 0x10(%0,%3,1),%%xmm3 \n" >+ "lea 0x20(%0),%0 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "pavgb %%xmm3,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm2 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%1) \n" >+ "lea 0x10(%1),%1 \n" >+ "sub $0x4,%2 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((intptr_t)(src_stride)) // %3 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3"); > } > > // Reads 4 pixels at a time. > // Alignment requirement: dst_argb 16 byte aligned. >-void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEven_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > intptr_t src_stepx_x4 = (intptr_t)(src_stepx); > intptr_t src_stepx_x12; > (void)src_stride; >- asm volatile ( >- "lea " MEMLEA3(0x00,1,4) ",%1 \n" >- "lea " MEMLEA4(0x00,1,1,2) ",%4 \n" >- LABELALIGN >- "1: \n" >- "movd " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1 >- "punpckldq %%xmm1,%%xmm0 \n" >- MEMOPREG(movd,0x00,0,1,2,xmm2) // movd (%0,%1,2),%%xmm2 >- MEMOPREG(movd,0x00,0,4,1,xmm3) // movd (%0,%4,1),%%xmm3 >- "lea " MEMLEA4(0x00,0,1,4) ",%0 \n" >- "punpckldq %%xmm3,%%xmm2 \n" >- "punpcklqdq %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(src_stepx_x4), // %1 >- "+r"(dst_argb), // %2 >- "+r"(dst_width), // %3 >- "=&r"(src_stepx_x12) // %4 >- :: "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3" >- ); >+ asm volatile( >+ "lea 0x00(,%1,4),%1 \n" >+ "lea 0x00(%1,%1,2),%4 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movd (%0),%%xmm0 \n" >+ "movd 0x00(%0,%1,1),%%xmm1 \n" >+ "punpckldq %%xmm1,%%xmm0 \n" >+ "movd 0x00(%0,%1,2),%%xmm2 \n" >+ "movd 0x00(%0,%4,1),%%xmm3 \n" >+ "lea 0x00(%0,%1,4),%0 \n" >+ "punpckldq %%xmm3,%%xmm2 \n" >+ "punpcklqdq %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(src_stepx_x4), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(dst_width), // %3 >+ "=&r"(src_stepx_x12) // %4 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3"); > } > > // Blends four 2x2 to 4x1. > // Alignment requirement: dst_argb 16 byte aligned. >-void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > intptr_t src_stepx_x4 = (intptr_t)(src_stepx); > intptr_t src_stepx_x12; > intptr_t row1 = (intptr_t)(src_stride); >- asm volatile ( >- "lea " MEMLEA3(0x00,1,4) ",%1 \n" >- "lea " MEMLEA4(0x00,1,1,2) ",%4 \n" >- "lea " MEMLEA4(0x00,0,5,1) ",%5 \n" >- >- LABELALIGN >- "1: \n" >- "movq " MEMACCESS(0) ",%%xmm0 \n" >- MEMOPREG(movhps,0x00,0,1,1,xmm0) // movhps (%0,%1,1),%%xmm0 >- MEMOPREG(movq,0x00,0,1,2,xmm1) // movq (%0,%1,2),%%xmm1 >- MEMOPREG(movhps,0x00,0,4,1,xmm1) // movhps (%0,%4,1),%%xmm1 >- "lea " MEMLEA4(0x00,0,1,4) ",%0 \n" >- "movq " MEMACCESS(5) ",%%xmm2 \n" >- MEMOPREG(movhps,0x00,5,1,1,xmm2) // movhps (%5,%1,1),%%xmm2 >- MEMOPREG(movq,0x00,5,1,2,xmm3) // movq (%5,%1,2),%%xmm3 >- MEMOPREG(movhps,0x00,5,4,1,xmm3) // movhps (%5,%4,1),%%xmm3 >- "lea " MEMLEA4(0x00,5,1,4) ",%5 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "pavgb %%xmm3,%%xmm1 \n" >- "movdqa %%xmm0,%%xmm2 \n" >- "shufps $0x88,%%xmm1,%%xmm0 \n" >- "shufps $0xdd,%%xmm1,%%xmm2 \n" >- "pavgb %%xmm2,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%3 \n" >- "jg 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(src_stepx_x4), // %1 >- "+r"(dst_argb), // %2 >- "+rm"(dst_width), // %3 >- "=&r"(src_stepx_x12), // %4 >- "+r"(row1) // %5 >- :: "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3" >- ); >+ asm volatile( >+ "lea 0x00(,%1,4),%1 \n" >+ "lea 0x00(%1,%1,2),%4 \n" >+ "lea 0x00(%0,%5,1),%5 \n" >+ >+ LABELALIGN >+ "1: \n" >+ "movq (%0),%%xmm0 \n" >+ "movhps 0x00(%0,%1,1),%%xmm0 \n" >+ "movq 0x00(%0,%1,2),%%xmm1 \n" >+ "movhps 0x00(%0,%4,1),%%xmm1 \n" >+ "lea 0x00(%0,%1,4),%0 \n" >+ "movq (%5),%%xmm2 \n" >+ "movhps 0x00(%5,%1,1),%%xmm2 \n" >+ "movq 0x00(%5,%1,2),%%xmm3 \n" >+ "movhps 0x00(%5,%4,1),%%xmm3 \n" >+ "lea 0x00(%5,%1,4),%5 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "pavgb %%xmm3,%%xmm1 \n" >+ "movdqa %%xmm0,%%xmm2 \n" >+ "shufps $0x88,%%xmm1,%%xmm0 \n" >+ "shufps $0xdd,%%xmm1,%%xmm2 \n" >+ "pavgb %%xmm2,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%3 \n" >+ "jg 1b \n" >+ : "+r"(src_argb), // %0 >+ "+r"(src_stepx_x4), // %1 >+ "+r"(dst_argb), // %2 >+ "+rm"(dst_width), // %3 >+ "=&r"(src_stepx_x12), // %4 >+ "+r"(row1) // %5 >+ ::"memory", >+ "cc", "xmm0", "xmm1", "xmm2", "xmm3"); > } > >-void ScaleARGBCols_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { > intptr_t x0, x1; >- asm volatile ( >- "movd %5,%%xmm2 \n" >- "movd %6,%%xmm3 \n" >- "pshufd $0x0,%%xmm2,%%xmm2 \n" >- "pshufd $0x11,%%xmm3,%%xmm0 \n" >- "paddd %%xmm0,%%xmm2 \n" >- "paddd %%xmm3,%%xmm3 \n" >- "pshufd $0x5,%%xmm3,%%xmm0 \n" >- "paddd %%xmm0,%%xmm2 \n" >- "paddd %%xmm3,%%xmm3 \n" >- "pshufd $0x0,%%xmm3,%%xmm3 \n" >- "pextrw $0x1,%%xmm2,%k0 \n" >- "pextrw $0x3,%%xmm2,%k1 \n" >- "cmp $0x0,%4 \n" >- "jl 99f \n" >- "sub $0x4,%4 \n" >- "jl 49f \n" >- >- LABELALIGN >- "40: \n" >- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 >- MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1 >- "pextrw $0x5,%%xmm2,%k0 \n" >- "pextrw $0x7,%%xmm2,%k1 \n" >- "paddd %%xmm3,%%xmm2 \n" >- "punpckldq %%xmm1,%%xmm0 \n" >- MEMOPREG(movd,0x00,3,0,4,xmm1) // movd (%3,%0,4),%%xmm1 >- MEMOPREG(movd,0x00,3,1,4,xmm4) // movd (%3,%1,4),%%xmm4 >- "pextrw $0x1,%%xmm2,%k0 \n" >- "pextrw $0x3,%%xmm2,%k1 \n" >- "punpckldq %%xmm4,%%xmm1 \n" >- "punpcklqdq %%xmm1,%%xmm0 \n" >- "movdqu %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x10,2) ",%2 \n" >- "sub $0x4,%4 \n" >- "jge 40b \n" >- >- "49: \n" >- "test $0x2,%4 \n" >- "je 29f \n" >- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 >- MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1 >- "pextrw $0x5,%%xmm2,%k0 \n" >- "punpckldq %%xmm1,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(2) " \n" >- "lea " MEMLEA(0x8,2) ",%2 \n" >- "29: \n" >- "test $0x1,%4 \n" >- "je 99f \n" >- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 >- "movd %%xmm0," MEMACCESS(2) " \n" >- "99: \n" >- : "=&a"(x0), // %0 >- "=&d"(x1), // %1 >- "+r"(dst_argb), // %2 >- "+r"(src_argb), // %3 >- "+r"(dst_width) // %4 >- : "rm"(x), // %5 >- "rm"(dx) // %6 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" >- ); >+ asm volatile( >+ "movd %5,%%xmm2 \n" >+ "movd %6,%%xmm3 \n" >+ "pshufd $0x0,%%xmm2,%%xmm2 \n" >+ "pshufd $0x11,%%xmm3,%%xmm0 \n" >+ "paddd %%xmm0,%%xmm2 \n" >+ "paddd %%xmm3,%%xmm3 \n" >+ "pshufd $0x5,%%xmm3,%%xmm0 \n" >+ "paddd %%xmm0,%%xmm2 \n" >+ "paddd %%xmm3,%%xmm3 \n" >+ "pshufd $0x0,%%xmm3,%%xmm3 \n" >+ "pextrw $0x1,%%xmm2,%k0 \n" >+ "pextrw $0x3,%%xmm2,%k1 \n" >+ "cmp $0x0,%4 \n" >+ "jl 99f \n" >+ "sub $0x4,%4 \n" >+ "jl 49f \n" >+ >+ LABELALIGN >+ "40: \n" >+ "movd 0x00(%3,%0,4),%%xmm0 \n" >+ "movd 0x00(%3,%1,4),%%xmm1 \n" >+ "pextrw $0x5,%%xmm2,%k0 \n" >+ "pextrw $0x7,%%xmm2,%k1 \n" >+ "paddd %%xmm3,%%xmm2 \n" >+ "punpckldq %%xmm1,%%xmm0 \n" >+ "movd 0x00(%3,%0,4),%%xmm1 \n" >+ "movd 0x00(%3,%1,4),%%xmm4 \n" >+ "pextrw $0x1,%%xmm2,%k0 \n" >+ "pextrw $0x3,%%xmm2,%k1 \n" >+ "punpckldq %%xmm4,%%xmm1 \n" >+ "punpcklqdq %%xmm1,%%xmm0 \n" >+ "movdqu %%xmm0,(%2) \n" >+ "lea 0x10(%2),%2 \n" >+ "sub $0x4,%4 \n" >+ "jge 40b \n" >+ >+ "49: \n" >+ "test $0x2,%4 \n" >+ "je 29f \n" >+ "movd 0x00(%3,%0,4),%%xmm0 \n" >+ "movd 0x00(%3,%1,4),%%xmm1 \n" >+ "pextrw $0x5,%%xmm2,%k0 \n" >+ "punpckldq %%xmm1,%%xmm0 \n" >+ "movq %%xmm0,(%2) \n" >+ "lea 0x8(%2),%2 \n" >+ "29: \n" >+ "test $0x1,%4 \n" >+ "je 99f \n" >+ "movd 0x00(%3,%0,4),%%xmm0 \n" >+ "movd %%xmm0,(%2) \n" >+ "99: \n" >+ : "=&a"(x0), // %0 >+ "=&d"(x1), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(src_argb), // %3 >+ "+r"(dst_width) // %4 >+ : "rm"(x), // %5 >+ "rm"(dx) // %6 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"); > } > > // Reads 4 pixels, duplicates them and writes 8 pixels. > // Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned. >-void ScaleARGBColsUp2_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBColsUp2_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { > (void)x; > (void)dx; >- asm volatile ( >- LABELALIGN >- "1: \n" >- "movdqu " MEMACCESS(1) ",%%xmm0 \n" >- "lea " MEMLEA(0x10,1) ",%1 \n" >- "movdqa %%xmm0,%%xmm1 \n" >- "punpckldq %%xmm0,%%xmm0 \n" >- "punpckhdq %%xmm1,%%xmm1 \n" >- "movdqu %%xmm0," MEMACCESS(0) " \n" >- "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" >- "lea " MEMLEA(0x20,0) ",%0 \n" >- "sub $0x8,%2 \n" >- "jg 1b \n" >- >- : "+r"(dst_argb), // %0 >- "+r"(src_argb), // %1 >- "+r"(dst_width) // %2 >- :: "memory", "cc", NACL_R14 >- "xmm0", "xmm1" >- ); >+ asm volatile( >+ >+ LABELALIGN >+ "1: \n" >+ "movdqu (%1),%%xmm0 \n" >+ "lea 0x10(%1),%1 \n" >+ "movdqa %%xmm0,%%xmm1 \n" >+ "punpckldq %%xmm0,%%xmm0 \n" >+ "punpckhdq %%xmm1,%%xmm1 \n" >+ "movdqu %%xmm0,(%0) \n" >+ "movdqu %%xmm1,0x10(%0) \n" >+ "lea 0x20(%0),%0 \n" >+ "sub $0x8,%2 \n" >+ "jg 1b \n" >+ >+ : "+r"(dst_argb), // %0 >+ "+r"(src_argb), // %1 >+ "+r"(dst_width) // %2 >+ ::"memory", >+ "cc", "xmm0", "xmm1"); > } > > // Shuffle table for arranging 2 pixels into pairs for pmaddubsw >-static uvec8 kShuffleColARGB = { >+static const uvec8 kShuffleColARGB = { > 0u, 4u, 1u, 5u, 2u, 6u, 3u, 7u, // bbggrraa 1st pixel > 8u, 12u, 9u, 13u, 10u, 14u, 11u, 15u // bbggrraa 2nd pixel > }; > > // Shuffle table for duplicating 2 fractions into 8 bytes each >-static uvec8 kShuffleFractions = { >+static const uvec8 kShuffleFractions = { > 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, > }; > > // Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version >-void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_SSSE3(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >@@ -1275,67 +1274,65 @@ void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, > "m"(kShuffleFractions) // %1 > ); > >- asm volatile ( >- "movd %5,%%xmm2 \n" >- "movd %6,%%xmm3 \n" >- "pcmpeqb %%xmm6,%%xmm6 \n" >- "psrlw $0x9,%%xmm6 \n" >- "pextrw $0x1,%%xmm2,%k3 \n" >- "sub $0x2,%2 \n" >- "jl 29f \n" >- "movdqa %%xmm2,%%xmm0 \n" >- "paddd %%xmm3,%%xmm0 \n" >- "punpckldq %%xmm0,%%xmm2 \n" >- "punpckldq %%xmm3,%%xmm3 \n" >- "paddd %%xmm3,%%xmm3 \n" >- "pextrw $0x3,%%xmm2,%k4 \n" >- >- LABELALIGN >- "2: \n" >- "movdqa %%xmm2,%%xmm1 \n" >- "paddd %%xmm3,%%xmm2 \n" >- MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0 >- "psrlw $0x9,%%xmm1 \n" >- MEMOPREG(movhps,0x00,1,4,4,xmm0) // movhps (%1,%4,4),%%xmm0 >- "pshufb %%xmm5,%%xmm1 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "pxor %%xmm6,%%xmm1 \n" >- "pmaddubsw %%xmm1,%%xmm0 \n" >- "psrlw $0x7,%%xmm0 \n" >- "pextrw $0x1,%%xmm2,%k3 \n" >- "pextrw $0x3,%%xmm2,%k4 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movq %%xmm0," MEMACCESS(0) " \n" >- "lea " MEMLEA(0x8,0) ",%0 \n" >- "sub $0x2,%2 \n" >- "jge 2b \n" >- >- LABELALIGN >- "29: \n" >- "add $0x1,%2 \n" >- "jl 99f \n" >- "psrlw $0x9,%%xmm2 \n" >- MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0 >- "pshufb %%xmm5,%%xmm2 \n" >- "pshufb %%xmm4,%%xmm0 \n" >- "pxor %%xmm6,%%xmm2 \n" >- "pmaddubsw %%xmm2,%%xmm0 \n" >- "psrlw $0x7,%%xmm0 \n" >- "packuswb %%xmm0,%%xmm0 \n" >- "movd %%xmm0," MEMACCESS(0) " \n" >- >- LABELALIGN >- "99: \n" >- : "+r"(dst_argb), // %0 >- "+r"(src_argb), // %1 >- "+rm"(dst_width), // %2 >- "=&r"(x0), // %3 >- "=&r"(x1) // %4 >- : "rm"(x), // %5 >- "rm"(dx) // %6 >- : "memory", "cc", NACL_R14 >- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" >- ); >+ asm volatile( >+ "movd %5,%%xmm2 \n" >+ "movd %6,%%xmm3 \n" >+ "pcmpeqb %%xmm6,%%xmm6 \n" >+ "psrlw $0x9,%%xmm6 \n" >+ "pextrw $0x1,%%xmm2,%k3 \n" >+ "sub $0x2,%2 \n" >+ "jl 29f \n" >+ "movdqa %%xmm2,%%xmm0 \n" >+ "paddd %%xmm3,%%xmm0 \n" >+ "punpckldq %%xmm0,%%xmm2 \n" >+ "punpckldq %%xmm3,%%xmm3 \n" >+ "paddd %%xmm3,%%xmm3 \n" >+ "pextrw $0x3,%%xmm2,%k4 \n" >+ >+ LABELALIGN >+ "2: \n" >+ "movdqa %%xmm2,%%xmm1 \n" >+ "paddd %%xmm3,%%xmm2 \n" >+ "movq 0x00(%1,%3,4),%%xmm0 \n" >+ "psrlw $0x9,%%xmm1 \n" >+ "movhps 0x00(%1,%4,4),%%xmm0 \n" >+ "pshufb %%xmm5,%%xmm1 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "pxor %%xmm6,%%xmm1 \n" >+ "pmaddubsw %%xmm1,%%xmm0 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "pextrw $0x1,%%xmm2,%k3 \n" >+ "pextrw $0x3,%%xmm2,%k4 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movq %%xmm0,(%0) \n" >+ "lea 0x8(%0),%0 \n" >+ "sub $0x2,%2 \n" >+ "jge 2b \n" >+ >+ LABELALIGN >+ "29: \n" >+ "add $0x1,%2 \n" >+ "jl 99f \n" >+ "psrlw $0x9,%%xmm2 \n" >+ "movq 0x00(%1,%3,4),%%xmm0 \n" >+ "pshufb %%xmm5,%%xmm2 \n" >+ "pshufb %%xmm4,%%xmm0 \n" >+ "pxor %%xmm6,%%xmm2 \n" >+ "pmaddubsw %%xmm2,%%xmm0 \n" >+ "psrlw $0x7,%%xmm0 \n" >+ "packuswb %%xmm0,%%xmm0 \n" >+ "movd %%xmm0,(%0) \n" >+ >+ LABELALIGN "99: \n" // clang-format error. >+ >+ : "+r"(dst_argb), // %0 >+ "+r"(src_argb), // %1 >+ "+rm"(dst_width), // %2 >+ "=&r"(x0), // %3 >+ "=&r"(x1) // %4 >+ : "rm"(x), // %5 >+ "rm"(dx) // %6 >+ : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"); > } > > // Divide num by div and return as 16.16 fixed point result. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc >index df1f482be6d..482a521f0d2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc >@@ -127,13 +127,13 @@ void ScaleARGBRowDownEven_MSA(const uint8_t* src_argb, > } > } > >-void ScaleARGBRowDownEvenBox_MSA(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_MSA(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > int x; >- const uint8* nxt_argb = src_argb + src_stride; >+ const uint8_t* nxt_argb = src_argb + src_stride; > int32_t stepx = src_stepx * 4; > int64_t data0, data1, data2, data3; > v16u8 src0 = {0}, src1 = {0}, src2 = {0}, src3 = {0}; >@@ -553,8 +553,8 @@ void ScaleAddRow_MSA(const uint8_t* src_ptr, uint16_t* dst_ptr, int src_width) { > } > } > >-void ScaleFilterCols_MSA(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_MSA(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -630,13 +630,13 @@ void ScaleFilterCols_MSA(uint8* dst_ptr, > } > } > >-void ScaleARGBCols_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_MSA(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint32* src = (const uint32*)(src_argb); >- uint32* dst = (uint32*)(dst_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); >+ uint32_t* dst = (uint32_t*)(dst_argb); > int j; > v4i32 x_vec = __msa_fill_w(x); > v4i32 dx_vec = __msa_fill_w(dx); >@@ -657,12 +657,12 @@ void ScaleARGBCols_MSA(uint8* dst_argb, > } > } > >-void ScaleARGBFilterCols_MSA(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_MSA(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint32* src = (const uint32*)(src_argb); >+ const uint32_t* src = (const uint32_t*)(src_argb); > int j; > v4u32 src0, src1, src2, src3; > v4u32 vec0, vec1, vec2, vec3; >@@ -722,9 +722,9 @@ void ScaleARGBFilterCols_MSA(uint8* dst_argb, > } > } > >-void ScaleRowDown34_MSA(const uint8* src_ptr, >+void ScaleRowDown34_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > int x; > (void)src_stride; >@@ -753,12 +753,12 @@ void ScaleRowDown34_MSA(const uint8* src_ptr, > } > } > >-void ScaleRowDown34_0_Box_MSA(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7, dst0, dst1, dst2; > v16u8 vec0, vec1, vec2, vec3, vec4, vec5; >@@ -847,12 +847,12 @@ void ScaleRowDown34_0_Box_MSA(const uint8* src_ptr, > } > } > >-void ScaleRowDown34_1_Box_MSA(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_MSA(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* d, >+ uint8_t* d, > int dst_width) { >- const uint8* s = src_ptr; >- const uint8* t = src_ptr + src_stride; >+ const uint8_t* s = src_ptr; >+ const uint8_t* t = src_ptr + src_stride; > int x; > v16u8 src0, src1, src2, src3, src4, src5, src6, src7, dst0, dst1, dst2; > v16u8 vec0, vec1, vec2, vec3, vec4, vec5; >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc >index b03a828213d..459a2995dfe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc >@@ -23,9 +23,9 @@ extern "C" { > // Provided by Fritz Koenig > > // Read 32x1 throw away even pixels, and write 16x1. >-void ScaleRowDown2_NEON(const uint8* src_ptr, >+void ScaleRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -44,9 +44,9 @@ void ScaleRowDown2_NEON(const uint8* src_ptr, > } > > // Read 32x1 average down and write 16x1. >-void ScaleRowDown2Linear_NEON(const uint8* src_ptr, >+void ScaleRowDown2Linear_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -65,9 +65,9 @@ void ScaleRowDown2Linear_NEON(const uint8* src_ptr, > } > > // Read 32x2 average down and write 16x1. >-void ScaleRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > asm volatile( > // change the stride to row 2 pointer >@@ -95,9 +95,9 @@ void ScaleRowDown2Box_NEON(const uint8* src_ptr, > ); > } > >-void ScaleRowDown4_NEON(const uint8* src_ptr, >+void ScaleRowDown4_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -113,13 +113,13 @@ void ScaleRowDown4_NEON(const uint8* src_ptr, > : "q0", "q1", "memory", "cc"); > } > >-void ScaleRowDown4Box_NEON(const uint8* src_ptr, >+void ScaleRowDown4Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- const uint8* src_ptr1 = src_ptr + src_stride; >- const uint8* src_ptr2 = src_ptr + src_stride * 2; >- const uint8* src_ptr3 = src_ptr + src_stride * 3; >+ const uint8_t* src_ptr1 = src_ptr + src_stride; >+ const uint8_t* src_ptr2 = src_ptr + src_stride * 2; >+ const uint8_t* src_ptr3 = src_ptr + src_stride * 3; > asm volatile( > "1: \n" > "vld1.8 {q0}, [%0]! \n" // load up 16x4 >@@ -149,9 +149,9 @@ void ScaleRowDown4Box_NEON(const uint8* src_ptr, > // Down scale from 4 to 3 pixels. Use the neon multilane read/write > // to load up the every 4th pixel into a 4 different registers. > // Point samples 32 pixels to 24 pixels. >-void ScaleRowDown34_NEON(const uint8* src_ptr, >+void ScaleRowDown34_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -168,9 +168,9 @@ void ScaleRowDown34_NEON(const uint8* src_ptr, > : "d0", "d1", "d2", "d3", "memory", "cc"); > } > >-void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "vmov.u8 d24, #3 \n" >@@ -225,9 +225,9 @@ void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, > "cc"); > } > >-void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "vmov.u8 d24, #3 \n" >@@ -264,18 +264,21 @@ void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, > } > > #define HAS_SCALEROWDOWN38_NEON >-static uvec8 kShuf38 = {0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0}; >-static uvec8 kShuf38_2 = {0, 8, 16, 2, 10, 17, 4, 12, >- 18, 6, 14, 19, 0, 0, 0, 0}; >-static vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12, >- 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12}; >-static vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18, >- 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18}; >+static const uvec8 kShuf38 = {0, 3, 6, 8, 11, 14, 16, 19, >+ 22, 24, 27, 30, 0, 0, 0, 0}; >+static const uvec8 kShuf38_2 = {0, 8, 16, 2, 10, 17, 4, 12, >+ 18, 6, 14, 19, 0, 0, 0, 0}; >+static const vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12, >+ 65536 / 12, 65536 / 12, 65536 / 12, >+ 65536 / 12, 65536 / 12}; >+static const vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18, >+ 65536 / 18, 65536 / 18, 65536 / 18, >+ 65536 / 18, 65536 / 18}; > > // 32 -> 12 >-void ScaleRowDown38_NEON(const uint8* src_ptr, >+void ScaleRowDown38_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -296,11 +299,11 @@ void ScaleRowDown38_NEON(const uint8* src_ptr, > } > > // 32x3 -> 12x1 >-void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, >+void OMITFP ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- const uint8* src_ptr1 = src_ptr + src_stride * 2; >+ const uint8_t* src_ptr1 = src_ptr + src_stride * 2; > > asm volatile( > "vld1.16 {q13}, [%5] \n" >@@ -408,9 +411,9 @@ void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, > } > > // 32x2 -> 12x1 >-void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "vld1.16 {q13}, [%4] \n" >@@ -501,12 +504,12 @@ void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, > : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc"); > } > >-void ScaleAddRows_NEON(const uint8* src_ptr, >+void ScaleAddRows_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int src_width, > int src_height) { >- const uint8* src_tmp; >+ const uint8_t* src_tmp; > asm volatile( > "1: \n" > "mov %0, %1 \n" >@@ -544,17 +547,17 @@ void ScaleAddRows_NEON(const uint8* src_ptr, > "vld2.8 {d6[" #n "], d7[" #n "]}, [%6] \n" > > // The NEON version mimics this formula (from row_common.cc): >-// #define BLENDER(a, b, f) (uint8)((int)(a) + >+// #define BLENDER(a, b, f) (uint8_t)((int)(a) + > // ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) > >-void ScaleFilterCols_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { > int dx_offset[4] = {0, 1, 2, 3}; > int* tmp = dx_offset; >- const uint8* src_tmp = src_ptr; >+ const uint8_t* src_tmp = src_ptr; > asm volatile ( > "vdup.32 q0, %3 \n" // x > "vdup.32 q1, %4 \n" // dx >@@ -612,8 +615,8 @@ void ScaleFilterCols_NEON(uint8* dst_ptr, > #undef LOAD2_DATA8_LANE > > // 16x2 -> 16x1 >-void ScaleFilterRows_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterRows_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >@@ -696,9 +699,9 @@ void ScaleFilterRows_NEON(uint8* dst_ptr, > : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc"); > } > >-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -724,9 +727,9 @@ void ScaleARGBRowDown2_NEON(const uint8* src_ptr, > // 54: f942 038d vst2.32 {d16-d19}, [r2]! > // 58: d1f5 bne.n 46 <ScaleARGBRowDown2_C+0x46> > >-void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -746,9 +749,9 @@ void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, > ); > } > >-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > asm volatile( > // change the stride to row 2 pointer >@@ -783,10 +786,10 @@ void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, > > // Reads 4 pixels at a time. > // Alignment requirement: src_argb 4 byte aligned. >-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEven_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -808,10 +811,10 @@ void ScaleARGBRowDownEven_NEON(const uint8* src_argb, > > // Reads 4 pixels at a time. > // Alignment requirement: src_argb 4 byte aligned. >-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > asm volatile( > "mov r12, %4, lsl #2 \n" >@@ -854,13 +857,13 @@ void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, > "add %3, %3, %4 \n" \ > "vld1.32 {" #dn "[" #n "]}, [%6] \n" > >-void ScaleARGBCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { > int tmp; >- const uint8* src_tmp = src_argb; >+ const uint8_t* src_tmp = src_argb; > asm volatile( > "1: \n" > // clang-format off >@@ -897,14 +900,14 @@ void ScaleARGBCols_NEON(uint8* dst_argb, > "add %3, %3, %4 \n" \ > "vld2.32 {" #dn1 "[" #n "], " #dn2 "[" #n "]}, [%6] \n" > >-void ScaleARGBFilterCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { > int dx_offset[4] = {0, 1, 2, 3}; > int* tmp = dx_offset; >- const uint8* src_tmp = src_argb; >+ const uint8_t* src_tmp = src_argb; > asm volatile ( > "vdup.32 q0, %3 \n" // x > "vdup.32 q1, %4 \n" // dx >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc >index 93fe67bf1e6..494a9cfbfbe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc >@@ -21,9 +21,9 @@ extern "C" { > #if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) > > // Read 32x1 throw away even pixels, and write 16x1. >-void ScaleRowDown2_NEON(const uint8* src_ptr, >+void ScaleRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -42,9 +42,9 @@ void ScaleRowDown2_NEON(const uint8* src_ptr, > } > > // Read 32x1 average down and write 16x1. >-void ScaleRowDown2Linear_NEON(const uint8* src_ptr, >+void ScaleRowDown2Linear_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -64,9 +64,9 @@ void ScaleRowDown2Linear_NEON(const uint8* src_ptr, > } > > // Read 32x2 average down and write 16x1. >-void ScaleRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > asm volatile( > // change the stride to row 2 pointer >@@ -92,9 +92,9 @@ void ScaleRowDown2Box_NEON(const uint8* src_ptr, > ); > } > >-void ScaleRowDown4_NEON(const uint8* src_ptr, >+void ScaleRowDown4_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -110,13 +110,13 @@ void ScaleRowDown4_NEON(const uint8* src_ptr, > : "v0", "v1", "v2", "v3", "memory", "cc"); > } > >-void ScaleRowDown4Box_NEON(const uint8* src_ptr, >+void ScaleRowDown4Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- const uint8* src_ptr1 = src_ptr + src_stride; >- const uint8* src_ptr2 = src_ptr + src_stride * 2; >- const uint8* src_ptr3 = src_ptr + src_stride * 3; >+ const uint8_t* src_ptr1 = src_ptr + src_stride; >+ const uint8_t* src_ptr2 = src_ptr + src_stride * 2; >+ const uint8_t* src_ptr3 = src_ptr + src_stride * 3; > asm volatile( > "1: \n" > "ld1 {v0.16b}, [%0], #16 \n" // load up 16x4 >@@ -145,9 +145,9 @@ void ScaleRowDown4Box_NEON(const uint8* src_ptr, > // Down scale from 4 to 3 pixels. Use the neon multilane read/write > // to load up the every 4th pixel into a 4 different registers. > // Point samples 32 pixels to 24 pixels. >-void ScaleRowDown34_NEON(const uint8* src_ptr, >+void ScaleRowDown34_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -164,9 +164,9 @@ void ScaleRowDown34_NEON(const uint8* src_ptr, > : "v0", "v1", "v2", "v3", "memory", "cc"); > } > >-void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_0_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movi v20.8b, #3 \n" >@@ -221,9 +221,9 @@ void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr, > "v19", "v20", "memory", "cc"); > } > >-void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown34_1_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > asm volatile( > "movi v20.8b, #3 \n" >@@ -261,18 +261,21 @@ void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr, > : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v20", "memory", "cc"); > } > >-static uvec8 kShuf38 = {0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0}; >-static uvec8 kShuf38_2 = {0, 16, 32, 2, 18, 33, 4, 20, >- 34, 6, 22, 35, 0, 0, 0, 0}; >-static vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12, >- 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12}; >-static vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18, >- 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18}; >+static const uvec8 kShuf38 = {0, 3, 6, 8, 11, 14, 16, 19, >+ 22, 24, 27, 30, 0, 0, 0, 0}; >+static const uvec8 kShuf38_2 = {0, 16, 32, 2, 18, 33, 4, 20, >+ 34, 6, 22, 35, 0, 0, 0, 0}; >+static const vec16 kMult38_Div6 = {65536 / 12, 65536 / 12, 65536 / 12, >+ 65536 / 12, 65536 / 12, 65536 / 12, >+ 65536 / 12, 65536 / 12}; >+static const vec16 kMult38_Div9 = {65536 / 18, 65536 / 18, 65536 / 18, >+ 65536 / 18, 65536 / 18, 65536 / 18, >+ 65536 / 18, 65536 / 18}; > > // 32 -> 12 >-void ScaleRowDown38_NEON(const uint8* src_ptr, >+void ScaleRowDown38_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -292,11 +295,11 @@ void ScaleRowDown38_NEON(const uint8* src_ptr, > } > > // 32x3 -> 12x1 >-void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, >+void OMITFP ScaleRowDown38_3_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { >- const uint8* src_ptr1 = src_ptr + src_stride * 2; >+ const uint8_t* src_ptr1 = src_ptr + src_stride * 2; > ptrdiff_t tmp_src_stride = src_stride; > > asm volatile( >@@ -412,9 +415,9 @@ void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr, > } > > // 32x2 -> 12x1 >-void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, >+void ScaleRowDown38_2_Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > // TODO(fbarchard): use src_stride directly for clang 3.5+. > ptrdiff_t tmp_src_stride = src_stride; >@@ -512,12 +515,12 @@ void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr, > "v19", "v30", "v31", "memory", "cc"); > } > >-void ScaleAddRows_NEON(const uint8* src_ptr, >+void ScaleAddRows_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst_ptr, >+ uint16_t* dst_ptr, > int src_width, > int src_height) { >- const uint8* src_tmp; >+ const uint8_t* src_tmp; > asm volatile( > "1: \n" > "mov %0, %1 \n" >@@ -555,19 +558,19 @@ void ScaleAddRows_NEON(const uint8* src_ptr, > "ld2 {v4.b, v5.b}[" #n "], [%6] \n" > > // The NEON version mimics this formula (from row_common.cc): >-// #define BLENDER(a, b, f) (uint8)((int)(a) + >+// #define BLENDER(a, b, f) (uint8_t)((int)(a) + > // ((((int)((f)) * ((int)(b) - (int)(a))) + 0x8000) >> 16)) > >-void ScaleFilterCols_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterCols_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { > int dx_offset[4] = {0, 1, 2, 3}; > int* tmp = dx_offset; >- const uint8* src_tmp = src_ptr; >- int64 x64 = (int64)x; // NOLINT >- int64 dx64 = (int64)dx; // NOLINT >+ const uint8_t* src_tmp = src_ptr; >+ int64_t x64 = (int64_t)x; // NOLINT >+ int64_t dx64 = (int64_t)dx; // NOLINT > asm volatile ( > "dup v0.4s, %w3 \n" // x > "dup v1.4s, %w4 \n" // dx >@@ -625,8 +628,8 @@ void ScaleFilterCols_NEON(uint8* dst_ptr, > #undef LOAD2_DATA8_LANE > > // 16x2 -> 16x1 >-void ScaleFilterRows_NEON(uint8* dst_ptr, >- const uint8* src_ptr, >+void ScaleFilterRows_NEON(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > ptrdiff_t src_stride, > int dst_width, > int source_y_fraction) { >@@ -710,9 +713,9 @@ void ScaleFilterRows_NEON(uint8* dst_ptr, > : "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "memory", "cc"); > } > >-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -731,9 +734,9 @@ void ScaleARGBRowDown2_NEON(const uint8* src_ptr, > ); > } > >-void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, >+void ScaleARGBRowDown2Linear_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -754,9 +757,9 @@ void ScaleARGBRowDown2Linear_NEON(const uint8* src_argb, > ); > } > >-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, >+void ScaleARGBRowDown2Box_NEON(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst, >+ uint8_t* dst, > int dst_width) { > asm volatile( > // change the stride to row 2 pointer >@@ -789,10 +792,10 @@ void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, > > // Reads 4 pixels at a time. > // Alignment requirement: src_argb 4 byte aligned. >-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEven_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > (void)src_stride; > asm volatile( >@@ -804,10 +807,10 @@ void ScaleARGBRowDownEven_NEON(const uint8* src_argb, > "subs %w2, %w2, #4 \n" // 4 pixels per loop. > "st1 {v0.16b}, [%1], #16 \n" > "b.gt 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(dst_argb), // %1 >- "+r"(dst_width) // %2 >- : "r"((int64)(src_stepx * 4)) // %3 >+ : "+r"(src_argb), // %0 >+ "+r"(dst_argb), // %1 >+ "+r"(dst_width) // %2 >+ : "r"((int64_t)(src_stepx * 4)) // %3 > : "memory", "cc", "v0"); > } > >@@ -815,10 +818,10 @@ void ScaleARGBRowDownEven_NEON(const uint8* src_argb, > // Alignment requirement: src_argb 4 byte aligned. > // TODO(Yang Zhang): Might be worth another optimization pass in future. > // It could be upgraded to 8 pixels at a time to start with. >-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, >+void ScaleARGBRowDownEvenBox_NEON(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > asm volatile( > "add %1, %1, %0 \n" >@@ -848,11 +851,11 @@ void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, > "subs %w3, %w3, #4 \n" // 4 pixels per loop. > "st1 {v0.16b}, [%2], #16 \n" > "b.gt 1b \n" >- : "+r"(src_argb), // %0 >- "+r"(src_stride), // %1 >- "+r"(dst_argb), // %2 >- "+r"(dst_width) // %3 >- : "r"((int64)(src_stepx * 4)) // %4 >+ : "+r"(src_argb), // %0 >+ "+r"(src_stride), // %1 >+ "+r"(dst_argb), // %2 >+ "+r"(dst_width) // %3 >+ : "r"((int64_t)(src_stepx * 4)) // %4 > : "memory", "cc", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16"); > } > >@@ -864,15 +867,15 @@ void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, > "add %3, %3, %4 \n" \ > "ld1 {" #vn ".s}[" #n "], [%6] \n" > >-void ScaleARGBCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >- const uint8* src_tmp = src_argb; >- int64 x64 = (int64)x; // NOLINT >- int64 dx64 = (int64)dx; // NOLINT >- int64 tmp64; >+ const uint8_t* src_tmp = src_argb; >+ int64_t x64 = (int64_t)x; // NOLINT >+ int64_t dx64 = (int64_t)dx; // NOLINT >+ int64_t tmp64; > asm volatile( > "1: \n" > // clang-format off >@@ -909,16 +912,16 @@ void ScaleARGBCols_NEON(uint8* dst_argb, > "add %3, %3, %4 \n" \ > "ld2 {" #vn1 ".s, " #vn2 ".s}[" #n "], [%6] \n" > >-void ScaleARGBFilterCols_NEON(uint8* dst_argb, >- const uint8* src_argb, >+void ScaleARGBFilterCols_NEON(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { > int dx_offset[4] = {0, 1, 2, 3}; > int* tmp = dx_offset; >- const uint8* src_tmp = src_argb; >- int64 x64 = (int64)x; // NOLINT >- int64 dx64 = (int64)dx; // NOLINT >+ const uint8_t* src_tmp = src_argb; >+ int64_t x64 = (int64_t)x; // NOLINT >+ int64_t dx64 = (int64_t)dx; // NOLINT > asm volatile ( > "dup v0.4s, %w3 \n" // x > "dup v1.4s, %w4 \n" // dx >@@ -975,9 +978,9 @@ void ScaleARGBFilterCols_NEON(uint8* dst_argb, > #undef LOAD2_DATA32_LANE > > // Read 16x2 average down and write 8x1. >-void ScaleRowDown2Box_16_NEON(const uint16* src_ptr, >+void ScaleRowDown2Box_16_NEON(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > asm volatile( > // change the stride to row 2 pointer >@@ -1005,9 +1008,9 @@ void ScaleRowDown2Box_16_NEON(const uint16* src_ptr, > > // Read 8x2 upsample with filtering and write 16x1. > // Actually reads an extra pixel, so 9x2. >-void ScaleRowUp2_16_NEON(const uint16* src_ptr, >+void ScaleRowUp2_16_NEON(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width) { > asm volatile( > "add %1, %0, %1, lsl #1 \n" // ptr + stide * 2 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_win.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_win.cc >index b5fd6638262..c5fc86f3e96 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_win.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/scale_win.cc >@@ -20,77 +20,78 @@ extern "C" { > #if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER) > > // Offsets for source bytes 0 to 9 >-static uvec8 kShuf0 = {0, 1, 3, 4, 5, 7, 8, 9, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf0 = {0, 1, 3, 4, 5, 7, 8, 9, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12. >-static uvec8 kShuf1 = {3, 4, 5, 7, 8, 9, 11, 12, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf1 = {3, 4, 5, 7, 8, 9, 11, 12, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. >-static uvec8 kShuf2 = {5, 7, 8, 9, 11, 12, 13, 15, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf2 = {5, 7, 8, 9, 11, 12, 13, 15, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Offsets for source bytes 0 to 10 >-static uvec8 kShuf01 = {0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10}; >+static const uvec8 kShuf01 = {0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10}; > > // Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13. >-static uvec8 kShuf11 = {2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13}; >+static const uvec8 kShuf11 = {2, 3, 4, 5, 5, 6, 6, 7, >+ 8, 9, 9, 10, 10, 11, 12, 13}; > > // Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. >-static uvec8 kShuf21 = {5, 6, 6, 7, 8, 9, 9, 10, >- 10, 11, 12, 13, 13, 14, 14, 15}; >+static const uvec8 kShuf21 = {5, 6, 6, 7, 8, 9, 9, 10, >+ 10, 11, 12, 13, 13, 14, 14, 15}; > > // Coefficients for source bytes 0 to 10 >-static uvec8 kMadd01 = {3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2}; >+static const uvec8 kMadd01 = {3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2}; > > // Coefficients for source bytes 10 to 21 >-static uvec8 kMadd11 = {1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1}; >+static const uvec8 kMadd11 = {1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1}; > > // Coefficients for source bytes 21 to 31 >-static uvec8 kMadd21 = {2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3}; >+static const uvec8 kMadd21 = {2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3}; > > // Coefficients for source bytes 21 to 31 >-static vec16 kRound34 = {2, 2, 2, 2, 2, 2, 2, 2}; >+static const vec16 kRound34 = {2, 2, 2, 2, 2, 2, 2, 2}; > >-static uvec8 kShuf38a = {0, 3, 6, 8, 11, 14, 128, 128, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShuf38a = {0, 3, 6, 8, 11, 14, 128, 128, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > >-static uvec8 kShuf38b = {128, 128, 128, 128, 128, 128, 0, 3, >- 6, 8, 11, 14, 128, 128, 128, 128}; >+static const uvec8 kShuf38b = {128, 128, 128, 128, 128, 128, 0, 3, >+ 6, 8, 11, 14, 128, 128, 128, 128}; > > // Arrange words 0,3,6 into 0,1,2 >-static uvec8 kShufAc = {0, 1, 6, 7, 12, 13, 128, 128, >- 128, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAc = {0, 1, 6, 7, 12, 13, 128, 128, >+ 128, 128, 128, 128, 128, 128, 128, 128}; > > // Arrange words 0,3,6 into 3,4,5 >-static uvec8 kShufAc3 = {128, 128, 128, 128, 128, 128, 0, 1, >- 6, 7, 12, 13, 128, 128, 128, 128}; >+static const uvec8 kShufAc3 = {128, 128, 128, 128, 128, 128, 0, 1, >+ 6, 7, 12, 13, 128, 128, 128, 128}; > > // Scaling values for boxes of 3x3 and 2x3 >-static uvec16 kScaleAc33 = {65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, >- 65536 / 9, 65536 / 6, 0, 0}; >+static const uvec16 kScaleAc33 = {65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, >+ 65536 / 9, 65536 / 6, 0, 0}; > > // Arrange first value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb0 = {0, 128, 3, 128, 6, 128, 8, 128, >- 11, 128, 14, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb0 = {0, 128, 3, 128, 6, 128, 8, 128, >+ 11, 128, 14, 128, 128, 128, 128, 128}; > > // Arrange second value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb1 = {1, 128, 4, 128, 7, 128, 9, 128, >- 12, 128, 15, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb1 = {1, 128, 4, 128, 7, 128, 9, 128, >+ 12, 128, 15, 128, 128, 128, 128, 128}; > > // Arrange third value for pixels 0,1,2,3,4,5 >-static uvec8 kShufAb2 = {2, 128, 5, 128, 128, 128, 10, 128, >- 13, 128, 128, 128, 128, 128, 128, 128}; >+static const uvec8 kShufAb2 = {2, 128, 5, 128, 128, 128, 10, 128, >+ 13, 128, 128, 128, 128, 128, 128, 128}; > > // Scaling values for boxes of 3x2 and 2x2 >-static uvec16 kScaleAb2 = {65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, >- 65536 / 3, 65536 / 2, 0, 0}; >+static const uvec16 kScaleAb2 = {65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, >+ 65536 / 3, 65536 / 2, 0, 0}; > > // Reads 32 pixels, throws half away and writes 16 pixels. >-__declspec(naked) void ScaleRowDown2_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -115,9 +116,9 @@ __declspec(naked) void ScaleRowDown2_SSSE3(const uint8* src_ptr, > } > > // Blends 32x1 rectangle to 16x1. >-__declspec(naked) void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2Linear_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -149,9 +150,9 @@ __declspec(naked) void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, > } > > // Blends 32x2 rectangle to 16x1. >-__declspec(naked) void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -194,9 +195,9 @@ __declspec(naked) void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, > > #ifdef HAS_SCALEROWDOWN2_AVX2 > // Reads 64 pixels, throws half away and writes 32 pixels. >-__declspec(naked) void ScaleRowDown2_AVX2(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -223,9 +224,9 @@ __declspec(naked) void ScaleRowDown2_AVX2(const uint8* src_ptr, > } > > // Blends 64x1 rectangle to 32x1. >-__declspec(naked) void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2Linear_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -261,9 +262,9 @@ __declspec(naked) void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, > // For rounding, average = (sum + 2) / 4 > // becomes average((sum >> 1), 0) > // Blends 64x2 rectangle to 32x1. >-__declspec(naked) void ScaleRowDown2Box_AVX2(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown2Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -308,9 +309,9 @@ __declspec(naked) void ScaleRowDown2Box_AVX2(const uint8* src_ptr, > #endif // HAS_SCALEROWDOWN2_AVX2 > > // Point samples 32 pixels to 8 pixels. >-__declspec(naked) void ScaleRowDown4_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown4_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -340,9 +341,9 @@ __declspec(naked) void ScaleRowDown4_SSSE3(const uint8* src_ptr, > } > > // Blends 32x4 rectangle to 8x1. >-__declspec(naked) void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown4Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -399,9 +400,9 @@ __declspec(naked) void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, > > #ifdef HAS_SCALEROWDOWN4_AVX2 > // Point samples 64 pixels to 16 pixels. >-__declspec(naked) void ScaleRowDown4_AVX2(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown4_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -434,9 +435,9 @@ __declspec(naked) void ScaleRowDown4_AVX2(const uint8* src_ptr, > } > > // Blends 64x4 rectangle to 16x1. >-__declspec(naked) void ScaleRowDown4Box_AVX2(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown4Box_AVX2(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -498,9 +499,9 @@ __declspec(naked) void ScaleRowDown4Box_AVX2(const uint8* src_ptr, > // Produces three 8 byte values. For each 8 bytes, 16 bytes are read. > // Then shuffled to do the scaling. > >-__declspec(naked) void ScaleRowDown34_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown34_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -546,9 +547,9 @@ __declspec(naked) void ScaleRowDown34_SSSE3(const uint8* src_ptr, > // xmm7 kRound34 > > // Note that movdqa+palign may be better than movdqu. >-__declspec(naked) void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown34_1_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -603,9 +604,9 @@ __declspec(naked) void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, > } > > // Note that movdqa+palign may be better than movdqu. >-__declspec(naked) void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown34_0_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -665,9 +666,9 @@ __declspec(naked) void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, > // 3/8 point sampler > > // Scale 32 pixels to 12 >-__declspec(naked) void ScaleRowDown38_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown38_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -697,9 +698,9 @@ __declspec(naked) void ScaleRowDown38_SSSE3(const uint8* src_ptr, > } > > // Scale 16x3 pixels to 6x1 with interpolation >-__declspec(naked) void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown38_3_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -762,9 +763,9 @@ __declspec(naked) void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, > } > > // Scale 16x2 pixels to 6x1 with interpolation >-__declspec(naked) void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, >+__declspec(naked) void ScaleRowDown38_2_Box_SSSE3(const uint8_t* src_ptr, > ptrdiff_t src_stride, >- uint8* dst_ptr, >+ uint8_t* dst_ptr, > int dst_width) { > __asm { > push esi >@@ -807,8 +808,8 @@ __declspec(naked) void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, > } > > // Reads 16 bytes and accumulates to 16 shorts at a time. >-__declspec(naked) void ScaleAddRow_SSE2(const uint8* src_ptr, >- uint16* dst_ptr, >+__declspec(naked) void ScaleAddRow_SSE2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, > int src_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -838,8 +839,8 @@ __declspec(naked) void ScaleAddRow_SSE2(const uint8* src_ptr, > > #ifdef HAS_SCALEADDROW_AVX2 > // Reads 32 bytes and accumulates to 32 shorts at a time. >-__declspec(naked) void ScaleAddRow_AVX2(const uint8* src_ptr, >- uint16* dst_ptr, >+__declspec(naked) void ScaleAddRow_AVX2(const uint8_t* src_ptr, >+ uint16_t* dst_ptr, > int src_width) { > __asm { > mov eax, [esp + 4] // src_ptr >@@ -870,16 +871,16 @@ __declspec(naked) void ScaleAddRow_AVX2(const uint8* src_ptr, > > // Constant for making pixels signed to avoid pmaddubsw > // saturation. >-static uvec8 kFsub80 = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, >- 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; >+static const uvec8 kFsub80 = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, >+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; > > // Constant for making pixels unsigned and adding .5 for rounding. >-static uvec16 kFadd40 = {0x4040, 0x4040, 0x4040, 0x4040, >- 0x4040, 0x4040, 0x4040, 0x4040}; >+static const uvec16 kFadd40 = {0x4040, 0x4040, 0x4040, 0x4040, >+ 0x4040, 0x4040, 0x4040, 0x4040}; > > // Bilinear column filtering. SSSE3 version. >-__declspec(naked) void ScaleFilterCols_SSSE3(uint8* dst_ptr, >- const uint8* src_ptr, >+__declspec(naked) void ScaleFilterCols_SSSE3(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -964,8 +965,8 @@ __declspec(naked) void ScaleFilterCols_SSSE3(uint8* dst_ptr, > } > > // Reads 16 pixels, duplicates them and writes 32 pixels. >-__declspec(naked) void ScaleColsUp2_SSE2(uint8* dst_ptr, >- const uint8* src_ptr, >+__declspec(naked) void ScaleColsUp2_SSE2(uint8_t* dst_ptr, >+ const uint8_t* src_ptr, > int dst_width, > int x, > int dx) { >@@ -991,9 +992,9 @@ __declspec(naked) void ScaleColsUp2_SSE2(uint8* dst_ptr, > } > > // Reads 8 pixels, throws half away and writes 4 even pixels (0, 2, 4, 6) >-__declspec(naked) void ScaleARGBRowDown2_SSE2(const uint8* src_argb, >+__declspec(naked) void ScaleARGBRowDown2_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -1016,9 +1017,9 @@ __declspec(naked) void ScaleARGBRowDown2_SSE2(const uint8* src_argb, > } > > // Blends 8x1 rectangle to 4x1. >-__declspec(naked) void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, >+__declspec(naked) void ScaleARGBRowDown2Linear_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > __asm { > mov eax, [esp + 4] // src_argb >@@ -1044,9 +1045,9 @@ __declspec(naked) void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, > } > > // Blends 8x2 rectangle to 4x1. >-__declspec(naked) void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, >+__declspec(naked) void ScaleARGBRowDown2Box_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > __asm { > push esi >@@ -1078,10 +1079,10 @@ __declspec(naked) void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, > } > > // Reads 4 pixels at a time. >-__declspec(naked) void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, >+__declspec(naked) void ScaleARGBRowDownEven_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > __asm { > push ebx >@@ -1115,10 +1116,10 @@ __declspec(naked) void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, > } > > // Blends four 2x2 to 4x1. >-__declspec(naked) void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, >+__declspec(naked) void ScaleARGBRowDownEvenBox_SSE2(const uint8_t* src_argb, > ptrdiff_t src_stride, > int src_stepx, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_width) { > __asm { > push ebx >@@ -1163,8 +1164,8 @@ __declspec(naked) void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, > } > > // Column scaling unfiltered. SSE2 version. >-__declspec(naked) void ScaleARGBCols_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+__declspec(naked) void ScaleARGBCols_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >@@ -1246,18 +1247,18 @@ __declspec(naked) void ScaleARGBCols_SSE2(uint8* dst_argb, > // TODO(fbarchard): Port to Neon > > // Shuffle table for arranging 2 pixels into pairs for pmaddubsw >-static uvec8 kShuffleColARGB = { >+static const uvec8 kShuffleColARGB = { > 0u, 4u, 1u, 5u, 2u, 6u, 3u, 7u, // bbggrraa 1st pixel > 8u, 12u, 9u, 13u, 10u, 14u, 11u, 15u // bbggrraa 2nd pixel > }; > > // Shuffle table for duplicating 2 fractions into 8 bytes each >-static uvec8 kShuffleFractions = { >+static const uvec8 kShuffleFractions = { > 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, > }; > >-__declspec(naked) void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, >- const uint8* src_argb, >+__declspec(naked) void ScaleARGBFilterCols_SSSE3(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >@@ -1329,8 +1330,8 @@ __declspec(naked) void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, > } > > // Reads 4 pixels, duplicates them and writes 8 pixels. >-__declspec(naked) void ScaleARGBColsUp2_SSE2(uint8* dst_argb, >- const uint8* src_argb, >+__declspec(naked) void ScaleARGBColsUp2_SSE2(uint8_t* dst_argb, >+ const uint8_t* src_argb, > int dst_width, > int x, > int dx) { >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/video_common.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/video_common.cc >index 3e9c6a29502..92384c050cd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/video_common.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/source/video_common.cc >@@ -15,14 +15,13 @@ namespace libyuv { > extern "C" { > #endif > >-#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0])) >- > struct FourCCAliasEntry { >- uint32 alias; >- uint32 canonical; >+ uint32_t alias; >+ uint32_t canonical; > }; > >-static const struct FourCCAliasEntry kFourCCAliases[] = { >+#define NUM_ALIASES 18 >+static const struct FourCCAliasEntry kFourCCAliases[NUM_ALIASES] = { > {FOURCC_IYUV, FOURCC_I420}, > {FOURCC_YU12, FOURCC_I420}, > {FOURCC_YU16, FOURCC_I422}, >@@ -46,9 +45,9 @@ static const struct FourCCAliasEntry kFourCCAliases[] = { > // {FOURCC_BGRA, FOURCC_ARGB}, // kCMPixelFormat_32BGRA > > LIBYUV_API >-uint32 CanonicalFourCC(uint32 fourcc) { >+uint32_t CanonicalFourCC(uint32_t fourcc) { > int i; >- for (i = 0; i < ARRAY_SIZE(kFourCCAliases); ++i) { >+ for (i = 0; i < NUM_ALIASES; ++i) { > if (kFourCCAliases[i].alias == fourcc) { > return kFourCCAliases[i].canonical; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/autoroller/roll_deps.py b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/autoroller/roll_deps.py >index efea81e07b1..09ddc40e730 100755 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/autoroller/roll_deps.py >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/autoroller/roll_deps.py >@@ -207,7 +207,13 @@ def BuildDepsentryDict(deps_dict): > """Builds a dict of paths to DepsEntry objects from a raw parsed deps dict.""" > result = {} > def AddDepsEntries(deps_subdict): >- for path, deps_url in deps_subdict.iteritems(): >+ for path, deps_url_spec in deps_subdict.iteritems(): >+ # The deps url is either an URL and a condition, or just the URL. >+ if isinstance(deps_url_spec, dict): >+ deps_url = deps_url_spec['url'] >+ else: >+ deps_url = deps_url_spec >+ > if not result.has_key(path): > url, revision = deps_url.split('@') if deps_url else (None, None) > result[path] = DepsEntry(path, url, revision) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/get_landmines.py b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/get_landmines.py >index 3dc78bb973f..c554f04a39a 100755 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/get_landmines.py >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/get_landmines.py >@@ -12,20 +12,8 @@ This file emits the list of reasons why a particular build needs to be clobbered > (or a list of 'landmines'). > """ > >-import os > import sys > >-script_dir = os.path.dirname(os.path.realpath(__file__)) >-checkout_root = os.path.abspath(os.path.join(script_dir, os.pardir)) >-sys.path.insert(0, os.path.join(checkout_root, 'build')) >-import landmine_utils >- >- >-distributor = landmine_utils.distributor >-gyp_defines = landmine_utils.gyp_defines >-gyp_msvs_version = landmine_utils.gyp_msvs_version >-platform = landmine_utils.platform >- > > def print_landmines(): > """ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.bat b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.bat >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.py b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.py >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.sh b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/chrome_tests.sh >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/locate_valgrind.sh b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/locate_valgrind.sh >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/memcheck_analyze.py b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/memcheck_analyze.py >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/valgrind.sh b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/valgrind.sh >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/valgrind_test.py b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/tools_libyuv/valgrind/valgrind_test.py >old mode 100644 >new mode 100755 >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/basictypes_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/basictypes_test.cc >index 89f7644d58e..9aaa2dcd989 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/basictypes_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/basictypes_test.cc >@@ -13,25 +13,15 @@ > > namespace libyuv { > >-TEST_F(LibYUVBaseTest, Endian) { >- uint16 v16 = 0x1234u; >- uint8 first_byte = *reinterpret_cast<uint8*>(&v16); >-#if defined(LIBYUV_LITTLE_ENDIAN) >- EXPECT_EQ(0x34u, first_byte); >-#else >- EXPECT_EQ(0x12u, first_byte); >-#endif >-} >- > TEST_F(LibYUVBaseTest, SizeOfTypes) { >- int8 i8 = -1; >- uint8 u8 = 1u; >- int16 i16 = -1; >- uint16 u16 = 1u; >- int32 i32 = -1; >- uint32 u32 = 1u; >- int64 i64 = -1; >- uint64 u64 = 1u; >+ int8_t i8 = -1; >+ uint8_t u8 = 1u; >+ int16_t i16 = -1; >+ uint16_t u16 = 1u; >+ int32_t i32 = -1; >+ uint32_t u32 = 1u; >+ int64_t i64 = -1; >+ uint64_t u64 = 1u; > EXPECT_EQ(1u, sizeof(i8)); > EXPECT_EQ(1u, sizeof(u8)); > EXPECT_EQ(2u, sizeof(i16)); >@@ -50,11 +40,4 @@ TEST_F(LibYUVBaseTest, SizeOfTypes) { > EXPECT_LT(0u, u64); > } > >-TEST_F(LibYUVBaseTest, SizeOfConstants) { >- EXPECT_EQ(8u, sizeof(INT64_C(0))); >- EXPECT_EQ(8u, sizeof(UINT64_C(0))); >- EXPECT_EQ(8u, sizeof(INT64_C(0x1234567887654321))); >- EXPECT_EQ(8u, sizeof(UINT64_C(0x8765432112345678))); >-} >- > } // namespace libyuv >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/color_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/color_test.cc >index 30b6411283f..4bb448d56fe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/color_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/color_test.cc >@@ -63,10 +63,10 @@ namespace libyuv { > \ > /* The test is overall for color conversion matrix being reversible, so */ \ > /* this initializes the pixel with 2x2 blocks to eliminate subsampling. */ \ >- uint8* p = orig_y; \ >+ uint8_t* p = orig_y; \ > for (int y = 0; y < benchmark_height_ - HS1; y += HS) { \ > for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ >- uint8 r = static_cast<uint8>(fastrand()); \ >+ uint8_t r = static_cast<uint8_t>(fastrand()); \ > p[0] = r; \ > p[1] = r; \ > p[HN] = r; \ >@@ -74,7 +74,7 @@ namespace libyuv { > p += 2; \ > } \ > if (benchmark_width_ & 1) { \ >- uint8 r = static_cast<uint8>(fastrand()); \ >+ uint8_t r = static_cast<uint8_t>(fastrand()); \ > p[0] = r; \ > p[HN] = r; \ > p += 1; \ >@@ -83,13 +83,13 @@ namespace libyuv { > } \ > if ((benchmark_height_ & 1) && HS == 2) { \ > for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ >- uint8 r = static_cast<uint8>(fastrand()); \ >+ uint8_t r = static_cast<uint8_t>(fastrand()); \ > p[0] = r; \ > p[1] = r; \ > p += 2; \ > } \ > if (benchmark_width_ & 1) { \ >- uint8 r = static_cast<uint8>(fastrand()); \ >+ uint8_t r = static_cast<uint8_t>(fastrand()); \ > p[0] = r; \ > p += 1; \ > } \ >@@ -147,10 +147,10 @@ static void YUVToRGB(int y, int u, int v, int* r, int* g, int* b) { > const int kPixels = kWidth * kHeight; > const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); > >- SIMD_ALIGNED(uint8 orig_y[16]); >- SIMD_ALIGNED(uint8 orig_u[8]); >- SIMD_ALIGNED(uint8 orig_v[8]); >- SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); >+ SIMD_ALIGNED(uint8_t orig_y[16]); >+ SIMD_ALIGNED(uint8_t orig_u[8]); >+ SIMD_ALIGNED(uint8_t orig_v[8]); >+ SIMD_ALIGNED(uint8_t orig_pixels[16 * 4]); > memset(orig_y, y, kPixels); > memset(orig_u, u, kHalfPixels); > memset(orig_v, v, kHalfPixels); >@@ -170,10 +170,10 @@ static void YUVJToRGB(int y, int u, int v, int* r, int* g, int* b) { > const int kPixels = kWidth * kHeight; > const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); > >- SIMD_ALIGNED(uint8 orig_y[16]); >- SIMD_ALIGNED(uint8 orig_u[8]); >- SIMD_ALIGNED(uint8 orig_v[8]); >- SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); >+ SIMD_ALIGNED(uint8_t orig_y[16]); >+ SIMD_ALIGNED(uint8_t orig_u[8]); >+ SIMD_ALIGNED(uint8_t orig_v[8]); >+ SIMD_ALIGNED(uint8_t orig_pixels[16 * 4]); > memset(orig_y, y, kPixels); > memset(orig_u, u, kHalfPixels); > memset(orig_v, v, kHalfPixels); >@@ -192,8 +192,8 @@ static void YToRGB(int y, int* r, int* g, int* b) { > const int kHeight = 1; > const int kPixels = kWidth * kHeight; > >- SIMD_ALIGNED(uint8 orig_y[16]); >- SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); >+ SIMD_ALIGNED(uint8_t orig_y[16]); >+ SIMD_ALIGNED(uint8_t orig_pixels[16 * 4]); > memset(orig_y, y, kPixels); > > /* YUV converted to ARGB. */ >@@ -209,8 +209,8 @@ static void YJToRGB(int y, int* r, int* g, int* b) { > const int kHeight = 1; > const int kPixels = kWidth * kHeight; > >- SIMD_ALIGNED(uint8 orig_y[16]); >- SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); >+ SIMD_ALIGNED(uint8_t orig_y[16]); >+ SIMD_ALIGNED(uint8_t orig_pixels[16 * 4]); > memset(orig_y, y, kPixels); > > /* YUV converted to ARGB. */ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/compare_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/compare_test.cc >index ff39b2b0f60..136254e169b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/compare_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/compare_test.cc >@@ -22,8 +22,10 @@ > namespace libyuv { > > // hash seed of 5381 recommended. >-static uint32 ReferenceHashDjb2(const uint8* src, uint64 count, uint32 seed) { >- uint32 hash = seed; >+static uint32_t ReferenceHashDjb2(const uint8_t* src, >+ uint64_t count, >+ uint32_t seed) { >+ uint32_t hash = seed; > if (count > 0) { > do { > hash = hash * 33 + *src++; >@@ -41,8 +43,8 @@ TEST_F(LibYUVCompareTest, Djb2_Test) { > "The quick brown fox jumps over the lazy dog" > " and feels as if he were in the seventh heaven of typography" > " together with Hermann Zapf"; >- uint32 foxhash = HashDjb2(reinterpret_cast<const uint8*>(fox), 131, 5381); >- const uint32 kExpectedFoxHash = 2611006483u; >+ uint32_t foxhash = HashDjb2(reinterpret_cast<const uint8_t*>(fox), 131, 5381); >+ const uint32_t kExpectedFoxHash = 2611006483u; > EXPECT_EQ(kExpectedFoxHash, foxhash); > > for (int i = 0; i < kMaxTest; ++i) { >@@ -50,8 +52,8 @@ TEST_F(LibYUVCompareTest, Djb2_Test) { > src_b[i] = (fastrand() & 0xff); > } > // Compare different buffers. Expect hash is different. >- uint32 h1 = HashDjb2(src_a, kMaxTest, 5381); >- uint32 h2 = HashDjb2(src_b, kMaxTest, 5381); >+ uint32_t h1 = HashDjb2(src_a, kMaxTest, 5381); >+ uint32_t h2 = HashDjb2(src_b, kMaxTest, 5381); > EXPECT_NE(h1, h2); > > // Make last half same. Expect hash is different. >@@ -124,8 +126,8 @@ TEST_F(LibYUVCompareTest, BenchmarkDjb2_Opt) { > for (int i = 0; i < kMaxTest; ++i) { > src_a[i] = i; > } >- uint32 h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381); >- uint32 h1; >+ uint32_t h2 = ReferenceHashDjb2(src_a, kMaxTest, 5381); >+ uint32_t h1; > for (int i = 0; i < benchmark_iterations_; ++i) { > h1 = HashDjb2(src_a, kMaxTest, 5381); > } >@@ -139,8 +141,8 @@ TEST_F(LibYUVCompareTest, BenchmarkDjb2_Unaligned) { > for (int i = 0; i < kMaxTest; ++i) { > src_a[i + 1] = i; > } >- uint32 h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381); >- uint32 h1; >+ uint32_t h2 = ReferenceHashDjb2(src_a + 1, kMaxTest, 5381); >+ uint32_t h1; > for (int i = 0; i < benchmark_iterations_; ++i) { > h1 = HashDjb2(src_a + 1, kMaxTest, 5381); > } >@@ -149,7 +151,7 @@ TEST_F(LibYUVCompareTest, BenchmarkDjb2_Unaligned) { > } > > TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Opt) { >- uint32 fourcc; >+ uint32_t fourcc; > const int kMaxTest = benchmark_width_ * benchmark_height_ * 4; > align_buffer_page_end(src_a, kMaxTest); > for (int i = 0; i < kMaxTest; ++i) { >@@ -159,12 +161,12 @@ TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Opt) { > src_a[0] = 0; > fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_, > benchmark_height_); >- EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_BGRA), fourcc); >+ EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_BGRA), fourcc); > src_a[0] = 255; > src_a[3] = 0; > fourcc = ARGBDetect(src_a, benchmark_width_ * 4, benchmark_width_, > benchmark_height_); >- EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_ARGB), fourcc); >+ EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_ARGB), fourcc); > src_a[3] = 255; > > for (int i = 0; i < benchmark_iterations_; ++i) { >@@ -177,7 +179,7 @@ TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Opt) { > } > > TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Unaligned) { >- uint32 fourcc; >+ uint32_t fourcc; > const int kMaxTest = benchmark_width_ * benchmark_height_ * 4 + 1; > align_buffer_page_end(src_a, kMaxTest); > for (int i = 1; i < kMaxTest; ++i) { >@@ -187,12 +189,12 @@ TEST_F(LibYUVCompareTest, BenchmarkARGBDetect_Unaligned) { > src_a[0 + 1] = 0; > fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_, > benchmark_height_); >- EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_BGRA), fourcc); >+ EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_BGRA), fourcc); > src_a[0 + 1] = 255; > src_a[3 + 1] = 0; > fourcc = ARGBDetect(src_a + 1, benchmark_width_ * 4, benchmark_width_, > benchmark_height_); >- EXPECT_EQ(static_cast<uint32>(libyuv::FOURCC_ARGB), fourcc); >+ EXPECT_EQ(static_cast<uint32_t>(libyuv::FOURCC_ARGB), fourcc); > src_a[3 + 1] = 255; > > for (int i = 0; i < benchmark_iterations_; ++i) { >@@ -214,14 +216,14 @@ TEST_F(LibYUVCompareTest, BenchmarkHammingDistance_Opt) { > // Test known value > memcpy(src_a, "test0123test4567", 16); > memcpy(src_b, "tick0123tock4567", 16); >- uint32 h1 = HammingDistance_C(src_a, src_b, 16); >+ uint32_t h1 = HammingDistance_C(src_a, src_b, 16); > EXPECT_EQ(16u, h1); > > // Test C vs OPT on random buffer > MemRandomize(src_a, kMaxWidth); > MemRandomize(src_b, kMaxWidth); > >- uint32 h0 = HammingDistance_C(src_a, src_b, kMaxWidth); >+ uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth); > > int count = > benchmark_iterations_ * >@@ -273,14 +275,14 @@ TEST_F(LibYUVCompareTest, BenchmarkHammingDistance_C) { > // Test known value > memcpy(src_a, "test0123test4567", 16); > memcpy(src_b, "tick0123tock4567", 16); >- uint32 h1 = HammingDistance_C(src_a, src_b, 16); >+ uint32_t h1 = HammingDistance_C(src_a, src_b, 16); > EXPECT_EQ(16u, h1); > > // Test C vs OPT on random buffer > MemRandomize(src_a, kMaxWidth); > MemRandomize(src_b, kMaxWidth); > >- uint32 h0 = HammingDistance_C(src_a, src_b, kMaxWidth); >+ uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth); > > int count = > benchmark_iterations_ * >@@ -304,14 +306,14 @@ TEST_F(LibYUVCompareTest, BenchmarkHammingDistance) { > > memcpy(src_a, "test0123test4567", 16); > memcpy(src_b, "tick0123tock4567", 16); >- uint64 h1 = ComputeHammingDistance(src_a, src_b, 16); >+ uint64_t h1 = ComputeHammingDistance(src_a, src_b, 16); > EXPECT_EQ(16u, h1); > > // Test C vs OPT on random buffer > MemRandomize(src_a, kMaxWidth); > MemRandomize(src_b, kMaxWidth); > >- uint32 h0 = HammingDistance_C(src_a, src_b, kMaxWidth); >+ uint32_t h0 = HammingDistance_C(src_a, src_b, kMaxWidth); > > int count = > benchmark_iterations_ * >@@ -337,14 +339,14 @@ static const int kMaxOptCount = (1 << (32 - 3)) - 64; // 536870848 > #endif > > TEST_F(LibYUVCompareTest, TestHammingDistance_Opt) { >- uint32 h1 = 0; >- const int kMaxWidth = benchmark_width_ * benchmark_height_; >+ uint32_t h1 = 0; >+ const int kMaxWidth = (benchmark_width_ * benchmark_height_ + 31) & ~31; > align_buffer_page_end(src_a, kMaxWidth); > align_buffer_page_end(src_b, kMaxWidth); > memset(src_a, 255u, kMaxWidth); > memset(src_b, 0u, kMaxWidth); > >- uint64 h0 = ComputeHammingDistance(src_a, src_b, kMaxWidth); >+ uint64_t h0 = ComputeHammingDistance(src_a, src_b, kMaxWidth); > EXPECT_EQ(kMaxWidth * 8ULL, h0); > > for (int i = 0; i < benchmark_iterations_; ++i) { >@@ -385,7 +387,7 @@ TEST_F(LibYUVCompareTest, TestHammingDistance_Opt) { > if (kMaxWidth <= kMaxOptCount) { > EXPECT_EQ(kMaxWidth * 8U, h1); > } else { >- if (kMaxWidth * 8ULL != static_cast<uint64>(h1)) { >+ if (kMaxWidth * 8ULL != static_cast<uint64_t>(h1)) { > printf( > "warning - HammingDistance_Opt %u does not match %llu " > "but length of %u is longer than guaranteed.\n", >@@ -408,7 +410,7 @@ TEST_F(LibYUVCompareTest, TestHammingDistance) { > memset(src_a, 255u, benchmark_width_ * benchmark_height_); > memset(src_b, 0, benchmark_width_ * benchmark_height_); > >- uint64 h1 = 0; >+ uint64_t h1 = 0; > for (int i = 0; i < benchmark_iterations_; ++i) { > h1 = ComputeHammingDistance(src_a, src_b, > benchmark_width_ * benchmark_height_); >@@ -428,7 +430,7 @@ TEST_F(LibYUVCompareTest, BenchmarkSumSquareError_Opt) { > > memcpy(src_a, "test0123test4567", 16); > memcpy(src_b, "tick0123tock4567", 16); >- uint64 h1 = ComputeSumSquareError(src_a, src_b, 16); >+ uint64_t h1 = ComputeSumSquareError(src_a, src_b, 16); > EXPECT_EQ(790u, h1); > > for (int i = 0; i < kMaxWidth; ++i) { >@@ -458,7 +460,7 @@ TEST_F(LibYUVCompareTest, SumSquareError) { > memset(src_a, 0, kMaxWidth); > memset(src_b, 0, kMaxWidth); > >- uint64 err; >+ uint64_t err; > err = ComputeSumSquareError(src_a, src_b, kMaxWidth); > > EXPECT_EQ(0u, err); >@@ -480,10 +482,10 @@ TEST_F(LibYUVCompareTest, SumSquareError) { > } > > MaskCpuFlags(disable_cpu_flags_); >- uint64 c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); >+ uint64_t c_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); > > MaskCpuFlags(benchmark_cpu_info_); >- uint64 opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); >+ uint64_t opt_err = ComputeSumSquareError(src_a, src_b, kMaxWidth); > > EXPECT_EQ(c_err, opt_err); > >@@ -502,9 +504,10 @@ TEST_F(LibYUVCompareTest, BenchmarkPsnr_Opt) { > MaskCpuFlags(benchmark_cpu_info_); > > double opt_time = get_time(); >- for (int i = 0; i < benchmark_iterations_; ++i) >+ for (int i = 0; i < benchmark_iterations_; ++i) { > CalcFramePsnr(src_a, benchmark_width_, src_b, benchmark_width_, > benchmark_width_, benchmark_height_); >+ } > > opt_time = (get_time() - opt_time) / benchmark_iterations_; > printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6); >@@ -526,9 +529,10 @@ TEST_F(LibYUVCompareTest, BenchmarkPsnr_Unaligned) { > MaskCpuFlags(benchmark_cpu_info_); > > double opt_time = get_time(); >- for (int i = 0; i < benchmark_iterations_; ++i) >+ for (int i = 0; i < benchmark_iterations_; ++i) { > CalcFramePsnr(src_a + 1, benchmark_width_, src_b, benchmark_width_, > benchmark_width_, benchmark_height_); >+ } > > opt_time = (get_time() - opt_time) / benchmark_iterations_; > printf("BenchmarkPsnr_Opt - %8.2f us opt\n", opt_time * 1e6); >@@ -627,9 +631,10 @@ TEST_F(LibYUVCompareTest, DISABLED_BenchmarkSsim_Opt) { > MaskCpuFlags(benchmark_cpu_info_); > > double opt_time = get_time(); >- for (int i = 0; i < benchmark_iterations_; ++i) >+ for (int i = 0; i < benchmark_iterations_; ++i) { > CalcFrameSsim(src_a, benchmark_width_, src_b, benchmark_width_, > benchmark_width_, benchmark_height_); >+ } > > opt_time = (get_time() - opt_time) / benchmark_iterations_; > printf("BenchmarkSsim_Opt - %8.2f us opt\n", opt_time * 1e6); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/convert_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/convert_test.cc >index 56b6364e5eb..39281ae0807 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/convert_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/convert_test.cc >@@ -8,9 +8,12 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include <assert.h> > #include <stdlib.h> > #include <time.h> > >+#include "libyuv/row.h" /* For ARGBToAR30Row_AVX2 */ >+ > #include "libyuv/basic_types.h" > #include "libyuv/compare.h" > #include "libyuv/convert.h" >@@ -26,102 +29,91 @@ > #include "libyuv/rotate.h" > #include "libyuv/video_common.h" > >+#if defined(__arm__) || defined(__aarch64__) >+// arm version subsamples by summing 4 pixels then multiplying by matrix with >+// 4x smaller coefficients which are rounded to nearest integer. >+#define ARM_YUV_ERROR 4 >+#else >+#define ARM_YUV_ERROR 0 >+#endif >+ > namespace libyuv { > >+// Alias to copy pixels as is >+#define AR30ToAR30 ARGBCopy >+#define ABGRToABGR ARGBCopy >+ > #define SUBSAMPLE(v, a) ((((v) + (a)-1)) / (a)) > >-#define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >- FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, W1280, N, NEG, OFF) \ >+// Planar test >+ >+#define TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \ >+ SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, \ >+ DST_SUBSAMP_X, DST_SUBSAMP_Y, W1280, N, NEG, OFF) \ > TEST_F(LibYUVConvertTest, SRC_FMT_PLANAR##To##FMT_PLANAR##N) { \ >+ static_assert(SRC_BPC == 1 || SRC_BPC == 2, "SRC BPC unsupported"); \ >+ static_assert(DST_BPC == 1 || DST_BPC == 2, "DST BPC unsupported"); \ >+ static_assert(SRC_SUBSAMP_X == 1 || SRC_SUBSAMP_X == 2, \ >+ "DST SRC_SUBSAMP_X unsupported"); \ >+ static_assert(SRC_SUBSAMP_Y == 1 || SRC_SUBSAMP_Y == 2, \ >+ "DST SRC_SUBSAMP_Y unsupported"); \ >+ static_assert(DST_SUBSAMP_X == 1 || DST_SUBSAMP_X == 2, \ >+ "DST DST_SUBSAMP_X unsupported"); \ >+ static_assert(DST_SUBSAMP_Y == 1 || DST_SUBSAMP_Y == 2, \ >+ "DST DST_SUBSAMP_Y unsupported"); \ > const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ > const int kHeight = benchmark_height_; \ >- align_buffer_page_end(src_y, kWidth* kHeight + OFF); \ >- align_buffer_page_end(src_u, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \ >- OFF); \ >- align_buffer_page_end(src_v, SUBSAMPLE(kWidth, SRC_SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SRC_SUBSAMP_Y) + \ >- OFF); \ >- align_buffer_page_end(dst_y_c, kWidth* kHeight); \ >- align_buffer_page_end(dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- align_buffer_page_end(dst_v_c, SUBSAMPLE(kWidth, SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- align_buffer_page_end(dst_y_opt, kWidth* kHeight); \ >- align_buffer_page_end(dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \ >- SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- for (int i = 0; i < kHeight; ++i) \ >- for (int j = 0; j < kWidth; ++j) \ >- src_y[i * kWidth + j + OFF] = (fastrand() & 0xff); \ >- for (int i = 0; i < SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); ++i) { \ >- for (int j = 0; j < SUBSAMPLE(kWidth, SRC_SUBSAMP_X); ++j) { \ >- src_u[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \ >- (fastrand() & 0xff); \ >- src_v[(i * SUBSAMPLE(kWidth, SRC_SUBSAMP_X)) + j + OFF] = \ >- (fastrand() & 0xff); \ >- } \ >- } \ >- memset(dst_y_c, 1, kWidth* kHeight); \ >- memset(dst_u_c, 2, \ >- SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- memset(dst_v_c, 3, \ >- SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- memset(dst_y_opt, 101, kWidth* kHeight); \ >- memset(dst_u_opt, 102, \ >- SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- memset(dst_v_opt, 103, \ >- SUBSAMPLE(kWidth, SUBSAMP_X) * SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >+ const int kSrcHalfWidth = SUBSAMPLE(kWidth, SRC_SUBSAMP_X); \ >+ const int kSrcHalfHeight = SUBSAMPLE(kHeight, SRC_SUBSAMP_Y); \ >+ const int kDstHalfWidth = SUBSAMPLE(kWidth, DST_SUBSAMP_X); \ >+ const int kDstHalfHeight = SUBSAMPLE(kHeight, DST_SUBSAMP_Y); \ >+ align_buffer_page_end(src_y, kWidth* kHeight* SRC_BPC + OFF); \ >+ align_buffer_page_end(src_u, \ >+ kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF); \ >+ align_buffer_page_end(src_v, \ >+ kSrcHalfWidth* kSrcHalfHeight* SRC_BPC + OFF); \ >+ align_buffer_page_end(dst_y_c, kWidth* kHeight* DST_BPC); \ >+ align_buffer_page_end(dst_u_c, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ align_buffer_page_end(dst_v_c, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ align_buffer_page_end(dst_y_opt, kWidth* kHeight* DST_BPC); \ >+ align_buffer_page_end(dst_u_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ align_buffer_page_end(dst_v_opt, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ MemRandomize(src_y + OFF, kWidth * kHeight * SRC_BPC); \ >+ MemRandomize(src_u + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC); \ >+ MemRandomize(src_v + OFF, kSrcHalfWidth * kSrcHalfHeight * SRC_BPC); \ >+ memset(dst_y_c, 1, kWidth* kHeight* DST_BPC); \ >+ memset(dst_u_c, 2, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ memset(dst_v_c, 3, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ memset(dst_y_opt, 101, kWidth* kHeight* DST_BPC); \ >+ memset(dst_u_opt, 102, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ >+ memset(dst_v_opt, 103, kDstHalfWidth* kDstHalfHeight* DST_BPC); \ > MaskCpuFlags(disable_cpu_flags_); \ > SRC_FMT_PLANAR##To##FMT_PLANAR( \ >- src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \ >- src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_c, kWidth, \ >- dst_u_c, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_c, \ >- SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \ >+ reinterpret_cast<SRC_T*>(src_y + OFF), kWidth, \ >+ reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth, \ >+ reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth, \ >+ reinterpret_cast<DST_T*>(dst_y_c), kWidth, \ >+ reinterpret_cast<DST_T*>(dst_u_c), kDstHalfWidth, \ >+ reinterpret_cast<DST_T*>(dst_v_c), kDstHalfWidth, kWidth, \ >+ NEG kHeight); \ > MaskCpuFlags(benchmark_cpu_info_); \ > for (int i = 0; i < benchmark_iterations_; ++i) { \ > SRC_FMT_PLANAR##To##FMT_PLANAR( \ >- src_y + OFF, kWidth, src_u + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), \ >- src_v + OFF, SUBSAMPLE(kWidth, SRC_SUBSAMP_X), dst_y_opt, kWidth, \ >- dst_u_opt, SUBSAMPLE(kWidth, SUBSAMP_X), dst_v_opt, \ >- SUBSAMPLE(kWidth, SUBSAMP_X), kWidth, NEG kHeight); \ >+ reinterpret_cast<SRC_T*>(src_y + OFF), kWidth, \ >+ reinterpret_cast<SRC_T*>(src_u + OFF), kSrcHalfWidth, \ >+ reinterpret_cast<SRC_T*>(src_v + OFF), kSrcHalfWidth, \ >+ reinterpret_cast<DST_T*>(dst_y_opt), kWidth, \ >+ reinterpret_cast<DST_T*>(dst_u_opt), kDstHalfWidth, \ >+ reinterpret_cast<DST_T*>(dst_v_opt), kDstHalfWidth, kWidth, \ >+ NEG kHeight); \ > } \ >- int max_diff = 0; \ >- for (int i = 0; i < kHeight; ++i) { \ >- for (int j = 0; j < kWidth; ++j) { \ >- int abs_diff = abs(static_cast<int>(dst_y_c[i * kWidth + j]) - \ >- static_cast<int>(dst_y_opt[i * kWidth + j])); \ >- if (abs_diff > max_diff) { \ >- max_diff = abs_diff; \ >- } \ >- } \ >- } \ >- EXPECT_EQ(0, max_diff); \ >- for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \ >- for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \ >- int abs_diff = abs( \ >- static_cast<int>(dst_u_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \ >- static_cast<int>( \ >- dst_u_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \ >- if (abs_diff > max_diff) { \ >- max_diff = abs_diff; \ >- } \ >- } \ >+ for (int i = 0; i < kHeight * kWidth * DST_BPC; ++i) { \ >+ EXPECT_EQ(dst_y_c[i], dst_y_opt[i]); \ > } \ >- EXPECT_LE(max_diff, 3); \ >- for (int i = 0; i < SUBSAMPLE(kHeight, SUBSAMP_Y); ++i) { \ >- for (int j = 0; j < SUBSAMPLE(kWidth, SUBSAMP_X); ++j) { \ >- int abs_diff = abs( \ >- static_cast<int>(dst_v_c[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j]) - \ >- static_cast<int>( \ >- dst_v_opt[i * SUBSAMPLE(kWidth, SUBSAMP_X) + j])); \ >- if (abs_diff > max_diff) { \ >- max_diff = abs_diff; \ >- } \ >- } \ >+ for (int i = 0; i < kDstHalfWidth * kDstHalfHeight * DST_BPC; ++i) { \ >+ EXPECT_EQ(dst_u_c[i], dst_u_opt[i]); \ >+ EXPECT_EQ(dst_v_c[i], dst_v_opt[i]); \ > } \ >- EXPECT_LE(max_diff, 3); \ > free_aligned_buffer_page_end(dst_y_c); \ > free_aligned_buffer_page_end(dst_u_c); \ > free_aligned_buffer_page_end(dst_v_c); \ >@@ -133,25 +125,36 @@ namespace libyuv { > free_aligned_buffer_page_end(src_v); \ > } > >-#define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >- FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \ >- TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \ >- SUBSAMP_X, SUBSAMP_Y, benchmark_width_ - 4, _Any, +, 0) \ >- TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \ >- SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Unaligned, +, 1) \ >- TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \ >- SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Invert, -, 0) \ >- TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, FMT_PLANAR, \ >- SUBSAMP_X, SUBSAMP_Y, benchmark_width_, _Opt, +, 0) >- >-TESTPLANARTOP(I420, 2, 2, I420, 2, 2) >-TESTPLANARTOP(I422, 2, 1, I420, 2, 2) >-TESTPLANARTOP(I444, 1, 1, I420, 2, 2) >-TESTPLANARTOP(I420, 2, 2, I422, 2, 1) >-TESTPLANARTOP(I420, 2, 2, I444, 1, 1) >-TESTPLANARTOP(I420, 2, 2, I420Mirror, 2, 2) >-TESTPLANARTOP(I422, 2, 1, I422, 2, 1) >-TESTPLANARTOP(I444, 1, 1, I444, 1, 1) >+#define TESTPLANARTOP(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, \ >+ SRC_SUBSAMP_Y, FMT_PLANAR, DST_T, DST_BPC, \ >+ DST_SUBSAMP_X, DST_SUBSAMP_Y) \ >+ TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >+ FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \ >+ benchmark_width_ - 4, _Any, +, 0) \ >+ TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >+ FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \ >+ benchmark_width_, _Unaligned, +, 1) \ >+ TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >+ FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \ >+ benchmark_width_, _Invert, -, 0) \ >+ TESTPLANARTOPI(SRC_FMT_PLANAR, SRC_T, SRC_BPC, SRC_SUBSAMP_X, SRC_SUBSAMP_Y, \ >+ FMT_PLANAR, DST_T, DST_BPC, DST_SUBSAMP_X, DST_SUBSAMP_Y, \ >+ benchmark_width_, _Opt, +, 0) >+ >+TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420, uint8_t, 1, 2, 2) >+TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I420, uint8_t, 1, 2, 2) >+TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I420, uint8_t, 1, 2, 2) >+TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I422, uint8_t, 1, 2, 1) >+TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I444, uint8_t, 1, 1, 1) >+TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I420Mirror, uint8_t, 1, 2, 2) >+TESTPLANARTOP(I422, uint8_t, 1, 2, 1, I422, uint8_t, 1, 2, 1) >+TESTPLANARTOP(I444, uint8_t, 1, 1, 1, I444, uint8_t, 1, 1, 1) >+TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I010, uint16_t, 2, 2, 2) >+TESTPLANARTOP(I010, uint16_t, 2, 2, 2, I420, uint8_t, 1, 2, 2) >+TESTPLANARTOP(I420, uint8_t, 1, 2, 2, I010, uint16_t, 2, 2, 2) >+TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H010, uint16_t, 2, 2, 2) >+TESTPLANARTOP(H010, uint16_t, 2, 2, 2, H420, uint8_t, 1, 2, 2) >+TESTPLANARTOP(H420, uint8_t, 1, 2, 2, H010, uint16_t, 2, 2, 2) > > // Test Android 420 to I420 > #define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, \ >@@ -175,8 +178,8 @@ TESTPLANARTOP(I444, 1, 1, I444, 1, 1) > SUBSAMPLE(kHeight, SUBSAMP_Y)); \ > align_buffer_page_end(dst_v_opt, SUBSAMPLE(kWidth, SUBSAMP_X) * \ > SUBSAMPLE(kHeight, SUBSAMP_Y)); \ >- uint8* src_u = src_uv + OFF_U; \ >- uint8* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \ >+ uint8_t* src_u = src_uv + OFF_U; \ >+ uint8_t* src_v = src_uv + (PIXEL_STRIDE == 1 ? kSizeUV : OFF_V); \ > int src_stride_uv = SUBSAMPLE(kWidth, SUBSAMP_X) * PIXEL_STRIDE; \ > for (int i = 0; i < kHeight; ++i) \ > for (int j = 0; j < kWidth; ++j) \ >@@ -491,110 +494,100 @@ TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2) > > #define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN)) > >-#define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, W1280, DIFF, N, NEG, OFF, FMT_C, BPP_C) \ >- TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \ >- const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ >- const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \ >- const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \ >- const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \ >- const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \ >- align_buffer_page_end(src_y, kWidth* kHeight + OFF); \ >- align_buffer_page_end(src_u, kSizeUV + OFF); \ >- align_buffer_page_end(src_v, kSizeUV + OFF); \ >- align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \ >- align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \ >- for (int i = 0; i < kWidth * kHeight; ++i) { \ >- src_y[i + OFF] = (fastrand() & 0xff); \ >- } \ >- for (int i = 0; i < kSizeUV; ++i) { \ >- src_u[i + OFF] = (fastrand() & 0xff); \ >- src_v[i + OFF] = (fastrand() & 0xff); \ >- } \ >- memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \ >- memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \ >- MaskCpuFlags(disable_cpu_flags_); \ >- FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \ >- src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \ >- kWidth, NEG kHeight); \ >- MaskCpuFlags(benchmark_cpu_info_); \ >- for (int i = 0; i < benchmark_iterations_; ++i) { \ >- FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \ >- src_v + OFF, kStrideUV, dst_argb_opt + OFF, \ >- kStrideB, kWidth, NEG kHeight); \ >- } \ >- int max_diff = 0; \ >- /* Convert to ARGB so 565 is expanded to bytes that can be compared. */ \ >- align_buffer_page_end(dst_argb32_c, kWidth* BPP_C* kHeight); \ >- align_buffer_page_end(dst_argb32_opt, kWidth* BPP_C* kHeight); \ >- memset(dst_argb32_c, 2, kWidth* BPP_C* kHeight); \ >- memset(dst_argb32_opt, 102, kWidth* BPP_C* kHeight); \ >- FMT_B##To##FMT_C(dst_argb_c + OFF, kStrideB, dst_argb32_c, kWidth * BPP_C, \ >- kWidth, kHeight); \ >- FMT_B##To##FMT_C(dst_argb_opt + OFF, kStrideB, dst_argb32_opt, \ >- kWidth * BPP_C, kWidth, kHeight); \ >- for (int i = 0; i < kWidth * BPP_C * kHeight; ++i) { \ >- int abs_diff = abs(static_cast<int>(dst_argb32_c[i]) - \ >- static_cast<int>(dst_argb32_opt[i])); \ >- if (abs_diff > max_diff) { \ >- max_diff = abs_diff; \ >- } \ >- } \ >- EXPECT_LE(max_diff, DIFF); \ >- free_aligned_buffer_page_end(src_y); \ >- free_aligned_buffer_page_end(src_u); \ >- free_aligned_buffer_page_end(src_v); \ >- free_aligned_buffer_page_end(dst_argb_c); \ >- free_aligned_buffer_page_end(dst_argb_opt); \ >- free_aligned_buffer_page_end(dst_argb32_c); \ >- free_aligned_buffer_page_end(dst_argb32_opt); \ >+#define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, W1280, N, NEG, OFF) \ >+ TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \ >+ const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ >+ const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \ >+ const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \ >+ const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \ >+ const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \ >+ align_buffer_page_end(src_y, kWidth* kHeight + OFF); \ >+ align_buffer_page_end(src_u, kSizeUV + OFF); \ >+ align_buffer_page_end(src_v, kSizeUV + OFF); \ >+ align_buffer_page_end(dst_argb_c, kStrideB* kHeight + OFF); \ >+ align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + OFF); \ >+ for (int i = 0; i < kWidth * kHeight; ++i) { \ >+ src_y[i + OFF] = (fastrand() & 0xff); \ >+ } \ >+ for (int i = 0; i < kSizeUV; ++i) { \ >+ src_u[i + OFF] = (fastrand() & 0xff); \ >+ src_v[i + OFF] = (fastrand() & 0xff); \ >+ } \ >+ memset(dst_argb_c + OFF, 1, kStrideB * kHeight); \ >+ memset(dst_argb_opt + OFF, 101, kStrideB * kHeight); \ >+ MaskCpuFlags(disable_cpu_flags_); \ >+ double time0 = get_time(); \ >+ FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \ >+ src_v + OFF, kStrideUV, dst_argb_c + OFF, kStrideB, \ >+ kWidth, NEG kHeight); \ >+ double time1 = get_time(); \ >+ MaskCpuFlags(benchmark_cpu_info_); \ >+ for (int i = 0; i < benchmark_iterations_; ++i) { \ >+ FMT_PLANAR##To##FMT_B(src_y + OFF, kWidth, src_u + OFF, kStrideUV, \ >+ src_v + OFF, kStrideUV, dst_argb_opt + OFF, \ >+ kStrideB, kWidth, NEG kHeight); \ >+ } \ >+ double time2 = get_time(); \ >+ printf(" %8d us C - %8d us OPT\n", \ >+ static_cast<int>((time1 - time0) * 1e6), \ >+ static_cast<int>((time2 - time1) * 1e6 / benchmark_iterations_)); \ >+ for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \ >+ EXPECT_EQ(dst_argb_c[i + OFF], dst_argb_opt[i + OFF]); \ >+ } \ >+ free_aligned_buffer_page_end(src_y); \ >+ free_aligned_buffer_page_end(src_u); \ >+ free_aligned_buffer_page_end(src_v); \ >+ free_aligned_buffer_page_end(dst_argb_c); \ >+ free_aligned_buffer_page_end(dst_argb_opt); \ > } > >-#define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, DIFF, FMT_C, BPP_C) \ >- TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, FMT_C, BPP_C) \ >- TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, FMT_C, \ >- BPP_C) \ >- TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, benchmark_width_, DIFF, _Invert, -, 0, FMT_C, BPP_C) \ >- TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >- YALIGN, benchmark_width_, DIFF, _Opt, +, 0, FMT_C, BPP_C) >- >-TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1, 2, ARGB, 4) >-TESTPLANARTOB(H420, 2, 2, RAW, 3, 3, 1, 2, ARGB, 4) >-TESTPLANARTOB(H420, 2, 2, RGB24, 3, 3, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1, 9, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1, 17, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, RGB565, 2, 2, 1, 9, ARGB, 4) >-TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1, 2, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1, 1, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1, 1, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1, 0, ARGB, 4) >-TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1, 0, ARGB, 4) >-TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1, 0, ARGB, 4) >-TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1, 0, ARGB, 4) >+#define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN) \ >+ TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_ - 4, _Any, +, 0) \ >+ TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, _Unaligned, +, 1) \ >+ TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, _Invert, -, 0) \ >+ TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, _Opt, +, 0) >+ >+TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1) >+TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1) >+TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1) >+TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1) >+TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1) >+TESTPLANARTOB(I420, 2, 2, BGRA, 4, 4, 1) >+TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1) >+TESTPLANARTOB(I420, 2, 2, RGBA, 4, 4, 1) >+TESTPLANARTOB(I420, 2, 2, RAW, 3, 3, 1) >+TESTPLANARTOB(I420, 2, 2, RGB24, 3, 3, 1) >+TESTPLANARTOB(H420, 2, 2, RAW, 3, 3, 1) >+TESTPLANARTOB(H420, 2, 2, RGB24, 3, 3, 1) >+TESTPLANARTOB(I420, 2, 2, RGB565, 2, 2, 1) >+TESTPLANARTOB(I420, 2, 2, ARGB1555, 2, 2, 1) >+TESTPLANARTOB(I420, 2, 2, ARGB4444, 2, 2, 1) >+TESTPLANARTOB(I422, 2, 1, ARGB, 4, 4, 1) >+TESTPLANARTOB(I422, 2, 1, RGB565, 2, 2, 1) >+TESTPLANARTOB(J422, 2, 1, ARGB, 4, 4, 1) >+TESTPLANARTOB(J422, 2, 1, ABGR, 4, 4, 1) >+TESTPLANARTOB(H422, 2, 1, ARGB, 4, 4, 1) >+TESTPLANARTOB(H422, 2, 1, ABGR, 4, 4, 1) >+TESTPLANARTOB(I422, 2, 1, BGRA, 4, 4, 1) >+TESTPLANARTOB(I422, 2, 1, ABGR, 4, 4, 1) >+TESTPLANARTOB(I422, 2, 1, RGBA, 4, 4, 1) >+TESTPLANARTOB(I444, 1, 1, ARGB, 4, 4, 1) >+TESTPLANARTOB(J444, 1, 1, ARGB, 4, 4, 1) >+TESTPLANARTOB(I444, 1, 1, ABGR, 4, 4, 1) >+TESTPLANARTOB(I420, 2, 2, YUY2, 2, 4, 1) >+TESTPLANARTOB(I420, 2, 2, UYVY, 2, 4, 1) >+TESTPLANARTOB(I422, 2, 1, YUY2, 2, 4, 1) >+TESTPLANARTOB(I422, 2, 1, UYVY, 2, 4, 1) >+TESTPLANARTOB(I420, 2, 2, I400, 1, 1, 1) >+TESTPLANARTOB(J420, 2, 2, J400, 1, 1, 1) >+TESTPLANARTOB(I420, 2, 2, AR30, 4, 4, 1) >+TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1) > > #define TESTQPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ > YALIGN, W1280, DIFF, N, NEG, OFF, ATTEN) \ >@@ -737,6 +730,10 @@ TESTQPLANARTOB(I420Alpha, 2, 2, ABGR, 4, 4, 1, 2) > > TESTBIPLANARTOB(NV12, 2, 2, ARGB, 4, 2) > TESTBIPLANARTOB(NV21, 2, 2, ARGB, 4, 2) >+TESTBIPLANARTOB(NV12, 2, 2, ABGR, 4, 2) >+TESTBIPLANARTOB(NV21, 2, 2, ABGR, 4, 2) >+TESTBIPLANARTOB(NV12, 2, 2, RGB24, 3, 2) >+TESTBIPLANARTOB(NV21, 2, 2, RGB24, 3, 2) > TESTBIPLANARTOB(NV12, 2, 2, RGB565, 2, 9) > > #ifdef DO_THREE_PLANES >@@ -865,15 +862,8 @@ TESTBIPLANARTOB(NV12, 2, 2, RGB565, 2, 9) > benchmark_width_, DIFF, _Opt, +, 0) > > TESTATOPLANAR(ARGB, 4, 1, I420, 2, 2, 4) >-#if defined(__arm__) || defined(__aarch64__) >-// arm version subsamples by summing 4 pixels then multiplying by matrix with >-// 4x smaller coefficients which are rounded to nearest integer. >-TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 4) >-TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 4) >-#else >-TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, 0) >-TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, 0) >-#endif >+TESTATOPLANAR(ARGB, 4, 1, J420, 2, 2, ARM_YUV_ERROR) >+TESTATOPLANAR(ARGB, 4, 1, J422, 2, 1, ARM_YUV_ERROR) > TESTATOPLANAR(BGRA, 4, 1, I420, 2, 2, 4) > TESTATOPLANAR(ABGR, 4, 1, I420, 2, 2, 4) > TESTATOPLANAR(RGBA, 4, 1, I420, 2, 2, 4) >@@ -1069,6 +1059,8 @@ TESTATOB(ARGB, 4, 4, 1, RGB24, 3, 3, 1, 0) > TESTATOB(ARGB, 4, 4, 1, RGB565, 2, 2, 1, 0) > TESTATOB(ARGB, 4, 4, 1, ARGB1555, 2, 2, 1, 0) > TESTATOB(ARGB, 4, 4, 1, ARGB4444, 2, 2, 1, 0) >+TESTATOB(ABGR, 4, 4, 1, AR30, 4, 4, 1, 0) >+TESTATOB(ARGB, 4, 4, 1, AR30, 4, 4, 1, 0) > TESTATOB(ARGB, 4, 4, 1, YUY2, 2, 4, 1, 4) > TESTATOB(ARGB, 4, 4, 1, UYVY, 2, 4, 1, 4) > TESTATOB(ARGB, 4, 4, 1, I400, 1, 1, 1, 2) >@@ -1076,14 +1068,20 @@ TESTATOB(ARGB, 4, 4, 1, J400, 1, 1, 1, 2) > TESTATOB(BGRA, 4, 4, 1, ARGB, 4, 4, 1, 0) > TESTATOB(ABGR, 4, 4, 1, ARGB, 4, 4, 1, 0) > TESTATOB(RGBA, 4, 4, 1, ARGB, 4, 4, 1, 0) >+TESTATOB(AR30, 4, 4, 1, AR30, 4, 4, 1, 0) > TESTATOB(RAW, 3, 3, 1, ARGB, 4, 4, 1, 0) > TESTATOB(RAW, 3, 3, 1, RGB24, 3, 3, 1, 0) > TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0) > TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0) > TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0) > TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0) >-TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, 4) >-TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, 4) >+TESTATOB(AR30, 4, 4, 1, ARGB, 4, 4, 1, 0) >+TESTATOB(AR30, 4, 4, 1, ABGR, 4, 4, 1, 0) >+TESTATOB(AB30, 4, 4, 1, ARGB, 4, 4, 1, 0) >+TESTATOB(AB30, 4, 4, 1, ABGR, 4, 4, 1, 0) >+TESTATOB(AR30, 4, 4, 1, AB30, 4, 4, 1, 0) >+TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR) >+TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, ARM_YUV_ERROR) > TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0) > TESTATOB(I400, 1, 1, 1, ARGB, 4, 4, 1, 0) > TESTATOB(J400, 1, 1, 1, ARGB, 4, 4, 1, 0) >@@ -1240,8 +1238,8 @@ TESTSYM(BGRAToARGB, 4, 4, 1) > TESTSYM(ABGRToARGB, 4, 4, 1) > > TEST_F(LibYUVConvertTest, Test565) { >- SIMD_ALIGNED(uint8 orig_pixels[256][4]); >- SIMD_ALIGNED(uint8 pixels565[256][2]); >+ SIMD_ALIGNED(uint8_t orig_pixels[256][4]); >+ SIMD_ALIGNED(uint8_t pixels565[256][2]); > > for (int i = 0; i < 256; ++i) { > for (int j = 0; j < 4; ++j) { >@@ -1249,7 +1247,7 @@ TEST_F(LibYUVConvertTest, Test565) { > } > } > ARGBToRGB565(&orig_pixels[0][0], 0, &pixels565[0][0], 0, 256, 1); >- uint32 checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381); >+ uint32_t checksum = HashDjb2(&pixels565[0][0], sizeof(pixels565), 5381); > EXPECT_EQ(610919429u, checksum); > } > >@@ -1444,7 +1442,7 @@ TEST_F(LibYUVConvertTest, NV12Crop) { > const int sample_size = > kWidth * kHeight + kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y) * 2; > align_buffer_page_end(src_y, sample_size); >- uint8* src_uv = src_y + kWidth * kHeight; >+ uint8_t* src_uv = src_y + kWidth * kHeight; > > align_buffer_page_end(dst_y, kDestWidth * kDestHeight); > align_buffer_page_end(dst_u, SUBSAMPLE(kDestWidth, SUBSAMP_X) * >@@ -1512,13 +1510,13 @@ TEST_F(LibYUVConvertTest, NV12Crop) { > } > > TEST_F(LibYUVConvertTest, TestYToARGB) { >- uint8 y[32]; >- uint8 expectedg[32]; >+ uint8_t y[32]; >+ uint8_t expectedg[32]; > for (int i = 0; i < 32; ++i) { > y[i] = i * 5 + 17; > expectedg[i] = static_cast<int>((y[i] - 16) * 1.164f + 0.5f); > } >- uint8 argb[32 * 4]; >+ uint8_t argb[32 * 4]; > YToARGB(y, 0, argb, 0, 32, 1); > > for (int i = 0; i < 32; ++i) { >@@ -1530,7 +1528,7 @@ TEST_F(LibYUVConvertTest, TestYToARGB) { > } > } > >-static const uint8 kNoDither4x4[16] = { >+static const uint8_t kNoDither4x4[16] = { > 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, > }; > >@@ -1557,7 +1555,7 @@ TEST_F(LibYUVConvertTest, TestNoDither) { > } > > // Ordered 4x4 dither for 888 to 565. Values from 0 to 7. >-static const uint8 kDither565_4x4[16] = { >+static const uint8_t kDither565_4x4[16] = { > 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2, > }; > >@@ -1728,6 +1726,8 @@ TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4) > TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12) > TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12) > >+// Transitive tests. A to B to C is same as A to C. >+ > #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \ > W1280, N, NEG, OFF, FMT_C, BPP_C) \ > TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \ >@@ -1893,6 +1893,64 @@ TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4) > TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4) > TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4) > >+#define TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, W1280, N, NEG, \ >+ OFF, FMT_C, BPP_C) \ >+ TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_##FMT_C##N) { \ >+ const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ >+ const int kHeight = benchmark_height_; \ >+ const int kStrideA = SUBSAMPLE(kWidth, SUB_A) * BPP_A; \ >+ const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \ >+ align_buffer_page_end(src_argb_a, kStrideA* kHeight + OFF); \ >+ align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \ >+ MemRandomize(src_argb_a + OFF, kStrideA * kHeight); \ >+ memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \ >+ for (int i = 0; i < benchmark_iterations_; ++i) { \ >+ FMT_A##To##FMT_B(src_argb_a + OFF, kStrideA, dst_argb_b + OFF, kStrideB, \ >+ kWidth, NEG kHeight); \ >+ } \ >+ /* Convert to a 3rd format in 1 step and 2 steps and compare */ \ >+ const int kStrideC = kWidth * BPP_C; \ >+ align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \ >+ align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \ >+ memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \ >+ memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \ >+ FMT_A##To##FMT_C(src_argb_a + OFF, kStrideA, dst_argb_c + OFF, kStrideC, \ >+ kWidth, NEG kHeight); \ >+ /* Convert B to C */ \ >+ FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \ >+ kWidth, kHeight); \ >+ for (int i = 0; i < kStrideC * kHeight; i += 4) { \ >+ EXPECT_EQ(dst_argb_c[i + OFF + 0], dst_argb_bc[i + OFF + 0]); \ >+ EXPECT_EQ(dst_argb_c[i + OFF + 1], dst_argb_bc[i + OFF + 1]); \ >+ EXPECT_EQ(dst_argb_c[i + OFF + 2], dst_argb_bc[i + OFF + 2]); \ >+ EXPECT_NEAR(dst_argb_c[i + OFF + 3], dst_argb_bc[i + OFF + 3], 64); \ >+ } \ >+ free_aligned_buffer_page_end(src_argb_a); \ >+ free_aligned_buffer_page_end(dst_argb_b); \ >+ free_aligned_buffer_page_end(dst_argb_c); \ >+ free_aligned_buffer_page_end(dst_argb_bc); \ >+ } >+ >+#define TESTPLANETOE(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, FMT_C, BPP_C) \ >+ TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, \ >+ benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C) \ >+ TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ >+ _Unaligned, +, 1, FMT_C, BPP_C) \ >+ TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ >+ _Invert, -, 0, FMT_C, BPP_C) \ >+ TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ >+ _Opt, +, 0, FMT_C, BPP_C) >+ >+// Caveat: Destination needs to be 4 bytes >+TESTPLANETOE(ARGB, 1, 4, AR30, 1, 4, ARGB, 4) >+TESTPLANETOE(ABGR, 1, 4, AR30, 1, 4, ABGR, 4) >+TESTPLANETOE(AR30, 1, 4, ARGB, 1, 4, ABGR, 4) >+TESTPLANETOE(AR30, 1, 4, ABGR, 1, 4, ARGB, 4) >+TESTPLANETOE(ARGB, 1, 4, AB30, 1, 4, ARGB, 4) >+TESTPLANETOE(ABGR, 1, 4, AB30, 1, 4, ABGR, 4) >+TESTPLANETOE(AB30, 1, 4, ARGB, 1, 4, ABGR, 4) >+TESTPLANETOE(AB30, 1, 4, ABGR, 1, 4, ARGB, 4) >+ > TEST_F(LibYUVConvertTest, RotateWithARGBSource) { > // 2x2 frames > uint32_t src[4]; >@@ -1928,4 +1986,476 @@ TEST_F(LibYUVConvertTest, RotateWithARGBSource) { > EXPECT_EQ(dst[3], src[1]); > } > >+#ifdef HAS_ARGBTOAR30ROW_AVX2 >+TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) { >+ // ARGBToAR30Row_AVX2 expects a multiple of 8 pixels. >+ const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7; >+ align_buffer_page_end(src, kPixels * 4); >+ align_buffer_page_end(dst_opt, kPixels * 4); >+ align_buffer_page_end(dst_c, kPixels * 4); >+ MemRandomize(src, kPixels * 4); >+ memset(dst_opt, 0, kPixels * 4); >+ memset(dst_c, 1, kPixels * 4); >+ >+ ARGBToAR30Row_C(src, dst_c, kPixels); >+ >+ int has_avx2 = TestCpuFlag(kCpuHasAVX2); >+ int has_ssse3 = TestCpuFlag(kCpuHasSSSE3); >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ if (has_avx2) { >+ ARGBToAR30Row_AVX2(src, dst_opt, kPixels); >+ } else if (has_ssse3) { >+ ARGBToAR30Row_SSSE3(src, dst_opt, kPixels); >+ } else { >+ ARGBToAR30Row_C(src, dst_opt, kPixels); >+ } >+ } >+ for (int i = 0; i < kPixels * 4; ++i) { >+ EXPECT_EQ(dst_opt[i], dst_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src); >+ free_aligned_buffer_page_end(dst_opt); >+ free_aligned_buffer_page_end(dst_c); >+} >+#endif // HAS_ARGBTOAR30ROW_AVX2 >+ >+#ifdef HAS_ABGRTOAR30ROW_AVX2 >+TEST_F(LibYUVConvertTest, ABGRToAR30Row_Opt) { >+ // ABGRToAR30Row_AVX2 expects a multiple of 8 pixels. >+ const int kPixels = (benchmark_width_ * benchmark_height_ + 7) & ~7; >+ align_buffer_page_end(src, kPixels * 4); >+ align_buffer_page_end(dst_opt, kPixels * 4); >+ align_buffer_page_end(dst_c, kPixels * 4); >+ MemRandomize(src, kPixels * 4); >+ memset(dst_opt, 0, kPixels * 4); >+ memset(dst_c, 1, kPixels * 4); >+ >+ ABGRToAR30Row_C(src, dst_c, kPixels); >+ >+ int has_avx2 = TestCpuFlag(kCpuHasAVX2); >+ int has_ssse3 = TestCpuFlag(kCpuHasSSSE3); >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ if (has_avx2) { >+ ABGRToAR30Row_AVX2(src, dst_opt, kPixels); >+ } else if (has_ssse3) { >+ ABGRToAR30Row_SSSE3(src, dst_opt, kPixels); >+ } else { >+ ABGRToAR30Row_C(src, dst_opt, kPixels); >+ } >+ } >+ for (int i = 0; i < kPixels * 4; ++i) { >+ EXPECT_EQ(dst_opt[i], dst_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src); >+ free_aligned_buffer_page_end(dst_opt); >+ free_aligned_buffer_page_end(dst_c); >+} >+#endif // HAS_ABGRTOAR30ROW_AVX2 >+ >+// TODO(fbarchard): Fix clamping issue affected by U channel. >+#define TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, \ >+ ALIGN, YALIGN, W1280, DIFF, N, NEG, SOFF, DOFF) \ >+ TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##N) { \ >+ const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ >+ const int kHeight = ALIGNINT(benchmark_height_, YALIGN); \ >+ const int kStrideB = ALIGNINT(kWidth * BPP_B, ALIGN); \ >+ const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \ >+ const int kSizeUV = kStrideUV * SUBSAMPLE(kHeight, SUBSAMP_Y); \ >+ const int kBpc = 2; \ >+ align_buffer_page_end(src_y, kWidth* kHeight* kBpc + SOFF); \ >+ align_buffer_page_end(src_u, kSizeUV* kBpc + SOFF); \ >+ align_buffer_page_end(src_v, kSizeUV* kBpc + SOFF); \ >+ align_buffer_page_end(dst_argb_c, kStrideB* kHeight + DOFF); \ >+ align_buffer_page_end(dst_argb_opt, kStrideB* kHeight + DOFF); \ >+ for (int i = 0; i < kWidth * kHeight; ++i) { \ >+ reinterpret_cast<uint16_t*>(src_y + SOFF)[i] = (fastrand() & 0x3ff); \ >+ } \ >+ for (int i = 0; i < kSizeUV; ++i) { \ >+ reinterpret_cast<uint16_t*>(src_u + SOFF)[i] = (fastrand() & 0x3ff); \ >+ reinterpret_cast<uint16_t*>(src_v + SOFF)[i] = (fastrand() & 0x3ff); \ >+ } \ >+ memset(dst_argb_c + DOFF, 1, kStrideB * kHeight); \ >+ memset(dst_argb_opt + DOFF, 101, kStrideB * kHeight); \ >+ MaskCpuFlags(disable_cpu_flags_); \ >+ FMT_PLANAR##To##FMT_B( \ >+ reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth, \ >+ reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV, \ >+ reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV, \ >+ dst_argb_c + DOFF, kStrideB, kWidth, NEG kHeight); \ >+ MaskCpuFlags(benchmark_cpu_info_); \ >+ for (int i = 0; i < benchmark_iterations_; ++i) { \ >+ FMT_PLANAR##To##FMT_B( \ >+ reinterpret_cast<uint16_t*>(src_y + SOFF), kWidth, \ >+ reinterpret_cast<uint16_t*>(src_u + SOFF), kStrideUV, \ >+ reinterpret_cast<uint16_t*>(src_v + SOFF), kStrideUV, \ >+ dst_argb_opt + DOFF, kStrideB, kWidth, NEG kHeight); \ >+ } \ >+ int max_diff = 0; \ >+ for (int i = 0; i < kWidth * BPP_B * kHeight; ++i) { \ >+ int abs_diff = abs(static_cast<int>(dst_argb_c[i + DOFF]) - \ >+ static_cast<int>(dst_argb_opt[i + DOFF])); \ >+ if (abs_diff > max_diff) { \ >+ max_diff = abs_diff; \ >+ } \ >+ } \ >+ EXPECT_LE(max_diff, DIFF); \ >+ free_aligned_buffer_page_end(src_y); \ >+ free_aligned_buffer_page_end(src_u); \ >+ free_aligned_buffer_page_end(src_v); \ >+ free_aligned_buffer_page_end(dst_argb_c); \ >+ free_aligned_buffer_page_end(dst_argb_opt); \ >+ } >+ >+#define TESTPLANAR16TOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, DIFF) \ >+ TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_ - 4, DIFF, _Any, +, 0, 0) \ >+ TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, DIFF, _Unaligned, +, 1, 1) \ >+ TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, DIFF, _Invert, -, 0, 0) \ >+ TESTPLANAR16TOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \ >+ YALIGN, benchmark_width_, DIFF, _Opt, +, 0, 0) >+ >+TESTPLANAR16TOB(I010, 2, 2, ARGB, 4, 4, 1, 2) >+TESTPLANAR16TOB(I010, 2, 2, ABGR, 4, 4, 1, 2) >+TESTPLANAR16TOB(I010, 2, 2, AR30, 4, 4, 1, 2) >+TESTPLANAR16TOB(I010, 2, 2, AB30, 4, 4, 1, 2) >+TESTPLANAR16TOB(H010, 2, 2, ARGB, 4, 4, 1, 2) >+TESTPLANAR16TOB(H010, 2, 2, ABGR, 4, 4, 1, 2) >+TESTPLANAR16TOB(H010, 2, 2, AR30, 4, 4, 1, 2) >+TESTPLANAR16TOB(H010, 2, 2, AB30, 4, 4, 1, 2) >+ >+static int Clamp(int y) { >+ if (y < 0) { >+ y = 0; >+ } >+ if (y > 255) { >+ y = 255; >+ } >+ return y; >+} >+ >+static int Clamp10(int y) { >+ if (y < 0) { >+ y = 0; >+ } >+ if (y > 1023) { >+ y = 1023; >+ } >+ return y; >+} >+ >+// Test 8 bit YUV to 8 bit RGB >+TEST_F(LibYUVConvertTest, TestH420ToARGB) { >+ const int kSize = 256; >+ int histogram_b[256]; >+ int histogram_g[256]; >+ int histogram_r[256]; >+ memset(histogram_b, 0, sizeof(histogram_b)); >+ memset(histogram_g, 0, sizeof(histogram_g)); >+ memset(histogram_r, 0, sizeof(histogram_r)); >+ align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2); >+ align_buffer_page_end(argb_pixels, kSize * 4); >+ uint8_t* orig_y = orig_yuv; >+ uint8_t* orig_u = orig_y + kSize; >+ uint8_t* orig_v = orig_u + kSize / 2; >+ >+ // Test grey scale >+ for (int i = 0; i < kSize; ++i) { >+ orig_y[i] = i; >+ } >+ for (int i = 0; i < kSize / 2; ++i) { >+ orig_u[i] = 128; // 128 is 0. >+ orig_v[i] = 128; >+ } >+ >+ H420ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1); >+ >+ for (int i = 0; i < kSize; ++i) { >+ int b = argb_pixels[i * 4 + 0]; >+ int g = argb_pixels[i * 4 + 1]; >+ int r = argb_pixels[i * 4 + 2]; >+ int a = argb_pixels[i * 4 + 3]; >+ ++histogram_b[b]; >+ ++histogram_g[g]; >+ ++histogram_r[r]; >+ int expected_y = Clamp(static_cast<int>((i - 16) * 1.164f)); >+ EXPECT_NEAR(b, expected_y, 1); >+ EXPECT_NEAR(g, expected_y, 1); >+ EXPECT_NEAR(r, expected_y, 1); >+ EXPECT_EQ(a, 255); >+ } >+ >+ int count_b = 0; >+ int count_g = 0; >+ int count_r = 0; >+ for (int i = 0; i < kSize; ++i) { >+ if (histogram_b[i]) { >+ ++count_b; >+ } >+ if (histogram_g[i]) { >+ ++count_g; >+ } >+ if (histogram_r[i]) { >+ ++count_r; >+ } >+ } >+ printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); >+ >+ free_aligned_buffer_page_end(orig_yuv); >+ free_aligned_buffer_page_end(argb_pixels); >+} >+ >+// Test 10 bit YUV to 8 bit RGB >+TEST_F(LibYUVConvertTest, TestH010ToARGB) { >+ const int kSize = 1024; >+ int histogram_b[1024]; >+ int histogram_g[1024]; >+ int histogram_r[1024]; >+ memset(histogram_b, 0, sizeof(histogram_b)); >+ memset(histogram_g, 0, sizeof(histogram_g)); >+ memset(histogram_r, 0, sizeof(histogram_r)); >+ align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2); >+ align_buffer_page_end(argb_pixels, kSize * 4); >+ uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv); >+ uint16_t* orig_u = orig_y + kSize; >+ uint16_t* orig_v = orig_u + kSize / 2; >+ >+ // Test grey scale >+ for (int i = 0; i < kSize; ++i) { >+ orig_y[i] = i; >+ } >+ for (int i = 0; i < kSize / 2; ++i) { >+ orig_u[i] = 512; // 512 is 0. >+ orig_v[i] = 512; >+ } >+ >+ H010ToARGB(orig_y, 0, orig_u, 0, orig_v, 0, argb_pixels, 0, kSize, 1); >+ >+ for (int i = 0; i < kSize; ++i) { >+ int b = argb_pixels[i * 4 + 0]; >+ int g = argb_pixels[i * 4 + 1]; >+ int r = argb_pixels[i * 4 + 2]; >+ int a = argb_pixels[i * 4 + 3]; >+ ++histogram_b[b]; >+ ++histogram_g[g]; >+ ++histogram_r[r]; >+ int expected_y = Clamp(static_cast<int>((i - 64) * 1.164f / 4)); >+ EXPECT_NEAR(b, expected_y, 1); >+ EXPECT_NEAR(g, expected_y, 1); >+ EXPECT_NEAR(r, expected_y, 1); >+ EXPECT_EQ(a, 255); >+ } >+ >+ int count_b = 0; >+ int count_g = 0; >+ int count_r = 0; >+ for (int i = 0; i < kSize; ++i) { >+ if (histogram_b[i]) { >+ ++count_b; >+ } >+ if (histogram_g[i]) { >+ ++count_g; >+ } >+ if (histogram_r[i]) { >+ ++count_r; >+ } >+ } >+ printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); >+ >+ free_aligned_buffer_page_end(orig_yuv); >+ free_aligned_buffer_page_end(argb_pixels); >+} >+ >+// Test 10 bit YUV to 10 bit RGB >+// Caveat: Result is near due to float rounding in expected result. >+TEST_F(LibYUVConvertTest, TestH010ToAR30) { >+ const int kSize = 1024; >+ int histogram_b[1024]; >+ int histogram_g[1024]; >+ int histogram_r[1024]; >+ memset(histogram_b, 0, sizeof(histogram_b)); >+ memset(histogram_g, 0, sizeof(histogram_g)); >+ memset(histogram_r, 0, sizeof(histogram_r)); >+ >+ align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2); >+ align_buffer_page_end(ar30_pixels, kSize * 4); >+ uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv); >+ uint16_t* orig_u = orig_y + kSize; >+ uint16_t* orig_v = orig_u + kSize / 2; >+ >+ // Test grey scale >+ for (int i = 0; i < kSize; ++i) { >+ orig_y[i] = i; >+ } >+ for (int i = 0; i < kSize / 2; ++i) { >+ orig_u[i] = 512; // 512 is 0. >+ orig_v[i] = 512; >+ } >+ >+ H010ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1); >+ >+ for (int i = 0; i < kSize; ++i) { >+ int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023; >+ int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023; >+ int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023; >+ int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3; >+ ++histogram_b[b10]; >+ ++histogram_g[g10]; >+ ++histogram_r[r10]; >+ int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f)); >+ EXPECT_NEAR(b10, expected_y, 4); >+ EXPECT_NEAR(g10, expected_y, 4); >+ EXPECT_NEAR(r10, expected_y, 4); >+ EXPECT_EQ(a2, 3); >+ } >+ >+ int count_b = 0; >+ int count_g = 0; >+ int count_r = 0; >+ for (int i = 0; i < kSize; ++i) { >+ if (histogram_b[i]) { >+ ++count_b; >+ } >+ if (histogram_g[i]) { >+ ++count_g; >+ } >+ if (histogram_r[i]) { >+ ++count_r; >+ } >+ } >+ printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); >+ >+ free_aligned_buffer_page_end(orig_yuv); >+ free_aligned_buffer_page_end(ar30_pixels); >+} >+ >+// Test 10 bit YUV to 10 bit RGB >+// Caveat: Result is near due to float rounding in expected result. >+TEST_F(LibYUVConvertTest, TestH010ToAB30) { >+ const int kSize = 1024; >+ int histogram_b[1024]; >+ int histogram_g[1024]; >+ int histogram_r[1024]; >+ memset(histogram_b, 0, sizeof(histogram_b)); >+ memset(histogram_g, 0, sizeof(histogram_g)); >+ memset(histogram_r, 0, sizeof(histogram_r)); >+ >+ align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2); >+ align_buffer_page_end(ab30_pixels, kSize * 4); >+ uint16_t* orig_y = reinterpret_cast<uint16_t*>(orig_yuv); >+ uint16_t* orig_u = orig_y + kSize; >+ uint16_t* orig_v = orig_u + kSize / 2; >+ >+ // Test grey scale >+ for (int i = 0; i < kSize; ++i) { >+ orig_y[i] = i; >+ } >+ for (int i = 0; i < kSize / 2; ++i) { >+ orig_u[i] = 512; // 512 is 0. >+ orig_v[i] = 512; >+ } >+ >+ H010ToAB30(orig_y, 0, orig_u, 0, orig_v, 0, ab30_pixels, 0, kSize, 1); >+ >+ for (int i = 0; i < kSize; ++i) { >+ int r10 = reinterpret_cast<uint32_t*>(ab30_pixels)[i] & 1023; >+ int g10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 10) & 1023; >+ int b10 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 20) & 1023; >+ int a2 = (reinterpret_cast<uint32_t*>(ab30_pixels)[i] >> 30) & 3; >+ ++histogram_b[b10]; >+ ++histogram_g[g10]; >+ ++histogram_r[r10]; >+ int expected_y = Clamp10(static_cast<int>((i - 64) * 1.164f)); >+ EXPECT_NEAR(b10, expected_y, 4); >+ EXPECT_NEAR(g10, expected_y, 4); >+ EXPECT_NEAR(r10, expected_y, 4); >+ EXPECT_EQ(a2, 3); >+ } >+ >+ int count_b = 0; >+ int count_g = 0; >+ int count_r = 0; >+ for (int i = 0; i < kSize; ++i) { >+ if (histogram_b[i]) { >+ ++count_b; >+ } >+ if (histogram_g[i]) { >+ ++count_g; >+ } >+ if (histogram_r[i]) { >+ ++count_r; >+ } >+ } >+ printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); >+ >+ free_aligned_buffer_page_end(orig_yuv); >+ free_aligned_buffer_page_end(ab30_pixels); >+} >+ >+// Test 8 bit YUV to 10 bit RGB >+TEST_F(LibYUVConvertTest, TestH420ToAR30) { >+ const int kSize = 256; >+ const int kHistSize = 1024; >+ int histogram_b[kHistSize]; >+ int histogram_g[kHistSize]; >+ int histogram_r[kHistSize]; >+ memset(histogram_b, 0, sizeof(histogram_b)); >+ memset(histogram_g, 0, sizeof(histogram_g)); >+ memset(histogram_r, 0, sizeof(histogram_r)); >+ align_buffer_page_end(orig_yuv, kSize + kSize / 2 * 2); >+ align_buffer_page_end(ar30_pixels, kSize * 4); >+ uint8_t* orig_y = orig_yuv; >+ uint8_t* orig_u = orig_y + kSize; >+ uint8_t* orig_v = orig_u + kSize / 2; >+ >+ // Test grey scale >+ for (int i = 0; i < kSize; ++i) { >+ orig_y[i] = i; >+ } >+ for (int i = 0; i < kSize / 2; ++i) { >+ orig_u[i] = 128; // 128 is 0. >+ orig_v[i] = 128; >+ } >+ >+ H420ToAR30(orig_y, 0, orig_u, 0, orig_v, 0, ar30_pixels, 0, kSize, 1); >+ >+ for (int i = 0; i < kSize; ++i) { >+ int b10 = reinterpret_cast<uint32_t*>(ar30_pixels)[i] & 1023; >+ int g10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 10) & 1023; >+ int r10 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 20) & 1023; >+ int a2 = (reinterpret_cast<uint32_t*>(ar30_pixels)[i] >> 30) & 3; >+ ++histogram_b[b10]; >+ ++histogram_g[g10]; >+ ++histogram_r[r10]; >+ int expected_y = Clamp10(static_cast<int>((i - 16) * 1.164f * 4.f)); >+ EXPECT_NEAR(b10, expected_y, 4); >+ EXPECT_NEAR(g10, expected_y, 4); >+ EXPECT_NEAR(r10, expected_y, 4); >+ EXPECT_EQ(a2, 3); >+ } >+ >+ int count_b = 0; >+ int count_g = 0; >+ int count_r = 0; >+ for (int i = 0; i < kHistSize; ++i) { >+ if (histogram_b[i]) { >+ ++count_b; >+ } >+ if (histogram_g[i]) { >+ ++count_g; >+ } >+ if (histogram_r[i]) { >+ ++count_r; >+ } >+ } >+ printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); >+ >+ free_aligned_buffer_page_end(orig_yuv); >+ free_aligned_buffer_page_end(ar30_pixels); >+} >+ > } // namespace libyuv >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/cpu_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/cpu_test.cc >index 4e694f55ce5..a8fb4b4ac01 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/cpu_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/cpu_test.cc >@@ -65,8 +65,6 @@ TEST_F(LibYUVBaseTest, TestCpuHas) { > #if defined(__mips__) > int has_mips = TestCpuFlag(kCpuHasMIPS); > printf("Has MIPS %x\n", has_mips); >- int has_dspr2 = TestCpuFlag(kCpuHasDSPR2); >- printf("Has DSPR2 %x\n", has_dspr2); > int has_msa = TestCpuFlag(kCpuHasMSA); > printf("Has MSA %x\n", has_msa); > #endif >@@ -147,6 +145,8 @@ static int FileExists(const char* file_name) { > > TEST_F(LibYUVBaseTest, TestLinuxNeon) { > if (FileExists("../../unit_test/testdata/arm_v7.txt")) { >+ printf("Note: testing to load \"../../unit_test/testdata/arm_v7.txt\"\n"); >+ > EXPECT_EQ(0, ArmCpuCaps("../../unit_test/testdata/arm_v7.txt")); > EXPECT_EQ(kCpuHasNEON, ArmCpuCaps("../../unit_test/testdata/tegra3.txt")); > EXPECT_EQ(kCpuHasNEON, ArmCpuCaps("../../unit_test/testdata/juno.txt")); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/math_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/math_test.cc >index 2b4b57b1cea..0abbad51321 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/math_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/math_test.cc >@@ -65,8 +65,8 @@ TEST_F(LibYUVBaseTest, TestFixedDiv) { > } > EXPECT_EQ(123 * 65536, libyuv::FixedDiv(123, 1)); > >- MemRandomize(reinterpret_cast<uint8*>(&num[0]), sizeof(num)); >- MemRandomize(reinterpret_cast<uint8*>(&div[0]), sizeof(div)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&num[0]), sizeof(num)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&div[0]), sizeof(div)); > for (int j = 0; j < 1280; ++j) { > if (div[j] == 0) { > div[j] = 1280; >@@ -90,8 +90,8 @@ TEST_F(LibYUVBaseTest, TestFixedDiv_Opt) { > int result_opt[1280]; > int result_c[1280]; > >- MemRandomize(reinterpret_cast<uint8*>(&num[0]), sizeof(num)); >- MemRandomize(reinterpret_cast<uint8*>(&div[0]), sizeof(div)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&num[0]), sizeof(num)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&div[0]), sizeof(div)); > for (int j = 0; j < 1280; ++j) { > num[j] &= 4095; // Make numerator smaller. > div[j] &= 4095; // Make divisor smaller. >@@ -124,8 +124,8 @@ TEST_F(LibYUVBaseTest, TestFixedDiv1_Opt) { > int result_opt[1280]; > int result_c[1280]; > >- MemRandomize(reinterpret_cast<uint8*>(&num[0]), sizeof(num)); >- MemRandomize(reinterpret_cast<uint8*>(&div[0]), sizeof(div)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&num[0]), sizeof(num)); >+ MemRandomize(reinterpret_cast<uint8_t*>(&div[0]), sizeof(div)); > for (int j = 0; j < 1280; ++j) { > num[j] &= 4095; // Make numerator smaller. > div[j] &= 4095; // Make divisor smaller. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/planar_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/planar_test.cc >index f9e6f8abb2f..756089558f7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/planar_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/planar_test.cc >@@ -252,8 +252,8 @@ TEST_F(LibYUVPlanarTest, ARGBUnattenuate_Opt) { > } > > TEST_F(LibYUVPlanarTest, TestARGBComputeCumulativeSum) { >- SIMD_ALIGNED(uint8 orig_pixels[16][16][4]); >- SIMD_ALIGNED(int32 added_pixels[16][16][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[16][16][4]); >+ SIMD_ALIGNED(int32_t added_pixels[16][16][4]); > > for (int y = 0; y < 16; ++y) { > for (int x = 0; x < 16; ++x) { >@@ -278,7 +278,7 @@ TEST_F(LibYUVPlanarTest, TestARGBComputeCumulativeSum) { > } > > TEST_F(LibYUVPlanarTest, TestARGBGray) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > // Test blue >@@ -349,8 +349,8 @@ TEST_F(LibYUVPlanarTest, TestARGBGray) { > } > > TEST_F(LibYUVPlanarTest, TestARGBGrayTo) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 gray_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t gray_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > // Test blue >@@ -421,7 +421,7 @@ TEST_F(LibYUVPlanarTest, TestARGBGrayTo) { > } > > TEST_F(LibYUVPlanarTest, TestARGBSepia) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > // Test blue >@@ -493,12 +493,12 @@ TEST_F(LibYUVPlanarTest, TestARGBSepia) { > } > > TEST_F(LibYUVPlanarTest, TestARGBColorMatrix) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_opt[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_c[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_opt[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_c[1280][4]); > > // Matrix for Sepia. >- SIMD_ALIGNED(static const int8 kRGBToSepia[]) = { >+ SIMD_ALIGNED(static const int8_t kRGBToSepia[]) = { > 17 / 2, 68 / 2, 35 / 2, 0, 22 / 2, 88 / 2, 45 / 2, 0, > 24 / 2, 98 / 2, 50 / 2, 0, 0, 0, 0, 64, // Copy alpha. > }; >@@ -569,10 +569,10 @@ TEST_F(LibYUVPlanarTest, TestARGBColorMatrix) { > } > > TEST_F(LibYUVPlanarTest, TestRGBColorMatrix) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > > // Matrix for Sepia. >- SIMD_ALIGNED(static const int8 kRGBToSepia[]) = { >+ SIMD_ALIGNED(static const int8_t kRGBToSepia[]) = { > 17, 68, 35, 0, 22, 88, 45, 0, > 24, 98, 50, 0, 0, 0, 0, 0, // Unused but makes matrix 16 bytes. > }; >@@ -629,11 +629,11 @@ TEST_F(LibYUVPlanarTest, TestRGBColorMatrix) { > } > > TEST_F(LibYUVPlanarTest, TestARGBColorTable) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > // Matrix for Sepia. >- static const uint8 kARGBTable[256 * 4] = { >+ static const uint8_t kARGBTable[256 * 4] = { > 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, > }; > >@@ -685,11 +685,11 @@ TEST_F(LibYUVPlanarTest, TestARGBColorTable) { > > // Same as TestARGBColorTable except alpha does not change. > TEST_F(LibYUVPlanarTest, TestRGBColorTable) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > // Matrix for Sepia. >- static const uint8 kARGBTable[256 * 4] = { >+ static const uint8_t kARGBTable[256 * 4] = { > 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, 15u, 16u, > }; > >@@ -740,7 +740,7 @@ TEST_F(LibYUVPlanarTest, TestRGBColorTable) { > } > > TEST_F(LibYUVPlanarTest, TestARGBQuantize) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); > > for (int i = 0; i < 1280; ++i) { > orig_pixels[i][0] = i; >@@ -764,8 +764,8 @@ TEST_F(LibYUVPlanarTest, TestARGBQuantize) { > } > > TEST_F(LibYUVPlanarTest, TestARGBMirror) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels[1280][4]); > > for (int i = 0; i < 1280; ++i) { > orig_pixels[i][0] = i; >@@ -787,8 +787,8 @@ TEST_F(LibYUVPlanarTest, TestARGBMirror) { > } > > TEST_F(LibYUVPlanarTest, TestShade) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 shade_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t shade_pixels[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > orig_pixels[0][0] = 10u; >@@ -845,9 +845,9 @@ TEST_F(LibYUVPlanarTest, TestShade) { > } > > TEST_F(LibYUVPlanarTest, TestARGBInterpolate) { >- SIMD_ALIGNED(uint8 orig_pixels_0[1280][4]); >- SIMD_ALIGNED(uint8 orig_pixels_1[1280][4]); >- SIMD_ALIGNED(uint8 interpolate_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels_0[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels_1[1280][4]); >+ SIMD_ALIGNED(uint8_t interpolate_pixels[1280][4]); > memset(orig_pixels_0, 0, sizeof(orig_pixels_0)); > memset(orig_pixels_1, 0, sizeof(orig_pixels_1)); > >@@ -926,9 +926,9 @@ TEST_F(LibYUVPlanarTest, TestARGBInterpolate) { > } > > TEST_F(LibYUVPlanarTest, TestInterpolatePlane) { >- SIMD_ALIGNED(uint8 orig_pixels_0[1280]); >- SIMD_ALIGNED(uint8 orig_pixels_1[1280]); >- SIMD_ALIGNED(uint8 interpolate_pixels[1280]); >+ SIMD_ALIGNED(uint8_t orig_pixels_0[1280]); >+ SIMD_ALIGNED(uint8_t orig_pixels_1[1280]); >+ SIMD_ALIGNED(uint8_t interpolate_pixels[1280]); > memset(orig_pixels_0, 0, sizeof(orig_pixels_0)); > memset(orig_pixels_1, 0, sizeof(orig_pixels_1)); > >@@ -1192,7 +1192,6 @@ static void TestBlendPlane(int width, > free_aligned_buffer_page_end(src_argb_alpha); > free_aligned_buffer_page_end(dst_argb_c); > free_aligned_buffer_page_end(dst_argb_opt); >- return; > } > > TEST_F(LibYUVPlanarTest, BlendPlane_Opt) { >@@ -1286,7 +1285,6 @@ static void TestI420Blend(int width, > free_aligned_buffer_page_end(dst_y_opt); > free_aligned_buffer_page_end(dst_u_opt); > free_aligned_buffer_page_end(dst_v_opt); >- return; > } > > TEST_F(LibYUVPlanarTest, I420Blend_Opt) { >@@ -1309,8 +1307,8 @@ TEST_F(LibYUVPlanarTest, I420Blend_Invert) { > } > > TEST_F(LibYUVPlanarTest, TestAffine) { >- SIMD_ALIGNED(uint8 orig_pixels_0[1280][4]); >- SIMD_ALIGNED(uint8 interpolate_pixels_C[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels_0[1280][4]); >+ SIMD_ALIGNED(uint8_t interpolate_pixels_C[1280][4]); > > for (int i = 0; i < 1280; ++i) { > for (int j = 0; j < 4; ++j) { >@@ -1327,7 +1325,7 @@ TEST_F(LibYUVPlanarTest, TestAffine) { > EXPECT_EQ(191u, interpolate_pixels_C[255][3]); > > #if defined(HAS_ARGBAFFINEROW_SSE2) >- SIMD_ALIGNED(uint8 interpolate_pixels_Opt[1280][4]); >+ SIMD_ALIGNED(uint8_t interpolate_pixels_Opt[1280][4]); > ARGBAffineRow_SSE2(&orig_pixels_0[0][0], 0, &interpolate_pixels_Opt[0][0], > uv_step, 1280); > EXPECT_EQ(0, memcmp(interpolate_pixels_Opt, interpolate_pixels_C, 1280 * 4)); >@@ -1367,7 +1365,7 @@ TEST_F(LibYUVPlanarTest, TestCopyPlane) { > > // Fill destination buffers with random data. > for (i = 0; i < y_plane_size; ++i) { >- uint8 random_number = fastrand() & 0x7f; >+ uint8_t random_number = fastrand() & 0x7f; > dst_c[i] = random_number; > dst_opt[i] = dst_c[i]; > } >@@ -1390,8 +1388,9 @@ TEST_F(LibYUVPlanarTest, TestCopyPlane) { > } > > for (i = 0; i < y_plane_size; ++i) { >- if (dst_c[i] != dst_opt[i]) >+ if (dst_c[i] != dst_opt[i]) { > ++err; >+ } > } > > free_aligned_buffer_page_end(orig_y); >@@ -1867,12 +1866,12 @@ static int TestBlur(int width, > > MaskCpuFlags(disable_cpu_flags); > ARGBBlur(src_argb_a + off, kStride, dst_argb_c, kStride, >- reinterpret_cast<int32*>(dst_cumsum), width * 4, width, >+ reinterpret_cast<int32_t*>(dst_cumsum), width * 4, width, > invert * height, radius); > MaskCpuFlags(benchmark_cpu_info); > for (int i = 0; i < benchmark_iterations; ++i) { > ARGBBlur(src_argb_a + off, kStride, dst_argb_opt, kStride, >- reinterpret_cast<int32*>(dst_cumsum), width * 4, width, >+ reinterpret_cast<int32_t*>(dst_cumsum), width * 4, width, > invert * height, radius); > } > int max_diff = 0; >@@ -1949,9 +1948,9 @@ TEST_F(LibYUVPlanarTest, ARGBBlurSmall_Opt) { > } > > TEST_F(LibYUVPlanarTest, TestARGBPolynomial) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_opt[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_c[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_opt[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_c[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > SIMD_ALIGNED(static const float kWarmifyPolynomial[16]) = { >@@ -2046,37 +2045,38 @@ int TestHalfFloatPlane(int benchmark_width, > const int y_plane_size = benchmark_width * benchmark_height * 2; > > align_buffer_page_end(orig_y, y_plane_size * 3); >- uint8* dst_opt = orig_y + y_plane_size; >- uint8* dst_c = orig_y + y_plane_size * 2; >+ uint8_t* dst_opt = orig_y + y_plane_size; >+ uint8_t* dst_c = orig_y + y_plane_size * 2; > > MemRandomize(orig_y, y_plane_size); > memset(dst_c, 0, y_plane_size); > memset(dst_opt, 1, y_plane_size); > > for (i = 0; i < y_plane_size / 2; ++i) { >- reinterpret_cast<uint16*>(orig_y)[i] &= mask; >+ reinterpret_cast<uint16_t*>(orig_y)[i] &= mask; > } > > // Disable all optimizations. > MaskCpuFlags(disable_cpu_flags); > for (j = 0; j < benchmark_iterations; j++) { >- HalfFloatPlane(reinterpret_cast<uint16*>(orig_y), benchmark_width * 2, >- reinterpret_cast<uint16*>(dst_c), benchmark_width * 2, scale, >- benchmark_width, benchmark_height); >+ HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y), benchmark_width * 2, >+ reinterpret_cast<uint16_t*>(dst_c), benchmark_width * 2, >+ scale, benchmark_width, benchmark_height); > } > > // Enable optimizations. > MaskCpuFlags(benchmark_cpu_info); > for (j = 0; j < benchmark_iterations; j++) { >- HalfFloatPlane(reinterpret_cast<uint16*>(orig_y), benchmark_width * 2, >- reinterpret_cast<uint16*>(dst_opt), benchmark_width * 2, >+ HalfFloatPlane(reinterpret_cast<uint16_t*>(orig_y), benchmark_width * 2, >+ reinterpret_cast<uint16_t*>(dst_opt), benchmark_width * 2, > scale, benchmark_width, benchmark_height); > } > > int max_diff = 0; > for (i = 0; i < y_plane_size / 2; ++i) { >- int abs_diff = abs(static_cast<int>(reinterpret_cast<uint16*>(dst_c)[i]) - >- static_cast<int>(reinterpret_cast<uint16*>(dst_opt)[i])); >+ int abs_diff = >+ abs(static_cast<int>(reinterpret_cast<uint16_t*>(dst_c)[i]) - >+ static_cast<int>(reinterpret_cast<uint16_t*>(dst_opt)[i])); > if (abs_diff > max_diff) { > max_diff = abs_diff; > } >@@ -2168,10 +2168,56 @@ TEST_F(LibYUVPlanarTest, TestHalfFloatPlane_12bit_One) { > EXPECT_LE(diff, 1); > } > >+float TestByteToFloat(int benchmark_width, >+ int benchmark_height, >+ int benchmark_iterations, >+ int disable_cpu_flags, >+ int benchmark_cpu_info, >+ float scale) { >+ int i, j; >+ const int y_plane_size = benchmark_width * benchmark_height; >+ >+ align_buffer_page_end(orig_y, y_plane_size * (1 + 4 + 4)); >+ float* dst_opt = reinterpret_cast<float*>(orig_y + y_plane_size); >+ float* dst_c = reinterpret_cast<float*>(orig_y + y_plane_size * 5); >+ >+ MemRandomize(orig_y, y_plane_size); >+ memset(dst_c, 0, y_plane_size * 4); >+ memset(dst_opt, 1, y_plane_size * 4); >+ >+ // Disable all optimizations. >+ MaskCpuFlags(disable_cpu_flags); >+ ByteToFloat(orig_y, dst_c, scale, y_plane_size); >+ >+ // Enable optimizations. >+ MaskCpuFlags(benchmark_cpu_info); >+ for (j = 0; j < benchmark_iterations; j++) { >+ ByteToFloat(orig_y, dst_opt, scale, y_plane_size); >+ } >+ >+ float max_diff = 0; >+ for (i = 0; i < y_plane_size; ++i) { >+ float abs_diff = fabs(dst_c[i] - dst_opt[i]); >+ if (abs_diff > max_diff) { >+ max_diff = abs_diff; >+ } >+ } >+ >+ free_aligned_buffer_page_end(orig_y); >+ return max_diff; >+} >+ >+TEST_F(LibYUVPlanarTest, TestByteToFloat) { >+ float diff = TestByteToFloat(benchmark_width_, benchmark_height_, >+ benchmark_iterations_, disable_cpu_flags_, >+ benchmark_cpu_info_, 1.0f); >+ EXPECT_EQ(0.f, diff); >+} >+ > TEST_F(LibYUVPlanarTest, TestARGBLumaColorTable) { >- SIMD_ALIGNED(uint8 orig_pixels[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_opt[1280][4]); >- SIMD_ALIGNED(uint8 dst_pixels_c[1280][4]); >+ SIMD_ALIGNED(uint8_t orig_pixels[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_opt[1280][4]); >+ SIMD_ALIGNED(uint8_t dst_pixels_c[1280][4]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > > align_buffer_page_end(lumacolortable, 32768); >@@ -2343,7 +2389,7 @@ static int TestARGBRect(int width, > } > const int kStride = width * bpp; > const int kSize = kStride * height; >- const uint32 v32 = fastrand() & (bpp == 4 ? 0xffffffff : 0xff); >+ const uint32_t v32 = fastrand() & (bpp == 4 ? 0xffffffff : 0xff); > > align_buffer_page_end(dst_argb_c, kSize + off); > align_buffer_page_end(dst_argb_opt, kSize + off); >@@ -2631,21 +2677,21 @@ TEST_F(LibYUVPlanarTest, MergeUVRow_16_Opt) { > memset(dst_pixels_uv_opt, 0, kPixels * 2 * 2); > memset(dst_pixels_uv_c, 1, kPixels * 2 * 2); > >- MergeUVRow_16_C(reinterpret_cast<const uint16*>(src_pixels_u), >- reinterpret_cast<const uint16*>(src_pixels_v), >- reinterpret_cast<uint16*>(dst_pixels_uv_c), 64, kPixels); >+ MergeUVRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_u), >+ reinterpret_cast<const uint16_t*>(src_pixels_v), >+ reinterpret_cast<uint16_t*>(dst_pixels_uv_c), 64, kPixels); > > int has_avx2 = TestCpuFlag(kCpuHasAVX2); > for (int i = 0; i < benchmark_iterations_; ++i) { > if (has_avx2) { >- MergeUVRow_16_AVX2(reinterpret_cast<const uint16*>(src_pixels_u), >- reinterpret_cast<const uint16*>(src_pixels_v), >- reinterpret_cast<uint16*>(dst_pixels_uv_opt), 64, >+ MergeUVRow_16_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_u), >+ reinterpret_cast<const uint16_t*>(src_pixels_v), >+ reinterpret_cast<uint16_t*>(dst_pixels_uv_opt), 64, > kPixels); > } else { >- MergeUVRow_16_C(reinterpret_cast<const uint16*>(src_pixels_u), >- reinterpret_cast<const uint16*>(src_pixels_v), >- reinterpret_cast<uint16*>(dst_pixels_uv_opt), 64, >+ MergeUVRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_u), >+ reinterpret_cast<const uint16_t*>(src_pixels_v), >+ reinterpret_cast<uint16_t*>(dst_pixels_uv_opt), 64, > kPixels); > } > } >@@ -2661,7 +2707,7 @@ TEST_F(LibYUVPlanarTest, MergeUVRow_16_Opt) { > } > #endif > >-// TODO(fbarchard): improve test for platforms and cpu detect >+// TODO(fbarchard): Improve test for more platforms. > #ifdef HAS_MULTIPLYROW_16_AVX2 > TEST_F(LibYUVPlanarTest, MultiplyRow_16_Opt) { > const int kPixels = benchmark_width_ * benchmark_height_; >@@ -2673,18 +2719,18 @@ TEST_F(LibYUVPlanarTest, MultiplyRow_16_Opt) { > memset(dst_pixels_y_opt, 0, kPixels * 2); > memset(dst_pixels_y_c, 1, kPixels * 2); > >- MultiplyRow_16_C(reinterpret_cast<const uint16*>(src_pixels_y), >- reinterpret_cast<uint16*>(dst_pixels_y_c), 64, kPixels); >+ MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ reinterpret_cast<uint16_t*>(dst_pixels_y_c), 64, kPixels); > > int has_avx2 = TestCpuFlag(kCpuHasAVX2); > for (int i = 0; i < benchmark_iterations_; ++i) { > if (has_avx2) { >- MultiplyRow_16_AVX2(reinterpret_cast<const uint16*>(src_pixels_y), >- reinterpret_cast<uint16*>(dst_pixels_y_opt), 64, >+ MultiplyRow_16_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64, > kPixels); > } else { >- MultiplyRow_16_C(reinterpret_cast<const uint16*>(src_pixels_y), >- reinterpret_cast<uint16*>(dst_pixels_y_opt), 64, >+ MultiplyRow_16_C(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 64, > kPixels); > } > } >@@ -2697,7 +2743,160 @@ TEST_F(LibYUVPlanarTest, MultiplyRow_16_Opt) { > free_aligned_buffer_page_end(dst_pixels_y_opt); > free_aligned_buffer_page_end(dst_pixels_y_c); > } >-#endif >+#endif // HAS_MULTIPLYROW_16_AVX2 >+ >+TEST_F(LibYUVPlanarTest, Convert16To8Plane) { >+ const int kPixels = benchmark_width_ * benchmark_height_; >+ align_buffer_page_end(src_pixels_y, kPixels * 2); >+ align_buffer_page_end(dst_pixels_y_opt, kPixels); >+ align_buffer_page_end(dst_pixels_y_c, kPixels); >+ >+ MemRandomize(src_pixels_y, kPixels * 2); >+ memset(dst_pixels_y_opt, 0, kPixels); >+ memset(dst_pixels_y_c, 1, kPixels); >+ >+ MaskCpuFlags(disable_cpu_flags_); >+ Convert16To8Plane(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ benchmark_width_, dst_pixels_y_c, benchmark_width_, 16384, >+ benchmark_width_, benchmark_height_); >+ MaskCpuFlags(benchmark_cpu_info_); >+ >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ Convert16To8Plane(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ benchmark_width_, dst_pixels_y_opt, benchmark_width_, >+ 16384, benchmark_width_, benchmark_height_); >+ } >+ >+ for (int i = 0; i < kPixels; ++i) { >+ EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src_pixels_y); >+ free_aligned_buffer_page_end(dst_pixels_y_opt); >+ free_aligned_buffer_page_end(dst_pixels_y_c); >+} >+ >+// TODO(fbarchard): Improve test for more platforms. >+#ifdef HAS_CONVERT16TO8ROW_AVX2 >+TEST_F(LibYUVPlanarTest, Convert16To8Row_Opt) { >+ // AVX2 does multiple of 32, so round count up >+ const int kPixels = (benchmark_width_ * benchmark_height_ + 31) & ~31; >+ align_buffer_page_end(src_pixels_y, kPixels * 2); >+ align_buffer_page_end(dst_pixels_y_opt, kPixels); >+ align_buffer_page_end(dst_pixels_y_c, kPixels); >+ >+ MemRandomize(src_pixels_y, kPixels * 2); >+ // clamp source range to 10 bits. >+ for (int i = 0; i < kPixels; ++i) { >+ reinterpret_cast<uint16_t*>(src_pixels_y)[i] &= 1023; >+ } >+ >+ memset(dst_pixels_y_opt, 0, kPixels); >+ memset(dst_pixels_y_c, 1, kPixels); >+ >+ Convert16To8Row_C(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ dst_pixels_y_c, 16384, kPixels); >+ >+ int has_avx2 = TestCpuFlag(kCpuHasAVX2); >+ int has_ssse3 = TestCpuFlag(kCpuHasSSSE3); >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ if (has_avx2) { >+ Convert16To8Row_AVX2(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ dst_pixels_y_opt, 16384, kPixels); >+ } else if (has_ssse3) { >+ Convert16To8Row_SSSE3(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ dst_pixels_y_opt, 16384, kPixels); >+ } else { >+ Convert16To8Row_C(reinterpret_cast<const uint16_t*>(src_pixels_y), >+ dst_pixels_y_opt, 16384, kPixels); >+ } >+ } >+ >+ for (int i = 0; i < kPixels; ++i) { >+ EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src_pixels_y); >+ free_aligned_buffer_page_end(dst_pixels_y_opt); >+ free_aligned_buffer_page_end(dst_pixels_y_c); >+} >+#endif // HAS_CONVERT16TO8ROW_AVX2 >+ >+TEST_F(LibYUVPlanarTest, Convert8To16Plane) { >+ const int kPixels = benchmark_width_ * benchmark_height_; >+ align_buffer_page_end(src_pixels_y, kPixels); >+ align_buffer_page_end(dst_pixels_y_opt, kPixels * 2); >+ align_buffer_page_end(dst_pixels_y_c, kPixels * 2); >+ >+ MemRandomize(src_pixels_y, kPixels); >+ memset(dst_pixels_y_opt, 0, kPixels * 2); >+ memset(dst_pixels_y_c, 1, kPixels * 2); >+ >+ MaskCpuFlags(disable_cpu_flags_); >+ Convert8To16Plane(src_pixels_y, benchmark_width_, >+ reinterpret_cast<uint16_t*>(dst_pixels_y_c), >+ benchmark_width_, 1024, benchmark_width_, >+ benchmark_height_); >+ MaskCpuFlags(benchmark_cpu_info_); >+ >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ Convert8To16Plane(src_pixels_y, benchmark_width_, >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), >+ benchmark_width_, 1024, benchmark_width_, >+ benchmark_height_); >+ } >+ >+ for (int i = 0; i < kPixels * 2; ++i) { >+ EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src_pixels_y); >+ free_aligned_buffer_page_end(dst_pixels_y_opt); >+ free_aligned_buffer_page_end(dst_pixels_y_c); >+} >+ >+// TODO(fbarchard): Improve test for more platforms. >+#ifdef HAS_CONVERT8TO16ROW_AVX2 >+TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) { >+ const int kPixels = (benchmark_width_ * benchmark_height_ + 31) & ~31; >+ align_buffer_page_end(src_pixels_y, kPixels); >+ align_buffer_page_end(dst_pixels_y_opt, kPixels * 2); >+ align_buffer_page_end(dst_pixels_y_c, kPixels * 2); >+ >+ MemRandomize(src_pixels_y, kPixels); >+ memset(dst_pixels_y_opt, 0, kPixels * 2); >+ memset(dst_pixels_y_c, 1, kPixels * 2); >+ >+ Convert8To16Row_C(src_pixels_y, reinterpret_cast<uint16_t*>(dst_pixels_y_c), >+ 1024, kPixels); >+ >+ int has_avx2 = TestCpuFlag(kCpuHasAVX2); >+ int has_sse2 = TestCpuFlag(kCpuHasSSE2); >+ for (int i = 0; i < benchmark_iterations_; ++i) { >+ if (has_avx2) { >+ Convert8To16Row_AVX2(src_pixels_y, >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 1024, >+ kPixels); >+ } else if (has_sse2) { >+ Convert8To16Row_SSE2(src_pixels_y, >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 1024, >+ kPixels); >+ } else { >+ Convert8To16Row_C(src_pixels_y, >+ reinterpret_cast<uint16_t*>(dst_pixels_y_opt), 1024, >+ kPixels); >+ } >+ } >+ >+ for (int i = 0; i < kPixels * 2; ++i) { >+ EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]); >+ } >+ >+ free_aligned_buffer_page_end(src_pixels_y); >+ free_aligned_buffer_page_end(dst_pixels_y_opt); >+ free_aligned_buffer_page_end(dst_pixels_y_c); >+} >+#endif // HAS_CONVERT8TO16ROW_AVX2 > > float TestScaleMaxSamples(int benchmark_width, > int benchmark_height, >@@ -2709,8 +2908,8 @@ float TestScaleMaxSamples(int benchmark_width, > // NEON does multiple of 8, so round count up > const int kPixels = (benchmark_width * benchmark_height + 7) & ~7; > align_buffer_page_end(orig_y, kPixels * 4 * 3 + 48); >- uint8* dst_c = orig_y + kPixels * 4 + 16; >- uint8* dst_opt = orig_y + kPixels * 4 * 2 + 32; >+ uint8_t* dst_c = orig_y + kPixels * 4 + 16; >+ uint8_t* dst_opt = orig_y + kPixels * 4 * 2 + 32; > > // Randomize works but may contain some denormals affecting performance. > // MemRandomize(orig_y, kPixels * 4); >@@ -2777,8 +2976,8 @@ float TestScaleSumSamples(int benchmark_width, > // NEON does multiple of 8, so round count up > const int kPixels = (benchmark_width * benchmark_height + 7) & ~7; > align_buffer_page_end(orig_y, kPixels * 4 * 3); >- uint8* dst_c = orig_y + kPixels * 4; >- uint8* dst_opt = orig_y + kPixels * 4 * 2; >+ uint8_t* dst_c = orig_y + kPixels * 4; >+ uint8_t* dst_opt = orig_y + kPixels * 4 * 2; > > // Randomize works but may contain some denormals affecting performance. > // MemRandomize(orig_y, kPixels * 4); >@@ -2855,8 +3054,8 @@ float TestScaleSamples(int benchmark_width, > // NEON does multiple of 8, so round count up > const int kPixels = (benchmark_width * benchmark_height + 7) & ~7; > align_buffer_page_end(orig_y, kPixels * 4 * 3); >- uint8* dst_c = orig_y + kPixels * 4; >- uint8* dst_opt = orig_y + kPixels * 4 * 2; >+ uint8_t* dst_c = orig_y + kPixels * 4; >+ uint8_t* dst_opt = orig_y + kPixels * 4 * 2; > > // Randomize works but may contain some denormals affecting performance. > // MemRandomize(orig_y, kPixels * 4); >@@ -2918,8 +3117,8 @@ float TestCopySamples(int benchmark_width, > // NEON does multiple of 16 floats, so round count up > const int kPixels = (benchmark_width * benchmark_height + 15) & ~15; > align_buffer_page_end(orig_y, kPixels * 4 * 3); >- uint8* dst_c = orig_y + kPixels * 4; >- uint8* dst_opt = orig_y + kPixels * 4 * 2; >+ uint8_t* dst_c = orig_y + kPixels * 4; >+ uint8_t* dst_opt = orig_y + kPixels * 4 * 2; > > // Randomize works but may contain some denormals affecting performance. > // MemRandomize(orig_y, kPixels * 4); >@@ -2970,13 +3169,13 @@ TEST_F(LibYUVPlanarTest, TestCopySamples_Opt) { > EXPECT_EQ(0, diff); > } > >-extern "C" void GaussRow_NEON(const uint32* src, uint16* dst, int width); >-extern "C" void GaussRow_C(const uint32* src, uint16* dst, int width); >+extern "C" void GaussRow_NEON(const uint32_t* src, uint16_t* dst, int width); >+extern "C" void GaussRow_C(const uint32_t* src, uint16_t* dst, int width); > > TEST_F(LibYUVPlanarTest, TestGaussRow_Opt) { >- SIMD_ALIGNED(uint32 orig_pixels[640 + 4]); >- SIMD_ALIGNED(uint16 dst_pixels_c[640]); >- SIMD_ALIGNED(uint16 dst_pixels_opt[640]); >+ SIMD_ALIGNED(uint32_t orig_pixels[640 + 4]); >+ SIMD_ALIGNED(uint16_t dst_pixels_c[640]); >+ SIMD_ALIGNED(uint16_t dst_pixels_opt[640]); > > memset(orig_pixels, 0, sizeof(orig_pixels)); > memset(dst_pixels_c, 1, sizeof(dst_pixels_c)); >@@ -3004,30 +3203,30 @@ TEST_F(LibYUVPlanarTest, TestGaussRow_Opt) { > } > > EXPECT_EQ(dst_pixels_c[0], >- static_cast<uint16>(0 * 1 + 1 * 4 + 2 * 6 + 3 * 4 + 4 * 1)); >- EXPECT_EQ(dst_pixels_c[639], static_cast<uint16>(10256)); >+ static_cast<uint16_t>(0 * 1 + 1 * 4 + 2 * 6 + 3 * 4 + 4 * 1)); >+ EXPECT_EQ(dst_pixels_c[639], static_cast<uint16_t>(10256)); > } > >-extern "C" void GaussCol_NEON(const uint16* src0, >- const uint16* src1, >- const uint16* src2, >- const uint16* src3, >- const uint16* src4, >- uint32* dst, >+extern "C" void GaussCol_NEON(const uint16_t* src0, >+ const uint16_t* src1, >+ const uint16_t* src2, >+ const uint16_t* src3, >+ const uint16_t* src4, >+ uint32_t* dst, > int width); > >-extern "C" void GaussCol_C(const uint16* src0, >- const uint16* src1, >- const uint16* src2, >- const uint16* src3, >- const uint16* src4, >- uint32* dst, >+extern "C" void GaussCol_C(const uint16_t* src0, >+ const uint16_t* src1, >+ const uint16_t* src2, >+ const uint16_t* src3, >+ const uint16_t* src4, >+ uint32_t* dst, > int width); > > TEST_F(LibYUVPlanarTest, TestGaussCol_Opt) { >- SIMD_ALIGNED(uint16 orig_pixels[640 * 5]); >- SIMD_ALIGNED(uint32 dst_pixels_c[640]); >- SIMD_ALIGNED(uint32 dst_pixels_opt[640]); >+ SIMD_ALIGNED(uint16_t orig_pixels[640 * 5]); >+ SIMD_ALIGNED(uint32_t dst_pixels_c[640]); >+ SIMD_ALIGNED(uint32_t dst_pixels_opt[640]); > > memset(orig_pixels, 0, sizeof(orig_pixels)); > memset(dst_pixels_c, 1, sizeof(dst_pixels_c)); >@@ -3062,9 +3261,10 @@ TEST_F(LibYUVPlanarTest, TestGaussCol_Opt) { > EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); > } > >- EXPECT_EQ(dst_pixels_c[0], static_cast<uint32>(0 * 1 + 640 * 4 + 640 * 2 * 6 + >- 640 * 3 * 4 + 640 * 4 * 1)); >- EXPECT_EQ(dst_pixels_c[639], static_cast<uint32>(30704)); >+ EXPECT_EQ(dst_pixels_c[0], >+ static_cast<uint32_t>(0 * 1 + 640 * 4 + 640 * 2 * 6 + 640 * 3 * 4 + >+ 640 * 4 * 1)); >+ EXPECT_EQ(dst_pixels_c[639], static_cast<uint32_t>(30704)); > } > > } // namespace libyuv >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_argb_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_argb_test.cc >index d11aec20476..a1be85b8d8a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_argb_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_argb_test.cc >@@ -37,7 +37,7 @@ static int ARGBTestFilter(int src_width, > > int i, j; > const int b = 0; // 128 to test for padding/stride. >- int64 src_argb_plane_size = >+ int64_t src_argb_plane_size = > (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2) * 4LL; > int src_stride_argb = (b * 2 + Abs(src_width)) * 4; > >@@ -48,7 +48,8 @@ static int ARGBTestFilter(int src_width, > } > MemRandomize(src_argb, src_argb_plane_size); > >- int64 dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4LL; >+ int64_t dst_argb_plane_size = >+ (dst_width + b * 2) * (dst_height + b * 2) * 4LL; > int dst_stride_argb = (b * 2 + dst_width) * 4; > > align_buffer_page_end(dst_argb_c, dst_argb_plane_size); >@@ -116,11 +117,11 @@ static int ARGBTestFilter(int src_width, > static const int kTileX = 8; > static const int kTileY = 8; > >-static int TileARGBScale(const uint8* src_argb, >+static int TileARGBScale(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -157,7 +158,7 @@ static int ARGBClipTestFilter(int src_width, > } > > const int b = 128; >- int64 src_argb_plane_size = >+ int64_t src_argb_plane_size = > (Abs(src_width) + b * 2) * (Abs(src_height) + b * 2) * 4; > int src_stride_argb = (b * 2 + Abs(src_width)) * 4; > >@@ -168,7 +169,7 @@ static int ARGBClipTestFilter(int src_width, > } > memset(src_argb, 1, src_argb_plane_size); > >- int64 dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4; >+ int64_t dst_argb_plane_size = (dst_width + b * 2) * (dst_height + b * 2) * 4; > int dst_stride_argb = (b * 2 + dst_width) * 4; > > int i, j; >@@ -310,19 +311,20 @@ TEST_SCALETO(ARGBScale, 1280, 720) > #undef TEST_SCALETO > > // Scale with YUV conversion to ARGB and clipping. >+// TODO(fbarchard): Add fourcc support. All 4 ARGB formats is easy to support. > LIBYUV_API >-int YUVToARGBScaleReference2(const uint8* src_y, >+int YUVToARGBScaleReference2(const uint8_t* src_y, > int src_stride_y, >- const uint8* src_u, >+ const uint8_t* src_u, > int src_stride_u, >- const uint8* src_v, >+ const uint8_t* src_v, > int src_stride_v, >- uint32 /* src_fourcc */, // TODO: Add support. >+ uint32 /* src_fourcc */, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, >- uint32 /* dst_fourcc */, // TODO: Add support. >+ uint32 /* dst_fourcc */, > int dst_width, > int dst_height, > int clip_x, >@@ -330,7 +332,8 @@ int YUVToARGBScaleReference2(const uint8* src_y, > int clip_width, > int clip_height, > enum FilterMode filtering) { >- uint8* argb_buffer = static_cast<uint8*>(malloc(src_width * src_height * 4)); >+ uint8_t* argb_buffer = >+ static_cast<uint8_t*>(malloc(src_width * src_height * 4)); > int r; > I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, > argb_buffer, src_width * 4, src_width, src_height); >@@ -342,7 +345,12 @@ int YUVToARGBScaleReference2(const uint8* src_y, > return r; > } > >-static void FillRamp(uint8* buf, int width, int height, int v, int dx, int dy) { >+static void FillRamp(uint8_t* buf, >+ int width, >+ int height, >+ int v, >+ int dx, >+ int dy) { > int rv = v; > for (int y = 0; y < height; ++y) { > for (int x = 0; x < width; ++x) { >@@ -369,8 +377,8 @@ static int YUVToARGBTestFilter(int src_width, > int dst_height, > FilterMode f, > int benchmark_iterations) { >- int64 src_y_plane_size = Abs(src_width) * Abs(src_height); >- int64 src_uv_plane_size = >+ int64_t src_y_plane_size = Abs(src_width) * Abs(src_height); >+ int64_t src_uv_plane_size = > ((Abs(src_width) + 1) / 2) * ((Abs(src_height) + 1) / 2); > int src_stride_y = Abs(src_width); > int src_stride_uv = (Abs(src_width) + 1) / 2; >@@ -379,7 +387,7 @@ static int YUVToARGBTestFilter(int src_width, > align_buffer_page_end(src_u, src_uv_plane_size); > align_buffer_page_end(src_v, src_uv_plane_size); > >- int64 dst_argb_plane_size = (dst_width) * (dst_height)*4LL; >+ int64_t dst_argb_plane_size = (dst_width) * (dst_height)*4LL; > int dst_stride_argb = (dst_width)*4; > align_buffer_page_end(dst_argb_c, dst_argb_plane_size); > align_buffer_page_end(dst_argb_opt, dst_argb_plane_size); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_test.cc >index c39211a161b..08b6cffaa26 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/scale_test.cc >@@ -38,8 +38,8 @@ static int TestFilter(int src_width, > int src_width_uv = (Abs(src_width) + 1) >> 1; > int src_height_uv = (Abs(src_height) + 1) >> 1; > >- int64 src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); >- int64 src_uv_plane_size = (src_width_uv) * (src_height_uv); >+ int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); >+ int64_t src_uv_plane_size = (src_width_uv) * (src_height_uv); > > int src_stride_y = Abs(src_width); > int src_stride_uv = src_width_uv; >@@ -58,8 +58,8 @@ static int TestFilter(int src_width, > int dst_width_uv = (dst_width + 1) >> 1; > int dst_height_uv = (dst_height + 1) >> 1; > >- int64 dst_y_plane_size = (dst_width) * (dst_height); >- int64 dst_uv_plane_size = (dst_width_uv) * (dst_height_uv); >+ int64_t dst_y_plane_size = (dst_width) * (dst_height); >+ int64_t dst_uv_plane_size = (dst_width_uv) * (dst_height_uv); > > int dst_stride_y = dst_width; > int dst_stride_uv = dst_width_uv; >@@ -157,8 +157,8 @@ static int TestFilter_16(int src_width, > int src_width_uv = (Abs(src_width) + 1) >> 1; > int src_height_uv = (Abs(src_height) + 1) >> 1; > >- int64 src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); >- int64 src_uv_plane_size = (src_width_uv) * (src_height_uv); >+ int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); >+ int64_t src_uv_plane_size = (src_width_uv) * (src_height_uv); > > int src_stride_y = Abs(src_width); > int src_stride_uv = src_width_uv; >@@ -173,9 +173,9 @@ static int TestFilter_16(int src_width, > printf("Skipped. Alloc failed " FILELINESTR(__FILE__, __LINE__) "\n"); > return 0; > } >- uint16* p_src_y_16 = reinterpret_cast<uint16*>(src_y_16); >- uint16* p_src_u_16 = reinterpret_cast<uint16*>(src_u_16); >- uint16* p_src_v_16 = reinterpret_cast<uint16*>(src_v_16); >+ uint16_t* p_src_y_16 = reinterpret_cast<uint16_t*>(src_y_16); >+ uint16_t* p_src_u_16 = reinterpret_cast<uint16_t*>(src_u_16); >+ uint16_t* p_src_v_16 = reinterpret_cast<uint16_t*>(src_v_16); > > MemRandomize(src_y, src_y_plane_size); > MemRandomize(src_u, src_uv_plane_size); >@@ -205,9 +205,9 @@ static int TestFilter_16(int src_width, > align_buffer_page_end(dst_u_16, dst_uv_plane_size * 2); > align_buffer_page_end(dst_v_16, dst_uv_plane_size * 2); > >- uint16* p_dst_y_16 = reinterpret_cast<uint16*>(dst_y_16); >- uint16* p_dst_u_16 = reinterpret_cast<uint16*>(dst_u_16); >- uint16* p_dst_v_16 = reinterpret_cast<uint16*>(dst_v_16); >+ uint16_t* p_dst_y_16 = reinterpret_cast<uint16_t*>(dst_y_16); >+ uint16_t* p_dst_u_16 = reinterpret_cast<uint16_t*>(dst_u_16); >+ uint16_t* p_dst_v_16 = reinterpret_cast<uint16_t*>(dst_v_16); > > MaskCpuFlags(disable_cpu_flags); // Disable all CPU optimization. > I420Scale(src_y, src_stride_y, src_u, src_stride_uv, src_v, src_stride_uv, >@@ -345,9 +345,9 @@ TEST_SCALETO(Scale, 1280, 720) > > #ifdef HAS_SCALEROWDOWN2_SSSE3 > TEST_F(LibYUVScaleTest, TestScaleRowDown2Box_Odd_SSSE3) { >- SIMD_ALIGNED(uint8 orig_pixels[128 * 2]); >- SIMD_ALIGNED(uint8 dst_pixels_opt[64]); >- SIMD_ALIGNED(uint8 dst_pixels_c[64]); >+ SIMD_ALIGNED(uint8_t orig_pixels[128 * 2]); >+ SIMD_ALIGNED(uint8_t dst_pixels_opt[64]); >+ SIMD_ALIGNED(uint8_t dst_pixels_c[64]); > memset(orig_pixels, 0, sizeof(orig_pixels)); > memset(dst_pixels_opt, 0, sizeof(dst_pixels_opt)); > memset(dst_pixels_c, 0, sizeof(dst_pixels_c)); >@@ -433,19 +433,19 @@ TEST_F(LibYUVScaleTest, TestScaleRowDown2Box_Odd_SSSE3) { > } > #endif // HAS_SCALEROWDOWN2_SSSE3 > >-extern "C" void ScaleRowUp2_16_NEON(const uint16* src_ptr, >+extern "C" void ScaleRowUp2_16_NEON(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); >-extern "C" void ScaleRowUp2_16_C(const uint16* src_ptr, >+extern "C" void ScaleRowUp2_16_C(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); > > TEST_F(LibYUVScaleTest, TestScaleRowUp2_16) { >- SIMD_ALIGNED(uint16 orig_pixels[640 * 2 + 1]); // 2 rows + 1 pixel overrun. >- SIMD_ALIGNED(uint16 dst_pixels_opt[1280]); >- SIMD_ALIGNED(uint16 dst_pixels_c[1280]); >+ SIMD_ALIGNED(uint16_t orig_pixels[640 * 2 + 1]); // 2 rows + 1 pixel overrun. >+ SIMD_ALIGNED(uint16_t dst_pixels_opt[1280]); >+ SIMD_ALIGNED(uint16_t dst_pixels_c[1280]); > > memset(orig_pixels, 0, sizeof(orig_pixels)); > memset(dst_pixels_opt, 1, sizeof(dst_pixels_opt)); >@@ -475,15 +475,15 @@ TEST_F(LibYUVScaleTest, TestScaleRowUp2_16) { > EXPECT_EQ(dst_pixels_c[1279], 800); > } > >-extern "C" void ScaleRowDown2Box_16_NEON(const uint16* src_ptr, >+extern "C" void ScaleRowDown2Box_16_NEON(const uint16_t* src_ptr, > ptrdiff_t src_stride, >- uint16* dst, >+ uint16_t* dst, > int dst_width); > > TEST_F(LibYUVScaleTest, TestScaleRowDown2Box_16) { >- SIMD_ALIGNED(uint16 orig_pixels[2560 * 2]); >- SIMD_ALIGNED(uint16 dst_pixels_c[1280]); >- SIMD_ALIGNED(uint16 dst_pixels_opt[1280]); >+ SIMD_ALIGNED(uint16_t orig_pixels[2560 * 2]); >+ SIMD_ALIGNED(uint16_t dst_pixels_c[1280]); >+ SIMD_ALIGNED(uint16_t dst_pixels_opt[1280]); > > memset(orig_pixels, 0, sizeof(orig_pixels)); > memset(dst_pixels_c, 1, sizeof(dst_pixels_c)); >@@ -530,7 +530,7 @@ static int TestPlaneFilter_16(int src_width, > } > > int i; >- int64 src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); >+ int64_t src_y_plane_size = (Abs(src_width)) * (Abs(src_height)); > int src_stride_y = Abs(src_width); > int dst_y_plane_size = dst_width * dst_height; > int dst_stride_y = dst_width; >@@ -539,8 +539,8 @@ static int TestPlaneFilter_16(int src_width, > align_buffer_page_end(src_y_16, src_y_plane_size * 2); > align_buffer_page_end(dst_y_8, dst_y_plane_size); > align_buffer_page_end(dst_y_16, dst_y_plane_size * 2); >- uint16* p_src_y_16 = reinterpret_cast<uint16*>(src_y_16); >- uint16* p_dst_y_16 = reinterpret_cast<uint16*>(dst_y_16); >+ uint16_t* p_src_y_16 = reinterpret_cast<uint16_t*>(src_y_16); >+ uint16_t* p_dst_y_16 = reinterpret_cast<uint16_t*>(dst_y_16); > > MemRandomize(src_y, src_y_plane_size); > memset(dst_y_8, 0, dst_y_plane_size); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.cc >index 1ad4dece861..20aadb44e2f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.cc >@@ -19,10 +19,6 @@ > #endif > #include "libyuv/cpu_id.h" > >-// Change this to 1000 for benchmarking. >-// TODO(fbarchard): Add command line parsing to pass this as option. >-#define BENCHMARK_ITERATIONS 1 >- > unsigned int fastrand_seed = 0xfb; > > #ifdef LIBYUV_USE_GFLAGS >@@ -35,11 +31,11 @@ DEFINE_int32(libyuv_cpu_info, > "cpu flags for benchmark code. 1 = C, -1 = SIMD"); > #else > // Disable command line parameters if gflags disabled. >-static const int32 FLAGS_libyuv_width = 0; >-static const int32 FLAGS_libyuv_height = 0; >-static const int32 FLAGS_libyuv_repeat = 0; >-static const int32 FLAGS_libyuv_flags = 0; >-static const int32 FLAGS_libyuv_cpu_info = 0; >+static const int32_t FLAGS_libyuv_width = 0; >+static const int32_t FLAGS_libyuv_height = 0; >+static const int32_t FLAGS_libyuv_repeat = 0; >+static const int32_t FLAGS_libyuv_flags = 0; >+static const int32_t FLAGS_libyuv_cpu_info = 0; > #endif > > // For quicker unittests, default is 128 x 72. But when benchmarking, >@@ -47,7 +43,7 @@ static const int32 FLAGS_libyuv_cpu_info = 0; > // Set flags to -1 for benchmarking to avoid slower C code. > > LibYUVConvertTest::LibYUVConvertTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -92,12 +88,6 @@ LibYUVConvertTest::LibYUVConvertTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -107,7 +97,7 @@ LibYUVConvertTest::LibYUVConvertTest() > } > > LibYUVColorTest::LibYUVColorTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -152,12 +142,6 @@ LibYUVColorTest::LibYUVColorTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -167,7 +151,7 @@ LibYUVColorTest::LibYUVColorTest() > } > > LibYUVScaleTest::LibYUVScaleTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -212,12 +196,6 @@ LibYUVScaleTest::LibYUVScaleTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -227,7 +205,7 @@ LibYUVScaleTest::LibYUVScaleTest() > } > > LibYUVRotateTest::LibYUVRotateTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -272,12 +250,6 @@ LibYUVRotateTest::LibYUVRotateTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -287,7 +259,7 @@ LibYUVRotateTest::LibYUVRotateTest() > } > > LibYUVPlanarTest::LibYUVPlanarTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -332,12 +304,6 @@ LibYUVPlanarTest::LibYUVPlanarTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -347,7 +313,7 @@ LibYUVPlanarTest::LibYUVPlanarTest() > } > > LibYUVBaseTest::LibYUVBaseTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -392,12 +358,6 @@ LibYUVBaseTest::LibYUVBaseTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >@@ -407,7 +367,7 @@ LibYUVBaseTest::LibYUVBaseTest() > } > > LibYUVCompareTest::LibYUVCompareTest() >- : benchmark_iterations_(BENCHMARK_ITERATIONS), >+ : benchmark_iterations_(1), > benchmark_width_(128), > benchmark_height_(72), > disable_cpu_flags_(1), >@@ -452,12 +412,6 @@ LibYUVCompareTest::LibYUVCompareTest() > benchmark_cpu_info_ = FLAGS_libyuv_cpu_info; > } > libyuv::MaskCpuFlags(benchmark_cpu_info_); >- benchmark_pixels_div256_ = >- static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * >- static_cast<double>(Abs(benchmark_height_)) * >- static_cast<double>(benchmark_iterations_) + >- 255.0) / >- 256.0); > benchmark_pixels_div1280_ = > static_cast<int>((static_cast<double>(Abs(benchmark_width_)) * > static_cast<double>(Abs(benchmark_height_)) * >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.h >index 6454389d52d..87907fa1603 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/unit_test.h >@@ -69,10 +69,10 @@ static inline bool SizeValid(int src_width, > return true; > } > >-#define align_buffer_page_end(var, size) \ >- uint8* var##_mem = \ >- reinterpret_cast<uint8*>(malloc(((size) + 4095 + 63) & ~4095)); \ >- uint8* var = reinterpret_cast<uint8*>( \ >+#define align_buffer_page_end(var, size) \ >+ uint8_t* var##_mem = \ >+ reinterpret_cast<uint8_t*>(malloc(((size) + 4095 + 63) & ~4095)); \ >+ uint8_t* var = reinterpret_cast<uint8_t*>( \ > (intptr_t)(var##_mem + (((size) + 4095 + 63) & ~4095) - (size)) & ~63) > > #define free_aligned_buffer_page_end(var) \ >@@ -111,10 +111,10 @@ inline int fastrand() { > return static_cast<int>((fastrand_seed >> 16) & 0xffff); > } > >-static inline void MemRandomize(uint8* dst, int64 len) { >- int64 i; >+static inline void MemRandomize(uint8_t* dst, int64_t len) { >+ int64_t i; > for (i = 0; i < len - 1; i += 2) { >- *reinterpret_cast<uint16*>(dst) = fastrand(); >+ *reinterpret_cast<uint16_t*>(dst) = fastrand(); > dst += 2; > } > for (; i < len; ++i) { >@@ -126,10 +126,9 @@ class LibYUVColorTest : public ::testing::Test { > protected: > LibYUVColorTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -139,10 +138,9 @@ class LibYUVConvertTest : public ::testing::Test { > protected: > LibYUVConvertTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -152,10 +150,9 @@ class LibYUVScaleTest : public ::testing::Test { > protected: > LibYUVScaleTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -165,10 +162,9 @@ class LibYUVRotateTest : public ::testing::Test { > protected: > LibYUVRotateTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -178,10 +174,9 @@ class LibYUVPlanarTest : public ::testing::Test { > protected: > LibYUVPlanarTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -191,10 +186,9 @@ class LibYUVBaseTest : public ::testing::Test { > protected: > LibYUVBaseTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >@@ -204,10 +198,9 @@ class LibYUVCompareTest : public ::testing::Test { > protected: > LibYUVCompareTest(); > >- int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >- int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >- int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. >- int benchmark_pixels_div256_; // Total pixels to benchmark / 256. >+ int benchmark_iterations_; // Default 1. Use 1000 for benchmarking. >+ int benchmark_width_; // Default 1280. Use 640 for benchmarking VGA. >+ int benchmark_height_; // Default 720. Use 360 for benchmarking VGA. > int benchmark_pixels_div1280_; // Total pixels to benchmark / 1280. > int disable_cpu_flags_; // Default 1. Use -1 for benchmarking. > int benchmark_cpu_info_; // Default -1. Use 1 to disable SIMD. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/video_common_test.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/video_common_test.cc >index f16b6772f95..4d89586e76f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/video_common_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/unit_test/video_common_test.cc >@@ -18,15 +18,12 @@ namespace libyuv { > > // Tests FourCC codes in video common, which are used for ConvertToI420(). > >-static bool TestValidChar(uint32 onecc) { >- if ((onecc >= '0' && onecc <= '9') || (onecc >= 'A' && onecc <= 'Z') || >- (onecc >= 'a' && onecc <= 'z') || (onecc == ' ') || (onecc == 0xff)) { >- return true; >- } >- return false; >+static bool TestValidChar(uint32_t onecc) { >+ return (onecc >= '0' && onecc <= '9') || (onecc >= 'A' && onecc <= 'Z') || >+ (onecc >= 'a' && onecc <= 'z') || (onecc == ' ') || (onecc == 0xff); > } > >-static bool TestValidFourCC(uint32 fourcc, int bpp) { >+static bool TestValidFourCC(uint32_t fourcc, int bpp) { > if (!TestValidChar(fourcc & 0xff) || !TestValidChar((fourcc >> 8) & 0xff) || > !TestValidChar((fourcc >> 16) & 0xff) || > !TestValidChar((fourcc >> 24) & 0xff)) { >@@ -39,23 +36,23 @@ static bool TestValidFourCC(uint32 fourcc, int bpp) { > } > > TEST_F(LibYUVBaseTest, TestCanonicalFourCC) { >- EXPECT_EQ(static_cast<uint32>(FOURCC_I420), CanonicalFourCC(FOURCC_IYUV)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_I420), CanonicalFourCC(FOURCC_YU12)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_I422), CanonicalFourCC(FOURCC_YU16)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_I444), CanonicalFourCC(FOURCC_YU24)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_YUY2), CanonicalFourCC(FOURCC_YUYV)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_YUY2), CanonicalFourCC(FOURCC_YUVS)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_UYVY), CanonicalFourCC(FOURCC_HDYC)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_UYVY), CanonicalFourCC(FOURCC_2VUY)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_MJPG), CanonicalFourCC(FOURCC_JPEG)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_MJPG), CanonicalFourCC(FOURCC_DMB1)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_RAW), CanonicalFourCC(FOURCC_RGB3)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_24BG), CanonicalFourCC(FOURCC_BGR3)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_BGRA), CanonicalFourCC(FOURCC_CM32)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_RAW), CanonicalFourCC(FOURCC_CM24)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_RGBO), CanonicalFourCC(FOURCC_L555)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_RGBP), CanonicalFourCC(FOURCC_L565)); >- EXPECT_EQ(static_cast<uint32>(FOURCC_RGBO), CanonicalFourCC(FOURCC_5551)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_I420), CanonicalFourCC(FOURCC_IYUV)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_I420), CanonicalFourCC(FOURCC_YU12)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_I422), CanonicalFourCC(FOURCC_YU16)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_I444), CanonicalFourCC(FOURCC_YU24)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_YUY2), CanonicalFourCC(FOURCC_YUYV)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_YUY2), CanonicalFourCC(FOURCC_YUVS)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_UYVY), CanonicalFourCC(FOURCC_HDYC)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_UYVY), CanonicalFourCC(FOURCC_2VUY)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_MJPG), CanonicalFourCC(FOURCC_JPEG)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_MJPG), CanonicalFourCC(FOURCC_DMB1)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_RAW), CanonicalFourCC(FOURCC_RGB3)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_24BG), CanonicalFourCC(FOURCC_BGR3)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_BGRA), CanonicalFourCC(FOURCC_CM32)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_RAW), CanonicalFourCC(FOURCC_CM24)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_RGBO), CanonicalFourCC(FOURCC_L555)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_RGBP), CanonicalFourCC(FOURCC_L565)); >+ EXPECT_EQ(static_cast<uint32_t>(FOURCC_RGBO), CanonicalFourCC(FOURCC_5551)); > } > > TEST_F(LibYUVBaseTest, TestFourCC) { >@@ -73,12 +70,16 @@ TEST_F(LibYUVBaseTest, TestFourCC) { > EXPECT_TRUE(TestValidFourCC(FOURCC_ARGB, FOURCC_BPP_ARGB)); > EXPECT_TRUE(TestValidFourCC(FOURCC_BGRA, FOURCC_BPP_BGRA)); > EXPECT_TRUE(TestValidFourCC(FOURCC_ABGR, FOURCC_BPP_ABGR)); >+ EXPECT_TRUE(TestValidFourCC(FOURCC_AR30, FOURCC_BPP_AR30)); >+ EXPECT_TRUE(TestValidFourCC(FOURCC_AB30, FOURCC_BPP_AB30)); > EXPECT_TRUE(TestValidFourCC(FOURCC_24BG, FOURCC_BPP_24BG)); > EXPECT_TRUE(TestValidFourCC(FOURCC_RAW, FOURCC_BPP_RAW)); > EXPECT_TRUE(TestValidFourCC(FOURCC_RGBA, FOURCC_BPP_RGBA)); > EXPECT_TRUE(TestValidFourCC(FOURCC_RGBP, FOURCC_BPP_RGBP)); > EXPECT_TRUE(TestValidFourCC(FOURCC_RGBO, FOURCC_BPP_RGBO)); > EXPECT_TRUE(TestValidFourCC(FOURCC_R444, FOURCC_BPP_R444)); >+ EXPECT_TRUE(TestValidFourCC(FOURCC_H420, FOURCC_BPP_H420)); >+ EXPECT_TRUE(TestValidFourCC(FOURCC_H010, FOURCC_BPP_H010)); > EXPECT_TRUE(TestValidFourCC(FOURCC_MJPG, FOURCC_BPP_MJPG)); > EXPECT_TRUE(TestValidFourCC(FOURCC_YV12, FOURCC_BPP_YV12)); > EXPECT_TRUE(TestValidFourCC(FOURCC_YV16, FOURCC_BPP_YV16)); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/Makefile b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/Makefile >index 6044d2adf63..40e74b6509c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/Makefile >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/Makefile >@@ -4,3 +4,6 @@ ifeq ($(CXX),icl) > else > $(CXX) -msse2 -O3 -fopenmp -static -o psnr psnr.cc ssim.cc psnr_main.cc -Wl,--strip-all > endif >+ >+# for MacOS >+# /usr/local/bin/g++-7 -msse2 -O3 -fopenmp -Bstatic -o psnr psnr.cc ssim.cc psnr_main.cc >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/compare.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/compare.cc >index ef0beefafee..a16613ee2f9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/compare.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/compare.cc >@@ -29,22 +29,24 @@ int main(int argc, char** argv) { > FILE* fin2 = name2 ? fopen(name2, "rb") : NULL; > > const int kBlockSize = 32768; >- uint8 buf1[kBlockSize]; >- uint8 buf2[kBlockSize]; >- uint32 hash1 = 5381; >- uint32 hash2 = 5381; >- uint64 sum_square_err = 0; >- uint64 size_min = 0; >+ uint8_t buf1[kBlockSize]; >+ uint8_t buf2[kBlockSize]; >+ uint32_t hash1 = 5381; >+ uint32_t hash2 = 5381; >+ uint64_t sum_square_err = 0; >+ uint64_t size_min = 0; > int amt1 = 0; > int amt2 = 0; > do { > amt1 = static_cast<int>(fread(buf1, 1, kBlockSize, fin1)); >- if (amt1 > 0) >+ if (amt1 > 0) { > hash1 = libyuv::HashDjb2(buf1, amt1, hash1); >+ } > if (fin2) { > amt2 = static_cast<int>(fread(buf2, 1, kBlockSize, fin2)); >- if (amt2 > 0) >+ if (amt2 > 0) { > hash2 = libyuv::HashDjb2(buf2, amt2, hash2); >+ } > int amt_min = (amt1 < amt2) ? amt1 : amt2; > size_min += amt_min; > sum_square_err += libyuv::ComputeSumSquareError(buf1, buf2, amt_min); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/cpuid.c b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/cpuid.c >index 9ff618e0d28..59c65d60e0f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/cpuid.c >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/cpuid.c >@@ -69,8 +69,8 @@ int main(int argc, const char* argv[]) { > printf("Has NEON %x\n", has_neon); > } > if (has_mips) { >- int has_dspr2 = TestCpuFlag(kCpuHasDSPR2); >- printf("Has DSPR2 %x\n", has_dspr2); >+ int has_msa = TestCpuFlag(kCpuHasMSA); >+ printf("Has MSA %x\n", has_msa); > } > if (has_x86) { > int has_sse2 = TestCpuFlag(kCpuHasSSE2); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.cc >index 27f876c0b4a..f54015bab82 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.cc >@@ -21,14 +21,14 @@ > extern "C" { > #endif > >-typedef unsigned int uint32; // NOLINT >+typedef unsigned int uint32_t; // NOLINT > #ifdef _MSC_VER >-typedef unsigned __int64 uint64; >+typedef unsigned __int64 uint64_t; > #else // COMPILER_MSVC > #if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) >-typedef unsigned long uint64; // NOLINT >+typedef unsigned long uint64_t; // NOLINT > #else // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__) >-typedef unsigned long long uint64; // NOLINT >+typedef unsigned long long uint64_t; // NOLINT > #endif // __LP64__ > #endif // _MSC_VER > >@@ -38,10 +38,10 @@ typedef unsigned long long uint64; // NOLINT > #if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__) && \ > !defined(__aarch64__) > #define HAS_SUMSQUAREERROR_NEON >-static uint32 SumSquareError_NEON(const uint8* src_a, >- const uint8* src_b, >- int count) { >- volatile uint32 sse; >+static uint32_t SumSquareError_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ volatile uint32_t sse; > asm volatile( > "vmov.u8 q7, #0 \n" > "vmov.u8 q9, #0 \n" >@@ -73,10 +73,10 @@ static uint32 SumSquareError_NEON(const uint8* src_a, > } > #elif !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) > #define HAS_SUMSQUAREERROR_NEON >-static uint32 SumSquareError_NEON(const uint8* src_a, >- const uint8* src_b, >- int count) { >- volatile uint32 sse; >+static uint32_t SumSquareError_NEON(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ volatile uint32_t sse; > asm volatile( > "eor v16.16b, v16.16b, v16.16b \n" > "eor v18.16b, v18.16b, v18.16b \n" >@@ -107,9 +107,9 @@ static uint32 SumSquareError_NEON(const uint8* src_a, > } > #elif !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER) > #define HAS_SUMSQUAREERROR_SSE2 >-__declspec(naked) static uint32 SumSquareError_SSE2(const uint8* /*src_a*/, >- const uint8* /*src_b*/, >- int /*count*/) { >+__declspec(naked) static uint32_t SumSquareError_SSE2(const uint8_t* /*src_a*/, >+ const uint8_t* /*src_b*/, >+ int /*count*/) { > __asm { > mov eax, [esp + 4] // src_a > mov edx, [esp + 8] // src_b >@@ -146,10 +146,10 @@ __declspec(naked) static uint32 SumSquareError_SSE2(const uint8* /*src_a*/, > } > #elif !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__)) > #define HAS_SUMSQUAREERROR_SSE2 >-static uint32 SumSquareError_SSE2(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint32 sse; >+static uint32_t SumSquareError_SSE2(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse; > asm volatile( // NOLINT > "pxor %%xmm0,%%xmm0 \n" > "pxor %%xmm5,%%xmm5 \n" >@@ -228,22 +228,22 @@ static int CpuHasSSE2() { > } > #endif // HAS_SUMSQUAREERROR_SSE2 > >-static uint32 SumSquareError_C(const uint8* src_a, >- const uint8* src_b, >- int count) { >- uint32 sse = 0u; >+static uint32_t SumSquareError_C(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count) { >+ uint32_t sse = 0u; > for (int x = 0; x < count; ++x) { > int diff = src_a[x] - src_b[x]; >- sse += static_cast<uint32>(diff * diff); >+ sse += static_cast<uint32_t>(diff * diff); > } > return sse; > } > >-double ComputeSumSquareError(const uint8* src_a, >- const uint8* src_b, >+double ComputeSumSquareError(const uint8_t* src_a, >+ const uint8_t* src_b, > int count) { >- uint32 (*SumSquareError)(const uint8* src_a, const uint8* src_b, int count) = >- SumSquareError_C; >+ uint32_t (*SumSquareError)(const uint8_t* src_a, const uint8_t* src_b, >+ int count) = SumSquareError_C; > #if defined(HAS_SUMSQUAREERROR_NEON) > SumSquareError = SumSquareError_NEON; > #endif >@@ -253,7 +253,7 @@ double ComputeSumSquareError(const uint8* src_a, > } > #endif > const int kBlockSize = 1 << 15; >- uint64 sse = 0; >+ uint64_t sse = 0; > #ifdef _OPENMP > #pragma omp parallel for reduction(+ : sse) > #endif >@@ -280,8 +280,9 @@ double ComputeSumSquareError(const uint8* src_a, > // Returns 128.0 (kMaxPSNR) if sse is 0 (perfect match). > double ComputePSNR(double sse, double size) { > const double kMINSSE = 255.0 * 255.0 * size / pow(10.0, kMaxPSNR / 10.0); >- if (sse <= kMINSSE) >+ if (sse <= kMINSSE) { > sse = kMINSSE; // Produces max PSNR of 128 >+ } > return 10.0 * log10(255.0 * 255.0 * size / sse); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.h >index 0816b976001..aac128cbca8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr.h >@@ -20,7 +20,7 @@ extern "C" { > #endif > > #if !defined(INT_TYPES_DEFINED) && !defined(UINT8_TYPE_DEFINED) >-typedef unsigned char uint8; >+typedef unsigned char uint8_t; > #define UINT8_TYPE_DEFINED > #endif > >@@ -31,7 +31,9 @@ static const double kMaxPSNR = 128.0; > #if !defined(HAVE_JPEG) > // Computer Sum of Squared Error (SSE). > // Pass this to ComputePSNR for final result. >-double ComputeSumSquareError(const uint8* org, const uint8* rec, int size); >+double ComputeSumSquareError(const uint8_t* src_a, >+ const uint8_t* src_b, >+ int count); > #endif > > // PSNR formula: psnr = 10 * log10 (Peak Signal^2 * size / sse) >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr_main.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr_main.cc >index 4d930be4aed..a930b202ecf 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr_main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/psnr_main.cc >@@ -90,9 +90,9 @@ bool ExtractResolutionFromFilename(const char* name, > fseek(file_org, 0, SEEK_END); > size_t total_size = ftell(file_org); > fseek(file_org, 0, SEEK_SET); >- uint8* const ch_org = new uint8[total_size]; >+ uint8_t* const ch_org = new uint8_t[total_size]; > memset(ch_org, 0, total_size); >- size_t bytes_org = fread(ch_org, sizeof(uint8), total_size, file_org); >+ size_t bytes_org = fread(ch_org, sizeof(uint8_t), total_size, file_org); > fclose(file_org); > if (bytes_org == total_size) { > if (0 == libyuv::MJPGSize(ch_org, total_size, width_ptr, height_ptr)) { >@@ -107,13 +107,15 @@ bool ExtractResolutionFromFilename(const char* name, > > // Scale Y channel from 16..240 to 0..255. > // This can be useful when comparing codecs that are inconsistant about Y >-uint8 ScaleY(uint8 y) { >+uint8_t ScaleY(uint8_t y) { > int ny = (y - 16) * 256 / 224; >- if (ny < 0) >+ if (ny < 0) { > ny = 0; >- if (ny > 255) >+ } >+ if (ny > 255) { > ny = 255; >- return static_cast<uint8>(ny); >+ } >+ return static_cast<uint8_t>(ny); > } > > // MSE = Mean Square Error >@@ -150,8 +152,9 @@ void PrintHelp(const char* program) { > } > > void ParseOptions(int argc, const char* argv[]) { >- if (argc <= 1) >+ if (argc <= 1) { > PrintHelp(argv[0]); >+ } > for (int c = 1; c < argc; ++c) { > if (!strcmp(argv[c], "-v")) { > verbose = true; >@@ -237,8 +240,8 @@ void ParseOptions(int argc, const char* argv[]) { > } > } > >-bool UpdateMetrics(uint8* ch_org, >- uint8* ch_rec, >+bool UpdateMetrics(uint8_t* ch_org, >+ uint8_t* ch_rec, > const int y_size, > const int uv_size, > const size_t total_size, >@@ -247,10 +250,10 @@ bool UpdateMetrics(uint8* ch_org, > metric* distorted_frame, > bool do_psnr) { > const int uv_offset = (do_swap_uv ? uv_size : 0); >- const uint8* const u_org = ch_org + y_size + uv_offset; >- const uint8* const u_rec = ch_rec + y_size; >- const uint8* const v_org = ch_org + y_size + (uv_size - uv_offset); >- const uint8* const v_rec = ch_rec + y_size + uv_size; >+ const uint8_t* const u_org = ch_org + y_size + uv_offset; >+ const uint8_t* const u_rec = ch_rec + y_size; >+ const uint8_t* const v_org = ch_org + y_size + (uv_size - uv_offset); >+ const uint8_t* const v_rec = ch_rec + y_size + uv_size; > if (do_psnr) { > #ifdef HAVE_JPEG > double y_err = static_cast<double>( >@@ -301,12 +304,15 @@ bool UpdateMetrics(uint8* ch_org, > cur_distortion_psnr->all += distorted_frame->all; > > bool ismin = false; >- if (distorted_frame->y < cur_distortion_psnr->min_y) >+ if (distorted_frame->y < cur_distortion_psnr->min_y) { > cur_distortion_psnr->min_y = distorted_frame->y; >- if (distorted_frame->u < cur_distortion_psnr->min_u) >+ } >+ if (distorted_frame->u < cur_distortion_psnr->min_u) { > cur_distortion_psnr->min_u = distorted_frame->u; >- if (distorted_frame->v < cur_distortion_psnr->min_v) >+ } >+ if (distorted_frame->v < cur_distortion_psnr->min_v) { > cur_distortion_psnr->min_v = distorted_frame->v; >+ } > if (distorted_frame->all < cur_distortion_psnr->min_all) { > cur_distortion_psnr->min_all = distorted_frame->all; > cur_distortion_psnr->min_frame = number_of_frames; >@@ -374,8 +380,8 @@ int main(int argc, const char* argv[]) { > #endif > } > >- uint8* const ch_org = new uint8[total_size]; >- uint8* const ch_rec = new uint8[total_size]; >+ uint8_t* const ch_org = new uint8_t[total_size]; >+ uint8_t* const ch_rec = new uint8_t[total_size]; > if (ch_org == NULL || ch_rec == NULL) { > fprintf(stderr, "No memory available\n"); > fclose(file_org); >@@ -429,14 +435,15 @@ int main(int argc, const char* argv[]) { > > int number_of_frames; > for (number_of_frames = 0;; ++number_of_frames) { >- if (num_frames && number_of_frames >= num_frames) >+ if (num_frames && number_of_frames >= num_frames) { > break; >+ } > >- size_t bytes_org = fread(ch_org, sizeof(uint8), total_size, file_org); >+ size_t bytes_org = fread(ch_org, sizeof(uint8_t), total_size, file_org); > if (bytes_org < total_size) { > #ifdef HAVE_JPEG > // Try parsing file as a jpeg. >- uint8* const ch_jpeg = new uint8[bytes_org]; >+ uint8_t* const ch_jpeg = new uint8_t[bytes_org]; > memcpy(ch_jpeg, ch_org, bytes_org); > memset(ch_org, 0, total_size); > >@@ -456,11 +463,11 @@ int main(int argc, const char* argv[]) { > > for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) { > size_t bytes_rec = >- fread(ch_rec, sizeof(uint8), total_size, file_rec[cur_rec]); >+ fread(ch_rec, sizeof(uint8_t), total_size, file_rec[cur_rec]); > if (bytes_rec < total_size) { > #ifdef HAVE_JPEG > // Try parsing file as a jpeg. >- uint8* const ch_jpeg = new uint8[bytes_rec]; >+ uint8_t* const ch_jpeg = new uint8_t[bytes_rec]; > memcpy(ch_jpeg, ch_rec, bytes_rec); > memset(ch_rec, 0, total_size); > >@@ -482,7 +489,7 @@ int main(int argc, const char* argv[]) { > printf("%5d", number_of_frames); > } > if (do_psnr) { >- metric distorted_frame; >+ metric distorted_frame = {}; > metric* cur_distortion_psnr = &distortion_psnr[cur_rec]; > bool ismin = UpdateMetrics(ch_org, ch_rec, y_size, uv_size, total_size, > number_of_frames, cur_distortion_psnr, >@@ -496,7 +503,7 @@ int main(int argc, const char* argv[]) { > } > } > if (do_ssim) { >- metric distorted_frame; >+ metric distorted_frame = {}; > metric* cur_distortion_ssim = &distortion_ssim[cur_rec]; > bool ismin = UpdateMetrics(ch_org, ch_rec, y_size, uv_size, total_size, > number_of_frames, cur_distortion_ssim, >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.cc >index 43e725d8210..096fbcf0610 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.cc >@@ -16,8 +16,8 @@ > extern "C" { > #endif > >-typedef unsigned int uint32; // NOLINT >-typedef unsigned short uint16; // NOLINT >+typedef unsigned int uint32_t; // NOLINT >+typedef unsigned short uint16_t; // NOLINT > > #if !defined(LIBYUV_DISABLE_X86) && !defined(__SSE2__) && \ > (defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2))) >@@ -50,7 +50,7 @@ static const double kiW[KERNEL + 1 + 1] = { > > #if !defined(LIBYUV_DISABLE_X86) && defined(__SSE2__) > >-#define PWEIGHT(A, B) static_cast<uint16>(K[(A)] * K[(B)]) // weight product >+#define PWEIGHT(A, B) static_cast<uint16_t>(K[(A)] * K[(B)]) // weight product > #define MAKE_WEIGHT(L) \ > { \ > { \ >@@ -66,7 +66,7 @@ static const double kiW[KERNEL + 1 + 1] = { > // values. We can't call _mm_set_epi16() for static compile-time initialization. > static const struct { > union { >- uint16 i16_[8]; >+ uint16_t i16_[8]; > __m128i m_; > } values_; > } W0 = MAKE_WEIGHT(0), W1 = MAKE_WEIGHT(1), W2 = MAKE_WEIGHT(2), >@@ -88,10 +88,12 @@ static double FinalizeSSIM(double iw, > double sxx = xxm * iw - iwx * iwx; > double syy = yym * iw - iwy * iwy; > // small errors are possible, due to rounding. Clamp to zero. >- if (sxx < 0.) >+ if (sxx < 0.) { > sxx = 0.; >- if (syy < 0.) >+ } >+ if (syy < 0.) { > syy = 0.; >+ } > const double sxsy = sqrt(sxx * syy); > const double sxy = xym * iw - iwx * iwy; > static const double C11 = (0.01 * 0.01) * (255 * 255); >@@ -109,21 +111,22 @@ static double FinalizeSSIM(double iw, > // Note: worst case of accumulation is a weight of 33 = 11 + 2 * (7 + 3 + 1) > // with a diff of 255, squared. The maximum error is thus 0x4388241, > // which fits into 32 bits integers. >-double GetSSIM(const uint8* org, >- const uint8* rec, >+double GetSSIM(const uint8_t* org, >+ const uint8_t* rec, > int xo, > int yo, > int W, > int H, > int stride) { >- uint32 ws = 0, xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; >+ uint32_t ws = 0, xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; > org += (yo - KERNEL) * stride; > org += (xo - KERNEL); > rec += (yo - KERNEL) * stride; > rec += (xo - KERNEL); > for (int y_ = 0; y_ < KERNEL_SIZE; ++y_, org += stride, rec += stride) { >- if (((yo - KERNEL + y_) < 0) || ((yo - KERNEL + y_) >= H)) >+ if (((yo - KERNEL + y_) < 0) || ((yo - KERNEL + y_) >= H)) { > continue; >+ } > const int Wy = K[y_]; > for (int x_ = 0; x_ < KERNEL_SIZE; ++x_) { > const int Wxy = Wy * K[x_]; >@@ -142,13 +145,13 @@ double GetSSIM(const uint8* org, > return FinalizeSSIM(1. / ws, xm, ym, xxm, xym, yym); > } > >-double GetSSIMFullKernel(const uint8* org, >- const uint8* rec, >+double GetSSIMFullKernel(const uint8_t* org, >+ const uint8_t* rec, > int xo, > int yo, > int stride, > double area_weight) { >- uint32 xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; >+ uint32_t xm = 0, ym = 0, xxm = 0, xym = 0, yym = 0; > > #if defined(LIBYUV_DISABLE_X86) || !defined(__SSE2__) > >@@ -262,7 +265,7 @@ double GetSSIMFullKernel(const uint8* org, > > #define ADD_AND_STORE_FOUR_EPI32(M, OUT) \ > do { \ >- uint32 tmp[4]; \ >+ uint32_t tmp[4]; \ > _mm_storeu_si128(reinterpret_cast<__m128i*>(tmp), (M)); \ > (OUT) = tmp[3] + tmp[2] + tmp[1] + tmp[0]; \ > } while (0) >@@ -292,8 +295,8 @@ static int start_max(int x, int y) { > return (x > y) ? x : y; > } > >-double CalcSSIM(const uint8* org, >- const uint8* rec, >+double CalcSSIM(const uint8_t* org, >+ const uint8_t* rec, > const int image_width, > const int image_height) { > double SSIM = 0.; >@@ -328,8 +331,8 @@ double CalcSSIM(const uint8* org, > // NOTE: we could use similar method for the left-most pixels too. > const int kScratchWidth = 8; > const int kScratchStride = kScratchWidth + KERNEL + 1; >- uint8 scratch_org[KERNEL_SIZE * kScratchStride] = {0}; >- uint8 scratch_rec[KERNEL_SIZE * kScratchStride] = {0}; >+ uint8_t scratch_org[KERNEL_SIZE * kScratchStride] = {0}; >+ uint8_t scratch_rec[KERNEL_SIZE * kScratchStride] = {0}; > > for (int k = 0; k < KERNEL_SIZE; ++k) { > const int offset = >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.h b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.h >index 4647f45de14..a855f1d1233 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.h >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/ssim.h >@@ -20,12 +20,12 @@ extern "C" { > #endif > > #if !defined(INT_TYPES_DEFINED) && !defined(UINT8_TYPE_DEFINED) >-typedef unsigned char uint8; >+typedef unsigned char uint8_t; > #define UINT8_TYPE_DEFINED > #endif > >-double CalcSSIM(const uint8* org, >- const uint8* rec, >+double CalcSSIM(const uint8_t* org, >+ const uint8_t* rec, > const int image_width, > const int image_height); > >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/yuvconvert.cc b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/yuvconvert.cc >index bc01d9ff503..27cdfe9e375 100644 >--- a/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/yuvconvert.cc >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/libyuv/util/yuvconvert.cc >@@ -37,7 +37,7 @@ int num_skip_org = 0; // Number of frames to skip in original. > int num_frames = 0; // Number of frames to convert. > int filter = 1; // Bilinear filter for scaling. > >-static __inline uint32 Abs(int32 v) { >+static __inline uint32_t Abs(int32_t v) { > return v >= 0 ? v : -v; > } > >@@ -79,8 +79,9 @@ void PrintHelp(const char* program) { > } > > void ParseOptions(int argc, const char* argv[]) { >- if (argc <= 1) >+ if (argc <= 1) { > PrintHelp(argv[0]); >+ } > for (int c = 1; c < argc; ++c) { > if (!strcmp(argv[c], "-v")) { > verbose = true; >@@ -158,11 +159,11 @@ void ParseOptions(int argc, const char* argv[]) { > static const int kTileX = 32; > static const int kTileY = 32; > >-static int TileARGBScale(const uint8* src_argb, >+static int TileARGBScale(const uint8_t* src_argb, > int src_stride_argb, > int src_width, > int src_height, >- uint8* dst_argb, >+ uint8_t* dst_argb, > int dst_stride_argb, > int dst_width, > int dst_height, >@@ -242,9 +243,9 @@ int main(int argc, const char* argv[]) { > fseek(file_org, num_skip_org * total_size, SEEK_SET); > #endif > >- uint8* const ch_org = new uint8[org_size]; >- uint8* const ch_dst = new uint8[dst_size]; >- uint8* const ch_rec = new uint8[total_size]; >+ uint8_t* const ch_org = new uint8_t[org_size]; >+ uint8_t* const ch_dst = new uint8_t[dst_size]; >+ uint8_t* const ch_rec = new uint8_t[total_size]; > if (ch_org == NULL || ch_rec == NULL) { > fprintf(stderr, "No memory available\n"); > fclose(file_org); >@@ -265,14 +266,16 @@ int main(int argc, const char* argv[]) { > > int number_of_frames; > for (number_of_frames = 0;; ++number_of_frames) { >- if (num_frames && number_of_frames >= num_frames) >+ if (num_frames && number_of_frames >= num_frames) { > break; >+ } > > // Load original YUV or ARGB frame. > size_t bytes_org = >- fread(ch_org, sizeof(uint8), static_cast<size_t>(org_size), file_org); >- if (bytes_org < static_cast<size_t>(org_size)) >+ fread(ch_org, sizeof(uint8_t), static_cast<size_t>(org_size), file_org); >+ if (bytes_org < static_cast<size_t>(org_size)) { > break; >+ } > > // TODO(fbarchard): Attenuate doesnt need to know dimensions. > // ARGB attenuate frame >@@ -329,16 +332,18 @@ int main(int argc, const char* argv[]) { > // Output YUV or ARGB frame. > if (rec_is_yuv) { > size_t bytes_rec = >- fwrite(ch_rec, sizeof(uint8), static_cast<size_t>(total_size), >+ fwrite(ch_rec, sizeof(uint8_t), static_cast<size_t>(total_size), > file_rec[cur_rec]); >- if (bytes_rec < static_cast<size_t>(total_size)) >+ if (bytes_rec < static_cast<size_t>(total_size)) { > break; >+ } > } else { > size_t bytes_rec = >- fwrite(ch_dst, sizeof(uint8), static_cast<size_t>(dst_size), >+ fwrite(ch_dst, sizeof(uint8_t), static_cast<size_t>(dst_size), > file_rec[cur_rec]); >- if (bytes_rec < static_cast<size_t>(dst_size)) >+ if (bytes_rec < static_cast<size_t>(dst_size)) { > break; >+ } > } > if (verbose) { > printf("%5d", number_of_frames); >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/BUILD.gn >new file mode 100644 >index 00000000000..c669179a5f0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/BUILD.gn >@@ -0,0 +1,38 @@ >+# Copyright 2018 The Chromium Authors. All rights reserved. >+# Use of this source code is governed by a BSD-style license that can be >+# found in the LICENSE file. >+ >+import("//testing/test.gni") >+ >+group("rnnoise") { >+ deps = [ >+ ":kiss_fft", >+ ":rnn_vad", >+ ] >+} >+ >+source_set("kiss_fft") { >+ sources = [ >+ "src/kiss_fft.cc", >+ "src/kiss_fft.h", >+ ] >+} >+ >+source_set("rnn_vad") { >+ sources = [ >+ "src/rnn_activations.h", >+ "src/rnn_vad_weights.cc", >+ "src/rnn_vad_weights.h", >+ ] >+} >+ >+test("kiss_fft_unittest") { >+ sources = [ >+ "src/kiss_fft_unittest.cc", >+ ] >+ deps = [ >+ ":kiss_fft", >+ "//testing/gtest", >+ "//testing/gtest:gtest_main", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/COPYING b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/COPYING >new file mode 100644 >index 00000000000..01ea4b1a2ac >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/COPYING >@@ -0,0 +1,31 @@ >+Copyright (c) 2017, Mozilla >+Copyright (c) 2007-2017, Jean-Marc Valin >+Copyright (c) 2005-2017, Xiph.Org Foundation >+Copyright (c) 2003-2004, Mark Borgerding >+ >+Redistribution and use in source and binary forms, with or without >+modification, are permitted provided that the following conditions >+are met: >+ >+- Redistributions of source code must retain the above copyright >+notice, this list of conditions and the following disclaimer. >+ >+- Redistributions in binary form must reproduce the above copyright >+notice, this list of conditions and the following disclaimer in the >+documentation and/or other materials provided with the distribution. >+ >+- Neither the name of the Xiph.Org Foundation nor the names of its >+contributors may be used to endorse or promote products derived from >+this software without specific prior written permission. >+ >+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION >+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/DEPS b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/DEPS >new file mode 100644 >index 00000000000..fca61fcf64b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/DEPS >@@ -0,0 +1,3 @@ >+include_rules = [ >+ "+testing/gtest/include/gtest", >+] >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/OWNERS b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/OWNERS >new file mode 100644 >index 00000000000..b3f35ec172b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/OWNERS >@@ -0,0 +1,2 @@ >+alessiob@chromium.org >+aleloi@chromium.org >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/README.chromium b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/README.chromium >new file mode 100644 >index 00000000000..8efe059ca6b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/README.chromium >@@ -0,0 +1,28 @@ >+Name: Recurrent neural network for audio noise reduction >+Short Name: rnnoise >+URL: https://github.com/xiph/rnnoise >+Version: 91ef401 >+Date: Oct 10, 2017 >+Revision: >+License: BSD 3-Clause >+License File: COPYING >+Security Critical: no >+License Android Compatible: >+ >+Description: >+RNNoise is a noise suppression library based on a recurrent neural network. >+The library is used for speech processing in WebRTC. >+ >+Local Modifications: >+* Only retaining COPYING and from src/ the following files: >+ - kiss_fft.c, kiss_fft.h >+ - rnn.c >+ - rnn_data.c >+ - tansig_table.h >+* KissFFT: non-floating point parts removed, code clean, from C to C++, >+ class wrapper added >+* BUILD targets and KissFFT unit tests added >+* rnn_vad_weights.h: output layer sizes + weights scaling factor >+* removing unwanted extern from constants in rnn_vad_weights.h and using >+ constants to declare array sizes >+* Add braces around arrays in unit test. >\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.cc b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.cc >new file mode 100644 >index 00000000000..27b4900b918 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.cc >@@ -0,0 +1,443 @@ >+/*Copyright (c) 2003-2004, Mark Borgerding >+ Lots of modifications by Jean-Marc Valin >+ Copyright (c) 2005-2007, Xiph.Org Foundation >+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO >+ Copyright (c) 2018, The WebRTC project authors >+ >+ All rights reserved. >+ >+ Redistribution and use in source and binary forms, with or without >+ modification, are permitted provided that the following conditions are met: >+ >+ * Redistributions of source code must retain the above copyright notice, >+ this list of conditions and the following disclaimer. >+ * Redistributions in binary form must reproduce the above copyright notice, >+ this list of conditions and the following disclaimer in the >+ documentation and/or other materials provided with the distribution. >+ >+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" >+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE >+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >+ POSSIBILITY OF SUCH DAMAGE.*/ >+ >+#include "third_party/rnnoise/src/kiss_fft.h" >+ >+#include <cassert> >+#include <cmath> >+#include <utility> >+ >+namespace rnnoise { >+namespace { >+ >+void kf_bfly2(std::complex<float>* Fout, int m, int N) { >+ if (m == 1) { >+ for (int i = 0; i < N; i++) { >+ const std::complex<float> t = Fout[1]; >+ Fout[1] = Fout[0] - t; >+ Fout[0] += t; >+ Fout += 2; >+ } >+ } else { >+ constexpr float tw = 0.7071067812f; >+ // We know that m==4 here because the radix-2 is just after a radix-4. >+ assert(m == 4); >+ for (int i = 0; i < N; i++) { >+ std::complex<float>* Fout2 = Fout + 4; >+ std::complex<float> t = Fout2[0]; >+ >+ *Fout2 = Fout[0] - t; >+ Fout[0] += t; >+ >+ t.real((Fout2[1].real() + Fout2[1].imag()) * tw); >+ t.imag((Fout2[1].imag() - Fout2[1].real()) * tw); >+ Fout2[1] = Fout[1] - t; >+ Fout[1] += t; >+ >+ t.real(Fout2[2].imag()); >+ t.imag(-Fout2[2].real()); >+ Fout2[2] = Fout[2] - t; >+ Fout[2] += t; >+ >+ t.real((Fout2[3].imag() - Fout2[3].real()) * tw); >+ t.imag(-(Fout2[3].imag() + Fout2[3].real()) * tw); >+ Fout2[3] = Fout[3] - t; >+ Fout[3] += t; >+ Fout += 8; >+ } >+ } >+} >+ >+void kf_bfly4(std::complex<float>* Fout, >+ const size_t fstride, >+ const KissFft::KissFftState* st, >+ int m, >+ int N, >+ int mm) { >+ assert(Fout); >+ assert(st); >+ if (m == 1) { >+ // Degenerate case where all the twiddles are 1. >+ for (int i = 0; i < N; i++) { >+ std::complex<float> scratch0 = Fout[0] - Fout[2]; >+ Fout[0] += Fout[2]; >+ std::complex<float> scratch1 = Fout[1] + Fout[3]; >+ Fout[2] = Fout[0] - scratch1; >+ Fout[0] += scratch1; >+ scratch1 = Fout[1] - Fout[3]; >+ >+ Fout[1].real(scratch0.real() + scratch1.imag()); >+ Fout[1].imag(scratch0.imag() - scratch1.real()); >+ Fout[3].real(scratch0.real() - scratch1.imag()); >+ Fout[3].imag(scratch0.imag() + scratch1.real()); >+ Fout += 4; >+ } >+ } else { >+ std::complex<float> scratch[6]; >+ const int m2 = 2 * m; >+ const int m3 = 3 * m; >+ std::complex<float>* Fout_beg = Fout; >+ for (int i = 0; i < N; i++) { >+ Fout = Fout_beg + i * mm; >+ const std::complex<float>* tw1; >+ const std::complex<float>* tw2; >+ const std::complex<float>* tw3; >+ tw3 = tw2 = tw1 = &st->twiddles[0]; >+ assert(m % 4 == 0); // |m| is guaranteed to be a multiple of 4. >+ for (int j = 0; j < m; j++) { >+ scratch[0] = Fout[m] * *tw1; >+ scratch[1] = Fout[m2] * *tw2; >+ scratch[2] = Fout[m3] * *tw3; >+ >+ scratch[5] = Fout[0] - scratch[1]; >+ Fout[0] += scratch[1]; >+ scratch[3] = scratch[0] + scratch[2]; >+ scratch[4] = scratch[0] - scratch[2]; >+ Fout[m2] = Fout[0] - scratch[3]; >+ >+ tw1 += fstride; >+ tw2 += fstride * 2; >+ tw3 += fstride * 3; >+ Fout[0] += scratch[3]; >+ >+ Fout[m].real(scratch[5].real() + scratch[4].imag()); >+ Fout[m].imag(scratch[5].imag() - scratch[4].real()); >+ Fout[m3].real(scratch[5].real() - scratch[4].imag()); >+ Fout[m3].imag(scratch[5].imag() + scratch[4].real()); >+ ++Fout; >+ } >+ } >+ } >+} >+ >+void kf_bfly3(std::complex<float>* Fout, >+ const size_t fstride, >+ const KissFft::KissFftState* st, >+ int m, >+ int N, >+ int mm) { >+ assert(Fout); >+ assert(st); >+ const size_t m2 = 2 * m; >+ const std::complex<float>*tw1, *tw2; >+ std::complex<float> scratch[5]; >+ std::complex<float> epi3; >+ >+ std::complex<float>* Fout_beg = Fout; >+ epi3 = st->twiddles[fstride * m]; >+ for (int i = 0; i < N; i++) { >+ Fout = Fout_beg + i * mm; >+ tw1 = tw2 = &st->twiddles[0]; >+ size_t k = m; >+ do { >+ scratch[1] = Fout[m] * *tw1; >+ scratch[2] = Fout[m2] * *tw2; >+ >+ scratch[3] = scratch[1] + scratch[2]; >+ scratch[0] = scratch[1] - scratch[2]; >+ tw1 += fstride; >+ tw2 += fstride * 2; >+ >+ Fout[m] = Fout[0] - 0.5f * scratch[3]; >+ >+ scratch[0] *= epi3.imag(); >+ >+ Fout[0] += scratch[3]; >+ >+ Fout[m2].real(Fout[m].real() + scratch[0].imag()); >+ Fout[m2].imag(Fout[m].imag() - scratch[0].real()); >+ >+ Fout[m].real(Fout[m].real() - scratch[0].imag()); >+ Fout[m].imag(Fout[m].imag() + scratch[0].real()); >+ >+ ++Fout; >+ } while (--k); >+ } >+} >+ >+void kf_bfly5(std::complex<float>* Fout, >+ const size_t fstride, >+ const KissFft::KissFftState* st, >+ int m, >+ int N, >+ int mm) { >+ assert(Fout); >+ assert(st); >+ std::complex<float> scratch[13]; >+ const std::complex<float>* tw; >+ std::complex<float> ya, yb; >+ std::complex<float>* const Fout_beg = Fout; >+ >+ ya = st->twiddles[fstride * m]; >+ yb = st->twiddles[fstride * 2 * m]; >+ tw = &st->twiddles[0]; >+ >+ for (int i = 0; i < N; i++) { >+ Fout = Fout_beg + i * mm; >+ std::complex<float>* Fout0 = Fout; >+ std::complex<float>* Fout1 = Fout0 + m; >+ std::complex<float>* Fout2 = Fout0 + 2 * m; >+ std::complex<float>* Fout3 = Fout0 + 3 * m; >+ std::complex<float>* Fout4 = Fout0 + 4 * m; >+ >+ // For non-custom modes, m is guaranteed to be a multiple of 4. >+ for (int u = 0; u < m; ++u) { >+ scratch[0] = *Fout0; >+ >+ scratch[1] = *Fout1 * tw[u * fstride]; >+ scratch[2] = *Fout2 * tw[2 * u * fstride]; >+ scratch[3] = *Fout3 * tw[3 * u * fstride]; >+ scratch[4] = *Fout4 * tw[4 * u * fstride]; >+ >+ scratch[7] = scratch[1] + scratch[4]; >+ scratch[10] = scratch[1] - scratch[4]; >+ scratch[8] = scratch[2] + scratch[3]; >+ scratch[9] = scratch[2] - scratch[3]; >+ >+ Fout0->real(Fout0->real() + scratch[7].real() + scratch[8].real()); >+ Fout0->imag(Fout0->imag() + scratch[7].imag() + scratch[8].imag()); >+ >+ scratch[5].real(scratch[0].real() + scratch[7].real() * ya.real() + >+ scratch[8].real() * yb.real()); >+ scratch[5].imag(scratch[0].imag() + scratch[7].imag() * ya.real() + >+ scratch[8].imag() * yb.real()); >+ >+ scratch[6].real(scratch[10].imag() * ya.imag() + >+ scratch[9].imag() * yb.imag()); >+ scratch[6].imag( >+ -(scratch[10].real() * ya.imag() + scratch[9].real() * yb.imag())); >+ >+ *Fout1 = scratch[5] - scratch[6]; >+ *Fout4 = scratch[5] + scratch[6]; >+ >+ scratch[11].real(scratch[0].real() + scratch[7].real() * yb.real() + >+ scratch[8].real() * ya.real()); >+ scratch[11].imag(scratch[0].imag() + scratch[7].imag() * yb.real() + >+ scratch[8].imag() * ya.real()); >+ scratch[12].real(scratch[9].imag() * ya.imag() - >+ scratch[10].imag() * yb.imag()); >+ scratch[12].imag(scratch[10].real() * yb.imag() - >+ scratch[9].real() * ya.imag()); >+ >+ *Fout2 = scratch[11] + scratch[12]; >+ *Fout3 = scratch[11] - scratch[12]; >+ >+ ++Fout0; >+ ++Fout1; >+ ++Fout2; >+ ++Fout3; >+ ++Fout4; >+ } >+ } >+} >+ >+void compute_bitrev_table(int base_index, >+ const size_t stride, >+ const int16_t* factors, >+ const KissFft::KissFftState* st, >+ const int16_t* bitrev_table_last, >+ int16_t* bitrev_table) { >+ const int p = *factors++; // The radix. >+ const int m = *factors++; // Stage's fft length/p. >+ if (m == 1) { >+ for (int j = 0; j < p; j++) { >+ assert(bitrev_table <= bitrev_table_last); >+ *bitrev_table = base_index + j; >+ bitrev_table += stride; >+ } >+ } else { >+ for (int j = 0; j < p; j++) { >+ compute_bitrev_table(base_index, stride * p, factors, st, >+ bitrev_table_last, bitrev_table); >+ bitrev_table += stride; >+ base_index += m; >+ } >+ } >+} >+ >+// Populates |facbuf| with p1, m1, p2, m2, ... where p[i] * m[i] = m[i-1] and >+// m0 = n. >+bool kf_factor(int n, int16_t* facbuf) { >+ assert(facbuf); >+ int p = 4; >+ int stages = 0; >+ int nbak = n; >+ >+ // Factor out powers of 4, powers of 2, then any remaining primes. >+ do { >+ while (n % p) { >+ switch (p) { >+ case 4: >+ p = 2; >+ break; >+ case 2: >+ p = 3; >+ break; >+ default: >+ p += 2; >+ break; >+ } >+ if (p > 32000 || p * p > n) >+ p = n; // No more factors, skip to end. >+ } >+ n /= p; >+ if (p > 5) >+ return false; >+ facbuf[2 * stages] = p; >+ if (p == 2 && stages > 1) { >+ facbuf[2 * stages] = 4; >+ facbuf[2] = 2; >+ } >+ stages++; >+ } while (n > 1); >+ n = nbak; >+ // Reverse the order to get the radix 4 at the end, so we can use the >+ // fast degenerate case. It turns out that reversing the order also >+ // improves the noise behavior. >+ for (int i = 0; i < stages / 2; i++) >+ std::swap(facbuf[2 * i], facbuf[2 * (stages - i - 1)]); >+ for (int i = 0; i < stages; i++) { >+ n /= facbuf[2 * i]; >+ facbuf[2 * i + 1] = n; >+ } >+ return true; >+} >+ >+void compute_twiddles(const int nfft, std::complex<float>* twiddles) { >+ constexpr double pi = 3.14159265358979323846264338327; >+ assert(twiddles); >+ for (int i = 0; i < nfft; ++i) { >+ const double phase = (-2 * pi / nfft) * i; >+ twiddles[i].real(std::cos(phase)); >+ twiddles[i].imag(std::sin(phase)); >+ } >+} >+ >+void fft_impl(const KissFft::KissFftState* st, std::complex<float>* fout) { >+ assert(st); >+ assert(fout); >+ int m2, m; >+ int p; >+ int L; >+ int fstride[KissFft::kMaxFactors]; >+ >+ fstride[0] = 1; >+ L = 0; >+ do { >+ p = st->factors[2 * L]; >+ m = st->factors[2 * L + 1]; >+ assert(static_cast<size_t>(L + 1) < KissFft::kMaxFactors); >+ fstride[L + 1] = fstride[L] * p; >+ L++; >+ } while (m != 1); >+ m = st->factors[2 * L - 1]; >+ for (int i = L - 1; i >= 0; i--) { >+ if (i != 0) >+ m2 = st->factors[2 * i - 1]; >+ else >+ m2 = 1; >+ switch (st->factors[2 * i]) { >+ case 2: >+ kf_bfly2(fout, m, fstride[i]); >+ break; >+ case 4: >+ kf_bfly4(fout, fstride[i], st, m, fstride[i], m2); >+ break; >+ case 3: >+ kf_bfly3(fout, fstride[i], st, m, fstride[i], m2); >+ break; >+ case 5: >+ kf_bfly5(fout, fstride[i], st, m, fstride[i], m2); >+ break; >+ default: >+ assert(0); >+ break; >+ } >+ m = m2; >+ } >+} >+ >+} // namespace >+ >+KissFft::KissFftState::KissFftState(int num_fft_points) >+ : nfft(num_fft_points), scale(1.f / nfft) { >+ // Factorize |nfft|. >+ // TODO(alessiob): Handle kf_factor fails (invalid nfft). >+ if (!kf_factor(nfft, factors.data())) >+ assert(0); >+ // Twiddles. >+ twiddles.resize(nfft); >+ compute_twiddles(nfft, twiddles.data()); >+ // Bit-reverse table. >+ bitrev.resize(nfft); >+ compute_bitrev_table(0, 1, factors.data(), this, &bitrev.back(), >+ bitrev.data()); >+} >+ >+KissFft::KissFftState::~KissFftState() = default; >+ >+KissFft::KissFft(const int nfft) : state_(nfft) {} >+ >+KissFft::~KissFft() = default; >+ >+void KissFft::ForwardFft(const size_t in_size, >+ const std::complex<float>* in, >+ const size_t out_size, >+ std::complex<float>* out) { >+ assert(in); >+ assert(out); >+ assert(in != out); // In-place FFT not supported. >+ assert(state_.nfft == static_cast<int>(in_size)); >+ assert(state_.nfft == static_cast<int>(out_size)); >+ // Bit-reverse the input. >+ for (int i = 0; i < state_.nfft; i++) >+ out[state_.bitrev[i]] = state_.scale * in[i]; >+ fft_impl(&state_, out); >+} >+ >+void KissFft::ReverseFft(const size_t in_size, >+ const std::complex<float>* in, >+ const size_t out_size, >+ std::complex<float>* out) { >+ assert(in); >+ assert(out); >+ assert(in != out); // In-place IFFT not supported. >+ assert(state_.nfft == static_cast<int>(in_size)); >+ assert(state_.nfft == static_cast<int>(out_size)); >+ // Bit-reverse the input. >+ for (int i = 0; i < state_.nfft; i++) >+ out[state_.bitrev[i]] = in[i]; >+ for (int i = 0; i < state_.nfft; i++) >+ out[i].imag(-out[i].imag()); >+ fft_impl(&state_, out); >+ for (int i = 0; i < state_.nfft; i++) >+ out[i].imag(-out[i].imag()); >+} >+ >+} // namespace rnnoise >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.h b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.h >new file mode 100644 >index 00000000000..b90f77d1ae3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft.h >@@ -0,0 +1,78 @@ >+/*Copyright (c) 2003-2004, Mark Borgerding >+ Lots of modifications by Jean-Marc Valin >+ Copyright (c) 2005-2007, Xiph.Org Foundation >+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO >+ Copyright (c) 2018, The WebRTC project authors >+ >+ All rights reserved. >+ >+ Redistribution and use in source and binary forms, with or without >+ modification, are permitted provided that the following conditions are met: >+ >+ * Redistributions of source code must retain the above copyright notice, >+ this list of conditions and the following disclaimer. >+ * Redistributions in binary form must reproduce the above copyright notice, >+ this list of conditions and the following disclaimer in the >+ documentation and/or other materials provided with the distribution. >+ >+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" >+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE >+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE >+ POSSIBILITY OF SUCH DAMAGE.*/ >+ >+#ifndef THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_ >+#define THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_ >+ >+#include <array> >+#include <complex> >+#include <vector> >+ >+namespace rnnoise { >+ >+class KissFft { >+ public: >+ // Example: an FFT of length 128 has 4 factors as far as kissfft is concerned >+ // (namely, 4*4*4*2). >+ static const size_t kMaxFactors = 8; >+ >+ class KissFftState { >+ public: >+ KissFftState(int num_fft_points); >+ KissFftState(const KissFftState&) = delete; >+ KissFftState& operator=(const KissFftState&) = delete; >+ ~KissFftState(); >+ >+ const int nfft; >+ const float scale; >+ std::array<int16_t, 2 * kMaxFactors> factors; >+ std::vector<int16_t> bitrev; >+ std::vector<std::complex<float>> twiddles; >+ }; >+ >+ explicit KissFft(const int nfft); >+ KissFft(const KissFft&) = delete; >+ KissFft& operator=(const KissFft&) = delete; >+ ~KissFft(); >+ void ForwardFft(const size_t in_size, >+ const std::complex<float>* in, >+ const size_t out_size, >+ std::complex<float>* out); >+ void ReverseFft(const size_t in_size, >+ const std::complex<float>* in, >+ const size_t out_size, >+ std::complex<float>* out); >+ >+ private: >+ KissFftState state_; >+}; >+ >+} // namespace rnnoise >+ >+#endif // THIRD_PARTY_RNNOISE_SRC_KISS_FFT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft_unittest.cc b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft_unittest.cc >new file mode 100644 >index 00000000000..31324453886 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/kiss_fft_unittest.cc >@@ -0,0 +1,145 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Use of this source code is governed by a BSD-style license that can be >+// found in the LICENSE file. >+ >+#include <array> >+#include <cmath> >+#include <limits> >+#include <tuple> >+#include <vector> >+ >+#include "testing/gtest/include/gtest/gtest.h" >+#include "third_party/rnnoise/src/kiss_fft.h" >+ >+namespace rnnoise { >+namespace test { >+namespace { >+ >+const double kPi = std::acos(-1.0); >+ >+void FillFftInputBuffer(const size_t num_samples, >+ const float* samples, >+ std::complex<float>* input_buf) { >+ for (size_t i = 0; i < num_samples; ++i) >+ input_buf[i].real(samples[i]); >+} >+ >+void CheckFftResult(const size_t num_fft_points, >+ const float* expected_real, >+ const float* expected_imag, >+ const std::complex<float>* computed, >+ const float tolerance) { >+ for (size_t i = 0; i < num_fft_points; ++i) { >+ SCOPED_TRACE(i); >+ EXPECT_NEAR(expected_real[i], computed[i].real(), tolerance); >+ EXPECT_NEAR(expected_imag[i], computed[i].imag(), tolerance); >+ } >+} >+ >+} // namespace >+ >+class RnnVadTest >+ : public testing::Test, >+ public ::testing::WithParamInterface<std::tuple<size_t, float, float>> {}; >+ >+// Check that IFFT(FFT(x)) == x (tolerating round-off errors). >+TEST_P(RnnVadTest, KissFftForwardReverseCheckIdentity) { >+ const auto params = GetParam(); >+ const float amplitude = std::get<0>(params); >+ const size_t num_fft = std::get<1>(params); >+ const float tolerance = std::get<2>(params); >+ std::vector<float> samples; >+ std::vector<float> zeros; >+ samples.resize(num_fft); >+ zeros.resize(num_fft); >+ for (size_t i = 0; i < num_fft; ++i) { >+ samples[i] = amplitude * std::sin(2.f * kPi * 10 * i / num_fft); >+ zeros[i] = 0.f; >+ } >+ >+ KissFft fft(num_fft); >+ std::vector<std::complex<float>> fft_buf_1; >+ fft_buf_1.resize(num_fft); >+ std::vector<std::complex<float>> fft_buf_2; >+ fft_buf_2.resize(num_fft); >+ >+ FillFftInputBuffer(samples.size(), samples.data(), fft_buf_1.data()); >+ { >+ // TODO(alessiob): Underflow with non power of 2 frame sizes. >+ // FloatingPointExceptionObserver fpe_observer; >+ >+ fft.ForwardFft(fft_buf_1.size(), fft_buf_1.data(), fft_buf_2.size(), >+ fft_buf_2.data()); >+ fft.ReverseFft(fft_buf_2.size(), fft_buf_2.data(), fft_buf_1.size(), >+ fft_buf_1.data()); >+ } >+ CheckFftResult(samples.size(), samples.data(), zeros.data(), fft_buf_1.data(), >+ tolerance); >+} >+ >+INSTANTIATE_TEST_CASE_P(FftPoints, >+ RnnVadTest, >+ ::testing::Values(std::make_tuple(1.f, 240, 3e-7f), >+ std::make_tuple(1.f, 256, 3e-7f), >+ std::make_tuple(1.f, 480, 3e-7f), >+ std::make_tuple(1.f, 512, 3e-7f), >+ std::make_tuple(1.f, 960, 4e-7f), >+ std::make_tuple(1.f, 1024, 3e-7f), >+ std::make_tuple(30.f, 240, 5e-6f), >+ std::make_tuple(30.f, 256, 5e-6f), >+ std::make_tuple(30.f, 480, 6e-6f), >+ std::make_tuple(30.f, 512, 6e-6f), >+ std::make_tuple(30.f, 960, 8e-6f), >+ std::make_tuple(30.f, 1024, 6e-6f))); >+ >+TEST(RnnVadTest, KissFftBitExactness) { >+ constexpr std::array<float, 32> samples = { >+ {0.3524301946163177490234375f, 0.891803801059722900390625f, >+ 0.07706542313098907470703125f, 0.699530780315399169921875f, >+ 0.3789891898632049560546875f, 0.5438187122344970703125f, >+ 0.332781612873077392578125f, 0.449340641498565673828125f, >+ 0.105229437351226806640625f, 0.722373783588409423828125f, >+ 0.13155306875705718994140625f, 0.340857982635498046875f, >+ 0.970204889774322509765625f, 0.53061950206756591796875f, >+ 0.91507828235626220703125f, 0.830274522304534912109375f, >+ 0.74468600749969482421875f, 0.24320767819881439208984375f, >+ 0.743998110294342041015625f, 0.17574800550937652587890625f, >+ 0.1834825575351715087890625f, 0.63317775726318359375f, >+ 0.11414264142513275146484375f, 0.1612723171710968017578125f, >+ 0.80316197872161865234375f, 0.4979794919490814208984375f, >+ 0.554282128810882568359375f, 0.67189347743988037109375f, >+ 0.06660757958889007568359375f, 0.89568817615509033203125f, >+ 0.29327380657196044921875f, 0.3472573757171630859375f}}; >+ constexpr std::array<float, 17> expected_real = { >+ {0.4813065826892852783203125f, -0.0246877372264862060546875f, >+ 0.04095232486724853515625f, -0.0401695556938648223876953125f, >+ 0.00500857271254062652587890625f, 0.0160773508250713348388671875f, >+ -0.011385642923414707183837890625f, -0.008461721241474151611328125f, >+ 0.01383177936077117919921875f, 0.0117270611226558685302734375f, >+ -0.0164460353553295135498046875f, 0.0585579685866832733154296875f, >+ 0.02038039825856685638427734375f, -0.0209107734262943267822265625f, >+ 0.01046995259821414947509765625f, -0.09019653499126434326171875f, >+ -0.0583711564540863037109375f}}; >+ constexpr std::array<float, 17> expected_imag = { >+ {0.f, -0.010482530109584331512451171875f, 0.04762755334377288818359375f, >+ -0.0558677613735198974609375f, 0.007908363826572895050048828125f, >+ -0.0071932487189769744873046875f, 0.01322011835873126983642578125f, >+ -0.011227893643081188201904296875f, -0.0400779247283935546875f, >+ -0.0290451310575008392333984375f, 0.01519204117357730865478515625f, >+ -0.09711246192455291748046875f, -0.00136523949913680553436279296875f, >+ 0.038602568209171295166015625f, -0.009693108499050140380859375f, >+ -0.0183933563530445098876953125f, 0.f}}; >+ >+ KissFft fft(32); >+ std::array<std::complex<float>, 32> fft_buf_in; >+ std::array<std::complex<float>, 32> fft_buf_out; >+ FillFftInputBuffer(samples.size(), samples.data(), fft_buf_in.data()); >+ fft.ForwardFft(fft_buf_in.size(), fft_buf_in.data(), fft_buf_out.size(), >+ fft_buf_out.data()); >+ CheckFftResult(expected_real.size(), expected_real.data(), >+ expected_imag.data(), fft_buf_out.data(), >+ std::numeric_limits<float>::min()); >+} >+ >+} // namespace test >+} // namespace rnnoise >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_activations.h b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_activations.h >new file mode 100644 >index 00000000000..af810319962 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_activations.h >@@ -0,0 +1,102 @@ >+/* Copyright (c) 2008-2011 Octasic Inc. >+ 2012-2017 Jean-Marc Valin */ >+/* >+ Redistribution and use in source and binary forms, with or without >+ modification, are permitted provided that the following conditions >+ are met: >+ >+ - Redistributions of source code must retain the above copyright >+ notice, this list of conditions and the following disclaimer. >+ >+ - Redistributions in binary form must reproduce the above copyright >+ notice, this list of conditions and the following disclaimer in the >+ documentation and/or other materials provided with the distribution. >+ >+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR >+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF >+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING >+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS >+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+*/ >+ >+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ >+#define THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ >+ >+#include <cmath> >+ >+namespace rnnoise { >+ >+inline float TansigApproximated(float x) { >+ static constexpr float kTansigTable[201] = { >+ 0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, 0.197375f, >+ 0.235496f, 0.272905f, 0.309507f, 0.345214f, 0.379949f, 0.413644f, >+ 0.446244f, 0.477700f, 0.507977f, 0.537050f, 0.564900f, 0.591519f, >+ 0.616909f, 0.641077f, 0.664037f, 0.685809f, 0.706419f, 0.725897f, >+ 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f, >+ 0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, >+ 0.893698f, 0.901468f, 0.908698f, 0.915420f, 0.921669f, 0.927473f, >+ 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, >+ 0.957917f, 0.961090f, 0.964028f, 0.966747f, 0.969265f, 0.971594f, >+ 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, >+ 0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, >+ 0.989867f, 0.990642f, 0.991359f, 0.992020f, 0.992631f, 0.993196f, >+ 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, >+ 0.996108f, 0.996407f, 0.996682f, 0.996937f, 0.997172f, 0.997389f, >+ 0.997590f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, >+ 0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999000f, >+ 0.999076f, 0.999147f, 0.999213f, 0.999273f, 0.999329f, 0.999381f, >+ 0.999428f, 0.999472f, 0.999513f, 0.999550f, 0.999585f, 0.999617f, >+ 0.999646f, 0.999673f, 0.999699f, 0.999722f, 0.999743f, 0.999763f, >+ 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, >+ 0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, >+ 0.999916f, 0.999923f, 0.999929f, 0.999934f, 0.999939f, 0.999944f, >+ 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, >+ 0.999968f, 0.999970f, 0.999973f, 0.999975f, 0.999977f, 0.999978f, >+ 0.999980f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, >+ 0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, 0.999992f, >+ 0.999992f, 0.999993f, 0.999994f, 0.999994f, 0.999994f, 0.999995f, >+ 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, >+ 0.999997f, 0.999997f, 0.999997f, 0.999998f, 0.999998f, 0.999998f, >+ 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, >+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, >+ 0.999999f, 0.999999f, 0.999999f, 0.999999f, 1.000000f, 1.000000f, >+ 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, >+ 1.000000f, 1.000000f, 1.000000f, >+ }; >+ >+ // Tests are reversed to catch NaNs. >+ if (!(x < 8.f)) >+ return 1.f; >+ if (!(x > -8.f)) >+ return -1.f; >+ float sign = 1.f; >+ if (x < 0.f) { >+ x = -x; >+ sign = -1.f; >+ } >+ // Look-up. >+ int i = static_cast<int>(std::floor(0.5f + 25 * x)); >+ float y = kTansigTable[i]; >+ // Map i back to x's scale (undo 25 factor). >+ x -= 0.04f * i; >+ y = y + x * (1.f - y * y) * (1.f - y * x); >+ return sign * y; >+} >+ >+inline float SigmoidApproximated(const float x) { >+ return 0.5f + 0.5f * TansigApproximated(0.5f * x); >+} >+ >+inline float RectifiedLinearUnit(const float x) { >+ return x < 0.f ? 0.f : x; >+} >+ >+} // namespace rnnoise >+ >+#endif // THIRD_PARTY_RNNOISE_SRC_RNN_ACTIVATIONS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.cc b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.cc >new file mode 100644 >index 00000000000..40c184b98b0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.cc >@@ -0,0 +1,401 @@ >+#include "third_party/rnnoise/src/rnn_vad_weights.h" >+ >+namespace rnnoise { >+ >+const int8_t kInputDenseWeights[kInputLayerWeights] = { >+ -10, 0, -3, 1, -8, -6, 3, -13, 1, 0, -3, -7, >+ -5, -3, 6, -1, -6, 0, -6, -4, -1, -2, 1, 1, >+ -7, 2, 21, 10, -5, -20, 24, 23, 37, 8, -2, 33, >+ -6, 22, 13, -2, 50, 8, 13, 1, -15, 30, -10, 30, >+ 0, 3, 5, 27, 1, 4, -3, 41, 56, 35, -2, 49, >+ -13, 11, 13, -2, -47, 5, -16, -60, -15, 77, -17, 26, >+ -3, 14, -21, 19, -5, -19, -13, 0, 10, 14, 9, 31, >+ -13, -41, -10, 4, 22, 18, -48, -6, -10, 62, -3, -18, >+ -14, 12, 26, -28, 3, 14, 25, -13, -19, 6, 5, 36, >+ -3, -65, -12, 0, 31, -7, -9, 101, -4, 26, 16, 17, >+ -12, -12, 14, -36, -3, 5, -15, 21, 2, 30, -3, 38, >+ -4, 1, -6, 7, -7, 14, 38, -22, -30, -3, -7, 3, >+ -39, -70, -126, 25, 34, 94, -67, -22, -33, 83, -47, -118, >+ 4, 70, 33, 25, 62, -128, -76, -118, -113, 49, -12, -100, >+ -18, -114, -33, 43, 32, 61, 40, -9, -106, 2, 36, -100, >+ -40, -5, 20, -75, 61, -51, -9, 126, -27, -52, 5, -24, >+ -21, -126, -114, -12, 15, 106, -2, 73, -125, 50, 13, -120, >+ 35, 35, 4, -61, 29, -124, 6, -53, -69, -125, 64, -89, >+ 36, -107, -103, -7, 27, 121, 69, 77, -35, 35, 95, -125, >+ -49, 97, -45, -43, -23, 23, -28, -65, -118, 2, 8, -126, >+ 27, -97, 92, 5, 55, 82, 17, -57, -115, 37, 8, -106, >+ -46, 41, -2, 21, -44, 8, -73, -58, -39, 34, 89, -95, >+ 95, -117, 120, -58, 31, 123, 1, -32, -109, -110, 60, -120, >+ -43, -74, 5, 91, 26, 21, 114, 82, -83, -126, 123, 22, >+ -16, -67, 25, -83, 46, 48, -34, -121, -124, -63, -35, -9, >+ 31, 82, 123, 6, -3, 117, 93, -2, -13, -36, 124, -112, >+ -6, -102, -5, -33, -15, 44, -69, -127, -23, -40, -34, -85, >+ 68, 83, -1, 40, 8, 84, 118, -58, -55, -102, 123, -55, >+ -14, -123, 44, -63, -14, 21, 35, 16, 24, -126, -13, -114, >+ 35, 20, -36, 61, -9, 97, 34, 19, -32, -109, 76, -104, >+ 99, -119, 45, -125, -51, -28, -8, -69, -8, 125, -45, -93, >+ 113, 103, -41, -82, 52, 7, 126, 0, -40, 104, 55, -58, >+ 17, -124, -93, -58, 8, -45, 1, 56, -123, 108, -47, -23, >+ 115, 127, 17, -68, -13, 116, -82, -44, 45, 67, -120, -101, >+ -15, -125, 120, -113, 17, -48, -73, 126, -64, -86, -118, -19, >+ 112, -1, -66, -27, -62, 121, -86, -58, 50, 89, -38, -75, >+ 95, -111, 12, -113, 2, -68, 2, -94, -121, 91, -5, 0, >+ 79, 43, -7, -18, 79, 35, -38, 47, 1, -45, 83, -50, >+ 102, 32, 55, -96, 15, -122, -69, 45, -27, 91, -62, -30, >+ 46, -95, 22, -72, -97, -1, 14, -122, 28, 127, 61, -126, >+ 121, 9, 68, -120, 49, -60, 90, 3, 43, 68, 54, 34, >+ -10, 28, 21, -24, -54, 22, -113, -12, 82, -2, -17, -9, >+ 127, 8, 116, -92, 0, -70, -33, 123, 66, 116, -74, -4, >+ 74, -72, -22, -47, 1, -83, -60, -124, 1, 122, -57, -43, >+ 49, 40, -126, -128, -8, -29, 28, -24, -123, -121, -70, -93, >+ -37, -126, 11, -125, -37, 11, -31, -51, -124, 116, -128, 8, >+ -25, 109, 75, -12, 7, 8, 10, 117, 124, -128, -128, 29, >+ -26, 101, 21, -128, 87, 8, -39, 23, -128, 127, -127, 74, >+ -55, 74, 112, 127, 4, 55, 44, -92, 123, 34, -93, 47, >+ -21, -92, 17, 49, -121, 92, 7, -126, -125, 124, -74, 3, >+ -59, 18, -91, 3, -9, 9, 56, 116, 7, -29, 33, 87, >+ -21, -128, -13, 57, 74, 9, -29, -61, -97, -21, -95, -12, >+ -114, 16, 82, 125, -7, 10, -24, 9, 77, -128, -102, -25, >+ 3, -126, 10, 13, -18, 51, 26, 127, -79, 35, 51, 12, >+ -50, -24, 1, -7, 22, 81, 65, 120, -30, -38, 85, 122, >+ -4, -106, -11, 27, 53, 41, 8, -104, -66, -38, -124, 10, >+ 12, 76, 117, -109, 9, 11, 2, -18, 3, 113, -16, -79, >+ -39, -123, -20, -128, 2, 13, -33, -58, 10, 84, -104, 13, >+ 64, 109, 1, 54, -12, 28, 24, 63, -126, 118, -82, 46, >+ -12, -15, 14, -43, 60, 22, -32, -19, -46, 91, -107, 24, >+ -94, 26, -47, 125, 6, 58, -15, -75, -26, -38, -35, 103, >+ -16, -17, -13, 63, -2, 45, -45, -73, -23, 70, -87, 51, >+ -17, 53, 76, 14, -18, -31, -14, 103, 8, 21, -28, -33, >+ -20, -47, 6, 39, 40, -30, 7, -76, 55, 31, -20, -21, >+ -59, 1, 25, -11, 17, 5, -13, -39, 0, -76, 50, -33, >+ -29, -50, -16, -11, -12, -1, -46, 40, -10, 65, -19, 21, >+ -41, -32, -83, -19, -4, 49, -60, 118, -24, -46, 9, 102, >+ -20, 8, -19, 25, 31, -3, -37, 0, 25, 7, 29, 2, >+ -39, 127, -64, -20, 64, 115, -30, 36, 100, 35, 122, 127, >+ 127, -127, 127, -127, 19, 127, -89, -79, -32, 39, -127, 125, >+ -80, 126, -127, 26, 8, 98, -8, -57, -90, -50, 126, 61, >+ 127, -126, 40, -106, -68, 104, -125, -119, 11, 10, -127, 66, >+ -56, -12, -126, -104, 27, 75, 38, -124, -126, -125, 84, -123, >+ -45, -114, -128, 127, 103, -101, -124, 127, -11, -23, -123, 92, >+ -123, 24, 126, 41, -2, -39, -27, -94, 40, -112, -48, 127, >+ 58, 14, 38, -75, -64, 73, 117, 100, -119, -11, 6, 32, >+ -126, -14, 35, 121, -10, 54, -60, 89, -3, 69, -25, -20, >+ 43, -86, -34, 24, 27, 7, -81, -99, -23, -16, -26, 13, >+ 35, -97, 80, -29, -13, -121, -12, -65, -94, 70, -89, -126, >+ -95, 88, 33, 96, 29, -90, 69, 114, -78, 65, 90, -47, >+ -47, 89, 1, -12, 3, 8, 30, 5, 2, -30, -1, 6, >+ -7, 10, -4, 46, -27, -40, 22, -6, -17, 45, 24, -9, >+ 23, -14, -63, -26, -12, -57, 27, 25, 55, -76, -47, 21, >+ 34, 33, 26, 17, 14, 6, 9, 26, 25, -25, -25, -18}; >+ >+const int8_t kInputDenseBias[kInputLayerOutputSize] = { >+ 38, -6, 127, 127, 127, -43, -127, 78, 127, 5, 127, 123, >+ 127, 127, -128, -76, -126, 28, 127, 125, -30, 127, -89, -20}; >+ >+const int8_t kHiddenGruWeights[kHiddenLayerWeights] = { >+ -124, 23, -123, -33, -95, -4, 8, -84, 4, 101, -119, 116, >+ -4, 123, 103, -51, 29, -124, -114, -49, 31, 9, 75, -128, >+ 0, -49, 37, -50, 46, -21, -63, -104, 54, 82, 33, 21, >+ 70, 127, -9, -79, -39, -23, -127, 107, 122, -96, -46, -18, >+ -39, 13, -28, -48, 14, 56, -52, 49, -1, -121, 25, -18, >+ -36, -52, -57, -30, 54, -124, -26, -47, 10, 39, 12, 2, >+ 9, -127, -128, 102, 21, 11, -64, -71, 89, -113, -111, 54, >+ 31, 94, 121, -40, 30, 40, -109, 73, -9, 108, -92, 2, >+ -127, 116, 127, 127, -122, 95, 127, -37, -127, 28, 89, 10, >+ 24, -104, -62, -67, -14, 38, 14, -71, 22, -41, 20, -50, >+ 39, 63, 86, 127, -18, 79, 4, -51, 2, 33, 117, -113, >+ -78, 56, -91, 37, 34, -45, -44, -22, 21, -16, 56, 30, >+ -84, -79, 38, -74, 127, 9, -25, 2, 82, 61, 25, -26, >+ 26, 11, 117, -65, 12, -58, 42, -62, -93, 11, 11, 124, >+ -123, 80, -125, 11, -90, 42, 94, 4, -109, -1, 85, -52, >+ 45, -26, -27, 77, -5, 30, 90, 0, 95, -7, 53, 29, >+ -82, 22, -9, 74, 2, -12, -73, 114, 97, -64, 122, -77, >+ 43, 91, 86, 126, 106, 72, 90, -43, 46, 96, -51, 21, >+ 22, 68, 22, 41, 79, 75, -46, -105, 23, -116, 127, -123, >+ 102, 57, 85, 10, -29, 34, 125, 126, 124, 81, -15, 54, >+ 96, -128, 39, -124, 103, 74, 126, 127, -50, -71, -122, -64, >+ 93, -75, 71, 105, 122, 123, 126, 122, -127, 33, -63, -74, >+ 124, -71, 33, 41, -56, 19, 6, 65, 41, 90, -116, -3, >+ -46, 75, -13, 98, -74, -42, 74, -95, -96, 81, 24, 32, >+ -19, -123, 74, 55, 109, 115, 0, 32, 33, 12, -20, 9, >+ 127, 127, -61, 79, -48, -54, -49, 101, -9, 27, -106, 74, >+ 119, 77, 87, -126, -24, 127, 124, 31, 34, 127, 40, 3, >+ -90, 127, 23, 57, -53, 127, -69, -88, -33, 127, 19, -46, >+ -9, -125, 13, -126, -113, 127, -41, 46, 106, -62, 3, -10, >+ 111, 49, -34, -24, -20, -112, 11, 101, -50, -34, 50, 65, >+ -64, -106, 70, -48, 60, 9, -122, -45, 15, -112, -26, -4, >+ 1, 39, 23, 58, -45, -80, 127, 82, 58, 30, -94, -119, >+ 51, -89, 95, -107, 30, 127, 125, 58, -52, -42, -38, -20, >+ -122, 115, 39, -26, 5, 73, 13, -39, 43, -23, -20, -125, >+ 23, 35, 53, -61, -66, 72, -20, 33, 8, 35, 4, 7, >+ 18, 19, 16, -45, -50, -71, 31, -29, -41, -27, 10, 14, >+ 27, 9, -23, 98, 6, -94, 92, 127, -114, 59, -26, -100, >+ -62, -127, -17, -85, -60, 126, -42, -6, 33, -120, -26, -126, >+ -127, -35, -114, -31, 25, -126, -100, -126, -64, -46, -31, 30, >+ 25, -74, -111, -97, -81, -104, -114, -19, -9, -116, -69, 22, >+ 30, 59, 8, -51, 16, -97, 18, -4, -89, 80, -50, 3, >+ 36, -67, 56, 69, -26, 107, -10, 58, -28, -4, -57, -72, >+ -111, 0, -75, -119, 14, -75, -49, -66, -49, 8, -121, 22, >+ -54, 121, 30, 54, -26, -126, -123, 56, 5, 48, 21, -127, >+ -11, 23, 25, -82, 6, -25, 119, 78, 4, -104, 27, 61, >+ -48, 37, -13, -52, 50, -50, 44, -1, -22, -43, -59, -78, >+ -67, -32, -26, 9, -3, 40, 16, 19, 3, -9, 20, -6, >+ -37, 28, 39, 17, -19, -10, 1, 6, -59, 74, 47, 3, >+ -119, 0, -128, -107, -25, -22, -69, -23, -111, -42, -93, -120, >+ 90, -85, -54, -118, 76, -79, 124, 101, -77, -75, -17, -71, >+ -114, 68, 55, 79, -1, -123, -20, 127, -65, -123, -128, -87, >+ 123, 9, -115, -14, 7, -4, 127, -79, -115, 125, -28, 89, >+ -83, 49, 89, 119, -69, -5, 12, -49, 60, 57, -24, -99, >+ -110, 76, -83, 125, 73, 81, 11, 8, -45, 1, 83, 13, >+ -70, -2, 97, 112, -97, 53, -9, -94, 124, 44, -49, -24, >+ 52, 76, -110, -70, -114, -12, 72, -4, -114, 43, -43, 81, >+ 102, -84, -27, 62, -40, 52, 58, 124, -35, -51, -123, -43, >+ 56, -75, -34, -35, -106, 93, -43, 14, -16, 46, 62, -97, >+ 21, 30, -53, 21, -11, -33, -20, -95, 4, -126, 12, 45, >+ 20, 108, 85, 11, 20, -40, 99, 4, -25, -18, -23, -12, >+ -126, -55, -20, -44, -51, 91, -127, 127, -44, 7, 127, 78, >+ 38, 125, -6, -94, -103, 73, 126, -126, 18, 59, -46, 106, >+ 76, 116, -31, 75, -4, 92, 102, 32, -31, 73, 42, -21, >+ -28, 57, 127, -8, -107, 115, 124, -94, -4, -128, 29, -57, >+ 70, -82, 50, -13, -44, 38, 67, -93, 6, -39, -46, 56, >+ 68, 27, 61, 26, 18, -72, 127, 22, 18, -31, 127, 61, >+ -65, -38, 1, -67, -1, 8, -73, 46, -116, -94, 58, -49, >+ 71, -40, -63, -82, -20, -60, 93, 76, 69, -106, 34, -31, >+ 4, -25, 107, -18, 45, 4, -61, 126, 54, -126, -125, 41, >+ 19, 44, 32, -98, 125, -24, 125, -96, -125, 15, 87, -4, >+ -90, 18, -40, 28, -69, 67, 22, 41, 39, 7, -48, -44, >+ 12, 69, -13, 2, 44, -38, 111, -7, -126, -22, -9, 74, >+ -128, -36, -7, -123, -15, -79, -91, -37, -127, -122, 104, 30, >+ 7, 98, -37, 111, -116, -47, 127, -45, 118, -111, -123, -120, >+ -77, -64, -125, 124, 77, 111, 77, 18, -113, 117, -9, 67, >+ -77, 126, 49, -20, -124, 39, 41, -124, -34, 114, -87, -126, >+ 98, -20, 59, -17, -24, 125, 107, 54, 35, 33, -44, 12, >+ -29, 125, -71, -28, -63, -114, 28, -17, 121, -36, 127, 89, >+ -122, -49, -18, -48, 17, 24, 19, -64, -128, 13, 86, 45, >+ 13, -49, 55, 84, 48, 80, -39, 99, -127, 70, -33, 30, >+ 50, 126, -65, -117, -13, -20, -24, 127, 115, -72, -104, 63, >+ 126, -42, 57, 17, 46, 21, 119, 110, -100, -60, -112, 62, >+ -33, 28, 26, -22, -60, -33, -54, 78, 25, 32, -114, 86, >+ 44, 26, 43, 76, 121, 19, 97, -2, -3, -73, -68, 6, >+ -116, 6, -43, -97, 46, -128, -120, -31, -119, -29, 16, 16, >+ -126, -128, -126, -46, -9, -3, 92, -31, -76, -126, -3, -107, >+ -12, -23, -69, 5, 51, 27, -42, 23, -70, -128, -29, 22, >+ 29, -126, -55, 50, -71, -3, 127, 44, -27, -70, -63, -66, >+ -70, 104, 86, 115, 29, -92, 41, -90, 44, -11, -28, 20, >+ -11, -63, -16, 43, 31, 17, -73, -31, -1, -17, -11, -39, >+ 56, 18, 124, 72, -14, 28, 69, -121, -125, 34, 127, 63, >+ 86, -80, -126, -125, -124, -47, 124, 77, 124, -19, 23, -7, >+ -50, 96, -128, -93, 102, -53, -36, -87, 119, -125, 92, -126, >+ 118, 102, 72, -2, 125, 10, 97, 124, -125, 125, 71, -20, >+ -47, -116, -121, -4, -9, -32, 79, -124, -36, 33, -128, -74, >+ 125, 23, 127, -29, -115, -32, 124, -89, 32, -107, 43, -17, >+ 24, 24, 18, 29, -13, -15, -36, 62, -91, 4, -41, 95, >+ 28, -23, 6, 46, 84, 66, 77, 68, -70, -1, -23, -6, >+ 65, 70, -21, 9, 77, -12, 2, -118, 4, 9, -108, 84, >+ 52, 2, 52, 13, -10, 58, -110, 18, 66, -95, -23, 70, >+ 31, -3, 56, 56, -3, -7, 1, -27, -48, -61, 41, -4, >+ 10, -62, 32, -7, -24, 9, -48, -60, -4, 79, -20, -38, >+ -76, 68, -49, -97, 0, -15, 5, -100, -49, -95, -99, -115, >+ -9, -40, 10, 104, 13, 56, 127, -27, -109, -94, -118, -102, >+ -44, -85, 52, 127, -4, 14, 62, 121, -122, -26, -79, -42, >+ -34, 1, 25, -38, -79, -58, -31, -31, -90, -30, -123, 32, >+ -56, 125, 66, 124, -1, 3, 91, -103, -7, 23, 78, -18, >+ 9, 69, -69, 76, -38, -33, -2, -98, 18, 106, 84, 55, >+ 87, -47, 35, -124, 64, 41, -14, 46, 25, -2, 120, -21, >+ 82, 19, -79, -37, -3, -8, -16, 21, 19, -5, -28, -112, >+ 39, -6, -30, 53, -69, 53, 46, 127, 123, 78, 20, 28, >+ -7, 73, 72, 17, -40, 41, 111, 57, 32, -95, 29, 28, >+ -39, -65, 54, -20, -63, 29, -67, 3, 44, -57, -47, 11, >+ 61, -22, -44, 61, 48, -100, 20, 125, 96, -24, -16, 3, >+ -69, -126, 74, -125, 9, 45, -67, -123, -59, -72, 118, 69, >+ 45, 50, -57, 67, 13, -66, -106, 47, 62, 22, -1, -22, >+ -25, -40, -125, 3, 125, 32, 102, -56, -25, -75, -30, 122, >+ 60, -13, 36, -73, 7, -84, 124, 40, -118, 17, -87, -118, >+ -8, 3, -27, 111, -40, 40, -51, 127, 125, -45, -30, -54, >+ 46, 80, -1, -30, 101, -17, 18, 26, 54, 7, -12, 1, >+ -127, 123, -122, -27, -75, 64, 10, 25, -15, -44, 127, -127, >+ 5, -84, -81, -7, 19, -26, 126, 15, 116, -126, 14, -76, >+ 44, 62, -110, -124, 125, -29, -87, -3, -69, 82, 90, 57, >+ -123, 123, 100, -19, -51, -32, 69, 37, -57, -128, -124, -72, >+ -13, 51, -7, -45, -73, 5, 99, -26, -117, -96, -109, 4, >+ -31, -12, 0, 31, -42, -27, 12, -81, 118, 39, 83, 14, >+ 41, -126, 107, -82, 94, -116, -122, -47, -109, -84, -128, -35, >+ -56, 66, 8, -65, 19, 42, -46, -72, -109, 41, 43, -127, >+ -113, 58, 127, 42, -75, -1, 65, 117, -55, -113, -123, 124, >+ 43, -96, -115, -19, 68, 15, 94, 3, 75, 0, 34, 9, >+ 42, 110, -48, 92, -76, 99, -17, 27, 32, 13, 125, 50, >+ -17, 56, 4, 53, 34, -8, 99, 80, -126, -21, -65, -11, >+ -46, 44, -81, -3, -121, 123, 66, -81, -84, 119, 127, 84, >+ 105, 45, -66, -42, -23, 32, -25, 12, 111, 127, 88, 125, >+ 30, 24, -127, -9, -54, 127, -116, -119, 88, 70, 94, -120, >+ 35, -93, 15, 22, -21, 25, -110, -123, -45, 8, -109, 125, >+ -122, -86, -126, 8, -14, -120, -45, -45, 69, -125, -122, 6, >+ 81, 86, 125, 95, 54, 77, 54, -123, 126, -85, -117, 56, >+ 11, 0, -61, -91, -12, -2, -113, -3, -15, -122, -63, -91, >+ 10, 84, -111, 125, 93, 21, 62, -78, -116, 13, -57, 28, >+ -124, 126, 110, 12, 15, 95, 15, -19, -125, -97, 52, -7, >+ 101, 9, 20, -125, -26, -56, 72, 77, 12, -126, 22, -29, >+ 47, 62, 95, 112, 69, 32, 97, -83, -8, -5, 67, -63, >+ -123, 79, 59, 0, -6, -17, 4, -111, -52, 27, 65, 0}; >+ >+const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights] = { >+ 65, 83, 35, 56, 24, -34, -28, -2, 125, 19, 42, -9, >+ 124, -53, 24, -87, 11, 35, -81, -35, -125, -31, 123, -21, >+ 33, -91, 113, -93, 45, -6, 53, 38, -92, 8, -27, 87, >+ 4, 43, 43, 10, -128, -128, -46, 127, -38, -45, 25, -87, >+ 19, 5, 52, -96, -23, -29, 121, -126, -24, -20, -2, 69, >+ -50, 6, 71, -81, -125, 90, -94, 1, -38, 36, 89, 17, >+ -60, 71, -48, 18, -15, 44, -18, 59, 11, 114, -51, 32, >+ 110, 1, 4, 109, -24, 127, 27, 60, 88, 24, 45, -59, >+ 75, -36, 8, 57, -32, -25, 13, 126, -89, -61, -76, 127, >+ 18, -62, -68, 23, -113, 5, 126, 43, -88, 26, -78, 18, >+ 75, 21, 9, -74, 20, 41, 126, -118, -15, 9, 116, 126, >+ -127, 34, -6, 126, -128, -53, -54, -55, -121, 70, 127, -12, >+ -68, 82, -25, 104, -126, 126, -21, -26, 124, -75, -127, -120, >+ 13, 61, -64, -108, -63, -65, -44, -35, -61, -39, 109, -74, >+ 113, -3, 108, -30, 125, 120, 39, 125, -128, -95, -99, 111, >+ 9, 25, 114, -75, -92, -54, -12, -32, -38, 10, 31, 10, >+ 63, 51, 40, -99, 74, 4, 50, -128, -36, -35, -11, -28, >+ -126, -7, 66, -58, -126, -22, -83, -61, -127, 49, 126, -8, >+ 7, 62, 36, -11, -32, -44, 63, 116, 41, 65, -127, 126, >+ 63, -30, -96, 74, -92, 127, 38, -18, -128, 68, -5, 101, >+ -4, 85, 58, 79, 0, -58, 8, 119, -70, -1, -79, -68, >+ 114, -28, -90, -6, -112, 2, 127, -8, 10, 55, -59, -126, >+ 127, 125, 80, 72, 35, -54, 95, -124, -124, 79, 23, -46, >+ -61, -127, -100, 99, -77, 8, -87, 5, -2, 49, 85, 7, >+ -71, 82, 53, -41, 22, -22, -93, -103, 6, 52, -56, 14, >+ -8, -111, 85, 16, 54, 32, -118, -24, 61, -53, 96, -70, >+ -5, -17, -67, -84, -7, -82, -107, -96, 21, -83, -58, 50, >+ 12, -126, -1, -28, 34, -126, 115, 17, 91, 1, -127, 72, >+ 11, 126, -81, 6, 96, -8, 77, 15, -6, 63, -27, 20, >+ -123, -109, 85, -79, -17, 126, -92, 2, -61, 20, 14, 17, >+ 121, 123, 30, 57, 120, 127, 57, 42, 117, 98, 67, 39, >+ -20, -70, 100, 7, 125, 122, 40, 16, -79, 125, 83, 41, >+ -106, -57, 24, 55, 27, -66, -111, -44, -7, -43, -66, 121, >+ 42, -128, -45, 35, 15, -127, 34, -35, -34, -40, -18, -6, >+ 63, 111, 31, 116, 127, 19, 24, -71, -39, 34, 11, 19, >+ -40, 27, 12, 106, -10, 56, -82, -106, -2, -50, -52, 114, >+ -126, -34, -43, -68, 10, 76, 57, -118, -128, 37, -104, 76, >+ 125, 3, -76, 127, -29, 84, -94, -15, 55, 125, 79, 127, >+ -57, -125, 104, -68, 126, 126, -77, 51, 45, 33, -109, 115, >+ -11, 1, 95, -121, -5, -9, -126, -114, 39, 68, -126, -107, >+ -51, -42, 24, -8, 51, -27, -43, 66, -45, 62, -98, -109, >+ 69, 67, 0, -125, -128, 49, 31, 126, -122, 2, -55, -67, >+ -126, -70, -128, -125, -77, 25, 16, -8, -102, 11, -75, 82, >+ 38, -5, 5, 19, 34, 47, -127, -93, 21, 24, -97, -18, >+ 31, 39, 34, -20, 22, 123, 7, -77, -81, -46, -9, 1, >+ 23, 39, -127, -43, -8, -50, 10, -21, 59, -9, -4, -13, >+ -27, 44, 127, 52, -47, 70, -43, 52, 101, -49, 27, 45, >+ 49, 33, -125, 55, 114, 20, -1, 76, -24, -96, 105, 24, >+ 126, 75, -21, -105, 13, -42, 40, 126, -30, -39, -95, 125, >+ -63, 11, 6, 125, 125, -14, 5, 42, -61, -4, 49, 88, >+ 6, -107, -28, 19, -29, 47, 126, 6, -46, -89, -18, 91, >+ -20, -6, 118, -21, -22, 39, 115, 11, -42, 54, 73, -55, >+ -77, 62, -27, -59, -99, -12, -127, -40, 56, -3, -124, -91, >+ 71, -111, 6, -19, 82, -24, -35, 102, -42, 7, -126, -126, >+ -125, 18, 98, -52, 127, 105, -52, 40, -83, 126, -122, 109, >+ 5, 127, 48, 6, 5, -125, 100, -16, 29, 85, -89, 8, >+ 4, 41, 62, -127, 62, 122, 85, 122, -107, 8, -125, 93, >+ -127, 127, 102, 19, 19, -66, 41, -42, 114, 127, -48, -117, >+ -29, -6, -73, -102, -3, -19, 0, 88, 42, 87, -117, -20, >+ 2, 122, 28, 63, 71, 66, 120, 93, 124, -43, 49, 103, >+ 31, 90, -91, -22, -126, 26, -24, -21, 51, -126, 87, -103, >+ -69, -10, -66, -23, 20, 97, 36, 25, -127, 30, -20, -63, >+ 30, 51, -116, 23, 40, -39, 36, -83, -77, -25, -50, 110, >+ 14, 13, -109, 125, -65, -55, -87, 124, -126, -32, -72, -108, >+ 127, 127, -125, -124, 61, 121, 102, -128, -127, 16, 100, 127, >+ -124, -68, 72, -93, -128, 43, -93, -19, -125, -97, -113, -33, >+ 83, 127, -44, 127, -75, 127, 16, 44, 50, -122, 23, 118, >+ 46, 19, 26, -128, 10, 4, 99, -14, -82, -13, 30, 125, >+ 57, 65, 60, -71, 35, 98, 28, 7, 1, 43, 89, 70, >+ 75, 121, -59, 82, -126, -53, -16, -116, -65, 52, -52, 0, >+ 80, 35, 45, -61, 46, 8, 107, 27, -26, -118, 90, 57, >+ -10, 7, -15, 0, -39, -4, 12, 29, -1, 116, 84, 79, >+ 119, 125, -59, 28, -6, -25, -43, 2, 90, 79, 67, 103, >+ -82, 2, -6, 125, 19, 73, 0, -105, 112, -17, 104, 107, >+ 124, 106, 19, 56, -44, 55, -112, 6, -39, -83, 126, -93, >+ -98, 57, -120, -23, -38, 2, -31, -48, 106, 127, 127, 69, >+ 16, 110, 71, 104, 62, -12, -22, 42, -37, -94, 34, -1, >+ -32, -12, -124, -47, -13, 60, -75, -66, 58, -127, -2, 64, >+ 76, -106, 73, -49, -31, 127, 126, 31, 16, 127, -110, 107, >+ -16, -53, 20, 69, -14, -125, 59, -44, 15, 120, 125, 125, >+ 43, 6, 19, -58, 127, 127, 43, 16, 82, 97, -127, 127, >+ -93, -41, 88, 0, 77, -15, 116, 16, -124, -31, -3, 95, >+ -40, -126, -54, -126, -83, -8, -59, 6, 67, -29, 4, 124, >+ -10, 112, -28, -8, 85, -21, 45, 84, 6, -8, 11, 72, >+ 32, 84, -62, 77, 2, -36, 75, 31, -50, 116, 126, 119, >+ -88, -55, -14, -37, 126, 40, -108, -6, -6, 57, 64, -28, >+ -76, 30, -117, -93, 31, -92, -44, -64, 94, 58, 65, 114, >+ 41, 47, 71, 42, -26, 99, -126, 57, -5, 74, -19, -113, >+ -1, 67, -21, 126, 1, -3, 33, 60, -82, 37, -48, 89, >+ 114, -38, 127, -114, 35, 58, -5, 21, -46, 121, -123, -43, >+ 127, 115, 123, 122, -101, 126, 127, 81, 52, 89, -127, 102, >+ 42, 117, -9, -2, 125, 127, 110, 96, 120, 66, 70, 124, >+ 55, 84, -38, -58, 119, -127, -16, -79, 123, 18, -127, -50, >+ -38, 120, -85, 1, 7, -56, 108, -77, -2, 21, 37, 1, >+ 13, -105, -69, 28, -87, 33, -104, -51, 126, 41, 3, -121, >+ 28, 71, 58, 86, -8, 127, 94, -55, 125, 40, -19, 127, >+ -33, -87, -23, 7, -111, -68, 9, 84, -119, 55, -82, 78, >+ -37, -20, -9, -23, 53, -13, 15, -46, 116, 126, -127, 56, >+ -126, 125, -7, -1, 45, 26, 125, 121, 29, 47, -86, 30, >+ 10, 76, -125, -7, 23, 92, -12, -39, -18, 92, -97, -8, >+ -85, -41, 49, -50, 123, -37, -126, -30, 14, 79, -49, -65, >+ 9, -36, -38, -96, 85, -24, -13, 37, -25, -5, -64, -127, >+ 55, -60, -18, -61, -63, 127, 56, 67, 15, 124, 72, 120, >+ 127, 40, -10, 114, 24, -23, 46, 78, -53, 125, 86, 124, >+ 86, 0, 38, 93, 21, 127, 123, 75, -72, 13, 48, 33, >+ 83, -51, 15, -32, -49, -33, 120, 64, 7, 9, 65, 60, >+ 21, -21, -61, -53, -113, 84, -97, 101, 37, -114, -27, 41, >+ 73, 126, -10, 59, 61, -15, 70, -13, 82, -4, 69, 56, >+ 94, -91, -50, 92, -74, -48, 53, -7, -107, 127, 28, 30, >+ -26, -21, -61, 77, 82, 64, -91, -125, 122, -104, 127, 123, >+ 122, 123, 76, -126, 127, -6, -80, 7, 40, -66, -65, 54, >+ -2, 23, 96, -64, 74, 2, -53, -12, -123, 39, 60, -20, >+ 16, -17, -97, 23, -4, -53, -122, 32, -16, -54, -95, 43, >+ 71, -1, -67, -33, 41, 18, 72, 28, -83, 31, -100, -91, >+ -27, 10, -128, -106, 2, 76, -13, 42, 34, 112, -19, 44, >+ 40, -9, -11, 65, 92, -43, -125, 2, 47, -32, 25, 122, >+ -29, 12, 101, -8, -126, -23, 43, 7, 125, -20, -124, 82, >+ -2, 13, -73, -106, 115, 31, 116, -23, -44, -71, 84, 3, >+ 47, 91, 127, 127, -15, 95, 7, 93, 5, 113, -50, 54, >+ 11, 13, -127, 17, 72, 43, -23, 5, -70, 20, 15, -27, >+ 99, 69, -109, -122, -94, 16, 127, 0, 116, 104, 45, 108, >+ -34, 87, 72, -14, 118, 46, 42, 109, -26, 95, 93, 127, >+ 60, 127, -93, -54, -122, 34, -105, 56, 55, 103, 125, -71, >+ -50, 95, -72, 127, 107, 21, 73, 126, 61, 127, 127, 24, >+ -62, 90, 73, 90, -46, -78, -124, 72, 123, -42, 50, -107, >+ 17, -32, -62, -89, 124, 1, 80, -2, 117, 119, -65, -127, >+ -95, -121, -52, 103, 66, 75, -3, -62, -127, 127, -74, 124, >+ 79, 49, 40, 105, -67, -71, -70, 43, 127, 119, -4, 66, >+ 43, 23, 91, -126, 15, 63, -119, 112, 103, 15, -99, 31, >+ -127, 69, 116, -46, -67, 2, -126, -29, 30, 30, -69, -98, >+ -47, -87, -70, -127, 23, -73, 30, -7, 94, -52, -65, 98, >+ -45, 97, 53, 23, -9, -22, -52, -47, 6, -1, -85, -15, >+ -61, -14, 68, 110, -10, -121, -25, -35, -15, -94, -123, 27, >+ 75, 48, -66, -56, -44, 93, 109, 67, -36, 24, 70, -126, >+ 8, -127, 126, 52, 11, -32, 120, -13, -26, -28, -125, 127, >+ 106, -50, 124, 36, -126, -12, 0, -23, 76, -71, -126, -12, >+ -17, -82, 12, 124, 57, 33, 4, 77, -46, 71, -34, 72, >+ 125, -128, 124, -24, -128, 75, -120, 69, -45, 55, 33, 127, >+ -33, 4, -105, -41, -59, -91, 123, 44, -127, 127, -67, 52, >+ 25, -125, -65, 100, -25, 123, 6, 11, -123, -92, -33, 126, >+ -17, -4, 29, 33, 127, 96, 3, 87, -48, -18, -70, 123, >+ 58, -127, -3, -52, -1, -36, -41, 127, 51, -52, -27, 46, >+ -83, 57, 9, 126, 127, 94, 79, -37, -127, -40, 67, 52, >+ 82, -66, 122, -13, -73, 127, -8, -80, 46, -48, 4, -54}; >+ >+const int8_t kHiddenGruBias[kHiddenLayerBiases] = { >+ 124, 125, -57, -126, 53, 123, 127, -75, 68, 102, -2, 116, >+ 124, 127, 124, 125, 126, 123, -16, 48, 125, 126, 78, 85, >+ 11, 126, -30, -30, -64, -3, -105, -29, -17, 69, 63, 2, >+ -32, -10, -62, 113, -52, 112, -109, 112, 7, -40, 73, 53, >+ 62, 6, -2, 0, 0, 100, -16, 26, -24, 56, 26, -10, >+ -33, 41, 70, 109, -29, 127, 34, -66, 49, 53, 27, 62}; >+ >+const int8_t kOutputDenseWeights[kOutputLayerWeights] = { >+ 127, 127, 127, 127, 127, 20, 127, -126, -126, -54, 14, 125, >+ -126, -126, 127, -125, -126, 127, -127, -127, -57, -30, 127, 80}; >+ >+const int8_t kOutputDenseBias[kOutputLayerOutputSize] = {-50}; >+ >+} // namespace rnnoise >diff --git a/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.h b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.h >new file mode 100644 >index 00000000000..d55e33ddad7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/third_party/rnnoise/src/rnn_vad_weights.h >@@ -0,0 +1,37 @@ >+#ifndef THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_ >+#define THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_ >+ >+#include <cstdint> >+#include <cstring> >+ >+namespace rnnoise { >+ >+// Weights scaling factor. >+const float kWeightsScale = 1.f / 256.f; >+ >+// Input layer (dense). >+const size_t kInputLayerInputSize = 42; >+const size_t kInputLayerOutputSize = 24; >+const size_t kInputLayerWeights = kInputLayerInputSize * kInputLayerOutputSize; >+extern const int8_t kInputDenseWeights[kInputLayerWeights]; >+extern const int8_t kInputDenseBias[kInputLayerOutputSize]; >+ >+// Hidden layer (GRU). >+const size_t kHiddenLayerOutputSize = 24; >+const size_t kHiddenLayerWeights = >+ 3 * kInputLayerOutputSize * kHiddenLayerOutputSize; >+const size_t kHiddenLayerBiases = 3 * kHiddenLayerOutputSize; >+extern const int8_t kHiddenGruWeights[kHiddenLayerWeights]; >+extern const int8_t kHiddenGruRecurrentWeights[kHiddenLayerWeights]; >+extern const int8_t kHiddenGruBias[kHiddenLayerBiases]; >+ >+// Output layer (dense). >+const size_t kOutputLayerOutputSize = 1; >+const size_t kOutputLayerWeights = >+ kHiddenLayerOutputSize * kOutputLayerOutputSize; >+extern const int8_t kOutputDenseWeights[kOutputLayerWeights]; >+extern const int8_t kOutputDenseBias[kOutputLayerOutputSize]; >+ >+} // namespace rnnoise >+ >+#endif // THIRD_PARTY_RNNOISE_SRC_RNN_VAD_WEIGHTS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/.git-blame-ignore-revs b/Source/ThirdParty/libwebrtc/Source/webrtc/.git-blame-ignore-revs >index dfa1db349d7..8f312425bb1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/.git-blame-ignore-revs >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/.git-blame-ignore-revs >@@ -18,3 +18,5 @@ > > # Format all Java in WebRTC. > b6760f9e4442410f2bcb6090b3b89bf709e2fce2 >+# Format all C++ in WebRTC. >+665174fdbb4e0540eccb27cf7412348f1b65534c >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/.gitignore b/Source/ThirdParty/libwebrtc/Source/webrtc/.gitignore >index bb2e7420f0f..bf937369ae8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/.gitignore >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/.gitignore >@@ -37,4 +37,34 @@ > .pydevproject > .settings > .sw? >+/Makefile >+/base >+/build >+/buildtools >+/ios >+/mojo >+/out >+/testing >+/third_party >+/tools >+/tools_webrtc/android/profiling/flamegraph >+/tools_webrtc/android/profiling/simpleperf >+/tools_webrtc/audio_quality/linux/pesq >+/tools_webrtc/audio_quality/linux/PolqaOem64 >+/tools_webrtc/audio_quality/mac/pesq >+/tools_webrtc/audio_quality/win/*.exe >+/tools_webrtc/audio_quality/win/*.dll >+/tools_webrtc/video_quality_toolchain/linux/ffmpeg >+/tools_webrtc/video_quality_toolchain/linux/frame_analyzer >+/tools_webrtc/video_quality_toolchain/linux/zxing >+/tools_webrtc/video_quality_toolchain/mac/ffmpeg >+/tools_webrtc/video_quality_toolchain/mac/zxing >+/tools_webrtc/video_quality_toolchain/win/*.dll >+/tools_webrtc/video_quality_toolchain/win/*.exe >+/rtc_tools/testing/*.zip >+/rtc_tools/testing/*.gz >+/rtc_tools/testing/golang/*/*.gz >+/rtc_tools/testing/golang/*/*.zip >+/x86-generic_out/ >+/xcodebuild > !webrtc/* >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/.gn >index 5e3c6ca9aff..9110455155b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/.gn >@@ -42,7 +42,6 @@ check_targets = [ > "//system_wrappers/*", > "//test/*", > "//video/*", >- "//voice_engine/*", > "//third_party/libyuv/*", > ] > >@@ -67,6 +66,10 @@ default_args = { > # http://bugs.webrtc.org/8570 > ios_deployment_target = "9.0" > >+ # The SDK API level, in contrast, is set by build/android/AndroidManifest.xml. >+ android32_ndk_api_level = 16 >+ android64_ndk_api_level = 21 >+ > # WebRTC does not want to switch to C++14 yet. > use_cxx11 = true > >@@ -76,4 +79,6 @@ default_args = { > # WebRTC does not provide the gflags dependency. Because libyuv uses it only > # for unittests, it can be disabled (see third_party/libyuv/BUILD.gn) > libyuv_use_gflags = false >+ >+ gtest_enable_absl_printers = true > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/.vpython b/Source/ThirdParty/libwebrtc/Source/webrtc/.vpython >index cf74427542e..05bbe14fde4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/.vpython >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/.vpython >@@ -30,3 +30,33 @@ wheel: < > name: "infra/python/wheels/psutil/${platform}_${py_python}_${py_abi}" > version: "version:5.2.2" > > >+ >+# Used by: >+# build/toolchain/win >+wheel: < >+ name: "infra/python/wheels/pypiwin32/${vpython_platform}" >+ version: "version:219" >+ match_tag: < >+ platform: "win32" >+ > >+ match_tag: < >+ platform: "win_amd64" >+ > >+> >+ >+wheel: < >+ name: "infra/python/wheels/six-py2_py3" >+ version: "version:1.10.0" >+> >+wheel: < >+ name: "infra/python/wheels/pbr-py2_py3" >+ version: "version:3.0.0" >+> >+wheel: < >+ name: "infra/python/wheels/funcsigs-py2_py3" >+ version: "version:1.0.2" >+> >+wheel: < >+ name: "infra/python/wheels/mock-py2_py3" >+ version: "version:2.0.0" >+> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/AUTHORS b/Source/ThirdParty/libwebrtc/Source/webrtc/AUTHORS >index 6fe77482297..41833d090bf 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/AUTHORS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/AUTHORS >@@ -14,6 +14,7 @@ Chris Tserng <tserng@amazon.com> > Christophe Dumez <ch.dumez@samsung.com> > Cody Barnes <conceptgenesis@gmail.com> > Colin Plumb >+David Porter <david@porter.me> > Dax Booysen <dax@younow.com> > Dmitry Lizin <sdkdimon@gmail.com> > Eric Rescorla, RTFM Inc. <ekr@rtfm.com> >@@ -24,20 +25,24 @@ Gustavo Garcia <gustavogb@gmail.com> > Hugues Ekra <hekra01@gmail.com> > Jake Hilton <jakehilton@gmail.com> > James H. Brown <jbrown@burgoyne.com> >+Jan Kalab <pitlicek@gmail.com> > Jens Nielsen <jens.nielsen@berotec.se> > Jiawei Ou <jiawei.ou@gmail.com> > Jie Mao <maojie0924@gmail.com> > Luke Weber <luke.weber@gmail.com> >+Maksim Khobat <maksimkhobat@gmail.com> > Mallikarjuna Rao V <vm.arjun@samsung.com> > Manish Jethani <manish.jethani@gmail.com> > Martin Storsjo <martin@martin.st> > Matthias Liebig <matthias.gcode@gmail.com> > Maxim Potapov <vopatop.skam@gmail.com> >+Michael Iedema <michael@kapsulate.com> > Mike Gilbert <floppymaster@gmail.com> > Mo Zanaty <mzanaty@cisco.com> > Pali Rohar > Paul Kapustin <pkapustin@gmail.com> > Philipp Hancke <philipp.hancke@googlemail.com> >+Peng Yu <yupeng323@gmail.com> > Rafael Lopez Diez <rafalopezdiez@gmail.com> > Ralph Giles <giles@ghostscript.com> > Riku Voipio <riku.voipio@linaro.org> >@@ -59,6 +64,10 @@ Yura Yaroshevich <yura.yaroshevich@gmail.com> > Hans Knoechel <hans@hans-knoechel.de> > Korniltsev Anatoly <korniltsev.anatoly@gmail.com> > Todd Wong <todd.wong.ndq@gmail.com> >+Sergio Garcia Murillo <sergio.garcia.murillo@gmail.com> >+Maxim Pavlov <pavllovmax@gmail.com> >+Yusuke Suzuki <utatane.tea@gmail.com> >+Piasy Xu <xz4215@gmail.com> > > &yet LLC <*@andyet.com> > Agora IO <*@agora.io> >@@ -66,6 +75,7 @@ ARM Holdings <*@arm.com> > BroadSoft Inc. <*@broadsoft.com> > Facebook Inc. <*@fb.com> > Google Inc. <*@google.com> >+HyperConnect Inc. <*@hpcnt.com> > Life On Air Inc. <*@lifeonair.com> > Intel Corporation <*@intel.com> > MIPS Technologies <*@mips.com> >@@ -78,6 +88,10 @@ Telenor Digital AS <*@telenor.com> > Temasys Communications <*@temasys.io> > The Chromium Authors <*@chromium.org> > The WebRTC Authors <*@webrtc.org> >+Videxio AS <*@videxio.com> > Vonage Holdings Corp. <*@vonage.com> > Wire Swiss GmbH <*@wire.com> > Miguel Paris <mparisdiaz@gmail.com> >+Vewd Software AS <*@vewd.com> >+Highfive, Inc. <*@highfive.com> >+CoSMo Software Consulting, Pte Ltd <*@cosmosoftware.io> >\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/BUILD.gn >index 2f48b6735a6..3ae4500f393 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/BUILD.gn >@@ -43,6 +43,7 @@ if (!build_with_chromium) { > ":video_engine_tests", > ":webrtc_nonparallel_tests", > ":webrtc_perf_tests", >+ "call:fake_network_unittests", > "common_audio:common_audio_unittests", > "common_video:common_video_unittests", > "media:rtc_media_unittests", >@@ -63,12 +64,11 @@ if (!build_with_chromium) { > "video:screenshare_loopback", > "video:sv_loopback", > "video:video_loopback", >- "voice_engine:voice_engine_unittests", > ] > if (is_android) { > deps += [ > ":android_junit_tests", >- "sdk/android:libjingle_peerconnection_android_unittest", >+ "sdk/android:android_instrumentation_test_apk", > ] > } else { > deps += [ "modules/video_capture:video_capture_tests" ] >@@ -93,6 +93,10 @@ config("common_inherited_config") { > defines += [ "WEBRTC_MOZILLA_BUILD" ] > } > >+ if (!rtc_builtin_ssl_root_certificates) { >+ defines += [ "WEBRTC_EXCLUDE_BUILT_IN_SSL_ROOT_CERTS" ] >+ } >+ > # Some tests need to declare their own trace event handlers. If this define is > # not set, the first time TRACE_EVENT_* is called it will store the return > # value for the current handler in an static variable, so that subsequent >@@ -105,13 +109,7 @@ config("common_inherited_config") { > defines += [ "WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=0" ] > } > if (build_with_chromium) { >- defines += [ >- # TODO(kjellander): Cleanup unused ones and move defines closer to >- # the source when webrtc:4256 is completed. >- "FEATURE_ENABLE_VOICEMAIL", >- "GTEST_RELATIVE_PATH", >- "WEBRTC_CHROMIUM_BUILD", >- ] >+ defines += [ "WEBRTC_CHROMIUM_BUILD" ] > include_dirs = [ > # The overrides must be included first as that is the mechanism for > # selecting the override headers in Chromium. >@@ -122,7 +120,7 @@ config("common_inherited_config") { > ".", > ] > } >- if (is_posix) { >+ if (is_posix || is_fuchsia) { > defines += [ "WEBRTC_POSIX" ] > } > if (is_ios) { >@@ -141,10 +139,7 @@ config("common_inherited_config") { > defines += [ "WEBRTC_FUCHSIA" ] > } > if (is_win) { >- defines += [ >- "WEBRTC_WIN", >- "_CRT_SECURE_NO_WARNINGS", # Suppress warnings about _vsnprinf >- ] >+ defines += [ "WEBRTC_WIN" ] > } > if (is_android) { > defines += [ >@@ -169,22 +164,13 @@ config("common_inherited_config") { > if (is_ubsan) { > cflags += [ "-fsanitize=float-cast-overflow" ] > } >- >- # TODO(GYP): Support these in GN. >- # if (is_bsd) { >- # defines += [ "BSD" ] >- # } >- # if (is_openbsd) { >- # defines += [ "OPENBSD" ] >- # } >- # if (is_freebsd) { >- # defines += [ "FREEBSD" ] >- # } > } > > config("common_config") { > cflags = [] >+ cflags_c = [] > cflags_cc = [] >+ cflags_objc = [] > defines = [] > > if (rtc_enable_protobuf) { >@@ -193,10 +179,6 @@ config("common_config") { > defines += [ "WEBRTC_ENABLE_PROTOBUF=0" ] > } > >- if (rtc_restrict_logging) { >- defines += [ "WEBRTC_RESTRICT_LOGGING" ] >- } >- > if (rtc_include_internal_audio_device) { > defines += [ "WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE" ] > } >@@ -213,6 +195,10 @@ config("common_config") { > defines += [ "ENABLE_EXTERNAL_AUTH" ] > } > >+ if (rtc_use_builtin_sw_codecs) { >+ defines += [ "USE_BUILTIN_SW_CODECS" ] >+ } >+ > if (build_with_chromium) { > defines += [ > # NOTICE: Since common_inherited_config is used in public_configs for our >@@ -222,10 +208,9 @@ config("common_config") { > "HAVE_WEBRTC_VIDEO", > "HAVE_WEBRTC_VOICE", > "LOGGING_INSIDE_WEBRTC", >- "USE_WEBRTC_DEV_BRANCH", > ] > } else { >- if (is_posix) { >+ if (is_posix || is_fuchsia) { > # Enable more warnings: -Wextra is currently disabled in Chromium. > cflags = [ > "-Wextra", >@@ -233,8 +218,21 @@ config("common_config") { > # Repeat some flags that get overridden by -Wextra. > "-Wno-unused-parameter", > "-Wno-missing-field-initializers", >- "-Wno-strict-overflow", > ] >+ cflags_c += [ >+ # TODO(bugs.webrtc.org/9029): enable commented compiler flags. >+ # Some of these flags should also be added to cflags_objc. >+ >+ # "-Wextra", (used when building C++ but not when building C) >+ # "-Wmissing-prototypes", (C/Obj-C only) >+ # "-Wmissing-declarations", (ensure this is always used C/C++, etc..) >+ "-Wstrict-prototypes", >+ >+ # "-Wpointer-arith", (ensure this is always used C/C++, etc..) >+ # "-Wbad-function-cast", (C/Obj-C only) >+ # "-Wnested-externs", (C/Obj-C only) >+ ] >+ cflags_objc += [ "-Wstrict-prototypes" ] > cflags_cc = [ > "-Wnon-virtual-dtor", > >@@ -261,6 +259,13 @@ config("common_config") { > cflags += [ "-Wunused-lambda-capture" ] > } > } >+ >+ if (is_win && !is_clang) { >+ # MSVC warning suppressions (needed to use Abseil). >+ # TODO(bugs.webrtc.org/9274): Remove these warnings as soon as MSVC allows >+ # external headers warning suppression (or fix them upstream). >+ cflags += [ "/wd4702" ] # unreachable code >+ } > } > > if (current_cpu == "arm64") { >@@ -307,7 +312,7 @@ config("common_config") { > ] > } > >- if (use_libfuzzer || use_drfuzz || use_afl) { >+ if (use_fuzzing_engine && optimize_for_fuzzing) { > # Used in Chromium's overrides to disable logging > defines += [ "WEBRTC_UNSAFE_FUZZER_MODE" ] > } >@@ -325,6 +330,7 @@ if (!build_with_chromium) { > > sources = [] > complete_static_lib = true >+ suppressed_configs += [ "//build/config/compiler:thin_archive" ] > defines = [] > > deps = [ >@@ -342,12 +348,22 @@ if (!build_with_chromium) { > "sdk", > "system_wrappers:system_wrappers_default", > "video", >- "voice_engine", >+ ] >+ >+ # Additional factory functions to be exposed. >+ # Rational: These factories are small enough (89 KiB / 32+ MiB) >+ # to be unconditionaly included for user convenience. >+ # That begin said: >+ # TODO(yvesg) Consider making all non-core APIs optional, so that users >+ # can build a customized library tailored to their needs. >+ deps += [ >+ "api/audio_codecs:builtin_audio_decoder_factory", >+ "api/audio_codecs:builtin_audio_encoder_factory", > ] > > if (build_with_mozilla) { > deps += [ >- "api:video_frame_api", >+ "api/video:video_frame", > "system_wrappers:field_trial_default", > "system_wrappers:metrics_default", > ] >@@ -368,21 +384,13 @@ if (!build_with_chromium) { > } > } > >-rtc_source_set("typedefs") { >- sources = [ >- "typedefs.h", >- ] >-} >- >-rtc_static_library("webrtc_common") { >+rtc_source_set("webrtc_common") { > sources = [ >- "common_types.cc", > "common_types.h", > ] > deps = [ >- ":typedefs", > "api:array_view", >- "api:optional", >+ "api/video:video_bitrate_allocation", > "rtc_base:checks", > "rtc_base:deprecation", > "rtc_base:stringutils", >@@ -406,25 +414,16 @@ if (use_libfuzzer || use_drfuzz || use_afl) { > } > > if (rtc_include_tests) { >- config("rtc_unittests_config") { >- # GN orders flags on a target before flags from configs. The default config >- # adds -Wall, and this flag have to be after -Wall -- so they need to >- # come from a config and can"t be on the target directly. >- if (is_clang) { >- cflags = [ >- "-Wno-sign-compare", >- "-Wno-unused-const-variable", >- ] >- } >- } >- > rtc_test("rtc_unittests") { > testonly = true > > deps = [ > ":webrtc_common", > "api:rtc_api_unittests", >+ "api/audio/test:audio_api_unittests", > "api/audio_codecs/test:audio_codecs_api_unittests", >+ "api/video/test:rtc_api_video_unittests", >+ "api/video_codecs/test:video_codecs_api_unittests", > "p2p:libstunprober_unittests", > "p2p:rtc_p2p_unittests", > "rtc_base:rtc_base_approved_unittests", >@@ -434,7 +433,9 @@ if (rtc_include_tests) { > "rtc_base:rtc_numerics_unittests", > "rtc_base:rtc_task_queue_unittests", > "rtc_base:sequenced_task_checker_unittests", >+ "rtc_base:sigslot_unittest", > "rtc_base:weak_ptr_unittests", >+ "rtc_base/experiments:experiments_unittests", > "system_wrappers:metrics_default", > "system_wrappers:runtime_enabled_features_default", > ] >@@ -444,12 +445,19 @@ if (rtc_include_tests) { > } > > if (is_android) { >- deps += [ "//testing/android/native_test:native_test_support" ] >+ # Do not use Chromium's launcher. native_unittests defines its own JNI_OnLoad. >+ use_default_launcher = false >+ >+ deps += [ >+ "sdk/android:native_unittests", >+ "sdk/android:native_unittests_java", >+ "//testing/android/native_test:native_test_support", >+ ] > shard_timeout = 900 > } > > if (is_ios || is_mac) { >- deps += [ "sdk:sdk_unittests_objc" ] >+ deps += [ "sdk:rtc_unittests_objc" ] > } > } > >@@ -526,14 +534,13 @@ if (rtc_include_tests) { > > rtc_test("webrtc_perf_tests") { > testonly = true >- configs += [ ":rtc_unittests_config" ] >- > deps = [ > "audio:audio_perf_tests", > "call:call_perf_tests", > "modules/audio_coding:audio_coding_perf_tests", > "modules/audio_processing:audio_processing_perf_tests", > "modules/remote_bitrate_estimator:remote_bitrate_estimator_perf_tests", >+ "pc:peerconnection_perf_tests", > "test:test_main", > "video:video_full_stack_tests", > ] >@@ -566,13 +573,35 @@ if (rtc_include_tests) { > "examples/androidjunit/src/org/appspot/apprtc/DirectRTCClientTest.java", > "examples/androidjunit/src/org/appspot/apprtc/TCPChannelClientTest.java", > "sdk/android/tests/src/org/webrtc/CameraEnumerationTest.java", >+ "sdk/android/tests/src/org/webrtc/CodecTestHelper.java", >+ "sdk/android/tests/src/org/webrtc/FakeMediaCodecWrapper.java", >+ "sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java", >+ "sdk/android/tests/src/org/webrtc/HardwareVideoEncoderTest.java", >+ "sdk/android/tests/src/org/webrtc/HardwareVideoDecoderTest.java", >+ "sdk/android/tests/src/org/webrtc/ScalingSettingsTest.java", > ] > > deps = [ > "examples:AppRTCMobile_javalib", > "sdk/android:libjingle_peerconnection_java", > "//base:base_java_test_support", >+ "//third_party/google-truth:google_truth_java", > ] > } > } > } >+ >+# ---- Poisons ---- >+# >+# Here is one empty dummy target for each poison type (needed because >+# "being poisonous with poison type foo" is implemented as "depends on >+# //:poison_foo"). >+# >+# The set of poison_* targets needs to be kept in sync with the >+# `all_poison_types` list in webrtc.gni. >+# >+group("poison_audio_codecs") { >+} >+ >+group("poison_software_video_codecs") { >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/DEPS >index 7a50227de5e..2512bc9fa35 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/DEPS >@@ -7,20 +7,16 @@ vars = { > 'checkout_configuration': 'default', > 'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"', > 'webrtc_git': 'https://webrtc.googlesource.com', >- 'chromium_revision': '97bf3ad18eb9c822964de681b94f7f880711c932', >+ 'chromium_revision': '012c9b03138d1b8398b756565826b93d95cf8277', > 'boringssl_git': 'https://boringssl.googlesource.com', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling swarming_client > # and whatever else without interference from each other. >- 'swarming_revision': '88229872dd17e71658fe96763feaa77915d8cbd6', >- # Three lines of non-changing comments so that >- # the commit queue can handle CLs rolling openmax_dl >- # and whatever else without interference from each other. >- 'openmax_dl_revision': 'b611996df3b8f6b151339d22c12c21f167009cb6', >+ 'swarming_revision': '486c9b53c4d54dd4b95bb6ce0e31160e600dfc11', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling BoringSSL > # and whatever else without interference from each other. >- 'boringssl_revision': '94cd196a80252c98e329e979870f2a462cc4f402', >+ 'boringssl_revision': '6b0d82229b2c4ce85b1c3f6d55bda661e07bead2', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling lss > # and whatever else without interference from each other. >@@ -28,39 +24,53 @@ vars = { > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling catapult > # and whatever else without interference from each other. >- 'catapult_revision': '785486272fdd040ffc53214deaa8d30a293df6f2', >+ 'catapult_revision': 'ed63b1319414a36b099cad8443d497bda8f085a2', > # Three lines of non-changing comments so that > # the commit queue can handle CLs rolling libFuzzer > # and whatever else without interference from each other. >- 'libfuzzer_revision': 'ba2c1cd6f87accb32b5dbce297387c56a2e53a2f', >+ 'libfuzzer_revision': '658ff786a213703ff0df6ba4a288e9a1e218c074', >+ # Three lines of non-changing comments so that >+ # the commit queue can handle CLs rolling freetype >+ # and whatever else without interference from each other. >+ 'freetype_revision': '96b5e500909cfce39ff78feabefd8063a229b951', >+ # Three lines of non-changing comments so that >+ # the commit queue can handle CLs rolling HarfBuzz >+ # and whatever else without interference from each other. >+ 'harfbuzz_revision': '22defe0965adddaa09eebc13df7fa6c64e2abba3', > } > deps = { > # TODO(kjellander): Move this to be Android-only once the libevent dependency > # in base/third_party/libevent is solved. > 'src/base': >- Var('chromium_git') + '/chromium/src/base' + '@' + 'dc7e66bd14356929c632bd3ebf304092ae9a07fa', >+ Var('chromium_git') + '/chromium/src/base' + '@' + '33838037fc6db947c6bb42d50c0b9d4da18c04c1', > 'src/build': >- Var('chromium_git') + '/chromium/src/build' + '@' + '2c4f0d08ec19c5be2c3bcb2e35c5bcebd6a61fc3', >+ Var('chromium_git') + '/chromium/src/build' + '@' + '48f1034a8c3bbc18ce994eaf7dbbc158a4789cf9', > 'src/buildtools': >- Var('chromium_git') + '/chromium/buildtools.git' + '@' + '6fe4a3251488f7af86d64fc25cf442e817cf6133', >+ Var('chromium_git') + '/chromium/buildtools.git' + '@' + '2dff9c9c74e9d732e6fe57c84ef7fd044cc45d96', >+ # Gradle 4.3-rc4. Used for testing Android Studio project generation for WebRTC. >+ 'src/examples/androidtests/third_party/gradle': { >+ 'url': Var('chromium_git') + '/external/github.com/gradle/gradle.git' + '@' + >+ '89af43c4d0506f69980f00dde78c97b2f81437f8', >+ 'condition': 'checkout_android', >+ }, > 'src/ios': { >- 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + '406d7b7ac94709f7b8ee20dd6feebe8c722a78af', >+ 'url': Var('chromium_git') + '/chromium/src/ios' + '@' + 'a2b3d838cc8e71f50108611600a57061ba90283f', > 'condition': 'checkout_ios', > }, > 'src/testing': >- Var('chromium_git') + '/chromium/src/testing' + '@' + 'e3baccadac00d406bb2c6011c3c80531204af782', >+ Var('chromium_git') + '/chromium/src/testing' + '@' + 'bc0a21b479692b7bf7a96ce5bb84cce79d655e97', > 'src/third_party': >- Var('chromium_git') + '/chromium/src/third_party' + '@' + 'f01e063dc62a220110fa5a0250fd60b0ed18ab95', >+ Var('chromium_git') + '/chromium/src/third_party' + '@' + '71a1eaaf86eddb7d6a327fc6b8905a0f0be361bf', > 'src/third_party/android_ndk': { >- 'url': Var('chromium_git') + '/android_ndk.git' + '@' + 'e951c37287c7d8cd915bf8d4149fd4a06d808b55', >+ 'url': Var('chromium_git') + '/android_ndk.git' + '@' + '4e2cea441bfd43f0863d14f57b1e1844260b9884', > 'condition': 'checkout_android', > }, > 'src/third_party/android_tools': { >- 'url': Var('chromium_git') + '/android_tools.git' + '@' + 'c78b25872734e0038ae2a333edc645cd96bc232d', >+ 'url': Var('chromium_git') + '/android_tools.git' + '@' + '130499e25286f4d56acafa252fee09f3cc595c49', > 'condition': 'checkout_android', > }, > 'src/third_party/auto/src': { >- 'url': Var('chromium_git') + '/external/github.com/google/auto.git' + '@' + '71802f2ae74dae2744abd999f8434e13055c4ee3', >+ 'url': Var('chromium_git') + '/external/github.com/google/auto.git' + '@' + '8a81a858ae7b78a1aef71ac3905fade0bbd64e82', > 'condition': 'checkout_android', > }, > 'src/third_party/boringssl/src': >@@ -74,24 +84,28 @@ deps = { > 'src/third_party/colorama/src': > Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', > 'src/third_party/depot_tools': >- Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '5d6b00fac64a829cca5637bb76abe618291b8b60', >+ Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'efb38bb3d729f9d5b27f5202c766d43186c0103a', > 'src/third_party/errorprone/lib': { >- 'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + 'ecc57c2b00627667874744b9ad8efe10734d97a8', >+ 'url': Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '980d49e839aa4984015efed34b0134d4b2c9b6d7', > 'condition': 'checkout_android', > }, > 'src/third_party/ffmpeg': >- Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b64dedac9d1d70148a50791d127eede2e7eb93ba', >+ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '90210b5e10d3917567a3025e4853704bfefd8384', > 'src/third_party/findbugs': { > 'url': Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '4275d9ac8610db6b1bc9a5e887f97e41b33fac67', > 'condition': 'checkout_android', > }, >+ 'src/third_party/freetype/src': >+ Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + Var('freetype_revision'), >+ 'src/third_party/harfbuzz-ng/src': >+ Var('chromium_git') + '/external/github.com/harfbuzz/harfbuzz.git' + '@' + Var('harfbuzz_revision'), > # WebRTC-only dependency (not present in Chromium). > 'src/third_party/gtest-parallel': >- Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + '180c2f52341c065fd4d8418a238375ab6c91b336', >+ Var('chromium_git') + '/external/github.com/google/gtest-parallel' + '@' + 'fe7f791f14769390d0b124ef8231cde4d575eb12', > 'src/third_party/googletest/src': >- Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + '0062e4869f07a3ef235703ddf63af604b712446c', >+ Var('chromium_git') + '/external/github.com/google/googletest.git' + '@' + 'd5266326752f0a1dadbd310932d8f4fd8c3c5e7d', > 'src/third_party/icu': { >- 'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f3d25bcc2e542a10248d5a272219ed7695fe3252', >+ 'url': Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '297a4dd02b9d36c92ab9b4f121e433c9c3bc14f8', > }, > 'src/third_party/jsr-305/src': { > 'url': Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919', >@@ -109,23 +123,31 @@ deps = { > 'src/third_party/libjpeg_turbo': > Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'a1750dbc79a8792dde3d3f7d7d8ac28ba01ac9dd', > 'src/third_party/libsrtp': >- Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '1d45b8e599dc2db6ea3ae22dbc94a8c504652423', >+ Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '368abd6bb3091df2b354250818714f72f0692ca5', > 'src/third_party/libvpx/source/libvpx': >- Var('chromium_git') + '/webm/libvpx.git' + '@' + 'bed28a55f593efd3a71a3a9d05cf8bb25d15fa44', >+ Var('chromium_git') + '/webm/libvpx.git' + '@' + 'b8642738c9851232c9bb1e1a22474953d3d367cf', > 'src/third_party/libyuv': >- Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '50f9e618fa4bcb0561622fd709bee5da922b0fd4', >+ Var('chromium_git') + '/libyuv/libyuv.git' + '@' + 'd694f0a82b4da9d8ea37e6c453b7a34947eb5790', > 'src/third_party/lss': { > 'url': Var('chromium_git') + '/linux-syscall-support.git' + '@' + Var('lss_revision'), > 'condition': 'checkout_android or checkout_linux', > }, > 'src/third_party/mockito/src': { >- 'url': Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'de83ad4598ad4cf5ea53c69a8a8053780b04b850', >+ 'url': Var('chromium_git') + '/external/mockito/mockito.git' + '@' + '04a2a289a4222f80ad20717c25144981210d2eac', > 'condition': 'checkout_android', > }, > 'src/third_party/openh264/src': >- Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '5a5c4f14f471b9f434a55c39e942153453f25661', >- 'src/third_party/openmax_dl': >- Var('webrtc_git') + '/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), >+ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3b51f16a4a41df729f8d647f03e48c5f272911ff', >+ 'src/third_party/r8': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/r8', >+ 'version': 'version:1.2.28-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, > 'src/third_party/requests/src': { > 'url': Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4', > 'condition': 'checkout_android', >@@ -139,10 +161,10 @@ deps = { > 'condition': 'checkout_android', > }, > 'src/third_party/usrsctp/usrsctplib': >- Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '0e076261b832121cf120ddc04aaff87ac3a34d30', >+ Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '7a8bc9a90ca96634aa56ee712856d97f27d903f8', > # WebRTC-only dependency (not present in Chromium). > 'src/third_party/winsdk_samples': { >- 'url': Var('webrtc_git') + '/deps/third_party/winsdk_samples_v71' + '@' + '2d31a1cbecc86359e6ec041fb9ff6c082babd073', >+ 'url': Var('webrtc_git') + '/deps/third_party/winsdk_samples_v71' + '@' + 'a59391ef795986633735a1695caa97622a9bfd56', > 'condition': 'checkout_win', > }, > # Dependency used by libjpeg-turbo. >@@ -151,13 +173,532 @@ deps = { > 'condition': 'checkout_win', > }, > 'src/third_party/yasm/source/patched-yasm': >- Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc', >+ Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '720b70524a4424b15fc57e82263568c8ba0496ad', > 'src/tools': >- Var('chromium_git') + '/chromium/src/tools' + '@' + 'c2699036532f9ce005eb549703b2d64518cabd7a', >- 'src/tools/gyp': >- Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb', >+ Var('chromium_git') + '/chromium/src/tools' + '@' + 'd6f9a30225a3b6fd4f5509d5727e991f69ea1627', > 'src/tools/swarming_client': > Var('chromium_git') + '/infra/luci/client-py.git' + '@' + Var('swarming_revision'), >+ >+ 'src/third_party/accessibility_test_framework': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/accessibility-test-framework', >+ 'version': 'version:2.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/android_support_test_runner': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_support_test_runner', >+ 'version': 'version:0.5-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/apk-patch-size-estimator': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/apk-patch-size-estimator', >+ 'version': 'version:0.2-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/bazel': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/bazel', >+ 'version': 'version:0.10.0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/bouncycastle': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/bouncycastle', >+ 'version': 'version:1.46-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/byte_buddy': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/byte_buddy', >+ 'version': 'version:1.8.8-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/espresso': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/espresso', >+ 'version': 'version:2.2.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/gson': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/gson', >+ 'version': 'version:2.8.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/guava': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/guava', >+ 'version': 'version:23.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/hamcrest': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/hamcrest', >+ 'version': 'version:1.3-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/icu4j': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/icu4j', >+ 'version': 'version:53.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/intellij': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/intellij', >+ 'version': 'version:12.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/javax_inject': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/javax_inject', >+ 'version': 'version:1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/objenesis': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/objenesis', >+ 'version': 'version:2.4-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/ow2_asm': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/ow2_asm', >+ 'version': 'version:5.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/robolectric': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/robolectric', >+ 'version': 'version:3.5.1', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/sqlite4java': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/sqlite4java', >+ 'version': 'version:0.282-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ 'src/third_party/xstream': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/xstream', >+ 'version': 'version:1.4.8-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ >+ # === ANDROID_DEPS Start === >+ 'src/third_party/android_deps/libs/android_arch_core_common': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/android_arch_core_common', >+ 'version': 'version:1.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/android_arch_lifecycle_common': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_common', >+ 'version': 'version:1.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/android_arch_lifecycle_runtime': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/android_arch_lifecycle_runtime', >+ 'version': 'version:1.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_animated_vector_drawable': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_animated_vector_drawable', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_appcompat_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_appcompat_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_cardview_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_cardview_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_design': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_design', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_gridlayout_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_gridlayout_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_leanback_v17': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_leanback_v17', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_mediarouter_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_mediarouter_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_multidex': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_multidex', >+ 'version': 'version:1.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_palette_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_palette_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_preference_leanback_v17': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_preference_leanback_v17', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_preference_v14': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_preference_v14', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_preference_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_preference_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_recyclerview_v7': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_recyclerview_v7', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_annotations': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_annotations', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_compat': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_compat', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_core_ui': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_core_ui', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_core_utils': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_core_utils', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_fragment': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_fragment', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_media_compat': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_media_compat', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_v13': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_v13', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_v4': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_v4', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_support_vector_drawable': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_support_vector_drawable', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_android_support_transition': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_android_support_transition', >+ 'version': 'version:27.0.0-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_google_android_gms_play_services_base': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_base', >+ 'version': 'version:12.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_auth_base', >+ 'version': 'version:12.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_google_android_gms_play_services_base': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_base', >+ 'version': 'version:12.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_google_android_gms_play_services_basement': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_basement', >+ 'version': 'version:12.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/android_deps/libs/com_google_android_gms_play_services_tasks': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/android_deps/libs/com_google_android_gms_play_services_tasks', >+ 'version': 'version:12.0.1-cr0', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ 'src/third_party/google-truth': { >+ 'packages': [ >+ { >+ 'package': 'chromium/third_party/google-truth', >+ 'version': 'version:0.40', >+ }, >+ ], >+ 'condition': 'checkout_android', >+ 'dep_type': 'cipd', >+ }, >+ # === ANDROID_DEPS End === > } > > hooks = [ >@@ -188,23 +729,62 @@ hooks = [ > ], > }, > { >- # Downloads the current stable linux sysroot to build/linux/ if needed. >- # This sysroot updates at about the same rate that the chrome build deps >- # change. This script is a no-op except for linux users who are doing >- # official chrome builds or cross compiling. >- 'name': 'sysroot', >+ 'name': 'sysroot_arm', >+ 'pattern': '.', >+ 'condition': 'checkout_linux and checkout_arm', >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=arm'], >+ }, >+ { >+ 'name': 'sysroot_arm64', > 'pattern': '.', >- 'condition': 'checkout_linux', >+ 'condition': 'checkout_linux and checkout_arm64', > 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >- '--running-as-hook'], >+ '--arch=arm64'], >+ }, >+ { >+ 'name': 'sysroot_x86', >+ 'pattern': '.', >+ 'condition': 'checkout_linux and (checkout_x86 or checkout_x64)', >+ # TODO(mbonadei): change to --arch=x86. >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=i386'], >+ }, >+ { >+ 'name': 'sysroot_mips', >+ 'pattern': '.', >+ 'condition': 'checkout_linux and checkout_mips', >+ # TODO(mbonadei): change to --arch=mips. >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=mipsel'], >+ }, >+ { >+ 'name': 'sysroot_x64', >+ 'pattern': '.', >+ 'condition': 'checkout_linux and checkout_x64', >+ # TODO(mbonadei): change to --arch=x64. >+ 'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py', >+ '--arch=amd64'], >+ }, >+ { >+ # Case-insensitivity for the Win SDK. Must run before win_toolchain below. >+ 'name': 'ciopfs_linux', >+ 'pattern': '.', >+ 'condition': 'checkout_win and host_os == "linux"', >+ 'action': [ 'python', >+ 'src/third_party/depot_tools/download_from_google_storage.py', >+ '--no_resume', >+ '--no_auth', >+ '--bucket', 'chromium-browser-clang/ciopfs', >+ '-s', 'src/build/ciopfs.sha1', >+ ] > }, > { > # Update the Windows toolchain if necessary. Must run before 'clang' below. > 'name': 'win_toolchain', > 'pattern': '.', >- # TODO(thakis): Put some condition here. Not just host_os == 'win', because >- # we also need this for (mac|linux) -> win cross builds. >- 'action': ['python', 'src/build/vs_toolchain.py', 'update'], >+ 'condition': 'checkout_win', >+ 'action': ['python', 'src/build/vs_toolchain.py', 'update', '--force'], > }, > { > # Update the Mac toolchain if necessary. >@@ -386,18 +966,6 @@ hooks = [ > '-d', 'src/tools/luci-go/linux64', > ], > }, >- # Pull the Syzygy binaries, used for optimization and instrumentation. >- { >- 'name': 'syzygy-binaries', >- 'pattern': '.', >- 'condition': 'host_os == "win"', >- 'action': ['python', >- 'src/build/get_syzygy_binaries.py', >- '--output-dir=src/third_party/syzygy/binaries', >- '--revision=a8456d9248a126881dcfb8707ca7dcdae56e1ac7', >- '--overwrite', >- ], >- }, > { > 'name': 'msan_chained_origins', > 'pattern': '.', >@@ -434,15 +1002,6 @@ hooks = [ > '--bucket', 'chromium-webrtc-resources', > 'src/resources'], > }, >- { >- 'name': 'Android CIPD Ensure', >- 'pattern': '.', >- 'condition': 'checkout_android', >- 'action': ['src/build/cipd/cipd_wrapper.py', >- '--chromium-root', 'src', >- '--ensure-file', 'src/build/cipd/android/android.ensure', >- ], >- }, > { > # This downloads SDK extras and puts them in the > # third_party/android_tools/sdk/extras directory. >@@ -473,11 +1032,9 @@ include_rules = [ > "-chromium", > "+external/webrtc/webrtc", # Android platform build. > "+libyuv", >- # Individual headers that will be moved out of here, see webrtc:4243. >- "+call/rtp_config.h", >+ >+ # These should eventually move out of here. > "+common_types.h", >- "+transport.h", >- "+typedefs.h", > > "+WebRTC", > "+api", >@@ -485,14 +1042,10 @@ include_rules = [ > "+rtc_base", > "+test", > "+rtc_tools", >-] > >-# The below rules will be removed when webrtc:4243 is fixed. >-specific_include_rules = { >- "video_receive_stream\.h": [ >- "+call/video_receive_stream.h", >- ], >- "video_send_stream\.h": [ >- "+call/video_send_stream.h", >- ], >-} >+ # Abseil whitelist. >+ "+absl/container/inlined_vector.h", >+ "+absl/memory/memory.h", >+ "+absl/types/optional.h", >+ "+absl/types/variant.h", >+] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/LICENSE_THIRD_PARTY b/Source/ThirdParty/libwebrtc/Source/webrtc/LICENSE_THIRD_PARTY >deleted file mode 100644 >index af1aa50d37e..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/LICENSE_THIRD_PARTY >+++ /dev/null >@@ -1,458 +0,0 @@ >-This source tree contains third party source code which is governed by third >-party licenses. Paths to the files and associated licenses are collected here. >- >-Files governed by third party licenses: >-base/base64.cc >-base/base64.h >-base/md5.cc >-base/md5.h >-base/sha1.cc >-base/sha1.h >-base/sigslot.cc >-base/sigslot.h >-common_audio/fft4g.c >-common_audio/signal_processing/spl_sqrt_floor.c >-common_audio/signal_processing/spl_sqrt_floor_arm.S >-modules/audio_coding/codecs/g711/main/source/g711.c >-modules/audio_coding/codecs/g711/main/source/g711.h >-modules/audio_coding/codecs/g722/main/source/g722_decode.c >-modules/audio_coding/codecs/g722/main/source/g722_enc_dec.h >-modules/audio_coding/codecs/g722/main/source/g722_encode.c >-modules/audio_coding/codecs/isac/main/source/fft.c >-modules/audio_device/mac/portaudio/pa_memorybarrier.h >-modules/audio_device/mac/portaudio/pa_ringbuffer.c >-modules/audio_device/mac/portaudio/pa_ringbuffer.h >-modules/audio_processing/aec/aec_rdft.c >-system_wrappers/source/condition_variable_event_win.cc >-system_wrappers/source/set_thread_name_win.h >- >-Individual licenses for each file: >-------------------------------------------------------------------------------- >-Files: >-base/base64.cc >-base/base64.h >- >-License: >-//********************************************************************* >-//* Base64 - a simple base64 encoder and decoder. >-//* >-//* Copyright (c) 1999, Bob Withers - bwit@pobox.com >-//* >-//* This code may be freely used for any purpose, either personal >-//* or commercial, provided the authors copyright notice remains >-//* intact. >-//* >-//* Enhancements by Stanley Yamane: >-//* o reverse lookup table for the decode function >-//* o reserve string buffer space in advance >-//* >-//********************************************************************* >-------------------------------------------------------------------------------- >-Files: >-base/md5.cc >-base/md5.h >- >-License: >-/* >- * This code implements the MD5 message-digest algorithm. >- * The algorithm is due to Ron Rivest. This code was >- * written by Colin Plumb in 1993, no copyright is claimed. >- * This code is in the public domain; do with it what you wish. >- * >-------------------------------------------------------------------------------- >-Files: >-base/sha1.cc >-base/sha1.h >- >-License: >-/* >- * SHA-1 in C >- * By Steve Reid <sreid@sea-to-sky.net> >- * 100% Public Domain >- * >- * ----------------- >- * Modified 7/98 >- * By James H. Brown <jbrown@burgoyne.com> >- * Still 100% Public Domain >- * >-------------------------------------------------------------------------------- >-Files: >-base/sigslot.cc >-base/sigslot.h >- >-License: >-// sigslot.h: Signal/Slot classes >-// >-// Written by Sarah Thompson (sarah@telergy.com) 2002. >-// >-// License: Public domain. You are free to use this code however you like, with >-// the proviso that the author takes on no responsibility or liability for any >-// use. >-------------------------------------------------------------------------------- >-Files: >-common_audio/signal_processing/spl_sqrt_floor.c >-common_audio/signal_processing/spl_sqrt_floor_arm.S >- >-License: >-/* >- * Written by Wilco Dijkstra, 1996. The following email exchange establishes the >- * license. >- * >- * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> >- * Date: Fri, Jun 24, 2011 at 3:20 AM >- * Subject: Re: sqrt routine >- * To: Kevin Ma <kma@google.com> >- * Hi Kevin, >- * Thanks for asking. Those routines are public domain (originally posted to >- * comp.sys.arm a long time ago), so you can use them freely for any purpose. >- * Cheers, >- * Wilco >- * >- * ----- Original Message ----- >- * From: "Kevin Ma" <kma@google.com> >- * To: <Wilco.Dijkstra@ntlworld.com> >- * Sent: Thursday, June 23, 2011 11:44 PM >- * Subject: Fwd: sqrt routine >- * Hi Wilco, >- * I saw your sqrt routine from several web sites, including >- * http://www.finesse.demon.co.uk/steven/sqrt.html. >- * Just wonder if there's any copyright information with your Successive >- * approximation routines, or if I can freely use it for any purpose. >- * Thanks. >- * Kevin >- */ >-------------------------------------------------------------------------------- >-Files: >-modules/audio_coding/codecs/g711/main/source/g711.c >-modules/audio_coding/codecs/g711/main/source/g711.h >- >-License: >-/* >- * SpanDSP - a series of DSP components for telephony >- * >- * g711.h - In line A-law and u-law conversion routines >- * >- * Written by Steve Underwood <steveu@coppice.org> >- * >- * Copyright (C) 2001 Steve Underwood >- * >- * Despite my general liking of the GPL, I place this code in the >- * public domain for the benefit of all mankind - even the slimy >- * ones who might try to proprietize my work and use it to my >- * detriment. >- */ >-------------------------------------------------------------------------------- >-Files: >-modules/audio_coding/codecs/g722/main/source/g722_decode.c >-modules/audio_coding/codecs/g722/main/source/g722_enc_dec.h >-modules/audio_coding/codecs/g722/main/source/g722_encode.c >- >-License: >-/* >- * SpanDSP - a series of DSP components for telephony >- * >- * g722_decode.c - The ITU G.722 codec, decode part. >- * >- * Written by Steve Underwood <steveu@coppice.org> >- * >- * Copyright (C) 2005 Steve Underwood >- * >- * Despite my general liking of the GPL, I place my own contributions >- * to this code in the public domain for the benefit of all mankind - >- * even the slimy ones who might try to proprietize my work and use it >- * to my detriment. >- * >- * Based in part on a single channel G.722 codec which is: >- * >- * Copyright (c) CMU 1993 >- * Computer Science, Speech Group >- * Chengxiang Lu and Alex Hauptmann >- */ >-------------------------------------------------------------------------------- >-Files: >-modules/audio_coding/codecs/isac/main/source/fft.c >- >-License: >-/* >- * Copyright(c)1995,97 Mark Olesen <olesen@me.QueensU.CA> >- * Queen's Univ at Kingston (Canada) >- * >- * Permission to use, copy, modify, and distribute this software for >- * any purpose without fee is hereby granted, provided that this >- * entire notice is included in all copies of any software which is >- * or includes a copy or modification of this software and in all >- * copies of the supporting documentation for such software. >- * >- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR >- * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S >- * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY >- * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS >- * FITNESS FOR ANY PARTICULAR PURPOSE. >- * >- * All of which is to say that you can do what you like with this >- * source code provided you don't try to sell it as your own and you >- * include an unaltered copy of this message (including the >- * copyright). >- * >- * It is also implicitly understood that bug fixes and improvements >- * should make their way back to the general Internet community so >- * that everyone benefits. >- */ >-------------------------------------------------------------------------------- >-Files: >-modules/audio_device/mac/portaudio/pa_memorybarrier.h >-modules/audio_device/mac/portaudio/pa_ringbuffer.c >-modules/audio_device/mac/portaudio/pa_ringbuffer.h >- >-License: >-/* >- * $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $ >- * Portable Audio I/O Library >- * Memory barrier utilities >- * >- * Author: Bjorn Roche, XO Audio, LLC >- * >- * This program uses the PortAudio Portable Audio Library. >- * For more information see: http://www.portaudio.com >- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk >- * >- * Permission is hereby granted, free of charge, to any person obtaining >- * a copy of this software and associated documentation files >- * (the "Software"), to deal in the Software without restriction, >- * including without limitation the rights to use, copy, modify, merge, >- * publish, distribute, sublicense, and/or sell copies of the Software, >- * and to permit persons to whom the Software is furnished to do so, >- * subject to the following conditions: >- * >- * The above copyright notice and this permission notice shall be >- * included in all copies or substantial portions of the Software. >- * >- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. >- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR >- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF >- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION >- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >- */ >- >-/* >- * The text above constitutes the entire PortAudio license; however, >- * the PortAudio community also makes the following non-binding requests: >- * >- * Any person wishing to distribute modifications to the Software is >- * requested to send the modifications to the original developer so that >- * they can be incorporated into the canonical version. It is also >- * requested that these non-binding requests be included along with the >- * license above. >- */ >- >-/* >- * $Id: pa_ringbuffer.c 1421 2009-11-18 16:09:05Z bjornroche $ >- * Portable Audio I/O Library >- * Ring Buffer utility. >- * >- * Author: Phil Burk, http://www.softsynth.com >- * modified for SMP safety on Mac OS X by Bjorn Roche >- * modified for SMP safety on Linux by Leland Lucius >- * also, allowed for const where possible >- * modified for multiple-byte-sized data elements by Sven Fischer >- * >- * Note that this is safe only for a single-thread reader and a >- * single-thread writer. >- * >- * This program uses the PortAudio Portable Audio Library. >- * For more information see: http://www.portaudio.com >- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk >- * >- * Permission is hereby granted, free of charge, to any person obtaining >- * a copy of this software and associated documentation files >- * (the "Software"), to deal in the Software without restriction, >- * including without limitation the rights to use, copy, modify, merge, >- * publish, distribute, sublicense, and/or sell copies of the Software, >- * and to permit persons to whom the Software is furnished to do so, >- * subject to the following conditions: >- * >- * The above copyright notice and this permission notice shall be >- * included in all copies or substantial portions of the Software. >- * >- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, >- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF >- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. >- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR >- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF >- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION >- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. >- */ >- >-/* >- * The text above constitutes the entire PortAudio license; however, >- * the PortAudio community also makes the following non-binding requests: >- * >- * Any person wishing to distribute modifications to the Software is >- * requested to send the modifications to the original developer so that >- * they can be incorporated into the canonical version. It is also >- * requested that these non-binding requests be included along with the >- * license above. >- */ >-------------------------------------------------------------------------------- >-Files: >-common_audio/fft4g.c >-modules/audio_processing/aec/aec_rdft.c >- >-License: >-/* >- * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html >- * Copyright Takuya OOURA, 1996-2001 >- * >- * You may use, copy, modify and distribute this code for any purpose (include >- * commercial use) and without fee. Please refer to this package when you modify >- * this code. >- */ >-------------------------------------------------------------------------------- >-Files: >-system_wrappers/source/condition_variable_event_win.cc >- >-Source: >-http://www1.cse.wustl.edu/~schmidt/ACE-copying.html >- >-License: >-Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), >-and CoSMIC(TM) >- >-ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to >-as "DOC software") are copyrighted by Douglas C. Schmidt and his research >-group at Washington University, University of California, Irvine, and >-Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC >-software is open-source, freely available software, you are free to use, >-modify, copy, and distribute--perpetually and irrevocably--the DOC software >-source code and object code produced from the source, as well as copy and >-distribute modified versions of this software. You must, however, include this >-copyright statement along with any code built using DOC software that you >-release. No copyright statement needs to be provided if you just ship binary >-executables of your software products. >-You can use DOC software in commercial and/or binary software releases and are >-under no obligation to redistribute any of your source code that is built >-using DOC software. Note, however, that you may not misappropriate the DOC >-software code, such as copyrighting it yourself or claiming authorship of the >-DOC software code, in a way that will prevent DOC software from being >-distributed freely using an open-source development model. You needn't inform >-anyone that you're using DOC software in your software, though we encourage >-you to let us know so we can promote your project in the DOC software success >-stories. >- >-The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC >-Group at the Institute for Software Integrated Systems (ISIS) and the Center >-for Distributed Object Computing of Washington University, St. Louis for the >-development of open-source software as part of the open-source software >-community. Submissions are provided by the submitter ``as is'' with no >-warranties whatsoever, including any warranty of merchantability, >-noninfringement of third party intellectual property, or fitness for any >-particular purpose. In no event shall the submitter be liable for any direct, >-indirect, special, exemplary, punitive, or consequential damages, including >-without limitation, lost profits, even if advised of the possibility of such >-damages. Likewise, DOC software is provided as is with no warranties of any >-kind, including the warranties of design, merchantability, and fitness for a >-particular purpose, noninfringement, or arising from a course of dealing, >-usage or trade practice. Washington University, UC Irvine, Vanderbilt >-University, their employees, and students shall have no liability with respect >-to the infringement of copyrights, trade secrets or any patents by DOC >-software or any part thereof. Moreover, in no event will Washington >-University, UC Irvine, or Vanderbilt University, their employees, or students >-be liable for any lost revenue or profits or other special, indirect and >-consequential damages. >- >-DOC software is provided with no support and without any obligation on the >-part of Washington University, UC Irvine, Vanderbilt University, their >-employees, or students to assist in its use, correction, modification, or >-enhancement. A number of companies around the world provide commercial support >-for DOC software, however. DOC software is Y2K-compliant, as long as the >-underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant >-with the new US daylight savings rule passed by Congress as "The Energy Policy >-Act of 2005," which established new daylight savings times (DST) rules for the >-United States that expand DST as of March 2007. Since DOC software obtains >-time/date and calendaring information from operating systems users will not be >-affected by the new DST rules as long as they upgrade their operating systems >-accordingly. >- >-The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington >-University, UC Irvine, and Vanderbilt University, may not be used to endorse >-or promote products or services derived from this source without express >-written permission from Washington University, UC Irvine, or Vanderbilt >-University. This license grants no permission to call products or services >-derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM), >-nor does it grant permission for the name Washington University, UC Irvine, or >-Vanderbilt University to appear in their names. >-------------------------------------------------------------------------------- >-Files: >-system_wrappers/source/set_thread_name_win.h >- >-Source: >-http://msdn.microsoft.com/en-us/cc300389.aspx#P >- >-License: >-This license governs use of code marked as âsampleâ or âexampleâ available on >-this web site without a license agreement, as provided under the section above >-titled âNOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.â If you use >-such code (the âsoftwareâ), you accept this license. If you do not accept the >-license, do not use the software. >- >-1. Definitions >- >-The terms âreproduce,â âreproduction,â âderivative works,â and âdistributionâ >-have the same meaning here as under U.S. copyright law. >- >-A âcontributionâ is the original software, or any additions or changes to the >-software. >- >-A âcontributorâ is any person that distributes its contribution under this >-license. >- >-âLicensed patentsâ are a contributorâs patent claims that read directly on its >-contribution. >- >-2. Grant of Rights >- >-(A) Copyright Grant - Subject to the terms of this license, including the >-license conditions and limitations in section 3, each contributor grants you a >-non-exclusive, worldwide, royalty-free copyright license to reproduce its >-contribution, prepare derivative works of its contribution, and distribute its >-contribution or any derivative works that you create. >- >-(B) Patent Grant - Subject to the terms of this license, including the license >-conditions and limitations in section 3, each contributor grants you a >-non-exclusive, worldwide, royalty-free license under its licensed patents to >-make, have made, use, sell, offer for sale, import, and/or otherwise dispose >-of its contribution in the software or derivative works of the contribution in >-the software. >- >-3. Conditions and Limitations >- >-(A) No Trademark License- This license does not grant you rights to use any >-contributorsâ name, logo, or trademarks. >- >-(B) If you bring a patent claim against any contributor over patents that you >-claim are infringed by the software, your patent license from such contributor >-to the software ends automatically. >- >-(C) If you distribute any portion of the software, you must retain all >-copyright, patent, trademark, and attribution notices that are present in the >-software. >- >-(D) If you distribute any portion of the software in source code form, you may >-do so only under this license by including a complete copy of this license >-with your distribution. If you distribute any portion of the software in >-compiled or object code form, you may only do so under a license that complies >-with this license. >- >-(E) The software is licensed âas-is.â You bear the risk of using it. The >-contributors give no express warranties, guarantees or conditions. You may >-have additional consumer rights under your local laws which this license >-cannot change. To the extent permitted under your local laws, the contributors >-exclude the implied warranties of merchantability, fitness for a particular >-purpose and non-infringement. >- >-(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) >-extend only to the software or derivative works that you create that run on a >-Microsoft Windows operating system product. >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/OWNERS >index f57794a473f..587f727e4d6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/OWNERS >@@ -2,16 +2,22 @@ henrika@webrtc.org > kwiberg@webrtc.org > mflodman@webrtc.org > niklas.enbom@webrtc.org >+phoglund@webrtc.org > stefan@webrtc.org > tina.legrand@webrtc.org > tommi@webrtc.org > per-file .gitignore=* >-per-file .gn=phoglund@webrtc.org >-per-file *.gn=phoglund@webrtc.org >-per-file *.gni=phoglund@webrtc.org >+per-file .gn=mbonadei@webrtc.org >+per-file *.gn=mbonadei@webrtc.org >+per-file *.gni=mbonadei@webrtc.org > per-file *.py=phoglund@webrtc.org > per-file AUTHORS=* > per-file BUILD.gn=phoglund@webrtc.org > per-file DEPS=* > per-file pylintrc=phoglund@webrtc.org >+per-file THIRD_PARTY_DEPS=phoglund@webrtc.org >+per-file THIRD_PARTY_DEPS=titovartem@webrtc.org > per-file WATCHLISTS=* >+per-file style-guide.md=danilchap@webrtc.org >+per-file style-guide.md=kwiberg@webrtc.org >+per-file native-api.md=kwiberg@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/PRESUBMIT.py b/Source/ThirdParty/libwebrtc/Source/webrtc/PRESUBMIT.py >old mode 100644 >new mode 100755 >index a621f3b058a..1b435a77e87 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/PRESUBMIT.py >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/PRESUBMIT.py >@@ -13,7 +13,6 @@ import sys > from collections import defaultdict > from contextlib import contextmanager > >- > # Files and directories that are *skipped* by cpplint in the presubmit script. > CPPLINT_BLACKLIST = [ > 'api/video_codecs/video_decoder.h', >@@ -29,11 +28,8 @@ CPPLINT_BLACKLIST = [ > 'modules/audio_processing', > 'modules/desktop_capture', > 'modules/include/module_common_types.h', >- 'modules/media_file', > 'modules/utility', > 'modules/video_capture', >- 'p2p/base/session.cc', >- 'p2p/base/session.h', > 'p2p/base/pseudotcp.cc', > 'p2p/base/pseudotcp.h', > 'rtc_base', >@@ -142,6 +138,7 @@ def VerifyNativeApiHeadersListIsValid(input_api, output_api): > non_existing_paths)] > return [] > >+ > API_CHANGE_MSG = """ > You seem to be changing native API header files. Please make sure that you: > 1. Make compatible changes that don't break existing clients. Usually >@@ -161,6 +158,7 @@ You seem to be changing native API header files. Please make sure that you: > Related files: > """ > >+ > def CheckNativeApiHeaderChanges(input_api, output_api): > """Checks to remind proper changing of native APIs.""" > files = [] >@@ -183,12 +181,15 @@ def CheckNativeApiHeaderChanges(input_api, output_api): > return [] > > >-def CheckNoIOStreamInHeaders(input_api, output_api): >+def CheckNoIOStreamInHeaders(input_api, output_api, >+ source_file_filter): > """Checks to make sure no .h files include <iostream>.""" > files = [] > pattern = input_api.re.compile(r'^#include\s*<iostream>', > input_api.re.MULTILINE) >- for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): >+ file_filter = lambda x: (input_api.FilterSourceFile(x) >+ and source_file_filter(x)) >+ for f in input_api.AffectedSourceFiles(file_filter): > if not f.LocalPath().endswith('.h'): > continue > contents = input_api.ReadFile(f) >@@ -204,12 +205,15 @@ def CheckNoIOStreamInHeaders(input_api, output_api): > return [] > > >-def CheckNoPragmaOnce(input_api, output_api): >+def CheckNoPragmaOnce(input_api, output_api, >+ source_file_filter): > """Make sure that banned functions are not used.""" > files = [] > pattern = input_api.re.compile(r'^#pragma\s+once', > input_api.re.MULTILINE) >- for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): >+ file_filter = lambda x: (input_api.FilterSourceFile(x) >+ and source_file_filter(x)) >+ for f in input_api.AffectedSourceFiles(file_filter): > if not f.LocalPath().endswith('.h'): > continue > contents = input_api.ReadFile(f) >@@ -224,13 +228,15 @@ def CheckNoPragmaOnce(input_api, output_api): > return [] > > >-def CheckNoFRIEND_TEST(input_api, output_api): # pylint: disable=invalid-name >+def CheckNoFRIEND_TEST(input_api, output_api, # pylint: disable=invalid-name >+ source_file_filter): > """Make sure that gtest's FRIEND_TEST() macro is not used, the > FRIEND_TEST_ALL_PREFIXES() macro from testsupport/gtest_prod_util.h should be > used instead since that allows for FLAKY_, FAILS_ and DISABLED_ prefixes.""" > problems = [] > >- file_filter = lambda f: f.LocalPath().endswith(('.cc', '.h')) >+ file_filter = lambda f: (f.LocalPath().endswith(('.cc', '.h')) >+ and source_file_filter(f)) > for f in input_api.AffectedFiles(file_filter=file_filter): > for line_num, line in f.ChangedContents(): > if 'FRIEND_TEST(' in line: >@@ -252,7 +258,7 @@ def IsLintBlacklisted(blacklist_paths, file_path): > > > def CheckApprovedFilesLintClean(input_api, output_api, >- source_file_filter=None): >+ source_file_filter=None): > """Checks that all new or non-blacklisted .cc and .h files pass cpplint.py. > This check is based on CheckChangeLintsClean in > depot_tools/presubmit_canned_checks.py but has less filters and only checks >@@ -282,7 +288,7 @@ def CheckApprovedFilesLintClean(input_api, output_api, > for f in input_api.AffectedSourceFiles(source_file_filter): > # Note that moved/renamed files also count as added. > if f.Action() == 'A' or not IsLintBlacklisted(blacklist_paths, >- f.LocalPath()): >+ f.LocalPath()): > files.append(f.AbsoluteLocalPath()) > > for file_name in files: >@@ -297,6 +303,7 @@ def CheckApprovedFilesLintClean(input_api, output_api, > > return result > >+ > def CheckNoSourcesAbove(input_api, gn_files, output_api): > # Disallow referencing source files with paths above the GN file location. > source_pattern = input_api.re.compile(r' +sources \+?= \[(.*?)\]', >@@ -325,11 +332,13 @@ def CheckNoSourcesAbove(input_api, gn_files, output_api): > items=violating_gn_files)] > return [] > >+ > def CheckNoMixingSources(input_api, gn_files, output_api): > """Disallow mixing C, C++ and Obj-C/Obj-C++ in the same target. > > See bugs.webrtc.org/7743 for more context. > """ >+ > def _MoreThanOneSourceUsed(*sources_lists): > sources_used = 0 > for source_list in sources_lists: >@@ -391,6 +400,7 @@ def CheckNoMixingSources(input_api, gn_files, output_api): > '\n'.join(errors.keys())))] > return [] > >+ > def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api): > cwd = input_api.PresubmitLocalPath() > with _AddToPath(input_api.os_path.join( >@@ -404,19 +414,98 @@ def CheckNoPackageBoundaryViolations(input_api, gn_files, output_api): > long_text='\n\n'.join(str(err) for err in errors))] > return [] > >-def CheckPublicDepsIsNotUsed(gn_files, output_api): >+ >+def _ReportFileAndLine(filename, line_num): >+ """Default error formatter for _FindNewViolationsOfRule.""" >+ return '%s (line %s)' % (filename, line_num) >+ >+ >+def CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, output_api, >+ error_formatter=_ReportFileAndLine): >+ """Make sure that warning suppression flags are not added wihtout a reason.""" >+ msg = ('Usage of //build/config/clang:extra_warnings is discouraged ' >+ 'in WebRTC.\n' >+ 'If you are not adding this code (e.g. you are just moving ' >+ 'existing code) or you want to add an exception,\n' >+ 'you can add a comment on the line that causes the problem:\n\n' >+ '"-Wno-odr" # no-presubmit-check TODO(bugs.webrtc.org/BUG_ID)\n' >+ '\n' >+ 'Affected files:\n') >+ errors = [] # 2-element tuples with (file, line number) >+ clang_warn_re = input_api.re.compile(r'//build/config/clang:extra_warnings') >+ no_presubmit_re = input_api.re.compile( >+ r'# no-presubmit-check TODO\(bugs\.webrtc\.org/\d+\)') >+ for f in gn_files: >+ for line_num, line in f.ChangedContents(): >+ if clang_warn_re.search(line) and not no_presubmit_re.search(line): >+ errors.append(error_formatter(f.LocalPath(), line_num)) >+ if errors: >+ return [output_api.PresubmitError(msg, errors)] >+ return [] >+ >+def CheckNoStreamUsageIsAdded(input_api, output_api, >+ source_file_filter, >+ error_formatter=_ReportFileAndLine): >+ """Make sure that no more dependencies on stringstream are added.""" >+ error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is ' >+ 'deprecated.\n' >+ 'This includes the following types:\n' >+ 'std::istringstream, std::ostringstream, std::wistringstream, ' >+ 'std::wostringstream,\n' >+ 'std::wstringstream, std::ostream, std::wostream, std::istream,' >+ 'std::wistream,\n' >+ 'std::iostream, std::wiostream.\n' >+ 'If you are not adding this code (e.g. you are just moving ' >+ 'existing code),\n' >+ 'you can add a comment on the line that causes the problem:\n\n' >+ '#include <sstream> // no-presubmit-check TODO(webrtc:8982)\n' >+ 'std::ostream& F() { // no-presubmit-check TODO(webrtc:8982)\n' >+ '\n' >+ 'If you are adding new code, consider using ' >+ 'rtc::SimpleStringBuilder\n' >+ '(in rtc_base/strings/string_builder.h).\n' >+ 'Affected files:\n') >+ errors = [] # 2-element tuples with (file, line number) >+ include_re = input_api.re.compile(r'#include <(i|o|s)stream>') >+ usage_re = input_api.re.compile(r'std::(w|i|o|io|wi|wo|wio)(string)*stream') >+ no_presubmit_re = input_api.re.compile( >+ r'// no-presubmit-check TODO\(webrtc:8982\)') >+ file_filter = lambda x: (input_api.FilterSourceFile(x) >+ and source_file_filter(x)) >+ for f in input_api.AffectedSourceFiles(file_filter): >+ if f.LocalPath() == 'PRESUBMIT.py': >+ continue >+ for line_num, line in f.ChangedContents(): >+ if ((include_re.search(line) or usage_re.search(line)) >+ and not no_presubmit_re.search(line)): >+ errors.append(error_formatter(f.LocalPath(), line_num)) >+ if errors: >+ return [output_api.PresubmitError(error_msg, errors)] >+ return [] >+ >+ >+def CheckPublicDepsIsNotUsed(gn_files, input_api, output_api): >+ """Checks that public_deps is not used without a good reason.""" > result = [] >- error_msg = ('public_deps is not allowed in WebRTC BUILD.gn files because ' >- 'it doesn\'t map well to downstream build systems.\n' >- 'Used in: %s (line %d).') >+ no_presubmit_check_re = input_api.re.compile( >+ r'# no-presubmit-check TODO\(webrtc:8603\)') >+ error_msg = ('public_deps is not recommended in WebRTC BUILD.gn files ' >+ 'because it doesn\'t map well to downstream build systems.\n' >+ 'Used in: %s (line %d).\n' >+ 'If you are not adding this code (e.g. you are just moving ' >+ 'existing code) or you have a good reason, you can add a ' >+ 'comment on the line that causes the problem:\n\n' >+ 'public_deps = [ # no-presubmit-check TODO(webrtc:8603)\n') > for affected_file in gn_files: > for (line_number, affected_line) in affected_file.ChangedContents(): >- if 'public_deps' in affected_line: >+ if ('public_deps' in affected_line >+ and not no_presubmit_check_re.search(affected_line)): > result.append( > output_api.PresubmitError(error_msg % (affected_file.LocalPath(), > line_number))) > return result > >+ > def CheckCheckIncludesIsNotUsed(gn_files, output_api): > result = [] > error_msg = ('check_includes overrides are not allowed since it can cause ' >@@ -434,13 +523,14 @@ def CheckCheckIncludesIsNotUsed(gn_files, output_api): > line_number))) > return result > >+ > def CheckGnChanges(input_api, output_api): >- source_file_filter = lambda x: input_api.FilterSourceFile( >+ file_filter = lambda x: (input_api.FilterSourceFile( > x, white_list=(r'.+\.(gn|gni)$',), >- black_list=(r'.*/presubmit_checks_lib/testdata/.*',)) >+ black_list=(r'.*/presubmit_checks_lib/testdata/.*',))) > > gn_files = [] >- for f in input_api.AffectedSourceFiles(source_file_filter): >+ for f in input_api.AffectedSourceFiles(file_filter): > gn_files.append(f) > > result = [] >@@ -449,10 +539,13 @@ def CheckGnChanges(input_api, output_api): > result.extend(CheckNoMixingSources(input_api, gn_files, output_api)) > result.extend(CheckNoPackageBoundaryViolations(input_api, gn_files, > output_api)) >- result.extend(CheckPublicDepsIsNotUsed(gn_files, output_api)) >+ result.extend(CheckPublicDepsIsNotUsed(gn_files, input_api, output_api)) > result.extend(CheckCheckIncludesIsNotUsed(gn_files, output_api)) >+ result.extend(CheckNoWarningSuppressionFlagsAreAdded(gn_files, input_api, >+ output_api)) > return result > >+ > def CheckGnGen(input_api, output_api): > """Runs `gn gen --check` with default args to detect mismatches between > #includes and dependencies in the BUILD.gn files, as well as general build >@@ -469,7 +562,8 @@ def CheckGnGen(input_api, output_api): > long_text='\n\n'.join(errors))] > return [] > >-def CheckUnwantedDependencies(input_api, output_api): >+ >+def CheckUnwantedDependencies(input_api, output_api, source_file_filter): > """Runs checkdeps on #include statements added in this > change. Breaking - rules is an error, breaking ! rules is a > warning. >@@ -491,7 +585,7 @@ def CheckUnwantedDependencies(input_api, output_api): > from rules import Rule > > added_includes = [] >- for f in input_api.AffectedFiles(): >+ for f in input_api.AffectedFiles(file_filter=source_file_filter): > if not CppChecker.IsCppFile(f.LocalPath()): > continue > >@@ -528,6 +622,7 @@ def CheckUnwantedDependencies(input_api, output_api): > warning_descriptions)) > return results > >+ > def CheckCommitMessageBugEntry(input_api, output_api): > """Check that bug entries are well-formed in commit message.""" > bogus_bug_msg = ( >@@ -553,6 +648,7 @@ def CheckCommitMessageBugEntry(input_api, output_api): > results.append(bogus_bug_msg % bug) > return [output_api.PresubmitError(r) for r in results] > >+ > def CheckChangeHasBugField(input_api, output_api): > """Requires that the changelist is associated with a bug. > >@@ -572,11 +668,13 @@ def CheckChangeHasBugField(input_api, output_api): > ' * https://bugs.webrtc.org - reference it using Bug: webrtc:XXXX\n' > ' * https://crbug.com - reference it using Bug: chromium:XXXXXX')] > >-def CheckJSONParseErrors(input_api, output_api): >+ >+def CheckJSONParseErrors(input_api, output_api, source_file_filter): > """Check that JSON files do not contain syntax errors.""" > > def FilterFile(affected_file): >- return input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json' >+ return (input_api.os_path.splitext(affected_file.LocalPath())[1] == '.json' >+ and source_file_filter(affected_file)) > > def GetJSONParseError(input_api, filename): > try: >@@ -593,7 +691,8 @@ def CheckJSONParseErrors(input_api, output_api): > affected_file.AbsoluteLocalPath()) > if parse_error: > results.append(output_api.PresubmitError('%s could not be parsed: %s' % >- (affected_file.LocalPath(), parse_error))) >+ (affected_file.LocalPath(), >+ parse_error))) > return results > > >@@ -622,12 +721,15 @@ def RunPythonTests(input_api, output_api): > return input_api.RunTests(tests, parallel=True) > > >-def CheckUsageOfGoogleProtobufNamespace(input_api, output_api): >+def CheckUsageOfGoogleProtobufNamespace(input_api, output_api, >+ source_file_filter): > """Checks that the namespace google::protobuf has not been used.""" > files = [] > pattern = input_api.re.compile(r'google::protobuf') > proto_utils_path = os.path.join('rtc_base', 'protobuf_utils.h') >- for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile): >+ file_filter = lambda x: (input_api.FilterSourceFile(x) >+ and source_file_filter(x)) >+ for f in input_api.AffectedSourceFiles(file_filter): > if f.LocalPath() in [proto_utils_path, 'PRESUBMIT.py']: > continue > contents = input_api.ReadFile(f) >@@ -690,7 +792,6 @@ def CommonChecks(input_api, output_api): > r'^tools[\\\/].*\.py$', > # TODO(phoglund): should arguably be checked. > r'^tools_webrtc[\\\/]mb[\\\/].*\.py$', >- r'^tools_webrtc[\\\/]valgrind[\\\/].*\.py$', > r'^xcodebuild.*[\\\/].*\.py$',), > pylintrc='pylintrc')) > >@@ -704,35 +805,52 @@ def CommonChecks(input_api, output_api): > objc_filter_list = (r'.+\.m$', r'.+\.mm$', r'.+objc\/.+\.h$') > # Skip long-lines check for DEPS and GN files. > build_file_filter_list = (r'.+\.gn$', r'.+\.gni$', 'DEPS') >+ # Also we will skip most checks for third_party directory. >+ third_party_filter_list = (r'^third_party[\\\/].+',) > eighty_char_sources = lambda x: input_api.FilterSourceFile(x, >- black_list=build_file_filter_list + objc_filter_list) >+ black_list=build_file_filter_list + objc_filter_list + >+ third_party_filter_list) > hundred_char_sources = lambda x: input_api.FilterSourceFile(x, > white_list=objc_filter_list) >+ non_third_party_sources = lambda x: input_api.FilterSourceFile(x, >+ black_list=third_party_filter_list) >+ > results.extend(input_api.canned_checks.CheckLongLines( > input_api, output_api, maxlen=80, source_file_filter=eighty_char_sources)) > results.extend(input_api.canned_checks.CheckLongLines( > input_api, output_api, maxlen=100, > source_file_filter=hundred_char_sources)) >- > results.extend(input_api.canned_checks.CheckChangeHasNoTabs( >- input_api, output_api)) >+ input_api, output_api, source_file_filter=non_third_party_sources)) > results.extend(input_api.canned_checks.CheckChangeHasNoStrayWhitespace( >- input_api, output_api)) >+ input_api, output_api, source_file_filter=non_third_party_sources)) > results.extend(input_api.canned_checks.CheckAuthorizedAuthor( > input_api, output_api)) > results.extend(input_api.canned_checks.CheckChangeTodoHasOwner( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(input_api.canned_checks.CheckPatchFormatted( > input_api, output_api)) > results.extend(CheckNativeApiHeaderChanges(input_api, output_api)) >- results.extend(CheckNoIOStreamInHeaders(input_api, output_api)) >- results.extend(CheckNoPragmaOnce(input_api, output_api)) >- results.extend(CheckNoFRIEND_TEST(input_api, output_api)) >+ results.extend(CheckNoIOStreamInHeaders( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckNoPragmaOnce( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckNoFRIEND_TEST( >+ input_api, output_api, source_file_filter=non_third_party_sources)) > results.extend(CheckGnChanges(input_api, output_api)) >- results.extend(CheckUnwantedDependencies(input_api, output_api)) >- results.extend(CheckJSONParseErrors(input_api, output_api)) >+ results.extend(CheckUnwantedDependencies( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckJSONParseErrors( >+ input_api, output_api, source_file_filter=non_third_party_sources)) > results.extend(RunPythonTests(input_api, output_api)) >- results.extend(CheckUsageOfGoogleProtobufNamespace(input_api, output_api)) >- results.extend(CheckOrphanHeaders(input_api, output_api)) >- results.extend(CheckNewlineAtTheEndOfProtoFiles(input_api, output_api)) >+ results.extend(CheckUsageOfGoogleProtobufNamespace( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckOrphanHeaders( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckNewlineAtTheEndOfProtoFiles( >+ input_api, output_api, source_file_filter=non_third_party_sources)) >+ results.extend(CheckNoStreamUsageIsAdded( >+ input_api, output_api, non_third_party_sources)) > return results > > >@@ -762,7 +880,7 @@ def CheckChangeOnCommit(input_api, output_api): > return results > > >-def CheckOrphanHeaders(input_api, output_api): >+def CheckOrphanHeaders(input_api, output_api, source_file_filter): > # We need to wait until we have an input_api object and use this > # roundabout construct to import prebubmit_checks_lib because this file is > # eval-ed and thus doesn't have __file__. >@@ -776,9 +894,9 @@ def CheckOrphanHeaders(input_api, output_api): > from check_orphan_headers import GetBuildGnPathFromFilePath > from check_orphan_headers import IsHeaderInBuildGn > >- source_file_filter = lambda x: input_api.FilterSourceFile( >- x, black_list=orphan_blacklist) >- for f in input_api.AffectedSourceFiles(source_file_filter): >+ file_filter = lambda x: input_api.FilterSourceFile( >+ x, black_list=orphan_blacklist) and source_file_filter(x) >+ for f in input_api.AffectedSourceFiles(file_filter): > if f.LocalPath().endswith('.h'): > file_path = os.path.abspath(f.LocalPath()) > root_dir = os.getcwd() >@@ -791,13 +909,13 @@ def CheckOrphanHeaders(input_api, output_api): > return results > > >-def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api): >+def CheckNewlineAtTheEndOfProtoFiles(input_api, output_api, source_file_filter): > """Checks that all .proto files are terminated with a newline.""" > error_msg = 'File {} must end with exactly one newline.' > results = [] >- source_file_filter = lambda x: input_api.FilterSourceFile( >- x, white_list=(r'.+\.proto$',)) >- for f in input_api.AffectedSourceFiles(source_file_filter): >+ file_filter = lambda x: input_api.FilterSourceFile( >+ x, white_list=(r'.+\.proto$',)) and source_file_filter(x) >+ for f in input_api.AffectedSourceFiles(file_filter): > file_path = f.LocalPath() > with open(file_path) as f: > lines = f.readlines() >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/WATCHLISTS b/Source/ThirdParty/libwebrtc/Source/webrtc/WATCHLISTS >index ed0a614009b..845ff3c1298 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/WATCHLISTS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/WATCHLISTS >@@ -16,90 +16,80 @@ > }, > 'all_webrtc': { > # NOTE: if you like this you might like webrtc-reviews@webrtc.org! >- 'filepath': '^webrtc/.*', >+ 'filepath': '^.*', > }, > 'root_files': { >- # webrtc/build/ and non-recursive contents of ./ and webrtc/ >- 'filepath': '^[^/]*$|^webrtc/[^/]*$|^webrtc/build/.*', >- }, >- 'documented_interfaces': { >- 'filepath': '^webrtc/[^/]*\.h$|'\ >- 'webrtc/voice_engine/include/.*', >+ # Non-recursive contents of ./ >+ 'filepath': '^[^/]*$', > }, > 'build_files': { >- 'filepath': '\.gyp$|\.gypi$|Android\.mk$', >+ 'filepath': '\.gni$|\.gn$', > }, > 'java_files': { > 'filepath': '\.java$|\.xml$', > }, > 'api': { >- 'filepath': 'webrtc/api/.*', >+ 'filepath': 'api/.*', > }, > 'audio': { >- 'filepath': 'webrtc/audio/.*', >+ 'filepath': 'audio/.*', > }, > 'base': { >- 'filepath': 'webrtc/base/.*', >+ 'filepath': 'rtc_base/.*', > }, > 'call': { >- 'filepath': 'webrtc/call/.*', >+ 'filepath': 'call/.*', > }, > 'media_engine': { >- 'filepath': 'webrtc/media/engine/.*', >+ 'filepath': 'media/engine/.*', > }, > 'video': { >- 'filepath': 'webrtc/video/.*', >- }, >- 'voice_engine': { >- 'filepath': 'webrtc/voice_engine/.*', >+ 'filepath': 'video/.*', > }, > 'common_audio': { >- 'filepath': 'webrtc/common_audio/.*', >+ 'filepath': 'common_audio/.*', > }, > 'common_video': { >- 'filepath': 'webrtc/common_video/.*', >+ 'filepath': 'common_video/.*', > }, > 'video_capture': { >- 'filepath': 'webrtc/modules/video_capture/.*', >- }, >- 'video_render': { >- 'filepath': 'webrtc/modules/video_render/.*', >+ 'filepath': 'modules/video_capture/.*', > }, > 'audio_device': { >- 'filepath': 'webrtc/modules/audio_device/.*', >+ 'filepath': 'modules/audio_device/.*', > }, > 'audio_coding': { >- 'filepath': 'webrtc/modules/audio_coding/.*', >+ 'filepath': 'modules/audio_coding/.*', > }, > 'neteq': { >- 'filepath': 'webrtc/modules/audio_coding/neteq/.*', >+ 'filepath': 'modules/audio_coding/neteq/.*', > }, > 'audio_mixer': { >- 'filepath': 'webrtc/modules/audio_mixer/.*', >+ 'filepath': 'modules/audio_mixer/.*', > }, > 'audio_processing': { >- 'filepath': 'webrtc/modules/audio_processing/.*', >+ 'filepath': 'modules/audio_processing/.*', > }, > 'video_coding': { >- 'filepath': 'webrtc/modules/video_coding/.*', >+ 'filepath': 'modules/video_coding/.*', > }, > 'video_processing': { >- 'filepath': 'webrtc/modules/video_processing/.*', >+ 'filepath': 'modules/video_processing/.*', > }, > 'bitrate_controller': { >- 'filepath': 'webrtc/modules/bitrate_controller/.*' >+ 'filepath': 'modules/bitrate_controller/.*' > }, > 'remote_bitrate_estimator': { >- 'filepath': 'webrtc/modules/remote_bitrate_estimator/.*' >+ 'filepath': 'modules/remote_bitrate_estimator/.*' > }, > 'pacing': { >- 'filepath': 'webrtc/modules/pacing/.*' >+ 'filepath': 'modules/pacing/.*' > }, > 'rtp_rtcp': { >- 'filepath': 'webrtc/modules/rtp_rtcp/.*' >+ 'filepath': 'modules/rtp_rtcp/.*' > }, > 'system_wrappers': { >- 'filepath': 'webrtc/system_wrappers/.*', >+ 'filepath': 'system_wrappers/.*', > }, > }, > >@@ -110,7 +100,7 @@ > 'peah@webrtc.org', > 'qiang.lu@intel.com', > 'yujie.mao@webrtc.org'], >- 'documented_interfaces': ['interface-changes@webrtc.org'], >+ 'build_files': ['mbonadei@webrtc.org'], > 'common_audio': ['alessiob@webrtc.org', > 'aluebs@webrtc.org', > 'andrew@webrtc.org', >@@ -126,28 +116,15 @@ > 'call': ['mflodman@webrtc.org', > 'solenberg@webrtc.org', > 'stefan@webrtc.org'], >- 'media_engine': ['solenberg@webrtc.org'], > 'video': ['mflodman@webrtc.org', > 'stefan@webrtc.org', > 'video-team@agora.io', > 'yujie.mao@webrtc.org', > 'zhengzhonghou@agora.io'], >- 'voice_engine': ['alessiob@webrtc.org', >- 'andrew@webrtc.org', >- 'audio-team@agora.io', >- 'henrika@webrtc.org', >- 'henrik.lundin@webrtc.org', >- 'minyue@webrtc.org', >- 'peah@webrtc.org', >- 'solenberg@webrtc.org'], > 'video_capture': ['mflodman@webrtc.org', > 'perkj@webrtc.org', > 'sdk-team@agora.io', > 'zhengzhonghou@agora.io'], >- 'video_render': ['mflodman@webrtc.org', >- 'perkj@webrtc.org', >- 'sdk-team@agora.io', >- 'zhengzhonghou@agora.io'], > 'audio_device': ['audio-team@agora.io', > 'henrika@webrtc.org', > 'peah@webrtc.org', >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/BUILD.gn >index e3af7bbf2f1..7271ece848a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/BUILD.gn >@@ -29,25 +29,36 @@ rtc_source_set("call_api") { > > deps = [ > # TODO(kjellander): Add remaining dependencies when webrtc:4243 is done. >- ":audio_mixer_api", > ":transport_api", > "..:webrtc_common", > "../rtc_base:rtc_base_approved", >+ "audio:audio_mixer_api", > "audio_codecs:audio_codecs_api", > ] > } > >+rtc_source_set("callfactory_api") { >+ visibility = [ "*" ] >+ sources = [ >+ "call/callfactoryinterface.h", >+ ] >+} >+ > rtc_static_library("libjingle_peerconnection_api") { > visibility = [ "*" ] > cflags = [] > sources = [ >+ "asyncresolverfactory.h", >+ "bitrate_constraints.h", > "candidate.cc", > "candidate.h", > "cryptoparams.h", >+ "datachannelinterface.cc", > "datachannelinterface.h", > "dtmfsenderinterface.h", > "jsep.cc", > "jsep.h", >+ "jsepicecandidate.cc", > "jsepicecandidate.h", > "jsepsessiondescription.h", > "mediaconstraintsinterface.cc", >@@ -60,6 +71,8 @@ rtc_static_library("libjingle_peerconnection_api") { > "mediatypes.h", > "notifier.h", > "peerconnectionfactoryproxy.h", >+ "peerconnectioninterface.cc", >+ "peerconnectioninterface.h", > "peerconnectionproxy.h", > "proxy.cc", > "proxy.h", >@@ -69,39 +82,39 @@ rtc_static_library("libjingle_peerconnection_api") { > "rtp_headers.h", > "rtpparameters.cc", > "rtpparameters.h", >+ "rtpreceiverinterface.cc", > "rtpreceiverinterface.h", > "rtpsenderinterface.h", >+ "rtptransceiverinterface.cc", > "rtptransceiverinterface.h", > "setremotedescriptionobserverinterface.h", > "statstypes.cc", > "statstypes.h", > "turncustomizer.h", >- "umametrics.cc", > "umametrics.h", >- "videosinkinterface.h", >- "videosourceinterface.cc", >- "videosourceinterface.h", > "videosourceproxy.h", > ] > >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > deps = [ > ":array_view", >- ":optional", >- ":peerconnection_and_implicit_call_api", >+ ":audio_options_api", >+ ":callfactory_api", >+ ":fec_controller_api", >+ ":libjingle_logging_api", > ":rtc_stats_api", >- ":video_frame_api", >+ "audio:audio_mixer_api", > "audio_codecs:audio_codecs_api", >+ "transport:bitrate_settings", >+ "transport:network_control", >+ "video:video_frame", >+ "//third_party/abseil-cpp/absl/types:optional", > > # Basically, don't add stuff here. You might break sensitive downstream > # targets like pnacl. API should not depend on anything outside of this > # file, really. All these should arguably go away in time. >- "..:typedefs", > "..:webrtc_common", >+ "../logging:rtc_event_log_api", >+ "../media:rtc_media_config", > "../modules/audio_processing:audio_processing_statistics", > "../rtc_base:checks", > "../rtc_base:deprecation", >@@ -109,24 +122,54 @@ rtc_static_library("libjingle_peerconnection_api") { > "../rtc_base:rtc_base_approved", > "../rtc_base:stringutils", > ] >+ > if (is_nacl) { > # This is needed by .h files included from rtc_base. > deps += [ "//native_client_sdk/src/libraries/nacl_io" ] > } > } > >-rtc_source_set("peerconnection_and_implicit_call_api") { >+rtc_source_set("video_quality_test_fixture_api") { > visibility = [ "*" ] >- >- # The peerconnectioninterface.h file pulls in call/callfactoryinterface.h >- # and the entire call module with it. We need to either get rid of this >- # dependency or pull most of call/ into the API. For now, silence the warnings >- # this creates since it creates a circular dependency (call very much depends >- # on API). See bugs.webrtc.org/8667. >- check_includes = false >+ testonly = true > sources = [ >- "peerconnectioninterface.h", >+ "test/video_quality_test_fixture.h", > ] >+ deps = [ >+ ":libjingle_peerconnection_api", >+ ":simulated_network_api", >+ "../call:fake_network", >+ "../call:rtp_interfaces", >+ "../test:test_common", >+ "../test:video_test_common", >+ "video_codecs:video_codecs_api", >+ ] >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+} >+ >+if (rtc_include_tests) { >+ rtc_source_set("create_video_quality_test_fixture_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/create_video_quality_test_fixture.cc", >+ "test/create_video_quality_test_fixture.h", >+ ] >+ deps = [ >+ ":fec_controller_api", >+ ":video_quality_test_fixture_api", >+ "../rtc_base:ptr_util", >+ "../video:video_quality_test", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ } > } > > rtc_source_set("libjingle_logging_api") { >@@ -159,9 +202,9 @@ rtc_source_set("ortc_api") { > # libjingle_peerconnection_api. > deps = [ > ":libjingle_peerconnection_api", >- ":optional", > "..:webrtc_common", > "../rtc_base:rtc_base", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -185,57 +228,48 @@ rtc_source_set("rtc_stats_api") { > ] > } > >-rtc_source_set("audio_mixer_api") { >+rtc_source_set("audio_options_api") { > visibility = [ "*" ] > sources = [ >- "audio/audio_mixer.h", >+ "audio_options.cc", >+ "audio_options.h", > ] > > deps = [ >- "../modules:module_api", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_source_set("transport_api") { > visibility = [ "*" ] > sources = [ >+ "call/transport.cc", > "call/transport.h", > ] > } > >-rtc_source_set("video_frame_api") { >+rtc_source_set("simulated_network_api") { > visibility = [ "*" ] > sources = [ >- "video/video_content_type.cc", >- "video/video_content_type.h", >- "video/video_frame.cc", >- "video/video_frame.h", >- "video/video_frame_buffer.cc", >- "video/video_frame_buffer.h", >- "video/video_rotation.h", >- "video/video_timing.cc", >- "video/video_timing.h", >+ "test/simulated_network.h", > ] >- > deps = [ >- "../rtc_base:checks", >- "../rtc_base:rtc_base_approved", >+ "../rtc_base:criticalsection", >+ "../rtc_base:rtc_base", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > >-rtc_source_set("video_frame_api_i420") { >+rtc_source_set("fec_controller_api") { > visibility = [ "*" ] > sources = [ >- "video/i420_buffer.cc", >- "video/i420_buffer.h", >+ "fec_controller.h", > ] >+ > deps = [ >- ":video_frame_api", >- "../rtc_base:checks", >- "../rtc_base:rtc_base", >- "../system_wrappers", >- "//third_party/libyuv", >+ "..:webrtc_common", >+ "../modules:module_fec_api", > ] > } > >@@ -250,19 +284,6 @@ rtc_source_set("array_view") { > ] > } > >-rtc_source_set("optional") { >- visibility = [ "*" ] >- sources = [ >- "optional.cc", >- "optional.h", >- ] >- deps = [ >- ":array_view", >- "../rtc_base:checks", >- "../rtc_base:sanitizer", >- ] >-} >- > rtc_source_set("refcountedbase") { > visibility = [ "*" ] > sources = [ >@@ -287,6 +308,86 @@ rtc_source_set("libjingle_peerconnection_test_api") { > } > > if (rtc_include_tests) { >+ if (rtc_enable_protobuf) { >+ rtc_source_set("audioproc_f_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/audioproc_float.cc", >+ "test/audioproc_float.h", >+ ] >+ >+ deps = [ >+ "../modules/audio_processing:audio_processing", >+ "../modules/audio_processing:audioproc_f_impl", >+ ] >+ } >+ } >+ >+ rtc_source_set("simulcast_test_fixture_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/simulcast_test_fixture.h", >+ ] >+ } >+ >+ rtc_source_set("create_simulcast_test_fixture_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/create_simulcast_test_fixture.cc", >+ "test/create_simulcast_test_fixture.h", >+ ] >+ deps = [ >+ ":simulcast_test_fixture_api", >+ "../modules/video_coding:simulcast_test_fixture_impl", >+ "../rtc_base:rtc_base_approved", >+ "video_codecs:video_codecs_api", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ } >+ >+ rtc_source_set("videocodec_test_fixture_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/videocodec_test_fixture.h", >+ "test/videocodec_test_stats.cc", >+ "test/videocodec_test_stats.h", >+ ] >+ deps = [ >+ "..:webrtc_common", >+ "../modules/video_coding:video_codec_interface", >+ "video_codecs:video_codecs_api", >+ ] >+ } >+ >+ rtc_source_set("create_videocodec_test_fixture_api") { >+ visibility = [ "*" ] >+ testonly = true >+ sources = [ >+ "test/create_videocodec_test_fixture.cc", >+ "test/create_videocodec_test_fixture.h", >+ ] >+ deps = [ >+ ":videocodec_test_fixture_api", >+ "../modules/video_coding:video_codecs_test_framework", >+ "../modules/video_coding:videocodec_test_impl", >+ "../rtc_base:rtc_base_approved", >+ "video_codecs:video_codecs_api", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ } >+ > rtc_source_set("mock_audio_mixer") { > testonly = true > sources = [ >@@ -294,9 +395,20 @@ if (rtc_include_tests) { > ] > > deps = [ >- ":audio_mixer_api", > "../test:test_support", >- "//testing/gmock", >+ "audio:audio_mixer_api", >+ ] >+ } >+ >+ rtc_source_set("mock_peerconnectioninterface") { >+ testonly = true >+ sources = [ >+ "test/mock_peerconnectioninterface.h", >+ ] >+ >+ deps = [ >+ ":libjingle_peerconnection_api", >+ "../test:test_support", > ] > } > >@@ -310,43 +422,32 @@ if (rtc_include_tests) { > deps = [ > ":libjingle_peerconnection_api", > "../test:test_support", >- "//testing/gmock", > ] > } > >- rtc_source_set("mock_video_codec_factory") { >+ rtc_source_set("mock_video_bitrate_allocator") { > testonly = true > sources = [ >- "test/mock_video_decoder_factory.h", >- "test/mock_video_encoder_factory.h", >+ "test/mock_video_bitrate_allocator.h", > ] > > deps = [ >- "../api/video_codecs:video_codecs_api", >+ "../api/video:video_bitrate_allocator", > "../test:test_support", >- "//testing/gmock", > ] > } > >- rtc_source_set("fakemetricsobserver") { >+ rtc_source_set("mock_video_codec_factory") { > testonly = true > sources = [ >- "fakemetricsobserver.cc", >- "fakemetricsobserver.h", >+ "test/mock_video_decoder_factory.h", >+ "test/mock_video_encoder_factory.h", > ] >+ > deps = [ >- "../api:peerconnection_and_implicit_call_api", >- "../media:rtc_media_base", >- "../rtc_base:checks", >- "../rtc_base:rtc_base_approved", >+ "../api/video_codecs:video_codecs_api", >+ "../test:test_support", > ] >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- if (!build_with_mozilla) { >- deps += [ ":libjingle_peerconnection_api" ] >- } > } > > rtc_source_set("rtc_api_unittests") { >@@ -354,7 +455,6 @@ if (rtc_include_tests) { > > sources = [ > "array_view_unittest.cc", >- "optional_unittest.cc", > "ortc/mediadescription_unittest.cc", > "ortc/sessiondescription_unittest.cc", > "rtcerror_unittest.cc", >@@ -370,12 +470,12 @@ if (rtc_include_tests) { > ":array_view", > ":libjingle_peerconnection_api", > ":libjingle_peerconnection_test_api", >- ":optional", > ":ortc_api", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_base_tests_utils", > "../test:test_support", >+ "units:units_unittests", > ] > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/DEPS >index a537633981d..847cce259f9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/DEPS >@@ -4,22 +4,12 @@ include_rules = [ > "+media", > "+p2p", > "+pc", >+ "+logging/rtc_event_log/rtc_event_log_factory_interface.h", >+ "+modules/audio_processing/include", >+ "+system_wrappers/include", > ] > > specific_include_rules = { >- "peerconnection_jni\.cc": [ >- "+voice_engine", >- ], >- >- # TODO(ossu): Remove this exception when {builtin_,}audio_encoder_factory.h >- # has moved to api/. >- "peerconnectioninterface\.h": [ >- "+call/callfactoryinterface.h", >- "+logging/rtc_event_log/rtc_event_log_factory_interface.h", >- "+modules/audio_coding/codecs/audio_encoder_factory.h", >- "+modules/audio_coding/codecs/builtin_audio_encoder_factory.h", >- ], >- > # Needed because AudioEncoderOpus is in the wrong place for > # backwards compatibilty reasons. See > # https://bugs.chromium.org/p/webrtc/issues/detail?id=7847 >@@ -33,14 +23,7 @@ specific_include_rules = { > # since no one #includes them. > ".*\.cc": [ > "+modules/audio_coding", >- ], >- >- ".*i420_buffer\.h": [ >- "+system_wrappers/include/aligned_malloc.h", >- ], >- >- # Needed to use the APM statistics. >- "mediastreaminterface.h": [ >- "+modules/audio_processing/include/audio_processing_statistics.h", >+ "+modules/audio_processing", >+ "+modules/video_coding", > ], > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/OWNERS >index 1c30e33a68a..593de230d37 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/OWNERS >@@ -5,8 +5,9 @@ perkj@webrtc.org > solenberg@webrtc.org > tkchin@webrtc.org > tommi@webrtc.org >-deadbeef@webrtc.org > kwiberg@webrtc.org >+steveanton@webrtc.org >+shampson@webrtc.org > > per-file peerconnection*=hbos@webrtc.org > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view.h >index b27bd29a8e2..efc642d6fc6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view.h >@@ -12,6 +12,7 @@ > #define API_ARRAY_VIEW_H_ > > #include <algorithm> >+#include <array> > #include <type_traits> > > #include "rtc_base/checks.h" >@@ -94,7 +95,7 @@ class ArrayViewBase { > static_assert(Size > 0, "ArrayView size must be variable or non-negative"); > > public: >- ArrayViewBase(T* data, size_t) : data_(data) {} >+ ArrayViewBase(T* data, size_t size) : data_(data) {} > > static constexpr size_t size() { return Size; } > static constexpr bool empty() { return false; } >@@ -111,7 +112,7 @@ class ArrayViewBase { > template <typename T> > class ArrayViewBase<T, 0> { > public: >- explicit ArrayViewBase(T*, size_t) {} >+ explicit ArrayViewBase(T* data, size_t size) {} > > static constexpr size_t size() { return 0; } > static constexpr bool empty() { return true; } >@@ -169,7 +170,7 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> { > RTC_DCHECK_EQ(0, size); > } > >- // Construct an ArrayView from an array. >+ // Construct an ArrayView from a C-style array. > template <typename U, size_t N> > ArrayView(U (&array)[N]) // NOLINT > : ArrayView(array, N) { >@@ -177,6 +178,26 @@ class ArrayView final : public impl::ArrayViewBase<T, Size> { > "Array size must match ArrayView size"); > } > >+ // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> from a >+ // non-const std::array instance. For an ArrayView with variable size, the >+ // used ctor is ArrayView(U& u) instead. >+ template <typename U, >+ size_t N, >+ typename std::enable_if< >+ Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr> >+ ArrayView(std::array<U, N>& u) // NOLINT >+ : ArrayView(u.data(), u.size()) {} >+ >+ // (Only if size is fixed.) Construct a fixed size ArrayView<T, N> where T is >+ // const from a const(expr) std::array instance. For an ArrayView with >+ // variable size, the used ctor is ArrayView(U& u) instead. >+ template <typename U, >+ size_t N, >+ typename std::enable_if< >+ Size == static_cast<std::ptrdiff_t>(N)>::type* = nullptr> >+ ArrayView(const std::array<U, N>& u) // NOLINT >+ : ArrayView(u.data(), u.size()) {} >+ > // (Only if size is fixed.) Construct an ArrayView from any type U that has a > // static constexpr size() method whose return value is equal to Size, and a > // data() method whose return value converts implicitly to T*. In particular, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view_unittest.cc >index 48dff2c266e..694ed0b0085 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/array_view_unittest.cc >@@ -9,6 +9,7 @@ > */ > > #include <algorithm> >+#include <array> > #include <string> > #include <utility> > #include <vector> >@@ -180,6 +181,38 @@ TEST(ArrayViewTest, TestCopyAssignmentFixed) { > // v = z; // Compile error, because can't drop const. > } > >+TEST(ArrayViewTest, TestStdArray) { >+ constexpr size_t size = 5; >+ std::array<float, size> arr{}; >+ // Fixed size view. >+ rtc::ArrayView<float, size> arr_view_fixed(arr); >+ EXPECT_EQ(arr.data(), arr_view_fixed.data()); >+ static_assert(size == arr_view_fixed.size(), ""); >+ // Variable size view. >+ rtc::ArrayView<float> arr_view(arr); >+ EXPECT_EQ(arr.data(), arr_view.data()); >+ EXPECT_EQ(size, arr_view.size()); >+} >+ >+TEST(ArrayViewTest, TestConstStdArray) { >+ constexpr size_t size = 5; >+ >+ constexpr std::array<float, size> constexpr_arr{}; >+ rtc::ArrayView<const float, size> constexpr_arr_view(constexpr_arr); >+ EXPECT_EQ(constexpr_arr.data(), constexpr_arr_view.data()); >+ static_assert(constexpr_arr.size() == constexpr_arr_view.size(), ""); >+ >+ const std::array<float, size> const_arr{}; >+ rtc::ArrayView<const float, size> const_arr_view(const_arr); >+ EXPECT_EQ(const_arr.data(), const_arr_view.data()); >+ static_assert(const_arr.size() == const_arr_view.size(), ""); >+ >+ std::array<float, size> non_const_arr{}; >+ rtc::ArrayView<const float, size> non_const_arr_view(non_const_arr); >+ EXPECT_EQ(non_const_arr.data(), non_const_arr_view.data()); >+ static_assert(non_const_arr.size() == non_const_arr_view.size(), ""); >+} >+ > TEST(ArrayViewTest, TestStdVector) { > std::vector<int> v; > v.push_back(3); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/asyncresolverfactory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/asyncresolverfactory.h >new file mode 100644 >index 00000000000..3c3bb1e7030 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/asyncresolverfactory.h >@@ -0,0 +1,33 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#ifndef API_ASYNCRESOLVERFACTORY_H_ >+#define API_ASYNCRESOLVERFACTORY_H_ >+ >+#include "rtc_base/asyncresolverinterface.h" >+ >+namespace webrtc { >+ >+// An abstract factory for creating AsyncResolverInterfaces. This allows >+// client applications to provide WebRTC with their own mechanism for >+// performing DNS resolution. >+class AsyncResolverFactory { >+ public: >+ AsyncResolverFactory() = default; >+ virtual ~AsyncResolverFactory() = default; >+ >+ // The returned object is responsible for deleting itself after address >+ // resolution has completed. >+ virtual rtc::AsyncResolverInterface* Create() = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_ASYNCRESOLVERFACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/BUILD.gn >new file mode 100644 >index 00000000000..286a5a6f1c6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/BUILD.gn >@@ -0,0 +1,66 @@ >+# Copyright (c) 2018 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. >+ >+import("../../webrtc.gni") >+ >+rtc_source_set("audio_frame_api") { >+ visibility = [ "*" ] >+ sources = [ >+ "audio_frame.cc", >+ "audio_frame.h", >+ ] >+ >+ deps = [ >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+ >+rtc_source_set("audio_mixer_api") { >+ visibility = [ "*" ] >+ sources = [ >+ "audio_mixer.h", >+ ] >+ >+ deps = [ >+ ":audio_frame_api", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+ >+rtc_source_set("aec3_config") { >+ visibility = [ "*" ] >+ sources = [ >+ "echo_canceller3_config.cc", >+ "echo_canceller3_config.h", >+ ] >+} >+ >+rtc_source_set("aec3_factory") { >+ visibility = [ "*" ] >+ configs += [ "../../modules/audio_processing:apm_debug_dump" ] >+ sources = [ >+ "echo_canceller3_factory.cc", >+ "echo_canceller3_factory.h", >+ ] >+ >+ deps = [ >+ ":aec3_config", >+ ":echo_control", >+ "../../modules/audio_processing/aec3", >+ "../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("echo_control") { >+ visibility = [ "*" ] >+ sources = [ >+ "echo_control.h", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/OWNERS >new file mode 100644 >index 00000000000..bb499b450fc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/OWNERS >@@ -0,0 +1,2 @@ >+gustaf@webrtc.org >+peah@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.cc >new file mode 100644 >index 00000000000..75d30b0ba27 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.cc >@@ -0,0 +1,130 @@ >+/* >+ * Copyright (c) 2018 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 "api/audio/audio_frame.h" >+ >+#include <string.h> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/timeutils.h" >+ >+namespace webrtc { >+ >+AudioFrame::AudioFrame() { >+ // Visual Studio doesn't like this in the class definition. >+ static_assert(sizeof(data_) == kMaxDataSizeBytes, "kMaxDataSizeBytes"); >+} >+ >+void AudioFrame::Reset() { >+ ResetWithoutMuting(); >+ muted_ = true; >+} >+ >+void AudioFrame::ResetWithoutMuting() { >+ // TODO(wu): Zero is a valid value for |timestamp_|. We should initialize >+ // to an invalid value, or add a new member to indicate invalidity. >+ timestamp_ = 0; >+ elapsed_time_ms_ = -1; >+ ntp_time_ms_ = -1; >+ samples_per_channel_ = 0; >+ sample_rate_hz_ = 0; >+ num_channels_ = 0; >+ speech_type_ = kUndefined; >+ vad_activity_ = kVadUnknown; >+ profile_timestamp_ms_ = 0; >+} >+ >+void AudioFrame::UpdateFrame(uint32_t timestamp, >+ const int16_t* data, >+ size_t samples_per_channel, >+ int sample_rate_hz, >+ SpeechType speech_type, >+ VADActivity vad_activity, >+ size_t num_channels) { >+ timestamp_ = timestamp; >+ samples_per_channel_ = samples_per_channel; >+ sample_rate_hz_ = sample_rate_hz; >+ speech_type_ = speech_type; >+ vad_activity_ = vad_activity; >+ num_channels_ = num_channels; >+ >+ const size_t length = samples_per_channel * num_channels; >+ RTC_CHECK_LE(length, kMaxDataSizeSamples); >+ if (data != nullptr) { >+ memcpy(data_, data, sizeof(int16_t) * length); >+ muted_ = false; >+ } else { >+ muted_ = true; >+ } >+} >+ >+void AudioFrame::CopyFrom(const AudioFrame& src) { >+ if (this == &src) >+ return; >+ >+ timestamp_ = src.timestamp_; >+ elapsed_time_ms_ = src.elapsed_time_ms_; >+ ntp_time_ms_ = src.ntp_time_ms_; >+ muted_ = src.muted(); >+ samples_per_channel_ = src.samples_per_channel_; >+ sample_rate_hz_ = src.sample_rate_hz_; >+ speech_type_ = src.speech_type_; >+ vad_activity_ = src.vad_activity_; >+ num_channels_ = src.num_channels_; >+ >+ const size_t length = samples_per_channel_ * num_channels_; >+ RTC_CHECK_LE(length, kMaxDataSizeSamples); >+ if (!src.muted()) { >+ memcpy(data_, src.data(), sizeof(int16_t) * length); >+ muted_ = false; >+ } >+} >+ >+void AudioFrame::UpdateProfileTimeStamp() { >+ profile_timestamp_ms_ = rtc::TimeMillis(); >+} >+ >+int64_t AudioFrame::ElapsedProfileTimeMs() const { >+ if (profile_timestamp_ms_ == 0) { >+ // Profiling has not been activated. >+ return -1; >+ } >+ return rtc::TimeSince(profile_timestamp_ms_); >+} >+ >+const int16_t* AudioFrame::data() const { >+ return muted_ ? empty_data() : data_; >+} >+ >+// TODO(henrik.lundin) Can we skip zeroing the buffer? >+// See https://bugs.chromium.org/p/webrtc/issues/detail?id=5647. >+int16_t* AudioFrame::mutable_data() { >+ if (muted_) { >+ memset(data_, 0, kMaxDataSizeBytes); >+ muted_ = false; >+ } >+ return data_; >+} >+ >+void AudioFrame::Mute() { >+ muted_ = true; >+} >+ >+bool AudioFrame::muted() const { >+ return muted_; >+} >+ >+// static >+const int16_t* AudioFrame::empty_data() { >+ static int16_t* null_data = new int16_t[kMaxDataSizeSamples](); >+ return &null_data[0]; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.h >new file mode 100644 >index 00000000000..cc078771fae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_frame.h >@@ -0,0 +1,131 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_AUDIO_FRAME_H_ >+#define API_AUDIO_AUDIO_FRAME_H_ >+ >+#include <stddef.h> >+#include <stdint.h> >+ >+#include "rtc_base/constructormagic.h" >+ >+namespace webrtc { >+ >+/* This class holds up to 60 ms of super-wideband (32 kHz) stereo audio. It >+ * allows for adding and subtracting frames while keeping track of the resulting >+ * states. >+ * >+ * Notes >+ * - This is a de-facto api, not designed for external use. The AudioFrame class >+ * is in need of overhaul or even replacement, and anyone depending on it >+ * should be prepared for that. >+ * - The total number of samples is samples_per_channel_ * num_channels_. >+ * - Stereo data is interleaved starting with the left channel. >+ */ >+class AudioFrame { >+ public: >+ // Using constexpr here causes linker errors unless the variable also has an >+ // out-of-class definition, which is impractical in this header-only class. >+ // (This makes no sense because it compiles as an enum value, which we most >+ // certainly cannot take the address of, just fine.) C++17 introduces inline >+ // variables which should allow us to switch to constexpr and keep this a >+ // header-only class. >+ enum : size_t { >+ // Stereo, 32 kHz, 60 ms (2 * 32 * 60) >+ kMaxDataSizeSamples = 3840, >+ kMaxDataSizeBytes = kMaxDataSizeSamples * sizeof(int16_t), >+ }; >+ >+ enum VADActivity { kVadActive = 0, kVadPassive = 1, kVadUnknown = 2 }; >+ enum SpeechType { >+ kNormalSpeech = 0, >+ kPLC = 1, >+ kCNG = 2, >+ kPLCCNG = 3, >+ kUndefined = 4 >+ }; >+ >+ AudioFrame(); >+ >+ // Resets all members to their default state. >+ void Reset(); >+ // Same as Reset(), but leaves mute state unchanged. Muting a frame requires >+ // the buffer to be zeroed on the next call to mutable_data(). Callers >+ // intending to write to the buffer immediately after Reset() can instead use >+ // ResetWithoutMuting() to skip this wasteful zeroing. >+ void ResetWithoutMuting(); >+ >+ void UpdateFrame(uint32_t timestamp, >+ const int16_t* data, >+ size_t samples_per_channel, >+ int sample_rate_hz, >+ SpeechType speech_type, >+ VADActivity vad_activity, >+ size_t num_channels = 1); >+ >+ void CopyFrom(const AudioFrame& src); >+ >+ // Sets a wall-time clock timestamp in milliseconds to be used for profiling >+ // of time between two points in the audio chain. >+ // Example: >+ // t0: UpdateProfileTimeStamp() >+ // t1: ElapsedProfileTimeMs() => t1 - t0 [msec] >+ void UpdateProfileTimeStamp(); >+ // Returns the time difference between now and when UpdateProfileTimeStamp() >+ // was last called. Returns -1 if UpdateProfileTimeStamp() has not yet been >+ // called. >+ int64_t ElapsedProfileTimeMs() const; >+ >+ // data() returns a zeroed static buffer if the frame is muted. >+ // mutable_frame() always returns a non-static buffer; the first call to >+ // mutable_frame() zeros the non-static buffer and marks the frame unmuted. >+ const int16_t* data() const; >+ int16_t* mutable_data(); >+ >+ // Prefer to mute frames using AudioFrameOperations::Mute. >+ void Mute(); >+ // Frame is muted by default. >+ bool muted() const; >+ >+ // RTP timestamp of the first sample in the AudioFrame. >+ uint32_t timestamp_ = 0; >+ // Time since the first frame in milliseconds. >+ // -1 represents an uninitialized value. >+ int64_t elapsed_time_ms_ = -1; >+ // NTP time of the estimated capture time in local timebase in milliseconds. >+ // -1 represents an uninitialized value. >+ int64_t ntp_time_ms_ = -1; >+ size_t samples_per_channel_ = 0; >+ int sample_rate_hz_ = 0; >+ size_t num_channels_ = 0; >+ SpeechType speech_type_ = kUndefined; >+ VADActivity vad_activity_ = kVadUnknown; >+ // Monotonically increasing timestamp intended for profiling of audio frames. >+ // Typically used for measuring elapsed time between two different points in >+ // the audio path. No lock is used to save resources and we are thread safe >+ // by design. Also, absl::optional is not used since it will cause a "complex >+ // class/struct needs an explicit out-of-line destructor" build error. >+ int64_t profile_timestamp_ms_ = 0; >+ >+ private: >+ // A permamently zeroed out buffer to represent muted frames. This is a >+ // header-only class, so the only way to avoid creating a separate empty >+ // buffer per translation unit is to wrap a static in an inline function. >+ static const int16_t* empty_data(); >+ >+ int16_t data_[kMaxDataSizeSamples]; >+ bool muted_ = true; >+ >+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioFrame); >+}; >+ >+} // namespace webrtc >+ >+#endif // API_AUDIO_AUDIO_FRAME_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_mixer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_mixer.h >index 63b8b8ff9bb..14eefc173be 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_mixer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/audio_mixer.h >@@ -13,7 +13,7 @@ > > #include <memory> > >-#include "modules/include/module_common_types.h" >+#include "api/audio/audio_frame.h" > #include "rtc_base/refcount.h" > > namespace webrtc { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.cc >new file mode 100644 >index 00000000000..9af7f11c578 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.cc >@@ -0,0 +1,24 @@ >+/* >+ * Copyright (c) 2018 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 "api/audio/echo_canceller3_config.h" >+ >+namespace webrtc { >+ >+EchoCanceller3Config::EchoCanceller3Config() = default; >+EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) = >+ default; >+EchoCanceller3Config::Mask::Mask() = default; >+EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default; >+ >+EchoCanceller3Config::EchoModel::EchoModel() = default; >+EchoCanceller3Config::EchoModel::EchoModel( >+ const EchoCanceller3Config::EchoModel& e) = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.h >new file mode 100644 >index 00000000000..d633d047b0f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_config.h >@@ -0,0 +1,173 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ >+#define API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ >+ >+#include <stddef.h> // size_t >+ >+namespace webrtc { >+ >+// Configuration struct for EchoCanceller3 >+struct EchoCanceller3Config { >+ EchoCanceller3Config(); >+ EchoCanceller3Config(const EchoCanceller3Config& e); >+ struct Delay { >+ size_t default_delay = 5; >+ size_t down_sampling_factor = 4; >+ size_t num_filters = 6; >+ size_t api_call_jitter_blocks = 26; >+ size_t min_echo_path_delay_blocks = 0; >+ size_t delay_headroom_blocks = 2; >+ size_t hysteresis_limit_1_blocks = 1; >+ size_t hysteresis_limit_2_blocks = 1; >+ size_t skew_hysteresis_blocks = 3; >+ } delay; >+ >+ struct Filter { >+ struct MainConfiguration { >+ size_t length_blocks; >+ float leakage_converged; >+ float leakage_diverged; >+ float error_floor; >+ float noise_gate; >+ }; >+ >+ struct ShadowConfiguration { >+ size_t length_blocks; >+ float rate; >+ float noise_gate; >+ }; >+ >+ MainConfiguration main = {13, 0.00005f, 0.01f, 0.1f, 20075344.f}; >+ ShadowConfiguration shadow = {13, 0.7f, 20075344.f}; >+ >+ MainConfiguration main_initial = {12, 0.005f, 0.5f, 0.001f, 20075344.f}; >+ ShadowConfiguration shadow_initial = {12, 0.9f, 20075344.f}; >+ >+ size_t config_change_duration_blocks = 250; >+ } filter; >+ >+ struct Erle { >+ float min = 1.f; >+ float max_l = 4.f; >+ float max_h = 1.5f; >+ } erle; >+ >+ struct EpStrength { >+ float lf = 1.f; >+ float mf = 1.f; >+ float hf = 1.f; >+ float default_len = 0.88f; >+ bool reverb_based_on_render = true; >+ bool echo_can_saturate = true; >+ bool bounded_erl = false; >+ } ep_strength; >+ >+ struct Mask { >+ Mask(); >+ Mask(const Mask& m); >+ float m0 = 0.1f; >+ float m1 = 0.01f; >+ float m2 = 0.0001f; >+ float m3 = 0.01f; >+ float m5 = 0.01f; >+ float m6 = 0.0001f; >+ float m7 = 0.01f; >+ float m8 = 0.0001f; >+ float m9 = 0.1f; >+ >+ float gain_curve_offset = 1.45f; >+ float gain_curve_slope = 5.f; >+ float temporal_masking_lf = 0.9f; >+ float temporal_masking_hf = 0.6f; >+ size_t temporal_masking_lf_bands = 3; >+ } gain_mask; >+ >+ struct EchoAudibility { >+ float low_render_limit = 4 * 64.f; >+ float normal_render_limit = 64.f; >+ float floor_power = 2 * 64.f; >+ float audibility_threshold_lf = 10; >+ float audibility_threshold_mf = 10; >+ float audibility_threshold_hf = 10; >+ bool use_stationary_properties = true; >+ } echo_audibility; >+ >+ struct RenderLevels { >+ float active_render_limit = 100.f; >+ float poor_excitation_render_limit = 150.f; >+ float poor_excitation_render_limit_ds8 = 20.f; >+ } render_levels; >+ >+ struct GainUpdates { >+ struct GainChanges { >+ float max_inc; >+ float max_dec; >+ float rate_inc; >+ float rate_dec; >+ float min_inc; >+ float min_dec; >+ }; >+ >+ GainChanges low_noise = {2.f, 2.f, 1.4f, 1.4f, 1.1f, 1.1f}; >+ GainChanges initial = {2.f, 2.f, 1.5f, 1.5f, 1.2f, 1.2f}; >+ GainChanges normal = {2.f, 2.f, 1.5f, 1.5f, 1.2f, 1.2f}; >+ GainChanges saturation = {1.2f, 1.2f, 1.5f, 1.5f, 1.f, 1.f}; >+ GainChanges nonlinear = {1.5f, 1.5f, 1.2f, 1.2f, 1.1f, 1.1f}; >+ >+ float max_inc_factor = 2.0f; >+ float max_dec_factor_lf = 0.25f; >+ float floor_first_increase = 0.00001f; >+ } gain_updates; >+ >+ struct EchoRemovalControl { >+ struct GainRampup { >+ float initial_gain = 0.0f; >+ float first_non_zero_gain = 0.001f; >+ int non_zero_gain_blocks = 187; >+ int full_gain_blocks = 312; >+ } gain_rampup; >+ bool has_clock_drift = false; >+ bool linear_and_stable_echo_path = false; >+ } echo_removal_control; >+ >+ struct EchoModel { >+ EchoModel(); >+ EchoModel(const EchoModel& e); >+ size_t noise_floor_hold = 50; >+ float min_noise_floor_power = 1638400.f; >+ float stationary_gate_slope = 10.f; >+ float noise_gate_power = 27509.42f; >+ float noise_gate_slope = 0.3f; >+ size_t render_pre_window_size = 1; >+ size_t render_post_window_size = 1; >+ size_t render_pre_window_size_init = 10; >+ size_t render_post_window_size_init = 10; >+ float nonlinear_hold = 1; >+ float nonlinear_release = 0.001f; >+ } echo_model; >+ >+ struct Suppressor { >+ size_t bands_with_reliable_coherence = 5; >+ size_t nearend_average_blocks = 4; >+ >+ struct MaskingThresholds { >+ float enr_transparent; >+ float enr_suppress; >+ float emr_transparent; >+ }; >+ MaskingThresholds mask_lf = {.2f, .3f, .3f}; >+ MaskingThresholds mask_hf = {.07f, .1f, .3f}; >+ } suppressor; >+}; >+} // namespace webrtc >+ >+#endif // API_AUDIO_ECHO_CANCELLER3_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.cc >new file mode 100644 >index 00000000000..07f295f2ea2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.cc >@@ -0,0 +1,27 @@ >+/* >+ * Copyright (c) 2018 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 "api/audio/echo_canceller3_factory.h" >+ >+#include <memory> >+ >+#include "absl/memory/memory.h" >+#include "modules/audio_processing/aec3/echo_canceller3.h" >+ >+namespace webrtc { >+ >+EchoCanceller3Factory::EchoCanceller3Factory() {} >+ >+EchoCanceller3Factory::EchoCanceller3Factory(const EchoCanceller3Config& config) >+ : config_(config) {} >+ >+std::unique_ptr<EchoControl> EchoCanceller3Factory::Create(int sample_rate_hz) { >+ return absl::make_unique<EchoCanceller3>(config_, sample_rate_hz, true); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.h >new file mode 100644 >index 00000000000..f6db1168503 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_canceller3_factory.h >@@ -0,0 +1,38 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_ECHO_CANCELLER3_FACTORY_H_ >+#define API_AUDIO_ECHO_CANCELLER3_FACTORY_H_ >+ >+#include <memory> >+ >+#include "api/audio/echo_canceller3_config.h" >+#include "api/audio/echo_control.h" >+ >+namespace webrtc { >+ >+class EchoCanceller3Factory : public EchoControlFactory { >+ public: >+ // Factory producing EchoCanceller3 instances with the default configuration. >+ EchoCanceller3Factory(); >+ >+ // Factory producing EchoCanceller3 instances with the specified >+ // configuration. >+ explicit EchoCanceller3Factory(const EchoCanceller3Config& config); >+ >+ // Creates an EchoCanceller3 running at the specified sampling rate. >+ std::unique_ptr<EchoControl> Create(int sample_rate_hz) override; >+ >+ private: >+ const EchoCanceller3Config config_; >+}; >+} // namespace webrtc >+ >+#endif // API_AUDIO_ECHO_CANCELLER3_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_control.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_control.h >new file mode 100644 >index 00000000000..f549f40fbb0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/echo_control.h >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_ECHO_CONTROL_H_ >+#define API_AUDIO_ECHO_CONTROL_H_ >+ >+#include <memory> >+ >+namespace webrtc { >+ >+class AudioBuffer; >+ >+// Interface for an acoustic echo cancellation (AEC) submodule. >+class EchoControl { >+ public: >+ // Analysis (not changing) of the render signal. >+ virtual void AnalyzeRender(AudioBuffer* render) = 0; >+ >+ // Analysis (not changing) of the capture signal. >+ virtual void AnalyzeCapture(AudioBuffer* capture) = 0; >+ >+ // Processes the capture signal in order to remove the echo. >+ virtual void ProcessCapture(AudioBuffer* capture, bool echo_path_change) = 0; >+ >+ struct Metrics { >+ double echo_return_loss; >+ double echo_return_loss_enhancement; >+ int delay_ms; >+ }; >+ >+ // Collect current metrics from the echo controller. >+ virtual Metrics GetMetrics() const = 0; >+ >+ // Provides an optional external estimate of the audio buffer delay. >+ virtual void SetAudioBufferDelay(size_t delay_ms) = 0; >+ >+ virtual ~EchoControl() {} >+}; >+ >+// Interface for a factory that creates EchoControllers. >+class EchoControlFactory { >+ public: >+ virtual std::unique_ptr<EchoControl> Create(int sample_rate_hz) = 0; >+ virtual ~EchoControlFactory() = default; >+}; >+} // namespace webrtc >+ >+#endif // API_AUDIO_ECHO_CONTROL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/BUILD.gn >new file mode 100644 >index 00000000000..9a797788f68 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/BUILD.gn >@@ -0,0 +1,27 @@ >+# Copyright (c) 2018 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. >+ >+import("../../../webrtc.gni") >+if (is_android) { >+ import("//build/config/android/config.gni") >+ import("//build/config/android/rules.gni") >+} >+ >+if (rtc_include_tests) { >+ rtc_source_set("audio_api_unittests") { >+ testonly = true >+ sources = [ >+ "audio_frame_unittest.cc", >+ ] >+ deps = [ >+ "..:audio_frame_api", >+ "../../../rtc_base:rtc_base_approved", >+ "../../../test:test_support", >+ ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/audio_frame_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/audio_frame_unittest.cc >new file mode 100644 >index 00000000000..b969d90a4c1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio/test/audio_frame_unittest.cc >@@ -0,0 +1,113 @@ >+/* >+ * Copyright 2018 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 <string.h> // memcmp >+ >+#include "api/audio/audio_frame.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+ >+namespace { >+ >+bool AllSamplesAre(int16_t sample, const AudioFrame& frame) { >+ const int16_t* frame_data = frame.data(); >+ for (size_t i = 0; i < AudioFrame::kMaxDataSizeSamples; i++) { >+ if (frame_data[i] != sample) { >+ return false; >+ } >+ } >+ return true; >+} >+ >+constexpr uint32_t kTimestamp = 27; >+constexpr int kSampleRateHz = 16000; >+constexpr size_t kNumChannels = 1; >+constexpr size_t kSamplesPerChannel = kSampleRateHz / 100; >+ >+} // namespace >+ >+TEST(AudioFrameTest, FrameStartsMuted) { >+ AudioFrame frame; >+ EXPECT_TRUE(frame.muted()); >+ EXPECT_TRUE(AllSamplesAre(0, frame)); >+} >+ >+TEST(AudioFrameTest, UnmutedFrameIsInitiallyZeroed) { >+ AudioFrame frame; >+ frame.mutable_data(); >+ EXPECT_FALSE(frame.muted()); >+ EXPECT_TRUE(AllSamplesAre(0, frame)); >+} >+ >+TEST(AudioFrameTest, MutedFrameBufferIsZeroed) { >+ AudioFrame frame; >+ int16_t* frame_data = frame.mutable_data(); >+ for (size_t i = 0; i < AudioFrame::kMaxDataSizeSamples; i++) { >+ frame_data[i] = 17; >+ } >+ ASSERT_TRUE(AllSamplesAre(17, frame)); >+ frame.Mute(); >+ EXPECT_TRUE(frame.muted()); >+ EXPECT_TRUE(AllSamplesAre(0, frame)); >+} >+ >+TEST(AudioFrameTest, UpdateFrame) { >+ AudioFrame frame; >+ int16_t samples[kNumChannels * kSamplesPerChannel] = {17}; >+ frame.UpdateFrame(kTimestamp, samples, kSamplesPerChannel, kSampleRateHz, >+ AudioFrame::kPLC, AudioFrame::kVadActive, kNumChannels); >+ >+ EXPECT_EQ(kTimestamp, frame.timestamp_); >+ EXPECT_EQ(kSamplesPerChannel, frame.samples_per_channel_); >+ EXPECT_EQ(kSampleRateHz, frame.sample_rate_hz_); >+ EXPECT_EQ(AudioFrame::kPLC, frame.speech_type_); >+ EXPECT_EQ(AudioFrame::kVadActive, frame.vad_activity_); >+ EXPECT_EQ(kNumChannels, frame.num_channels_); >+ >+ EXPECT_FALSE(frame.muted()); >+ EXPECT_EQ(0, memcmp(samples, frame.data(), sizeof(samples))); >+ >+ frame.UpdateFrame(kTimestamp, nullptr /* data*/, kSamplesPerChannel, >+ kSampleRateHz, AudioFrame::kPLC, AudioFrame::kVadActive, >+ kNumChannels); >+ EXPECT_TRUE(frame.muted()); >+ EXPECT_TRUE(AllSamplesAre(0, frame)); >+} >+ >+TEST(AudioFrameTest, CopyFrom) { >+ AudioFrame frame1; >+ AudioFrame frame2; >+ >+ int16_t samples[kNumChannels * kSamplesPerChannel] = {17}; >+ frame2.UpdateFrame(kTimestamp, samples, kSamplesPerChannel, kSampleRateHz, >+ AudioFrame::kPLC, AudioFrame::kVadActive, kNumChannels); >+ frame1.CopyFrom(frame2); >+ >+ EXPECT_EQ(frame2.timestamp_, frame1.timestamp_); >+ EXPECT_EQ(frame2.samples_per_channel_, frame1.samples_per_channel_); >+ EXPECT_EQ(frame2.sample_rate_hz_, frame1.sample_rate_hz_); >+ EXPECT_EQ(frame2.speech_type_, frame1.speech_type_); >+ EXPECT_EQ(frame2.vad_activity_, frame1.vad_activity_); >+ EXPECT_EQ(frame2.num_channels_, frame1.num_channels_); >+ >+ EXPECT_EQ(frame2.muted(), frame1.muted()); >+ EXPECT_EQ(0, memcmp(frame2.data(), frame1.data(), sizeof(samples))); >+ >+ frame2.UpdateFrame(kTimestamp, nullptr /* data */, kSamplesPerChannel, >+ kSampleRateHz, AudioFrame::kPLC, AudioFrame::kVadActive, >+ kNumChannels); >+ frame1.CopyFrom(frame2); >+ >+ EXPECT_EQ(frame2.muted(), frame1.muted()); >+ EXPECT_EQ(0, memcmp(frame2.data(), frame1.data(), sizeof(samples))); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/BUILD.gn >index f7302600154..8e6a0f35225 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/BUILD.gn >@@ -15,6 +15,8 @@ if (is_android) { > rtc_source_set("audio_codecs_api") { > visibility = [ "*" ] > sources = [ >+ "audio_codec_pair_id.cc", >+ "audio_codec_pair_id.h", > "audio_decoder.cc", > "audio_decoder.h", > "audio_decoder_factory.h", >@@ -28,18 +30,18 @@ rtc_source_set("audio_codecs_api") { > ] > deps = [ > "..:array_view", >- "..:optional", > "../..:webrtc_common", >- "../../:typedefs", > "../../rtc_base:checks", > "../../rtc_base:deprecation", > "../../rtc_base:rtc_base_approved", > "../../rtc_base:sanitizer", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("builtin_audio_decoder_factory") { > visibility = [ "*" ] >+ allow_poison = [ "audio_codecs" ] > sources = [ > "builtin_audio_decoder_factory.cc", > "builtin_audio_decoder_factory.h", >@@ -69,6 +71,7 @@ rtc_static_library("builtin_audio_decoder_factory") { > > rtc_static_library("builtin_audio_encoder_factory") { > visibility = [ "*" ] >+ allow_poison = [ "audio_codecs" ] > sources = [ > "builtin_audio_encoder_factory.cc", > "builtin_audio_encoder_factory.h", >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/BUILD.gn >index f047bf132de..97248050012 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/BUILD.gn >@@ -14,30 +14,35 @@ if (is_android) { > > rtc_static_library("audio_encoder_L16") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_L16.cc", > "audio_encoder_L16.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:pcm16b", > "../../../rtc_base:rtc_base_approved", >+ "../../../rtc_base:safe_minmax", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_L16") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_L16.cc", > "audio_decoder_L16.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:pcm16b", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.cc >index dd14e601f4e..a71e3087007 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.cc >@@ -10,22 +10,22 @@ > > #include "api/audio_codecs/L16/audio_decoder_L16.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/pcm16b/audio_decoder_pcm16b.h" > #include "modules/audio_coding/codecs/pcm16b/pcm16b_common.h" > #include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderL16::Config> AudioDecoderL16::SdpToConfig( >+absl::optional<AudioDecoderL16::Config> AudioDecoderL16::SdpToConfig( > const SdpAudioFormat& format) { > Config config; > config.sample_rate_hz = format.clockrate_hz; > config.num_channels = rtc::checked_cast<int>(format.num_channels); > return STR_CASE_CMP(format.name.c_str(), "L16") == 0 && config.IsOk() >- ? rtc::Optional<Config>(config) >- : rtc::nullopt; >+ ? absl::optional<Config>(config) >+ : absl::nullopt; > } > > void AudioDecoderL16::AppendSupportedDecoders( >@@ -34,8 +34,9 @@ void AudioDecoderL16::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderL16::MakeAudioDecoder( >- const Config& config) { >- return config.IsOk() ? rtc::MakeUnique<AudioDecoderPcm16B>( >+ const Config& config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { >+ return config.IsOk() ? absl::make_unique<AudioDecoderPcm16B>( > config.sample_rate_hz, config.num_channels) > : nullptr; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.h >index db863b37de8..184ec24ed92 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_decoder_L16.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -34,9 +35,11 @@ struct AudioDecoderL16 { > int sample_rate_hz = 8000; > int num_channels = 1; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(const Config& config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ const Config& config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.cc >index d0d9f6f6448..b516f62863d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.cc >@@ -10,25 +10,34 @@ > > #include "api/audio_codecs/L16/audio_encoder_L16.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h" > #include "modules/audio_coding/codecs/pcm16b/pcm16b_common.h" > #include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" >+#include "rtc_base/numerics/safe_minmax.h" >+#include "rtc_base/string_to_number.h" > > namespace webrtc { > >-rtc::Optional<AudioEncoderL16::Config> AudioEncoderL16::SdpToConfig( >+absl::optional<AudioEncoderL16::Config> AudioEncoderL16::SdpToConfig( > const SdpAudioFormat& format) { > if (!rtc::IsValueInRangeForNumericType<int>(format.num_channels)) { >- return rtc::nullopt; >+ return absl::nullopt; > } > Config config; > config.sample_rate_hz = format.clockrate_hz; > config.num_channels = rtc::dchecked_cast<int>(format.num_channels); >+ auto ptime_iter = format.parameters.find("ptime"); >+ if (ptime_iter != format.parameters.end()) { >+ const auto ptime = rtc::StringToNumber<int>(ptime_iter->second); >+ if (ptime && *ptime > 0) { >+ config.frame_size_ms = rtc::SafeClamp(10 * (*ptime / 10), 10, 60); >+ } >+ } > return STR_CASE_CMP(format.name.c_str(), "L16") == 0 && config.IsOk() >- ? rtc::Optional<Config>(config) >- : rtc::nullopt; >+ ? absl::optional<Config>(config) >+ : absl::nullopt; > } > > void AudioEncoderL16::AppendSupportedEncoders( >@@ -46,14 +55,15 @@ AudioCodecInfo AudioEncoderL16::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderL16::MakeAudioEncoder( > const AudioEncoderL16::Config& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); > AudioEncoderPcm16B::Config c; > c.sample_rate_hz = config.sample_rate_hz; > c.num_channels = config.num_channels; > c.frame_size_ms = config.frame_size_ms; > c.payload_type = payload_type; >- return rtc::MakeUnique<AudioEncoderPcm16B>(c); >+ return absl::make_unique<AudioEncoderPcm16B>(c); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.h >index e099bd5747d..340e3af47fb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/L16/audio_encoder_L16.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -36,11 +37,13 @@ struct AudioEncoderL16 { > int num_channels = 1; > int frame_size_ms = 10; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const Config& config); >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(const Config& config, >- int payload_type); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ const Config& config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.cc >new file mode 100644 >index 00000000000..ac84107eda1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.cc >@@ -0,0 +1,90 @@ >+/* >+ * Copyright (c) 2018 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 "api/audio_codecs/audio_codec_pair_id.h" >+ >+#include <atomic> >+ >+#include "rtc_base/checks.h" >+ >+namespace webrtc { >+ >+namespace { >+ >+// Returns a new value that it has never returned before. You may call it at >+// most 2^63 times in the lifetime of the program. Note: The returned values >+// may be easily predictable. >+uint64_t GetNextId() { >+ static std::atomic<uint64_t> next_id(0); >+ >+ // Atomically increment `next_id`, and return the previous value. Relaxed >+ // memory order is sufficient, since all we care about is that different >+ // callers return different values. >+ const uint64_t new_id = next_id.fetch_add(1, std::memory_order_relaxed); >+ >+ // This check isn't atomic with the increment, so if we start 2^63 + 1 >+ // invocations of GetNextId() in parallel, the last one to do the atomic >+ // increment could return the ID 0 before any of the others had time to >+ // trigger this DCHECK. We blithely assume that this won't happen. >+ RTC_DCHECK_LT(new_id, uint64_t{1} << 63) << "Used up all ID values"; >+ >+ return new_id; >+} >+ >+// Make an integer ID more unpredictable. This is a 1:1 mapping, so you can >+// feed it any value, but the idea is that you can feed it a sequence such as >+// 0, 1, 2, ... and get a new sequence that isn't as trivially predictable, so >+// that users won't rely on it being consecutive or increasing or anything like >+// that. >+constexpr uint64_t ObfuscateId(uint64_t id) { >+ // Any nonzero coefficient that's relatively prime to 2^64 (that is, any odd >+ // number) and any constant will give a 1:1 mapping. These high-entropy >+ // values will prevent the sequence from being trivially predictable. >+ // >+ // Both the multiplication and the addition going to overflow almost always, >+ // but that's fine---we *want* arithmetic mod 2^64. >+ return uint64_t{0x85fdb20e1294309a} + uint64_t{0xc516ef5c37462469} * id; >+} >+ >+// The first ten values. Verified against the Python function >+// >+// def f(n): >+// return (0x85fdb20e1294309a + 0xc516ef5c37462469 * n) % 2**64 >+// >+// Callers should obviously not depend on these exact values... >+// >+// (On Visual C++, we have to disable warning C4307 (integral constant >+// overflow), even though unsigned integers have perfectly well-defined >+// overflow behavior.) >+#ifdef _MSC_VER >+#pragma warning(push) >+#pragma warning(disable : 4307) >+#endif >+static_assert(ObfuscateId(0) == uint64_t{0x85fdb20e1294309a}, ""); >+static_assert(ObfuscateId(1) == uint64_t{0x4b14a16a49da5503}, ""); >+static_assert(ObfuscateId(2) == uint64_t{0x102b90c68120796c}, ""); >+static_assert(ObfuscateId(3) == uint64_t{0xd5428022b8669dd5}, ""); >+static_assert(ObfuscateId(4) == uint64_t{0x9a596f7eefacc23e}, ""); >+static_assert(ObfuscateId(5) == uint64_t{0x5f705edb26f2e6a7}, ""); >+static_assert(ObfuscateId(6) == uint64_t{0x24874e375e390b10}, ""); >+static_assert(ObfuscateId(7) == uint64_t{0xe99e3d93957f2f79}, ""); >+static_assert(ObfuscateId(8) == uint64_t{0xaeb52cefccc553e2}, ""); >+static_assert(ObfuscateId(9) == uint64_t{0x73cc1c4c040b784b}, ""); >+#ifdef _MSC_VER >+#pragma warning(pop) >+#endif >+ >+} // namespace >+ >+AudioCodecPairId AudioCodecPairId::Create() { >+ return AudioCodecPairId(ObfuscateId(GetNextId())); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.h >new file mode 100644 >index 00000000000..b10f14ea66d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_codec_pair_id.h >@@ -0,0 +1,74 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_ >+#define API_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_ >+ >+#include <stdint.h> >+ >+#include <utility> >+ >+namespace webrtc { >+ >+class AudioCodecPairId final { >+ public: >+ // Copyable, but not default constructible. >+ AudioCodecPairId() = delete; >+ AudioCodecPairId(const AudioCodecPairId&) = default; >+ AudioCodecPairId(AudioCodecPairId&&) = default; >+ AudioCodecPairId& operator=(const AudioCodecPairId&) = default; >+ AudioCodecPairId& operator=(AudioCodecPairId&&) = default; >+ >+ friend void swap(AudioCodecPairId& a, AudioCodecPairId& b) { >+ using std::swap; >+ swap(a.id_, b.id_); >+ } >+ >+ // Creates a new ID, unequal to any previously created ID. >+ static AudioCodecPairId Create(); >+ >+ // IDs can be tested for equality. >+ friend bool operator==(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ == b.id_; >+ } >+ friend bool operator!=(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ != b.id_; >+ } >+ >+ // Comparisons. The ordering of ID values is completely arbitrary, but >+ // stable, so it's useful e.g. if you want to use IDs as keys in an ordered >+ // map. >+ friend bool operator<(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ < b.id_; >+ } >+ friend bool operator<=(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ <= b.id_; >+ } >+ friend bool operator>=(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ >= b.id_; >+ } >+ friend bool operator>(AudioCodecPairId a, AudioCodecPairId b) { >+ return a.id_ > b.id_; >+ } >+ >+ // Returns a numeric representation of the ID. The numeric values are >+ // completely arbitrary, but stable, collision-free, and reasonably evenly >+ // distributed, so they are e.g. useful as hash values in unordered maps. >+ uint64_t NumericRepresentation() const { return id_; } >+ >+ private: >+ explicit AudioCodecPairId(uint64_t id) : id_(id) {} >+ >+ uint64_t id_; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_AUDIO_CODECS_AUDIO_CODEC_PAIR_ID_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.cc >index ddb06d27eeb..00e45d960a4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.cc >@@ -33,14 +33,14 @@ class OldStyleEncodedFrame final : public AudioDecoder::EncodedAudioFrame { > return ret < 0 ? 0 : static_cast<size_t>(ret); > } > >- rtc::Optional<DecodeResult> Decode( >+ absl::optional<DecodeResult> Decode( > rtc::ArrayView<int16_t> decoded) const override { > auto speech_type = AudioDecoder::kSpeech; > const int ret = decoder_->Decode( > payload_.data(), payload_.size(), decoder_->SampleRateHz(), > decoded.size() * sizeof(int16_t), decoded.data(), &speech_type); >- return ret < 0 ? rtc::nullopt >- : rtc::Optional<DecodeResult>( >+ return ret < 0 ? absl::nullopt >+ : absl::optional<DecodeResult>( > {static_cast<size_t>(ret), speech_type}); > } > >@@ -51,6 +51,10 @@ class OldStyleEncodedFrame final : public AudioDecoder::EncodedAudioFrame { > > } // namespace > >+bool AudioDecoder::EncodedAudioFrame::IsDtxPacket() const { >+ return false; >+} >+ > AudioDecoder::ParseResult::ParseResult() = default; > AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default; > AudioDecoder::ParseResult::ParseResult(uint32_t timestamp, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.h >index 545bdf52cc0..9a955a6ecc0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder.h >@@ -14,11 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/array_view.h" >-#include "api/optional.h" > #include "rtc_base/buffer.h" > #include "rtc_base/constructormagic.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -48,13 +47,16 @@ class AudioDecoder { > // If no duration can be ascertained, returns zero. > virtual size_t Duration() const = 0; > >+ // Returns true if this packet contains DTX. >+ virtual bool IsDtxPacket() const; >+ > // Decodes this frame of audio and writes the result in |decoded|. > // |decoded| must be large enough to store as many samples as indicated by a >- // call to Duration() . On success, returns an rtc::Optional containing the >+ // call to Duration() . On success, returns an absl::optional containing the > // total number of samples across all channels, as well as whether the > // decoder produced comfort noise or speech. On failure, returns an empty >- // rtc::Optional. Decode may be called at most once per frame object. >- virtual rtc::Optional<DecodeResult> Decode( >+ // absl::optional. Decode may be called at most once per frame object. >+ virtual absl::optional<DecodeResult> Decode( > rtc::ArrayView<int16_t> decoded) const = 0; > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory.h >index ac0f4519d8e..90f93f0cd5f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory.h >@@ -14,6 +14,8 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" > #include "rtc_base/refcount.h" >@@ -28,8 +30,18 @@ class AudioDecoderFactory : public rtc::RefCountInterface { > > virtual bool IsSupportedDecoder(const SdpAudioFormat& format) = 0; > >+ // Create a new decoder instance. The `codec_pair_id` argument is used to >+ // link encoders and decoders that talk to the same remote entity; if a >+ // MakeAudioEncoder() and a MakeAudioDecoder() call receive non-null IDs that >+ // compare equal, the factory implementations may assume that the encoder and >+ // decoder form a pair. >+ // >+ // Note: Implementations need to be robust against combinations other than >+ // one encoder, one decoder getting the same ID; such decoders must still >+ // work. > virtual std::unique_ptr<AudioDecoder> MakeAudioDecoder( >- const SdpAudioFormat& format) = 0; >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) = 0; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory_template.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory_template.h >index f40c271ec8a..cdbe8bde7a8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory_template.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_decoder_factory_template.h >@@ -31,7 +31,8 @@ struct Helper<> { > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs) {} > static bool IsSupportedDecoder(const SdpAudioFormat& format) { return false; } > static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >- const SdpAudioFormat& format) { >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) { > return nullptr; > } > }; >@@ -47,16 +48,17 @@ struct Helper<T, Ts...> { > static bool IsSupportedDecoder(const SdpAudioFormat& format) { > auto opt_config = T::SdpToConfig(format); > static_assert(std::is_same<decltype(opt_config), >- rtc::Optional<typename T::Config>>::value, >+ absl::optional<typename T::Config>>::value, > "T::SdpToConfig() must return a value of type " >- "rtc::Optional<T::Config>"); >+ "absl::optional<T::Config>"); > return opt_config ? true : Helper<Ts...>::IsSupportedDecoder(format); > } > static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >- const SdpAudioFormat& format) { >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) { > auto opt_config = T::SdpToConfig(format); >- return opt_config ? T::MakeAudioDecoder(*opt_config) >- : Helper<Ts...>::MakeAudioDecoder(format); >+ return opt_config ? T::MakeAudioDecoder(*opt_config, codec_pair_id) >+ : Helper<Ts...>::MakeAudioDecoder(format, codec_pair_id); > } > }; > >@@ -74,8 +76,9 @@ class AudioDecoderFactoryT : public AudioDecoderFactory { > } > > std::unique_ptr<AudioDecoder> MakeAudioDecoder( >- const SdpAudioFormat& format) override { >- return Helper<Ts...>::MakeAudioDecoder(format); >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) override { >+ return Helper<Ts...>::MakeAudioDecoder(format, codec_pair_id); > } > }; > >@@ -89,7 +92,7 @@ class AudioDecoderFactoryT : public AudioDecoderFactory { > // // Converts |audio_format| to a ConfigType instance. Returns an empty > // // optional if |audio_format| doesn't correctly specify an decoder of our > // // type. >-// rtc::Optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format); >+// absl::optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format); > // > // // Appends zero or more AudioCodecSpecs to the list that will be returned > // // by AudioDecoderFactory::GetSupportedDecoders(). >@@ -97,7 +100,9 @@ class AudioDecoderFactoryT : public AudioDecoderFactory { > // > // // Creates an AudioDecoder for the specified format. Used to implement > // // AudioDecoderFactory::MakeAudioDecoder(). >-// std::unique_ptr<AudioDecoder> MakeAudioDecoder(const ConfigType& config); >+// std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+// const ConfigType& config, >+// absl::optional<AudioCodecPairId> codec_pair_id); > // > // ConfigType should be a type that encapsulates all the settings needed to > // create an AudioDecoder. T::Config (where T is the decoder struct) should >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.cc >index 4f9b9f0bb28..595c11131e7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.cc >@@ -85,12 +85,12 @@ void AudioEncoder::OnReceivedUplinkRecoverablePacketLossFraction( > float uplink_recoverable_packet_loss_fraction) {} > > void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) { >- OnReceivedUplinkBandwidth(target_audio_bitrate_bps, rtc::nullopt); >+ OnReceivedUplinkBandwidth(target_audio_bitrate_bps, absl::nullopt); > } > > void AudioEncoder::OnReceivedUplinkBandwidth( > int target_audio_bitrate_bps, >- rtc::Optional<int64_t> bwe_period_ms) {} >+ absl::optional<int64_t> bwe_period_ms) {} > > void AudioEncoder::OnReceivedRtt(int rtt_ms) {} > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.h >index 7ad9ba4d095..6a1f6534b21 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder.h >@@ -16,11 +16,10 @@ > #include <string> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/array_view.h" >-#include "api/optional.h" > #include "rtc_base/buffer.h" > #include "rtc_base/deprecation.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -34,30 +33,30 @@ struct ANAStats { > // Number of actions taken by the ANA bitrate controller since the start of > // the call. If this value is not set, it indicates that the bitrate > // controller is disabled. >- rtc::Optional<uint32_t> bitrate_action_counter; >+ absl::optional<uint32_t> bitrate_action_counter; > // Number of actions taken by the ANA channel controller since the start of > // the call. If this value is not set, it indicates that the channel > // controller is disabled. >- rtc::Optional<uint32_t> channel_action_counter; >+ absl::optional<uint32_t> channel_action_counter; > // Number of actions taken by the ANA DTX controller since the start of the > // call. If this value is not set, it indicates that the DTX controller is > // disabled. >- rtc::Optional<uint32_t> dtx_action_counter; >+ absl::optional<uint32_t> dtx_action_counter; > // Number of actions taken by the ANA FEC controller since the start of the > // call. If this value is not set, it indicates that the FEC controller is > // disabled. >- rtc::Optional<uint32_t> fec_action_counter; >+ absl::optional<uint32_t> fec_action_counter; > // Number of times the ANA frame length controller decided to increase the > // frame length since the start of the call. If this value is not set, it > // indicates that the frame length controller is disabled. >- rtc::Optional<uint32_t> frame_length_increase_counter; >+ absl::optional<uint32_t> frame_length_increase_counter; > // Number of times the ANA frame length controller decided to decrease the > // frame length since the start of the call. If this value is not set, it > // indicates that the frame length controller is disabled. >- rtc::Optional<uint32_t> frame_length_decrease_counter; >+ absl::optional<uint32_t> frame_length_decrease_counter; > // The uplink packet loss fractions as set by the ANA FEC controller. If this > // value is not set, it indicates that the ANA FEC controller is not active. >- rtc::Optional<float> uplink_packet_loss_fraction; >+ absl::optional<float> uplink_packet_loss_fraction; > }; > > // This is the interface class for encoders in AudioCoding module. Each codec >@@ -220,9 +219,8 @@ class AudioEncoder { > > // Provides target audio bitrate and corresponding probing interval of > // the bandwidth estimator to this encoder to allow it to adapt. >- virtual void OnReceivedUplinkBandwidth( >- int target_audio_bitrate_bps, >- rtc::Optional<int64_t> bwe_period_ms); >+ virtual void OnReceivedUplinkBandwidth(int target_audio_bitrate_bps, >+ absl::optional<int64_t> bwe_period_ms); > > // Provides RTT to this encoder to allow it to adapt. > virtual void OnReceivedRtt(int rtt_ms); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory.h >index 43461f6b9a6..fb4e23ffe78 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory.h >@@ -14,6 +14,8 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" > #include "rtc_base/refcount.h" >@@ -30,15 +32,25 @@ class AudioEncoderFactory : public rtc::RefCountInterface { > // Returns information about how this format would be encoded, provided it's > // supported. More format and format variations may be supported than those > // returned by GetSupportedEncoders(). >- virtual rtc::Optional<AudioCodecInfo> QueryAudioEncoder( >+ virtual absl::optional<AudioCodecInfo> QueryAudioEncoder( > const SdpAudioFormat& format) = 0; > >- // Creates an AudioEncoder for the specified format. The encoder will tags its >- // payloads with the specified payload type. >+ // Creates an AudioEncoder for the specified format. The encoder will tags >+ // its payloads with the specified payload type. The `codec_pair_id` argument >+ // is used to link encoders and decoders that talk to the same remote entity; >+ // if a MakeAudioEncoder() and a MakeAudioDecoder() call receive non-null IDs >+ // that compare equal, the factory implementations may assume that the >+ // encoder and decoder form a pair. >+ // >+ // Note: Implementations need to be robust against combinations other than >+ // one encoder, one decoder getting the same ID; such encoders must still >+ // work. >+ // > // TODO(ossu): Try to avoid audio encoders having to know their payload type. > virtual std::unique_ptr<AudioEncoder> MakeAudioEncoder( > int payload_type, >- const SdpAudioFormat& format) = 0; >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) = 0; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory_template.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory_template.h >index 060ba8cb045..376b39e4c6f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory_template.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_encoder_factory_template.h >@@ -29,13 +29,14 @@ struct Helper; > template <> > struct Helper<> { > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs) {} >- static rtc::Optional<AudioCodecInfo> QueryAudioEncoder( >+ static absl::optional<AudioCodecInfo> QueryAudioEncoder( > const SdpAudioFormat& format) { >- return rtc::nullopt; >+ return absl::nullopt; > } > static std::unique_ptr<AudioEncoder> MakeAudioEncoder( > int payload_type, >- const SdpAudioFormat& format) { >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) { > return nullptr; > } > }; >@@ -48,25 +49,27 @@ struct Helper<T, Ts...> { > T::AppendSupportedEncoders(specs); > Helper<Ts...>::AppendSupportedEncoders(specs); > } >- static rtc::Optional<AudioCodecInfo> QueryAudioEncoder( >+ static absl::optional<AudioCodecInfo> QueryAudioEncoder( > const SdpAudioFormat& format) { > auto opt_config = T::SdpToConfig(format); > static_assert(std::is_same<decltype(opt_config), >- rtc::Optional<typename T::Config>>::value, >+ absl::optional<typename T::Config>>::value, > "T::SdpToConfig() must return a value of type " >- "rtc::Optional<T::Config>"); >- return opt_config ? rtc::Optional<AudioCodecInfo>( >+ "absl::optional<T::Config>"); >+ return opt_config ? absl::optional<AudioCodecInfo>( > T::QueryAudioEncoder(*opt_config)) > : Helper<Ts...>::QueryAudioEncoder(format); > } > static std::unique_ptr<AudioEncoder> MakeAudioEncoder( > int payload_type, >- const SdpAudioFormat& format) { >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) { > auto opt_config = T::SdpToConfig(format); > if (opt_config) { >- return T::MakeAudioEncoder(*opt_config, payload_type); >+ return T::MakeAudioEncoder(*opt_config, payload_type, codec_pair_id); > } else { >- return Helper<Ts...>::MakeAudioEncoder(payload_type, format); >+ return Helper<Ts...>::MakeAudioEncoder(payload_type, format, >+ codec_pair_id); > } > } > }; >@@ -80,15 +83,16 @@ class AudioEncoderFactoryT : public AudioEncoderFactory { > return specs; > } > >- rtc::Optional<AudioCodecInfo> QueryAudioEncoder( >+ absl::optional<AudioCodecInfo> QueryAudioEncoder( > const SdpAudioFormat& format) override { > return Helper<Ts...>::QueryAudioEncoder(format); > } > > std::unique_ptr<AudioEncoder> MakeAudioEncoder( > int payload_type, >- const SdpAudioFormat& format) override { >- return Helper<Ts...>::MakeAudioEncoder(payload_type, format); >+ const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id) override { >+ return Helper<Ts...>::MakeAudioEncoder(payload_type, format, codec_pair_id); > } > }; > >@@ -102,7 +106,7 @@ class AudioEncoderFactoryT : public AudioEncoderFactory { > // // Converts |audio_format| to a ConfigType instance. Returns an empty > // // optional if |audio_format| doesn't correctly specify an encoder of our > // // type. >-// rtc::Optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format); >+// absl::optional<ConfigType> SdpToConfig(const SdpAudioFormat& audio_format); > // > // // Appends zero or more AudioCodecSpecs to the list that will be returned > // // by AudioEncoderFactory::GetSupportedEncoders(). >@@ -114,8 +118,10 @@ class AudioEncoderFactoryT : public AudioEncoderFactory { > // > // // Creates an AudioEncoder for the specified format. Used to implement > // // AudioEncoderFactory::MakeAudioEncoder(). >-// std::unique_ptr<AudioEncoder> MakeAudioEncoder(const ConfigType& config, >-// int payload_type); >+// std::unique_ptr<AudioDecoder> MakeAudioEncoder( >+// const ConfigType& config, >+// int payload_type, >+// absl::optional<AudioCodecPairId> codec_pair_id); > // > // ConfigType should be a type that encapsulates all the settings needed to > // create an AudioEncoder. T::Config (where T is the encoder struct) should >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.cc >index 82c166f5c00..9db5ce01dc8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.cc >@@ -68,20 +68,6 @@ void swap(SdpAudioFormat& a, SdpAudioFormat& b) { > swap(a.parameters, b.parameters); > } > >-std::ostream& operator<<(std::ostream& os, const SdpAudioFormat& saf) { >- os << "{name: " << saf.name; >- os << ", clockrate_hz: " << saf.clockrate_hz; >- os << ", num_channels: " << saf.num_channels; >- os << ", parameters: {"; >- const char* sep = ""; >- for (const auto& kv : saf.parameters) { >- os << sep << kv.first << ": " << kv.second; >- sep = ", "; >- } >- os << "}}"; >- return os; >-} >- > AudioCodecInfo::AudioCodecInfo(int sample_rate_hz, > size_t num_channels, > int bitrate_bps) >@@ -108,23 +94,4 @@ AudioCodecInfo::AudioCodecInfo(int sample_rate_hz, > RTC_DCHECK_GE(max_bitrate_bps, default_bitrate_bps); > } > >-std::ostream& operator<<(std::ostream& os, const AudioCodecInfo& aci) { >- os << "{sample_rate_hz: " << aci.sample_rate_hz; >- os << ", num_channels: " << aci.num_channels; >- os << ", default_bitrate_bps: " << aci.default_bitrate_bps; >- os << ", min_bitrate_bps: " << aci.min_bitrate_bps; >- os << ", max_bitrate_bps: " << aci.max_bitrate_bps; >- os << ", allow_comfort_noise: " << aci.allow_comfort_noise; >- os << ", supports_network_adaption: " << aci.supports_network_adaption; >- os << "}"; >- return os; >-} >- >-std::ostream& operator<<(std::ostream& os, const AudioCodecSpec& acs) { >- os << "{format: " << acs.format; >- os << ", info: " << acs.info; >- os << "}"; >- return os; >-} >- > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.h >index 12e9552e933..d132067d095 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/audio_format.h >@@ -12,11 +12,11 @@ > #define API_AUDIO_CODECS_AUDIO_FORMAT_H_ > > #include <map> >-#include <ostream> > #include <string> > #include <utility> > >-#include "api/optional.h" >+#include "absl/types/optional.h" >+#include "rtc_base/checks.h" > > namespace webrtc { > >@@ -61,7 +61,6 @@ struct SdpAudioFormat { > }; > > void swap(SdpAudioFormat& a, SdpAudioFormat& b); >-std::ostream& operator<<(std::ostream& os, const SdpAudioFormat& saf); > > // Information about how an audio format is treated by the codec implementation. > // Contains basic information, such as sample rate and number of channels, which >@@ -120,8 +119,6 @@ struct AudioCodecInfo { > // network conditions. > }; > >-std::ostream& operator<<(std::ostream& os, const AudioCodecInfo& aci); >- > // AudioCodecSpec ties an audio format to specific information about the codec > // and its implementation. > struct AudioCodecSpec { >@@ -135,8 +132,6 @@ struct AudioCodecSpec { > AudioCodecInfo info; > }; > >-std::ostream& operator<<(std::ostream& os, const AudioCodecSpec& acs); >- > } // namespace webrtc > > #endif // API_AUDIO_CODECS_AUDIO_FORMAT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_decoder_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_decoder_factory.cc >index 9520d2a9e73..e3ca1b0e06d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_decoder_factory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_decoder_factory.cc >@@ -33,14 +33,17 @@ namespace { > template <typename T> > struct NotAdvertised { > using Config = typename T::Config; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format) { >+ static absl::optional<Config> SdpToConfig( >+ const SdpAudioFormat& audio_format) { > return T::SdpToConfig(audio_format); > } > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs) { > // Don't advertise support for anything. > } >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(const Config& config) { >- return T::MakeAudioDecoder(config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ const Config& config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt) { >+ return T::MakeAudioDecoder(config, codec_pair_id); > } > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_encoder_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_encoder_factory.cc >index 877f85026f3..c0caff42e28 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_encoder_factory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/builtin_audio_encoder_factory.cc >@@ -33,7 +33,8 @@ namespace { > template <typename T> > struct NotAdvertised { > using Config = typename T::Config; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format) { >+ static absl::optional<Config> SdpToConfig( >+ const SdpAudioFormat& audio_format) { > return T::SdpToConfig(audio_format); > } > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs) { >@@ -42,9 +43,11 @@ struct NotAdvertised { > static AudioCodecInfo QueryAudioEncoder(const Config& config) { > return T::QueryAudioEncoder(config); > } >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(const Config& config, >- int payload_type) { >- return T::MakeAudioEncoder(config, payload_type); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ const Config& config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt) { >+ return T::MakeAudioEncoder(config, payload_type, codec_pair_id); > } > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/BUILD.gn >index b62c6790769..169172a6682 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/BUILD.gn >@@ -14,30 +14,35 @@ if (is_android) { > > rtc_static_library("audio_encoder_g711") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_g711.cc", > "audio_encoder_g711.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:g711", > "../../../rtc_base:rtc_base_approved", >+ "../../../rtc_base:safe_minmax", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_g711") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_g711.cc", > "audio_decoder_g711.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:g711", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc >index 71d363be735..cb16584cdee 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.cc >@@ -13,14 +13,14 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/g711/audio_decoder_pcm.h" > #include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderG711::Config> AudioDecoderG711::SdpToConfig( >+absl::optional<AudioDecoderG711::Config> AudioDecoderG711::SdpToConfig( > const SdpAudioFormat& format) { > const bool is_pcmu = STR_CASE_CMP(format.name.c_str(), "PCMU") == 0; > const bool is_pcma = STR_CASE_CMP(format.name.c_str(), "PCMA") == 0; >@@ -32,7 +32,7 @@ rtc::Optional<AudioDecoderG711::Config> AudioDecoderG711::SdpToConfig( > RTC_DCHECK(config.IsOk()); > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -44,13 +44,14 @@ void AudioDecoderG711::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderG711::MakeAudioDecoder( >- const Config& config) { >+ const Config& config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); > switch (config.type) { > case Config::Type::kPcmU: >- return rtc::MakeUnique<AudioDecoderPcmU>(config.num_channels); >+ return absl::make_unique<AudioDecoderPcmU>(config.num_channels); > case Config::Type::kPcmA: >- return rtc::MakeUnique<AudioDecoderPcmA>(config.num_channels); >+ return absl::make_unique<AudioDecoderPcmA>(config.num_channels); > default: > return nullptr; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.h >index 652e23ebcfd..8275a8c7a14 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_decoder_g711.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -33,9 +34,11 @@ struct AudioDecoderG711 { > Type type; > int num_channels; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(const Config& config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ const Config& config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc >index 7029caeaad1..1d5e541276b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.cc >@@ -13,16 +13,16 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/g711/audio_encoder_pcm.h" > #include "rtc_base/numerics/safe_conversions.h" > #include "rtc_base/numerics/safe_minmax.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/string_to_number.h" > > namespace webrtc { > >-rtc::Optional<AudioEncoderG711::Config> AudioEncoderG711::SdpToConfig( >+absl::optional<AudioEncoderG711::Config> AudioEncoderG711::SdpToConfig( > const SdpAudioFormat& format) { > const bool is_pcmu = STR_CASE_CMP(format.name.c_str(), "PCMU") == 0; > const bool is_pcma = STR_CASE_CMP(format.name.c_str(), "PCMA") == 0; >@@ -42,7 +42,7 @@ rtc::Optional<AudioEncoderG711::Config> AudioEncoderG711::SdpToConfig( > RTC_DCHECK(config.IsOk()); > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -61,7 +61,8 @@ AudioCodecInfo AudioEncoderG711::QueryAudioEncoder(const Config& config) { > > std::unique_ptr<AudioEncoder> AudioEncoderG711::MakeAudioEncoder( > const Config& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); > switch (config.type) { > case Config::Type::kPcmU: { >@@ -69,14 +70,14 @@ std::unique_ptr<AudioEncoder> AudioEncoderG711::MakeAudioEncoder( > impl_config.num_channels = config.num_channels; > impl_config.frame_size_ms = config.frame_size_ms; > impl_config.payload_type = payload_type; >- return rtc::MakeUnique<AudioEncoderPcmU>(impl_config); >+ return absl::make_unique<AudioEncoderPcmU>(impl_config); > } > case Config::Type::kPcmA: { > AudioEncoderPcmA::Config impl_config; > impl_config.num_channels = config.num_channels; > impl_config.frame_size_ms = config.frame_size_ms; > impl_config.payload_type = payload_type; >- return rtc::MakeUnique<AudioEncoderPcmA>(impl_config); >+ return absl::make_unique<AudioEncoderPcmA>(impl_config); > } > default: { return nullptr; } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.h >index ecdb9a39017..6b6eb5fce0c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g711/audio_encoder_g711.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -35,12 +36,14 @@ struct AudioEncoderG711 { > int num_channels = 1; > int frame_size_ms = 20; > }; >- static rtc::Optional<AudioEncoderG711::Config> SdpToConfig( >+ static absl::optional<AudioEncoderG711::Config> SdpToConfig( > const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const Config& config); >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(const Config& config, >- int payload_type); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ const Config& config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/BUILD.gn >index 0d12195b692..50b1396d291 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/BUILD.gn >@@ -21,6 +21,7 @@ rtc_source_set("audio_encoder_g722_config") { > > rtc_static_library("audio_encoder_g722") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_g722.cc", > "audio_encoder_g722.h", >@@ -28,24 +29,28 @@ rtc_static_library("audio_encoder_g722") { > deps = [ > ":audio_encoder_g722_config", > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:g722", > "../../../rtc_base:rtc_base_approved", >+ "../../../rtc_base:safe_minmax", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_g722") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_g722.cc", > "audio_decoder_g722.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:g722", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.cc >index 961b1267fe1..f1e2afbab50 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.cc >@@ -13,21 +13,21 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/g722/audio_decoder_g722.h" > #include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderG722::Config> AudioDecoderG722::SdpToConfig( >+absl::optional<AudioDecoderG722::Config> AudioDecoderG722::SdpToConfig( > const SdpAudioFormat& format) { > return STR_CASE_CMP(format.name.c_str(), "G722") == 0 && > format.clockrate_hz == 8000 && > (format.num_channels == 1 || format.num_channels == 2) >- ? rtc::Optional<Config>( >+ ? absl::optional<Config>( > Config{rtc::dchecked_cast<int>(format.num_channels)}) >- : rtc::nullopt; >+ : absl::nullopt; > } > > void AudioDecoderG722::AppendSupportedDecoders( >@@ -36,12 +36,13 @@ void AudioDecoderG722::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderG722::MakeAudioDecoder( >- Config config) { >+ Config config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > switch (config.num_channels) { > case 1: >- return rtc::MakeUnique<AudioDecoderG722Impl>(); >+ return absl::make_unique<AudioDecoderG722Impl>(); > case 2: >- return rtc::MakeUnique<AudioDecoderG722StereoImpl>(); >+ return absl::make_unique<AudioDecoderG722StereoImpl>(); > default: > return nullptr; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.h >index fddb89aaf84..b7bb0893f33 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_decoder_g722.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -29,9 +30,11 @@ struct AudioDecoderG722 { > bool IsOk() const { return num_channels == 1 || num_channels == 2; } > int num_channels; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ Config config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc >index f8aa6162d23..0cf71639bf3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.cc >@@ -13,20 +13,20 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/g722/audio_encoder_g722.h" > #include "rtc_base/numerics/safe_conversions.h" > #include "rtc_base/numerics/safe_minmax.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/string_to_number.h" > > namespace webrtc { > >-rtc::Optional<AudioEncoderG722Config> AudioEncoderG722::SdpToConfig( >+absl::optional<AudioEncoderG722Config> AudioEncoderG722::SdpToConfig( > const SdpAudioFormat& format) { > if (STR_CASE_CMP(format.name.c_str(), "g722") != 0 || > format.clockrate_hz != 8000) { >- return rtc::nullopt; >+ return absl::nullopt; > } > > AudioEncoderG722Config config; >@@ -39,8 +39,8 @@ rtc::Optional<AudioEncoderG722Config> AudioEncoderG722::SdpToConfig( > config.frame_size_ms = rtc::SafeClamp<int>(whole_packets * 10, 10, 60); > } > } >- return config.IsOk() ? rtc::Optional<AudioEncoderG722Config>(config) >- : rtc::nullopt; >+ return config.IsOk() ? absl::optional<AudioEncoderG722Config>(config) >+ : absl::nullopt; > } > > void AudioEncoderG722::AppendSupportedEncoders( >@@ -59,9 +59,10 @@ AudioCodecInfo AudioEncoderG722::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderG722::MakeAudioEncoder( > const AudioEncoderG722Config& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); >- return rtc::MakeUnique<AudioEncoderG722Impl>(config, payload_type); >+ return absl::make_unique<AudioEncoderG722Impl>(config, payload_type); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.h >index 0763615cf7c..b97fe1b1478 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/g722/audio_encoder_g722.h >@@ -14,10 +14,11 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" > #include "api/audio_codecs/g722/audio_encoder_g722_config.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -27,13 +28,14 @@ namespace webrtc { > // NOTE: This struct is still under development and may change without notice. > struct AudioEncoderG722 { > using Config = AudioEncoderG722Config; >- static rtc::Optional<AudioEncoderG722Config> SdpToConfig( >+ static absl::optional<AudioEncoderG722Config> SdpToConfig( > const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const AudioEncoderG722Config& config); > static std::unique_ptr<AudioEncoder> MakeAudioEncoder( > const AudioEncoderG722Config& config, >- int payload_type); >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/BUILD.gn >index 944d4eb8745..d4f504fd4f9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/BUILD.gn >@@ -21,6 +21,7 @@ rtc_source_set("audio_encoder_ilbc_config") { > > rtc_static_library("audio_encoder_ilbc") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_ilbc.cc", > "audio_encoder_ilbc.h", >@@ -28,24 +29,28 @@ rtc_static_library("audio_encoder_ilbc") { > deps = [ > ":audio_encoder_ilbc_config", > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:ilbc", > "../../../rtc_base:rtc_base_approved", >+ "../../../rtc_base:safe_minmax", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_ilbc") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_ilbc.cc", > "audio_decoder_ilbc.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:ilbc", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc >index 2ffae480ca8..1f4c475c406 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.cc >@@ -13,18 +13,18 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/ilbc/audio_decoder_ilbc.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderIlbc::Config> AudioDecoderIlbc::SdpToConfig( >+absl::optional<AudioDecoderIlbc::Config> AudioDecoderIlbc::SdpToConfig( > const SdpAudioFormat& format) { > return STR_CASE_CMP(format.name.c_str(), "ILBC") == 0 && > format.clockrate_hz == 8000 && format.num_channels == 1 >- ? rtc::Optional<Config>(Config()) >- : rtc::nullopt; >+ ? absl::optional<Config>(Config()) >+ : absl::nullopt; > } > > void AudioDecoderIlbc::AppendSupportedDecoders( >@@ -33,8 +33,9 @@ void AudioDecoderIlbc::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderIlbc::MakeAudioDecoder( >- Config config) { >- return rtc::MakeUnique<AudioDecoderIlbcImpl>(); >+ Config config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { >+ return absl::make_unique<AudioDecoderIlbcImpl>(); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h >index f7292d60c63..20f6ffd287f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_decoder_ilbc.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -26,9 +27,11 @@ namespace webrtc { > // NOTE: This struct is still under development and may change without notice. > struct AudioDecoderIlbc { > struct Config {}; // Empty---no config values needed! >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ Config config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc >index 6db88402e39..2ae75474ccd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.cc >@@ -13,11 +13,11 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/ilbc/audio_encoder_ilbc.h" > #include "rtc_base/numerics/safe_conversions.h" > #include "rtc_base/numerics/safe_minmax.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/string_to_number.h" > > namespace webrtc { >@@ -38,11 +38,11 @@ int GetIlbcBitrate(int ptime) { > } > } // namespace > >-rtc::Optional<AudioEncoderIlbcConfig> AudioEncoderIlbc::SdpToConfig( >+absl::optional<AudioEncoderIlbcConfig> AudioEncoderIlbc::SdpToConfig( > const SdpAudioFormat& format) { > if (STR_CASE_CMP(format.name.c_str(), "ILBC") != 0 || > format.clockrate_hz != 8000 || format.num_channels != 1) { >- return rtc::nullopt; >+ return absl::nullopt; > } > > AudioEncoderIlbcConfig config; >@@ -54,8 +54,8 @@ rtc::Optional<AudioEncoderIlbcConfig> AudioEncoderIlbc::SdpToConfig( > config.frame_size_ms = rtc::SafeClamp<int>(whole_packets * 10, 20, 60); > } > } >- return config.IsOk() ? rtc::Optional<AudioEncoderIlbcConfig>(config) >- : rtc::nullopt; >+ return config.IsOk() ? absl::optional<AudioEncoderIlbcConfig>(config) >+ : absl::nullopt; > } > > void AudioEncoderIlbc::AppendSupportedEncoders( >@@ -73,9 +73,10 @@ AudioCodecInfo AudioEncoderIlbc::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderIlbc::MakeAudioEncoder( > const AudioEncoderIlbcConfig& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); >- return rtc::MakeUnique<AudioEncoderIlbcImpl>(config, payload_type); >+ return absl::make_unique<AudioEncoderIlbcImpl>(config, payload_type); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h >index dd653757742..0a86b162e81 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/ilbc/audio_encoder_ilbc.h >@@ -14,10 +14,11 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" > #include "api/audio_codecs/ilbc/audio_encoder_ilbc_config.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -27,13 +28,14 @@ namespace webrtc { > // NOTE: This struct is still under development and may change without notice. > struct AudioEncoderIlbc { > using Config = AudioEncoderIlbcConfig; >- static rtc::Optional<AudioEncoderIlbcConfig> SdpToConfig( >+ static absl::optional<AudioEncoderIlbcConfig> SdpToConfig( > const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const AudioEncoderIlbcConfig& config); > static std::unique_ptr<AudioEncoder> MakeAudioEncoder( > const AudioEncoderIlbcConfig& config, >- int payload_type); >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/BUILD.gn >index f63435c93aa..ed9d9622577 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/BUILD.gn >@@ -19,6 +19,7 @@ if (is_android) { > > rtc_source_set("audio_encoder_isac") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > public = [ > "audio_encoder_isac.h", > ] >@@ -36,6 +37,7 @@ rtc_source_set("audio_encoder_isac") { > > rtc_source_set("audio_decoder_isac") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > public = [ > "audio_decoder_isac.h", > ] >@@ -68,60 +70,68 @@ config("isac_config") { > > rtc_static_library("audio_encoder_isac_fix") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_isac_fix.cc", > "audio_encoder_isac_fix.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:isac_fix", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_isac_fix") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_isac_fix.cc", > "audio_decoder_isac_fix.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:isac_fix", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_encoder_isac_float") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_encoder_isac_float.cc", > "audio_encoder_isac_float.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:isac", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_isac_float") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_isac_float.cc", > "audio_decoder_isac_float.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:isac", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.cc >index 011be4f24a7..446640ff70c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.cc >@@ -10,18 +10,18 @@ > > #include "api/audio_codecs/isac/audio_decoder_isac_fix.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/isac/fix/include/audio_decoder_isacfix.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderIsacFix::Config> AudioDecoderIsacFix::SdpToConfig( >+absl::optional<AudioDecoderIsacFix::Config> AudioDecoderIsacFix::SdpToConfig( > const SdpAudioFormat& format) { > return STR_CASE_CMP(format.name.c_str(), "ISAC") == 0 && > format.clockrate_hz == 16000 && format.num_channels == 1 >- ? rtc::Optional<Config>(Config()) >- : rtc::nullopt; >+ ? absl::optional<Config>(Config()) >+ : absl::nullopt; > } > > void AudioDecoderIsacFix::AppendSupportedDecoders( >@@ -30,8 +30,9 @@ void AudioDecoderIsacFix::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderIsacFix::MakeAudioDecoder( >- Config config) { >- return rtc::MakeUnique<AudioDecoderIsacFixImpl>(16000); >+ Config config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { >+ return absl::make_unique<AudioDecoderIsacFixImpl>(16000); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.h >index f3d210eb84b..a4ce6858385 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_fix.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -26,9 +27,11 @@ namespace webrtc { > // NOTE: This struct is still under development and may change without notice. > struct AudioDecoderIsacFix { > struct Config {}; // Empty---no config values needed! >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ Config config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.cc >index 65ad6ac15d1..1c1926f1a1e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.cc >@@ -10,14 +10,14 @@ > > #include "api/audio_codecs/isac/audio_decoder_isac_float.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderIsacFloat::Config> AudioDecoderIsacFloat::SdpToConfig( >- const SdpAudioFormat& format) { >+absl::optional<AudioDecoderIsacFloat::Config> >+AudioDecoderIsacFloat::SdpToConfig(const SdpAudioFormat& format) { > if (STR_CASE_CMP(format.name.c_str(), "ISAC") == 0 && > (format.clockrate_hz == 16000 || format.clockrate_hz == 32000) && > format.num_channels == 1) { >@@ -25,7 +25,7 @@ rtc::Optional<AudioDecoderIsacFloat::Config> AudioDecoderIsacFloat::SdpToConfig( > config.sample_rate_hz = format.clockrate_hz; > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -36,9 +36,10 @@ void AudioDecoderIsacFloat::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderIsacFloat::MakeAudioDecoder( >- Config config) { >+ Config config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); >- return rtc::MakeUnique<AudioDecoderIsacFloatImpl>(config.sample_rate_hz); >+ return absl::make_unique<AudioDecoderIsacFloatImpl>(config.sample_rate_hz); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.h >index 1decd5af3dc..cc139634196 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_decoder_isac_float.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -31,9 +32,11 @@ struct AudioDecoderIsacFloat { > } > int sample_rate_hz = 16000; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ Config config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.cc >index 17c1a761b81..cd8975398b4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.cc >@@ -10,14 +10,14 @@ > > #include "api/audio_codecs/isac/audio_encoder_isac_fix.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/isac/fix/include/audio_encoder_isacfix.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/string_to_number.h" > > namespace webrtc { > >-rtc::Optional<AudioEncoderIsacFix::Config> AudioEncoderIsacFix::SdpToConfig( >+absl::optional<AudioEncoderIsacFix::Config> AudioEncoderIsacFix::SdpToConfig( > const SdpAudioFormat& format) { > if (STR_CASE_CMP(format.name.c_str(), "ISAC") == 0 && > format.clockrate_hz == 16000 && format.num_channels == 1) { >@@ -31,7 +31,7 @@ rtc::Optional<AudioEncoderIsacFix::Config> AudioEncoderIsacFix::SdpToConfig( > } > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -50,12 +50,13 @@ AudioCodecInfo AudioEncoderIsacFix::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderIsacFix::MakeAudioEncoder( > AudioEncoderIsacFix::Config config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); > AudioEncoderIsacFixImpl::Config c; > c.frame_size_ms = config.frame_size_ms; > c.payload_type = payload_type; >- return rtc::MakeUnique<AudioEncoderIsacFixImpl>(c); >+ return absl::make_unique<AudioEncoderIsacFixImpl>(c); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.h >index 5970c025349..731e48d0c27 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_fix.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -29,11 +30,13 @@ struct AudioEncoderIsacFix { > bool IsOk() const { return frame_size_ms == 30 || frame_size_ms == 60; } > int frame_size_ms = 30; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(Config config); >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(Config config, >- int payload_type); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ Config config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.cc >index bdfbcfbebc3..b70a82e2852 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.cc >@@ -10,15 +10,15 @@ > > #include "api/audio_codecs/isac/audio_encoder_isac_float.h" > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/string_to_number.h" > > namespace webrtc { > >-rtc::Optional<AudioEncoderIsacFloat::Config> AudioEncoderIsacFloat::SdpToConfig( >- const SdpAudioFormat& format) { >+absl::optional<AudioEncoderIsacFloat::Config> >+AudioEncoderIsacFloat::SdpToConfig(const SdpAudioFormat& format) { > if (STR_CASE_CMP(format.name.c_str(), "ISAC") == 0 && > (format.clockrate_hz == 16000 || format.clockrate_hz == 32000) && > format.num_channels == 1) { >@@ -37,7 +37,7 @@ rtc::Optional<AudioEncoderIsacFloat::Config> AudioEncoderIsacFloat::SdpToConfig( > } > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -61,13 +61,14 @@ AudioCodecInfo AudioEncoderIsacFloat::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderIsacFloat::MakeAudioEncoder( > const AudioEncoderIsacFloat::Config& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > RTC_DCHECK(config.IsOk()); > AudioEncoderIsacFloatImpl::Config c; > c.sample_rate_hz = config.sample_rate_hz; > c.frame_size_ms = config.frame_size_ms; > c.payload_type = payload_type; >- return rtc::MakeUnique<AudioEncoderIsacFloatImpl>(c); >+ return absl::make_unique<AudioEncoderIsacFloatImpl>(c); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.h >index f14c2a25f50..6d98bf99685 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/isac/audio_encoder_isac_float.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -34,11 +35,13 @@ struct AudioEncoderIsacFloat { > int sample_rate_hz = 16000; > int frame_size_ms = 30; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const Config& config); >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(const Config& config, >- int payload_type); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ const Config& config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/BUILD.gn >index 13a4b5d3ee1..800abbe279b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/BUILD.gn >@@ -19,8 +19,8 @@ rtc_static_library("audio_encoder_opus_config") { > "audio_encoder_opus_config.h", > ] > deps = [ >- "../..:optional", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > defines = [] > if (rtc_opus_variable_complexity) { >@@ -32,6 +32,7 @@ rtc_static_library("audio_encoder_opus_config") { > > rtc_source_set("audio_encoder_opus") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > public = [ > "audio_encoder_opus.h", > ] >@@ -41,27 +42,25 @@ rtc_source_set("audio_encoder_opus") { > deps = [ > ":audio_encoder_opus_config", > "..:audio_codecs_api", >- "../..:optional", > "../../../modules/audio_coding:webrtc_opus", > "../../../rtc_base:rtc_base_approved", >- ] >- public_deps = [ >- # TODO(kwiberg): Remove this public_dep when bug 7847 has been fixed. >- "../../../rtc_base:protobuf_utils", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_static_library("audio_decoder_opus") { > visibility = [ "*" ] >+ poisonous = [ "audio_codecs" ] > sources = [ > "audio_decoder_opus.cc", > "audio_decoder_opus.h", > ] > deps = [ > "..:audio_codecs_api", >- "../..:optional", > "../../..:webrtc_common", > "../../../modules/audio_coding:webrtc_opus", > "../../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc >index 472a0794358..41397f04d20 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.cc >@@ -14,15 +14,15 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/codecs/opus/audio_decoder_opus.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >-rtc::Optional<AudioDecoderOpus::Config> AudioDecoderOpus::SdpToConfig( >+absl::optional<AudioDecoderOpus::Config> AudioDecoderOpus::SdpToConfig( > const SdpAudioFormat& format) { >- const auto num_channels = [&]() -> rtc::Optional<int> { >+ const auto num_channels = [&]() -> absl::optional<int> { > auto stereo = format.parameters.find("stereo"); > if (stereo != format.parameters.end()) { > if (stereo->second == "0") { >@@ -30,7 +30,7 @@ rtc::Optional<AudioDecoderOpus::Config> AudioDecoderOpus::SdpToConfig( > } else if (stereo->second == "1") { > return 2; > } else { >- return rtc::nullopt; // Bad stereo parameter. >+ return absl::nullopt; // Bad stereo parameter. > } > } > return 1; // Default to mono. >@@ -40,7 +40,7 @@ rtc::Optional<AudioDecoderOpus::Config> AudioDecoderOpus::SdpToConfig( > num_channels) { > return Config{*num_channels}; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -55,8 +55,9 @@ void AudioDecoderOpus::AppendSupportedDecoders( > } > > std::unique_ptr<AudioDecoder> AudioDecoderOpus::MakeAudioDecoder( >- Config config) { >- return rtc::MakeUnique<AudioDecoderOpusImpl>(config.num_channels); >+ Config config, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { >+ return absl::make_unique<AudioDecoderOpusImpl>(config.num_channels); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.h >index 0cd917f04b9..de26026b783 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_decoder_opus.h >@@ -14,9 +14,10 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_decoder.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -28,9 +29,11 @@ struct AudioDecoderOpus { > struct Config { > int num_channels; > }; >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); >+ static absl::optional<Config> SdpToConfig(const SdpAudioFormat& audio_format); > static void AppendSupportedDecoders(std::vector<AudioCodecSpec>* specs); >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(Config config); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ Config config, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc >index 603da6f223b..36d82b3eff9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.cc >@@ -14,7 +14,7 @@ > > namespace webrtc { > >-rtc::Optional<AudioEncoderOpusConfig> AudioEncoderOpus::SdpToConfig( >+absl::optional<AudioEncoderOpusConfig> AudioEncoderOpus::SdpToConfig( > const SdpAudioFormat& format) { > return AudioEncoderOpusImpl::SdpToConfig(format); > } >@@ -31,7 +31,8 @@ AudioCodecInfo AudioEncoderOpus::QueryAudioEncoder( > > std::unique_ptr<AudioEncoder> AudioEncoderOpus::MakeAudioEncoder( > const AudioEncoderOpusConfig& config, >- int payload_type) { >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/) { > return AudioEncoderOpusImpl::MakeAudioEncoder(config, payload_type); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.h >index d348a178977..20aaaf726f9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus.h >@@ -14,10 +14,11 @@ > #include <memory> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_format.h" > #include "api/audio_codecs/opus/audio_encoder_opus_config.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -27,13 +28,14 @@ namespace webrtc { > // NOTE: This struct is still under development and may change without notice. > struct AudioEncoderOpus { > using Config = AudioEncoderOpusConfig; >- static rtc::Optional<AudioEncoderOpusConfig> SdpToConfig( >+ static absl::optional<AudioEncoderOpusConfig> SdpToConfig( > const SdpAudioFormat& audio_format); > static void AppendSupportedEncoders(std::vector<AudioCodecSpec>* specs); > static AudioCodecInfo QueryAudioEncoder(const AudioEncoderOpusConfig& config); > static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >- const AudioEncoderOpusConfig&, >- int payload_type); >+ const AudioEncoderOpusConfig& config, >+ int payload_type, >+ absl::optional<AudioCodecPairId> codec_pair_id = absl::nullopt); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h >index d586592ab09..c7067bb1c32 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/opus/audio_encoder_opus_config.h >@@ -15,7 +15,7 @@ > > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > > namespace webrtc { > >@@ -42,7 +42,7 @@ struct AudioEncoderOpusConfig { > > // NOTE: This member must always be set. > // TODO(kwiberg): Turn it into just an int. >- rtc::Optional<int> bitrate_bps; >+ absl::optional<int> bitrate_bps; > > bool fec_enabled; > bool cbr_enabled; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/BUILD.gn >index 0f742f57cc2..cc7a4d9cd06 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/BUILD.gn >@@ -38,7 +38,7 @@ if (rtc_include_tests) { > "../isac:audio_encoder_isac_float", > "../opus:audio_decoder_opus", > "../opus:audio_encoder_opus", >- "//testing/gmock", >+ "//third_party/abseil-cpp/absl/memory", > ] > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc >index 53199034c94..d8fd9e02c12 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_decoder_factory_template_unittest.cc >@@ -9,6 +9,7 @@ > */ > > #include "api/audio_codecs/audio_decoder_factory_template.h" >+#include "absl/memory/memory.h" > #include "api/audio_codecs/L16/audio_decoder_L16.h" > #include "api/audio_codecs/g711/audio_decoder_g711.h" > #include "api/audio_codecs/g722/audio_decoder_g722.h" >@@ -16,7 +17,6 @@ > #include "api/audio_codecs/isac/audio_decoder_isac_fix.h" > #include "api/audio_codecs/isac/audio_decoder_isac_float.h" > #include "api/audio_codecs/opus/audio_decoder_opus.h" >-#include "rtc_base/ptr_util.h" > #include "test/gmock.h" > #include "test/gtest.h" > #include "test/mock_audio_decoder.h" >@@ -43,12 +43,13 @@ struct AudioDecoderFakeApi { > SdpAudioFormat audio_format; > }; > >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format) { >+ static absl::optional<Config> SdpToConfig( >+ const SdpAudioFormat& audio_format) { > if (Params::AudioFormat() == audio_format) { > Config config = {audio_format}; > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -60,8 +61,10 @@ struct AudioDecoderFakeApi { > return Params::CodecInfo(); > } > >- static std::unique_ptr<AudioDecoder> MakeAudioDecoder(const Config&) { >- auto dec = rtc::MakeUnique<testing::StrictMock<MockAudioDecoder>>(); >+ static std::unique_ptr<AudioDecoder> MakeAudioDecoder( >+ const Config&, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/ = absl::nullopt) { >+ auto dec = absl::make_unique<testing::StrictMock<MockAudioDecoder>>(); > EXPECT_CALL(*dec, SampleRateHz()) > .WillOnce(testing::Return(Params::CodecInfo().sample_rate_hz)); > EXPECT_CALL(*dec, Die()); >@@ -77,7 +80,8 @@ TEST(AudioDecoderFactoryTemplateTest, NoDecoderTypes) { > audio_decoder_factory_template_impl::AudioDecoderFactoryT<>>()); > EXPECT_THAT(factory->GetSupportedDecoders(), testing::IsEmpty()); > EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 16000, 1}, absl::nullopt)); > } > > TEST(AudioDecoderFactoryTemplateTest, OneDecoderType) { >@@ -87,8 +91,9 @@ TEST(AudioDecoderFactoryTemplateTest, OneDecoderType) { > AudioCodecSpec{{"bogus", 8000, 1}, {8000, 1, 12345}})); > EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"bogus", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); >- auto dec = factory->MakeAudioDecoder({"bogus", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 16000, 1}, absl::nullopt)); >+ auto dec = factory->MakeAudioDecoder({"bogus", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec); > EXPECT_EQ(8000, dec->SampleRateHz()); > } >@@ -105,13 +110,15 @@ TEST(AudioDecoderFactoryTemplateTest, TwoDecoderTypes) { > EXPECT_TRUE(factory->IsSupportedDecoder({"bogus", 8000, 1})); > EXPECT_TRUE( > factory->IsSupportedDecoder({"sham", 16000, 2, {{"param", "value"}}})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); >- auto dec1 = factory->MakeAudioDecoder({"bogus", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 16000, 1}, absl::nullopt)); >+ auto dec1 = factory->MakeAudioDecoder({"bogus", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec1); > EXPECT_EQ(8000, dec1->SampleRateHz()); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"sham", 16000, 2})); >- auto dec2 = >- factory->MakeAudioDecoder({"sham", 16000, 2, {{"param", "value"}}}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"sham", 16000, 2}, absl::nullopt)); >+ auto dec2 = factory->MakeAudioDecoder( >+ {"sham", 16000, 2, {{"param", "value"}}}, absl::nullopt); > ASSERT_NE(nullptr, dec2); > EXPECT_EQ(16000, dec2->SampleRateHz()); > } >@@ -125,11 +132,12 @@ TEST(AudioDecoderFactoryTemplateTest, G711) { > EXPECT_FALSE(factory->IsSupportedDecoder({"G711", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"PCMU", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"pcma", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"pcmu", 16000, 1})); >- auto dec1 = factory->MakeAudioDecoder({"pcmu", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"pcmu", 16000, 1}, absl::nullopt)); >+ auto dec1 = factory->MakeAudioDecoder({"pcmu", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec1); > EXPECT_EQ(8000, dec1->SampleRateHz()); >- auto dec2 = factory->MakeAudioDecoder({"PCMA", 8000, 1}); >+ auto dec2 = factory->MakeAudioDecoder({"PCMA", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec2); > EXPECT_EQ(8000, dec2->SampleRateHz()); > } >@@ -141,16 +149,17 @@ TEST(AudioDecoderFactoryTemplateTest, G722) { > AudioCodecSpec{{"G722", 8000, 1}, {16000, 1, 64000}})); > EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"G722", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); >- auto dec1 = factory->MakeAudioDecoder({"G722", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 16000, 1}, absl::nullopt)); >+ auto dec1 = factory->MakeAudioDecoder({"G722", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec1); > EXPECT_EQ(16000, dec1->SampleRateHz()); > EXPECT_EQ(1u, dec1->Channels()); >- auto dec2 = factory->MakeAudioDecoder({"G722", 8000, 2}); >+ auto dec2 = factory->MakeAudioDecoder({"G722", 8000, 2}, absl::nullopt); > ASSERT_NE(nullptr, dec2); > EXPECT_EQ(16000, dec2->SampleRateHz()); > EXPECT_EQ(2u, dec2->Channels()); >- auto dec3 = factory->MakeAudioDecoder({"G722", 8000, 3}); >+ auto dec3 = factory->MakeAudioDecoder({"G722", 8000, 3}, absl::nullopt); > ASSERT_EQ(nullptr, dec3); > } > >@@ -161,8 +170,9 @@ TEST(AudioDecoderFactoryTemplateTest, Ilbc) { > AudioCodecSpec{{"ILBC", 8000, 1}, {8000, 1, 13300}})); > EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"ilbc", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 8000, 1})); >- auto dec = factory->MakeAudioDecoder({"ilbc", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 8000, 1}, absl::nullopt)); >+ auto dec = factory->MakeAudioDecoder({"ilbc", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec); > EXPECT_EQ(8000, dec->SampleRateHz()); > } >@@ -175,8 +185,9 @@ TEST(AudioDecoderFactoryTemplateTest, IsacFix) { > EXPECT_FALSE(factory->IsSupportedDecoder({"isac", 16000, 2})); > EXPECT_TRUE(factory->IsSupportedDecoder({"isac", 16000, 1})); > EXPECT_FALSE(factory->IsSupportedDecoder({"isac", 32000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"isac", 8000, 1})); >- auto dec = factory->MakeAudioDecoder({"isac", 16000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"isac", 8000, 1}, absl::nullopt)); >+ auto dec = factory->MakeAudioDecoder({"isac", 16000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec); > EXPECT_EQ(16000, dec->SampleRateHz()); > } >@@ -191,11 +202,12 @@ TEST(AudioDecoderFactoryTemplateTest, IsacFloat) { > EXPECT_FALSE(factory->IsSupportedDecoder({"isac", 16000, 2})); > EXPECT_TRUE(factory->IsSupportedDecoder({"isac", 16000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"isac", 32000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"isac", 8000, 1})); >- auto dec1 = factory->MakeAudioDecoder({"isac", 16000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"isac", 8000, 1}, absl::nullopt)); >+ auto dec1 = factory->MakeAudioDecoder({"isac", 16000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec1); > EXPECT_EQ(16000, dec1->SampleRateHz()); >- auto dec2 = factory->MakeAudioDecoder({"isac", 32000, 1}); >+ auto dec2 = factory->MakeAudioDecoder({"isac", 32000, 1}, absl::nullopt); > ASSERT_NE(nullptr, dec2); > EXPECT_EQ(32000, dec2->SampleRateHz()); > } >@@ -214,8 +226,9 @@ TEST(AudioDecoderFactoryTemplateTest, L16) { > EXPECT_FALSE(factory->IsSupportedDecoder({"foo", 8000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"L16", 48000, 1})); > EXPECT_FALSE(factory->IsSupportedDecoder({"L16", 96000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"L16", 8000, 0})); >- auto dec = factory->MakeAudioDecoder({"L16", 48000, 2}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"L16", 8000, 0}, absl::nullopt)); >+ auto dec = factory->MakeAudioDecoder({"L16", 48000, 2}, absl::nullopt); > ASSERT_NE(nullptr, dec); > EXPECT_EQ(48000, dec->SampleRateHz()); > } >@@ -231,8 +244,9 @@ TEST(AudioDecoderFactoryTemplateTest, Opus) { > testing::ElementsAre(AudioCodecSpec{opus_format, opus_info})); > EXPECT_FALSE(factory->IsSupportedDecoder({"opus", 48000, 1})); > EXPECT_TRUE(factory->IsSupportedDecoder({"opus", 48000, 2})); >- EXPECT_EQ(nullptr, factory->MakeAudioDecoder({"bar", 16000, 1})); >- auto dec = factory->MakeAudioDecoder({"opus", 48000, 2}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioDecoder({"bar", 16000, 1}, absl::nullopt)); >+ auto dec = factory->MakeAudioDecoder({"opus", 48000, 2}, absl::nullopt); > ASSERT_NE(nullptr, dec); > EXPECT_EQ(48000, dec->SampleRateHz()); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc >index 4f16ff452fd..ca024b9326e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_codecs/test/audio_encoder_factory_template_unittest.cc >@@ -9,6 +9,7 @@ > */ > > #include "api/audio_codecs/audio_encoder_factory_template.h" >+#include "absl/memory/memory.h" > #include "api/audio_codecs/L16/audio_encoder_L16.h" > #include "api/audio_codecs/g711/audio_encoder_g711.h" > #include "api/audio_codecs/g722/audio_encoder_g722.h" >@@ -16,7 +17,6 @@ > #include "api/audio_codecs/isac/audio_encoder_isac_fix.h" > #include "api/audio_codecs/isac/audio_encoder_isac_float.h" > #include "api/audio_codecs/opus/audio_encoder_opus.h" >-#include "rtc_base/ptr_util.h" > #include "test/gmock.h" > #include "test/gtest.h" > #include "test/mock_audio_encoder.h" >@@ -43,12 +43,13 @@ struct AudioEncoderFakeApi { > SdpAudioFormat audio_format; > }; > >- static rtc::Optional<Config> SdpToConfig(const SdpAudioFormat& audio_format) { >+ static absl::optional<Config> SdpToConfig( >+ const SdpAudioFormat& audio_format) { > if (Params::AudioFormat() == audio_format) { > Config config = {audio_format}; > return config; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -60,12 +61,13 @@ struct AudioEncoderFakeApi { > return Params::CodecInfo(); > } > >- static std::unique_ptr<AudioEncoder> MakeAudioEncoder(const Config&, >- int payload_type) { >- auto enc = rtc::MakeUnique<testing::StrictMock<MockAudioEncoder>>(); >+ static std::unique_ptr<AudioEncoder> MakeAudioEncoder( >+ const Config&, >+ int payload_type, >+ absl::optional<AudioCodecPairId> /*codec_pair_id*/ = absl::nullopt) { >+ auto enc = absl::make_unique<testing::StrictMock<MockAudioEncoder>>(); > EXPECT_CALL(*enc, SampleRateHz()) > .WillOnce(testing::Return(Params::CodecInfo().sample_rate_hz)); >- EXPECT_CALL(*enc, Die()); > return std::move(enc); > } > }; >@@ -77,8 +79,9 @@ TEST(AudioEncoderFactoryTemplateTest, NoEncoderTypes) { > new rtc::RefCountedObject< > audio_encoder_factory_template_impl::AudioEncoderFactoryT<>>()); > EXPECT_THAT(factory->GetSupportedEncoders(), testing::IsEmpty()); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 16000, 1}, absl::nullopt)); > } > > TEST(AudioEncoderFactoryTemplateTest, OneEncoderType) { >@@ -86,11 +89,12 @@ TEST(AudioEncoderFactoryTemplateTest, OneEncoderType) { > EXPECT_THAT(factory->GetSupportedEncoders(), > testing::ElementsAre( > AudioCodecSpec{{"bogus", 8000, 1}, {8000, 1, 12345}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); > EXPECT_EQ(AudioCodecInfo(8000, 1, 12345), > factory->QueryAudioEncoder({"bogus", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); >- auto enc = factory->MakeAudioEncoder(17, {"bogus", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 16000, 1}, absl::nullopt)); >+ auto enc = factory->MakeAudioEncoder(17, {"bogus", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc); > EXPECT_EQ(8000, enc->SampleRateHz()); > } >@@ -103,19 +107,21 @@ TEST(AudioEncoderFactoryTemplateTest, TwoEncoderTypes) { > AudioCodecSpec{{"bogus", 8000, 1}, {8000, 1, 12345}}, > AudioCodecSpec{{"sham", 16000, 2, {{"param", "value"}}}, > {16000, 2, 23456}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); > EXPECT_EQ(AudioCodecInfo(8000, 1, 12345), > factory->QueryAudioEncoder({"bogus", 8000, 1})); > EXPECT_EQ( > AudioCodecInfo(16000, 2, 23456), > factory->QueryAudioEncoder({"sham", 16000, 2, {{"param", "value"}}})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); >- auto enc1 = factory->MakeAudioEncoder(17, {"bogus", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 16000, 1}, absl::nullopt)); >+ auto enc1 = factory->MakeAudioEncoder(17, {"bogus", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc1); > EXPECT_EQ(8000, enc1->SampleRateHz()); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"sham", 16000, 2})); >- auto enc2 = >- factory->MakeAudioEncoder(17, {"sham", 16000, 2, {{"param", "value"}}}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"sham", 16000, 2}, absl::nullopt)); >+ auto enc2 = factory->MakeAudioEncoder( >+ 17, {"sham", 16000, 2, {{"param", "value"}}}, absl::nullopt); > ASSERT_NE(nullptr, enc2); > EXPECT_EQ(16000, enc2->SampleRateHz()); > } >@@ -126,14 +132,15 @@ TEST(AudioEncoderFactoryTemplateTest, G711) { > testing::ElementsAre( > AudioCodecSpec{{"PCMU", 8000, 1}, {8000, 1, 64000}}, > AudioCodecSpec{{"PCMA", 8000, 1}, {8000, 1, 64000}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"PCMA", 16000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"PCMA", 16000, 1})); > EXPECT_EQ(AudioCodecInfo(8000, 1, 64000), > factory->QueryAudioEncoder({"PCMA", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"PCMU", 16000, 1})); >- auto enc1 = factory->MakeAudioEncoder(17, {"PCMU", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"PCMU", 16000, 1}, absl::nullopt)); >+ auto enc1 = factory->MakeAudioEncoder(17, {"PCMU", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc1); > EXPECT_EQ(8000, enc1->SampleRateHz()); >- auto enc2 = factory->MakeAudioEncoder(17, {"PCMA", 8000, 1}); >+ auto enc2 = factory->MakeAudioEncoder(17, {"PCMA", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc2); > EXPECT_EQ(8000, enc2->SampleRateHz()); > } >@@ -143,11 +150,12 @@ TEST(AudioEncoderFactoryTemplateTest, G722) { > EXPECT_THAT(factory->GetSupportedEncoders(), > testing::ElementsAre( > AudioCodecSpec{{"G722", 8000, 1}, {16000, 1, 64000}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); > EXPECT_EQ(AudioCodecInfo(16000, 1, 64000), > factory->QueryAudioEncoder({"G722", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); >- auto enc = factory->MakeAudioEncoder(17, {"G722", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 16000, 1}, absl::nullopt)); >+ auto enc = factory->MakeAudioEncoder(17, {"G722", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc); > EXPECT_EQ(16000, enc->SampleRateHz()); > } >@@ -157,11 +165,12 @@ TEST(AudioEncoderFactoryTemplateTest, Ilbc) { > EXPECT_THAT(factory->GetSupportedEncoders(), > testing::ElementsAre( > AudioCodecSpec{{"ILBC", 8000, 1}, {8000, 1, 13333}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); > EXPECT_EQ(AudioCodecInfo(8000, 1, 13333), > factory->QueryAudioEncoder({"ilbc", 8000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 8000, 1})); >- auto enc = factory->MakeAudioEncoder(17, {"ilbc", 8000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 8000, 1}, absl::nullopt)); >+ auto enc = factory->MakeAudioEncoder(17, {"ilbc", 8000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc); > EXPECT_EQ(8000, enc->SampleRateHz()); > } >@@ -171,17 +180,18 @@ TEST(AudioEncoderFactoryTemplateTest, IsacFix) { > EXPECT_THAT(factory->GetSupportedEncoders(), > testing::ElementsAre(AudioCodecSpec{ > {"ISAC", 16000, 1}, {16000, 1, 32000, 10000, 32000}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"isac", 16000, 2})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"isac", 16000, 2})); > EXPECT_EQ(AudioCodecInfo(16000, 1, 32000, 10000, 32000), > factory->QueryAudioEncoder({"isac", 16000, 1})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"isac", 32000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"isac", 8000, 1})); >- auto enc1 = factory->MakeAudioEncoder(17, {"isac", 16000, 1}); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"isac", 32000, 1})); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"isac", 8000, 1}, absl::nullopt)); >+ auto enc1 = factory->MakeAudioEncoder(17, {"isac", 16000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc1); > EXPECT_EQ(16000, enc1->SampleRateHz()); > EXPECT_EQ(3u, enc1->Num10MsFramesInNextPacket()); >- auto enc2 = >- factory->MakeAudioEncoder(17, {"isac", 16000, 1, {{"ptime", "60"}}}); >+ auto enc2 = factory->MakeAudioEncoder( >+ 17, {"isac", 16000, 1, {{"ptime", "60"}}}, absl::nullopt); > ASSERT_NE(nullptr, enc2); > EXPECT_EQ(6u, enc2->Num10MsFramesInNextPacket()); > } >@@ -193,16 +203,17 @@ TEST(AudioEncoderFactoryTemplateTest, IsacFloat) { > testing::ElementsAre( > AudioCodecSpec{{"ISAC", 16000, 1}, {16000, 1, 32000, 10000, 32000}}, > AudioCodecSpec{{"ISAC", 32000, 1}, {32000, 1, 56000, 10000, 56000}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"isac", 16000, 2})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"isac", 16000, 2})); > EXPECT_EQ(AudioCodecInfo(16000, 1, 32000, 10000, 32000), > factory->QueryAudioEncoder({"isac", 16000, 1})); > EXPECT_EQ(AudioCodecInfo(32000, 1, 56000, 10000, 56000), > factory->QueryAudioEncoder({"isac", 32000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"isac", 8000, 1})); >- auto enc1 = factory->MakeAudioEncoder(17, {"isac", 16000, 1}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"isac", 8000, 1}, absl::nullopt)); >+ auto enc1 = factory->MakeAudioEncoder(17, {"isac", 16000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc1); > EXPECT_EQ(16000, enc1->SampleRateHz()); >- auto enc2 = factory->MakeAudioEncoder(17, {"isac", 32000, 1}); >+ auto enc2 = factory->MakeAudioEncoder(17, {"isac", 32000, 1}, absl::nullopt); > ASSERT_NE(nullptr, enc2); > EXPECT_EQ(32000, enc2->SampleRateHz()); > } >@@ -218,11 +229,12 @@ TEST(AudioEncoderFactoryTemplateTest, L16) { > AudioCodecSpec{{"L16", 8000, 2}, {8000, 2, 8000 * 16 * 2}}, > AudioCodecSpec{{"L16", 16000, 2}, {16000, 2, 16000 * 16 * 2}}, > AudioCodecSpec{{"L16", 32000, 2}, {32000, 2, 32000 * 16 * 2}})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"L16", 8000, 0})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"L16", 8000, 0})); > EXPECT_EQ(AudioCodecInfo(48000, 1, 48000 * 16), > factory->QueryAudioEncoder({"L16", 48000, 1})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"L16", 8000, 0})); >- auto enc = factory->MakeAudioEncoder(17, {"L16", 48000, 2}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"L16", 8000, 0}, absl::nullopt)); >+ auto enc = factory->MakeAudioEncoder(17, {"L16", 48000, 2}, absl::nullopt); > ASSERT_NE(nullptr, enc); > EXPECT_EQ(48000, enc->SampleRateHz()); > } >@@ -237,13 +249,14 @@ TEST(AudioEncoderFactoryTemplateTest, Opus) { > testing::ElementsAre(AudioCodecSpec{ > {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}}, > info})); >- EXPECT_EQ(rtc::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); >+ EXPECT_EQ(absl::nullopt, factory->QueryAudioEncoder({"foo", 8000, 1})); > EXPECT_EQ( > info, > factory->QueryAudioEncoder( > {"opus", 48000, 2, {{"minptime", "10"}, {"useinbandfec", "1"}}})); >- EXPECT_EQ(nullptr, factory->MakeAudioEncoder(17, {"bar", 16000, 1})); >- auto enc = factory->MakeAudioEncoder(17, {"opus", 48000, 2}); >+ EXPECT_EQ(nullptr, >+ factory->MakeAudioEncoder(17, {"bar", 16000, 1}, absl::nullopt)); >+ auto enc = factory->MakeAudioEncoder(17, {"opus", 48000, 2}, absl::nullopt); > ASSERT_NE(nullptr, enc); > EXPECT_EQ(48000, enc->SampleRateHz()); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.cc >new file mode 100644 >index 00000000000..c196d7d9df0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.cc >@@ -0,0 +1,18 @@ >+/* >+ * Copyright (c) 2018 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 "api/audio_options.h" >+ >+namespace cricket { >+ >+AudioOptions::AudioOptions() = default; >+AudioOptions::~AudioOptions() = default; >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.h >new file mode 100644 >index 00000000000..df66d360c56 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/audio_options.h >@@ -0,0 +1,196 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_AUDIO_OPTIONS_H_ >+#define API_AUDIO_OPTIONS_H_ >+ >+#include <string> >+ >+#include "absl/types/optional.h" >+#include "rtc_base/stringencode.h" >+ >+namespace cricket { >+ >+// Options that can be applied to a VoiceMediaChannel or a VoiceMediaEngine. >+// Used to be flags, but that makes it hard to selectively apply options. >+// We are moving all of the setting of options to structs like this, >+// but some things currently still use flags. >+struct AudioOptions { >+ AudioOptions(); >+ ~AudioOptions(); >+ void SetAll(const AudioOptions& change) { >+ SetFrom(&echo_cancellation, change.echo_cancellation); >+#if defined(WEBRTC_IOS) >+ SetFrom(&ios_force_software_aec_HACK, change.ios_force_software_aec_HACK); >+#endif >+ SetFrom(&auto_gain_control, change.auto_gain_control); >+ SetFrom(&noise_suppression, change.noise_suppression); >+ SetFrom(&highpass_filter, change.highpass_filter); >+ SetFrom(&stereo_swapping, change.stereo_swapping); >+ SetFrom(&audio_jitter_buffer_max_packets, >+ change.audio_jitter_buffer_max_packets); >+ SetFrom(&audio_jitter_buffer_fast_accelerate, >+ change.audio_jitter_buffer_fast_accelerate); >+ SetFrom(&typing_detection, change.typing_detection); >+ SetFrom(&aecm_generate_comfort_noise, change.aecm_generate_comfort_noise); >+ SetFrom(&experimental_agc, change.experimental_agc); >+ SetFrom(&extended_filter_aec, change.extended_filter_aec); >+ SetFrom(&delay_agnostic_aec, change.delay_agnostic_aec); >+ SetFrom(&experimental_ns, change.experimental_ns); >+ SetFrom(&intelligibility_enhancer, change.intelligibility_enhancer); >+ SetFrom(&residual_echo_detector, change.residual_echo_detector); >+ SetFrom(&tx_agc_target_dbov, change.tx_agc_target_dbov); >+ SetFrom(&tx_agc_digital_compression_gain, >+ change.tx_agc_digital_compression_gain); >+ SetFrom(&tx_agc_limiter, change.tx_agc_limiter); >+ SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe); >+ SetFrom(&audio_network_adaptor, change.audio_network_adaptor); >+ SetFrom(&audio_network_adaptor_config, change.audio_network_adaptor_config); >+ } >+ >+ bool operator==(const AudioOptions& o) const { >+ return echo_cancellation == o.echo_cancellation && >+#if defined(WEBRTC_IOS) >+ ios_force_software_aec_HACK == o.ios_force_software_aec_HACK && >+#endif >+ auto_gain_control == o.auto_gain_control && >+ noise_suppression == o.noise_suppression && >+ highpass_filter == o.highpass_filter && >+ stereo_swapping == o.stereo_swapping && >+ audio_jitter_buffer_max_packets == >+ o.audio_jitter_buffer_max_packets && >+ audio_jitter_buffer_fast_accelerate == >+ o.audio_jitter_buffer_fast_accelerate && >+ typing_detection == o.typing_detection && >+ aecm_generate_comfort_noise == o.aecm_generate_comfort_noise && >+ experimental_agc == o.experimental_agc && >+ extended_filter_aec == o.extended_filter_aec && >+ delay_agnostic_aec == o.delay_agnostic_aec && >+ experimental_ns == o.experimental_ns && >+ intelligibility_enhancer == o.intelligibility_enhancer && >+ residual_echo_detector == o.residual_echo_detector && >+ tx_agc_target_dbov == o.tx_agc_target_dbov && >+ tx_agc_digital_compression_gain == >+ o.tx_agc_digital_compression_gain && >+ tx_agc_limiter == o.tx_agc_limiter && >+ combined_audio_video_bwe == o.combined_audio_video_bwe && >+ audio_network_adaptor == o.audio_network_adaptor && >+ audio_network_adaptor_config == o.audio_network_adaptor_config; >+ } >+ bool operator!=(const AudioOptions& o) const { return !(*this == o); } >+ >+ std::string ToString() const { >+ std::ostringstream ost; >+ ost << "AudioOptions {"; >+ ost << ToStringIfSet("aec", echo_cancellation); >+#if defined(WEBRTC_IOS) >+ ost << ToStringIfSet("ios_force_software_aec_HACK", >+ ios_force_software_aec_HACK); >+#endif >+ ost << ToStringIfSet("agc", auto_gain_control); >+ ost << ToStringIfSet("ns", noise_suppression); >+ ost << ToStringIfSet("hf", highpass_filter); >+ ost << ToStringIfSet("swap", stereo_swapping); >+ ost << ToStringIfSet("audio_jitter_buffer_max_packets", >+ audio_jitter_buffer_max_packets); >+ ost << ToStringIfSet("audio_jitter_buffer_fast_accelerate", >+ audio_jitter_buffer_fast_accelerate); >+ ost << ToStringIfSet("typing", typing_detection); >+ ost << ToStringIfSet("comfort_noise", aecm_generate_comfort_noise); >+ ost << ToStringIfSet("experimental_agc", experimental_agc); >+ ost << ToStringIfSet("extended_filter_aec", extended_filter_aec); >+ ost << ToStringIfSet("delay_agnostic_aec", delay_agnostic_aec); >+ ost << ToStringIfSet("experimental_ns", experimental_ns); >+ ost << ToStringIfSet("intelligibility_enhancer", intelligibility_enhancer); >+ ost << ToStringIfSet("residual_echo_detector", residual_echo_detector); >+ ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov); >+ ost << ToStringIfSet("tx_agc_digital_compression_gain", >+ tx_agc_digital_compression_gain); >+ ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter); >+ ost << ToStringIfSet("combined_audio_video_bwe", combined_audio_video_bwe); >+ ost << ToStringIfSet("audio_network_adaptor", audio_network_adaptor); >+ // The adaptor config is a serialized proto buffer and therefore not human >+ // readable. So we comment out the following line. >+ // ost << ToStringIfSet("audio_network_adaptor_config", >+ // audio_network_adaptor_config); >+ ost << "}"; >+ return ost.str(); >+ } >+ >+ // Audio processing that attempts to filter away the output signal from >+ // later inbound pickup. >+ absl::optional<bool> echo_cancellation; >+#if defined(WEBRTC_IOS) >+ // Forces software echo cancellation on iOS. This is a temporary workaround >+ // (until Apple fixes the bug) for a device with non-functioning AEC. May >+ // improve performance on that particular device, but will cause unpredictable >+ // behavior in all other cases. See http://bugs.webrtc.org/8682. >+ absl::optional<bool> ios_force_software_aec_HACK; >+#endif >+ // Audio processing to adjust the sensitivity of the local mic dynamically. >+ absl::optional<bool> auto_gain_control; >+ // Audio processing to filter out background noise. >+ absl::optional<bool> noise_suppression; >+ // Audio processing to remove background noise of lower frequencies. >+ absl::optional<bool> highpass_filter; >+ // Audio processing to swap the left and right channels. >+ absl::optional<bool> stereo_swapping; >+ // Audio receiver jitter buffer (NetEq) max capacity in number of packets. >+ absl::optional<int> audio_jitter_buffer_max_packets; >+ // Audio receiver jitter buffer (NetEq) fast accelerate mode. >+ absl::optional<bool> audio_jitter_buffer_fast_accelerate; >+ // Audio processing to detect typing. >+ absl::optional<bool> typing_detection; >+ absl::optional<bool> aecm_generate_comfort_noise; >+ absl::optional<bool> experimental_agc; >+ absl::optional<bool> extended_filter_aec; >+ absl::optional<bool> delay_agnostic_aec; >+ absl::optional<bool> experimental_ns; >+ absl::optional<bool> intelligibility_enhancer; >+ // Note that tx_agc_* only applies to non-experimental AGC. >+ absl::optional<bool> residual_echo_detector; >+ absl::optional<uint16_t> tx_agc_target_dbov; >+ absl::optional<uint16_t> tx_agc_digital_compression_gain; >+ absl::optional<bool> tx_agc_limiter; >+ // Enable combined audio+bandwidth BWE. >+ // TODO(pthatcher): This flag is set from the >+ // "googCombinedAudioVideoBwe", but not used anywhere. So delete it, >+ // and check if any other AudioOptions members are unused. >+ absl::optional<bool> combined_audio_video_bwe; >+ // Enable audio network adaptor. >+ absl::optional<bool> audio_network_adaptor; >+ // Config string for audio network adaptor. >+ absl::optional<std::string> audio_network_adaptor_config; >+ >+ private: >+ template <class T> >+ static std::string ToStringIfSet(const char* key, >+ const absl::optional<T>& val) { >+ std::string str; >+ if (val) { >+ str = key; >+ str += ": "; >+ str += val ? rtc::ToString(*val) : ""; >+ str += ", "; >+ } >+ return str; >+ } >+ >+ template <typename T> >+ static void SetFrom(absl::optional<T>* s, const absl::optional<T>& o) { >+ if (o) { >+ *s = o; >+ } >+ } >+}; >+ >+} // namespace cricket >+ >+#endif // API_AUDIO_OPTIONS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/bitrate_constraints.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/bitrate_constraints.h >new file mode 100644 >index 00000000000..98e89c08585 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/bitrate_constraints.h >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_BITRATE_CONSTRAINTS_H_ >+#define API_BITRATE_CONSTRAINTS_H_ >+ >+#include <algorithm> >+ >+namespace webrtc { >+// TODO(srte): BitrateConstraints and BitrateSettings should be merged. >+// Both represent the same kind data, but are using different default >+// initializer and representation of unset values. >+struct BitrateConstraints { >+ int min_bitrate_bps = 0; >+ int start_bitrate_bps = kDefaultStartBitrateBps; >+ int max_bitrate_bps = -1; >+ >+ private: >+ static constexpr int kDefaultStartBitrateBps = 300000; >+}; >+ >+// Like std::min, but considers non-positive values to be unset. >+template <typename T> >+static T MinPositive(T a, T b) { >+ if (a <= 0) { >+ return b; >+ } >+ if (b <= 0) { >+ return a; >+ } >+ return std::min(a, b); >+} >+} // namespace webrtc >+#endif // API_BITRATE_CONSTRAINTS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactoryinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/callfactoryinterface.h >similarity index 74% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactoryinterface.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/call/callfactoryinterface.h >index a3cf6ebc46c..a7f32453c63 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactoryinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/callfactoryinterface.h >@@ -8,15 +8,17 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef CALL_CALLFACTORYINTERFACE_H_ >-#define CALL_CALLFACTORYINTERFACE_H_ >+#ifndef API_CALL_CALLFACTORYINTERFACE_H_ >+#define API_CALL_CALLFACTORYINTERFACE_H_ > > #include <memory> > >-#include "call/call.h" >- > namespace webrtc { > >+// These classes are not part of the API, and are treated as opaque pointers. >+class Call; >+struct CallConfig; >+ > // This interface exists to allow webrtc to be optionally built without media > // support (i.e., if only being used for data channels). PeerConnectionFactory > // is constructed with a CallFactoryInterface, which may or may not be null. >@@ -24,11 +26,11 @@ class CallFactoryInterface { > public: > virtual ~CallFactoryInterface() {} > >- virtual Call* CreateCall(const Call::Config& config) = 0; >+ virtual Call* CreateCall(const CallConfig& config) = 0; > }; > > std::unique_ptr<CallFactoryInterface> CreateCallFactory(); > > } // namespace webrtc > >-#endif // CALL_CALLFACTORYINTERFACE_H_ >+#endif // API_CALL_CALLFACTORYINTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.cc >new file mode 100644 >index 00000000000..0a9dd5bcc7e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.cc >@@ -0,0 +1,21 @@ >+/* >+ * Copyright (c) 2018 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 "api/call/transport.h" >+ >+namespace webrtc { >+ >+PacketOptions::PacketOptions() = default; >+ >+PacketOptions::PacketOptions(const PacketOptions&) = default; >+ >+PacketOptions::~PacketOptions() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.h >index 1cdb0d366d8..18d22705cd6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/call/transport.h >@@ -13,15 +13,25 @@ > > #include <stddef.h> > #include <stdint.h> >+#include <vector> > > namespace webrtc { > > // TODO(holmer): Look into unifying this with the PacketOptions in > // asyncpacketsocket.h. > struct PacketOptions { >+ PacketOptions(); >+ PacketOptions(const PacketOptions&); >+ ~PacketOptions(); >+ > // A 16 bits positive id. Negative ids are invalid and should be interpreted > // as packet_id not being set. > int packet_id = -1; >+ // Additional data bound to the RTP packet for use in application code, >+ // outside of WebRTC. >+ std::vector<uint8_t> application_data; >+ // Whether this is a retransmission of an earlier packet. >+ bool is_retransmit = false; > }; > > class Transport { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.cc >index 62cd1bd1352..d51fb843712 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.cc >@@ -73,8 +73,9 @@ std::string Candidate::ToStringInternal(bool sensitive) const { > sensitive ? address_.ToSensitiveString() : address_.ToString(); > ost << "Cand[" << transport_name_ << ":" << foundation_ << ":" << component_ > << ":" << protocol_ << ":" << priority_ << ":" << address << ":" << type_ >- << ":" << related_address_ << ":" << username_ << ":" << password_ << ":" >- << network_id_ << ":" << network_cost_ << ":" << generation_ << "]"; >+ << ":" << related_address_.ToString() << ":" << username_ << ":" >+ << password_ << ":" << network_id_ << ":" << network_cost_ << ":" >+ << generation_ << "]"; > return ost.str(); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.h >index a1f45c215e1..6e0547b5e2f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/candidate.h >@@ -46,14 +46,14 @@ class Candidate { > Candidate(const Candidate&); > ~Candidate(); > >- const std::string & id() const { return id_; } >- void set_id(const std::string & id) { id_ = id; } >+ const std::string& id() const { return id_; } >+ void set_id(const std::string& id) { id_ = id; } > > int component() const { return component_; } > void set_component(int component) { component_ = component; } > >- const std::string & protocol() const { return protocol_; } >- void set_protocol(const std::string & protocol) { protocol_ = protocol; } >+ const std::string& protocol() const { return protocol_; } >+ void set_protocol(const std::string& protocol) { protocol_ = protocol; } > > // The protocol used to talk to relay. > const std::string& relay_protocol() const { return relay_protocol_; } >@@ -61,10 +61,8 @@ class Candidate { > relay_protocol_ = protocol; > } > >- const rtc::SocketAddress & address() const { return address_; } >- void set_address(const rtc::SocketAddress & address) { >- address_ = address; >- } >+ const rtc::SocketAddress& address() const { return address_; } >+ void set_address(const rtc::SocketAddress& address) { address_ = address; } > > uint32_t priority() const { return priority_; } > void set_priority(const uint32_t priority) { priority_ = priority; } >@@ -91,17 +89,17 @@ class Candidate { > } > > // TODO(honghaiz): Change to usernameFragment or ufrag. >- const std::string & username() const { return username_; } >- void set_username(const std::string & username) { username_ = username; } >+ const std::string& username() const { return username_; } >+ void set_username(const std::string& username) { username_ = username; } > >- const std::string & password() const { return password_; } >- void set_password(const std::string & password) { password_ = password; } >+ const std::string& password() const { return password_; } >+ void set_password(const std::string& password) { password_ = password; } > >- const std::string & type() const { return type_; } >- void set_type(const std::string & type) { type_ = type; } >+ const std::string& type() const { return type_; } >+ void set_type(const std::string& type) { type_ = type; } > >- const std::string & network_name() const { return network_name_; } >- void set_network_name(const std::string & network_name) { >+ const std::string& network_name() const { return network_name_; } >+ void set_network_name(const std::string& network_name) { > network_name_ = network_name; > } > >@@ -127,24 +125,17 @@ class Candidate { > uint16_t network_id() const { return network_id_; } > void set_network_id(uint16_t network_id) { network_id_ = network_id; } > >- const std::string& foundation() const { >- return foundation_; >- } >+ const std::string& foundation() const { return foundation_; } > void set_foundation(const std::string& foundation) { > foundation_ = foundation; > } > >- const rtc::SocketAddress & related_address() const { >- return related_address_; >- } >- void set_related_address( >- const rtc::SocketAddress & related_address) { >+ const rtc::SocketAddress& related_address() const { return related_address_; } >+ void set_related_address(const rtc::SocketAddress& related_address) { > related_address_ = related_address; > } > const std::string& tcptype() const { return tcptype_; } >- void set_tcptype(const std::string& tcptype) { >- tcptype_ = tcptype; >- } >+ void set_tcptype(const std::string& tcptype) { tcptype_ = tcptype; } > > // The name of the transport channel of this candidate. > // TODO(phoglund): remove. >@@ -164,13 +155,9 @@ class Candidate { > // given one when looking for a matching candidate to remove. > bool MatchesForRemoval(const Candidate& c) const; > >- std::string ToString() const { >- return ToStringInternal(false); >- } >+ std::string ToString() const { return ToStringInternal(false); } > >- std::string ToSensitiveString() const { >- return ToStringInternal(true); >- } >+ std::string ToSensitiveString() const { return ToStringInternal(true); } > > uint32_t GetPriority(uint32_t type_preference, > int network_adapter_preference, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.cc >new file mode 100644 >index 00000000000..141462d9075 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.cc >@@ -0,0 +1,35 @@ >+/* >+ * Copyright 2018 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 "api/datachannelinterface.h" >+ >+namespace webrtc { >+ >+bool DataChannelInterface::ordered() const { >+ return false; >+} >+ >+uint16_t DataChannelInterface::maxRetransmitTime() const { >+ return 0; >+} >+ >+uint16_t DataChannelInterface::maxRetransmits() const { >+ return 0; >+} >+ >+std::string DataChannelInterface::protocol() const { >+ return std::string(); >+} >+ >+bool DataChannelInterface::negotiated() const { >+ return false; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.h >index 4b5ce9a7333..a0d2b3b51a5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/datachannelinterface.h >@@ -16,7 +16,6 @@ > > #include <string> > >-#include "rtc_base/basictypes.h" > #include "rtc_base/checks.h" > #include "rtc_base/copyonwritebuffer.h" > #include "rtc_base/refcount.h" >@@ -24,7 +23,7 @@ > namespace webrtc { > > // C++ version of: https://www.w3.org/TR/webrtc/#idl-def-rtcdatachannelinit >-// TODO(deadbeef): Use rtc::Optional for the "-1 if unset" things. >+// TODO(deadbeef): Use absl::optional for the "-1 if unset" things. > struct DataChannelInit { > // Deprecated. Reliability is assumed, and channel will be unreliable if > // maxRetransmitTime or MaxRetransmits is set. >@@ -62,14 +61,10 @@ struct DataChannelInit { > // as binary or text. > struct DataBuffer { > DataBuffer(const rtc::CopyOnWriteBuffer& data, bool binary) >- : data(data), >- binary(binary) { >- } >+ : data(data), binary(binary) {} > // For convenience for unit tests. > explicit DataBuffer(const std::string& text) >- : data(text.data(), text.length()), >- binary(false) { >- } >+ : data(text.data(), text.length()), binary(false) {} > size_t size() const { return data.size(); } > > rtc::CopyOnWriteBuffer data; >@@ -90,10 +85,10 @@ class DataChannelObserver { > // A data buffer was successfully received. > virtual void OnMessage(const DataBuffer& buffer) = 0; > // The data channel's buffered_amount has changed. >- virtual void OnBufferedAmountChange(uint64_t) {} >+ virtual void OnBufferedAmountChange(uint64_t previous_amount) {} > > protected: >- virtual ~DataChannelObserver() {} >+ virtual ~DataChannelObserver() = default; > }; > > class DataChannelInterface : public rtc::RefCountInterface { >@@ -139,11 +134,11 @@ class DataChannelInterface : public rtc::RefCountInterface { > // TODO(deadbeef): Remove these dummy implementations when all classes have > // implemented these APIs. They should all just return the values the > // DataChannel was created with. >- virtual bool ordered() const { return false; } >- virtual uint16_t maxRetransmitTime() const { return 0; } >- virtual uint16_t maxRetransmits() const { return 0; } >- virtual std::string protocol() const { return std::string(); } >- virtual bool negotiated() const { return false; } >+ virtual bool ordered() const; >+ virtual uint16_t maxRetransmitTime() const; >+ virtual uint16_t maxRetransmits() const; >+ virtual std::string protocol() const; >+ virtual bool negotiated() const; > > // Returns the ID from the DataChannelInit, if it was negotiated out-of-band. > // If negotiated in-band, this ID will be populated once the DTLS role is >@@ -175,7 +170,7 @@ class DataChannelInterface : public rtc::RefCountInterface { > virtual bool Send(const DataBuffer& buffer) = 0; > > protected: >- virtual ~DataChannelInterface() {} >+ ~DataChannelInterface() override = default; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/dtmfsenderinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/dtmfsenderinterface.h >index 8f0ab71206c..b79bb318047 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/dtmfsenderinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/dtmfsenderinterface.h >@@ -29,7 +29,7 @@ class DtmfSenderObserverInterface { > virtual void OnToneChange(const std::string& tone) = 0; > > protected: >- virtual ~DtmfSenderObserverInterface() {} >+ virtual ~DtmfSenderObserverInterface() = default; > }; > > // The interface of native implementation of the RTCDTMFSender defined by the >@@ -67,14 +67,10 @@ class DtmfSenderInterface : public rtc::RefCountInterface { > // If InsertDtmf is called on the same object while an existing task for this > // object to generate DTMF is still running, the previous task is canceled. > // Returns true on success and false on failure. >- virtual bool InsertDtmf(const std::string& tones, int duration, >+ virtual bool InsertDtmf(const std::string& tones, >+ int duration, > int inter_tone_gap) = 0; > >- // Returns the track given as argument to the constructor. Only exists for >- // backwards compatibilty; now that DtmfSenders are tied to RtpSenders, it's >- // no longer relevant. >- virtual const AudioTrackInterface* track() const = 0; >- > // Returns the tones remaining to be played out. > virtual std::string tones() const = 0; > >@@ -89,7 +85,7 @@ class DtmfSenderInterface : public rtc::RefCountInterface { > virtual int inter_tone_gap() const = 0; > > protected: >- virtual ~DtmfSenderInterface() {} >+ ~DtmfSenderInterface() override = default; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.cc >deleted file mode 100644 >index d09bf171851..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.cc >+++ /dev/null >@@ -1,64 +0,0 @@ >-/* >- * Copyright 2015 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 "api/fakemetricsobserver.h" >-#include "rtc_base/checks.h" >- >-namespace webrtc { >- >-FakeMetricsObserver::FakeMetricsObserver() { >- Reset(); >-} >- >-void FakeMetricsObserver::Reset() { >- RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- counters_.clear(); >- memset(histogram_samples_, 0, sizeof(histogram_samples_)); >-} >- >-void FakeMetricsObserver::IncrementEnumCounter( >- PeerConnectionEnumCounterType type, >- int counter, >- int counter_max) { >- RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- if (counters_.size() <= static_cast<size_t>(type)) { >- counters_.resize(type + 1); >- } >- auto& counters = counters_[type]; >- ++counters[counter]; >-} >- >-void FakeMetricsObserver::AddHistogramSample(PeerConnectionMetricsName type, >- int value) { >- RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- RTC_DCHECK_EQ(histogram_samples_[type], 0); >- histogram_samples_[type] = value; >-} >- >-int FakeMetricsObserver::GetEnumCounter(PeerConnectionEnumCounterType type, >- int counter) const { >- RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- if (counters_.size() <= static_cast<size_t>(type)) { >- return 0; >- } >- const auto& it = counters_[type].find(counter); >- if (it == counters_[type].end()) { >- return 0; >- } >- return it->second; >-} >- >-int FakeMetricsObserver::GetHistogramSample( >- PeerConnectionMetricsName type) const { >- RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- return histogram_samples_[type]; >-} >- >-} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.h >deleted file mode 100644 >index afd019391a6..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/fakemetricsobserver.h >+++ /dev/null >@@ -1,52 +0,0 @@ >-/* >- * Copyright 2015 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. >- */ >- >-#ifndef API_FAKEMETRICSOBSERVER_H_ >-#define API_FAKEMETRICSOBSERVER_H_ >- >-#include <map> >-#include <string> >-#include <vector> >- >-#include "api/peerconnectioninterface.h" >-#include "rtc_base/thread_checker.h" >- >-namespace webrtc { >- >-class FakeMetricsObserver : public MetricsObserverInterface { >- public: >- FakeMetricsObserver(); >- void Reset(); >- >- void IncrementEnumCounter(PeerConnectionEnumCounterType, >- int counter, >- int counter_max) override; >- void AddHistogramSample(PeerConnectionMetricsName type, >- int value) override; >- >- // Accessors to be used by the tests. >- int GetEnumCounter(PeerConnectionEnumCounterType type, int counter) const; >- int GetHistogramSample(PeerConnectionMetricsName type) const; >- >- protected: >- ~FakeMetricsObserver() {} >- >- private: >- rtc::ThreadChecker thread_checker_; >- // The vector contains maps for each counter type. In the map, it's a mapping >- // from individual counter to its count, such that it's memory efficient when >- // comes to sparse enum types, like the SSL ciphers in the IANA registry. >- std::vector<std::map<int, int>> counters_; >- int histogram_samples_[kPeerConnectionMetricsName_Max]; >-}; >- >-} // namespace webrtc >- >-#endif // API_FAKEMETRICSOBSERVER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/fec_controller.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/fec_controller.h >new file mode 100644 >index 00000000000..59e86ccedbd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/fec_controller.h >@@ -0,0 +1,91 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+ >+#ifndef API_FEC_CONTROLLER_H_ >+#define API_FEC_CONTROLLER_H_ >+ >+#include <memory> >+#include <vector> >+ >+#include "common_types.h" // NOLINT(build/include) >+#include "modules/include/module_fec_types.h" >+ >+namespace webrtc { >+// TODO(yinwa): work in progress. API in class FecController should not be >+// used by other users until this comment is removed. >+ >+// Callback class used for telling the user about how to configure the FEC, >+// and the rates sent the last second is returned to the VCM. >+class VCMProtectionCallback { >+ public: >+ virtual int ProtectionRequest(const FecProtectionParams* delta_params, >+ const FecProtectionParams* key_params, >+ uint32_t* sent_video_rate_bps, >+ uint32_t* sent_nack_rate_bps, >+ uint32_t* sent_fec_rate_bps) = 0; >+ >+ protected: >+ virtual ~VCMProtectionCallback() {} >+}; >+ >+// FecController calculates how much of the allocated network >+// capacity that can be used by an encoder and how much that >+// is needed for redundant packets such as FEC and NACK. It uses an >+// implementation of |VCMProtectionCallback| to set new FEC parameters and get >+// the bitrate currently used for FEC and NACK. >+// Usage: >+// Setup by calling SetProtectionMethod and SetEncodingData. >+// For each encoded image, call UpdateWithEncodedData. >+// Each time the bandwidth estimate change, call UpdateFecRates. UpdateFecRates >+// will return the bitrate that can be used by an encoder. >+// A lock is used to protect internal states, so methods can be called on an >+// arbitrary thread. >+class FecController { >+ public: >+ virtual ~FecController() {} >+ >+ virtual void SetProtectionCallback( >+ VCMProtectionCallback* protection_callback) = 0; >+ virtual void SetProtectionMethod(bool enable_fec, bool enable_nack) = 0; >+ >+ // Informs loss protectoin logic of initial encoding state. >+ virtual void SetEncodingData(size_t width, >+ size_t height, >+ size_t num_temporal_layers, >+ size_t max_payload_size) = 0; >+ >+ // Returns target rate for the encoder given the channel parameters. >+ // Inputs: estimated_bitrate_bps - the estimated network bitrate in bits/s. >+ // actual_framerate - encoder frame rate. >+ // fraction_lost - packet loss rate in % in the network. >+ // loss_mask_vector - packet loss mask since last time this method >+ // was called. round_trip_time_ms - round trip time in milliseconds. >+ virtual uint32_t UpdateFecRates(uint32_t estimated_bitrate_bps, >+ int actual_framerate, >+ uint8_t fraction_lost, >+ std::vector<bool> loss_mask_vector, >+ int64_t round_trip_time_ms) = 0; >+ >+ // Informs of encoded output. >+ virtual void UpdateWithEncodedData(size_t encoded_image_length, >+ FrameType encoded_image_frametype) = 0; >+ >+ // Returns whether this FEC Controller needs Loss Vector Mask as input. >+ virtual bool UseLossVectorMask() = 0; >+}; >+ >+class FecControllerFactoryInterface { >+ public: >+ virtual std::unique_ptr<FecController> CreateFecController() = 0; >+ virtual ~FecControllerFactoryInterface() = default; >+}; >+ >+} // namespace webrtc >+#endif // API_FEC_CONTROLLER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.cc >index 1f4afbaca1c..52a60f95e32 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.cc >@@ -21,4 +21,21 @@ size_t SessionDescriptionInterface::RemoveCandidates( > return 0; > } > >+void CreateSessionDescriptionObserver::OnFailure(RTCError error) { >+ OnFailure(error.message()); >+} >+ >+void CreateSessionDescriptionObserver::OnFailure(const std::string& error) { >+ OnFailure(RTCError(RTCErrorType::INTERNAL_ERROR, std::string(error))); >+} >+ >+void SetSessionDescriptionObserver::OnFailure(RTCError error) { >+ std::string message(error.message()); >+ OnFailure(message); >+} >+ >+void SetSessionDescriptionObserver::OnFailure(const std::string& error) { >+ OnFailure(RTCError(RTCErrorType::INTERNAL_ERROR, std::string(error))); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.h >index 581f689d1c6..4d4bcc0bfb6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsep.h >@@ -26,7 +26,8 @@ > #include <string> > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" >+#include "api/rtcerror.h" > #include "rtc_base/refcount.h" > > namespace cricket { >@@ -77,6 +78,12 @@ IceCandidateInterface* CreateIceCandidate(const std::string& sdp_mid, > const std::string& sdp, > SdpParseError* error); > >+// Creates an IceCandidateInterface based on a parsed candidate structure. >+std::unique_ptr<IceCandidateInterface> CreateIceCandidate( >+ const std::string& sdp_mid, >+ int sdp_mline_index, >+ const cricket::Candidate& candidate); >+ > // This class represents a collection of candidates for a specific m= section. > // Used in SessionDescriptionInterface. > class IceCandidateCollection { >@@ -106,7 +113,7 @@ const char* SdpTypeToString(SdpType type); > // Returns the SdpType from its string form. The string form can be one of the > // constants defined in SessionDescriptionInterface. Passing in any other string > // results in nullopt. >-rtc::Optional<SdpType> SdpTypeFromString(const std::string& type_str); >+absl::optional<SdpType> SdpTypeFromString(const std::string& type_str); > > // Class representation of an SDP session description. > // >@@ -190,6 +197,14 @@ std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription( > const std::string& sdp, > SdpParseError* error_out); > >+// Creates a SessionDescriptionInterface based on a parsed SDP structure and the >+// given type, ID and version. >+std::unique_ptr<SessionDescriptionInterface> CreateSessionDescription( >+ SdpType type, >+ const std::string& session_id, >+ const std::string& session_version, >+ std::unique_ptr<cricket::SessionDescription> description); >+ > // CreateOffer and CreateAnswer callback interface. > class CreateSessionDescriptionObserver : public rtc::RefCountInterface { > public: >@@ -197,7 +212,15 @@ class CreateSessionDescriptionObserver : public rtc::RefCountInterface { > // TODO(deadbeef): Make this take an std::unique_ptr<> to avoid confusion > // around ownership. > virtual void OnSuccess(SessionDescriptionInterface* desc) = 0; >- virtual void OnFailure(const std::string& error) = 0; >+ // The OnFailure callback takes an RTCError, which consists of an >+ // error code and a string. >+ // RTCError is non-copyable, so it must be passed using std::move. >+ // Earlier versions of the API used a string argument. This version >+ // is deprecated; in order to let clients remove the old version, it has a >+ // default implementation. If both versions are unimplemented, the >+ // result will be a runtime error (stack overflow). This is intentional. >+ virtual void OnFailure(RTCError error); >+ virtual void OnFailure(const std::string& error); > > protected: > ~CreateSessionDescriptionObserver() override = default; >@@ -207,7 +230,10 @@ class CreateSessionDescriptionObserver : public rtc::RefCountInterface { > class SetSessionDescriptionObserver : public rtc::RefCountInterface { > public: > virtual void OnSuccess() = 0; >- virtual void OnFailure(const std::string& error) = 0; >+ // See description in CreateSessionDescriptionObserver for OnFailure. >+ virtual void OnFailure(RTCError error); >+ >+ virtual void OnFailure(const std::string& error); > > protected: > ~SetSessionDescriptionObserver() override = default; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.cc >new file mode 100644 >index 00000000000..b9ba2fea29a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.cc >@@ -0,0 +1,83 @@ >+/* >+ * Copyright 2018 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 "api/jsepicecandidate.h" >+ >+namespace webrtc { >+ >+std::string JsepIceCandidate::sdp_mid() const { >+ return sdp_mid_; >+} >+ >+int JsepIceCandidate::sdp_mline_index() const { >+ return sdp_mline_index_; >+} >+ >+const cricket::Candidate& JsepIceCandidate::candidate() const { >+ return candidate_; >+} >+ >+std::string JsepIceCandidate::server_url() const { >+ return candidate_.url(); >+} >+ >+JsepCandidateCollection::JsepCandidateCollection() = default; >+ >+JsepCandidateCollection::JsepCandidateCollection(JsepCandidateCollection&& o) >+ : candidates_(std::move(o.candidates_)) {} >+ >+size_t JsepCandidateCollection::count() const { >+ return candidates_.size(); >+} >+ >+void JsepCandidateCollection::add(JsepIceCandidate* candidate) { >+ candidates_.push_back(candidate); >+} >+ >+const IceCandidateInterface* JsepCandidateCollection::at(size_t index) const { >+ return candidates_[index]; >+} >+ >+JsepCandidateCollection::~JsepCandidateCollection() { >+ for (std::vector<JsepIceCandidate*>::iterator it = candidates_.begin(); >+ it != candidates_.end(); ++it) { >+ delete *it; >+ } >+} >+ >+bool JsepCandidateCollection::HasCandidate( >+ const IceCandidateInterface* candidate) const { >+ bool ret = false; >+ for (std::vector<JsepIceCandidate*>::const_iterator it = candidates_.begin(); >+ it != candidates_.end(); ++it) { >+ if ((*it)->sdp_mid() == candidate->sdp_mid() && >+ (*it)->sdp_mline_index() == candidate->sdp_mline_index() && >+ (*it)->candidate().IsEquivalent(candidate->candidate())) { >+ ret = true; >+ break; >+ } >+ } >+ return ret; >+} >+ >+size_t JsepCandidateCollection::remove(const cricket::Candidate& candidate) { >+ auto iter = std::find_if(candidates_.begin(), candidates_.end(), >+ [candidate](JsepIceCandidate* c) { >+ return candidate.MatchesForRemoval(c->candidate()); >+ }); >+ if (iter != candidates_.end()) { >+ delete *iter; >+ candidates_.erase(iter); >+ return 1; >+ } >+ return 0; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.h >index dae6121eade..50520fe7279 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepicecandidate.h >@@ -28,24 +28,23 @@ namespace webrtc { > class JsepIceCandidate : public IceCandidateInterface { > public: > JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index); >- JsepIceCandidate(const std::string& sdp_mid, int sdp_mline_index, >+ JsepIceCandidate(const std::string& sdp_mid, >+ int sdp_mline_index, > const cricket::Candidate& candidate); >- ~JsepIceCandidate(); >+ ~JsepIceCandidate() override; > // |err| may be null. > bool Initialize(const std::string& sdp, SdpParseError* err); > void SetCandidate(const cricket::Candidate& candidate) { > candidate_ = candidate; > } > >- virtual std::string sdp_mid() const { return sdp_mid_; } >- virtual int sdp_mline_index() const { return sdp_mline_index_; } >- virtual const cricket::Candidate& candidate() const { >- return candidate_; >- } >+ std::string sdp_mid() const override; >+ int sdp_mline_index() const override; >+ const cricket::Candidate& candidate() const override; > >- virtual std::string server_url() const { return candidate_.url(); } >+ std::string server_url() const override; > >- virtual bool ToString(std::string* out) const; >+ bool ToString(std::string* out) const override; > > private: > std::string sdp_mid_; >@@ -58,25 +57,18 @@ class JsepIceCandidate : public IceCandidateInterface { > // Implementation of IceCandidateCollection which stores JsepIceCandidates. > class JsepCandidateCollection : public IceCandidateCollection { > public: >- JsepCandidateCollection() {} >+ JsepCandidateCollection(); > // Move constructor is defined so that a vector of JsepCandidateCollections > // can be resized. >- JsepCandidateCollection(JsepCandidateCollection&& o) >- : candidates_(std::move(o.candidates_)) {} >- ~JsepCandidateCollection(); >- virtual size_t count() const { >- return candidates_.size(); >- } >- virtual bool HasCandidate(const IceCandidateInterface* candidate) const; >+ JsepCandidateCollection(JsepCandidateCollection&& o); >+ ~JsepCandidateCollection() override; >+ size_t count() const override; >+ bool HasCandidate(const IceCandidateInterface* candidate) const override; > // Adds and takes ownership of the JsepIceCandidate. > // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is > // more clear. >- virtual void add(JsepIceCandidate* candidate) { >- candidates_.push_back(candidate); >- } >- virtual const IceCandidateInterface* at(size_t index) const { >- return candidates_[index]; >- } >+ virtual void add(JsepIceCandidate* candidate); >+ const IceCandidateInterface* at(size_t index) const override; > // Removes the candidate that has a matching address and protocol. > // > // Returns the number of candidates that were removed. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepsessiondescription.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepsessiondescription.h >index 70bb27710a2..d70829e0fbe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepsessiondescription.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/jsepsessiondescription.h >@@ -41,8 +41,8 @@ class JsepSessionDescription : public SessionDescriptionInterface { > // TODO(deadbeef): Make this use an std::unique_ptr<>, so ownership logic is > // more clear. > bool Initialize(cricket::SessionDescription* description, >- const std::string& session_id, >- const std::string& session_version); >+ const std::string& session_id, >+ const std::string& session_version); > > virtual cricket::SessionDescription* description() { > return description_.get(); >@@ -50,12 +50,8 @@ class JsepSessionDescription : public SessionDescriptionInterface { > virtual const cricket::SessionDescription* description() const { > return description_.get(); > } >- virtual std::string session_id() const { >- return session_id_; >- } >- virtual std::string session_version() const { >- return session_version_; >- } >+ virtual std::string session_id() const { return session_id_; } >+ virtual std::string session_version() const { return session_version_; } > virtual SdpType GetType() const { return type_; } > virtual std::string type() const { return SdpTypeToString(type_); } > // Allows changing the type. Used for testing. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.cc >index 90a957cfa48..fb4481f35b5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.cc >@@ -59,11 +59,11 @@ bool FindConstraint(const webrtc::MediaConstraintsInterface* constraints, > } > > // Converts a constraint (mandatory takes precedence over optional) to an >-// rtc::Optional. >+// absl::optional. > template <typename T> > void ConstraintToOptional(const webrtc::MediaConstraintsInterface* constraints, > const std::string& key, >- rtc::Optional<T>* value_out) { >+ absl::optional<T>* value_out) { > T value; > bool present = FindConstraint<T>(constraints, key, &value, nullptr); > if (present) { >@@ -89,8 +89,7 @@ const char MediaConstraintsInterface::kMaxFrameRate[] = "maxFrameRate"; > const char MediaConstraintsInterface::kMinFrameRate[] = "minFrameRate"; > > // Audio constraints. >-const char MediaConstraintsInterface::kEchoCancellation[] = >- "echoCancellation"; >+const char MediaConstraintsInterface::kEchoCancellation[] = "echoCancellation"; > const char MediaConstraintsInterface::kGoogEchoCancellation[] = > "googEchoCancellation"; > const char MediaConstraintsInterface::kExtendedFilterEchoCancellation[] = >@@ -107,11 +106,7 @@ const char MediaConstraintsInterface::kExperimentalNoiseSuppression[] = > "googNoiseSuppression2"; > const char MediaConstraintsInterface::kIntelligibilityEnhancer[] = > "intelligibilityEnhancer"; >-const char MediaConstraintsInterface::kLevelControl[] = "levelControl"; >-const char MediaConstraintsInterface::kLevelControlInitialPeakLevelDBFS[] = >- "levelControlInitialPeakLevelDBFS"; >-const char MediaConstraintsInterface::kHighpassFilter[] = >- "googHighpassFilter"; >+const char MediaConstraintsInterface::kHighpassFilter[] = "googHighpassFilter"; > const char MediaConstraintsInterface::kTypingNoiseDetection[] = > "googTypingNoiseDetection"; > const char MediaConstraintsInterface::kAudioMirroring[] = "googAudioMirroring"; >@@ -128,11 +123,9 @@ const char MediaConstraintsInterface::kOfferToReceiveVideo[] = > "OfferToReceiveVideo"; > const char MediaConstraintsInterface::kVoiceActivityDetection[] = > "VoiceActivityDetection"; >-const char MediaConstraintsInterface::kIceRestart[] = >- "IceRestart"; >+const char MediaConstraintsInterface::kIceRestart[] = "IceRestart"; > // Google specific constraint for BUNDLE enable/disable. >-const char MediaConstraintsInterface::kUseRtpMux[] = >- "googUseRtpMUX"; >+const char MediaConstraintsInterface::kUseRtpMux[] = "googUseRtpMUX"; > > // Below constraints should be used during PeerConnection construction. > const char MediaConstraintsInterface::kEnableDtlsSrtp[] = >@@ -153,11 +146,11 @@ const char MediaConstraintsInterface::kCpuOveruseDetection[] = > "googCpuOveruseDetection"; > const char MediaConstraintsInterface::kPayloadPadding[] = "googPayloadPadding"; > >- > // Set |value| to the value associated with the first appearance of |key|, or > // return false if |key| is not found. > bool MediaConstraintsInterface::Constraints::FindFirst( >- const std::string& key, std::string* value) const { >+ const std::string& key, >+ std::string* value) const { > for (Constraints::const_iterator iter = begin(); iter != end(); ++iter) { > if (iter->key == key) { > *value = iter->value; >@@ -168,7 +161,8 @@ bool MediaConstraintsInterface::Constraints::FindFirst( > } > > bool FindConstraint(const MediaConstraintsInterface* constraints, >- const std::string& key, bool* value, >+ const std::string& key, >+ bool* value, > size_t* mandatory_constraints) { > return ::FindConstraint<bool>(constraints, key, value, mandatory_constraints); > } >@@ -195,9 +189,9 @@ void CopyConstraintsIntoRtcConfiguration( > } > FindConstraint(constraints, MediaConstraintsInterface::kEnableDscp, > &configuration->media_config.enable_dscp, nullptr); >- FindConstraint( >- constraints, MediaConstraintsInterface::kCpuOveruseDetection, >- &configuration->media_config.video.enable_cpu_overuse_detection, nullptr); >+ FindConstraint(constraints, MediaConstraintsInterface::kCpuOveruseDetection, >+ &configuration->media_config.video.enable_cpu_adaptation, >+ nullptr); > FindConstraint(constraints, MediaConstraintsInterface::kEnableRtpDataChannels, > &configuration->enable_rtp_data_channel, nullptr); > // Find Suspend Below Min Bitrate constraint. >@@ -247,9 +241,6 @@ void CopyConstraintsIntoAudioOptions( > ConstraintToOptional<bool>( > constraints, MediaConstraintsInterface::kIntelligibilityEnhancer, > &options->intelligibility_enhancer); >- ConstraintToOptional<bool>(constraints, >- MediaConstraintsInterface::kLevelControl, >- &options->level_control); > ConstraintToOptional<bool>(constraints, > MediaConstraintsInterface::kHighpassFilter, > &options->highpass_filter); >@@ -259,9 +250,6 @@ void CopyConstraintsIntoAudioOptions( > ConstraintToOptional<bool>(constraints, > MediaConstraintsInterface::kAudioMirroring, > &options->stereo_swapping); >- ConstraintToOptional<float>( >- constraints, MediaConstraintsInterface::kLevelControlInitialPeakLevelDBFS, >- &options->level_control_initial_peak_level_dbfs); > ConstraintToOptional<std::string>( > constraints, MediaConstraintsInterface::kAudioNetworkAdaptorConfig, > &options->audio_network_adaptor_config); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.h >index 73e4619bca9..54ab7067660 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediaconstraintsinterface.h >@@ -23,7 +23,7 @@ > #include <string> > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "api/peerconnectioninterface.h" > > namespace webrtc { >@@ -39,8 +39,7 @@ class MediaConstraintsInterface { > struct Constraint { > Constraint() {} > Constraint(const std::string& key, const std::string value) >- : key(key), value(value) { >- } >+ : key(key), value(value) {} > std::string key; > std::string value; > }; >@@ -54,12 +53,12 @@ class MediaConstraintsInterface { > // Specified by draft-alvestrand-constraints-resolution-00b > static const char kMinAspectRatio[]; // minAspectRatio > static const char kMaxAspectRatio[]; // maxAspectRatio >- static const char kMaxWidth[]; // maxWidth >- static const char kMinWidth[]; // minWidth >- static const char kMaxHeight[]; // maxHeight >- static const char kMinHeight[]; // minHeight >- static const char kMaxFrameRate[]; // maxFrameRate >- static const char kMinFrameRate[]; // minFrameRate >+ static const char kMaxWidth[]; // maxWidth >+ static const char kMinWidth[]; // minWidth >+ static const char kMaxHeight[]; // maxHeight >+ static const char kMinHeight[]; // minHeight >+ static const char kMaxFrameRate[]; // maxFrameRate >+ static const char kMinFrameRate[]; // minFrameRate > > // Constraint keys used by a local audio source. > static const char kEchoCancellation[]; // echoCancellation >@@ -68,18 +67,15 @@ class MediaConstraintsInterface { > static const char kGoogEchoCancellation[]; // googEchoCancellation > > static const char kExtendedFilterEchoCancellation[]; // googEchoCancellation2 >- static const char kDAEchoCancellation[]; // googDAEchoCancellation >- static const char kAutoGainControl[]; // googAutoGainControl >- static const char kExperimentalAutoGainControl[]; // googAutoGainControl2 >- static const char kNoiseSuppression[]; // googNoiseSuppression >+ static const char kDAEchoCancellation[]; // googDAEchoCancellation >+ static const char kAutoGainControl[]; // googAutoGainControl >+ static const char kExperimentalAutoGainControl[]; // googAutoGainControl2 >+ static const char kNoiseSuppression[]; // googNoiseSuppression > static const char kExperimentalNoiseSuppression[]; // googNoiseSuppression2 >- static const char kIntelligibilityEnhancer[]; // intelligibilityEnhancer >- static const char kLevelControl[]; // levelControl >- static const char >- kLevelControlInitialPeakLevelDBFS[]; // levelControlInitialPeakLevelDBFS >- static const char kHighpassFilter[]; // googHighpassFilter >+ static const char kIntelligibilityEnhancer[]; // intelligibilityEnhancer >+ static const char kHighpassFilter[]; // googHighpassFilter > static const char kTypingNoiseDetection[]; // googTypingNoiseDetection >- static const char kAudioMirroring[]; // googAudioMirroring >+ static const char kAudioMirroring[]; // googAudioMirroring > static const char > kAudioNetworkAdaptorConfig[]; // goodAudioNetworkAdaptorConfig > >@@ -88,15 +84,15 @@ class MediaConstraintsInterface { > > // Constraint keys for CreateOffer / CreateAnswer > // Specified by the W3C PeerConnection spec >- static const char kOfferToReceiveVideo[]; // OfferToReceiveVideo >- static const char kOfferToReceiveAudio[]; // OfferToReceiveAudio >+ static const char kOfferToReceiveVideo[]; // OfferToReceiveVideo >+ static const char kOfferToReceiveAudio[]; // OfferToReceiveAudio > static const char kVoiceActivityDetection[]; // VoiceActivityDetection >- static const char kIceRestart[]; // IceRestart >+ static const char kIceRestart[]; // IceRestart > // These keys are google specific. > static const char kUseRtpMux[]; // googUseRtpMUX > > // Constraints values. >- static const char kValueTrue[]; // true >+ static const char kValueTrue[]; // true > static const char kValueFalse[]; // false > > // PeerConnection constraint keys. >@@ -111,12 +107,12 @@ class MediaConstraintsInterface { > static const char kEnableIPv6[]; // googIPv6 > // Temporary constraint to enable suspend below min bitrate feature. > static const char kEnableVideoSuspendBelowMinBitrate[]; >- // googSuspendBelowMinBitrate >+ // googSuspendBelowMinBitrate > // Constraint to enable combined audio+video bandwidth estimation. > static const char kCombinedAudioVideoBwe[]; // googCombinedAudioVideoBwe >- static const char kScreencastMinBitrate[]; // googScreencastMinBitrate >- static const char kCpuOveruseDetection[]; // googCpuOveruseDetection >- static const char kPayloadPadding[]; // googPayloadPadding >+ static const char kScreencastMinBitrate[]; // googScreencastMinBitrate >+ static const char kCpuOveruseDetection[]; // googCpuOveruseDetection >+ static const char kPayloadPadding[]; // googPayloadPadding > > // The prefix of internal-only constraints whose JS set values should be > // stripped by Chrome before passed down to Libjingle. >@@ -129,7 +125,8 @@ class MediaConstraintsInterface { > }; > > bool FindConstraint(const MediaConstraintsInterface* constraints, >- const std::string& key, bool* value, >+ const std::string& key, >+ bool* value, > size_t* mandatory_constraints); > > bool FindConstraint(const MediaConstraintsInterface* constraints, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.cc >index 0bc5d61e800..6f08a0caf1c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.cc >@@ -45,4 +45,17 @@ AudioProcessorInterface::GetStats(bool /*has_remote_tracks*/) { > return new_stats; > } > >+VideoTrackInterface::ContentHint VideoTrackInterface::content_hint() const { >+ return ContentHint::kNone; >+} >+ >+bool AudioTrackInterface::GetSignalLevel(int* level) { >+ return false; >+} >+ >+rtc::scoped_refptr<AudioProcessorInterface> >+AudioTrackInterface::GetAudioProcessor() { >+ return nullptr; >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.h >index 2b7b56a2b12..b661351e9fc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreaminterface.h >@@ -22,13 +22,13 @@ > #include <string> > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "api/video/video_frame.h" > // TODO(zhihuang): Remove unrelated headers once downstream applications stop > // relying on them; they were previously transitively included by > // mediachannel.h, which is no longer a dependency of this file. >-#include "api/videosinkinterface.h" >-#include "api/videosourceinterface.h" >+#include "api/video/video_sink_interface.h" >+#include "api/video/video_source_interface.h" > #include "modules/audio_processing/include/audio_processing_statistics.h" > #include "rtc_base/ratetracker.h" > #include "rtc_base/refcount.h" >@@ -60,19 +60,14 @@ class NotifierInterface { > class MediaSourceInterface : public rtc::RefCountInterface, > public NotifierInterface { > public: >- enum SourceState { >- kInitializing, >- kLive, >- kEnded, >- kMuted >- }; >+ enum SourceState { kInitializing, kLive, kEnded, kMuted }; > > virtual SourceState state() const = 0; > > virtual bool remote() const = 0; > > protected: >- virtual ~MediaSourceInterface() {} >+ ~MediaSourceInterface() override = default; > }; > > // C++ version of MediaStreamTrack. >@@ -106,7 +101,7 @@ class MediaStreamTrackInterface : public rtc::RefCountInterface, > virtual TrackState state() const = 0; > > protected: >- virtual ~MediaStreamTrackInterface() {} >+ ~MediaStreamTrackInterface() override = default; > }; > > // VideoTrackSourceInterface is a reference counted source used for >@@ -116,9 +111,8 @@ class MediaStreamTrackInterface : public rtc::RefCountInterface, > // on the worker thread via a VideoTrack. A custom implementation of a source > // can inherit AdaptedVideoTrackSource instead of directly implementing this > // interface. >-class VideoTrackSourceInterface >- : public MediaSourceInterface, >- public rtc::VideoSourceInterface<VideoFrame> { >+class VideoTrackSourceInterface : public MediaSourceInterface, >+ public rtc::VideoSourceInterface<VideoFrame> { > public: > struct Stats { > // Original size of captured frame, before video adaptation. >@@ -138,7 +132,7 @@ class VideoTrackSourceInterface > // depending on video codec. > // TODO(perkj): Remove this once denoising is done by the source, and not by > // the encoder. >- virtual rtc::Optional<bool> needs_denoising() const = 0; >+ virtual absl::optional<bool> needs_denoising() const = 0; > > // Returns false if no stats are available, e.g, for a remote source, or a > // source which has not seen its first frame yet. >@@ -147,7 +141,7 @@ class VideoTrackSourceInterface > virtual bool GetStats(Stats* stats) = 0; > > protected: >- virtual ~VideoTrackSourceInterface() {} >+ ~VideoTrackSourceInterface() override = default; > }; > > // VideoTrackInterface is designed to be invoked on the signaling thread except >@@ -156,28 +150,27 @@ class VideoTrackSourceInterface > // PeerConnectionFactory::CreateVideoTrack can be used for creating a VideoTrack > // that ensures thread safety and that all methods are called on the right > // thread. >-class VideoTrackInterface >- : public MediaStreamTrackInterface, >- public rtc::VideoSourceInterface<VideoFrame> { >+class VideoTrackInterface : public MediaStreamTrackInterface, >+ public rtc::VideoSourceInterface<VideoFrame> { > public: > // Video track content hint, used to override the source is_screencast > // property. >- // See https://crbug.com/653531 and https://github.com/WICG/mst-content-hint. >- enum class ContentHint { kNone, kFluid, kDetailed }; >+ // See https://crbug.com/653531 and https://w3c.github.io/mst-content-hint. >+ enum class ContentHint { kNone, kFluid, kDetailed, kText }; > > // Register a video sink for this track. Used to connect the track to the > // underlying video engine. >- void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>*, >- const rtc::VideoSinkWants&) override {} >- void RemoveSink(rtc::VideoSinkInterface<VideoFrame>*) override {} >+ void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink, >+ const rtc::VideoSinkWants& wants) override {} >+ void RemoveSink(rtc::VideoSinkInterface<VideoFrame>* sink) override {} > > virtual VideoTrackSourceInterface* GetSource() const = 0; > >- virtual ContentHint content_hint() const { return ContentHint::kNone; } >- virtual void set_content_hint(ContentHint) {} >+ virtual ContentHint content_hint() const; >+ virtual void set_content_hint(ContentHint hint) {} > > protected: >- virtual ~VideoTrackInterface() {} >+ ~VideoTrackInterface() override = default; > }; > > // Interface for receiving audio data from a AudioTrack. >@@ -211,15 +204,15 @@ class AudioSourceInterface : public MediaSourceInterface { > // Sets the volume of the source. |volume| is in the range of [0, 10]. > // TODO(tommi): This method should be on the track and ideally volume should > // be applied in the track in a way that does not affect clones of the track. >- virtual void SetVolume(double) {} >+ virtual void SetVolume(double volume) {} > > // Registers/unregisters observers to the audio source. >- virtual void RegisterAudioObserver(AudioObserver*) {} >- virtual void UnregisterAudioObserver(AudioObserver*) {} >+ virtual void RegisterAudioObserver(AudioObserver* observer) {} >+ virtual void UnregisterAudioObserver(AudioObserver* observer) {} > > // TODO(tommi): Make pure virtual. >- virtual void AddSink(AudioTrackSinkInterface*) {} >- virtual void RemoveSink(AudioTrackSinkInterface*) {} >+ virtual void AddSink(AudioTrackSinkInterface* sink) {} >+ virtual void RemoveSink(AudioTrackSinkInterface* sink) {} > }; > > // Interface of the audio processor used by the audio track to collect >@@ -269,14 +262,14 @@ class AudioProcessorInterface : public rtc::RefCountInterface { > virtual AudioProcessorStatistics GetStats(bool has_remote_tracks); > > protected: >- virtual ~AudioProcessorInterface() {} >+ ~AudioProcessorInterface() override = default; > }; > > class AudioTrackInterface : public MediaStreamTrackInterface { > public: > // TODO(deadbeef): Figure out if the following interface should be const or > // not. >- virtual AudioSourceInterface* GetSource() const = 0; >+ virtual AudioSourceInterface* GetSource() const = 0; > > // Add/Remove a sink that will receive the audio data from the track. > virtual void AddSink(AudioTrackSinkInterface* sink) = 0; >@@ -286,23 +279,19 @@ class AudioTrackInterface : public MediaStreamTrackInterface { > // Return true on success, otherwise false. > // TODO(deadbeef): Change the interface to int GetSignalLevel() and pure > // virtual after it's implemented in chromium. >- virtual bool GetSignalLevel(int*) { return false; } >+ virtual bool GetSignalLevel(int* level); > > // Get the audio processor used by the audio track. Return null if the track > // does not have any processor. > // TODO(deadbeef): Make the interface pure virtual. >- virtual rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor() { >- return nullptr; >- } >+ virtual rtc::scoped_refptr<AudioProcessorInterface> GetAudioProcessor(); > > protected: >- virtual ~AudioTrackInterface() {} >+ ~AudioTrackInterface() override = default; > }; > >-typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> > >- AudioTrackVector; >-typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > >- VideoTrackVector; >+typedef std::vector<rtc::scoped_refptr<AudioTrackInterface> > AudioTrackVector; >+typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > VideoTrackVector; > > // C++ version of https://www.w3.org/TR/mediacapture-streams/#mediastream. > // >@@ -315,15 +304,14 @@ typedef std::vector<rtc::scoped_refptr<VideoTrackInterface> > > class MediaStreamInterface : public rtc::RefCountInterface, > public NotifierInterface { > public: >- // TODO(steveanton): This could be renamed to id() to match the spec. >- virtual std::string label() const = 0; >+ virtual std::string id() const = 0; > > virtual AudioTrackVector GetAudioTracks() = 0; > virtual VideoTrackVector GetVideoTracks() = 0; >- virtual rtc::scoped_refptr<AudioTrackInterface> >- FindAudioTrack(const std::string& track_id) = 0; >- virtual rtc::scoped_refptr<VideoTrackInterface> >- FindVideoTrack(const std::string& track_id) = 0; >+ virtual rtc::scoped_refptr<AudioTrackInterface> FindAudioTrack( >+ const std::string& track_id) = 0; >+ virtual rtc::scoped_refptr<VideoTrackInterface> FindVideoTrack( >+ const std::string& track_id) = 0; > > virtual bool AddTrack(AudioTrackInterface* track) = 0; > virtual bool AddTrack(VideoTrackInterface* track) = 0; >@@ -331,7 +319,7 @@ class MediaStreamInterface : public rtc::RefCountInterface, > virtual bool RemoveTrack(VideoTrackInterface* track) = 0; > > protected: >- virtual ~MediaStreamInterface() {} >+ ~MediaStreamInterface() override = default; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamproxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamproxy.h >index e32d52b16b7..4c544595aa1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamproxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamproxy.h >@@ -21,22 +21,22 @@ namespace webrtc { > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_SIGNALING_PROXY_MAP(MediaStream) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_CONSTMETHOD0(std::string, label) >- PROXY_METHOD0(AudioTrackVector, GetAudioTracks) >- PROXY_METHOD0(VideoTrackVector, GetVideoTracks) >- PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>, >- FindAudioTrack, >- const std::string&) >- PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>, >- FindVideoTrack, >- const std::string&) >- PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*) >- PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*) >- PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*) >- PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*) >- PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >- PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_CONSTMETHOD0(std::string, id) >+PROXY_METHOD0(AudioTrackVector, GetAudioTracks) >+PROXY_METHOD0(VideoTrackVector, GetVideoTracks) >+PROXY_METHOD1(rtc::scoped_refptr<AudioTrackInterface>, >+ FindAudioTrack, >+ const std::string&) >+PROXY_METHOD1(rtc::scoped_refptr<VideoTrackInterface>, >+ FindVideoTrack, >+ const std::string&) >+PROXY_METHOD1(bool, AddTrack, AudioTrackInterface*) >+PROXY_METHOD1(bool, AddTrack, VideoTrackInterface*) >+PROXY_METHOD1(bool, RemoveTrack, AudioTrackInterface*) >+PROXY_METHOD1(bool, RemoveTrack, VideoTrackInterface*) >+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) > END_PROXY_MAP() > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamtrackproxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamtrackproxy.h >index 57a76955998..77b7bad9b4b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamtrackproxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediastreamtrackproxy.h >@@ -25,39 +25,39 @@ namespace webrtc { > // are called on is an implementation detail. > > BEGIN_SIGNALING_PROXY_MAP(AudioTrack) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_CONSTMETHOD0(std::string, kind) >- PROXY_CONSTMETHOD0(std::string, id) >- PROXY_CONSTMETHOD0(TrackState, state) >- PROXY_CONSTMETHOD0(bool, enabled) >- PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource) >- PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*) >- PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*) >- PROXY_METHOD1(bool, GetSignalLevel, int*) >- PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor) >- PROXY_METHOD1(bool, set_enabled, bool) >- PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >- PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_CONSTMETHOD0(std::string, kind) >+PROXY_CONSTMETHOD0(std::string, id) >+PROXY_CONSTMETHOD0(TrackState, state) >+PROXY_CONSTMETHOD0(bool, enabled) >+PROXY_CONSTMETHOD0(AudioSourceInterface*, GetSource) >+PROXY_METHOD1(void, AddSink, AudioTrackSinkInterface*) >+PROXY_METHOD1(void, RemoveSink, AudioTrackSinkInterface*) >+PROXY_METHOD1(bool, GetSignalLevel, int*) >+PROXY_METHOD0(rtc::scoped_refptr<AudioProcessorInterface>, GetAudioProcessor) >+PROXY_METHOD1(bool, set_enabled, bool) >+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) > END_PROXY_MAP() > > BEGIN_PROXY_MAP(VideoTrack) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_CONSTMETHOD0(std::string, kind) >- PROXY_CONSTMETHOD0(std::string, id) >- PROXY_CONSTMETHOD0(TrackState, state) >- PROXY_CONSTMETHOD0(bool, enabled) >- PROXY_METHOD1(bool, set_enabled, bool) >- PROXY_CONSTMETHOD0(ContentHint, content_hint) >- PROXY_METHOD1(void, set_content_hint, ContentHint) >- PROXY_WORKER_METHOD2(void, >- AddOrUpdateSink, >- rtc::VideoSinkInterface<VideoFrame>*, >- const rtc::VideoSinkWants&) >- PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) >- PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_CONSTMETHOD0(std::string, kind) >+PROXY_CONSTMETHOD0(std::string, id) >+PROXY_CONSTMETHOD0(TrackState, state) >+PROXY_CONSTMETHOD0(bool, enabled) >+PROXY_METHOD1(bool, set_enabled, bool) >+PROXY_CONSTMETHOD0(ContentHint, content_hint) >+PROXY_METHOD1(void, set_content_hint, ContentHint) >+PROXY_WORKER_METHOD2(void, >+ AddOrUpdateSink, >+ rtc::VideoSinkInterface<VideoFrame>*, >+ const rtc::VideoSinkWants&) >+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) >+PROXY_CONSTMETHOD0(VideoTrackSourceInterface*, GetSource) > >- PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >- PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) >+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) > END_PROXY_MAP() > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediatypes.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediatypes.h >index 93ce1a231dd..f2812760255 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediatypes.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/mediatypes.h >@@ -13,13 +13,12 @@ > > #include <string> > >+// The cricket and webrtc have separate definitions for what a media type is. >+// They're not compatible. Watch out for this. >+ > namespace cricket { > >-enum MediaType { >- MEDIA_TYPE_AUDIO, >- MEDIA_TYPE_VIDEO, >- MEDIA_TYPE_DATA >-}; >+enum MediaType { MEDIA_TYPE_AUDIO, MEDIA_TYPE_VIDEO, MEDIA_TYPE_DATA }; > > std::string MediaTypeToString(MediaType type); > // Aborts on invalid string. Only expected to be used on strings that are >@@ -28,4 +27,10 @@ MediaType MediaTypeFromString(const std::string& type_str); > > } // namespace cricket > >+namespace webrtc { >+ >+enum class MediaType { ANY, AUDIO, VIDEO, DATA }; >+ >+} // namespace webrtc >+ > #endif // API_MEDIATYPES_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/notifier.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/notifier.h >index ceeda4de557..e5c61c96674 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/notifier.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/notifier.h >@@ -23,8 +23,7 @@ namespace webrtc { > template <class T> > class Notifier : public T { > public: >- Notifier() { >- } >+ Notifier() {} > > virtual void RegisterObserver(ObserverInterface* observer) { > RTC_DCHECK(observer != nullptr); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.cc >deleted file mode 100644 >index 94126170a5a..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.cc >+++ /dev/null >@@ -1,34 +0,0 @@ >-/* >- * Copyright 2016 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 "api/optional.h" >- >-namespace rtc { >-namespace optional_internal { >- >-#if RTC_HAS_ASAN >- >-void* FunctionThatDoesNothingImpl(void* x) { >- return x; >-} >- >-#endif >- >-struct NulloptArg { >- constexpr NulloptArg() {} >-}; >- >-static NulloptArg nullopt_arg; >- >-} // namespace optional_internal >- >-const nullopt_t nullopt(rtc::optional_internal::nullopt_arg); >- >-} // namespace rtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.h >deleted file mode 100644 >index 7a623357337..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional.h >+++ /dev/null >@@ -1,449 +0,0 @@ >-/* >- * Copyright 2015 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. >- */ >- >-#ifndef API_OPTIONAL_H_ >-#define API_OPTIONAL_H_ >- >-#include <algorithm> >-#include <memory> >-#include <utility> >- >-#ifdef UNIT_TEST >-#include <iomanip> >-#include <ostream> >-#endif // UNIT_TEST >- >-#include "api/array_view.h" >-#include "rtc_base/checks.h" >-#include "rtc_base/sanitizer.h" >- >-namespace rtc { >- >-namespace optional_internal { >- >-#if RTC_HAS_ASAN >- >-// This is a non-inlined function. The optimizer can't see inside it. It >-// prevents the compiler from generating optimized code that reads value_ even >-// if it is unset. Although safe, this causes memory sanitizers to complain. >-void* FunctionThatDoesNothingImpl(void*); >- >-template <typename T> >-inline T* FunctionThatDoesNothing(T* x) { >- return reinterpret_cast<T*>( >- FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x))); >-} >- >-#else >- >-template <typename T> >-inline T* FunctionThatDoesNothing(T* x) { >- return x; >-} >- >-#endif >- >-struct NulloptArg; >- >-} // namespace optional_internal >- >-// nullopt_t must be a non-aggregate literal type with a constexpr constructor >-// that takes some implementation-defined literal type. It mustn't have a >-// default constructor nor an initializer-list constructor. >-// See: >-// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t >-// That page uses int, though this seems to confuse older versions of GCC. >-struct nullopt_t { >- constexpr explicit nullopt_t(rtc::optional_internal::NulloptArg&) {} >-}; >- >-// Specification: >-// http://en.cppreference.com/w/cpp/utility/optional/nullopt >-extern const nullopt_t nullopt; >- >-// Simple std::optional-wannabe. It either contains a T or not. >-// >-// A moved-from Optional<T> may only be destroyed, and assigned to if T allows >-// being assigned to after having been moved from. Specifically, you may not >-// assume that it just doesn't contain a value anymore. >-// >-// Examples of good places to use Optional: >-// >-// - As a class or struct member, when the member doesn't always have a value: >-// struct Prisoner { >-// std::string name; >-// Optional<int> cell_number; // Empty if not currently incarcerated. >-// }; >-// >-// - As a return value for functions that may fail to return a value on all >-// allowed inputs. For example, a function that searches an array might >-// return an Optional<size_t> (the index where it found the element, or >-// nothing if it didn't find it); and a function that parses numbers might >-// return Optional<double> (the parsed number, or nothing if parsing failed). >-// >-// Examples of bad places to use Optional: >-// >-// - As a return value for functions that may fail because of disallowed >-// inputs. For example, a string length function should not return >-// Optional<size_t> so that it can return nothing in case the caller passed >-// it a null pointer; the function should probably use RTC_[D]CHECK instead, >-// and return plain size_t. >-// >-// - As a return value for functions that may fail to return a value on all >-// allowed inputs, but need to tell the caller what went wrong. Returning >-// Optional<double> when parsing a single number as in the example above >-// might make sense, but any larger parse job is probably going to need to >-// tell the caller what the problem was, not just that there was one. >-// >-// - As a non-mutable function argument. When you want to pass a value of a >-// type T that can fail to be there, const T* is almost always both fastest >-// and cleanest. (If you're *sure* that the the caller will always already >-// have an Optional<T>, const Optional<T>& is slightly faster than const T*, >-// but this is a micro-optimization. In general, stick to const T*.) >-// >-// TODO(kwiberg): Get rid of this class when the standard library has >-// std::optional (and we're allowed to use it). >-template <typename T> >-class Optional final { >- public: >- // Construct an empty Optional. >- Optional() : has_value_(false), empty_('\0') { PoisonValue(); } >- >- Optional(rtc::nullopt_t) // NOLINT(runtime/explicit) >- : Optional() {} >- >- // Construct an Optional that contains a value. >- Optional(const T& value) // NOLINT(runtime/explicit) >- : has_value_(true) { >- new (&value_) T(value); >- } >- Optional(T&& value) // NOLINT(runtime/explicit) >- : has_value_(true) { >- new (&value_) T(std::move(value)); >- } >- >- // Copy constructor: copies the value from m if it has one. >- Optional(const Optional& m) : has_value_(m.has_value_) { >- if (has_value_) >- new (&value_) T(m.value_); >- else >- PoisonValue(); >- } >- >- // Move constructor: if m has a value, moves the value from m, leaving m >- // still in a state where it has a value, but a moved-from one (the >- // properties of which depends on T; the only general guarantee is that we >- // can destroy m). >- Optional(Optional&& m) : has_value_(m.has_value_) { >- if (has_value_) >- new (&value_) T(std::move(m.value_)); >- else >- PoisonValue(); >- } >- >- ~Optional() { >- if (has_value_) >- value_.~T(); >- else >- UnpoisonValue(); >- } >- >- Optional& operator=(rtc::nullopt_t) { >- reset(); >- return *this; >- } >- >- // Copy assignment. Uses T's copy assignment if both sides have a value, T's >- // copy constructor if only the right-hand side has a value. >- Optional& operator=(const Optional& m) { >- if (m.has_value_) { >- if (has_value_) { >- value_ = m.value_; // T's copy assignment. >- } else { >- UnpoisonValue(); >- new (&value_) T(m.value_); // T's copy constructor. >- has_value_ = true; >- } >- } else { >- reset(); >- } >- return *this; >- } >- >- // Move assignment. Uses T's move assignment if both sides have a value, T's >- // move constructor if only the right-hand side has a value. The state of m >- // after it's been moved from is as for the move constructor. >- Optional& operator=(Optional&& m) { >- if (m.has_value_) { >- if (has_value_) { >- value_ = std::move(m.value_); // T's move assignment. >- } else { >- UnpoisonValue(); >- new (&value_) T(std::move(m.value_)); // T's move constructor. >- has_value_ = true; >- } >- } else { >- reset(); >- } >- return *this; >- } >- >- // Swap the values if both m1 and m2 have values; move the value if only one >- // of them has one. >- friend void swap(Optional& m1, Optional& m2) { >- if (m1.has_value_) { >- if (m2.has_value_) { >- // Both have values: swap. >- using std::swap; >- swap(m1.value_, m2.value_); >- } else { >- // Only m1 has a value: move it to m2. >- m2.UnpoisonValue(); >- new (&m2.value_) T(std::move(m1.value_)); >- m1.value_.~T(); // Destroy the moved-from value. >- m1.has_value_ = false; >- m2.has_value_ = true; >- m1.PoisonValue(); >- } >- } else if (m2.has_value_) { >- // Only m2 has a value: move it to m1. >- m1.UnpoisonValue(); >- new (&m1.value_) T(std::move(m2.value_)); >- m2.value_.~T(); // Destroy the moved-from value. >- m1.has_value_ = true; >- m2.has_value_ = false; >- m2.PoisonValue(); >- } >- } >- >- // Destroy any contained value. Has no effect if we have no value. >- void reset() { >- if (!has_value_) >- return; >- value_.~T(); >- has_value_ = false; >- PoisonValue(); >- } >- >- template <class... Args> >- void emplace(Args&&... args) { >- if (has_value_) >- value_.~T(); >- else >- UnpoisonValue(); >- new (&value_) T(std::forward<Args>(args)...); >- has_value_ = true; >- } >- >- // Conversion to bool to test if we have a value. >- explicit operator bool() const { return has_value_; } >- bool has_value() const { return has_value_; } >- >- // Dereferencing. Only allowed if we have a value. >- const T* operator->() const { >- RTC_DCHECK(has_value_); >- return &value_; >- } >- T* operator->() { >- RTC_DCHECK(has_value_); >- return &value_; >- } >- const T& operator*() const { >- RTC_DCHECK(has_value_); >- return value_; >- } >- T& operator*() { >- RTC_DCHECK(has_value_); >- return value_; >- } >- const T& value() const { >- RTC_DCHECK(has_value_); >- return value_; >- } >- T& value() { >- RTC_DCHECK(has_value_); >- return value_; >- } >- >- // Dereference with a default value in case we don't have a value. >- const T& value_or(const T& default_val) const { >- // The no-op call prevents the compiler from generating optimized code that >- // reads value_ even if !has_value_, but only if FunctionThatDoesNothing is >- // not completely inlined; see its declaration.). >- return has_value_ ? *optional_internal::FunctionThatDoesNothing(&value_) >- : default_val; >- } >- >- // Dereference and move value. >- T MoveValue() { >- RTC_DCHECK(has_value_); >- return std::move(value_); >- } >- >- // Equality tests. Two Optionals are equal if they contain equivalent values, >- // or if they're both empty. >- friend bool operator==(const Optional& m1, const Optional& m2) { >- return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ >- : m1.has_value_ == m2.has_value_; >- } >- friend bool operator==(const Optional& opt, const T& value) { >- return opt.has_value_ && opt.value_ == value; >- } >- friend bool operator==(const T& value, const Optional& opt) { >- return opt.has_value_ && value == opt.value_; >- } >- >- friend bool operator==(const Optional& opt, rtc::nullopt_t) { >- return !opt.has_value_; >- } >- >- friend bool operator==(rtc::nullopt_t, const Optional& opt) { >- return !opt.has_value_; >- } >- >- friend bool operator!=(const Optional& m1, const Optional& m2) { >- return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ >- : m1.has_value_ != m2.has_value_; >- } >- friend bool operator!=(const Optional& opt, const T& value) { >- return !opt.has_value_ || opt.value_ != value; >- } >- friend bool operator!=(const T& value, const Optional& opt) { >- return !opt.has_value_ || value != opt.value_; >- } >- >- friend bool operator!=(const Optional& opt, rtc::nullopt_t) { >- return opt.has_value_; >- } >- >- friend bool operator!=(rtc::nullopt_t, const Optional& opt) { >- return opt.has_value_; >- } >- >- private: >- // Tell sanitizers that value_ shouldn't be touched. >- void PoisonValue() { >- rtc::AsanPoison(rtc::MakeArrayView(&value_, 1)); >- rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1)); >- } >- >- // Tell sanitizers that value_ is OK to touch again. >- void UnpoisonValue() { rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1)); } >- >- bool has_value_; // True iff value_ contains a live value. >- union { >- // empty_ exists only to make it possible to initialize the union, even when >- // it doesn't contain any data. If the union goes uninitialized, it may >- // trigger compiler warnings. >- char empty_; >- // By placing value_ in a union, we get to manage its construction and >- // destruction manually: the Optional constructors won't automatically >- // construct it, and the Optional destructor won't automatically destroy >- // it. Basically, this just allocates a properly sized and aligned block of >- // memory in which we can manually put a T with placement new. >- T value_; >- }; >-}; >- >-#ifdef UNIT_TEST >-namespace optional_internal { >- >-// Checks if there's a valid PrintTo(const T&, std::ostream*) call for T. >-template <typename T> >-struct HasPrintTo { >- private: >- struct No {}; >- >- template <typename T2> >- static auto Test(const T2& obj) >- -> decltype(PrintTo(obj, std::declval<std::ostream*>())); >- >- template <typename> >- static No Test(...); >- >- public: >- static constexpr bool value = >- !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value; >-}; >- >-// Checks if there's a valid operator<<(std::ostream&, const T&) call for T. >-template <typename T> >-struct HasOstreamOperator { >- private: >- struct No {}; >- >- template <typename T2> >- static auto Test(const T2& obj) >- -> decltype(std::declval<std::ostream&>() << obj); >- >- template <typename> >- static No Test(...); >- >- public: >- static constexpr bool value = >- !std::is_same<decltype(Test<T>(std::declval<const T&>())), No>::value; >-}; >- >-// Prefer using PrintTo to print the object. >-template <typename T> >-typename std::enable_if<HasPrintTo<T>::value, void>::type OptionalPrintToHelper( >- const T& value, >- std::ostream* os) { >- PrintTo(value, os); >-} >- >-// Fall back to operator<<(std::ostream&, ...) if it exists. >-template <typename T> >-typename std::enable_if<HasOstreamOperator<T>::value && !HasPrintTo<T>::value, >- void>::type >-OptionalPrintToHelper(const T& value, std::ostream* os) { >- *os << value; >-} >- >-inline void OptionalPrintObjectBytes(const unsigned char* bytes, >- size_t size, >- std::ostream* os) { >- *os << "<optional with " << size << "-byte object ["; >- for (size_t i = 0; i != size; ++i) { >- *os << (i == 0 ? "" : ((i & 1) ? "-" : " ")); >- *os << std::hex << std::setw(2) << std::setfill('0') >- << static_cast<int>(bytes[i]); >- } >- *os << "]>"; >-} >- >-// As a final back-up, just print the contents of the objcets byte-wise. >-template <typename T> >-typename std::enable_if<!HasOstreamOperator<T>::value && !HasPrintTo<T>::value, >- void>::type >-OptionalPrintToHelper(const T& value, std::ostream* os) { >- OptionalPrintObjectBytes(reinterpret_cast<const unsigned char*>(&value), >- sizeof(value), os); >-} >- >-} // namespace optional_internal >- >-// PrintTo is used by gtest to print out the results of tests. We want to ensure >-// the object contained in an Optional can be printed out if it's set, while >-// avoiding touching the object's storage if it is undefined. >-template <typename T> >-void PrintTo(const rtc::Optional<T>& opt, std::ostream* os) { >- if (opt) { >- optional_internal::OptionalPrintToHelper(*opt, os); >- } else { >- *os << "<empty optional>"; >- } >-} >- >-#endif // UNIT_TEST >- >-} // namespace rtc >- >-#endif // API_OPTIONAL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional_unittest.cc >deleted file mode 100644 >index 2149033f404..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/optional_unittest.cc >+++ /dev/null >@@ -1,902 +0,0 @@ >-/* >- * Copyright 2015 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 <memory> >-#include <sstream> >-#include <string> >-#include <utility> >-#include <vector> >- >-#include "api/optional.h" >-#include "rtc_base/gunit.h" >- >-namespace rtc { >- >-namespace { >- >-struct MyUnprintableType { >- int value; >-}; >- >-struct MyPrintableType { >- int value; >-}; >- >-struct MyOstreamPrintableType { >- int value; >-}; >- >-void PrintTo(const MyPrintableType& mpt, std::ostream* os) { >- *os << "The value is " << mpt.value; >-} >- >-std::ostream& operator<<(std::ostream& os, const MyPrintableType& mpt) { >- os << mpt.value; >- return os; >-} >- >-std::ostream& operator<<(std::ostream& os, const MyOstreamPrintableType& mpt) { >- os << mpt.value; >- return os; >-} >- >-// Class whose instances logs various method calls (constructor, destructor, >-// etc.). Each instance has a unique ID (a simple global sequence number) and >-// an origin ID. When a copy is made, the new object gets a fresh ID but copies >-// the origin ID from the original. When a new Logger is created from scratch, >-// it gets a fresh ID, and the origin ID is the same as the ID (default >-// constructor) or given as an argument (explicit constructor). >-class Logger { >- public: >- Logger() : id_(g_next_id++), origin_(id_) { Log("default constructor"); } >- explicit Logger(int origin) : id_(g_next_id++), origin_(origin) { >- Log("explicit constructor"); >- } >- Logger(int origin, const Logger& pass_by_ref, Logger pass_by_value) >- : id_(g_next_id++), origin_(origin) { >- Log("multi parameter constructor"); >- } >- Logger(const Logger& other) : id_(g_next_id++), origin_(other.origin_) { >- LogFrom("copy constructor", other); >- } >- Logger(Logger&& other) : id_(g_next_id++), origin_(other.origin_) { >- LogFrom("move constructor", other); >- } >- ~Logger() { Log("destructor"); } >- Logger& operator=(const Logger& other) { >- origin_ = other.origin_; >- LogFrom("operator= copy", other); >- return *this; >- } >- Logger& operator=(Logger&& other) { >- origin_ = other.origin_; >- LogFrom("operator= move", other); >- return *this; >- } >- friend void swap(Logger& a, Logger& b) { >- using std::swap; >- swap(a.origin_, b.origin_); >- Log2("swap", a, b); >- } >- friend bool operator==(const Logger& a, const Logger& b) { >- Log2("operator==", a, b); >- return a.origin_ == b.origin_; >- } >- friend bool operator!=(const Logger& a, const Logger& b) { >- Log2("operator!=", a, b); >- return a.origin_ != b.origin_; >- } >- void Foo() { Log("Foo()"); } >- void Foo() const { Log("Foo() const"); } >- static std::unique_ptr<std::vector<std::string>> Setup() { >- std::unique_ptr<std::vector<std::string>> s(new std::vector<std::string>); >- g_log = s.get(); >- g_next_id = 0; >- return s; >- } >- >- private: >- int id_; >- int origin_; >- static std::vector<std::string>* g_log; >- static int g_next_id; >- void Log(const char* msg) const { >- std::ostringstream oss; >- oss << id_ << ':' << origin_ << ". " << msg; >- g_log->push_back(oss.str()); >- } >- void LogFrom(const char* msg, const Logger& other) const { >- std::ostringstream oss; >- oss << id_ << ':' << origin_ << ". " << msg << " (from " << other.id_ << ':' >- << other.origin_ << ")"; >- g_log->push_back(oss.str()); >- } >- static void Log2(const char* msg, const Logger& a, const Logger& b) { >- std::ostringstream oss; >- oss << msg << ' ' << a.id_ << ':' << a.origin_ << ", " << b.id_ << ':' >- << b.origin_; >- g_log->push_back(oss.str()); >- } >-}; >- >-std::vector<std::string>* Logger::g_log = nullptr; >-int Logger::g_next_id = 0; >- >-// Append all the other args to the vector pointed to by the first arg. >-template <typename T> >-void VectorAppend(std::vector<T>* v) {} >-template <typename T, typename... Ts> >-void VectorAppend(std::vector<T>* v, const T& e, Ts... es) { >- v->push_back(e); >- VectorAppend(v, es...); >-} >- >-// Create a vector of strings. Because we're not allowed to use >-// std::initializer_list. >-template <typename... Ts> >-std::vector<std::string> V(Ts... es) { >- std::vector<std::string> strings; >- VectorAppend(&strings, static_cast<std::string>(es)...); >- return strings; >-} >- >-} // namespace >- >-TEST(OptionalTest, TestConstructDefault) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- EXPECT_FALSE(x); >- EXPECT_FALSE(x.has_value()); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestConstructNullopt) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(nullopt); >- EXPECT_FALSE(x); >- EXPECT_FALSE(x.has_value()); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestConstructCopyEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- EXPECT_FALSE(x); >- EXPECT_FALSE(x.has_value()); >- auto y = x; >- EXPECT_FALSE(y); >- EXPECT_FALSE(y.has_value()); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestConstructCopyFull) { >- auto log = Logger::Setup(); >- { >- Logger a; >- Optional<Logger> x(a); >- EXPECT_TRUE(x); >- EXPECT_TRUE(x.has_value()); >- log->push_back("---"); >- auto y = x; >- EXPECT_TRUE(y); >- EXPECT_TRUE(y.has_value()); >- log->push_back("---"); >- } >- EXPECT_EQ(V("0:0. default constructor", "1:0. copy constructor (from 0:0)", >- "---", "2:0. copy constructor (from 1:0)", "---", >- "2:0. destructor", "1:0. destructor", "0:0. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestConstructMoveEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- EXPECT_FALSE(x); >- EXPECT_FALSE(x.has_value()); >- auto y = std::move(x); >- EXPECT_FALSE(y); >- EXPECT_FALSE(y.has_value()); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestConstructMoveFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- EXPECT_TRUE(x); >- EXPECT_TRUE(x.has_value()); >- log->push_back("---"); >- auto y = std::move(x); >- EXPECT_TRUE(x); >- EXPECT_TRUE(x.has_value()); >- EXPECT_TRUE(y); >- EXPECT_TRUE(y.has_value()); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "2:17. move constructor (from 1:17)", "---", >- "2:17. destructor", "1:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToEmptyFromEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x, y; >- x = y; >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToFullFromEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Optional<Logger> y; >- log->push_back("---"); >- x = y; >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "1:17. destructor", "---"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToFullFromNullopt) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- log->push_back("---"); >- x = nullopt; >- log->push_back("---"); >- EXPECT_FALSE(x); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "1:17. destructor", "---"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToFullFromEmptyBraces) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- log->push_back("---"); >- x = {}; >- log->push_back("---"); >- EXPECT_FALSE(x); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "1:17. destructor", "---"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToEmptyFromFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Optional<Logger> y(Logger(17)); >- log->push_back("---"); >- x = y; >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "2:17. copy constructor (from 1:17)", "---", >- "1:17. destructor", "2:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToFullFromFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Optional<Logger> y(Logger(42)); >- log->push_back("---"); >- x = y; >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "2:42. explicit constructor", >- "3:42. move constructor (from 2:42)", "2:42. destructor", "---", >- "1:42. operator= copy (from 3:42)", "---", "3:42. destructor", >- "1:42. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToEmptyFromT) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Logger y(17); >- log->push_back("---"); >- x = Optional<Logger>(y); >- log->push_back("---"); >- } >- EXPECT_EQ(V("0:17. explicit constructor", "---", >- "1:17. copy constructor (from 0:17)", >- "2:17. move constructor (from 1:17)", "1:17. destructor", "---", >- "0:17. destructor", "2:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestCopyAssignToFullFromT) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Logger y(42); >- log->push_back("---"); >- x = Optional<Logger>(y); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "2:42. explicit constructor", "---", >- "3:42. copy constructor (from 2:42)", >- "1:42. operator= move (from 3:42)", "3:42. destructor", "---", >- "2:42. destructor", "1:42. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToEmptyFromEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x, y; >- x = std::move(y); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToFullFromEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Optional<Logger> y; >- log->push_back("---"); >- x = std::move(y); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "1:17. destructor", "---"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToEmptyFromFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Optional<Logger> y(Logger(17)); >- log->push_back("---"); >- x = std::move(y); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "2:17. move constructor (from 1:17)", "---", >- "1:17. destructor", "2:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToFullFromFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Optional<Logger> y(Logger(42)); >- log->push_back("---"); >- x = std::move(y); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "2:42. explicit constructor", >- "3:42. move constructor (from 2:42)", "2:42. destructor", "---", >- "1:42. operator= move (from 3:42)", "---", "3:42. destructor", >- "1:42. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToEmptyFromT) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Logger y(17); >- log->push_back("---"); >- x = Optional<Logger>(std::move(y)); >- log->push_back("---"); >- } >- EXPECT_EQ(V("0:17. explicit constructor", "---", >- "1:17. move constructor (from 0:17)", >- "2:17. move constructor (from 1:17)", "1:17. destructor", "---", >- "0:17. destructor", "2:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveAssignToFullFromT) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Logger y(42); >- log->push_back("---"); >- x = Optional<Logger>(std::move(y)); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "2:42. explicit constructor", "---", >- "3:42. move constructor (from 2:42)", >- "1:42. operator= move (from 3:42)", "3:42. destructor", "---", >- "2:42. destructor", "1:42. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestResetEmpty) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- x.reset(); >- } >- EXPECT_EQ(V(), *log); >-} >- >-TEST(OptionalTest, TestResetFull) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- log->push_back("---"); >- x.reset(); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:17. move constructor (from 0:17)", >- "0:17. destructor", "---", "1:17. destructor", "---"), >- *log); >-} >- >-TEST(OptionalTest, TestEmplaceEmptyWithExplicit) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- log->push_back("---"); >- x.emplace(42); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("---", >- "0:42. explicit constructor", >- "---", >- "0:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceEmptyWithMultipleParameters) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Logger ref(21); >- Logger value(35); >- log->push_back("---"); >- x.emplace(42, ref, std::move(value)); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:21. explicit constructor", >- "1:35. explicit constructor", >- "---", >- "2:35. move constructor (from 1:35)", >- "3:42. multi parameter constructor", >- "2:35. destructor", >- "---", >- "1:35. destructor", >- "0:21. destructor", >- "3:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceEmptyWithCopy) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Logger y(42); >- log->push_back("---"); >- x.emplace(y); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:42. explicit constructor", >- "---", >- "1:42. copy constructor (from 0:42)", >- "---", >- "0:42. destructor", >- "1:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceEmptyWithMove) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x; >- Logger y(42); >- log->push_back("---"); >- x.emplace(std::move(y)); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:42. explicit constructor", >- "---", >- "1:42. move constructor (from 0:42)", >- "---", >- "0:42. destructor", >- "1:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceFullWithExplicit) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- log->push_back("---"); >- x.emplace(42); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ( >- V("0:17. explicit constructor", >- "1:17. move constructor (from 0:17)", >- "0:17. destructor", >- "---", >- "1:17. destructor", >- "2:42. explicit constructor", >- "---", >- "2:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceFullWithMultipleParameters) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Logger ref(21); >- Logger value(35); >- log->push_back("---"); >- x.emplace(42, ref, std::move(value)); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:17. explicit constructor", >- "1:17. move constructor (from 0:17)", >- "0:17. destructor", >- "2:21. explicit constructor", >- "3:35. explicit constructor", >- "---", >- "1:17. destructor", >- "4:35. move constructor (from 3:35)", >- "5:42. multi parameter constructor", >- "4:35. destructor", >- "---", >- "3:35. destructor", >- "2:21. destructor", >- "5:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceFullWithCopy) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Logger y(42); >- log->push_back("---"); >- x.emplace(y); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:17. explicit constructor", >- "1:17. move constructor (from 0:17)", >- "0:17. destructor", >- "2:42. explicit constructor", >- "---", >- "1:17. destructor", >- "3:42. copy constructor (from 2:42)", >- "---", >- "2:42. destructor", >- "3:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEmplaceFullWithMove) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(17)); >- Logger y(42); >- log->push_back("---"); >- x.emplace(std::move(y)); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:17. explicit constructor", >- "1:17. move constructor (from 0:17)", >- "0:17. destructor", >- "2:42. explicit constructor", >- "---", >- "1:17. destructor", >- "3:42. move constructor (from 2:42)", >- "---", >- "2:42. destructor", >- "3:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestDereference) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(42)); >- const auto& y = x; >- log->push_back("---"); >- x->Foo(); >- y->Foo(); >- std::move(x)->Foo(); >- std::move(y)->Foo(); >- log->push_back("---"); >- (*x).Foo(); >- (*y).Foo(); >- (*std::move(x)).Foo(); >- (*std::move(y)).Foo(); >- log->push_back("---"); >- x.value().Foo(); >- y.value().Foo(); >- std::move(x).value().Foo(); >- std::move(y).value().Foo(); >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:42. explicit constructor", >- "1:42. move constructor (from 0:42)", >- "0:42. destructor", >- "---", >- "1:42. Foo()", >- "1:42. Foo() const", >- "1:42. Foo()", >- "1:42. Foo() const", >- "---", >- "1:42. Foo()", >- "1:42. Foo() const", >- "1:42. Foo()", >- "1:42. Foo() const", >- "---", >- "1:42. Foo()", >- "1:42. Foo() const", >- "1:42. Foo()", >- "1:42. Foo() const", >- "---", >- "1:42. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestDereferenceWithDefault) { >- auto log = Logger::Setup(); >- { >- const Logger a(17), b(42); >- Optional<Logger> x(a); >- Optional<Logger> y; >- log->push_back("-1-"); >- EXPECT_EQ(a, x.value_or(Logger(42))); >- log->push_back("-2-"); >- EXPECT_EQ(b, y.value_or(Logger(42))); >- log->push_back("-3-"); >- EXPECT_EQ(a, Optional<Logger>(Logger(17)).value_or(b)); >- log->push_back("-4-"); >- EXPECT_EQ(b, Optional<Logger>().value_or(b)); >- log->push_back("-5-"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:42. explicit constructor", >- "2:17. copy constructor (from 0:17)", "-1-", >- "3:42. explicit constructor", "operator== 0:17, 2:17", >- "3:42. destructor", "-2-", "4:42. explicit constructor", >- "operator== 1:42, 4:42", "4:42. destructor", "-3-", >- "5:17. explicit constructor", "6:17. move constructor (from 5:17)", >- "operator== 0:17, 6:17", "6:17. destructor", "5:17. destructor", "-4-", >- "operator== 1:42, 1:42", "-5-", "2:17. destructor", "1:42. destructor", >- "0:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestEquality) { >- auto log = Logger::Setup(); >- { >- Logger a(17), b(42); >- Optional<Logger> ma1(a), ma2(a), mb(b), me1, me2; >- log->push_back("---"); >- EXPECT_EQ(ma1, ma1); >- EXPECT_EQ(ma1, ma2); >- EXPECT_NE(ma1, mb); >- EXPECT_NE(ma1, me1); >- EXPECT_EQ(me1, me1); >- EXPECT_EQ(me1, me2); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:17. explicit constructor", "1:42. explicit constructor", >- "2:17. copy constructor (from 0:17)", >- "3:17. copy constructor (from 0:17)", >- "4:42. copy constructor (from 1:42)", "---", "operator== 2:17, 2:17", >- "operator== 2:17, 3:17", "operator!= 2:17, 4:42", "---", >- "4:42. destructor", "3:17. destructor", "2:17. destructor", >- "1:42. destructor", "0:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestEqualityWithNullopt) { >- auto log = Logger::Setup(); >- { >- Logger a(17); >- Optional<Logger> ma(a), me; >- // Using operator== and operator!= explicitly instead of EXPECT_EQ/EXPECT_NE >- // macros because those operators are under test. >- log->push_back("---"); >- >- EXPECT_FALSE(ma == nullopt); >- EXPECT_FALSE(nullopt == ma); >- EXPECT_TRUE(me == nullopt); >- EXPECT_TRUE(nullopt == me); >- >- EXPECT_TRUE(ma != nullopt); >- EXPECT_TRUE(nullopt != ma); >- EXPECT_FALSE(me != nullopt); >- EXPECT_FALSE(nullopt != me); >- >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:17. explicit constructor", >- "1:17. copy constructor (from 0:17)", >- "---", >- // No operators should be called when comparing to empty. >- "---", >- "1:17. destructor", >- "0:17. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestEqualityWithObject) { >- auto log = Logger::Setup(); >- { >- Logger a(17), b(42); >- Optional<Logger> ma(a), me; >- // Using operator== and operator!= explicitly instead of EXPECT_EQ/EXPECT_NE >- // macros because those operators are under test. >- log->push_back("---"); >- >- EXPECT_TRUE(ma == a); >- EXPECT_TRUE(a == ma); >- EXPECT_FALSE(ma == b); >- EXPECT_FALSE(b == ma); >- EXPECT_FALSE(me == a); >- EXPECT_FALSE(a == me); >- >- EXPECT_FALSE(ma != a); >- EXPECT_FALSE(a != ma); >- EXPECT_TRUE(ma != b); >- EXPECT_TRUE(b != ma); >- EXPECT_TRUE(me != a); >- EXPECT_TRUE(a != me); >- >- log->push_back("---"); >- } >- // clang-format off >- EXPECT_EQ(V("0:17. explicit constructor", >- "1:42. explicit constructor", >- "2:17. copy constructor (from 0:17)", >- "---", >- "operator== 2:17, 0:17", >- "operator== 0:17, 2:17", >- "operator== 2:17, 1:42", >- "operator== 1:42, 2:17", >- // No operator should be called when comparing to empty. >- "operator!= 2:17, 0:17", >- "operator!= 0:17, 2:17", >- "operator!= 2:17, 1:42", >- "operator!= 1:42, 2:17", >- // No operator should be called when comparing to empty. >- "---", >- "2:17. destructor", >- "1:42. destructor", >- "0:17. destructor"), >- *log); >- // clang-format on >-} >- >-TEST(OptionalTest, TestSwap) { >- auto log = Logger::Setup(); >- { >- Logger a(17), b(42); >- Optional<Logger> x1(a), x2(b), y1(a), y2, z1, z2; >- log->push_back("---"); >- swap(x1, x2); // Swap full <-> full. >- swap(y1, y2); // Swap full <-> empty. >- swap(z1, z2); // Swap empty <-> empty. >- log->push_back("---"); >- } >- EXPECT_EQ(V("0:17. explicit constructor", "1:42. explicit constructor", >- "2:17. copy constructor (from 0:17)", >- "3:42. copy constructor (from 1:42)", >- "4:17. copy constructor (from 0:17)", "---", "swap 2:42, 3:17", >- "5:17. move constructor (from 4:17)", "4:17. destructor", "---", >- "5:17. destructor", "3:17. destructor", "2:42. destructor", >- "1:42. destructor", "0:17. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestMoveValue) { >- auto log = Logger::Setup(); >- { >- Optional<Logger> x(Logger(42)); >- log->push_back("---"); >- Logger moved = x.MoveValue(); >- log->push_back("---"); >- } >- EXPECT_EQ( >- V("0:42. explicit constructor", "1:42. move constructor (from 0:42)", >- "0:42. destructor", "---", "2:42. move constructor (from 1:42)", "---", >- "2:42. destructor", "1:42. destructor"), >- *log); >-} >- >-TEST(OptionalTest, TestPrintTo) { >- constexpr char kEmptyOptionalMessage[] = "<empty optional>"; >- const Optional<MyUnprintableType> empty_unprintable; >- const Optional<MyPrintableType> empty_printable; >- const Optional<MyOstreamPrintableType> empty_ostream_printable; >- EXPECT_EQ(kEmptyOptionalMessage, ::testing::PrintToString(empty_unprintable)); >- EXPECT_EQ(kEmptyOptionalMessage, ::testing::PrintToString(empty_printable)); >- EXPECT_EQ(kEmptyOptionalMessage, >- ::testing::PrintToString(empty_ostream_printable)); >- EXPECT_NE("1", ::testing::PrintToString(Optional<MyUnprintableType>({1}))); >- EXPECT_NE("1", ::testing::PrintToString(Optional<MyPrintableType>({1}))); >- EXPECT_EQ("The value is 1", >- ::testing::PrintToString(Optional<MyPrintableType>({1}))); >- EXPECT_EQ("1", >- ::testing::PrintToString(Optional<MyOstreamPrintableType>({1}))); >-} >- >-void UnusedFunctionWorkaround() { >- // These are here to ensure we don't get warnings about ostream and PrintTo >- // for MyPrintableType never getting called. >- const MyPrintableType dont_warn{17}; >- const MyOstreamPrintableType dont_warn2{18}; >- std::stringstream sstr; >- sstr << dont_warn; >- PrintTo(dont_warn, &sstr); >- sstr << dont_warn2; >-} >- >-} // namespace rtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/mediadescription.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/mediadescription.h >index 1a6d0e9037c..5cf1d1a67be 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/mediadescription.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/mediadescription.h >@@ -15,8 +15,8 @@ > #include <utility> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/cryptoparams.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -31,7 +31,7 @@ class MediaDescription { > // The mid(media stream identification) is used for identifying media streams > // within a session description. > // https://tools.ietf.org/html/rfc5888#section-6 >- rtc::Optional<std::string> mid() const { return mid_; } >+ absl::optional<std::string> mid() const { return mid_; } > void set_mid(std::string mid) { mid_.emplace(std::move(mid)); } > > // Security keys and parameters for this media stream. Can be used to >@@ -43,7 +43,7 @@ class MediaDescription { > } > > private: >- rtc::Optional<std::string> mid_; >+ absl::optional<std::string> mid_; > > std::vector<cricket::CryptoParams> sdes_params_; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/ortcfactoryinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/ortcfactoryinterface.h >index d99fcd44651..ea25c8a3cbc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/ortcfactoryinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/ortcfactoryinterface.h >@@ -215,20 +215,6 @@ class OrtcFactoryInterface { > return CreateAudioSource(cricket::AudioOptions()); > } > >- // Creates a video source object wrapping and taking ownership of |capturer|. >- // >- // |constraints| can be used for selection of resolution and frame rate, and >- // may be null if no constraints are desired. >- virtual rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( >- std::unique_ptr<cricket::VideoCapturer> capturer, >- const MediaConstraintsInterface* constraints) = 0; >- >- // Version of the above method that omits |constraints|. >- rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( >- std::unique_ptr<cricket::VideoCapturer> capturer) { >- return CreateVideoSource(std::move(capturer), nullptr); >- } >- > // Creates a new local video track wrapping |source|. The same |source| can > // be used in several tracks. > virtual rtc::scoped_refptr<VideoTrackInterface> CreateVideoTrack( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/packettransportinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/packettransportinterface.h >index 9d53ad311bf..f357f8af63a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/packettransportinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/packettransportinterface.h >@@ -31,6 +31,7 @@ class PacketTransportInterface { > > // Classes that can use this internal interface. > friend class RtpTransportControllerAdapter; >+ friend class RtpTransportAdapter; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/rtptransportinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/rtptransportinterface.h >index 716a297c54e..b0d30e8560e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/rtptransportinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/rtptransportinterface.h >@@ -13,46 +13,17 @@ > > #include <string> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "api/ortc/packettransportinterface.h" > #include "api/rtcerror.h" > #include "api/rtp_headers.h" >+#include "api/rtpparameters.h" > #include "common_types.h" // NOLINT(build/include) > > namespace webrtc { > > class RtpTransportAdapter; > >-struct RtcpParameters final { >- // The SSRC to be used in the "SSRC of packet sender" field. If not set, one >- // will be chosen by the implementation. >- // TODO(deadbeef): Not implemented. >- rtc::Optional<uint32_t> ssrc; >- >- // The Canonical Name (CNAME) used by RTCP (e.g. in SDES messages). >- // >- // If empty in the construction of the RtpTransport, one will be generated by >- // the implementation, and returned in GetRtcpParameters. Multiple >- // RtpTransports created by the same OrtcFactory will use the same generated >- // CNAME. >- // >- // If empty when passed into SetParameters, the CNAME simply won't be >- // modified. >- std::string cname; >- >- // Send reduced-size RTCP? >- bool reduced_size = false; >- >- // Send RTCP multiplexed on the RTP transport? >- bool mux = true; >- >- bool operator==(const RtcpParameters& o) const { >- return ssrc == o.ssrc && cname == o.cname && >- reduced_size == o.reduced_size && mux == o.mux; >- } >- bool operator!=(const RtcpParameters& o) const { return !(*this == o); } >-}; >- > struct RtpTransportParameters final { > RtcpParameters rtcp; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/sessiondescription_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/sessiondescription_unittest.cc >index fd6f43de437..e4611c6c6b2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/sessiondescription_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/sessiondescription_unittest.cc >@@ -20,4 +20,4 @@ TEST_F(SessionDescriptionTest, CreateSessionDescription) { > EXPECT_EQ(-1, s.session_id()); > EXPECT_EQ("0", s.session_version()); > } >-} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/srtptransportinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/srtptransportinterface.h >index 41c8ccc9c14..4b757e400cc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/srtptransportinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/ortc/srtptransportinterface.h >@@ -11,9 +11,9 @@ > #ifndef API_ORTC_SRTPTRANSPORTINTERFACE_H_ > #define API_ORTC_SRTPTRANSPORTINTERFACE_H_ > >+#include "api/cryptoparams.h" > #include "api/ortc/rtptransportinterface.h" > #include "api/rtcerror.h" >-#include "api/cryptoparams.h" > > namespace webrtc { > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionfactoryproxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionfactoryproxy.h >index 7601ed144ec..db52083567b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionfactoryproxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionfactoryproxy.h >@@ -24,48 +24,59 @@ namespace webrtc { > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_SIGNALING_PROXY_MAP(PeerConnectionFactory) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- // Use the overloads of CreateVideoSource that take raw VideoCapturer >- // pointers from PeerConnectionFactoryInterface. >- // TODO(deadbeef): Remove this using statement once those overloads are >- // removed. >- using PeerConnectionFactoryInterface::CreateVideoSource; >- PROXY_METHOD1(void, SetOptions, const Options&) >- PROXY_METHOD5(rtc::scoped_refptr<PeerConnectionInterface>, >- CreatePeerConnection, >- const PeerConnectionInterface::RTCConfiguration&, >- const MediaConstraintsInterface*, >- std::unique_ptr<cricket::PortAllocator>, >- std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, >- PeerConnectionObserver*); >- PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>, >- CreatePeerConnection, >- const PeerConnectionInterface::RTCConfiguration&, >- std::unique_ptr<cricket::PortAllocator>, >- std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, >- PeerConnectionObserver*); >- PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>, >- CreateLocalMediaStream, const std::string&) >- PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, >- CreateAudioSource, const MediaConstraintsInterface*) >- PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, >- CreateAudioSource, >- const cricket::AudioOptions&) >- PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>, >- CreateVideoSource, >- std::unique_ptr<cricket::VideoCapturer>, >- const MediaConstraintsInterface*) >- PROXY_METHOD1(rtc::scoped_refptr<VideoTrackSourceInterface>, >- CreateVideoSource, >- std::unique_ptr<cricket::VideoCapturer>) >- PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>, >- CreateVideoTrack, >- const std::string&, >- VideoTrackSourceInterface*) >- PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>, >- CreateAudioTrack, const std::string&, AudioSourceInterface*) >- PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t) >- PROXY_METHOD0(void, StopAecDump) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+// Use the overloads of CreateVideoSource that take raw VideoCapturer >+// pointers from PeerConnectionFactoryInterface. >+// TODO(deadbeef): Remove this using statement once those overloads are >+// removed. >+using PeerConnectionFactoryInterface::CreateVideoSource; >+PROXY_METHOD1(void, SetOptions, const Options&) >+PROXY_METHOD5(rtc::scoped_refptr<PeerConnectionInterface>, >+ CreatePeerConnection, >+ const PeerConnectionInterface::RTCConfiguration&, >+ const MediaConstraintsInterface*, >+ std::unique_ptr<cricket::PortAllocator>, >+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, >+ PeerConnectionObserver*); >+PROXY_METHOD4(rtc::scoped_refptr<PeerConnectionInterface>, >+ CreatePeerConnection, >+ const PeerConnectionInterface::RTCConfiguration&, >+ std::unique_ptr<cricket::PortAllocator>, >+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, >+ PeerConnectionObserver*); >+PROXY_METHOD2(rtc::scoped_refptr<PeerConnectionInterface>, >+ CreatePeerConnection, >+ const PeerConnectionInterface::RTCConfiguration&, >+ PeerConnectionDependencies); >+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities, >+ GetRtpSenderCapabilities, >+ cricket::MediaType); >+PROXY_CONSTMETHOD1(webrtc::RtpCapabilities, >+ GetRtpReceiverCapabilities, >+ cricket::MediaType); >+PROXY_METHOD1(rtc::scoped_refptr<MediaStreamInterface>, >+ CreateLocalMediaStream, >+ const std::string&) >+PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, >+ CreateAudioSource, >+ const cricket::AudioOptions&) >+PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>, >+ CreateVideoSource, >+ std::unique_ptr<cricket::VideoCapturer>, >+ const MediaConstraintsInterface*) >+PROXY_METHOD1(rtc::scoped_refptr<VideoTrackSourceInterface>, >+ CreateVideoSource, >+ std::unique_ptr<cricket::VideoCapturer>) >+PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>, >+ CreateVideoTrack, >+ const std::string&, >+ VideoTrackSourceInterface*) >+PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>, >+ CreateAudioTrack, >+ const std::string&, >+ AudioSourceInterface*) >+PROXY_METHOD2(bool, StartAecDump, rtc::PlatformFile, int64_t) >+PROXY_METHOD0(void, StopAecDump) > END_PROXY_MAP() > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.cc >new file mode 100644 >index 00000000000..ddaeb362c1a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.cc >@@ -0,0 +1,258 @@ >+/* >+ * Copyright 2018 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 "api/peerconnectioninterface.h" >+ >+namespace webrtc { >+ >+PeerConnectionInterface::IceServer::IceServer() = default; >+PeerConnectionInterface::IceServer::IceServer(const IceServer& rhs) = default; >+PeerConnectionInterface::IceServer::~IceServer() = default; >+ >+PeerConnectionInterface::RTCConfiguration::RTCConfiguration() = default; >+ >+PeerConnectionInterface::RTCConfiguration::RTCConfiguration( >+ const RTCConfiguration& rhs) = default; >+ >+PeerConnectionInterface::RTCConfiguration::RTCConfiguration( >+ RTCConfigurationType type) { >+ if (type == RTCConfigurationType::kAggressive) { >+ // These parameters are also defined in Java and IOS configurations, >+ // so their values may be overwritten by the Java or IOS configuration. >+ bundle_policy = kBundlePolicyMaxBundle; >+ rtcp_mux_policy = kRtcpMuxPolicyRequire; >+ ice_connection_receiving_timeout = kAggressiveIceConnectionReceivingTimeout; >+ >+ // These parameters are not defined in Java or IOS configuration, >+ // so their values will not be overwritten. >+ enable_ice_renomination = true; >+ redetermine_role_on_ice_restart = false; >+ } >+} >+ >+PeerConnectionInterface::RTCConfiguration::~RTCConfiguration() = default; >+ >+RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> >+PeerConnectionInterface::AddTrack( >+ rtc::scoped_refptr<MediaStreamTrackInterface> track, >+ const std::vector<std::string>& stream_ids) { >+ return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented"); >+} >+ >+bool PeerConnectionInterface::RemoveTrack(RtpSenderInterface* sender) { >+ return RemoveTrackNew(sender).ok(); >+} >+ >+RTCError PeerConnectionInterface::RemoveTrackNew( >+ rtc::scoped_refptr<RtpSenderInterface> sender) { >+ return RTCError(RemoveTrack(sender) ? RTCErrorType::NONE >+ : RTCErrorType::INTERNAL_ERROR); >+} >+ >+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >+PeerConnectionInterface::AddTransceiver( >+ rtc::scoped_refptr<MediaStreamTrackInterface> track) { >+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >+} >+ >+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >+PeerConnectionInterface::AddTransceiver( >+ rtc::scoped_refptr<MediaStreamTrackInterface> track, >+ const RtpTransceiverInit& init) { >+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >+} >+ >+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >+PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type) { >+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >+} >+ >+RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >+PeerConnectionInterface::AddTransceiver(cricket::MediaType media_type, >+ const RtpTransceiverInit& init) { >+ return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >+} >+ >+rtc::scoped_refptr<RtpSenderInterface> PeerConnectionInterface::CreateSender( >+ const std::string& kind, >+ const std::string& stream_id) { >+ return rtc::scoped_refptr<RtpSenderInterface>(); >+} >+ >+std::vector<rtc::scoped_refptr<RtpSenderInterface>> >+PeerConnectionInterface::GetSenders() const { >+ return std::vector<rtc::scoped_refptr<RtpSenderInterface>>(); >+} >+ >+std::vector<rtc::scoped_refptr<RtpReceiverInterface>> >+PeerConnectionInterface::GetReceivers() const { >+ return std::vector<rtc::scoped_refptr<RtpReceiverInterface>>(); >+} >+ >+std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> >+PeerConnectionInterface::GetTransceivers() const { >+ return std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>(); >+} >+ >+const SessionDescriptionInterface* >+PeerConnectionInterface::current_local_description() const { >+ return nullptr; >+} >+ >+const SessionDescriptionInterface* >+PeerConnectionInterface::current_remote_description() const { >+ return nullptr; >+} >+ >+const SessionDescriptionInterface* >+PeerConnectionInterface::pending_local_description() const { >+ return nullptr; >+} >+ >+const SessionDescriptionInterface* >+PeerConnectionInterface::pending_remote_description() const { >+ return nullptr; >+} >+ >+PeerConnectionInterface::RTCConfiguration >+PeerConnectionInterface::GetConfiguration() { >+ return PeerConnectionInterface::RTCConfiguration(); >+} >+ >+bool PeerConnectionInterface::SetConfiguration( >+ const PeerConnectionInterface::RTCConfiguration& config, >+ RTCError* error) { >+ return false; >+} >+ >+bool PeerConnectionInterface::SetConfiguration( >+ const PeerConnectionInterface::RTCConfiguration& config) { >+ return false; >+} >+ >+bool PeerConnectionInterface::RemoveIceCandidates( >+ const std::vector<cricket::Candidate>& candidates) { >+ return false; >+} >+ >+RTCError PeerConnectionInterface::SetBitrate(const BitrateSettings& bitrate) { >+ BitrateParameters bitrate_parameters; >+ bitrate_parameters.min_bitrate_bps = bitrate.min_bitrate_bps; >+ bitrate_parameters.current_bitrate_bps = bitrate.start_bitrate_bps; >+ bitrate_parameters.max_bitrate_bps = bitrate.max_bitrate_bps; >+ return SetBitrate(bitrate_parameters); >+} >+ >+RTCError PeerConnectionInterface::SetBitrate( >+ const BitrateParameters& bitrate_parameters) { >+ BitrateSettings bitrate; >+ bitrate.min_bitrate_bps = bitrate_parameters.min_bitrate_bps; >+ bitrate.start_bitrate_bps = bitrate_parameters.current_bitrate_bps; >+ bitrate.max_bitrate_bps = bitrate_parameters.max_bitrate_bps; >+ return SetBitrate(bitrate); >+} >+ >+bool PeerConnectionInterface::StartRtcEventLog(rtc::PlatformFile file, >+ int64_t max_size_bytes) { >+ return false; >+} >+ >+bool PeerConnectionInterface::StartRtcEventLog( >+ std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) { >+ return false; >+} >+ >+PeerConnectionInterface::BitrateParameters::BitrateParameters() = default; >+ >+PeerConnectionInterface::BitrateParameters::~BitrateParameters() = default; >+ >+PeerConnectionDependencies::PeerConnectionDependencies( >+ PeerConnectionObserver* observer_in) >+ : observer(observer_in) {} >+ >+PeerConnectionDependencies::PeerConnectionDependencies( >+ PeerConnectionDependencies&&) = default; >+ >+PeerConnectionDependencies::~PeerConnectionDependencies() = default; >+ >+PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies() = >+ default; >+ >+PeerConnectionFactoryDependencies::PeerConnectionFactoryDependencies( >+ PeerConnectionFactoryDependencies&&) = default; >+ >+PeerConnectionFactoryDependencies::~PeerConnectionFactoryDependencies() = >+ default; >+ >+rtc::scoped_refptr<PeerConnectionInterface> >+PeerConnectionFactoryInterface::CreatePeerConnection( >+ const PeerConnectionInterface::RTCConfiguration& configuration, >+ const MediaConstraintsInterface* constraints, >+ std::unique_ptr<cricket::PortAllocator> allocator, >+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, >+ PeerConnectionObserver* observer) { >+ return nullptr; >+} >+ >+rtc::scoped_refptr<PeerConnectionInterface> >+PeerConnectionFactoryInterface::CreatePeerConnection( >+ const PeerConnectionInterface::RTCConfiguration& configuration, >+ std::unique_ptr<cricket::PortAllocator> allocator, >+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, >+ PeerConnectionObserver* observer) { >+ return nullptr; >+} >+ >+rtc::scoped_refptr<PeerConnectionInterface> >+PeerConnectionFactoryInterface::CreatePeerConnection( >+ const PeerConnectionInterface::RTCConfiguration& configuration, >+ PeerConnectionDependencies dependencies) { >+ return nullptr; >+} >+ >+RtpCapabilities PeerConnectionFactoryInterface::GetRtpSenderCapabilities( >+ cricket::MediaType kind) const { >+ return {}; >+} >+ >+RtpCapabilities PeerConnectionFactoryInterface::GetRtpReceiverCapabilities( >+ cricket::MediaType kind) const { >+ return {}; >+} >+ >+rtc::scoped_refptr<VideoTrackSourceInterface> >+PeerConnectionFactoryInterface::CreateVideoSource( >+ std::unique_ptr<cricket::VideoCapturer> capturer) { >+ return nullptr; >+} >+ >+rtc::scoped_refptr<VideoTrackSourceInterface> >+PeerConnectionFactoryInterface::CreateVideoSource( >+ std::unique_ptr<cricket::VideoCapturer> capturer, >+ const MediaConstraintsInterface* constraints) { >+ return nullptr; >+} >+ >+rtc::scoped_refptr<VideoTrackSourceInterface> >+PeerConnectionFactoryInterface::CreateVideoSource( >+ cricket::VideoCapturer* capturer) { >+ return CreateVideoSource(std::unique_ptr<cricket::VideoCapturer>(capturer)); >+} >+ >+rtc::scoped_refptr<VideoTrackSourceInterface> >+PeerConnectionFactoryInterface::CreateVideoSource( >+ cricket::VideoCapturer* capturer, >+ const MediaConstraintsInterface* constraints) { >+ return CreateVideoSource(std::unique_ptr<cricket::VideoCapturer>(capturer), >+ constraints); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.h >index a4d57eb7dfd..0fc2a2b5b8a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectioninterface.h >@@ -9,7 +9,7 @@ > */ > > // This file contains the PeerConnection interface as defined in >-// http://dev.w3.org/2011/webrtc/editor/webrtc.html#peer-to-peer-connections. >+// https://w3c.github.io/webrtc-pc/#peer-to-peer-connections > // > // The PeerConnectionFactory class provides factory methods to create > // PeerConnection, MediaStream and MediaStreamTrack objects. >@@ -67,19 +67,20 @@ > #ifndef API_PEERCONNECTIONINTERFACE_H_ > #define API_PEERCONNECTIONINTERFACE_H_ > >-// TODO(sakal): Remove this define after migration to virtual PeerConnection >-// observer is complete. >-#define VIRTUAL_PEERCONNECTION_OBSERVER_DESTRUCTOR >- > #include <memory> > #include <string> > #include <utility> > #include <vector> > >+#include "api/asyncresolverfactory.h" >+#include "api/audio/audio_mixer.h" > #include "api/audio_codecs/audio_decoder_factory.h" > #include "api/audio_codecs/audio_encoder_factory.h" >+#include "api/audio_options.h" >+#include "api/call/callfactoryinterface.h" > #include "api/datachannelinterface.h" > #include "api/dtmfsenderinterface.h" >+#include "api/fec_controller.h" > #include "api/jsep.h" > #include "api/mediastreaminterface.h" > #include "api/rtcerror.h" >@@ -90,34 +91,44 @@ > #include "api/setremotedescriptionobserverinterface.h" > #include "api/stats/rtcstatscollectorcallback.h" > #include "api/statstypes.h" >+#include "api/transport/bitrate_settings.h" >+#include "api/transport/network_control.h" > #include "api/turncustomizer.h" > #include "api/umametrics.h" >-#include "call/callfactoryinterface.h" > #include "logging/rtc_event_log/rtc_event_log_factory_interface.h" >-#include "media/base/mediachannel.h" >-#include "media/base/videocapturer.h" >-#include "p2p/base/portallocator.h" >+#include "media/base/mediaconfig.h" >+// TODO(bugs.webrtc.org/6353): cricket::VideoCapturer is deprecated and should >+// be deleted from the PeerConnection api. >+#include "media/base/videocapturer.h" // nogncheck >+// TODO(bugs.webrtc.org/7447): We plan to provide a way to let applications >+// inject a PacketSocketFactory and/or NetworkManager, and not expose >+// PortAllocator in the PeerConnection api. >+#include "media/base/mediaengine.h" // nogncheck >+#include "p2p/base/portallocator.h" // nogncheck >+// TODO(nisse): The interface for bitrate allocation strategy belongs in api/. >+#include "rtc_base/bitrateallocationstrategy.h" > #include "rtc_base/network.h" >+#include "rtc_base/platform_file.h" > #include "rtc_base/rtccertificate.h" > #include "rtc_base/rtccertificategenerator.h" > #include "rtc_base/socketaddress.h" >+#include "rtc_base/sslcertificate.h" > #include "rtc_base/sslstreamadapter.h" > > namespace rtc { > class SSLIdentity; > class Thread; >-} >+} // namespace rtc > > namespace cricket { >-class MediaEngineInterface; > class WebRtcVideoDecoderFactory; > class WebRtcVideoEncoderFactory; >-} >+} // namespace cricket > > namespace webrtc { > class AudioDeviceModule; > class AudioMixer; >-class CallFactoryInterface; >+class AudioProcessing; > class MediaConstraintsInterface; > class VideoDecoderFactory; > class VideoEncoderFactory; >@@ -129,14 +140,12 @@ class StreamCollectionInterface : public rtc::RefCountInterface { > virtual size_t count() = 0; > virtual MediaStreamInterface* at(size_t index) = 0; > virtual MediaStreamInterface* find(const std::string& label) = 0; >- virtual MediaStreamTrackInterface* FindAudioTrack( >- const std::string& id) = 0; >- virtual MediaStreamTrackInterface* FindVideoTrack( >- const std::string& id) = 0; >+ virtual MediaStreamTrackInterface* FindAudioTrack(const std::string& id) = 0; >+ virtual MediaStreamTrackInterface* FindVideoTrack(const std::string& id) = 0; > > protected: > // Dtor protected as objects shouldn't be deleted via this interface. >- ~StreamCollectionInterface() {} >+ ~StreamCollectionInterface() override = default; > }; > > class StatsObserver : public rtc::RefCountInterface { >@@ -144,16 +153,14 @@ class StatsObserver : public rtc::RefCountInterface { > virtual void OnComplete(const StatsReports& reports) = 0; > > protected: >- virtual ~StatsObserver() {} >+ ~StatsObserver() override = default; > }; > >-// For now, kDefault is interpreted as kPlanB. >-// TODO(bugs.webrtc.org/8530): Switch default to kUnifiedPlan. >-enum class SdpSemantics { kDefault, kPlanB, kUnifiedPlan }; >+enum class SdpSemantics { kPlanB, kUnifiedPlan }; > > class PeerConnectionInterface : public rtc::RefCountInterface { > public: >- // See http://dev.w3.org/2011/webrtc/editor/webrtc.html#state-definitions . >+ // See https://w3c.github.io/webrtc-pc/#state-definitions > enum SignalingState { > kStable, > kHaveLocalOffer, >@@ -192,6 +199,10 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > }; > > struct IceServer { >+ IceServer(); >+ IceServer(const IceServer&); >+ ~IceServer(); >+ > // TODO(jbauch): Remove uri when all code using it has switched to urls. > // List of URIs associated with this server. Valid formats are described > // in RFC7064 and RFC7065, and more may be added in the future. The "host" >@@ -231,14 +242,14 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > kAll > }; > >- // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-08#section-4.1.1 >+ // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1 > enum BundlePolicy { > kBundlePolicyBalanced, > kBundlePolicyMaxBundle, > kBundlePolicyMaxCompat > }; > >- // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-09#section-4.1.1 >+ // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-4.1.1 > enum RtcpMuxPolicy { > kRtcpMuxPolicyNegotiate, > kRtcpMuxPolicyRequire, >@@ -254,10 +265,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > kCandidateNetworkPolicyLowCost > }; > >- enum ContinualGatheringPolicy { >- GATHER_ONCE, >- GATHER_CONTINUALLY >- }; >+ enum ContinualGatheringPolicy { GATHER_ONCE, GATHER_CONTINUALLY }; > > enum class RTCConfigurationType { > // A configuration that is safer to use, despite not having the best >@@ -281,53 +289,43 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // methods for all settings which are of interest to applications, > // Chrome in particular. > >- RTCConfiguration() = default; >- explicit RTCConfiguration(RTCConfigurationType type) { >- if (type == RTCConfigurationType::kAggressive) { >- // These parameters are also defined in Java and IOS configurations, >- // so their values may be overwritten by the Java or IOS configuration. >- bundle_policy = kBundlePolicyMaxBundle; >- rtcp_mux_policy = kRtcpMuxPolicyRequire; >- ice_connection_receiving_timeout = >- kAggressiveIceConnectionReceivingTimeout; >- >- // These parameters are not defined in Java or IOS configuration, >- // so their values will not be overwritten. >- enable_ice_renomination = true; >- redetermine_role_on_ice_restart = false; >- } >- } >+ RTCConfiguration(); >+ RTCConfiguration(const RTCConfiguration&); >+ explicit RTCConfiguration(RTCConfigurationType type); >+ ~RTCConfiguration(); > > bool operator==(const RTCConfiguration& o) const; > bool operator!=(const RTCConfiguration& o) const; > >- bool dscp() { return media_config.enable_dscp; } >+ bool dscp() const { return media_config.enable_dscp; } > void set_dscp(bool enable) { media_config.enable_dscp = enable; } > >- // TODO(nisse): The corresponding flag in MediaConfig and >- // elsewhere should be renamed enable_cpu_adaptation. >- bool cpu_adaptation() { >- return media_config.video.enable_cpu_overuse_detection; >+ bool cpu_adaptation() const { >+ return media_config.video.enable_cpu_adaptation; > } > void set_cpu_adaptation(bool enable) { >- media_config.video.enable_cpu_overuse_detection = enable; >+ media_config.video.enable_cpu_adaptation = enable; > } > >- bool suspend_below_min_bitrate() { >+ bool suspend_below_min_bitrate() const { > return media_config.video.suspend_below_min_bitrate; > } > void set_suspend_below_min_bitrate(bool enable) { > media_config.video.suspend_below_min_bitrate = enable; > } > >- // TODO(nisse): The negation in the corresponding MediaConfig >- // attribute is inconsistent, and it should be renamed at some >- // point. >- bool prerenderer_smoothing() { >- return !media_config.video.disable_prerenderer_smoothing; >+ bool prerenderer_smoothing() const { >+ return media_config.video.enable_prerenderer_smoothing; > } > void set_prerenderer_smoothing(bool enable) { >- media_config.video.disable_prerenderer_smoothing = !enable; >+ media_config.video.enable_prerenderer_smoothing = enable; >+ } >+ >+ bool experiment_cpu_load_estimator() const { >+ return media_config.video.experiment_cpu_load_estimator; >+ } >+ void set_experiment_cpu_load_estimator(bool enable) { >+ media_config.video.experiment_cpu_load_estimator = enable; > } > > static const int kUndefined = -1; >@@ -338,7 +336,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > > //////////////////////////////////////////////////////////////////////// > // The below few fields mirror the standard RTCConfiguration dictionary: >- // https://www.w3.org/TR/webrtc/#rtcconfiguration-dictionary >+ // https://w3c.github.io/webrtc-pc/#rtcconfiguration-dictionary > //////////////////////////////////////////////////////////////////////// > > // TODO(pthatcher): Rename this ice_servers, but update Chromium >@@ -356,7 +354,7 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // The below fields correspond to constraints from the deprecated > // constraints interface for constructing a PeerConnection. > // >- // rtc::Optional fields can be "missing", in which case the implementation >+ // absl::optional fields can be "missing", in which case the implementation > // default will be used. > ////////////////////////////////////////////////////////////////////////// > >@@ -378,6 +376,10 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // Can be set to INT_MAX to effectively disable the limit. > int max_ipv6_networks = cricket::kDefaultMaxIPv6Networks; > >+ // Exclude link-local network interfaces >+ // from considertaion for gathering ICE candidates. >+ bool disable_link_local_networks = false; >+ > // If set to true, use RTP data channels instead of SCTP. > // TODO(deadbeef): Remove this. We no longer commit to supporting RTP data > // channels, though some applications are still working on moving off of >@@ -387,15 +389,15 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // Minimum bitrate at which screencast video tracks will be encoded at. > // This means adding padding bits up to this bitrate, which can help > // when switching from a static scene to one with motion. >- rtc::Optional<int> screencast_min_bitrate; >+ absl::optional<int> screencast_min_bitrate; > > // Use new combined audio/video bandwidth estimation? >- rtc::Optional<bool> combined_audio_video_bwe; >+ absl::optional<bool> combined_audio_video_bwe; > > // Can be used to disable DTLS-SRTP. This should never be done, but can be > // useful for testing purposes, for example in setting up a loopback call > // with a single PeerConnection. >- rtc::Optional<bool> enable_dtls_srtp; >+ absl::optional<bool> enable_dtls_srtp; > > ///////////////////////////////////////////////// > // The below fields are not part of the standard. >@@ -444,6 +446,9 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // standard priority order. > bool prioritize_most_likely_ice_candidate_pairs = false; > >+ // Implementation defined settings. A public member only for the benefit of >+ // the implementation. Applications must not access it directly, and should >+ // instead use provided accessor methods, e.g., set_cpu_adaptation. > struct cricket::MediaConfig media_config; > > // If set to true, only one preferred TURN allocation will be used per >@@ -470,15 +475,51 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // re-determining was removed in ICEbis (ICE v2). > bool redetermine_role_on_ice_restart = true; > >- // If set, the min interval (max rate) at which we will send ICE checks >- // (STUN pings), in milliseconds. >- rtc::Optional<int> ice_check_min_interval; >+ // The following fields define intervals in milliseconds at which ICE >+ // connectivity checks are sent. >+ // >+ // We consider ICE is "strongly connected" for an agent when there is at >+ // least one candidate pair that currently succeeds in connectivity check >+ // from its direction i.e. sending a STUN ping and receives a STUN ping >+ // response, AND all candidate pairs have sent a minimum number of pings for >+ // connectivity (this number is implementation-specific). Otherwise, ICE is >+ // considered in "weak connectivity". >+ // >+ // Note that the above notion of strong and weak connectivity is not defined >+ // in RFC 5245, and they apply to our current ICE implementation only. >+ // >+ // 1) ice_check_interval_strong_connectivity defines the interval applied to >+ // ALL candidate pairs when ICE is strongly connected, and it overrides the >+ // default value of this interval in the ICE implementation; >+ // 2) ice_check_interval_weak_connectivity defines the counterpart for ALL >+ // pairs when ICE is weakly connected, and it overrides the default value of >+ // this interval in the ICE implementation; >+ // 3) ice_check_min_interval defines the minimal interval (equivalently the >+ // maximum rate) that overrides the above two intervals when either of them >+ // is less. >+ absl::optional<int> ice_check_interval_strong_connectivity; >+ absl::optional<int> ice_check_interval_weak_connectivity; >+ absl::optional<int> ice_check_min_interval; >+ >+ // The min time period for which a candidate pair must wait for response to >+ // connectivity checks before it becomes unwritable. This parameter >+ // overrides the default value in the ICE implementation if set. >+ absl::optional<int> ice_unwritable_timeout; >+ >+ // The min number of connectivity checks that a candidate pair must sent >+ // without receiving response before it becomes unwritable. This parameter >+ // overrides the default value in the ICE implementation if set. >+ absl::optional<int> ice_unwritable_min_checks; >+ >+ // The interval in milliseconds at which STUN candidates will resend STUN >+ // binding requests to keep NAT bindings open. >+ absl::optional<int> stun_candidate_keepalive_interval; > > // ICE Periodic Regathering > // If set, WebRTC will periodically create and propose candidates without > // starting a new ICE generation. The regathering happens continuously with > // interval specified in milliseconds by the uniform distribution [a, b]. >- rtc::Optional<rtc::IntervalRange> ice_regather_interval_range; >+ absl::optional<rtc::IntervalRange> ice_regather_interval_range; > > // Optional TurnCustomizer. > // With this class one can modify outgoing TURN messages. >@@ -486,6 +527,12 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // called. > webrtc::TurnCustomizer* turn_customizer = nullptr; > >+ // Preferred network interface. >+ // A candidate pair on a preferred network has a higher precedence in ICE >+ // than one on an un-preferred network, regardless of priority or network >+ // cost. >+ absl::optional<rtc::AdapterType> network_preference; >+ > // Configure the SDP semantics used by this PeerConnection. Note that the > // WebRTC 1.0 specification requires kUnifiedPlan semantics. The > // RtpTransceiver API is only available with kUnifiedPlan semantics. >@@ -493,26 +540,28 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // kPlanB will cause PeerConnection to create offers and answers with at > // most one audio and one video m= section with multiple RtpSenders and > // RtpReceivers specified as multiple a=ssrc lines within the section. This >- // will also cause PeerConnection to reject offers/answers with multiple m= >- // sections of the same media type. >+ // will also cause PeerConnection to ignore all but the first m= section of >+ // the same media type. > // > // kUnifiedPlan will cause PeerConnection to create offers and answers with > // multiple m= sections where each m= section maps to one RtpSender and one >- // RtpReceiver (an RtpTransceiver), either both audio or both video. Plan B >- // style offers or answers will be rejected in calls to SetLocalDescription >- // or SetRemoteDescription. >- // >- // For users who only send at most one audio and one video track, this >- // choice does not matter and should be left as kDefault. >+ // RtpReceiver (an RtpTransceiver), either both audio or both video. This >+ // will also cause PeerConnection to ignore all but the first a=ssrc lines >+ // that form a Plan B stream. > // > // For users who wish to send multiple audio/video streams and need to stay >- // interoperable with legacy WebRTC implementations, specify kPlanB. >+ // interoperable with legacy WebRTC implementations or use legacy APIs, >+ // specify kPlanB. > // >- // For users who wish to send multiple audio/video streams and/or wish to >- // use the new RtpTransceiver API, specify kUnifiedPlan. >- // >- // TODO(steveanton): Implement support for kUnifiedPlan. >- SdpSemantics sdp_semantics = SdpSemantics::kDefault; >+ // For all other users, specify kUnifiedPlan. >+ SdpSemantics sdp_semantics = SdpSemantics::kPlanB; >+ >+ // Actively reset the SRTP parameters whenever the DTLS transports >+ // underneath are reset for every offer/answer negotiation. >+ // This is only intended to be a workaround for crbug.com/835958 >+ // WARNING: This would cause RTP/RTCP packets decryption failure if not used >+ // correctly. This flag will be deprecated soon. Do not rely on it. >+ bool active_reset_srtp_params = false; > > // > // Don't forget to update operator== if adding something. >@@ -527,8 +576,9 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // The default value for constraint offerToReceiveX:true. > static const int kOfferToReceiveMediaTrue = 1; > >- // These have been removed from the standard in favor of the "transceiver" >- // API, but given that we don't support that API, we still have them here. >+ // These options are left as backwards compatibility for clients who need >+ // "Plan B" semantics. Clients who have switched to "Unified Plan" semantics >+ // should use the RtpTransceiver API (AddTransceiver) instead. > // > // offer_to_receive_X set to 1 will cause a media description to be > // generated in the offer, even if no tracks of that type have been added. >@@ -570,12 +620,14 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > }; > > // Accessor methods to active local streams. >- virtual rtc::scoped_refptr<StreamCollectionInterface> >- local_streams() = 0; >+ // This method is not supported with kUnifiedPlan semantics. Please use >+ // GetSenders() instead. >+ virtual rtc::scoped_refptr<StreamCollectionInterface> local_streams() = 0; > > // Accessor methods to remote streams. >- virtual rtc::scoped_refptr<StreamCollectionInterface> >- remote_streams() = 0; >+ // This method is not supported with kUnifiedPlan semantics. Please use >+ // GetReceivers() instead. >+ virtual rtc::scoped_refptr<StreamCollectionInterface> remote_streams() = 0; > > // Add a new MediaStream to be sent on this PeerConnection. > // Note that a SessionDescription negotiation is needed before the >@@ -586,39 +638,48 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // stream, with the one difference that if "stream->AddTrack(...)" is called > // later, the PeerConnection will automatically pick up the new track. Though > // this functionality will be deprecated in the future. >+ // >+ // This method is not supported with kUnifiedPlan semantics. Please use >+ // AddTrack instead. > virtual bool AddStream(MediaStreamInterface* stream) = 0; > > // Remove a MediaStream from this PeerConnection. > // Note that a SessionDescription negotiation is needed before the > // remote peer is notified. >+ // >+ // This method is not supported with kUnifiedPlan semantics. Please use >+ // RemoveTrack instead. > virtual void RemoveStream(MediaStreamInterface* stream) = 0; > > // Add a new MediaStreamTrack to be sent on this PeerConnection, and return > // the newly created RtpSender. The RtpSender will be associated with the >- // streams specified in the |stream_labels| list. >+ // streams specified in the |stream_ids| list. > // > // Errors: > // - INVALID_PARAMETER: |track| is null, has a kind other than audio or video, > // or a sender already exists for the track. > // - INVALID_STATE: The PeerConnection is closed. >- // TODO(steveanton): Remove default implementation once downstream >- // implementations have been updated. > virtual RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>> AddTrack( >- rtc::scoped_refptr<MediaStreamTrackInterface>, >- const std::vector<std::string>&) { >- return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented"); >- } >- // |streams| indicates which stream labels the track should be associated >- // with. >- // TODO(steveanton): Remove this overload once callers have moved to the >- // signature with stream labels. >- virtual rtc::scoped_refptr<RtpSenderInterface> AddTrack( >- MediaStreamTrackInterface* track, >- std::vector<MediaStreamInterface*> streams) = 0; >+ rtc::scoped_refptr<MediaStreamTrackInterface> track, >+ const std::vector<std::string>& stream_ids); > > // Remove an RtpSender from this PeerConnection. > // Returns true on success. >- virtual bool RemoveTrack(RtpSenderInterface* sender) = 0; >+ // TODO(steveanton): Replace with signature that returns RTCError. >+ virtual bool RemoveTrack(RtpSenderInterface* sender); >+ >+ // Plan B semantics: Removes the RtpSender from this PeerConnection. >+ // Unified Plan semantics: Stop sending on the RtpSender and mark the >+ // corresponding RtpTransceiver direction as no longer sending. >+ // >+ // Errors: >+ // - INVALID_PARAMETER: |sender| is null or (Plan B only) the sender is not >+ // associated with this PeerConnection. >+ // - INVALID_STATE: PeerConnection is closed. >+ // TODO(bugs.webrtc.org/9534): Rename to RemoveTrack once the other signature >+ // is removed. >+ virtual RTCError RemoveTrackNew( >+ rtc::scoped_refptr<RtpSenderInterface> sender); > > // AddTransceiver creates a new RtpTransceiver and adds it to the set of > // transceivers. Adding a transceiver will cause future calls to CreateOffer >@@ -647,14 +708,10 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // Errors: > // - INVALID_PARAMETER: |track| is null. > virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >- AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface>) { >- return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >- } >+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track); > virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >- AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface>, >- const RtpTransceiverInit&) { >- return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >- } >+ AddTransceiver(rtc::scoped_refptr<MediaStreamTrackInterface> track, >+ const RtpTransceiverInit& init); > > // Adds a transceiver with the given kind. Can either be MEDIA_TYPE_AUDIO or > // MEDIA_TYPE_VIDEO. >@@ -662,22 +719,9 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // - INVALID_PARAMETER: |media_type| is not MEDIA_TYPE_AUDIO or > // MEDIA_TYPE_VIDEO. > virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >- AddTransceiver(cricket::MediaType) { >- return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >- } >+ AddTransceiver(cricket::MediaType media_type); > virtual RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>> >- AddTransceiver(cricket::MediaType, >- const RtpTransceiverInit&) { >- return RTCError(RTCErrorType::INTERNAL_ERROR, "not implemented"); >- } >- >- // Returns pointer to a DtmfSender on success. Otherwise returns null. >- // >- // This API is no longer part of the standard; instead DtmfSenders are >- // obtained from RtpSenders. Which is what the implementation does; it finds >- // an RtpSender for |track| and just returns its DtmfSender. >- virtual rtc::scoped_refptr<DtmfSenderInterface> CreateDtmfSender( >- AudioTrackInterface* track) = 0; >+ AddTransceiver(cricket::MediaType media_type, const RtpTransceiverInit& init); > > // TODO(deadbeef): Make these pure virtual once all subclasses implement them. > >@@ -692,53 +736,82 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // > // |stream_id| is used to populate the msid attribute; if empty, one will > // be generated automatically. >+ // >+ // This method is not supported with kUnifiedPlan semantics. Please use >+ // AddTransceiver instead. > virtual rtc::scoped_refptr<RtpSenderInterface> CreateSender( >- const std::string& /* kind */, >- const std::string& /* stream_id */) { >- return rtc::scoped_refptr<RtpSenderInterface>(); >- } >+ const std::string& kind, >+ const std::string& stream_id); > >- // Get all RtpSenders, created either through AddStream, AddTrack, or >- // CreateSender. Note that these are "Plan B SDP" RtpSenders, not "Unified >- // Plan SDP" RtpSenders, which means that all senders of a specific media >- // type share the same media description. >+ // If Plan B semantics are specified, gets all RtpSenders, created either >+ // through AddStream, AddTrack, or CreateSender. All senders of a specific >+ // media type share the same media description. >+ // >+ // If Unified Plan semantics are specified, gets the RtpSender for each >+ // RtpTransceiver. > virtual std::vector<rtc::scoped_refptr<RtpSenderInterface>> GetSenders() >- const { >- return std::vector<rtc::scoped_refptr<RtpSenderInterface>>(); >- } >+ const; > >- // Get all RtpReceivers, created when a remote description is applied. >- // Note that these are "Plan B SDP" RtpReceivers, not "Unified Plan SDP" >- // RtpReceivers, which means that all receivers of a specific media type >- // share the same media description. >+ // If Plan B semantics are specified, gets all RtpReceivers created when a >+ // remote description is applied. All receivers of a specific media type share >+ // the same media description. It is also possible to have a media description >+ // with no associated RtpReceivers, if the directional attribute does not >+ // indicate that the remote peer is sending any media. > // >- // It is also possible to have a media description with no associated >- // RtpReceivers, if the directional attribute does not indicate that the >- // remote peer is sending any media. >+ // If Unified Plan semantics are specified, gets the RtpReceiver for each >+ // RtpTransceiver. > virtual std::vector<rtc::scoped_refptr<RtpReceiverInterface>> GetReceivers() >- const { >- return std::vector<rtc::scoped_refptr<RtpReceiverInterface>>(); >- } >+ const; > > // Get all RtpTransceivers, created either through AddTransceiver, AddTrack or > // by a remote description applied with SetRemoteDescription. >+ // > // Note: This method is only available when Unified Plan is enabled (see > // RTCConfiguration). > virtual std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> >- GetTransceivers() const { >- return {}; >- } >+ GetTransceivers() const; > >+ // The legacy non-compliant GetStats() API. This correspond to the >+ // callback-based version of getStats() in JavaScript. The returned metrics >+ // are UNDOCUMENTED and many of them rely on implementation-specific details. >+ // The goal is to DELETE THIS VERSION but we can't today because it is heavily >+ // relied upon by third parties. See https://crbug.com/822696. >+ // >+ // This version is wired up into Chrome. Any stats implemented are >+ // automatically exposed to the Web Platform. This has BYPASSED the Chrome >+ // release processes for years and lead to cross-browser incompatibility >+ // issues and web application reliance on Chrome-only behavior. >+ // >+ // This API is in "maintenance mode", serious regressions should be fixed but >+ // adding new stats is highly discouraged. >+ // >+ // TODO(hbos): Deprecate and remove this when third parties have migrated to >+ // the spec-compliant GetStats() API. https://crbug.com/822696 > virtual bool GetStats(StatsObserver* observer, >- MediaStreamTrackInterface* track, >+ MediaStreamTrackInterface* track, // Optional > StatsOutputLevel level) = 0; >- // Gets stats using the new stats collection API, see webrtc/api/stats/. These >- // will replace old stats collection API when the new API has matured enough. >- // TODO(hbos): Default implementation that does nothing only exists as to not >- // break third party projects. As soon as they have been updated this should >- // be changed to "= 0;". >- virtual void GetStats(RTCStatsCollectorCallback*) {} >- // Clear cached stats in the rtcstatscollector. >+ // The spec-compliant GetStats() API. This correspond to the promise-based >+ // version of getStats() in JavaScript. Implementation status is described in >+ // api/stats/rtcstats_objects.h. For more details on stats, see spec: >+ // https://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-getstats >+ // TODO(hbos): Takes shared ownership, use rtc::scoped_refptr<> instead. This >+ // requires stop overriding the current version in third party or making third >+ // party calls explicit to avoid ambiguity during switch. Make the future >+ // version abstract as soon as third party projects implement it. >+ virtual void GetStats(RTCStatsCollectorCallback* callback) {} >+ // Spec-compliant getStats() performing the stats selection algorithm with the >+ // sender. https://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-getstats >+ // TODO(hbos): Make abstract as soon as third party projects implement it. >+ virtual void GetStats( >+ rtc::scoped_refptr<RtpSenderInterface> selector, >+ rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {} >+ // Spec-compliant getStats() performing the stats selection algorithm with the >+ // receiver. https://w3c.github.io/webrtc-pc/#dom-rtcrtpreceiver-getstats >+ // TODO(hbos): Make abstract as soon as third party projects implement it. >+ virtual void GetStats( >+ rtc::scoped_refptr<RtpReceiverInterface> selector, >+ rtc::scoped_refptr<RTCStatsCollectorCallback> callback) {} >+ // Clear cached stats in the RTCStatsCollector. > // Exposed for testing while waiting for automatic cache clear to work. > // https://bugs.webrtc.org/8693 > virtual void ClearStatsCache() {} >@@ -761,44 +834,34 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > > // A "current" description the one currently negotiated from a complete > // offer/answer exchange. >- virtual const SessionDescriptionInterface* current_local_description() const { >- return nullptr; >- } >- virtual const SessionDescriptionInterface* current_remote_description() >- const { >- return nullptr; >- } >+ virtual const SessionDescriptionInterface* current_local_description() const; >+ virtual const SessionDescriptionInterface* current_remote_description() const; > > // A "pending" description is one that's part of an incomplete offer/answer > // exchange (thus, either an offer or a pranswer). Once the offer/answer > // exchange is finished, the "pending" description will become "current". >- virtual const SessionDescriptionInterface* pending_local_description() const { >- return nullptr; >- } >- virtual const SessionDescriptionInterface* pending_remote_description() >- const { >- return nullptr; >- } >+ virtual const SessionDescriptionInterface* pending_local_description() const; >+ virtual const SessionDescriptionInterface* pending_remote_description() const; > > // Create a new offer. > // The CreateSessionDescriptionObserver callback will be called when done. >- virtual void CreateOffer(CreateSessionDescriptionObserver*, >- const MediaConstraintsInterface*) {} >+ virtual void CreateOffer(CreateSessionDescriptionObserver* observer, >+ const MediaConstraintsInterface* constraints) {} > > // TODO(jiayl): remove the default impl and the old interface when chromium > // code is updated. >- virtual void CreateOffer(CreateSessionDescriptionObserver*, >- const RTCOfferAnswerOptions&) {} >+ virtual void CreateOffer(CreateSessionDescriptionObserver* observer, >+ const RTCOfferAnswerOptions& options) {} > > // Create an answer to an offer. > // The CreateSessionDescriptionObserver callback will be called when done. >- virtual void CreateAnswer(CreateSessionDescriptionObserver*, >- const RTCOfferAnswerOptions&) {} >+ virtual void CreateAnswer(CreateSessionDescriptionObserver* observer, >+ const RTCOfferAnswerOptions& options) {} > // Deprecated - use version above. > // TODO(hta): Remove and remove default implementations when all callers > // are updated. >- virtual void CreateAnswer(CreateSessionDescriptionObserver*, >- const MediaConstraintsInterface*) {} >+ virtual void CreateAnswer(CreateSessionDescriptionObserver* observer, >+ const MediaConstraintsInterface* constraints) {} > > // Sets the local session description. > // The PeerConnection takes the ownership of |desc| even if it fails. >@@ -811,25 +874,16 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // The PeerConnection takes the ownership of |desc| even if it fails. > // The |observer| callback will be called when done. > // TODO(hbos): Remove when Chrome implements the new signature. >- virtual void SetRemoteDescription(SetSessionDescriptionObserver*, >- SessionDescriptionInterface*) {} >+ virtual void SetRemoteDescription(SetSessionDescriptionObserver* observer, >+ SessionDescriptionInterface* desc) {} > // TODO(hbos): Make pure virtual when Chrome has updated its signature. > virtual void SetRemoteDescription( >- std::unique_ptr<SessionDescriptionInterface>, >- rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>) {} >- // Deprecated; Replaced by SetConfiguration. >- // TODO(deadbeef): Remove once Chrome is moved over to SetConfiguration. >- virtual bool UpdateIce(const IceServers&, >- const MediaConstraintsInterface*) { >- return false; >- } >- virtual bool UpdateIce(const IceServers&) { return false; } >+ std::unique_ptr<SessionDescriptionInterface> desc, >+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface> observer) {} > > // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of > // PeerConnectionInterface implement it. >- virtual PeerConnectionInterface::RTCConfiguration GetConfiguration() { >- return PeerConnectionInterface::RTCConfiguration(); >- } >+ virtual PeerConnectionInterface::RTCConfiguration GetConfiguration(); > > // Sets the PeerConnection's global configuration to |config|. > // >@@ -855,16 +909,13 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // TODO(deadbeef): Make this pure virtual once all Chrome subclasses of > // PeerConnectionInterface implement it. > virtual bool SetConfiguration( >- const PeerConnectionInterface::RTCConfiguration&, >- RTCError*) { >- return false; >- } >+ const PeerConnectionInterface::RTCConfiguration& config, >+ RTCError* error); >+ > // Version without error output param for backwards compatibility. > // TODO(deadbeef): Remove once chromium is updated. > virtual bool SetConfiguration( >- const PeerConnectionInterface::RTCConfiguration&) { >- return false; >- } >+ const PeerConnectionInterface::RTCConfiguration& config); > > // Provides a remote candidate to the ICE Agent. > // A copy of the |candidate| will be created and added to the remote >@@ -876,21 +927,16 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // continual gathering, to avoid an ever-growing list of candidates as > // networks come and go. > virtual bool RemoveIceCandidates( >- const std::vector<cricket::Candidate>&) { >- return false; >- } >- >- // Register a metric observer (used by chromium). It's reference counted, and >- // this method takes a reference. RegisterUMAObserver(nullptr) will release >- // the reference. >- // TODO(deadbeef): Take argument as scoped_refptr? >- virtual void RegisterUMAObserver(UMAObserver* observer) = 0; >+ const std::vector<cricket::Candidate>& candidates); > > // 0 <= min <= current <= max should hold for set parameters. > struct BitrateParameters { >- rtc::Optional<int> min_bitrate_bps; >- rtc::Optional<int> current_bitrate_bps; >- rtc::Optional<int> max_bitrate_bps; >+ BitrateParameters(); >+ ~BitrateParameters(); >+ >+ absl::optional<int> min_bitrate_bps; >+ absl::optional<int> current_bitrate_bps; >+ absl::optional<int> max_bitrate_bps; > }; > > // SetBitrate limits the bandwidth allocated for all RTP streams sent by >@@ -899,14 +945,20 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // > // Setting |current_bitrate_bps| will reset the current bitrate estimate > // to the provided value. >- virtual RTCError SetBitrate(const BitrateParameters& bitrate) = 0; >+ virtual RTCError SetBitrate(const BitrateSettings& bitrate); >+ >+ // TODO(nisse): Deprecated - use version above. These two default >+ // implementations require subclasses to implement one or the other >+ // of the methods. >+ virtual RTCError SetBitrate(const BitrateParameters& bitrate_parameters); > > // Sets current strategy. If not set default WebRTC allocator will be used. > // May be changed during an active session. The strategy > // ownership is passed with std::unique_ptr > // TODO(alexnarest): Make this pure virtual when tests will be updated > virtual void SetBitrateAllocationStrategy( >- std::unique_ptr<rtc::BitrateAllocationStrategy>) {} >+ std::unique_ptr<rtc::BitrateAllocationStrategy> >+ bitrate_allocation_strategy) {} > > // Enable/disable playout of received audio streams. Enabled by default. Note > // that even if playout is enabled, streams will only be played out if the >@@ -915,13 +967,13 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // for audio data every 10ms to ensure that audio processing happens and the > // audio statistics are updated. > // TODO(henrika): deprecate and remove this. >- virtual void SetAudioPlayout(bool /* playout */) {} >+ virtual void SetAudioPlayout(bool playout) {} > > // Enable/disable recording of transmitted audio streams. Enabled by default. > // Note that even if recording is enabled, streams will only be recorded if > // the appropriate SDP is also applied. > // TODO(henrika): deprecate and remove this. >- virtual void SetAudioRecording(bool /* recording */) {} >+ virtual void SetAudioRecording(bool recording) {} > > // Returns the current SignalingState. > virtual SignalingState signaling_state() = 0; >@@ -940,19 +992,14 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > // automatically after 10 minutes have passed, or when the StopRtcEventLog > // function is called. > // TODO(eladalon): Deprecate and remove this. >- virtual bool StartRtcEventLog(rtc::PlatformFile, >- int64_t /* max_size_bytes */) { >- return false; >- } >+ virtual bool StartRtcEventLog(rtc::PlatformFile file, int64_t max_size_bytes); > > // Start RtcEventLog using an existing output-sink. Takes ownership of > // |output| and passes it on to Call, which will take the ownership. If the > // operation fails the output will be closed and deallocated. The event log > // will send serialized events to the output object every |output_period_ms|. >- virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput>, >- int64_t /* output_period_ms */) { >- return false; >- } >+ virtual bool StartRtcEventLog(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms); > > // Stops logging the RtcEventLog. > // TODO(ivoc): Make this pure virtual when Chrome is updated. >@@ -968,34 +1015,25 @@ class PeerConnectionInterface : public rtc::RefCountInterface { > > protected: > // Dtor protected as objects shouldn't be deleted via this interface. >- ~PeerConnectionInterface() {} >+ ~PeerConnectionInterface() override = default; > }; > > // PeerConnection callback interface, used for RTCPeerConnection events. > // Application should implement these methods. > class PeerConnectionObserver { > public: >- enum StateType { >- kSignalingState, >- kIceState, >- }; >- > virtual ~PeerConnectionObserver() = default; > > // Triggered when the SignalingState changed. > virtual void OnSignalingChange( > PeerConnectionInterface::SignalingState new_state) = 0; > >- // TODO(deadbeef): Once all subclasses override the scoped_refptr versions >- // of the below three methods, make them pure virtual and remove the raw >- // pointer version. >- > // Triggered when media is received on a new stream from remote peer. >- virtual void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) = 0; >+ virtual void OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) {} > >- // Triggered when a remote peer close a stream. >- virtual void OnRemoveStream( >- rtc::scoped_refptr<MediaStreamInterface> stream) = 0; >+ // Triggered when a remote peer closes a stream. >+ virtual void OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) { >+ } > > // Triggered when a remote peer opens a data channel. > virtual void OnDataChannel( >@@ -1025,35 +1063,106 @@ class PeerConnectionObserver { > // TODO(honghaiz): Make this a pure virtual method when all its subclasses > // implement it. > virtual void OnIceCandidatesRemoved( >- const std::vector<cricket::Candidate>&) {} >+ const std::vector<cricket::Candidate>& candidates) {} > > // Called when the ICE connection receiving status changes. >- virtual void OnIceConnectionReceivingChange(bool) {} >+ virtual void OnIceConnectionReceivingChange(bool receiving) {} > >- // This is called when a receiver and its track is created. >+ // This is called when a receiver and its track are created. > // TODO(zhihuang): Make this pure virtual when all subclasses implement it. >+ // Note: This is called with both Plan B and Unified Plan semantics. Unified >+ // Plan users should prefer OnTrack, OnAddTrack is only called as backwards >+ // compatibility (and is called in the exact same situations as OnTrack). > virtual void OnAddTrack( >- rtc::scoped_refptr<RtpReceiverInterface>, >- const std::vector<rtc::scoped_refptr<MediaStreamInterface>>&) {} >- >- // TODO(hbos,deadbeef): Add |OnAssociatedStreamsUpdated| with |receiver| and >- // |streams| as arguments. This should be called when an existing receiver its >- // associated streams updated. https://crbug.com/webrtc/8315 >- // This may be blocked on supporting multiple streams per sender or else >- // this may count as the removal and addition of a track? >- // https://crbug.com/webrtc/7932 >- >- // Called when a receiver is completely removed. This is current (Plan B SDP) >- // behavior that occurs when processing the removal of a remote track, and is >- // called when the receiver is removed and the track is muted. When Unified >- // Plan SDP is supported, transceivers can change direction (and receivers >- // stopped) but receivers are never removed. >+ rtc::scoped_refptr<RtpReceiverInterface> receiver, >+ const std::vector<rtc::scoped_refptr<MediaStreamInterface>>& streams) {} >+ >+ // This is called when signaling indicates a transceiver will be receiving >+ // media from the remote endpoint. This is fired during a call to >+ // SetRemoteDescription. The receiving track can be accessed by: >+ // |transceiver->receiver()->track()| and its associated streams by >+ // |transceiver->receiver()->streams()|. >+ // Note: This will only be called if Unified Plan semantics are specified. >+ // This behavior is specified in section 2.2.8.2.5 of the "Set the >+ // RTCSessionDescription" algorithm: >+ // https://w3c.github.io/webrtc-pc/#set-description >+ virtual void OnTrack( >+ rtc::scoped_refptr<RtpTransceiverInterface> transceiver) {} >+ >+ // Called when signaling indicates that media will no longer be received on a >+ // track. >+ // With Plan B semantics, the given receiver will have been removed from the >+ // PeerConnection and the track muted. >+ // With Unified Plan semantics, the receiver will remain but the transceiver >+ // will have changed direction to either sendonly or inactive. > // https://w3c.github.io/webrtc-pc/#process-remote-track-removal >- // TODO(hbos,deadbeef): When Unified Plan SDP is supported and receivers are >- // no longer removed, deprecate and remove this callback. > // TODO(hbos,deadbeef): Make pure virtual when all subclasses implement it. > virtual void OnRemoveTrack( >- rtc::scoped_refptr<RtpReceiverInterface>) {} >+ rtc::scoped_refptr<RtpReceiverInterface> receiver) {} >+ >+ // Called when an interesting usage is detected by WebRTC. >+ // An appropriate action is to add information about the context of the >+ // PeerConnection and write the event to some kind of "interesting events" >+ // log function. >+ // The heuristics for defining what constitutes "interesting" are >+ // implementation-defined. >+ virtual void OnInterestingUsage(int usage_pattern) {} >+}; >+ >+// PeerConnectionDependencies holds all of PeerConnections dependencies. >+// A dependency is distinct from a configuration as it defines significant >+// executable code that can be provided by a user of the API. >+// >+// All new dependencies should be added as a unique_ptr to allow the >+// PeerConnection object to be the definitive owner of the dependencies >+// lifetime making injection safer. >+struct PeerConnectionDependencies final { >+ explicit PeerConnectionDependencies(PeerConnectionObserver* observer_in); >+ // This object is not copyable or assignable. >+ PeerConnectionDependencies(const PeerConnectionDependencies&) = delete; >+ PeerConnectionDependencies& operator=(const PeerConnectionDependencies&) = >+ delete; >+ // This object is only moveable. >+ PeerConnectionDependencies(PeerConnectionDependencies&&); >+ PeerConnectionDependencies& operator=(PeerConnectionDependencies&&) = default; >+ ~PeerConnectionDependencies(); >+ // Mandatory dependencies >+ PeerConnectionObserver* observer = nullptr; >+ // Optional dependencies >+ std::unique_ptr<cricket::PortAllocator> allocator; >+ std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory; >+ std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator; >+ std::unique_ptr<rtc::SSLCertificateVerifier> tls_cert_verifier; >+}; >+ >+// PeerConnectionFactoryDependencies holds all of the PeerConnectionFactory >+// dependencies. All new dependencies should be added here instead of >+// overloading the function. This simplifies dependency injection and makes it >+// clear which are mandatory and optional. If possible please allow the peer >+// connection factory to take ownership of the dependency by adding a unique_ptr >+// to this structure. >+struct PeerConnectionFactoryDependencies final { >+ PeerConnectionFactoryDependencies(); >+ // This object is not copyable or assignable. >+ PeerConnectionFactoryDependencies(const PeerConnectionFactoryDependencies&) = >+ delete; >+ PeerConnectionFactoryDependencies& operator=( >+ const PeerConnectionFactoryDependencies&) = delete; >+ // This object is only moveable. >+ PeerConnectionFactoryDependencies(PeerConnectionFactoryDependencies&&); >+ PeerConnectionFactoryDependencies& operator=( >+ PeerConnectionFactoryDependencies&&) = default; >+ ~PeerConnectionFactoryDependencies(); >+ >+ // Optional dependencies >+ rtc::Thread* network_thread = nullptr; >+ rtc::Thread* worker_thread = nullptr; >+ rtc::Thread* signaling_thread = nullptr; >+ std::unique_ptr<cricket::MediaEngineInterface> media_engine; >+ std::unique_ptr<CallFactoryInterface> call_factory; >+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory; >+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory; >+ std::unique_ptr<NetworkControllerFactoryInterface> network_controller_factory; > }; > > // PeerConnectionFactoryInterface is the factory interface used for creating >@@ -1108,8 +1217,16 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > // Set the options to be used for subsequently created PeerConnections. > virtual void SetOptions(const Options& options) = 0; > >- // |allocator| and |cert_generator| may be null, in which case default >- // implementations will be used. >+ // The preferred way to create a new peer connection. Simply provide the >+ // configuration and a PeerConnectionDependencies structure. >+ // TODO(benwright): Make pure virtual once downstream mock PC factory classes >+ // are updated. >+ virtual rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection( >+ const PeerConnectionInterface::RTCConfiguration& configuration, >+ PeerConnectionDependencies dependencies); >+ >+ // Deprecated; |allocator| and |cert_generator| may be null, in which case >+ // default implementations will be used. > // > // |observer| must not be null. > // >@@ -1121,7 +1238,7 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > const PeerConnectionInterface::RTCConfiguration& configuration, > std::unique_ptr<cricket::PortAllocator> allocator, > std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, >- PeerConnectionObserver* observer) = 0; >+ PeerConnectionObserver* observer); > > // Deprecated; should use RTCConfiguration for everything that previously > // used constraints. >@@ -1130,19 +1247,27 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > const MediaConstraintsInterface* constraints, > std::unique_ptr<cricket::PortAllocator> allocator, > std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, >- PeerConnectionObserver* observer) = 0; >+ PeerConnectionObserver* observer); >+ >+ // Returns the capabilities of an RTP sender of type |kind|. >+ // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure. >+ // TODO(orphis): Make pure virtual when all subclasses implement it. >+ virtual RtpCapabilities GetRtpSenderCapabilities( >+ cricket::MediaType kind) const; >+ >+ // Returns the capabilities of an RTP receiver of type |kind|. >+ // If for some reason you pass in MEDIA_TYPE_DATA, returns an empty structure. >+ // TODO(orphis): Make pure virtual when all subclasses implement it. >+ virtual RtpCapabilities GetRtpReceiverCapabilities( >+ cricket::MediaType kind) const; > >- virtual rtc::scoped_refptr<MediaStreamInterface> >- CreateLocalMediaStream(const std::string& label) = 0; >+ virtual rtc::scoped_refptr<MediaStreamInterface> CreateLocalMediaStream( >+ const std::string& stream_id) = 0; > > // Creates an AudioSourceInterface. > // |options| decides audio processing settings. > virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource( > const cricket::AudioOptions& options) = 0; >- // Deprecated - use version above. >- // Can use CopyConstraintsIntoAudioOptions to bridge the gap. >- virtual rtc::scoped_refptr<AudioSourceInterface> CreateAudioSource( >- const MediaConstraintsInterface* constraints) = 0; > > // Creates a VideoTrackSourceInterface from |capturer|. > // TODO(deadbeef): We should aim to remove cricket::VideoCapturer from the >@@ -1152,9 +1277,7 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > // TODO(deadbeef): Make pure virtual once downstream mock PC factory classes > // are updated. > virtual rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( >- std::unique_ptr<cricket::VideoCapturer>) { >- return nullptr; >- } >+ std::unique_ptr<cricket::VideoCapturer> capturer); > > // A video source creator that allows selection of resolution and frame rate. > // |constraints| decides video resolution and frame rate but can be null. >@@ -1163,23 +1286,16 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > // |constraints| is only used for the invocation of this method, and can > // safely be destroyed afterwards. > virtual rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( >- std::unique_ptr<cricket::VideoCapturer>, >- const MediaConstraintsInterface*) { >- return nullptr; >- } >+ std::unique_ptr<cricket::VideoCapturer> capturer, >+ const MediaConstraintsInterface* constraints); > > // Deprecated; please use the versions that take unique_ptrs above. > // TODO(deadbeef): Remove these once safe to do so. > virtual rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( >- cricket::VideoCapturer* capturer) { >- return CreateVideoSource(std::unique_ptr<cricket::VideoCapturer>(capturer)); >- } >+ cricket::VideoCapturer* capturer); > virtual rtc::scoped_refptr<VideoTrackSourceInterface> CreateVideoSource( > cricket::VideoCapturer* capturer, >- const MediaConstraintsInterface* constraints) { >- return CreateVideoSource(std::unique_ptr<cricket::VideoCapturer>(capturer), >- constraints); >- } >+ const MediaConstraintsInterface* constraints); > > // Creates a new local VideoTrack. The same |source| can be used in several > // tracks. >@@ -1188,9 +1304,9 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > VideoTrackSourceInterface* source) = 0; > > // Creates an new AudioTrack. At the moment |source| can be null. >- virtual rtc::scoped_refptr<AudioTrackInterface> >- CreateAudioTrack(const std::string& label, >- AudioSourceInterface* source) = 0; >+ virtual rtc::scoped_refptr<AudioTrackInterface> CreateAudioTrack( >+ const std::string& label, >+ AudioSourceInterface* source) = 0; > > // Starts AEC dump using existing file. Takes ownership of |file| and passes > // it on to VoiceEngine (via other objects) immediately, which will take >@@ -1208,7 +1324,7 @@ class PeerConnectionFactoryInterface : public rtc::RefCountInterface { > // Dtor and ctor protected as objects shouldn't be created or deleted via > // this interface. > PeerConnectionFactoryInterface() {} >- ~PeerConnectionFactoryInterface() {} // NOLINT >+ ~PeerConnectionFactoryInterface() override = default; > }; > > // Create a new instance of PeerConnectionFactoryInterface. >@@ -1263,9 +1379,36 @@ rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( > rtc::scoped_refptr<AudioMixer> audio_mixer, > rtc::scoped_refptr<AudioProcessing> audio_processing); > >+// Create a new instance of PeerConnectionFactoryInterface with optional >+// external audio mixer, audio processing, and fec controller modules. >+// >+// If |audio_mixer| is null, an internal audio mixer will be created and used. >+// If |audio_processing| is null, an internal audio processing module will be >+// created and used. >+// If |fec_controller_factory| is null, an internal fec controller module will >+// be created and used. >+// If |network_controller_factory| is provided, it will be used if enabled via >+// field trial. >+rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( >+ rtc::Thread* network_thread, >+ rtc::Thread* worker_thread, >+ rtc::Thread* signaling_thread, >+ AudioDeviceModule* default_adm, >+ rtc::scoped_refptr<AudioEncoderFactory> audio_encoder_factory, >+ rtc::scoped_refptr<AudioDecoderFactory> audio_decoder_factory, >+ cricket::WebRtcVideoEncoderFactory* video_encoder_factory, >+ cricket::WebRtcVideoDecoderFactory* video_decoder_factory, >+ rtc::scoped_refptr<AudioMixer> audio_mixer, >+ rtc::scoped_refptr<AudioProcessing> audio_processing, >+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, >+ std::unique_ptr<NetworkControllerFactoryInterface> >+ network_controller_factory = nullptr); >+ > // Create a new instance of PeerConnectionFactoryInterface with optional video > // codec factories. These video factories represents all video codecs, i.e. no > // extra internal video codecs will be added. >+// When building WebRTC with rtc_use_builtin_sw_codecs = false, this is the >+// only available CreatePeerConnectionFactory overload. > rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory( > rtc::Thread* network_thread, > rtc::Thread* worker_thread, >@@ -1352,6 +1495,22 @@ CreateModularPeerConnectionFactory( > std::unique_ptr<CallFactoryInterface> call_factory, > std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory); > >+rtc::scoped_refptr<PeerConnectionFactoryInterface> >+CreateModularPeerConnectionFactory( >+ rtc::Thread* network_thread, >+ rtc::Thread* worker_thread, >+ rtc::Thread* signaling_thread, >+ std::unique_ptr<cricket::MediaEngineInterface> media_engine, >+ std::unique_ptr<CallFactoryInterface> call_factory, >+ std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory, >+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory, >+ std::unique_ptr<NetworkControllerFactoryInterface> >+ network_controller_factory = nullptr); >+ >+rtc::scoped_refptr<PeerConnectionFactoryInterface> >+CreateModularPeerConnectionFactory( >+ PeerConnectionFactoryDependencies dependencies); >+ > } // namespace webrtc > > #endif // API_PEERCONNECTIONINTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionproxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionproxy.h >index 7235f5b4b2f..7fc5e1716aa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionproxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/peerconnectionproxy.h >@@ -23,124 +23,124 @@ namespace webrtc { > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_SIGNALING_PROXY_MAP(PeerConnection) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams) >- PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams) >- PROXY_METHOD1(bool, AddStream, MediaStreamInterface*) >- PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) >- PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>, >- AddTrack, >- rtc::scoped_refptr<MediaStreamTrackInterface>, >- const std::vector<std::string>&); >- PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>, >- AddTrack, >- MediaStreamTrackInterface*, >- std::vector<MediaStreamInterface*>) >- PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*) >- PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >- AddTransceiver, >- rtc::scoped_refptr<MediaStreamTrackInterface>) >- PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >- AddTransceiver, >- rtc::scoped_refptr<MediaStreamTrackInterface>, >- const RtpTransceiverInit&) >- PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >- AddTransceiver, >- cricket::MediaType) >- PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >- AddTransceiver, >- cricket::MediaType, >- const RtpTransceiverInit&) >- PROXY_METHOD1(rtc::scoped_refptr<DtmfSenderInterface>, >- CreateDtmfSender, >- AudioTrackInterface*) >- PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>, >- CreateSender, >- const std::string&, >- const std::string&) >- PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>, >- GetSenders) >- PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>, >- GetReceivers) >- PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>, >- GetTransceivers) >- PROXY_METHOD3(bool, >- GetStats, >- StatsObserver*, >- MediaStreamTrackInterface*, >- StatsOutputLevel) >- PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*) >- PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>, >- CreateDataChannel, >- const std::string&, >- const DataChannelInit*) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >- pending_local_description) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >- pending_remote_description) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >- current_local_description) >- PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >- current_remote_description) >- PROXY_METHOD2(void, >- CreateOffer, >- CreateSessionDescriptionObserver*, >- const MediaConstraintsInterface*) >- PROXY_METHOD2(void, >- CreateAnswer, >- CreateSessionDescriptionObserver*, >- const MediaConstraintsInterface*) >- PROXY_METHOD2(void, >- CreateOffer, >- CreateSessionDescriptionObserver*, >- const RTCOfferAnswerOptions&) >- PROXY_METHOD2(void, >- CreateAnswer, >- CreateSessionDescriptionObserver*, >- const RTCOfferAnswerOptions&) >- PROXY_METHOD2(void, >- SetLocalDescription, >- SetSessionDescriptionObserver*, >- SessionDescriptionInterface*) >- PROXY_METHOD2(void, >- SetRemoteDescription, >- SetSessionDescriptionObserver*, >- SessionDescriptionInterface*) >- PROXY_METHOD2(void, >- SetRemoteDescription, >- std::unique_ptr<SessionDescriptionInterface>, >- rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>); >- PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration); >- PROXY_METHOD2(bool, >- SetConfiguration, >- const PeerConnectionInterface::RTCConfiguration&, >- RTCError*); >- PROXY_METHOD1(bool, >- SetConfiguration, >- const PeerConnectionInterface::RTCConfiguration&); >- PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*) >- PROXY_METHOD1(bool, >- RemoveIceCandidates, >- const std::vector<cricket::Candidate>&); >- PROXY_METHOD1(void, SetAudioPlayout, bool) >- PROXY_METHOD1(void, SetAudioRecording, bool) >- PROXY_METHOD1(void, RegisterUMAObserver, UMAObserver*) >- PROXY_METHOD1(RTCError, SetBitrate, const BitrateParameters&); >- PROXY_METHOD1(void, >- SetBitrateAllocationStrategy, >- std::unique_ptr<rtc::BitrateAllocationStrategy>); >- PROXY_METHOD0(SignalingState, signaling_state) >- PROXY_METHOD0(IceConnectionState, ice_connection_state) >- PROXY_METHOD0(IceGatheringState, ice_gathering_state) >- PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t) >- PROXY_METHOD2(bool, >- StartRtcEventLog, >- std::unique_ptr<RtcEventLogOutput>, >- int64_t); >- PROXY_METHOD0(void, StopRtcEventLog) >- PROXY_METHOD0(void, Close) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, local_streams) >+PROXY_METHOD0(rtc::scoped_refptr<StreamCollectionInterface>, remote_streams) >+PROXY_METHOD1(bool, AddStream, MediaStreamInterface*) >+PROXY_METHOD1(void, RemoveStream, MediaStreamInterface*) >+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>, >+ AddTrack, >+ rtc::scoped_refptr<MediaStreamTrackInterface>, >+ const std::vector<std::string>&); >+PROXY_METHOD1(bool, RemoveTrack, RtpSenderInterface*) >+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >+ AddTransceiver, >+ rtc::scoped_refptr<MediaStreamTrackInterface>) >+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >+ AddTransceiver, >+ rtc::scoped_refptr<MediaStreamTrackInterface>, >+ const RtpTransceiverInit&) >+PROXY_METHOD1(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >+ AddTransceiver, >+ cricket::MediaType) >+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>, >+ AddTransceiver, >+ cricket::MediaType, >+ const RtpTransceiverInit&) >+PROXY_METHOD2(rtc::scoped_refptr<RtpSenderInterface>, >+ CreateSender, >+ const std::string&, >+ const std::string&) >+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpSenderInterface>>, >+ GetSenders) >+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpReceiverInterface>>, >+ GetReceivers) >+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>, >+ GetTransceivers) >+PROXY_METHOD3(bool, >+ GetStats, >+ StatsObserver*, >+ MediaStreamTrackInterface*, >+ StatsOutputLevel) >+PROXY_METHOD1(void, GetStats, RTCStatsCollectorCallback*) >+PROXY_METHOD2(void, >+ GetStats, >+ rtc::scoped_refptr<RtpSenderInterface>, >+ rtc::scoped_refptr<RTCStatsCollectorCallback>); >+PROXY_METHOD2(void, >+ GetStats, >+ rtc::scoped_refptr<RtpReceiverInterface>, >+ rtc::scoped_refptr<RTCStatsCollectorCallback>); >+PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>, >+ CreateDataChannel, >+ const std::string&, >+ const DataChannelInit*) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, remote_description) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >+ pending_local_description) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >+ pending_remote_description) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >+ current_local_description) >+PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, >+ current_remote_description) >+PROXY_METHOD2(void, >+ CreateOffer, >+ CreateSessionDescriptionObserver*, >+ const MediaConstraintsInterface*) >+PROXY_METHOD2(void, >+ CreateAnswer, >+ CreateSessionDescriptionObserver*, >+ const MediaConstraintsInterface*) >+PROXY_METHOD2(void, >+ CreateOffer, >+ CreateSessionDescriptionObserver*, >+ const RTCOfferAnswerOptions&) >+PROXY_METHOD2(void, >+ CreateAnswer, >+ CreateSessionDescriptionObserver*, >+ const RTCOfferAnswerOptions&) >+PROXY_METHOD2(void, >+ SetLocalDescription, >+ SetSessionDescriptionObserver*, >+ SessionDescriptionInterface*) >+PROXY_METHOD2(void, >+ SetRemoteDescription, >+ SetSessionDescriptionObserver*, >+ SessionDescriptionInterface*) >+PROXY_METHOD2(void, >+ SetRemoteDescription, >+ std::unique_ptr<SessionDescriptionInterface>, >+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>); >+PROXY_METHOD0(PeerConnectionInterface::RTCConfiguration, GetConfiguration); >+PROXY_METHOD2(bool, >+ SetConfiguration, >+ const PeerConnectionInterface::RTCConfiguration&, >+ RTCError*); >+PROXY_METHOD1(bool, >+ SetConfiguration, >+ const PeerConnectionInterface::RTCConfiguration&); >+PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*) >+PROXY_METHOD1(bool, >+ RemoveIceCandidates, >+ const std::vector<cricket::Candidate>&); >+PROXY_METHOD1(void, SetAudioPlayout, bool) >+PROXY_METHOD1(void, SetAudioRecording, bool) >+PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&); >+PROXY_METHOD1(void, >+ SetBitrateAllocationStrategy, >+ std::unique_ptr<rtc::BitrateAllocationStrategy>); >+PROXY_METHOD0(SignalingState, signaling_state) >+PROXY_METHOD0(IceConnectionState, ice_connection_state) >+PROXY_METHOD0(IceGatheringState, ice_gathering_state) >+PROXY_METHOD2(bool, StartRtcEventLog, rtc::PlatformFile, int64_t) >+PROXY_METHOD2(bool, >+ StartRtcEventLog, >+ std::unique_ptr<RtcEventLogOutput>, >+ int64_t); >+PROXY_METHOD0(void, StopRtcEventLog) >+PROXY_METHOD0(void, Close) > END_PROXY_MAP() > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/proxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/proxy.h >index dd7182e5546..c8962efed7c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/proxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/proxy.h >@@ -64,8 +64,10 @@ namespace webrtc { > template <typename R> > class ReturnType { > public: >- template<typename C, typename M> >- void Invoke(C* c, M m) { r_ = (c->*m)(); } >+ template <typename C, typename M> >+ void Invoke(C* c, M m) { >+ r_ = (c->*m)(); >+ } > template <typename C, typename M, typename T1> > void Invoke(C* c, M m, T1 a1) { > r_ = (c->*m)(std::move(a1)); >@@ -78,13 +80,22 @@ class ReturnType { > void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3) { > r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3)); > } >- template<typename C, typename M, typename T1, typename T2, typename T3, >- typename T4> >+ template <typename C, >+ typename M, >+ typename T1, >+ typename T2, >+ typename T3, >+ typename T4> > void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4) { > r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3), std::move(a4)); > } >- template<typename C, typename M, typename T1, typename T2, typename T3, >- typename T4, typename T5> >+ template <typename C, >+ typename M, >+ typename T1, >+ typename T2, >+ typename T3, >+ typename T4, >+ typename T5> > void Invoke(C* c, M m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) { > r_ = (c->*m)(std::move(a1), std::move(a2), std::move(a3), std::move(a4), > std::move(a5)); >@@ -99,8 +110,10 @@ class ReturnType { > template <> > class ReturnType<void> { > public: >- template<typename C, typename M> >- void Invoke(C* c, M m) { (c->*m)(); } >+ template <typename C, typename M> >+ void Invoke(C* c, M m) { >+ (c->*m)(); >+ } > template <typename C, typename M, typename T1> > void Invoke(C* c, M m, T1 a1) { > (c->*m)(std::move(a1)); >@@ -119,9 +132,8 @@ class ReturnType<void> { > > namespace internal { > >-class SynchronousMethodCall >- : public rtc::MessageData, >- public rtc::MessageHandler { >+class SynchronousMethodCall : public rtc::MessageData, >+ public rtc::MessageHandler { > public: > explicit SynchronousMethodCall(rtc::MessageHandler* proxy); > ~SynchronousMethodCall() override; >@@ -138,8 +150,7 @@ class SynchronousMethodCall > } // namespace internal > > template <typename C, typename R> >-class MethodCall0 : public rtc::Message, >- public rtc::MessageHandler { >+class MethodCall0 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(); > MethodCall0(C* c, Method m) : c_(c), m_(m) {} >@@ -150,7 +161,7 @@ class MethodCall0 : public rtc::Message, > } > > private: >- void OnMessage(rtc::Message*) { r_.Invoke(c_, m_); } >+ void OnMessage(rtc::Message*) { r_.Invoke(c_, m_); } > > C* c_; > Method m_; >@@ -158,8 +169,7 @@ class MethodCall0 : public rtc::Message, > }; > > template <typename C, typename R> >-class ConstMethodCall0 : public rtc::Message, >- public rtc::MessageHandler { >+class ConstMethodCall0 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)() const; > ConstMethodCall0(C* c, Method m) : c_(c), m_(m) {} >@@ -177,9 +187,8 @@ class ConstMethodCall0 : public rtc::Message, > ReturnType<R> r_; > }; > >-template <typename C, typename R, typename T1> >-class MethodCall1 : public rtc::Message, >- public rtc::MessageHandler { >+template <typename C, typename R, typename T1> >+class MethodCall1 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1); > MethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(std::move(a1)) {} >@@ -198,9 +207,8 @@ class MethodCall1 : public rtc::Message, > T1 a1_; > }; > >-template <typename C, typename R, typename T1> >-class ConstMethodCall1 : public rtc::Message, >- public rtc::MessageHandler { >+template <typename C, typename R, typename T1> >+class ConstMethodCall1 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1) const; > ConstMethodCall1(C* c, Method m, T1 a1) : c_(c), m_(m), a1_(std::move(a1)) {} >@@ -220,8 +228,7 @@ class ConstMethodCall1 : public rtc::Message, > }; > > template <typename C, typename R, typename T1, typename T2> >-class MethodCall2 : public rtc::Message, >- public rtc::MessageHandler { >+class MethodCall2 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1, T2 a2); > MethodCall2(C* c, Method m, T1 a1, T2 a2) >@@ -245,8 +252,7 @@ class MethodCall2 : public rtc::Message, > }; > > template <typename C, typename R, typename T1, typename T2, typename T3> >-class MethodCall3 : public rtc::Message, >- public rtc::MessageHandler { >+class MethodCall3 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1, T2 a2, T3 a3); > MethodCall3(C* c, Method m, T1 a1, T2 a2, T3 a3) >@@ -274,10 +280,13 @@ class MethodCall3 : public rtc::Message, > T3 a3_; > }; > >-template <typename C, typename R, typename T1, typename T2, typename T3, >- typename T4> >-class MethodCall4 : public rtc::Message, >- public rtc::MessageHandler { >+template <typename C, >+ typename R, >+ typename T1, >+ typename T2, >+ typename T3, >+ typename T4> >+class MethodCall4 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4); > MethodCall4(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4) >@@ -308,10 +317,14 @@ class MethodCall4 : public rtc::Message, > T4 a4_; > }; > >-template <typename C, typename R, typename T1, typename T2, typename T3, >- typename T4, typename T5> >-class MethodCall5 : public rtc::Message, >- public rtc::MessageHandler { >+template <typename C, >+ typename R, >+ typename T1, >+ typename T2, >+ typename T3, >+ typename T4, >+ typename T5> >+class MethodCall5 : public rtc::Message, public rtc::MessageHandler { > public: > typedef R (C::*Method)(T1 a1, T2 a2, T3 a3, T4 a4, T5 a5); > MethodCall5(C* c, Method m, T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) >@@ -344,7 +357,6 @@ class MethodCall5 : public rtc::Message, > T5 a5_; > }; > >- > // Helper macros to reduce code duplication. > #define PROXY_MAP_BOILERPLATE(c) \ > template <class INTERNAL_CLASS> \ >@@ -359,8 +371,12 @@ class MethodCall5 : public rtc::Message, > const INTERNAL_CLASS* internal() const { return c_; } \ > INTERNAL_CLASS* internal() { return c_; } > >+// clang-format off >+// clang-format would put the semicolon alone, >+// leading to a presubmit error (cpplint.py) > #define END_PROXY_MAP() \ > }; >+// clang-format on > > #define SIGNALING_PROXY_MAP_BOILERPLATE(c) \ > protected: \ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.cc >index f9a31d08934..55ac15e196b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.cc >@@ -93,9 +93,10 @@ void RTCError::set_message(std::string&& message) { > } > } > >-std::ostream& operator<<(std::ostream& stream, RTCErrorType error) { >+// TODO(jonasolsson): Change to use absl::string_view when it's available. >+std::string ToString(RTCErrorType error) { > int index = static_cast<int>(error); >- return stream << kRTCErrorTypeNames[index]; >+ return std::string(kRTCErrorTypeNames[index]); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.h >index 962f46dd818..c87ce916501 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror.h >@@ -11,7 +11,9 @@ > #ifndef API_RTCERROR_H_ > #define API_RTCERROR_H_ > >+#ifdef UNIT_TEST > #include <ostream> >+#endif // UNIT_TEST > #include <string> > #include <utility> // For std::move. > >@@ -143,16 +145,24 @@ class RTCError { > // error type. > // > // Only intended to be used for logging/disagnostics. >-std::ostream& operator<<(std::ostream& stream, RTCErrorType error); >+std::string ToString(RTCErrorType error); >+ >+#ifdef UNIT_TEST >+inline std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982) >+ std::ostream& stream, // no-presubmit-check TODO(webrtc:8982) >+ RTCErrorType error) { >+ return stream << ToString(error); >+} >+#endif // UNIT_TEST > > // Helper macro that can be used by implementations to create an error with a > // message and log it. |message| should be a string literal or movable > // std::string. >-#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \ >- { \ >- RTC_DCHECK(type != RTCErrorType::NONE); \ >- RTC_LOG(severity) << message << " (" << type << ")"; \ >- return webrtc::RTCError(type, message); \ >+#define LOG_AND_RETURN_ERROR_EX(type, message, severity) \ >+ { \ >+ RTC_DCHECK(type != RTCErrorType::NONE); \ >+ RTC_LOG(severity) << message << " (" << ToString(type) << ")"; \ >+ return webrtc::RTCError(type, message); \ > } > > #define LOG_AND_RETURN_ERROR(type, message) \ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror_unittest.cc >index d8f7ca6d49d..90593cf5246 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtcerror_unittest.cc >@@ -58,15 +58,6 @@ struct MoveOnlyInt2 { > > namespace webrtc { > >-// Simple test for ostream operator for RTCErrorType. >-TEST(RTCErrorTypeTest, OstreamOperator) { >- std::ostringstream oss; >- oss << webrtc::RTCErrorType::NONE << ' ' >- << webrtc::RTCErrorType::INVALID_PARAMETER << ' ' >- << webrtc::RTCErrorType::INTERNAL_ERROR; >- EXPECT_EQ("NONE INVALID_PARAMETER INTERNAL_ERROR", oss.str()); >-} >- > // Test that the default constructor creates a "no error" error. > TEST(RTCErrorTest, DefaultConstructor) { > RTCError e; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtp_headers.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtp_headers.h >index 2624a33e5f5..c762534ab3a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtp_headers.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtp_headers.h >@@ -13,20 +13,18 @@ > > #include <stddef.h> > #include <string.h> >-#include <ostream> > #include <string> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/array_view.h" >-#include "api/optional.h" > #include "api/video/video_content_type.h" > #include "api/video/video_rotation.h" > #include "api/video/video_timing.h" > >+#include "common_types.h" // NOLINT(build/include) > #include "rtc_base/checks.h" > #include "rtc_base/deprecation.h" >-#include "common_types.h" // NOLINT(build/include) >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -41,7 +39,14 @@ class StringRtpHeaderExtension { > // maximum length that can be encoded with one-byte header extensions. > static constexpr size_t kMaxSize = 16; > >- static bool IsLegalName(rtc::ArrayView<const char> name); >+ static bool IsLegalMidName(rtc::ArrayView<const char> name); >+ static bool IsLegalRsidName(rtc::ArrayView<const char> name); >+ >+ // TODO(bugs.webrtc.org/9537): Deprecate and remove when third parties have >+ // migrated to "IsLegalRsidName". >+ static bool IsLegalName(rtc::ArrayView<const char> name) { >+ return IsLegalRsidName(name); >+ } > > StringRtpHeaderExtension() { value_[0] = 0; } > explicit StringRtpHeaderExtension(rtc::ArrayView<const char> value) { >@@ -103,7 +108,7 @@ struct RTPHeaderExtension { > bool hasVideoRotation; > VideoRotation videoRotation; > >- // TODO(ilnik): Refactor this and one above to be rtc::Optional() and remove >+ // TODO(ilnik): Refactor this and one above to be absl::optional() and remove > // a corresponding bool flag. > bool hasVideoContentType; > VideoContentType videoContentType; >@@ -168,11 +173,6 @@ struct RtpKeepAliveConfig final { > bool operator!=(const RtpKeepAliveConfig& o) const { return !(*this == o); } > }; > >-// Currently only VP8/VP9 specific. >-struct RtpPayloadState { >- int16_t picture_id = -1; >-}; >- > } // namespace webrtc > > #endif // API_RTP_HEADERS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.cc >index 79fd3a93f93..62ca3fc0254 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.cc >@@ -10,26 +10,27 @@ > #include "api/rtpparameters.h" > > #include <algorithm> >-#include <sstream> > #include <string> > > #include "rtc_base/checks.h" >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > > const double kDefaultBitratePriority = 1.0; > >-RtcpFeedback::RtcpFeedback() {} >+RtcpFeedback::RtcpFeedback() = default; > RtcpFeedback::RtcpFeedback(RtcpFeedbackType type) : type(type) {} > RtcpFeedback::RtcpFeedback(RtcpFeedbackType type, > RtcpFeedbackMessageType message_type) > : type(type), message_type(message_type) {} >-RtcpFeedback::~RtcpFeedback() {} >+RtcpFeedback::RtcpFeedback(const RtcpFeedback& rhs) = default; >+RtcpFeedback::~RtcpFeedback() = default; > >-RtpCodecCapability::RtpCodecCapability() {} >-RtpCodecCapability::~RtpCodecCapability() {} >+RtpCodecCapability::RtpCodecCapability() = default; >+RtpCodecCapability::~RtpCodecCapability() = default; > >-RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() {} >+RtpHeaderExtensionCapability::RtpHeaderExtensionCapability() = default; > RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( > const std::string& uri) > : uri(uri) {} >@@ -37,46 +38,57 @@ RtpHeaderExtensionCapability::RtpHeaderExtensionCapability( > const std::string& uri, > int preferred_id) > : uri(uri), preferred_id(preferred_id) {} >-RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() {} >+RtpHeaderExtensionCapability::~RtpHeaderExtensionCapability() = default; > >-RtpExtension::RtpExtension() {} >+RtpExtension::RtpExtension() = default; > RtpExtension::RtpExtension(const std::string& uri, int id) : uri(uri), id(id) {} > RtpExtension::RtpExtension(const std::string& uri, int id, bool encrypt) > : uri(uri), id(id), encrypt(encrypt) {} >-RtpExtension::~RtpExtension() {} >+RtpExtension::~RtpExtension() = default; > >-RtpFecParameters::RtpFecParameters() {} >+RtpFecParameters::RtpFecParameters() = default; > RtpFecParameters::RtpFecParameters(FecMechanism mechanism) > : mechanism(mechanism) {} > RtpFecParameters::RtpFecParameters(FecMechanism mechanism, uint32_t ssrc) > : ssrc(ssrc), mechanism(mechanism) {} >-RtpFecParameters::~RtpFecParameters() {} >+RtpFecParameters::RtpFecParameters(const RtpFecParameters& rhs) = default; >+RtpFecParameters::~RtpFecParameters() = default; > >-RtpRtxParameters::RtpRtxParameters() {} >+RtpRtxParameters::RtpRtxParameters() = default; > RtpRtxParameters::RtpRtxParameters(uint32_t ssrc) : ssrc(ssrc) {} >-RtpRtxParameters::~RtpRtxParameters() {} >+RtpRtxParameters::RtpRtxParameters(const RtpRtxParameters& rhs) = default; >+RtpRtxParameters::~RtpRtxParameters() = default; > >-RtpEncodingParameters::RtpEncodingParameters() {} >-RtpEncodingParameters::~RtpEncodingParameters() {} >+RtpEncodingParameters::RtpEncodingParameters() = default; >+RtpEncodingParameters::RtpEncodingParameters(const RtpEncodingParameters& rhs) = >+ default; >+RtpEncodingParameters::~RtpEncodingParameters() = default; > >-RtpCodecParameters::RtpCodecParameters() {} >-RtpCodecParameters::~RtpCodecParameters() {} >+RtpCodecParameters::RtpCodecParameters() = default; >+RtpCodecParameters::RtpCodecParameters(const RtpCodecParameters& rhs) = default; >+RtpCodecParameters::~RtpCodecParameters() = default; > >-RtpCapabilities::RtpCapabilities() {} >-RtpCapabilities::~RtpCapabilities() {} >+RtpCapabilities::RtpCapabilities() = default; >+RtpCapabilities::~RtpCapabilities() = default; > >-RtpParameters::RtpParameters() {} >-RtpParameters::~RtpParameters() {} >+RtcpParameters::RtcpParameters() = default; >+RtcpParameters::RtcpParameters(const RtcpParameters& rhs) = default; >+RtcpParameters::~RtcpParameters() = default; >+ >+RtpParameters::RtpParameters() = default; >+RtpParameters::RtpParameters(const RtpParameters& rhs) = default; >+RtpParameters::~RtpParameters() = default; > > std::string RtpExtension::ToString() const { >- std::stringstream ss; >- ss << "{uri: " << uri; >- ss << ", id: " << id; >+ char buf[256]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "{uri: " << uri; >+ sb << ", id: " << id; > if (encrypt) { >- ss << ", encrypt"; >+ sb << ", encrypt"; > } >- ss << '}'; >- return ss.str(); >+ sb << '}'; >+ return sb.str(); > } > > const char RtpExtension::kAudioLevelUri[] = >@@ -114,6 +126,9 @@ const char RtpExtension::kVideoTimingUri[] = > "http://www.webrtc.org/experiments/rtp-hdrext/video-timing"; > const int RtpExtension::kVideoTimingDefaultId = 8; > >+const char RtpExtension::kMidUri[] = "urn:ietf:params:rtp-hdrext:sdes:mid"; >+const int RtpExtension::kMidDefaultId = 9; >+ > const char RtpExtension::kEncryptHeaderExtensionsUri[] = > "urn:ietf:params:rtp-hdrext:encrypt"; > >@@ -122,7 +137,8 @@ const int RtpExtension::kMaxId = 14; > > bool RtpExtension::IsSupportedForAudio(const std::string& uri) { > return uri == webrtc::RtpExtension::kAudioLevelUri || >- uri == webrtc::RtpExtension::kTransportSequenceNumberUri; >+ uri == webrtc::RtpExtension::kTransportSequenceNumberUri || >+ uri == webrtc::RtpExtension::kMidUri; > } > > bool RtpExtension::IsSupportedForVideo(const std::string& uri) { >@@ -132,7 +148,8 @@ bool RtpExtension::IsSupportedForVideo(const std::string& uri) { > uri == webrtc::RtpExtension::kTransportSequenceNumberUri || > uri == webrtc::RtpExtension::kPlayoutDelayUri || > uri == webrtc::RtpExtension::kVideoContentTypeUri || >- uri == webrtc::RtpExtension::kVideoTimingUri; >+ uri == webrtc::RtpExtension::kVideoTimingUri || >+ uri == webrtc::RtpExtension::kMidUri; > } > > bool RtpExtension::IsEncryptionSupported(const std::string& uri) { >@@ -149,7 +166,8 @@ bool RtpExtension::IsEncryptionSupported(const std::string& uri) { > uri == webrtc::RtpExtension::kVideoRotationUri || > uri == webrtc::RtpExtension::kTransportSequenceNumberUri || > uri == webrtc::RtpExtension::kPlayoutDelayUri || >- uri == webrtc::RtpExtension::kVideoContentTypeUri; >+ uri == webrtc::RtpExtension::kVideoContentTypeUri || >+ uri == webrtc::RtpExtension::kMidUri; > } > > const RtpExtension* RtpExtension::FindHeaderExtensionByUri( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.h >index e3408258605..9a29c08d1c9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpparameters.h >@@ -15,8 +15,8 @@ > #include <unordered_map> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/mediatypes.h" >-#include "api/optional.h" > > namespace webrtc { > >@@ -66,9 +66,22 @@ enum class DtxStatus { > ENABLED, > }; > >+// Based on the spec in >+// https://w3c.github.io/webrtc-pc/#idl-def-rtcdegradationpreference. >+// These options are enforced on a best-effort basis. For instance, all of >+// these options may suffer some frame drops in order to avoid queuing. >+// TODO(sprang): Look into possibility of more strictly enforcing the >+// maintain-framerate option. >+// TODO(deadbeef): Default to "balanced", as the spec indicates? > enum class DegradationPreference { >+ // Don't take any actions based on over-utilization signals. Not part of the >+ // web API. >+ DISABLED, >+ // On over-use, request lower frame rate, possibly causing frame drops. > MAINTAIN_FRAMERATE, >+ // On over-use, request lower resolution, possibly causing down-scaling. > MAINTAIN_RESOLUTION, >+ // Try to strike a "pleasing" balance between frame rate or resolution. > BALANCED, > }; > >@@ -81,12 +94,13 @@ struct RtcpFeedback { > // 1. It's an enum instead of a string. > // 2. Generic NACK feedback is represented by a GENERIC_NACK message type, > // rather than an unset "parameter" value. >- rtc::Optional<RtcpFeedbackMessageType> message_type; >+ absl::optional<RtcpFeedbackMessageType> message_type; > > // Constructors for convenience. > RtcpFeedback(); > explicit RtcpFeedback(RtcpFeedbackType type); > RtcpFeedback(RtcpFeedbackType type, RtcpFeedbackMessageType message_type); >+ RtcpFeedback(const RtcpFeedback&); > ~RtcpFeedback(); > > bool operator==(const RtcpFeedback& o) const { >@@ -112,23 +126,23 @@ struct RtpCodecCapability { > cricket::MediaType kind = cricket::MEDIA_TYPE_AUDIO; > > // Clock rate in Hertz. If unset, the codec is applicable to any clock rate. >- rtc::Optional<int> clock_rate; >+ absl::optional<int> clock_rate; > > // Default payload type for this codec. Mainly needed for codecs that use > // that have statically assigned payload types. >- rtc::Optional<int> preferred_payload_type; >+ absl::optional<int> preferred_payload_type; > > // Maximum packetization time supported by an RtpReceiver for this codec. > // TODO(deadbeef): Not implemented. >- rtc::Optional<int> max_ptime; >+ absl::optional<int> max_ptime; > > // Preferred packetization time for an RtpReceiver or RtpSender of this > // codec. > // TODO(deadbeef): Not implemented. >- rtc::Optional<int> ptime; >+ absl::optional<int> ptime; > > // The number of audio channels supported. Unused for video codecs. >- rtc::Optional<int> num_channels; >+ absl::optional<int> num_channels; > > // Feedback mechanisms supported for this codec. > std::vector<RtcpFeedback> rtcp_feedback; >@@ -191,7 +205,7 @@ struct RtpHeaderExtensionCapability { > std::string uri; > > // Preferred value of ID that goes in the packet. >- rtc::Optional<int> preferred_id; >+ absl::optional<int> preferred_id; > > // If true, it's preferred that the value in the header is encrypted. > // TODO(deadbeef): Not implemented. >@@ -276,6 +290,11 @@ struct RtpExtension { > static const char kPlayoutDelayUri[]; > static const int kPlayoutDelayDefaultId; > >+ // Header extension for identifying media section within a transport. >+ // https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-49#section-15 >+ static const char kMidUri[]; >+ static const int kMidDefaultId; >+ > // Encryption of Header Extensions, see RFC 6904 for details: > // https://tools.ietf.org/html/rfc6904 > static const char kEncryptHeaderExtensionsUri[]; >@@ -295,7 +314,7 @@ typedef RtpExtension RtpHeaderExtensionParameters; > struct RtpFecParameters { > // If unset, a value is chosen by the implementation. > // Works just like RtpEncodingParameters::ssrc. >- rtc::Optional<uint32_t> ssrc; >+ absl::optional<uint32_t> ssrc; > > FecMechanism mechanism = FecMechanism::RED; > >@@ -303,6 +322,7 @@ struct RtpFecParameters { > RtpFecParameters(); > explicit RtpFecParameters(FecMechanism mechanism); > RtpFecParameters(FecMechanism mechanism, uint32_t ssrc); >+ RtpFecParameters(const RtpFecParameters&); > ~RtpFecParameters(); > > bool operator==(const RtpFecParameters& o) const { >@@ -314,11 +334,12 @@ struct RtpFecParameters { > struct RtpRtxParameters { > // If unset, a value is chosen by the implementation. > // Works just like RtpEncodingParameters::ssrc. >- rtc::Optional<uint32_t> ssrc; >+ absl::optional<uint32_t> ssrc; > > // Constructors for convenience. > RtpRtxParameters(); > explicit RtpRtxParameters(uint32_t ssrc); >+ RtpRtxParameters(const RtpRtxParameters&); > ~RtpRtxParameters(); > > bool operator==(const RtpRtxParameters& o) const { return ssrc == o.ssrc; } >@@ -327,6 +348,7 @@ struct RtpRtxParameters { > > struct RtpEncodingParameters { > RtpEncodingParameters(); >+ RtpEncodingParameters(const RtpEncodingParameters&); > ~RtpEncodingParameters(); > > // If unset, a value is chosen by the implementation. >@@ -335,7 +357,7 @@ struct RtpEncodingParameters { > // may change due to an SSRC conflict, in which case the conflict is handled > // internally without any event. Another way of looking at this is that an > // unset SSRC acts as a "wildcard" SSRC. >- rtc::Optional<uint32_t> ssrc; >+ absl::optional<uint32_t> ssrc; > > // Can be used to reference a codec in the |codecs| member of the > // RtpParameters that contains this RtpEncodingParameters. If unset, the >@@ -343,32 +365,45 @@ struct RtpEncodingParameters { > // prepare to receive any codec (for a receiver). > // TODO(deadbeef): Not implemented. Implementation of RtpSender will always > // choose the first codec from the list. >- rtc::Optional<int> codec_payload_type; >+ absl::optional<int> codec_payload_type; > > // Specifies the FEC mechanism, if set. > // TODO(deadbeef): Not implemented. Current implementation will use whatever > // FEC codecs are available, including red+ulpfec. >- rtc::Optional<RtpFecParameters> fec; >+ absl::optional<RtpFecParameters> fec; > > // Specifies the RTX parameters, if set. > // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. >- rtc::Optional<RtpRtxParameters> rtx; >+ absl::optional<RtpRtxParameters> rtx; > > // Only used for audio. If set, determines whether or not discontinuous > // transmission will be used, if an available codec supports it. If not > // set, the implementation default setting will be used. > // TODO(deadbeef): Not implemented. Current implementation will use a CN > // codec as long as it's present. >- rtc::Optional<DtxStatus> dtx; >+ absl::optional<DtxStatus> dtx; > > // The relative bitrate priority of this encoding. Currently this is >- // implemented on the sender level (using the first RtpEncodingParameters >- // of the rtp parameters). >+ // implemented for the entire rtp sender by using the value of the first >+ // encoding parameter. >+ // TODO(webrtc.bugs.org/8630): Implement this per encoding parameter. >+ // Currently there is logic for how bitrate is distributed per simulcast layer >+ // in the VideoBitrateAllocator. This must be updated to incorporate relative >+ // bitrate priority. > double bitrate_priority = kDefaultBitratePriority; > >+ // Indicates the preferred duration of media represented by a packet in >+ // milliseconds for this encoding. If set, this will take precedence over the >+ // ptime set in the RtpCodecParameters. This could happen if SDP negotiation >+ // creates a ptime for a specific codec, which is later changed in the >+ // RtpEncodingParameters by the application. >+ // TODO(bugs.webrtc.org/8819): Not implemented. >+ absl::optional<int> ptime; >+ > // If set, this represents the Transport Independent Application Specific > // maximum bandwidth defined in RFC3890. If unset, there is no maximum >- // bitrate. >+ // bitrate. Currently this is implemented for the entire rtp sender by using >+ // the value of the first encoding parameter. > // > // Just called "maxBitrate" in ORTC spec. > // >@@ -376,23 +411,29 @@ struct RtpEncodingParameters { > // bandwidth for the entire bandwidth estimator (audio and video). This is > // just always how "b=AS" was handled, but it's not correct and should be > // fixed. >- rtc::Optional<int> max_bitrate_bps; >+ absl::optional<int> max_bitrate_bps; >+ >+ // Specifies the minimum bitrate in bps for video. >+ // TODO(asapersson): Not implemented for ORTC API. >+ absl::optional<int> min_bitrate_bps; > > // TODO(deadbeef): Not implemented. >- rtc::Optional<int> max_framerate; >+ absl::optional<int> max_framerate; > > // For video, scale the resolution down by this factor. > // TODO(deadbeef): Not implemented. >- double scale_resolution_down_by = 1.0; >+ absl::optional<double> scale_resolution_down_by; > > // Scale the framerate down by this factor. > // TODO(deadbeef): Not implemented. >- double scale_framerate_down_by = 1.0; >- >- // For an RtpSender, set to true to cause this encoding to be sent, and false >- // for it not to be sent. For an RtpReceiver, set to true to cause the >- // encoding to be decoded, and false for it to be ignored. >- // TODO(deadbeef): Not implemented for PeerConnection RtpReceivers. >+ absl::optional<double> scale_framerate_down_by; >+ >+ // For an RtpSender, set to true to cause this encoding to be encoded and >+ // sent, and false for it not to be encoded and sent. This allows control >+ // across multiple encodings of a sender for turning simulcast layers on and >+ // off. >+ // TODO(webrtc.bugs.org/8807): Updating this parameter will trigger an encoder >+ // reset, but this isn't necessarily required. > bool active = true; > > // Value to use for RID RTP header extension. >@@ -408,7 +449,7 @@ struct RtpEncodingParameters { > bool operator==(const RtpEncodingParameters& o) const { > return ssrc == o.ssrc && codec_payload_type == o.codec_payload_type && > fec == o.fec && rtx == o.rtx && dtx == o.dtx && >- bitrate_priority == o.bitrate_priority && >+ bitrate_priority == o.bitrate_priority && ptime == o.ptime && > max_bitrate_bps == o.max_bitrate_bps && > max_framerate == o.max_framerate && > scale_resolution_down_by == o.scale_resolution_down_by && >@@ -423,6 +464,7 @@ struct RtpEncodingParameters { > > struct RtpCodecParameters { > RtpCodecParameters(); >+ RtpCodecParameters(const RtpCodecParameters&); > ~RtpCodecParameters(); > > // Build MIME "type/subtype" string from |name| and |kind|. >@@ -440,24 +482,24 @@ struct RtpCodecParameters { > int payload_type = 0; > > // If unset, the implementation default is used. >- rtc::Optional<int> clock_rate; >+ absl::optional<int> clock_rate; > > // The number of audio channels used. Unset for video codecs. If unset for > // audio, the implementation default is used. > // TODO(deadbeef): The "implementation default" part isn't fully implemented. > // Only defaults to 1, even though some codecs (such as opus) should really > // default to 2. >- rtc::Optional<int> num_channels; >+ absl::optional<int> num_channels; > > // The maximum packetization time to be used by an RtpSender. > // If |ptime| is also set, this will be ignored. > // TODO(deadbeef): Not implemented. >- rtc::Optional<int> max_ptime; >+ absl::optional<int> max_ptime; > > // The packetization time to be used by an RtpSender. > // If unset, will use any time up to max_ptime. > // TODO(deadbeef): Not implemented. >- rtc::Optional<int> ptime; >+ absl::optional<int> ptime; > > // Feedback mechanisms to be used for this codec. > // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. >@@ -470,8 +512,6 @@ struct RtpCodecParameters { > // Contrary to ORTC, these parameters are named using all lowercase strings. > // This helps make the mapping to SDP simpler, if an application is using > // SDP. Boolean values are represented by the string "1". >- // >- // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. > std::unordered_map<std::string, std::string> parameters; > > bool operator==(const RtpCodecParameters& o) const { >@@ -508,17 +548,49 @@ struct RtpCapabilities { > bool operator!=(const RtpCapabilities& o) const { return !(*this == o); } > }; > >-// Note that unlike in ORTC, an RtcpParameters structure is not included in >-// RtpParameters, because our API includes an additional "RtpTransport" >-// abstraction on which RTCP parameters are set. >+struct RtcpParameters final { >+ RtcpParameters(); >+ RtcpParameters(const RtcpParameters&); >+ ~RtcpParameters(); >+ >+ // The SSRC to be used in the "SSRC of packet sender" field. If not set, one >+ // will be chosen by the implementation. >+ // TODO(deadbeef): Not implemented. >+ absl::optional<uint32_t> ssrc; >+ >+ // The Canonical Name (CNAME) used by RTCP (e.g. in SDES messages). >+ // >+ // If empty in the construction of the RtpTransport, one will be generated by >+ // the implementation, and returned in GetRtcpParameters. Multiple >+ // RtpTransports created by the same OrtcFactory will use the same generated >+ // CNAME. >+ // >+ // If empty when passed into SetParameters, the CNAME simply won't be >+ // modified. >+ std::string cname; >+ >+ // Send reduced-size RTCP? >+ bool reduced_size = false; >+ >+ // Send RTCP multiplexed on the RTP transport? >+ // Not used with PeerConnection senders/receivers >+ bool mux = true; >+ >+ bool operator==(const RtcpParameters& o) const { >+ return ssrc == o.ssrc && cname == o.cname && >+ reduced_size == o.reduced_size && mux == o.mux; >+ } >+ bool operator!=(const RtcpParameters& o) const { return !(*this == o); } >+}; >+ > struct RtpParameters { > RtpParameters(); >+ RtpParameters(const RtpParameters&); > ~RtpParameters(); > > // Used when calling getParameters/setParameters with a PeerConnection > // RtpSender, to ensure that outdated parameters are not unintentionally > // applied successfully. >- // TODO(deadbeef): Not implemented. > std::string transaction_id; > > // Value to use for MID RTP header extension. >@@ -528,19 +600,25 @@ struct RtpParameters { > > std::vector<RtpCodecParameters> codecs; > >- // TODO(deadbeef): Not implemented with PeerConnection senders/receivers. > std::vector<RtpHeaderExtensionParameters> header_extensions; > > std::vector<RtpEncodingParameters> encodings; > >- // TODO(deadbeef): Not implemented. >+ // Only available with a Peerconnection RtpSender. >+ // In ORTC, our API includes an additional "RtpTransport" >+ // abstraction on which RTCP parameters are set. >+ RtcpParameters rtcp; >+ >+ // When bandwidth is constrained and the RtpSender needs to choose between >+ // degrading resolution or degrading framerate, degradationPreference >+ // indicates which is preferred. Only for video tracks. > DegradationPreference degradation_preference = > DegradationPreference::BALANCED; > > bool operator==(const RtpParameters& o) const { > return mid == o.mid && codecs == o.codecs && > header_extensions == o.header_extensions && >- encodings == o.encodings && >+ encodings == o.encodings && rtcp == o.rtcp && > degradation_preference == o.degradation_preference; > } > bool operator!=(const RtpParameters& o) const { return !(*this == o); } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.cc >new file mode 100644 >index 00000000000..fcdca698927 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.cc >@@ -0,0 +1,48 @@ >+/* >+ * Copyright 2018 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 "api/rtpreceiverinterface.h" >+ >+namespace webrtc { >+ >+RtpSource::RtpSource(int64_t timestamp_ms, >+ uint32_t source_id, >+ RtpSourceType source_type) >+ : timestamp_ms_(timestamp_ms), >+ source_id_(source_id), >+ source_type_(source_type) {} >+ >+RtpSource::RtpSource(int64_t timestamp_ms, >+ uint32_t source_id, >+ RtpSourceType source_type, >+ uint8_t audio_level) >+ : timestamp_ms_(timestamp_ms), >+ source_id_(source_id), >+ source_type_(source_type), >+ audio_level_(audio_level) {} >+ >+RtpSource::RtpSource(const RtpSource&) = default; >+RtpSource& RtpSource::operator=(const RtpSource&) = default; >+RtpSource::~RtpSource() = default; >+ >+std::vector<std::string> RtpReceiverInterface::stream_ids() const { >+ return {}; >+} >+ >+std::vector<rtc::scoped_refptr<MediaStreamInterface>> >+RtpReceiverInterface::streams() const { >+ return {}; >+} >+ >+std::vector<RtpSource> RtpReceiverInterface::GetSources() const { >+ return {}; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.h >index ac2e090dad8..b2499b41699 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpreceiverinterface.h >@@ -34,19 +34,16 @@ enum class RtpSourceType { > class RtpSource { > public: > RtpSource() = delete; >- RtpSource(int64_t timestamp_ms, uint32_t source_id, RtpSourceType source_type) >- : timestamp_ms_(timestamp_ms), >- source_id_(source_id), >- source_type_(source_type) {} >- >+ RtpSource(int64_t timestamp_ms, >+ uint32_t source_id, >+ RtpSourceType source_type); > RtpSource(int64_t timestamp_ms, > uint32_t source_id, > RtpSourceType source_type, >- uint8_t audio_level) >- : timestamp_ms_(timestamp_ms), >- source_id_(source_id), >- source_type_(source_type), >- audio_level_(audio_level) {} >+ uint8_t audio_level); >+ RtpSource(const RtpSource&); >+ RtpSource& operator=(const RtpSource&); >+ ~RtpSource(); > > int64_t timestamp_ms() const { return timestamp_ms_; } > void update_timestamp_ms(int64_t timestamp_ms) { >@@ -60,8 +57,8 @@ class RtpSource { > // The source can be either a contributing source or a synchronization source. > RtpSourceType source_type() const { return source_type_; } > >- rtc::Optional<uint8_t> audio_level() const { return audio_level_; } >- void set_audio_level(const rtc::Optional<uint8_t>& level) { >+ absl::optional<uint8_t> audio_level() const { return audio_level_; } >+ void set_audio_level(const absl::optional<uint8_t>& level) { > audio_level_ = level; > } > >@@ -74,7 +71,7 @@ class RtpSource { > int64_t timestamp_ms_; > uint32_t source_id_; > RtpSourceType source_type_; >- rtc::Optional<uint8_t> audio_level_; >+ absl::optional<uint8_t> audio_level_; > }; > > class RtpReceiverObserverInterface { >@@ -96,12 +93,13 @@ class RtpReceiverInterface : public rtc::RefCountInterface { > virtual rtc::scoped_refptr<MediaStreamTrackInterface> track() const = 0; > // The list of streams that |track| is associated with. This is the same as > // the [[AssociatedRemoteMediaStreams]] internal slot in the spec. >- // https://w3c.github.io/webrtc-pc/#dfn-x%5B%5Bassociatedremotemediastreams%5D%5D >+ // https://w3c.github.io/webrtc-pc/#dfn-associatedremotemediastreams > // TODO(hbos): Make pure virtual as soon as Chromium's mock implements this. >- virtual std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams() >- const { >- return std::vector<rtc::scoped_refptr<MediaStreamInterface>>(); >- } >+ // TODO(https://crbug.com/webrtc/9480): Remove streams() in favor of >+ // stream_ids() as soon as downstream projects are no longer dependent on >+ // stream objects. >+ virtual std::vector<std::string> stream_ids() const; >+ virtual std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams() const; > > // Audio or video receiver? > virtual cricket::MediaType media_type() const = 0; >@@ -124,37 +122,27 @@ class RtpReceiverInterface : public rtc::RefCountInterface { > // TODO(zhihuang): Remove the default implementation once the subclasses > // implement this. Currently, the only relevant subclass is the > // content::FakeRtpReceiver in Chromium. >- virtual std::vector<RtpSource> GetSources() const { >- return std::vector<RtpSource>(); >- } >- // TODO(hta): Remove default implementation or move function to >- // an internal interface. content::FakeRtpReceiver in Chromium needs this. >- >- // Returns an ID that changes if the attached track changes, but >- // otherwise remains constant. Used to generate IDs for stats. >- // The special value zero means that no track is attached. >- virtual int AttachmentId() const { return 0; } >+ virtual std::vector<RtpSource> GetSources() const; > > protected: >- virtual ~RtpReceiverInterface() {} >+ ~RtpReceiverInterface() override = default; > }; > > // Define proxy for RtpReceiverInterface. > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_SIGNALING_PROXY_MAP(RtpReceiver) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) >- PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>, >- streams) >- PROXY_CONSTMETHOD0(cricket::MediaType, media_type) >- PROXY_CONSTMETHOD0(std::string, id) >- PROXY_CONSTMETHOD0(RtpParameters, GetParameters); >- PROXY_METHOD1(bool, SetParameters, const RtpParameters&) >- PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*); >- PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources); >- PROXY_CONSTMETHOD0(int, AttachmentId); >- END_PROXY_MAP() >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) >+PROXY_CONSTMETHOD0(std::vector<rtc::scoped_refptr<MediaStreamInterface>>, >+ streams) >+PROXY_CONSTMETHOD0(cricket::MediaType, media_type) >+PROXY_CONSTMETHOD0(std::string, id) >+PROXY_CONSTMETHOD0(RtpParameters, GetParameters); >+PROXY_METHOD1(bool, SetParameters, const RtpParameters&) >+PROXY_METHOD1(void, SetObserver, RtpReceiverObserverInterface*); >+PROXY_CONSTMETHOD0(std::vector<RtpSource>, GetSources); >+END_PROXY_MAP() > > } // namespace webrtc > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpsenderinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpsenderinterface.h >index a7d7edc4b0b..a7eec4972e5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpsenderinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtpsenderinterface.h >@@ -21,7 +21,9 @@ > #include "api/mediastreaminterface.h" > #include "api/mediatypes.h" > #include "api/proxy.h" >+#include "api/rtcerror.h" > #include "api/rtpparameters.h" >+#include "rtc_base/deprecation.h" > #include "rtc_base/refcount.h" > #include "rtc_base/scoped_ref_ptr.h" > >@@ -36,7 +38,7 @@ class RtpSenderInterface : public rtc::RefCountInterface { > > // Returns primary SSRC used by this sender for sending media. > // Returns 0 if not yet determined. >- // TODO(deadbeef): Change to rtc::Optional. >+ // TODO(deadbeef): Change to absl::optional. > // TODO(deadbeef): Remove? With GetParameters this should be redundant. > virtual uint32_t ssrc() const = 0; > >@@ -47,45 +49,39 @@ class RtpSenderInterface : public rtc::RefCountInterface { > // to uniquely identify a receiver until we implement Unified Plan SDP. > virtual std::string id() const = 0; > >- // Returns a list of streams associated with this sender's track. Although we >- // only support one track per stream, in theory the API allows for multiple. >+ // Returns a list of media stream ids associated with this sender's track. >+ // These are signalled in the SDP so that the remote side can associate >+ // tracks. > virtual std::vector<std::string> stream_ids() const = 0; > >- virtual RtpParameters GetParameters() const = 0; >+ virtual RtpParameters GetParameters() = 0; > // Note that only a subset of the parameters can currently be changed. See > // rtpparameters.h >- virtual bool SetParameters(const RtpParameters& parameters) = 0; >+ // The encodings are in increasing quality order for simulcast. >+ virtual RTCError SetParameters(const RtpParameters& parameters) = 0; > > // Returns null for a video sender. > virtual rtc::scoped_refptr<DtmfSenderInterface> GetDtmfSender() const = 0; > >- // Returns an ID that changes every time SetTrack() is called, but >- // otherwise remains constant. Used to generate IDs for stats. >- // The special value zero means that no track is attached. >- // TODO(hta): Remove default implementation when callers have updated, >- // or move function to an internal interface. >- virtual int AttachmentId() const { return 0; } >- > protected: >- virtual ~RtpSenderInterface() {} >+ ~RtpSenderInterface() override = default; > }; > > // Define proxy for RtpSenderInterface. > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_SIGNALING_PROXY_MAP(RtpSender) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*) >- PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) >- PROXY_CONSTMETHOD0(uint32_t, ssrc) >- PROXY_CONSTMETHOD0(cricket::MediaType, media_type) >- PROXY_CONSTMETHOD0(std::string, id) >- PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids) >- PROXY_CONSTMETHOD0(RtpParameters, GetParameters); >- PROXY_METHOD1(bool, SetParameters, const RtpParameters&) >- PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender); >- PROXY_CONSTMETHOD0(int, AttachmentId); >- END_PROXY_MAP() >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_METHOD1(bool, SetTrack, MediaStreamTrackInterface*) >+PROXY_CONSTMETHOD0(rtc::scoped_refptr<MediaStreamTrackInterface>, track) >+PROXY_CONSTMETHOD0(uint32_t, ssrc) >+PROXY_CONSTMETHOD0(cricket::MediaType, media_type) >+PROXY_CONSTMETHOD0(std::string, id) >+PROXY_CONSTMETHOD0(std::vector<std::string>, stream_ids) >+PROXY_METHOD0(RtpParameters, GetParameters); >+PROXY_METHOD1(RTCError, SetParameters, const RtpParameters&) >+PROXY_CONSTMETHOD0(rtc::scoped_refptr<DtmfSenderInterface>, GetDtmfSender); >+END_PROXY_MAP() > > } // namespace webrtc > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.cc >new file mode 100644 >index 00000000000..065ac049778 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.cc >@@ -0,0 +1,26 @@ >+/* >+ * Copyright 2018 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 "api/rtptransceiverinterface.h" >+ >+namespace webrtc { >+ >+RtpTransceiverInit::RtpTransceiverInit() = default; >+ >+RtpTransceiverInit::RtpTransceiverInit(const RtpTransceiverInit& rhs) = default; >+ >+RtpTransceiverInit::~RtpTransceiverInit() = default; >+ >+absl::optional<RtpTransceiverDirection> >+RtpTransceiverInterface::fired_direction() const { >+ return absl::nullopt; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.h >index 5d74ae1023c..4c22957b790 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/rtptransceiverinterface.h >@@ -14,7 +14,8 @@ > #include <string> > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" >+#include "api/array_view.h" > #include "api/rtpreceiverinterface.h" > #include "api/rtpsenderinterface.h" > #include "rtc_base/refcount.h" >@@ -29,19 +30,18 @@ enum class RtpTransceiverDirection { > kInactive > }; > >-// This is provided as a debugging aid. The format of the output is unspecified. >-std::ostream& operator<<(std::ostream& os, RtpTransceiverDirection direction); >- > // Structure for initializing an RtpTransceiver in a call to > // PeerConnectionInterface::AddTransceiver. > // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiverinit > struct RtpTransceiverInit final { >+ RtpTransceiverInit(); >+ RtpTransceiverInit(const RtpTransceiverInit&); >+ ~RtpTransceiverInit(); > // Direction of the RtpTransceiver. See RtpTransceiverInterface::direction(). > RtpTransceiverDirection direction = RtpTransceiverDirection::kSendRecv; > > // The added RtpTransceiver will be added to these streams. >- // TODO(bugs.webrtc.org/7600): Not implemented. >- std::vector<std::string> stream_labels; >+ std::vector<std::string> stream_ids; > > // TODO(bugs.webrtc.org/7600): Not implemented. > std::vector<RtpEncodingParameters> send_encodings; >@@ -63,11 +63,15 @@ struct RtpTransceiverInit final { > // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver > class RtpTransceiverInterface : public rtc::RefCountInterface { > public: >+ // Media type of the transceiver. Any sender(s)/receiver(s) will have this >+ // type as well. >+ virtual cricket::MediaType media_type() const = 0; >+ > // The mid attribute is the mid negotiated and present in the local and > // remote descriptions. Before negotiation is complete, the mid value may be > // null. After rollbacks, the value may change from a non-null value to null. > // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-mid >- virtual rtc::Optional<std::string> mid() const = 0; >+ virtual absl::optional<std::string> mid() const = 0; > > // The sender attribute exposes the RtpSender corresponding to the RTP media > // that may be sent with the transceiver's mid. The sender is always present, >@@ -104,7 +108,14 @@ class RtpTransceiverInterface : public rtc::RefCountInterface { > // for this transceiver. If this transceiver has never been represented in an > // offer/answer exchange, or if the transceiver is stopped, the value is null. > // https://w3c.github.io/webrtc-pc/#dom-rtcrtptransceiver-currentdirection >- virtual rtc::Optional<RtpTransceiverDirection> current_direction() const = 0; >+ virtual absl::optional<RtpTransceiverDirection> current_direction() const = 0; >+ >+ // An internal slot designating for which direction the relevant >+ // PeerConnection events have been fired. This is to ensure that events like >+ // OnAddTrack only get fired once even if the same session description is >+ // applied again. >+ // Exposed in the public interface for use by Chromium. >+ virtual absl::optional<RtpTransceiverDirection> fired_direction() const; > > // The Stop method irreversibly stops the RtpTransceiver. The sender of this > // transceiver will no longer send, the receiver will no longer receive. >@@ -119,7 +130,7 @@ class RtpTransceiverInterface : public rtc::RefCountInterface { > rtc::ArrayView<RtpCodecCapability> codecs) = 0; > > protected: >- virtual ~RtpTransceiverInterface() = default; >+ ~RtpTransceiverInterface() override = default; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats.h >index 887d602042c..1705f6ab58e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats.h >@@ -78,7 +78,7 @@ class RTCStats { > > // Downcasts the stats object to an |RTCStats| subclass |T|. DCHECKs that the > // object is of type |T|. >- template<typename T> >+ template <typename T> > const T& cast_to() const { > RTC_DCHECK_EQ(type(), T::kType); > return static_cast<const T&>(*this); >@@ -90,8 +90,7 @@ class RTCStats { > // shall be reserved in the vector (so that subclasses can allocate a vector > // with room for both parent and child members without it having to resize). > virtual std::vector<const RTCStatsMemberInterface*> >- MembersOfThisObjectAndAncestors( >- size_t additional_capacity) const; >+ MembersOfThisObjectAndAncestors(size_t additional_capacity) const; > > std::string const id_; > int64_t timestamp_us_; >@@ -138,18 +137,18 @@ class RTCStats { > // bar("bar") { > // } > // >-#define WEBRTC_RTCSTATS_DECL() \ >- public: \ >- static const char kType[]; \ >- \ >- std::unique_ptr<webrtc::RTCStats> copy() const override; \ >- const char* type() const override; \ >- \ >- protected: \ >- std::vector<const webrtc::RTCStatsMemberInterface*> \ >- MembersOfThisObjectAndAncestors( \ >- size_t local_var_additional_capacity) const override; \ >- \ >+#define WEBRTC_RTCSTATS_DECL() \ >+ public: \ >+ static const char kType[]; \ >+ \ >+ std::unique_ptr<webrtc::RTCStats> copy() const override; \ >+ const char* type() const override; \ >+ \ >+ protected: \ >+ std::vector<const webrtc::RTCStatsMemberInterface*> \ >+ MembersOfThisObjectAndAncestors(size_t local_var_additional_capacity) \ >+ const override; \ >+ \ > public: > > #define WEBRTC_RTCSTATS_IMPL(this_class, parent_class, type_str, ...) \ >@@ -159,20 +158,17 @@ class RTCStats { > return std::unique_ptr<webrtc::RTCStats>(new this_class(*this)); \ > } \ > \ >- const char* this_class::type() const { \ >- return this_class::kType; \ >- } \ >+ const char* this_class::type() const { return this_class::kType; } \ > \ > std::vector<const webrtc::RTCStatsMemberInterface*> \ > this_class::MembersOfThisObjectAndAncestors( \ > size_t local_var_additional_capacity) const { \ > const webrtc::RTCStatsMemberInterface* local_var_members[] = { \ >- __VA_ARGS__ \ >- }; \ >+ __VA_ARGS__}; \ > size_t local_var_members_count = \ > sizeof(local_var_members) / sizeof(local_var_members[0]); \ >- std::vector<const webrtc::RTCStatsMemberInterface*> local_var_members_vec =\ >- parent_class::MembersOfThisObjectAndAncestors( \ >+ std::vector<const webrtc::RTCStatsMemberInterface*> \ >+ local_var_members_vec = parent_class::MembersOfThisObjectAndAncestors( \ > local_var_members_count + local_var_additional_capacity); \ > RTC_DCHECK_GE( \ > local_var_members_vec.capacity() - local_var_members_vec.size(), \ >@@ -191,21 +187,21 @@ class RTCStatsMemberInterface { > public: > // Member value types. > enum Type { >- kBool, // bool >- kInt32, // int32_t >- kUint32, // uint32_t >- kInt64, // int64_t >- kUint64, // uint64_t >- kDouble, // double >- kString, // std::string >+ kBool, // bool >+ kInt32, // int32_t >+ kUint32, // uint32_t >+ kInt64, // int64_t >+ kUint64, // uint64_t >+ kDouble, // double >+ kString, // std::string > >- kSequenceBool, // std::vector<bool> >- kSequenceInt32, // std::vector<int32_t> >- kSequenceUint32, // std::vector<uint32_t> >- kSequenceInt64, // std::vector<int64_t> >- kSequenceUint64, // std::vector<uint64_t> >- kSequenceDouble, // std::vector<double> >- kSequenceString, // std::vector<std::string> >+ kSequenceBool, // std::vector<bool> >+ kSequenceInt32, // std::vector<int32_t> >+ kSequenceUint32, // std::vector<uint32_t> >+ kSequenceInt64, // std::vector<int64_t> >+ kSequenceUint64, // std::vector<uint64_t> >+ kSequenceDouble, // std::vector<double> >+ kSequenceString, // std::vector<std::string> > }; > > virtual ~RTCStatsMemberInterface() {} >@@ -215,6 +211,9 @@ class RTCStatsMemberInterface { > virtual bool is_sequence() const = 0; > virtual bool is_string() const = 0; > bool is_defined() const { return is_defined_; } >+ // Is this part of the stats spec? Used so that chromium can easily filter >+ // out anything unstandardized. >+ virtual bool is_standardized() const = 0; > // Type and value comparator. The names are not compared. These operators are > // exposed for testing. > virtual bool operator==(const RTCStatsMemberInterface& other) const = 0; >@@ -229,7 +228,7 @@ class RTCStatsMemberInterface { > // instead. > virtual std::string ValueToJson() const = 0; > >- template<typename T> >+ template <typename T> > const T& cast_to() const { > RTC_DCHECK_EQ(type(), T::kType); > return static_cast<const T&>(*this); >@@ -247,19 +246,17 @@ class RTCStatsMemberInterface { > // specialized in rtcstats.cc, using a different |T| results in a linker error > // (undefined reference to |kType|). The supported types are the ones described > // by |RTCStatsMemberInterface::Type|. >-template<typename T> >+template <typename T> > class RTCStatsMember : public RTCStatsMemberInterface { > public: > static const Type kType; > > explicit RTCStatsMember(const char* name) >- : RTCStatsMemberInterface(name, false), >- value_() {} >+ : RTCStatsMemberInterface(name, /*is_defined=*/false), value_() {} > RTCStatsMember(const char* name, const T& value) >- : RTCStatsMemberInterface(name, true), >- value_(value) {} >+ : RTCStatsMemberInterface(name, /*is_defined=*/true), value_(value) {} > RTCStatsMember(const char* name, T&& value) >- : RTCStatsMemberInterface(name, true), >+ : RTCStatsMemberInterface(name, /*is_defined=*/true), > value_(std::move(value)) {} > explicit RTCStatsMember(const RTCStatsMember<T>& other) > : RTCStatsMemberInterface(other.name_, other.is_defined_), >@@ -271,8 +268,9 @@ class RTCStatsMember : public RTCStatsMemberInterface { > Type type() const override { return kType; } > bool is_sequence() const override; > bool is_string() const override; >+ bool is_standardized() const override { return true; } > bool operator==(const RTCStatsMemberInterface& other) const override { >- if (type() != other.type()) >+ if (type() != other.type() || is_standardized() != other.is_standardized()) > return false; > const RTCStatsMember<T>& other_t = > static_cast<const RTCStatsMember<T>&>(other); >@@ -298,7 +296,10 @@ class RTCStatsMember : public RTCStatsMemberInterface { > } > T& operator=(const RTCStatsMember<T>& other) { > RTC_DCHECK(other.is_defined_); >- value_ = other.is_defined_; >+ // Shouldn't be attempting to assign an RTCNonStandardStatsMember to an >+ // RTCStatsMember or vice versa. >+ RTC_DCHECK(is_standardized() == other.is_standardized()); >+ value_ = other.value_; > is_defined_ = true; > return value_; > } >@@ -327,6 +328,26 @@ class RTCStatsMember : public RTCStatsMemberInterface { > T value_; > }; > >+// Same as above, but "is_standardized" returns false. >+// >+// Using inheritance just so that it's obvious from the member's declaration >+// whether it's standardized or not. >+template <typename T> >+class RTCNonStandardStatsMember : public RTCStatsMember<T> { >+ public: >+ explicit RTCNonStandardStatsMember(const char* name) >+ : RTCStatsMember<T>(name) {} >+ RTCNonStandardStatsMember(const char* name, const T& value) >+ : RTCStatsMember<T>(name, value) {} >+ RTCNonStandardStatsMember(const char* name, T&& value) >+ : RTCStatsMember<T>(name, std::move(value)) {} >+ explicit RTCNonStandardStatsMember(const RTCNonStandardStatsMember<T>& other) >+ : RTCStatsMember<T>(other) {} >+ explicit RTCNonStandardStatsMember(RTCNonStandardStatsMember<T>&& other) >+ : RTCStatsMember<T>(std::move(other)) {} >+ >+ bool is_standardized() const override { return false; } >+}; > } // namespace webrtc > > #endif // API_STATS_RTCSTATS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats_objects.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats_objects.h >index a052c173834..7e6bcd3228b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats_objects.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstats_objects.h >@@ -11,6 +11,7 @@ > #ifndef API_STATS_RTCSTATS_OBJECTS_H_ > #define API_STATS_RTCSTATS_OBJECTS_H_ > >+#include <memory> > #include <string> > #include <vector> > >@@ -183,6 +184,8 @@ class RTCIceCandidatePairStats final : public RTCStats { > // TODO(hbos): |RTCStatsCollector| only collects candidates that are part of > // ice candidate pairs, but there could be candidates not paired with anything. > // crbug.com/632723 >+// TODO(qingsi): Add the stats of STUN binding requests (keepalives) and collect >+// them in the new PeerConnection::GetStats. > class RTCIceCandidateStats : public RTCStats { > public: > WEBRTC_RTCSTATS_DECL(); >@@ -206,8 +209,9 @@ class RTCIceCandidateStats : public RTCStats { > RTCStatsMember<bool> deleted; // = false > > protected: >- RTCIceCandidateStats( >- const std::string& id, int64_t timestamp_us, bool is_remote); >+ RTCIceCandidateStats(const std::string& id, >+ int64_t timestamp_us, >+ bool is_remote); > RTCIceCandidateStats(std::string&& id, int64_t timestamp_us, bool is_remote); > }; > >@@ -215,11 +219,13 @@ class RTCIceCandidateStats : public RTCStats { > // But here we define them as subclasses of |RTCIceCandidateStats| because the > // |kType| need to be different ("RTCStatsType type") in the local/remote case. > // https://w3c.github.io/webrtc-stats/#rtcstatstype-str* >+// This forces us to have to override copy() and type(). > class RTCLocalIceCandidateStats final : public RTCIceCandidateStats { > public: > static const char kType[]; > RTCLocalIceCandidateStats(const std::string& id, int64_t timestamp_us); > RTCLocalIceCandidateStats(std::string&& id, int64_t timestamp_us); >+ std::unique_ptr<RTCStats> copy() const override; > const char* type() const override; > }; > >@@ -228,6 +234,7 @@ class RTCRemoteIceCandidateStats final : public RTCIceCandidateStats { > static const char kType[]; > RTCRemoteIceCandidateStats(const std::string& id, int64_t timestamp_us); > RTCRemoteIceCandidateStats(std::string&& id, int64_t timestamp_us); >+ std::unique_ptr<RTCStats> copy() const override; > const char* type() const override; > }; > >@@ -252,9 +259,11 @@ class RTCMediaStreamTrackStats final : public RTCStats { > public: > WEBRTC_RTCSTATS_DECL(); > >- RTCMediaStreamTrackStats(const std::string& id, int64_t timestamp_us, >+ RTCMediaStreamTrackStats(const std::string& id, >+ int64_t timestamp_us, > const char* kind); >- RTCMediaStreamTrackStats(std::string&& id, int64_t timestamp_us, >+ RTCMediaStreamTrackStats(std::string&& id, >+ int64_t timestamp_us, > const char* kind); > RTCMediaStreamTrackStats(const RTCMediaStreamTrackStats& other); > ~RTCMediaStreamTrackStats() override; >@@ -277,6 +286,7 @@ class RTCMediaStreamTrackStats final : public RTCStats { > // TODO(hbos): Not collected by |RTCStatsCollector|. crbug.com/659137 > RTCStatsMember<double> frames_per_second; > RTCStatsMember<uint32_t> frames_sent; >+ RTCStatsMember<uint32_t> huge_frames_sent; > RTCStatsMember<uint32_t> frames_received; > RTCStatsMember<uint32_t> frames_decoded; > RTCStatsMember<uint32_t> frames_dropped; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatscollectorcallback.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatscollectorcallback.h >index 2c67bb81bbc..92422176593 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatscollectorcallback.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatscollectorcallback.h >@@ -19,7 +19,7 @@ namespace webrtc { > > class RTCStatsCollectorCallback : public virtual rtc::RefCountInterface { > public: >- virtual ~RTCStatsCollectorCallback() {} >+ ~RTCStatsCollectorCallback() override = default; > > virtual void OnStatsDelivered( > const rtc::scoped_refptr<const RTCStatsReport>& report) = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatsreport.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatsreport.h >index ee56b35d062..f7410b39f79 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatsreport.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/stats/rtcstatsreport.h >@@ -57,12 +57,16 @@ class RTCStatsReport : public rtc::RefCountInterface { > > explicit RTCStatsReport(int64_t timestamp_us); > RTCStatsReport(const RTCStatsReport& other) = delete; >+ rtc::scoped_refptr<RTCStatsReport> Copy() const; > > int64_t timestamp_us() const { return timestamp_us_; } > void AddStats(std::unique_ptr<const RTCStats> stats); > const RTCStats* Get(const std::string& id) const; > size_t size() const { return stats_.size(); } > >+ // Removes the stats object from the report, returning ownership of it or null >+ // if there is no object with |id|. >+ std::unique_ptr<const RTCStats> Take(const std::string& id); > // Takes ownership of all the stats in |victim|, leaving it empty. > void TakeMembersFrom(rtc::scoped_refptr<RTCStatsReport> victim); > >@@ -72,7 +76,7 @@ class RTCStatsReport : public rtc::RefCountInterface { > > // Gets the subset of stats that are of type |T|, where |T| is any class > // descending from |RTCStats|. >- template<typename T> >+ template <typename T> > std::vector<const T*> GetStatsOfType() const { > std::vector<const T*> stats_of_type; > for (const RTCStats& stats : *this) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.cc >index d1637e3ffd1..ad68894f481 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.cc >@@ -98,9 +98,8 @@ class TypedIntId : public StatsReport::IdBase { > } > > std::string ToString() const override { >- return std::string(InternalTypeToString(type_)) + >- kSeparator + >- rtc::ToString<int>(id_); >+ return std::string(InternalTypeToString(type_)) + kSeparator + >+ rtc::ToString(id_); > } > > protected: >@@ -109,7 +108,8 @@ class TypedIntId : public StatsReport::IdBase { > > class IdWithDirection : public TypedId { > public: >- IdWithDirection(StatsReport::StatsType type, const std::string& id, >+ IdWithDirection(StatsReport::StatsType type, >+ const std::string& id, > StatsReport::Direction direction) > : TypedId(type, id), direction_(direction) {} > >@@ -132,45 +132,40 @@ class IdWithDirection : public TypedId { > class CandidateId : public TypedId { > public: > CandidateId(bool local, const std::string& id) >- : TypedId(local ? >- StatsReport::kStatsReportTypeIceLocalCandidate : >- StatsReport::kStatsReportTypeIceRemoteCandidate, >- id) { >- } >+ : TypedId(local ? StatsReport::kStatsReportTypeIceLocalCandidate >+ : StatsReport::kStatsReportTypeIceRemoteCandidate, >+ id) {} > >- std::string ToString() const override { >- return "Cand-" + id_; >- } >+ std::string ToString() const override { return "Cand-" + id_; } > }; > > class ComponentId : public StatsReport::IdBase { > public: > ComponentId(const std::string& content_name, int component) >- : ComponentId(StatsReport::kStatsReportTypeComponent, content_name, >- component) {} >+ : ComponentId(StatsReport::kStatsReportTypeComponent, >+ content_name, >+ component) {} > > bool Equals(const IdBase& other) const override { > return IdBase::Equals(other) && >- static_cast<const ComponentId&>(other).component_ == component_ && >- static_cast<const ComponentId&>(other).content_name_ == content_name_; >+ static_cast<const ComponentId&>(other).component_ == component_ && >+ static_cast<const ComponentId&>(other).content_name_ == >+ content_name_; > } > >- std::string ToString() const override { >- return ToString("Channel-"); >- } >+ std::string ToString() const override { return ToString("Channel-"); } > > protected: >- ComponentId(StatsReport::StatsType type, const std::string& content_name, >+ ComponentId(StatsReport::StatsType type, >+ const std::string& content_name, > int component) >- : IdBase(type), >- content_name_(content_name), >- component_(component) {} >+ : IdBase(type), content_name_(content_name), component_(component) {} > > std::string ToString(const char* prefix) const { > std::string ret(prefix); > ret += content_name_; > ret += '-'; >- ret += rtc::ToString<>(component_); >+ ret += rtc::ToString(component_); > return ret; > } > >@@ -182,19 +177,20 @@ class ComponentId : public StatsReport::IdBase { > class CandidatePairId : public ComponentId { > public: > CandidatePairId(const std::string& content_name, int component, int index) >- : ComponentId(StatsReport::kStatsReportTypeCandidatePair, content_name, >- component), >+ : ComponentId(StatsReport::kStatsReportTypeCandidatePair, >+ content_name, >+ component), > index_(index) {} > > bool Equals(const IdBase& other) const override { > return ComponentId::Equals(other) && >- static_cast<const CandidatePairId&>(other).index_ == index_; >+ static_cast<const CandidatePairId&>(other).index_ == index_; > } > > std::string ToString() const override { > std::string ret(ComponentId::ToString("Conn-")); > ret += '-'; >- ret += rtc::ToString<>(index_); >+ ret += rtc::ToString(index_); > return ret; > } > >@@ -207,7 +203,9 @@ class CandidatePairId : public ComponentId { > StatsReport::IdBase::IdBase(StatsType type) : type_(type) {} > StatsReport::IdBase::~IdBase() {} > >-StatsReport::StatsType StatsReport::IdBase::type() const { return type_; } >+StatsReport::StatsType StatsReport::IdBase::type() const { >+ return type_; >+} > > bool StatsReport::IdBase::Equals(const IdBase& other) const { > return other.type_ == type_; >@@ -316,8 +314,8 @@ bool StatsReport::Value::operator==(const char* value) const { > } > > bool StatsReport::Value::operator==(int64_t value) const { >- return type_ == kInt ? value_.int_ == static_cast<int>(value) : >- (type_ == kInt64 ? value_.int64_ == value : false); >+ return type_ == kInt ? value_.int_ == static_cast<int>(value) >+ : (type_ == kInt64 ? value_.int64_ == value : false); > } > > bool StatsReport::Value::operator==(bool value) const { >@@ -430,7 +428,9 @@ const char* StatsReport::Value::display_name() const { > case kStatsValueNameBandwidthLimitedResolution: > return "googBandwidthLimitedResolution"; > // STUN ping related attributes. >+ // > // TODO(zhihuang) Rename these stats to follow the standards. >+ // Connectivity checks. > case kStatsValueNameSentPingRequestsTotal: > return "requestsSent"; > case kStatsValueNameSentPingRequestsBeforeFirstResponse: >@@ -441,6 +441,15 @@ const char* StatsReport::Value::display_name() const { > return "requestsReceived"; > case kStatsValueNameRecvPingResponses: > return "responsesReceived"; >+ // STUN Keepalive pings. >+ case kStatsValueNameSentStunKeepaliveRequests: >+ return "stunKeepaliveRequestsSent"; >+ case kStatsValueNameRecvStunKeepaliveResponses: >+ return "stunKeepaliveResponsesReceived"; >+ case kStatsValueNameStunKeepaliveRttTotal: >+ return "stunKeepaliveRttTotal"; >+ case kStatsValueNameStunKeepaliveRttSquaredTotal: >+ return "stunKeepaliveRttSquaredTotal"; > > // Candidate related attributes. Values are taken from > // http://w3c.github.io/webrtc-stats/#rtcstatstype-enum*. >@@ -547,6 +556,8 @@ const char* StatsReport::Value::display_name() const { > return "googFrameWidthSent"; > case kStatsValueNameHasEnteredLowResolution: > return "googHasEnteredLowResolution"; >+ case kStatsValueNameHugeFramesSent: >+ return "hugeFramesSent"; > case kStatsValueNameInitiator: > return "googInitiator"; > case kStatsValueNameInterframeDelayMaxMs: >@@ -686,7 +697,9 @@ StatsReport::Id StatsReport::NewTypedIntId(StatsType type, int id) { > > // static > StatsReport::Id StatsReport::NewIdWithDirection( >- StatsType type, const std::string& id, StatsReport::Direction direction) { >+ StatsType type, >+ const std::string& id, >+ StatsReport::Direction direction) { > return Id(new RefCountedObject<IdWithDirection>(type, id, direction)); > } > >@@ -696,16 +709,17 @@ StatsReport::Id StatsReport::NewCandidateId(bool local, const std::string& id) { > } > > // static >-StatsReport::Id StatsReport::NewComponentId( >- const std::string& content_name, int component) { >+StatsReport::Id StatsReport::NewComponentId(const std::string& content_name, >+ int component) { > return Id(new RefCountedObject<ComponentId>(content_name, component)); > } > > // static >-StatsReport::Id StatsReport::NewCandidatePairId( >- const std::string& content_name, int component, int index) { >- return Id(new RefCountedObject<CandidatePairId>( >- content_name, component, index)); >+StatsReport::Id StatsReport::NewCandidatePairId(const std::string& content_name, >+ int component, >+ int index) { >+ return Id( >+ new RefCountedObject<CandidatePairId>(content_name, component, index)); > } > > const char* StatsReport::TypeToString() const { >@@ -750,8 +764,7 @@ void StatsReport::AddBoolean(StatsReport::StatsValueName name, bool value) { > values_[name] = ValuePtr(new Value(name, value)); > } > >-void StatsReport::AddId(StatsReport::StatsValueName name, >- const Id& value) { >+void StatsReport::AddId(StatsReport::StatsValueName name, const Id& value) { > const Value* found = FindValue(name); > if (!found || !(*found == value)) > values_[name] = ValuePtr(new Value(name, value)); >@@ -762,8 +775,7 @@ const StatsReport::Value* StatsReport::FindValue(StatsValueName name) const { > return it == values_.end() ? nullptr : it->second.get(); > } > >-StatsCollection::StatsCollection() { >-} >+StatsCollection::StatsCollection() {} > > StatsCollection::~StatsCollection() { > RTC_DCHECK(thread_checker_.CalledOnValidThread()); >@@ -803,8 +815,9 @@ StatsReport* StatsCollection::FindOrAddNew(const StatsReport::Id& id) { > StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) { > RTC_DCHECK(thread_checker_.CalledOnValidThread()); > RTC_DCHECK(id.get()); >- Container::iterator it = std::find_if(list_.begin(), list_.end(), >- [&id](const StatsReport* r)->bool { return r->id()->Equals(id); }); >+ Container::iterator it = std::find_if( >+ list_.begin(), list_.end(), >+ [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); }); > if (it != end()) { > StatsReport* report = new StatsReport((*it)->id()); > delete *it; >@@ -818,8 +831,9 @@ StatsReport* StatsCollection::ReplaceOrAddNew(const StatsReport::Id& id) { > // will be returned. > StatsReport* StatsCollection::Find(const StatsReport::Id& id) { > RTC_DCHECK(thread_checker_.CalledOnValidThread()); >- Container::iterator it = std::find_if(list_.begin(), list_.end(), >- [&id](const StatsReport* r)->bool { return r->id()->Equals(id); }); >+ Container::iterator it = std::find_if( >+ list_.begin(), list_.end(), >+ [&id](const StatsReport* r) -> bool { return r->id()->Equals(id); }); > return it == list_.end() ? nullptr : *it; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.h >index a034017458e..857b1afaa7b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/statstypes.h >@@ -20,7 +20,6 @@ > #include <string> > #include <vector> > >-#include "rtc_base/basictypes.h" > #include "rtc_base/constructormagic.h" > #include "rtc_base/refcount.h" > #include "rtc_base/scoped_ref_ptr.h" >@@ -129,6 +128,10 @@ class StatsReport { > kStatsValueNameSentPingResponses, > kStatsValueNameRecvPingRequests, > kStatsValueNameRecvPingResponses, >+ kStatsValueNameSentStunKeepaliveRequests, >+ kStatsValueNameRecvStunKeepaliveResponses, >+ kStatsValueNameStunKeepaliveRttTotal, >+ kStatsValueNameStunKeepaliveRttSquaredTotal, > > // Internal StatsValue names. > kStatsValueNameAccelerateRate, >@@ -185,6 +188,7 @@ class StatsReport { > kStatsValueNameFrameWidthReceived, > kStatsValueNameFrameWidthSent, > kStatsValueNameHasEnteredLowResolution, >+ kStatsValueNameHugeFramesSent, > kStatsValueNameInitiator, > kStatsValueNameInterframeDelayMaxMs, // Max over last 10 seconds. > kStatsValueNameIssuerId, >@@ -337,7 +341,7 @@ class StatsReport { > > private: > rtc::ThreadChecker thread_checker_; >- mutable int ref_count_ RTC_ACCESS_ON(thread_checker_) = 0; >+ mutable int ref_count_ RTC_GUARDED_BY(thread_checker_) = 0; > > const Type type_; > // TODO(tommi): Use C++ 11 union and make value_ const. >@@ -365,13 +369,14 @@ class StatsReport { > static Id NewBandwidthEstimationId(); > static Id NewTypedId(StatsType type, const std::string& id); > static Id NewTypedIntId(StatsType type, int id); >- static Id NewIdWithDirection( >- StatsType type, const std::string& id, Direction direction); >+ static Id NewIdWithDirection(StatsType type, >+ const std::string& id, >+ Direction direction); > static Id NewCandidateId(bool local, const std::string& id); >- static Id NewComponentId( >- const std::string& content_name, int component); >- static Id NewCandidatePairId( >- const std::string& content_name, int component, int index); >+ static Id NewComponentId(const std::string& content_name, int component); >+ static Id NewCandidatePairId(const std::string& content_name, >+ int component, >+ int index); > > const Id& id() const { return id_; } > StatsType type() const { return id_->type(); } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/DEPS >new file mode 100644 >index 00000000000..98b1ad391fc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/DEPS >@@ -0,0 +1,8 @@ >+specific_include_rules = { >+ ".*": [ >+ "+modules/video_coding", >+ ], >+ ".*": [ >+ "+video" >+ ], >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.cc >new file mode 100644 >index 00000000000..9d3ad7e9d88 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.cc >@@ -0,0 +1,27 @@ >+/* >+ * Copyright (c) 2018 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 "api/test/audioproc_float.h" >+ >+#include <utility> >+ >+#include "modules/audio_processing/test/audioproc_float_impl.h" >+ >+namespace webrtc { >+namespace test { >+ >+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder, >+ int argc, >+ char* argv[]) { >+ return AudioprocFloatImpl(std::move(ap_builder), argc, argv); >+} >+ >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.h >new file mode 100644 >index 00000000000..25e4dd5b1cd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/audioproc_float.h >@@ -0,0 +1,42 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_AUDIOPROC_FLOAT_H_ >+#define API_TEST_AUDIOPROC_FLOAT_H_ >+ >+#include <memory> >+ >+#include "modules/audio_processing/include/audio_processing.h" >+ >+namespace webrtc { >+namespace test { >+ >+// This is an interface for the audio processing simulation utility. This >+// utility can be used to simulate the audioprocessing module using a recording >+// (either an AEC dump or wav files), and generate the output as a wav file. >+// The |ap_builder| object will be used to create the AudioProcessing instance >+// that is used during the simulation. The |ap_builder| supports setting of >+// injectable components, which will be passed on to the created AudioProcessing >+// instance. It is needed to pass the command line flags as |argc| and |argv|, >+// so these can be interpreted properly by the utility. >+// To get a fully-working audioproc_f utility, all that is needed is to write a >+// main function, create an AudioProcessingBuilder, optionally set custom >+// processing components on it, and pass the builder together with the command >+// line arguments into this function. >+// To see a list of all supported command line flags, run the executable with >+// the '--help' flag. >+int AudioprocFloat(std::unique_ptr<AudioProcessingBuilder> ap_builder, >+ int argc, >+ char* argv[]); >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_AUDIOPROC_FLOAT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.cc >new file mode 100644 >index 00000000000..897746d00d2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.cc >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (c) 2018 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 "api/test/create_simulcast_test_fixture.h" >+ >+#include <memory> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "api/test/simulcast_test_fixture.h" >+#include "modules/video_coding/utility/simulcast_test_fixture_impl.h" >+ >+namespace webrtc { >+namespace test { >+ >+std::unique_ptr<SimulcastTestFixture> CreateSimulcastTestFixture( >+ std::unique_ptr<VideoEncoderFactory> encoder_factory, >+ std::unique_ptr<VideoDecoderFactory> decoder_factory, >+ SdpVideoFormat video_format) { >+ return absl::make_unique<SimulcastTestFixtureImpl>( >+ std::move(encoder_factory), std::move(decoder_factory), video_format); >+} >+ >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.h >new file mode 100644 >index 00000000000..87f229c0092 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_simulcast_test_fixture.h >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_ >+#define API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_ >+ >+#include <memory> >+ >+#include "api/test/simulcast_test_fixture.h" >+#include "api/video_codecs/sdp_video_format.h" >+#include "api/video_codecs/video_decoder_factory.h" >+#include "api/video_codecs/video_encoder_factory.h" >+ >+namespace webrtc { >+namespace test { >+ >+std::unique_ptr<SimulcastTestFixture> CreateSimulcastTestFixture( >+ std::unique_ptr<VideoEncoderFactory> encoder_factory, >+ std::unique_ptr<VideoDecoderFactory> decoder_factory, >+ SdpVideoFormat video_format); >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_CREATE_SIMULCAST_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.cc >new file mode 100644 >index 00000000000..994401b65bc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.cc >@@ -0,0 +1,34 @@ >+/* >+ * Copyright (c) 2018 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 <memory> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "api/test/create_video_quality_test_fixture.h" >+#include "video/video_quality_test.h" >+ >+namespace webrtc { >+ >+std::unique_ptr<VideoQualityTestFixtureInterface> >+CreateVideoQualityTestFixture() { >+ // By default, we don't override the FEC module, so pass an empty factory. >+ return absl::make_unique<VideoQualityTest>(nullptr); >+} >+ >+std::unique_ptr<VideoQualityTestFixtureInterface> >+CreateVideoQualityTestFixture( >+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory) { >+ return absl::make_unique<VideoQualityTest>(std::move(fec_controller_factory)); >+} >+ >+} // namespace webrtc >+ >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.h >new file mode 100644 >index 00000000000..07c222f16ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_video_quality_test_fixture.h >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+#ifndef API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_ >+#define API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_ >+ >+#include <memory> >+ >+#include "api/fec_controller.h" >+#include "api/test/video_quality_test_fixture.h" >+ >+namespace webrtc { >+ >+std::unique_ptr<VideoQualityTestFixtureInterface> >+CreateVideoQualityTestFixture(); >+ >+std::unique_ptr<VideoQualityTestFixtureInterface> >+CreateVideoQualityTestFixture( >+ std::unique_ptr<FecControllerFactoryInterface> fec_controller_factory); >+ >+} >+ >+#endif // API_TEST_CREATE_VIDEO_QUALITY_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.cc >new file mode 100644 >index 00000000000..df8ad8b35fc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.cc >@@ -0,0 +1,39 @@ >+/* >+ * Copyright (c) 2018 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 "api/test/create_videocodec_test_fixture.h" >+ >+#include <memory> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "api/test/videocodec_test_fixture.h" >+#include "modules/video_coding/codecs/test/videocodec_test_fixture_impl.h" >+ >+namespace webrtc { >+namespace test { >+ >+using Config = VideoCodecTestFixture::Config; >+ >+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture( >+ const Config& config) { >+ return absl::make_unique<VideoCodecTestFixtureImpl>(config); >+} >+ >+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture( >+ const Config& config, >+ std::unique_ptr<VideoDecoderFactory> decoder_factory, >+ std::unique_ptr<VideoEncoderFactory> encoder_factory) { >+ return absl::make_unique<VideoCodecTestFixtureImpl>( >+ config, std::move(decoder_factory), std::move(encoder_factory)); >+} >+ >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.h >new file mode 100644 >index 00000000000..7a44f6b0580 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/create_videocodec_test_fixture.h >@@ -0,0 +1,34 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_ >+#define API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_ >+ >+#include <memory> >+ >+#include "api/test/videocodec_test_fixture.h" >+#include "api/video_codecs/video_decoder_factory.h" >+#include "api/video_codecs/video_encoder_factory.h" >+ >+namespace webrtc { >+namespace test { >+ >+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture( >+ const VideoCodecTestFixture::Config& config); >+ >+std::unique_ptr<VideoCodecTestFixture> CreateVideoCodecTestFixture( >+ const VideoCodecTestFixture::Config& config, >+ std::unique_ptr<VideoDecoderFactory> decoder_factory, >+ std::unique_ptr<VideoEncoderFactory> encoder_factory); >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_CREATE_VIDEOCODEC_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/fakeconstraints.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/fakeconstraints.h >index 2010400aa4e..d9c767de335 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/fakeconstraints.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/fakeconstraints.h >@@ -21,20 +21,16 @@ namespace webrtc { > > class FakeConstraints : public webrtc::MediaConstraintsInterface { > public: >- FakeConstraints() { } >- virtual ~FakeConstraints() { } >+ FakeConstraints() {} >+ virtual ~FakeConstraints() {} > >- virtual const Constraints& GetMandatory() const { >- return mandatory_; >- } >+ virtual const Constraints& GetMandatory() const { return mandatory_; } > >- virtual const Constraints& GetOptional() const { >- return optional_; >- } >+ virtual const Constraints& GetOptional() const { return optional_; } > > template <class T> > void AddMandatory(const std::string& key, const T& value) { >- mandatory_.push_back(Constraint(key, rtc::ToString<T>(value))); >+ mandatory_.push_back(Constraint(key, rtc::ToString(value))); > } > > template <class T> >@@ -49,12 +45,12 @@ class FakeConstraints : public webrtc::MediaConstraintsInterface { > } > } > } >- mandatory_.push_back(Constraint(key, rtc::ToString<T>(value))); >+ mandatory_.push_back(Constraint(key, rtc::ToString(value))); > } > > template <class T> > void AddOptional(const std::string& key, const T& value) { >- optional_.push_back(Constraint(key, rtc::ToString<T>(value))); >+ optional_.push_back(Constraint(key, rtc::ToString(value))); > } > > void SetMandatoryMinAspectRatio(double ratio) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_peerconnectioninterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_peerconnectioninterface.h >new file mode 100644 >index 00000000000..58ca741033e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_peerconnectioninterface.h >@@ -0,0 +1,139 @@ >+/* >+ * Copyright 2016 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. >+ */ >+ >+#ifndef API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_ >+#define API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_ >+ >+#include <memory> >+#include <string> >+#include <utility> >+#include <vector> >+ >+#include "api/peerconnectioninterface.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+ >+class MockPeerConnectionInterface >+ : public rtc::RefCountedObject<webrtc::PeerConnectionInterface> { >+ public: >+ // PeerConnectionInterface >+ MOCK_METHOD0(local_streams, rtc::scoped_refptr<StreamCollectionInterface>()); >+ MOCK_METHOD0(remote_streams, rtc::scoped_refptr<StreamCollectionInterface>()); >+ MOCK_METHOD1(AddStream, bool(MediaStreamInterface*)); >+ MOCK_METHOD1(RemoveStream, void(MediaStreamInterface*)); >+ MOCK_METHOD2(AddTrack, >+ RTCErrorOr<rtc::scoped_refptr<RtpSenderInterface>>( >+ rtc::scoped_refptr<MediaStreamTrackInterface>, >+ const std::vector<std::string>&)); >+ MOCK_METHOD2(AddTrack, >+ rtc::scoped_refptr<RtpSenderInterface>( >+ MediaStreamTrackInterface*, >+ std::vector<MediaStreamInterface*>)); >+ MOCK_METHOD1(RemoveTrack, bool(RtpSenderInterface*)); >+ MOCK_METHOD1(AddTransceiver, >+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>( >+ rtc::scoped_refptr<MediaStreamTrackInterface>)); >+ MOCK_METHOD2(AddTransceiver, >+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>( >+ rtc::scoped_refptr<MediaStreamTrackInterface>, >+ const RtpTransceiverInit&)); >+ MOCK_METHOD1(AddTransceiver, >+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>( >+ cricket::MediaType)); >+ MOCK_METHOD2(AddTransceiver, >+ RTCErrorOr<rtc::scoped_refptr<RtpTransceiverInterface>>( >+ cricket::MediaType, >+ const RtpTransceiverInit&)); >+ MOCK_METHOD2(CreateSender, >+ rtc::scoped_refptr<RtpSenderInterface>(const std::string&, >+ const std::string&)); >+ MOCK_CONST_METHOD0(GetSenders, >+ std::vector<rtc::scoped_refptr<RtpSenderInterface>>()); >+ MOCK_CONST_METHOD0(GetReceivers, >+ std::vector<rtc::scoped_refptr<RtpReceiverInterface>>()); >+ MOCK_CONST_METHOD0( >+ GetTransceivers, >+ std::vector<rtc::scoped_refptr<RtpTransceiverInterface>>()); >+ MOCK_METHOD3(GetStats, >+ bool(StatsObserver*, >+ MediaStreamTrackInterface*, >+ StatsOutputLevel)); >+ MOCK_METHOD1(GetStats, void(RTCStatsCollectorCallback*)); >+ MOCK_METHOD2(GetStats, >+ void(rtc::scoped_refptr<RtpSenderInterface>, >+ rtc::scoped_refptr<RTCStatsCollectorCallback>)); >+ MOCK_METHOD2(GetStats, >+ void(rtc::scoped_refptr<RtpReceiverInterface>, >+ rtc::scoped_refptr<RTCStatsCollectorCallback>)); >+ MOCK_METHOD0(ClearStatsCache, void()); >+ MOCK_METHOD2( >+ CreateDataChannel, >+ rtc::scoped_refptr<DataChannelInterface>(const std::string&, >+ const DataChannelInit*)); >+ MOCK_CONST_METHOD0(local_description, const SessionDescriptionInterface*()); >+ MOCK_CONST_METHOD0(remote_description, const SessionDescriptionInterface*()); >+ MOCK_CONST_METHOD0(current_local_description, >+ const SessionDescriptionInterface*()); >+ MOCK_CONST_METHOD0(current_remote_description, >+ const SessionDescriptionInterface*()); >+ MOCK_CONST_METHOD0(pending_local_description, >+ const SessionDescriptionInterface*()); >+ MOCK_CONST_METHOD0(pending_remote_description, >+ const SessionDescriptionInterface*()); >+ MOCK_METHOD2(CreateOffer, >+ void(CreateSessionDescriptionObserver*, >+ const MediaConstraintsInterface*)); >+ MOCK_METHOD2(CreateOffer, >+ void(CreateSessionDescriptionObserver*, >+ const RTCOfferAnswerOptions&)); >+ MOCK_METHOD2(CreateAnswer, >+ void(CreateSessionDescriptionObserver*, >+ const RTCOfferAnswerOptions&)); >+ MOCK_METHOD2(CreateAnswer, >+ void(CreateSessionDescriptionObserver*, >+ const MediaConstraintsInterface*)); >+ MOCK_METHOD2(SetLocalDescription, >+ void(SetSessionDescriptionObserver*, >+ SessionDescriptionInterface*)); >+ MOCK_METHOD2(SetRemoteDescription, >+ void(SetSessionDescriptionObserver*, >+ SessionDescriptionInterface*)); >+ MOCK_METHOD2(SetRemoteDescription, >+ void(std::unique_ptr<SessionDescriptionInterface>, >+ rtc::scoped_refptr<SetRemoteDescriptionObserverInterface>)); >+ MOCK_METHOD0(GetConfiguration, PeerConnectionInterface::RTCConfiguration()); >+ MOCK_METHOD2(SetConfiguration, >+ bool(const PeerConnectionInterface::RTCConfiguration&, >+ RTCError*)); >+ MOCK_METHOD1(SetConfiguration, >+ bool(const PeerConnectionInterface::RTCConfiguration&)); >+ MOCK_METHOD1(AddIceCandidate, bool(const IceCandidateInterface*)); >+ MOCK_METHOD1(RemoveIceCandidates, >+ bool(const std::vector<cricket::Candidate>&)); >+ MOCK_METHOD1(SetBitrate, RTCError(const BitrateSettings&)); >+ MOCK_METHOD1(SetBitrate, RTCError(const BitrateParameters&)); >+ MOCK_METHOD1(SetBitrateAllocationStrategy, >+ void(std::unique_ptr<rtc::BitrateAllocationStrategy>)); >+ MOCK_METHOD1(SetAudioPlayout, void(bool)); >+ MOCK_METHOD1(SetAudioRecording, void(bool)); >+ MOCK_METHOD0(signaling_state, SignalingState()); >+ MOCK_METHOD0(ice_connection_state, IceConnectionState()); >+ MOCK_METHOD0(ice_gathering_state, IceGatheringState()); >+ MOCK_METHOD2(StartRtcEventLog, bool(rtc::PlatformFile, int64_t)); >+ MOCK_METHOD2(StartRtcEventLog, >+ bool(std::unique_ptr<RtcEventLogOutput>, int64_t)); >+ MOCK_METHOD0(StopRtcEventLog, void()); >+ MOCK_METHOD0(Close, void()); >+}; >+ >+} // namespace webrtc >+ >+#endif // API_TEST_MOCK_PEERCONNECTIONINTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpreceiver.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpreceiver.h >index 7a612004ba2..de69ceaccdb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpreceiver.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpreceiver.h >@@ -31,7 +31,6 @@ class MockRtpReceiver : public rtc::RefCountedObject<RtpReceiverInterface> { > MOCK_METHOD1(SetParameters, bool(const RtpParameters&)); > MOCK_METHOD1(SetObserver, void(RtpReceiverObserverInterface*)); > MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>()); >- MOCK_CONST_METHOD0(AttachmentId, int()); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpsender.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpsender.h >index 35d048c18ac..22f391b86c2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpsender.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_rtpsender.h >@@ -27,10 +27,9 @@ class MockRtpSender : public rtc::RefCountedObject<RtpSenderInterface> { > MOCK_CONST_METHOD0(media_type, cricket::MediaType()); > MOCK_CONST_METHOD0(id, std::string()); > MOCK_CONST_METHOD0(stream_ids, std::vector<std::string>()); >- MOCK_CONST_METHOD0(GetParameters, RtpParameters()); >- MOCK_METHOD1(SetParameters, bool(const RtpParameters&)); >+ MOCK_METHOD0(GetParameters, RtpParameters()); >+ MOCK_METHOD1(SetParameters, RTCError(const RtpParameters&)); > MOCK_CONST_METHOD0(GetDtmfSender, rtc::scoped_refptr<DtmfSenderInterface>()); >- MOCK_CONST_METHOD0(AttachmentId, int()); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_video_bitrate_allocator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_video_bitrate_allocator.h >new file mode 100644 >index 00000000000..d25537a2b93 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/mock_video_bitrate_allocator.h >@@ -0,0 +1,28 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_ >+#define API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_ >+ >+#include "api/video/video_bitrate_allocator.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+ >+class MockVideoBitrateAllocator : public webrtc::VideoBitrateAllocator { >+ MOCK_METHOD2(GetAllocation, >+ VideoBitrateAllocation(uint32_t total_bitrate, >+ uint32_t framerate)); >+ MOCK_METHOD1(GetPreferredBitrateBps, uint32_t(uint32_t framerate)); >+}; >+ >+} // namespace webrtc >+ >+#endif // API_TEST_MOCK_VIDEO_BITRATE_ALLOCATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulated_network.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulated_network.h >new file mode 100644 >index 00000000000..fcb83cd8a8b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulated_network.h >@@ -0,0 +1,87 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_SIMULATED_NETWORK_H_ >+#define API_TEST_SIMULATED_NETWORK_H_ >+ >+#include <stddef.h> >+#include <stdint.h> >+#include <deque> >+#include <queue> >+#include <vector> >+ >+#include "absl/types/optional.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/random.h" >+#include "rtc_base/thread_annotations.h" >+ >+namespace webrtc { >+ >+struct PacketInFlightInfo { >+ PacketInFlightInfo(size_t size, int64_t send_time_us, uint64_t packet_id) >+ : size(size), send_time_us(send_time_us), packet_id(packet_id) {} >+ >+ size_t size; >+ int64_t send_time_us; >+ // Unique identifier for the packet in relation to other packets in flight. >+ uint64_t packet_id; >+}; >+ >+struct PacketDeliveryInfo { >+ static constexpr int kNotReceived = -1; >+ PacketDeliveryInfo(PacketInFlightInfo source, int64_t receive_time_us) >+ : receive_time_us(receive_time_us), packet_id(source.packet_id) {} >+ int64_t receive_time_us; >+ uint64_t packet_id; >+}; >+ >+// DefaultNetworkSimulationConfig is a default network simulation configuration >+// for default network simulation that will be used by WebRTC if no custom >+// NetworkSimulationInterface is provided. >+struct DefaultNetworkSimulationConfig { >+ DefaultNetworkSimulationConfig() {} >+ // Queue length in number of packets. >+ size_t queue_length_packets = 0; >+ // Delay in addition to capacity induced delay. >+ int queue_delay_ms = 0; >+ // Standard deviation of the extra delay. >+ int delay_standard_deviation_ms = 0; >+ // Link capacity in kbps. >+ int link_capacity_kbps = 0; >+ // Random packet loss. >+ int loss_percent = 0; >+ // If packets are allowed to be reordered. >+ bool allow_reordering = false; >+ // The average length of a burst of lost packets. >+ int avg_burst_loss_length = -1; >+}; >+ >+class NetworkSimulationInterface { >+ public: >+ // DO NOT USE. Use DefaultNetworkSimulationConfig directly. This reference >+ // should be removed when all users will be switched on direct usage. >+ using SimulatedNetworkConfig = DefaultNetworkSimulationConfig; >+ >+ // DO NOT USE. Method added temporary for further refactoring and will be >+ // removed soon. >+ // Sets a new configuration. This won't affect packets already in the pipe. >+ virtual void SetConfig(const SimulatedNetworkConfig& config) = 0; >+ >+ virtual bool EnqueuePacket(PacketInFlightInfo packet_info) = 0; >+ // Retrieves all packets that should be delivered by the given receive time. >+ virtual std::vector<PacketDeliveryInfo> DequeueDeliverablePackets( >+ int64_t receive_time_us) = 0; >+ virtual absl::optional<int64_t> NextDeliveryTimeUs() const = 0; >+ virtual ~NetworkSimulationInterface() = default; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_TEST_SIMULATED_NETWORK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulcast_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulcast_test_fixture.h >new file mode 100644 >index 00000000000..e7eab241348 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/simulcast_test_fixture.h >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_SIMULCAST_TEST_FIXTURE_H_ >+#define API_TEST_SIMULCAST_TEST_FIXTURE_H_ >+ >+namespace webrtc { >+namespace test { >+ >+class SimulcastTestFixture { >+ public: >+ virtual ~SimulcastTestFixture() = default; >+ >+ virtual void TestKeyFrameRequestsOnAllStreams() = 0; >+ virtual void TestPaddingAllStreams() = 0; >+ virtual void TestPaddingTwoStreams() = 0; >+ virtual void TestPaddingTwoStreamsOneMaxedOut() = 0; >+ virtual void TestPaddingOneStream() = 0; >+ virtual void TestPaddingOneStreamTwoMaxedOut() = 0; >+ virtual void TestSendAllStreams() = 0; >+ virtual void TestDisablingStreams() = 0; >+ virtual void TestActiveStreams() = 0; >+ virtual void TestSwitchingToOneStream() = 0; >+ virtual void TestSwitchingToOneOddStream() = 0; >+ virtual void TestSwitchingToOneSmallStream() = 0; >+ virtual void TestSpatioTemporalLayers333PatternEncoder() = 0; >+ virtual void TestSpatioTemporalLayers321PatternEncoder() = 0; >+ virtual void TestStrideEncodeDecode() = 0; >+}; >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_SIMULCAST_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/video_quality_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/video_quality_test_fixture.h >new file mode 100644 >index 00000000000..1d8fc346504 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/video_quality_test_fixture.h >@@ -0,0 +1,111 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_ >+#define API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_ >+ >+#include <map> >+#include <memory> >+#include <string> >+#include <vector> >+ >+#include "api/bitrate_constraints.h" >+#include "api/mediatypes.h" >+#include "api/test/simulated_network.h" >+#include "api/video_codecs/video_encoder_config.h" >+ >+namespace webrtc { >+ >+class VideoQualityTestFixtureInterface { >+ public: >+ // Parameters are grouped into smaller structs to make it easier to set >+ // the desired elements and skip unused, using aggregate initialization. >+ // Unfortunately, C++11 (as opposed to C11) doesn't support unnamed structs, >+ // which makes the implementation of VideoQualityTest a bit uglier. >+ struct Params { >+ Params(); >+ ~Params(); >+ struct CallConfig { >+ bool send_side_bwe; >+ BitrateConstraints call_bitrate_config; >+ int num_thumbnails; >+ // Indicates if secondary_(video|ss|screenshare) structures are used. >+ bool dual_video; >+ } call; >+ struct Video { >+ bool enabled; >+ size_t width; >+ size_t height; >+ int32_t fps; >+ int min_bitrate_bps; >+ int target_bitrate_bps; >+ int max_bitrate_bps; >+ bool suspend_below_min_bitrate; >+ std::string codec; >+ int num_temporal_layers; >+ int selected_tl; >+ int min_transmit_bps; >+ bool ulpfec; >+ bool flexfec; >+ bool automatic_scaling; >+ std::string clip_name; // "Generator" to generate frames instead. >+ size_t capture_device_index; >+ SdpVideoFormat::Parameters sdp_params; >+ } video[2]; >+ struct Audio { >+ bool enabled; >+ bool sync_video; >+ bool dtx; >+ } audio; >+ struct Screenshare { >+ bool enabled; >+ bool generate_slides; >+ int32_t slide_change_interval; >+ int32_t scroll_duration; >+ std::vector<std::string> slides; >+ } screenshare[2]; >+ struct Analyzer { >+ std::string test_label; >+ double avg_psnr_threshold; // (*) >+ double avg_ssim_threshold; // (*) >+ int test_durations_secs; >+ std::string graph_data_output_filename; >+ std::string graph_title; >+ } analyzer; >+ DefaultNetworkSimulationConfig pipe; >+ struct SS { // Spatial scalability. >+ std::vector<VideoStream> streams; // If empty, one stream is assumed. >+ size_t selected_stream; >+ int num_spatial_layers; >+ int selected_sl; >+ InterLayerPredMode inter_layer_pred; >+ // If empty, bitrates are generated in VP9Impl automatically. >+ std::vector<SpatialLayer> spatial_layers; >+ // If set, default parameters will be used instead of |streams|. >+ bool infer_streams; >+ } ss[2]; >+ struct Logging { >+ std::string rtc_event_log_name; >+ std::string rtp_dump_name; >+ std::string encoded_frame_base_path; >+ } logging; >+ }; >+ >+ virtual ~VideoQualityTestFixtureInterface() = default; >+ >+ virtual void RunWithAnalyzer(const Params& params) = 0; >+ virtual void RunWithRenderers(const Params& params) = 0; >+ >+ virtual const std::map<uint8_t, webrtc::MediaType>& payload_type_map() = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_TEST_VIDEO_QUALITY_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_fixture.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_fixture.h >new file mode 100644 >index 00000000000..ec69e50ae19 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_fixture.h >@@ -0,0 +1,153 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_VIDEOCODEC_TEST_FIXTURE_H_ >+#define API_TEST_VIDEOCODEC_TEST_FIXTURE_H_ >+ >+#include <string> >+#include <vector> >+ >+#include "api/test/videocodec_test_stats.h" >+#include "api/video_codecs/video_decoder_factory.h" >+#include "api/video_codecs/video_encoder_factory.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+ >+namespace webrtc { >+namespace test { >+ >+// Rates for the encoder and the frame number when to change profile. >+struct RateProfile { >+ size_t target_kbps; >+ size_t input_fps; >+ size_t frame_index_rate_update; >+}; >+ >+struct RateControlThresholds { >+ double max_avg_bitrate_mismatch_percent; >+ double max_time_to_reach_target_bitrate_sec; >+ // TODO(ssilkin): Use absolute threshold for framerate. >+ double max_avg_framerate_mismatch_percent; >+ double max_avg_buffer_level_sec; >+ double max_max_key_frame_delay_sec; >+ double max_max_delta_frame_delay_sec; >+ size_t max_num_spatial_resizes; >+ size_t max_num_key_frames; >+}; >+ >+struct QualityThresholds { >+ double min_avg_psnr; >+ double min_min_psnr; >+ double min_avg_ssim; >+ double min_min_ssim; >+}; >+ >+struct BitstreamThresholds { >+ size_t max_max_nalu_size_bytes; >+}; >+ >+// NOTE: This class is still under development and may change without notice. >+class VideoCodecTestFixture { >+ public: >+ class EncodedFrameChecker { >+ public: >+ virtual ~EncodedFrameChecker() = default; >+ virtual void CheckEncodedFrame(webrtc::VideoCodecType codec, >+ const EncodedImage& encoded_frame) const = 0; >+ }; >+ >+ struct Config { >+ Config(); >+ void SetCodecSettings(std::string codec_name, >+ size_t num_simulcast_streams, >+ size_t num_spatial_layers, >+ size_t num_temporal_layers, >+ bool denoising_on, >+ bool frame_dropper_on, >+ bool spatial_resize_on, >+ size_t width, >+ size_t height); >+ >+ size_t NumberOfCores() const; >+ size_t NumberOfTemporalLayers() const; >+ size_t NumberOfSpatialLayers() const; >+ size_t NumberOfSimulcastStreams() const; >+ >+ std::string ToString() const; >+ std::string CodecName() const; >+ bool IsAsyncCodec() const; >+ >+ // Plain name of YUV file to process without file extension. >+ std::string filename; >+ >+ // File to process. This must be a video file in the YUV format. >+ std::string filepath; >+ >+ // Number of frames to process. >+ size_t num_frames = 0; >+ >+ // Bitstream constraints. >+ size_t max_payload_size_bytes = 1440; >+ >+ // Should we decode the encoded frames? >+ bool decode = true; >+ >+ // Force the encoder and decoder to use a single core for processing. >+ bool use_single_core = false; >+ >+ // Should cpu usage be measured? >+ // If set to true, the encoding will run in real-time. >+ bool measure_cpu = false; >+ >+ // If > 0: forces the encoder to create a keyframe every Nth frame. >+ size_t keyframe_interval = 0; >+ >+ // Codec settings to use. >+ webrtc::VideoCodec codec_settings; >+ >+ // Name of the codec being tested. >+ std::string codec_name; >+ >+ // H.264 specific settings. >+ struct H264CodecSettings { >+ H264::Profile profile = H264::kProfileConstrainedBaseline; >+ H264PacketizationMode packetization_mode = >+ webrtc::H264PacketizationMode::NonInterleaved; >+ } h264_codec_settings; >+ >+ // Should hardware accelerated codecs be used? >+ bool hw_encoder = false; >+ bool hw_decoder = false; >+ >+ // Custom checker that will be called for each frame. >+ const EncodedFrameChecker* encoded_frame_checker = nullptr; >+ >+ // Print out frame level stats. >+ bool print_frame_level_stats = false; >+ >+ // Should video be saved persistently to disk for post-run visualization? >+ struct VisualizationParams { >+ bool save_encoded_ivf = false; >+ bool save_decoded_y4m = false; >+ } visualization_params; >+ }; >+ >+ virtual ~VideoCodecTestFixture() = default; >+ >+ virtual void RunTest(const std::vector<RateProfile>& rate_profiles, >+ const std::vector<RateControlThresholds>* rc_thresholds, >+ const std::vector<QualityThresholds>* quality_thresholds, >+ const BitstreamThresholds* bs_thresholds) = 0; >+ virtual VideoCodecTestStats& GetStats() = 0; >+}; >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_VIDEOCODEC_TEST_FIXTURE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.cc >new file mode 100644 >index 00000000000..72522785cf0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.cc >@@ -0,0 +1,95 @@ >+/* >+ * Copyright (c) 2018 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 "api/test/videocodec_test_stats.h" >+ >+namespace webrtc { >+namespace test { >+ >+std::string VideoCodecTestStats::FrameStatistics::ToString() const { >+ std::stringstream ss; >+ ss << "frame_number " << frame_number; >+ ss << " decoded_width " << decoded_width; >+ ss << " decoded_height " << decoded_height; >+ ss << " spatial_idx " << spatial_idx; >+ ss << " temporal_idx " << temporal_idx; >+ ss << " inter_layer_predicted " << inter_layer_predicted; >+ ss << " non_ref_for_inter_layer_pred " << non_ref_for_inter_layer_pred; >+ ss << " frame_type " << frame_type; >+ ss << " length_bytes " << length_bytes; >+ ss << " qp " << qp; >+ ss << " psnr " << psnr; >+ ss << " psnr_y " << psnr_y; >+ ss << " psnr_u " << psnr_u; >+ ss << " psnr_v " << psnr_v; >+ ss << " ssim " << ssim; >+ ss << " encode_time_us " << encode_time_us; >+ ss << " decode_time_us " << decode_time_us; >+ ss << " rtp_timestamp " << rtp_timestamp; >+ ss << " target_bitrate_kbps " << target_bitrate_kbps; >+ return ss.str(); >+} >+ >+VideoCodecTestStats::VideoStatistics::VideoStatistics() = default; >+VideoCodecTestStats::VideoStatistics::VideoStatistics(const VideoStatistics&) = >+ default; >+ >+std::string VideoCodecTestStats::VideoStatistics::ToString( >+ std::string prefix) const { >+ std::stringstream ss; >+ ss << prefix << "target_bitrate_kbps: " << target_bitrate_kbps; >+ ss << "\n" << prefix << "input_framerate_fps: " << input_framerate_fps; >+ ss << "\n" << prefix << "spatial_idx: " << spatial_idx; >+ ss << "\n" << prefix << "temporal_idx: " << temporal_idx; >+ ss << "\n" << prefix << "width: " << width; >+ ss << "\n" << prefix << "height: " << height; >+ ss << "\n" << prefix << "length_bytes: " << length_bytes; >+ ss << "\n" << prefix << "bitrate_kbps: " << bitrate_kbps; >+ ss << "\n" << prefix << "framerate_fps: " << framerate_fps; >+ ss << "\n" << prefix << "enc_speed_fps: " << enc_speed_fps; >+ ss << "\n" << prefix << "dec_speed_fps: " << dec_speed_fps; >+ ss << "\n" << prefix << "avg_delay_sec: " << avg_delay_sec; >+ ss << "\n" >+ << prefix << "max_key_frame_delay_sec: " << max_key_frame_delay_sec; >+ ss << "\n" >+ << prefix << "max_delta_frame_delay_sec: " << max_delta_frame_delay_sec; >+ ss << "\n" >+ << prefix << "time_to_reach_target_bitrate_sec: " >+ << time_to_reach_target_bitrate_sec; >+ ss << "\n" >+ << prefix << "avg_key_frame_size_bytes: " << avg_key_frame_size_bytes; >+ ss << "\n" >+ << prefix << "avg_delta_frame_size_bytes: " << avg_delta_frame_size_bytes; >+ ss << "\n" << prefix << "avg_qp: " << avg_qp; >+ ss << "\n" << prefix << "avg_psnr: " << avg_psnr; >+ ss << "\n" << prefix << "min_psnr: " << min_psnr; >+ ss << "\n" << prefix << "avg_ssim: " << avg_ssim; >+ ss << "\n" << prefix << "min_ssim: " << min_ssim; >+ ss << "\n" << prefix << "num_input_frames: " << num_input_frames; >+ ss << "\n" << prefix << "num_encoded_frames: " << num_encoded_frames; >+ ss << "\n" << prefix << "num_decoded_frames: " << num_decoded_frames; >+ ss << "\n" >+ << prefix >+ << "num_dropped_frames: " << num_input_frames - num_encoded_frames; >+ ss << "\n" << prefix << "num_key_frames: " << num_key_frames; >+ ss << "\n" << prefix << "num_spatial_resizes: " << num_spatial_resizes; >+ ss << "\n" << prefix << "max_nalu_size_bytes: " << max_nalu_size_bytes; >+ return ss.str(); >+} >+ >+VideoCodecTestStats::FrameStatistics::FrameStatistics(size_t frame_number, >+ size_t rtp_timestamp) >+ : frame_number(frame_number), rtp_timestamp(rtp_timestamp) {} >+ >+VideoCodecTestStats::FrameStatistics::FrameStatistics( >+ const FrameStatistics& rhs) = default; >+ >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.h >new file mode 100644 >index 00000000000..de6d3500d43 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/test/videocodec_test_stats.h >@@ -0,0 +1,149 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TEST_VIDEOCODEC_TEST_STATS_H_ >+#define API_TEST_VIDEOCODEC_TEST_STATS_H_ >+ >+#include <map> >+#include <string> >+#include <vector> >+ >+#include "common_types.h" // NOLINT(build/include) >+ >+namespace webrtc { >+namespace test { >+ >+// Statistics for a sequence of processed frames. This class is not thread safe. >+class VideoCodecTestStats { >+ public: >+ // Statistics for one processed frame. >+ struct FrameStatistics { >+ FrameStatistics(size_t frame_number, size_t rtp_timestamp); >+ FrameStatistics(const FrameStatistics& rhs); >+ >+ std::string ToString() const; >+ >+ size_t frame_number = 0; >+ size_t rtp_timestamp = 0; >+ >+ // Encoding. >+ int64_t encode_start_ns = 0; >+ int encode_return_code = 0; >+ bool encoding_successful = false; >+ size_t encode_time_us = 0; >+ size_t target_bitrate_kbps = 0; >+ size_t length_bytes = 0; >+ webrtc::FrameType frame_type = kVideoFrameDelta; >+ >+ // Layering. >+ size_t spatial_idx = 0; >+ size_t temporal_idx = 0; >+ bool inter_layer_predicted = false; >+ bool non_ref_for_inter_layer_pred = true; >+ >+ // H264 specific. >+ size_t max_nalu_size_bytes = 0; >+ >+ // Decoding. >+ int64_t decode_start_ns = 0; >+ int decode_return_code = 0; >+ bool decoding_successful = false; >+ size_t decode_time_us = 0; >+ size_t decoded_width = 0; >+ size_t decoded_height = 0; >+ >+ // Quantization. >+ int qp = -1; >+ >+ // Quality. >+ float psnr_y = 0.0f; >+ float psnr_u = 0.0f; >+ float psnr_v = 0.0f; >+ float psnr = 0.0f; // 10 * log10(255^2 / (mse_y + mse_u + mse_v)). >+ float ssim = 0.0f; // 0.8 * ssim_y + 0.1 * (ssim_u + ssim_v). >+ }; >+ >+ struct VideoStatistics { >+ VideoStatistics(); >+ VideoStatistics(const VideoStatistics&); >+ >+ std::string ToString(std::string prefix) const; >+ >+ size_t target_bitrate_kbps = 0; >+ float input_framerate_fps = 0.0f; >+ >+ size_t spatial_idx = 0; >+ size_t temporal_idx = 0; >+ >+ size_t width = 0; >+ size_t height = 0; >+ >+ size_t length_bytes = 0; >+ size_t bitrate_kbps = 0; >+ float framerate_fps = 0; >+ >+ float enc_speed_fps = 0.0f; >+ float dec_speed_fps = 0.0f; >+ >+ float avg_delay_sec = 0.0f; >+ float max_key_frame_delay_sec = 0.0f; >+ float max_delta_frame_delay_sec = 0.0f; >+ float time_to_reach_target_bitrate_sec = 0.0f; >+ >+ float avg_key_frame_size_bytes = 0.0f; >+ float avg_delta_frame_size_bytes = 0.0f; >+ float avg_qp = 0.0f; >+ >+ float avg_psnr_y = 0.0f; >+ float avg_psnr_u = 0.0f; >+ float avg_psnr_v = 0.0f; >+ float avg_psnr = 0.0f; >+ float min_psnr = 0.0f; >+ float avg_ssim = 0.0f; >+ float min_ssim = 0.0f; >+ >+ size_t num_input_frames = 0; >+ size_t num_encoded_frames = 0; >+ size_t num_decoded_frames = 0; >+ size_t num_key_frames = 0; >+ size_t num_spatial_resizes = 0; >+ size_t max_nalu_size_bytes = 0; >+ }; >+ >+ virtual ~VideoCodecTestStats() = default; >+ >+ // Creates a FrameStatistics for the next frame to be processed. >+ virtual FrameStatistics* AddFrame(size_t timestamp, size_t spatial_idx) = 0; >+ >+ // Returns the FrameStatistics corresponding to |frame_number| or |timestamp|. >+ virtual FrameStatistics* GetFrame(size_t frame_number, >+ size_t spatial_idx) = 0; >+ virtual FrameStatistics* GetFrameWithTimestamp(size_t timestamp, >+ size_t spatial_idx) = 0; >+ >+ virtual std::vector<VideoStatistics> SliceAndCalcLayerVideoStatistic( >+ size_t first_frame_num, >+ size_t last_frame_num) = 0; >+ >+ virtual VideoStatistics SliceAndCalcAggregatedVideoStatistic( >+ size_t first_frame_num, >+ size_t last_frame_num) = 0; >+ >+ virtual void PrintFrameStatistics() = 0; >+ >+ virtual size_t Size(size_t spatial_idx) = 0; >+ >+ virtual void Clear() = 0; >+}; >+ >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TEST_VIDEOCODEC_TEST_STATS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/BUILD.gn >new file mode 100644 >index 00000000000..f473179dd14 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/BUILD.gn >@@ -0,0 +1,54 @@ >+# Copyright (c) 2018 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. >+ >+import("../../webrtc.gni") >+ >+rtc_source_set("bitrate_settings") { >+ visibility = [ "*" ] >+ sources = [ >+ "bitrate_settings.cc", >+ "bitrate_settings.h", >+ ] >+ deps = [ >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_static_library("network_control") { >+ sources = [ >+ "network_control.h", >+ "network_types.cc", >+ "network_types.h", >+ ] >+ >+ deps = [ >+ "../units:data_rate", >+ "../units:data_size", >+ "../units:time_delta", >+ "../units:timestamp", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+if (rtc_include_tests) { >+ rtc_source_set("network_control_test") { >+ testonly = true >+ sources = [ >+ "test/mock_network_control.h", >+ "test/network_control_tester.cc", >+ "test/network_control_tester.h", >+ ] >+ deps = [ >+ ":network_control", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ "../../test:test_support", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.cc >new file mode 100644 >index 00000000000..c72bd827911 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.cc >@@ -0,0 +1,19 @@ >+/* >+ * Copyright (c) 2018 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 "api/transport/bitrate_settings.h" >+ >+namespace webrtc { >+ >+BitrateSettings::BitrateSettings() = default; >+BitrateSettings::~BitrateSettings() = default; >+BitrateSettings::BitrateSettings(const BitrateSettings&) = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.h >new file mode 100644 >index 00000000000..77654bc4016 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/bitrate_settings.h >@@ -0,0 +1,35 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TRANSPORT_BITRATE_SETTINGS_H_ >+#define API_TRANSPORT_BITRATE_SETTINGS_H_ >+ >+#include "absl/types/optional.h" >+ >+namespace webrtc { >+ >+// Configuration of send bitrate. The |start_bitrate_bps| value is >+// used for multiple purposes, both as a prior in the bandwidth >+// estimator, and for initial configuration of the encoder. We may >+// want to create separate apis for those, and use a smaller struct >+// with only the min and max constraints. >+struct BitrateSettings { >+ BitrateSettings(); >+ ~BitrateSettings(); >+ BitrateSettings(const BitrateSettings&); >+ // 0 <= min <= start <= max should hold for set parameters. >+ absl::optional<int> min_bitrate_bps; >+ absl::optional<int> start_bitrate_bps; >+ absl::optional<int> max_bitrate_bps; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_TRANSPORT_BITRATE_SETTINGS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_control.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_control.h >new file mode 100644 >index 00000000000..abd945d8970 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_control.h >@@ -0,0 +1,93 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TRANSPORT_NETWORK_CONTROL_H_ >+#define API_TRANSPORT_NETWORK_CONTROL_H_ >+#include <stdint.h> >+#include <memory> >+ >+#include "api/transport/network_types.h" >+ >+namespace webrtc { >+ >+class TargetTransferRateObserver { >+ public: >+ virtual ~TargetTransferRateObserver() = default; >+ // Called to indicate target transfer rate as well as giving information about >+ // the current estimate of network parameters. >+ virtual void OnTargetTransferRate(TargetTransferRate) = 0; >+}; >+ >+// Configuration sent to factory create function. The parameters here are >+// optional to use for a network controller implementation. >+struct NetworkControllerConfig { >+ // The initial constraints to start with, these can be changed at any later >+ // time by calls to OnTargetRateConstraints. >+ TargetRateConstraints constraints; >+ // Initial stream specific configuration, these are changed at any later time >+ // by calls to OnStreamsConfig. >+ StreamsConfig stream_based_config; >+ // The initial bandwidth estimate to base target rate on. This should be used >+ // as the basis for initial OnTargetTransferRate and OnPacerConfig callbacks. >+ // Note that starting rate is only provided on construction. >+ DataRate starting_bandwidth = DataRate::Infinity(); >+}; >+ >+// NetworkControllerInterface is implemented by network controllers. A network >+// controller is a class that uses information about network state and traffic >+// to estimate network parameters such as round trip time and bandwidth. Network >+// controllers does not guarantee thread safety, the interface must be used in a >+// non-concurrent fashion. >+class NetworkControllerInterface { >+ public: >+ virtual ~NetworkControllerInterface() = default; >+ >+ // Called when network availabilty changes. >+ virtual NetworkControlUpdate OnNetworkAvailability(NetworkAvailability) = 0; >+ // Called when the receiving or sending endpoint changes address. >+ virtual NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange) = 0; >+ // Called periodically with a periodicy as specified by >+ // NetworkControllerFactoryInterface::GetProcessInterval. >+ virtual NetworkControlUpdate OnProcessInterval(ProcessInterval) = 0; >+ // Called when remotely calculated bitrate is received. >+ virtual NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport) = 0; >+ // Called round trip time has been calculated by protocol specific mechanisms. >+ virtual NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0; >+ // Called when a packet is sent on the network. >+ virtual NetworkControlUpdate OnSentPacket(SentPacket) = 0; >+ // Called when the stream specific configuration has been updated. >+ virtual NetworkControlUpdate OnStreamsConfig(StreamsConfig) = 0; >+ // Called when target transfer rate constraints has been changed. >+ virtual NetworkControlUpdate OnTargetRateConstraints( >+ TargetRateConstraints) = 0; >+ // Called when a protocol specific calculation of packet loss has been made. >+ virtual NetworkControlUpdate OnTransportLossReport(TransportLossReport) = 0; >+ // Called with per packet feedback regarding receive time. >+ virtual NetworkControlUpdate OnTransportPacketsFeedback( >+ TransportPacketsFeedback) = 0; >+}; >+ >+// NetworkControllerFactoryInterface is an interface for creating a network >+// controller. >+class NetworkControllerFactoryInterface { >+ public: >+ virtual ~NetworkControllerFactoryInterface() = default; >+ >+ // Used to create a new network controller, requires an observer to be >+ // provided to handle callbacks. >+ virtual std::unique_ptr<NetworkControllerInterface> Create( >+ NetworkControllerConfig config) = 0; >+ // Returns the interval by which the network controller expects >+ // OnProcessInterval calls. >+ virtual TimeDelta GetProcessInterval() const = 0; >+}; >+} // namespace webrtc >+ >+#endif // API_TRANSPORT_NETWORK_CONTROL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.cc >new file mode 100644 >index 00000000000..b4c09d47c0c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.cc >@@ -0,0 +1,84 @@ >+/* >+ * Copyright (c) 2018 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 "api/transport/network_types.h" >+ >+namespace webrtc { >+ >+StreamsConfig::StreamsConfig() = default; >+StreamsConfig::StreamsConfig(const StreamsConfig&) = default; >+StreamsConfig::~StreamsConfig() = default; >+ >+TargetRateConstraints::TargetRateConstraints() = default; >+TargetRateConstraints::TargetRateConstraints(const TargetRateConstraints&) = >+ default; >+TargetRateConstraints::~TargetRateConstraints() = default; >+ >+NetworkRouteChange::NetworkRouteChange() = default; >+NetworkRouteChange::NetworkRouteChange(const NetworkRouteChange&) = default; >+NetworkRouteChange::~NetworkRouteChange() = default; >+ >+PacketResult::PacketResult() = default; >+PacketResult::PacketResult(const PacketResult& other) = default; >+PacketResult::~PacketResult() = default; >+ >+TransportPacketsFeedback::TransportPacketsFeedback() = default; >+TransportPacketsFeedback::TransportPacketsFeedback( >+ const TransportPacketsFeedback& other) = default; >+TransportPacketsFeedback::~TransportPacketsFeedback() = default; >+ >+std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo() >+ const { >+ std::vector<PacketResult> res; >+ for (const PacketResult& fb : packet_feedbacks) { >+ if (fb.receive_time.IsFinite() && fb.sent_packet.has_value()) { >+ res.push_back(fb); >+ } >+ } >+ return res; >+} >+ >+std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const { >+ std::vector<PacketResult> res; >+ for (const PacketResult& fb : packet_feedbacks) { >+ if (fb.receive_time.IsInfinite() && fb.sent_packet.has_value()) { >+ res.push_back(fb); >+ } >+ } >+ return res; >+} >+ >+std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback() >+ const { >+ return packet_feedbacks; >+} >+ >+NetworkControlUpdate::NetworkControlUpdate() = default; >+NetworkControlUpdate::NetworkControlUpdate(const NetworkControlUpdate&) = >+ default; >+NetworkControlUpdate::~NetworkControlUpdate() = default; >+ >+PacedPacketInfo::PacedPacketInfo() = default; >+ >+PacedPacketInfo::PacedPacketInfo(int probe_cluster_id, >+ int probe_cluster_min_probes, >+ int probe_cluster_min_bytes) >+ : probe_cluster_id(probe_cluster_id), >+ probe_cluster_min_probes(probe_cluster_min_probes), >+ probe_cluster_min_bytes(probe_cluster_min_bytes) {} >+ >+bool PacedPacketInfo::operator==(const PacedPacketInfo& rhs) const { >+ return send_bitrate_bps == rhs.send_bitrate_bps && >+ probe_cluster_id == rhs.probe_cluster_id && >+ probe_cluster_min_probes == rhs.probe_cluster_min_probes && >+ probe_cluster_min_bytes == rhs.probe_cluster_min_bytes; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.h >new file mode 100644 >index 00000000000..a3897168825 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/network_types.h >@@ -0,0 +1,200 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TRANSPORT_NETWORK_TYPES_H_ >+#define API_TRANSPORT_NETWORK_TYPES_H_ >+#include <stdint.h> >+#include <vector> >+ >+#include "absl/types/optional.h" >+#include "api/units/data_rate.h" >+#include "api/units/data_size.h" >+#include "api/units/time_delta.h" >+#include "api/units/timestamp.h" >+ >+namespace webrtc { >+ >+// Configuration >+ >+// Use StreamsConfig for information about streams that is required for specific >+// adjustments to the algorithms in network controllers. Especially useful >+// for experiments. >+struct StreamsConfig { >+ StreamsConfig(); >+ StreamsConfig(const StreamsConfig&); >+ ~StreamsConfig(); >+ Timestamp at_time = Timestamp::Infinity(); >+ bool requests_alr_probing = false; >+ absl::optional<double> pacing_factor; >+ absl::optional<DataRate> min_pacing_rate; >+ absl::optional<DataRate> max_padding_rate; >+ absl::optional<DataRate> max_total_allocated_bitrate; >+}; >+ >+struct TargetRateConstraints { >+ TargetRateConstraints(); >+ TargetRateConstraints(const TargetRateConstraints&); >+ ~TargetRateConstraints(); >+ Timestamp at_time = Timestamp::Infinity(); >+ absl::optional<DataRate> min_data_rate; >+ absl::optional<DataRate> max_data_rate; >+}; >+ >+// Send side information >+ >+struct NetworkAvailability { >+ Timestamp at_time = Timestamp::Infinity(); >+ bool network_available = false; >+}; >+ >+struct NetworkRouteChange { >+ NetworkRouteChange(); >+ NetworkRouteChange(const NetworkRouteChange&); >+ ~NetworkRouteChange(); >+ Timestamp at_time = Timestamp::Infinity(); >+ // The TargetRateConstraints are set here so they can be changed synchronously >+ // when network route changes. >+ TargetRateConstraints constraints; >+ absl::optional<DataRate> starting_rate; >+}; >+ >+struct PacedPacketInfo { >+ PacedPacketInfo(); >+ PacedPacketInfo(int probe_cluster_id, >+ int probe_cluster_min_probes, >+ int probe_cluster_min_bytes); >+ >+ bool operator==(const PacedPacketInfo& rhs) const; >+ >+ // TODO(srte): Move probing info to a separate, optional struct. >+ static constexpr int kNotAProbe = -1; >+ int send_bitrate_bps = -1; >+ int probe_cluster_id = kNotAProbe; >+ int probe_cluster_min_probes = -1; >+ int probe_cluster_min_bytes = -1; >+}; >+ >+struct SentPacket { >+ Timestamp send_time = Timestamp::Infinity(); >+ DataSize size = DataSize::Zero(); >+ PacedPacketInfo pacing_info; >+ // Transport independent sequence number, any tracked packet should have a >+ // sequence number that is unique over the whole call and increasing by 1 for >+ // each packet. >+ int64_t sequence_number; >+ // Data in flight when the packet was sent, including the packet. >+ DataSize data_in_flight = DataSize::Zero(); >+}; >+ >+// Transport level feedback >+ >+struct RemoteBitrateReport { >+ Timestamp receive_time = Timestamp::Infinity(); >+ DataRate bandwidth = DataRate::Infinity(); >+}; >+ >+struct RoundTripTimeUpdate { >+ Timestamp receive_time = Timestamp::Infinity(); >+ TimeDelta round_trip_time = TimeDelta::PlusInfinity(); >+ bool smoothed = false; >+}; >+ >+struct TransportLossReport { >+ Timestamp receive_time = Timestamp::Infinity(); >+ Timestamp start_time = Timestamp::Infinity(); >+ Timestamp end_time = Timestamp::Infinity(); >+ uint64_t packets_lost_delta = 0; >+ uint64_t packets_received_delta = 0; >+}; >+ >+// Packet level feedback >+ >+struct PacketResult { >+ PacketResult(); >+ PacketResult(const PacketResult&); >+ ~PacketResult(); >+ >+ absl::optional<SentPacket> sent_packet; >+ Timestamp receive_time = Timestamp::Infinity(); >+}; >+ >+struct TransportPacketsFeedback { >+ TransportPacketsFeedback(); >+ TransportPacketsFeedback(const TransportPacketsFeedback& other); >+ ~TransportPacketsFeedback(); >+ >+ Timestamp feedback_time = Timestamp::Infinity(); >+ DataSize data_in_flight = DataSize::Zero(); >+ DataSize prior_in_flight = DataSize::Zero(); >+ std::vector<PacketResult> packet_feedbacks; >+ >+ std::vector<PacketResult> ReceivedWithSendInfo() const; >+ std::vector<PacketResult> LostWithSendInfo() const; >+ std::vector<PacketResult> PacketsWithFeedback() const; >+}; >+ >+// Network estimation >+ >+struct NetworkEstimate { >+ Timestamp at_time = Timestamp::Infinity(); >+ DataRate bandwidth = DataRate::Infinity(); >+ TimeDelta round_trip_time = TimeDelta::PlusInfinity(); >+ TimeDelta bwe_period = TimeDelta::PlusInfinity(); >+ >+ float loss_rate_ratio = 0; >+}; >+ >+// Network control >+ >+struct PacerConfig { >+ Timestamp at_time = Timestamp::Infinity(); >+ // Pacer should send at most data_window data over time_window duration. >+ DataSize data_window = DataSize::Infinity(); >+ TimeDelta time_window = TimeDelta::PlusInfinity(); >+ // Pacer should send at least pad_window data over time_window duration. >+ DataSize pad_window = DataSize::Zero(); >+ DataRate data_rate() const { return data_window / time_window; } >+ DataRate pad_rate() const { return pad_window / time_window; } >+}; >+ >+struct ProbeClusterConfig { >+ Timestamp at_time = Timestamp::Infinity(); >+ DataRate target_data_rate = DataRate::Zero(); >+ TimeDelta target_duration = TimeDelta::Zero(); >+ int32_t target_probe_count = 0; >+}; >+ >+struct TargetTransferRate { >+ Timestamp at_time = Timestamp::Infinity(); >+ // The estimate on which the target rate is based on. >+ NetworkEstimate network_estimate; >+ DataRate target_rate = DataRate::Zero(); >+}; >+ >+// Contains updates of network controller comand state. Using optionals to >+// indicate whether a member has been updated. The array of probe clusters >+// should be used to send out probes if not empty. >+struct NetworkControlUpdate { >+ NetworkControlUpdate(); >+ NetworkControlUpdate(const NetworkControlUpdate&); >+ ~NetworkControlUpdate(); >+ absl::optional<DataSize> congestion_window; >+ absl::optional<PacerConfig> pacer_config; >+ std::vector<ProbeClusterConfig> probe_cluster_configs; >+ absl::optional<TargetTransferRate> target_rate; >+}; >+ >+// Process control >+struct ProcessInterval { >+ Timestamp at_time = Timestamp::Infinity(); >+}; >+} // namespace webrtc >+ >+#endif // API_TRANSPORT_NETWORK_TYPES_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/mock_network_control.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/mock_network_control.h >new file mode 100644 >index 00000000000..df83791e18c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/mock_network_control.h >@@ -0,0 +1,26 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_ >+#define API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_ >+ >+#include "api/transport/include/network_control.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+namespace test { >+class MockTargetTransferRateObserver : public TargetTransferRateObserver { >+ public: >+ MOCK_METHOD1(OnTargetTransferRate, void(TargetTransferRate)); >+}; >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TRANSPORT_TEST_MOCK_NETWORK_CONTROL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.cc >new file mode 100644 >index 00000000000..2edabd0717e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.cc >@@ -0,0 +1,147 @@ >+/* >+ * Copyright (c) 2018 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 "api/transport/test/network_control_tester.h" >+ >+#include <algorithm> >+ >+#include "api/transport/network_control.h" >+#include "rtc_base/logging.h" >+ >+namespace webrtc { >+namespace test { >+namespace { >+void Update(NetworkControlUpdate* target, const NetworkControlUpdate& update) { >+ if (update.congestion_window) { >+ RTC_LOG(LS_INFO) << "Received window=" >+ << ToString(*update.congestion_window); >+ target->congestion_window = update.congestion_window; >+ } >+ if (update.pacer_config) { >+ RTC_LOG(LS_INFO) << "Received pacing at:" >+ << ToString(update.pacer_config->at_time) >+ << ": rate=" << ToString(update.pacer_config->data_rate()) >+ << ", pad=" << ToString(update.pacer_config->pad_rate()); >+ target->pacer_config = update.pacer_config; >+ } >+ if (update.target_rate) { >+ RTC_LOG(LS_INFO) >+ << "Received target at:" << ToString(update.target_rate->at_time) >+ << ": rate=" << ToString(update.target_rate->target_rate) << ", rtt=" >+ << ToString(update.target_rate->network_estimate.round_trip_time); >+ target->target_rate = update.target_rate; >+ } >+ for (const auto& probe : update.probe_cluster_configs) { >+ target->probe_cluster_configs.push_back(probe); >+ RTC_LOG(LS_INFO) << "Received probe at:" << ToString(probe.at_time) >+ << ": target=" << ToString(probe.target_data_rate); >+ } >+} >+} // namespace >+ >+SentPacket SimpleTargetRateProducer::ProduceNext( >+ const NetworkControlUpdate& cache, >+ Timestamp current_time, >+ TimeDelta time_delta) { >+ DataRate actual_send_rate = >+ std::max(cache.target_rate->target_rate, cache.pacer_config->pad_rate()); >+ SentPacket packet; >+ packet.send_time = current_time; >+ packet.size = time_delta * actual_send_rate; >+ return packet; >+} >+ >+NetworkControllerTester::NetworkControllerTester( >+ NetworkControllerFactoryInterface* factory, >+ NetworkControllerConfig initial_config) >+ : current_time_(Timestamp::seconds(100000)), >+ packet_sequence_number_(1), >+ accumulated_buffer_(TimeDelta::Zero()) { >+ initial_config.constraints.at_time = current_time_; >+ controller_ = factory->Create(initial_config); >+ process_interval_ = factory->GetProcessInterval(); >+ ProcessInterval interval_msg; >+ interval_msg.at_time = current_time_; >+ Update(&state_, controller_->OnProcessInterval(interval_msg)); >+} >+ >+NetworkControllerTester::~NetworkControllerTester() = default; >+ >+void NetworkControllerTester::RunSimulation(TimeDelta duration, >+ TimeDelta packet_interval, >+ DataRate actual_bandwidth, >+ TimeDelta propagation_delay, >+ PacketProducer next_packet) { >+ RTC_CHECK(actual_bandwidth.bps() > 0); >+ Timestamp start_time = current_time_; >+ Timestamp last_process_time = current_time_; >+ while (current_time_ - start_time < duration) { >+ bool send_packet = true; >+ if (state_.congestion_window && state_.congestion_window->IsFinite()) { >+ DataSize data_in_flight = DataSize::Zero(); >+ for (PacketResult& packet : outstanding_packets_) >+ data_in_flight += packet.sent_packet->size; >+ if (data_in_flight > *state_.congestion_window) >+ send_packet = false; >+ } >+ >+ if (send_packet) { >+ SentPacket sent_packet; >+ sent_packet = next_packet(state_, current_time_, packet_interval); >+ sent_packet.sequence_number = packet_sequence_number_++; >+ sent_packet.data_in_flight = sent_packet.size; >+ for (PacketResult& packet : outstanding_packets_) >+ sent_packet.data_in_flight += packet.sent_packet->size; >+ Update(&state_, controller_->OnSentPacket(sent_packet)); >+ >+ TimeDelta time_in_flight = sent_packet.size / actual_bandwidth; >+ accumulated_buffer_ += time_in_flight; >+ TimeDelta total_delay = propagation_delay + accumulated_buffer_; >+ PacketResult result; >+ result.sent_packet = sent_packet; >+ result.receive_time = sent_packet.send_time + total_delay; >+ >+ outstanding_packets_.push_back(result); >+ } >+ >+ TimeDelta buffer_consumed = std::min(accumulated_buffer_, packet_interval); >+ accumulated_buffer_ -= buffer_consumed; >+ >+ if (outstanding_packets_.size() >= 2 && >+ current_time_ >= >+ outstanding_packets_[1].receive_time + propagation_delay) { >+ TransportPacketsFeedback feedback; >+ feedback.prior_in_flight = DataSize::Zero(); >+ for (PacketResult& packet : outstanding_packets_) >+ feedback.prior_in_flight += packet.sent_packet->size; >+ while (!outstanding_packets_.empty() && >+ current_time_ >= outstanding_packets_.front().receive_time + >+ propagation_delay) { >+ feedback.packet_feedbacks.push_back(outstanding_packets_.front()); >+ outstanding_packets_.pop_front(); >+ } >+ feedback.feedback_time = >+ feedback.packet_feedbacks.back().receive_time + propagation_delay; >+ feedback.data_in_flight = DataSize::Zero(); >+ for (PacketResult& packet : outstanding_packets_) >+ feedback.data_in_flight += packet.sent_packet->size; >+ Update(&state_, controller_->OnTransportPacketsFeedback(feedback)); >+ } >+ current_time_ += packet_interval; >+ if (current_time_ - last_process_time > process_interval_) { >+ ProcessInterval interval_msg; >+ interval_msg.at_time = current_time_; >+ Update(&state_, controller_->OnProcessInterval(interval_msg)); >+ } >+ } >+} >+ >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.h >new file mode 100644 >index 00000000000..4dfcc1498ad >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/transport/test/network_control_tester.h >@@ -0,0 +1,73 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_TRANSPORT_TEST_NETWORK_CONTROL_TESTER_H_ >+#define API_TRANSPORT_TEST_NETWORK_CONTROL_TESTER_H_ >+ >+#include <deque> >+#include <functional> >+#include <memory> >+ >+#include "absl/types/optional.h" >+#include "api/transport/network_control.h" >+ >+namespace webrtc { >+namespace test { >+ >+// Produces one packet per time delta >+class SimpleTargetRateProducer { >+ public: >+ static SentPacket ProduceNext(const NetworkControlUpdate& state, >+ Timestamp current_time, >+ TimeDelta time_delta); >+}; >+ >+class NetworkControllerTester { >+ public: >+ // A PacketProducer is a function that takes a network control state, a >+ // timestamp representing the expected send time and a time delta of the send >+ // times (This allows the PacketProducer to be stateless). It returns a >+ // SentPacket struct with actual send time and packet size. >+ using PacketProducer = std::function< >+ SentPacket(const NetworkControlUpdate&, Timestamp, TimeDelta)>; >+ NetworkControllerTester(NetworkControllerFactoryInterface* factory, >+ NetworkControllerConfig initial_config); >+ ~NetworkControllerTester(); >+ >+ // Runs the simulations for the given duration, the PacketProducer will be >+ // called repeatedly based on the given packet interval and the network will >+ // be simulated using given bandwidth and propagation delay. The simulation >+ // will call the controller under test with OnSentPacket and >+ // OnTransportPacketsFeedback. >+ >+ // Note that OnTransportPacketsFeedback will only be called for >+ // packets with resulting feedback time within the simulated duration. Packets >+ // with later feedback time are saved and used in the next call to >+ // RunSimulation where enough simulated time has passed. >+ void RunSimulation(TimeDelta duration, >+ TimeDelta packet_interval, >+ DataRate actual_bandwidth, >+ TimeDelta propagation_delay, >+ PacketProducer next_packet); >+ NetworkControlUpdate GetState() { return state_; } >+ >+ private: >+ std::unique_ptr<NetworkControllerInterface> controller_; >+ TimeDelta process_interval_ = TimeDelta::PlusInfinity(); >+ Timestamp current_time_; >+ int64_t packet_sequence_number_; >+ TimeDelta accumulated_buffer_; >+ std::deque<PacketResult> outstanding_packets_; >+ NetworkControlUpdate state_; >+}; >+} // namespace test >+} // namespace webrtc >+ >+#endif // API_TRANSPORT_TEST_NETWORK_CONTROL_TESTER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/turncustomizer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/turncustomizer.h >index 517abcc8f0d..85c4e77c9c0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/turncustomizer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/turncustomizer.h >@@ -18,7 +18,6 @@ class PortInterface; > class StunMessage; > } // namespace cricket > >- > namespace webrtc { > > class TurnCustomizer { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/umametrics.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/umametrics.h >index 0d66a5e51fe..88ab08c1bef 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/umametrics.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/umametrics.h >@@ -17,29 +17,6 @@ > > namespace webrtc { > >-// Used to specify which enum counter type we're incrementing in >-// MetricsObserverInterface::IncrementEnumCounter. >-enum PeerConnectionEnumCounterType { >- kEnumCounterAddressFamily, >- // For the next 2 counters, we track them separately based on the "first hop" >- // protocol used by the local candidate. "First hop" means the local candidate >- // type in the case of non-TURN candidates, and the protocol used to connect >- // to the TURN server in the case of TURN candidates. >- kEnumCounterIceCandidatePairTypeUdp, >- kEnumCounterIceCandidatePairTypeTcp, >- >- kEnumCounterAudioSrtpCipher, >- kEnumCounterAudioSslCipher, >- kEnumCounterVideoSrtpCipher, >- kEnumCounterVideoSslCipher, >- kEnumCounterDataSrtpCipher, >- kEnumCounterDataSslCipher, >- kEnumCounterDtlsHandshakeError, >- kEnumCounterIceRegathering, >- kEnumCounterIceRestart, >- kPeerConnectionEnumCounterMax >-}; >- > // Currently this contains information related to WebRTC network/transport > // information. > >@@ -111,26 +88,67 @@ enum IceCandidatePairType { > kIceCandidatePairMax > }; > >-class MetricsObserverInterface : public rtc::RefCountInterface { >- public: >- // |type| is the type of the enum counter to be incremented. |counter| >- // is the particular counter in that type. |counter_max| is the next sequence >- // number after the highest counter. >- virtual void IncrementEnumCounter(PeerConnectionEnumCounterType, >- int, >- int) {} >- >- // This is used to handle sparse counters like SSL cipher suites. >- // TODO(guoweis): Remove the implementation once the dependency's interface >- // definition is updated. >- virtual void IncrementSparseEnumCounter(PeerConnectionEnumCounterType type, >- int counter); >- >- virtual void AddHistogramSample(PeerConnectionMetricsName type, >- int value) = 0; >+enum KeyExchangeProtocolType { >+ kEnumCounterKeyProtocolDtls, >+ kEnumCounterKeyProtocolSdes, >+ kEnumCounterKeyProtocolMax >+}; >+ >+enum KeyExchangeProtocolMedia { >+ kEnumCounterKeyProtocolMediaTypeDtlsAudio, >+ kEnumCounterKeyProtocolMediaTypeDtlsVideo, >+ kEnumCounterKeyProtocolMediaTypeDtlsData, >+ kEnumCounterKeyProtocolMediaTypeSdesAudio, >+ kEnumCounterKeyProtocolMediaTypeSdesVideo, >+ kEnumCounterKeyProtocolMediaTypeSdesData, >+ kEnumCounterKeyProtocolMediaTypeMax >+}; >+ >+enum SdpSemanticRequested { >+ kSdpSemanticRequestDefault, >+ kSdpSemanticRequestPlanB, >+ kSdpSemanticRequestUnifiedPlan, >+ kSdpSemanticRequestMax > }; > >-typedef MetricsObserverInterface UMAObserver; >+enum SdpSemanticNegotiated { >+ kSdpSemanticNegotiatedNone, >+ kSdpSemanticNegotiatedPlanB, >+ kSdpSemanticNegotiatedUnifiedPlan, >+ kSdpSemanticNegotiatedMixed, >+ kSdpSemanticNegotiatedMax >+}; >+ >+// Metric which records the format of the received SDP for tracking how much the >+// difference between Plan B and Unified Plan affect users. >+enum SdpFormatReceived { >+ // No audio or video tracks. This is worth special casing since it seems to be >+ // the most common scenario (data-channel only). >+ kSdpFormatReceivedNoTracks, >+ // No more than one audio and one video track. Should be compatible with both >+ // Plan B and Unified Plan endpoints. >+ kSdpFormatReceivedSimple, >+ // More than one audio track or more than one video track in the Plan B format >+ // (e.g., one audio media section with multiple streams). >+ kSdpFormatReceivedComplexPlanB, >+ // More than one audio track or more than one video track in the Unified Plan >+ // format (e.g., two audio media sections). >+ kSdpFormatReceivedComplexUnifiedPlan, >+ kSdpFormatReceivedMax >+}; >+ >+// Metric for counting the outcome of adding an ICE candidate >+enum AddIceCandidateResult { >+ kAddIceCandidateSuccess, >+ kAddIceCandidateFailClosed, >+ kAddIceCandidateFailNoRemoteDescription, >+ kAddIceCandidateFailNullCandidate, >+ kAddIceCandidateFailNotValid, >+ kAddIceCandidateFailNotReady, >+ kAddIceCandidateFailInAddition, >+ kAddIceCandidateFailNotUsable, >+ kAddIceCandidateMax >+}; > > } // namespace webrtc > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/BUILD.gn >new file mode 100644 >index 00000000000..7dbddf4e622 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/BUILD.gn >@@ -0,0 +1,78 @@ >+# Copyright (c) 2018 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. >+ >+import("../../webrtc.gni") >+ >+rtc_source_set("data_rate") { >+ sources = [ >+ "data_rate.cc", >+ "data_rate.h", >+ ] >+ >+ deps = [ >+ ":data_size", >+ ":time_delta", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+ >+rtc_source_set("data_size") { >+ sources = [ >+ "data_size.cc", >+ "data_size.h", >+ ] >+ >+ deps = [ >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+rtc_source_set("time_delta") { >+ sources = [ >+ "time_delta.cc", >+ "time_delta.h", >+ ] >+ >+ deps = [ >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+ >+rtc_source_set("timestamp") { >+ sources = [ >+ "timestamp.cc", >+ "timestamp.h", >+ ] >+ >+ deps = [ >+ ":time_delta", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ ] >+} >+ >+if (rtc_include_tests) { >+ rtc_source_set("units_unittests") { >+ testonly = true >+ sources = [ >+ "data_rate_unittest.cc", >+ "data_size_unittest.cc", >+ "time_delta_unittest.cc", >+ "timestamp_unittest.cc", >+ ] >+ deps = [ >+ ":data_rate", >+ ":data_size", >+ ":time_delta", >+ ":timestamp", >+ "../../test:test_support", >+ ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.cc >new file mode 100644 >index 00000000000..4e31d51f46e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.cc >@@ -0,0 +1,27 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/data_rate.h" >+ >+#include "rtc_base/strings/string_builder.h" >+ >+namespace webrtc { >+ >+std::string ToString(const DataRate& value) { >+ char buf[64]; >+ rtc::SimpleStringBuilder sb(buf); >+ if (value.IsInfinite()) { >+ sb << "inf bps"; >+ } else { >+ sb << value.bps() << " bps"; >+ } >+ return sb.str(); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.h >new file mode 100644 >index 00000000000..47a143c8897 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate.h >@@ -0,0 +1,202 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_UNITS_DATA_RATE_H_ >+#define API_UNITS_DATA_RATE_H_ >+#include <stdint.h> >+#include <cmath> >+#include <limits> >+#include <string> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/numerics/safe_conversions.h" >+ >+#include "api/units/data_size.h" >+#include "api/units/time_delta.h" >+ >+namespace webrtc { >+namespace data_rate_impl { >+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max(); >+ >+inline int64_t Microbits(const DataSize& size) { >+ constexpr int64_t kMaxBeforeConversion = >+ std::numeric_limits<int64_t>::max() / 8000000; >+ RTC_DCHECK_LE(size.bytes(), kMaxBeforeConversion) >+ << "size is too large to be expressed in microbytes"; >+ return size.bytes() * 8000000; >+} >+} // namespace data_rate_impl >+ >+// DataRate is a class that represents a given data rate. This can be used to >+// represent bandwidth, encoding bitrate, etc. The internal storage is bits per >+// second (bps). >+class DataRate { >+ public: >+ DataRate() = delete; >+ static constexpr DataRate Zero() { return DataRate(0); } >+ static constexpr DataRate Infinity() { >+ return DataRate(data_rate_impl::kPlusInfinityVal); >+ } >+ template <int64_t bps> >+ static constexpr DataRate BitsPerSec() { >+ static_assert(bps >= 0, ""); >+ static_assert(bps < data_rate_impl::kPlusInfinityVal, ""); >+ return DataRate(bps); >+ } >+ template <int64_t kbps> >+ static constexpr DataRate KilobitsPerSec() { >+ static_assert(kbps >= 0, ""); >+ static_assert(kbps < data_rate_impl::kPlusInfinityVal / 1000, ""); >+ return DataRate(kbps * 1000); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static DataRate bps(T bits_per_second) { >+ RTC_DCHECK_GE(bits_per_second, 0); >+ RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal); >+ return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second)); >+ } >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static DataRate kbps(T kilobits_per_sec) { >+ RTC_DCHECK_GE(kilobits_per_sec, 0); >+ RTC_DCHECK_LT(kilobits_per_sec, data_rate_impl::kPlusInfinityVal / 1000); >+ return DataRate::bps(rtc::dchecked_cast<int64_t>(kilobits_per_sec) * 1000); >+ } >+ >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static DataRate bps(T bits_per_second) { >+ if (bits_per_second == std::numeric_limits<T>::infinity()) { >+ return Infinity(); >+ } else { >+ RTC_DCHECK(!std::isnan(bits_per_second)); >+ RTC_DCHECK_GE(bits_per_second, 0); >+ RTC_DCHECK_LT(bits_per_second, data_rate_impl::kPlusInfinityVal); >+ return DataRate(rtc::dchecked_cast<int64_t>(bits_per_second)); >+ } >+ } >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static DataRate kbps(T kilobits_per_sec) { >+ return DataRate::bps(kilobits_per_sec * 1e3); >+ } >+ >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type bps() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(bits_per_sec_); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type kbps() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(UnsafeKilobitsPerSec()); >+ } >+ >+ template <typename T> >+ typename std::enable_if<std::is_floating_point<T>::value, >+ T>::type constexpr bps() const { >+ return IsInfinite() ? std::numeric_limits<T>::infinity() : bits_per_sec_; >+ } >+ template <typename T> >+ typename std::enable_if<std::is_floating_point<T>::value, >+ T>::type constexpr kbps() const { >+ return bps<T>() * 1e-3; >+ } >+ >+ constexpr int64_t bps_or(int64_t fallback_value) const { >+ return IsFinite() ? bits_per_sec_ : fallback_value; >+ } >+ constexpr int64_t kbps_or(int64_t fallback_value) const { >+ return IsFinite() ? UnsafeKilobitsPerSec() : fallback_value; >+ } >+ >+ constexpr bool IsZero() const { return bits_per_sec_ == 0; } >+ constexpr bool IsInfinite() const { >+ return bits_per_sec_ == data_rate_impl::kPlusInfinityVal; >+ } >+ constexpr bool IsFinite() const { return !IsInfinite(); } >+ >+ constexpr double operator/(const DataRate& other) const { >+ return bps<double>() / other.bps<double>(); >+ } >+ constexpr bool operator==(const DataRate& other) const { >+ return bits_per_sec_ == other.bits_per_sec_; >+ } >+ constexpr bool operator!=(const DataRate& other) const { >+ return bits_per_sec_ != other.bits_per_sec_; >+ } >+ constexpr bool operator<=(const DataRate& other) const { >+ return bits_per_sec_ <= other.bits_per_sec_; >+ } >+ constexpr bool operator>=(const DataRate& other) const { >+ return bits_per_sec_ >= other.bits_per_sec_; >+ } >+ constexpr bool operator>(const DataRate& other) const { >+ return bits_per_sec_ > other.bits_per_sec_; >+ } >+ constexpr bool operator<(const DataRate& other) const { >+ return bits_per_sec_ < other.bits_per_sec_; >+ } >+ >+ private: >+ // Bits per second used internally to simplify debugging by making the value >+ // more recognizable. >+ explicit constexpr DataRate(int64_t bits_per_second) >+ : bits_per_sec_(bits_per_second) {} >+ constexpr int64_t UnsafeKilobitsPerSec() const { >+ return (bits_per_sec_ + 500) / 1000; >+ } >+ int64_t bits_per_sec_; >+}; >+ >+inline DataRate operator*(const DataRate& rate, const double& scalar) { >+ return DataRate::bps(std::round(rate.bps() * scalar)); >+} >+inline DataRate operator*(const double& scalar, const DataRate& rate) { >+ return rate * scalar; >+} >+inline DataRate operator*(const DataRate& rate, const int64_t& scalar) { >+ return DataRate::bps(rate.bps() * scalar); >+} >+inline DataRate operator*(const int64_t& scalar, const DataRate& rate) { >+ return rate * scalar; >+} >+inline DataRate operator*(const DataRate& rate, const int32_t& scalar) { >+ return DataRate::bps(rate.bps() * scalar); >+} >+inline DataRate operator*(const int32_t& scalar, const DataRate& rate) { >+ return rate * scalar; >+} >+ >+inline DataRate operator/(const DataSize& size, const TimeDelta& duration) { >+ return DataRate::bps(data_rate_impl::Microbits(size) / duration.us()); >+} >+inline TimeDelta operator/(const DataSize& size, const DataRate& rate) { >+ return TimeDelta::us(data_rate_impl::Microbits(size) / rate.bps()); >+} >+inline DataSize operator*(const DataRate& rate, const TimeDelta& duration) { >+ int64_t microbits = rate.bps() * duration.us(); >+ return DataSize::bytes((microbits + 4000000) / 8000000); >+} >+inline DataSize operator*(const TimeDelta& duration, const DataRate& rate) { >+ return rate * duration; >+} >+ >+std::string ToString(const DataRate& value); >+ >+} // namespace webrtc >+ >+#endif // API_UNITS_DATA_RATE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate_unittest.cc >new file mode 100644 >index 00000000000..9c91fd62470 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_rate_unittest.cc >@@ -0,0 +1,142 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/data_rate.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace test { >+ >+TEST(DataRateTest, ConstExpr) { >+ constexpr int64_t kValue = 12345; >+ constexpr DataRate kDataRateZero = DataRate::Zero(); >+ constexpr DataRate kDataRateInf = DataRate::Infinity(); >+ static_assert(kDataRateZero.IsZero(), ""); >+ static_assert(kDataRateInf.IsInfinite(), ""); >+ static_assert(kDataRateInf.bps_or(-1) == -1, ""); >+ static_assert(kDataRateInf > kDataRateZero, ""); >+ >+ constexpr DataRate kDataRateBps = DataRate::BitsPerSec<kValue>(); >+ constexpr DataRate kDataRateKbps = DataRate::KilobitsPerSec<kValue>(); >+ static_assert(kDataRateBps.bps<double>() == kValue, ""); >+ static_assert(kDataRateBps.bps_or(0) == kValue, ""); >+ static_assert(kDataRateKbps.kbps_or(0) == kValue, ""); >+} >+ >+TEST(DataRateTest, GetBackSameValues) { >+ const int64_t kValue = 123 * 8; >+ EXPECT_EQ(DataRate::bps(kValue).bps(), kValue); >+ EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue); >+} >+ >+TEST(DataRateTest, GetDifferentPrefix) { >+ const int64_t kValue = 123 * 8000; >+ EXPECT_EQ(DataRate::bps(kValue).kbps(), kValue / 1000); >+} >+ >+TEST(DataRateTest, IdentityChecks) { >+ const int64_t kValue = 3000; >+ EXPECT_TRUE(DataRate::Zero().IsZero()); >+ EXPECT_FALSE(DataRate::bps(kValue).IsZero()); >+ >+ EXPECT_TRUE(DataRate::Infinity().IsInfinite()); >+ EXPECT_FALSE(DataRate::Zero().IsInfinite()); >+ EXPECT_FALSE(DataRate::bps(kValue).IsInfinite()); >+ >+ EXPECT_FALSE(DataRate::Infinity().IsFinite()); >+ EXPECT_TRUE(DataRate::bps(kValue).IsFinite()); >+ EXPECT_TRUE(DataRate::Zero().IsFinite()); >+} >+ >+TEST(DataRateTest, ComparisonOperators) { >+ const int64_t kSmall = 450; >+ const int64_t kLarge = 451; >+ const DataRate small = DataRate::bps(kSmall); >+ const DataRate large = DataRate::bps(kLarge); >+ >+ EXPECT_EQ(DataRate::Zero(), DataRate::bps(0)); >+ EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity()); >+ EXPECT_EQ(small, small); >+ EXPECT_LE(small, small); >+ EXPECT_GE(small, small); >+ EXPECT_NE(small, large); >+ EXPECT_LE(small, large); >+ EXPECT_LT(small, large); >+ EXPECT_GE(large, small); >+ EXPECT_GT(large, small); >+ EXPECT_LT(DataRate::Zero(), small); >+ EXPECT_GT(DataRate::Infinity(), large); >+} >+ >+TEST(DataRateTest, ConvertsToAndFromDouble) { >+ const int64_t kValue = 128; >+ const double kDoubleValue = static_cast<double>(kValue); >+ const double kDoubleKbps = kValue * 1e-3; >+ const double kFloatKbps = static_cast<float>(kDoubleKbps); >+ >+ EXPECT_EQ(DataRate::bps(kValue).bps<double>(), kDoubleValue); >+ EXPECT_EQ(DataRate::bps(kValue).kbps<double>(), kDoubleKbps); >+ EXPECT_EQ(DataRate::bps(kValue).kbps<float>(), kFloatKbps); >+ EXPECT_EQ(DataRate::bps(kDoubleValue).bps(), kValue); >+ EXPECT_EQ(DataRate::kbps(kDoubleKbps).bps(), kValue); >+ >+ const double kInfinity = std::numeric_limits<double>::infinity(); >+ EXPECT_EQ(DataRate::Infinity().bps<double>(), kInfinity); >+ EXPECT_TRUE(DataRate::bps(kInfinity).IsInfinite()); >+ EXPECT_TRUE(DataRate::kbps(kInfinity).IsInfinite()); >+} >+ >+TEST(DataRateTest, MathOperations) { >+ const int64_t kValueA = 450; >+ const int64_t kValueB = 267; >+ const DataRate rate_a = DataRate::bps(kValueA); >+ const DataRate rate_b = DataRate::bps(kValueB); >+ const int32_t kInt32Value = 123; >+ const double kFloatValue = 123.0; >+ EXPECT_EQ((rate_a * kValueB).bps(), kValueA * kValueB); >+ EXPECT_EQ((rate_a * kInt32Value).bps(), kValueA * kInt32Value); >+ EXPECT_EQ((rate_a * kFloatValue).bps(), kValueA * kFloatValue); >+ >+ EXPECT_EQ(rate_a / rate_b, static_cast<double>(kValueA) / kValueB); >+} >+ >+TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) { >+ const int64_t kSeconds = 5; >+ const int64_t kBitsPerSecond = 440; >+ const int64_t kBytes = 44000; >+ const TimeDelta delta_a = TimeDelta::seconds(kSeconds); >+ const DataRate rate_b = DataRate::bps(kBitsPerSecond); >+ const DataSize size_c = DataSize::bytes(kBytes); >+ EXPECT_EQ((delta_a * rate_b).bytes(), kSeconds * kBitsPerSecond / 8); >+ EXPECT_EQ((rate_b * delta_a).bytes(), kSeconds * kBitsPerSecond / 8); >+ EXPECT_EQ((size_c / delta_a).bps(), kBytes * 8 / kSeconds); >+ EXPECT_EQ((size_c / rate_b).seconds(), kBytes * 8 / kBitsPerSecond); >+} >+ >+TEST(UnitConversionTest, DivisionFailsOnLargeSize) { >+ // Note that the failure is expected since the current implementation is >+ // implementated in a way that does not support division of large sizes. If >+ // the implementation is changed, this test can safely be removed. >+ const int64_t kJustSmallEnoughForDivision = >+ std::numeric_limits<int64_t>::max() / 8000000; >+ const DataSize large_size = DataSize::bytes(kJustSmallEnoughForDivision); >+ const DataRate data_rate = DataRate::kbps(100); >+ const TimeDelta time_delta = TimeDelta::ms(100); >+ EXPECT_TRUE((large_size / data_rate).IsFinite()); >+ EXPECT_TRUE((large_size / time_delta).IsFinite()); >+#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) && RTC_DCHECK_IS_ON >+ const int64_t kToolargeForDivision = kJustSmallEnoughForDivision + 1; >+ const DataSize too_large_size = DataSize::bytes(kToolargeForDivision); >+ EXPECT_DEATH(too_large_size / data_rate, ""); >+ EXPECT_DEATH(too_large_size / time_delta, ""); >+#endif // GTEST_HAS_DEATH_TEST && !!defined(WEBRTC_ANDROID) && RTC_DCHECK_IS_ON >+} >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.cc >new file mode 100644 >index 00000000000..4440f89d03c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.cc >@@ -0,0 +1,27 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/data_size.h" >+ >+#include "rtc_base/strings/string_builder.h" >+ >+namespace webrtc { >+ >+std::string ToString(const DataSize& value) { >+ char buf[64]; >+ rtc::SimpleStringBuilder sb(buf); >+ if (value.IsInfinite()) { >+ sb << "inf bytes"; >+ } else { >+ sb << value.bytes() << " bytes"; >+ } >+ return sb.str(); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.h >new file mode 100644 >index 00000000000..00ab2eccf73 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size.h >@@ -0,0 +1,154 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_UNITS_DATA_SIZE_H_ >+#define API_UNITS_DATA_SIZE_H_ >+ >+#include <stdint.h> >+#include <cmath> >+#include <limits> >+#include <string> >+#include <type_traits> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/numerics/safe_conversions.h" >+ >+namespace webrtc { >+namespace data_size_impl { >+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max(); >+} // namespace data_size_impl >+ >+// DataSize is a class represeting a count of bytes. >+class DataSize { >+ public: >+ DataSize() = delete; >+ static constexpr DataSize Zero() { return DataSize(0); } >+ static constexpr DataSize Infinity() { >+ return DataSize(data_size_impl::kPlusInfinityVal); >+ } >+ template <int64_t bytes> >+ static constexpr DataSize Bytes() { >+ static_assert(bytes >= 0, ""); >+ static_assert(bytes < data_size_impl::kPlusInfinityVal, ""); >+ return DataSize(bytes); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static DataSize bytes(T bytes) { >+ RTC_DCHECK_GE(bytes, 0); >+ RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal); >+ return DataSize(rtc::dchecked_cast<int64_t>(bytes)); >+ } >+ >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static DataSize bytes(T bytes) { >+ if (bytes == std::numeric_limits<T>::infinity()) { >+ return Infinity(); >+ } else { >+ RTC_DCHECK(!std::isnan(bytes)); >+ RTC_DCHECK_GE(bytes, 0); >+ RTC_DCHECK_LT(bytes, data_size_impl::kPlusInfinityVal); >+ return DataSize(rtc::dchecked_cast<int64_t>(bytes)); >+ } >+ } >+ >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type bytes() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(bytes_); >+ } >+ >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ bytes() const { >+ return IsInfinite() ? std::numeric_limits<T>::infinity() : bytes_; >+ } >+ >+ constexpr int64_t bytes_or(int64_t fallback_value) const { >+ return IsFinite() ? bytes_ : fallback_value; >+ } >+ >+ constexpr bool IsZero() const { return bytes_ == 0; } >+ constexpr bool IsInfinite() const { >+ return bytes_ == data_size_impl::kPlusInfinityVal; >+ } >+ constexpr bool IsFinite() const { return !IsInfinite(); } >+ DataSize operator-(const DataSize& other) const { >+ return DataSize::bytes(bytes() - other.bytes()); >+ } >+ DataSize operator+(const DataSize& other) const { >+ return DataSize::bytes(bytes() + other.bytes()); >+ } >+ DataSize& operator-=(const DataSize& other) { >+ bytes_ -= other.bytes(); >+ return *this; >+ } >+ DataSize& operator+=(const DataSize& other) { >+ bytes_ += other.bytes(); >+ return *this; >+ } >+ constexpr double operator/(const DataSize& other) const { >+ return bytes<double>() / other.bytes<double>(); >+ } >+ constexpr bool operator==(const DataSize& other) const { >+ return bytes_ == other.bytes_; >+ } >+ constexpr bool operator!=(const DataSize& other) const { >+ return bytes_ != other.bytes_; >+ } >+ constexpr bool operator<=(const DataSize& other) const { >+ return bytes_ <= other.bytes_; >+ } >+ constexpr bool operator>=(const DataSize& other) const { >+ return bytes_ >= other.bytes_; >+ } >+ constexpr bool operator>(const DataSize& other) const { >+ return bytes_ > other.bytes_; >+ } >+ constexpr bool operator<(const DataSize& other) const { >+ return bytes_ < other.bytes_; >+ } >+ >+ private: >+ explicit constexpr DataSize(int64_t bytes) : bytes_(bytes) {} >+ int64_t bytes_; >+}; >+ >+inline DataSize operator*(const DataSize& size, const double& scalar) { >+ return DataSize::bytes(std::round(size.bytes() * scalar)); >+} >+inline DataSize operator*(const double& scalar, const DataSize& size) { >+ return size * scalar; >+} >+inline DataSize operator*(const DataSize& size, const int64_t& scalar) { >+ return DataSize::bytes(size.bytes() * scalar); >+} >+inline DataSize operator*(const int64_t& scalar, const DataSize& size) { >+ return size * scalar; >+} >+inline DataSize operator*(const DataSize& size, const int32_t& scalar) { >+ return DataSize::bytes(size.bytes() * scalar); >+} >+inline DataSize operator*(const int32_t& scalar, const DataSize& size) { >+ return size * scalar; >+} >+inline DataSize operator/(const DataSize& size, const int64_t& scalar) { >+ return DataSize::bytes(size.bytes() / scalar); >+} >+ >+std::string ToString(const DataSize& value); >+ >+} // namespace webrtc >+ >+#endif // API_UNITS_DATA_SIZE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size_unittest.cc >new file mode 100644 >index 00000000000..fe7f591dc0d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/data_size_unittest.cc >@@ -0,0 +1,107 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/data_size.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace test { >+ >+TEST(DataSizeTest, ConstExpr) { >+ constexpr int64_t kValue = 12345; >+ constexpr DataSize kDataSizeZero = DataSize::Zero(); >+ constexpr DataSize kDataSizeInf = DataSize::Infinity(); >+ static_assert(kDataSizeZero.IsZero(), ""); >+ static_assert(kDataSizeInf.IsInfinite(), ""); >+ static_assert(kDataSizeInf.bytes_or(-1) == -1, ""); >+ static_assert(kDataSizeInf > kDataSizeZero, ""); >+ >+ constexpr DataSize kDataSize = DataSize::Bytes<kValue>(); >+ static_assert(kDataSize.bytes_or(-1) == kValue, ""); >+ >+ EXPECT_EQ(kDataSize.bytes(), kValue); >+} >+ >+TEST(DataSizeTest, GetBackSameValues) { >+ const int64_t kValue = 123 * 8; >+ EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue); >+} >+ >+TEST(DataSizeTest, IdentityChecks) { >+ const int64_t kValue = 3000; >+ EXPECT_TRUE(DataSize::Zero().IsZero()); >+ EXPECT_FALSE(DataSize::bytes(kValue).IsZero()); >+ >+ EXPECT_TRUE(DataSize::Infinity().IsInfinite()); >+ EXPECT_FALSE(DataSize::Zero().IsInfinite()); >+ EXPECT_FALSE(DataSize::bytes(kValue).IsInfinite()); >+ >+ EXPECT_FALSE(DataSize::Infinity().IsFinite()); >+ EXPECT_TRUE(DataSize::bytes(kValue).IsFinite()); >+ EXPECT_TRUE(DataSize::Zero().IsFinite()); >+} >+ >+TEST(DataSizeTest, ComparisonOperators) { >+ const int64_t kSmall = 450; >+ const int64_t kLarge = 451; >+ const DataSize small = DataSize::bytes(kSmall); >+ const DataSize large = DataSize::bytes(kLarge); >+ >+ EXPECT_EQ(DataSize::Zero(), DataSize::bytes(0)); >+ EXPECT_EQ(DataSize::Infinity(), DataSize::Infinity()); >+ EXPECT_EQ(small, small); >+ EXPECT_LE(small, small); >+ EXPECT_GE(small, small); >+ EXPECT_NE(small, large); >+ EXPECT_LE(small, large); >+ EXPECT_LT(small, large); >+ EXPECT_GE(large, small); >+ EXPECT_GT(large, small); >+ EXPECT_LT(DataSize::Zero(), small); >+ EXPECT_GT(DataSize::Infinity(), large); >+} >+ >+TEST(DataSizeTest, ConvertsToAndFromDouble) { >+ const int64_t kValue = 128; >+ const double kDoubleValue = static_cast<double>(kValue); >+ >+ EXPECT_EQ(DataSize::bytes(kValue).bytes<double>(), kDoubleValue); >+ EXPECT_EQ(DataSize::bytes(kDoubleValue).bytes(), kValue); >+ >+ const double kInfinity = std::numeric_limits<double>::infinity(); >+ EXPECT_EQ(DataSize::Infinity().bytes<double>(), kInfinity); >+ EXPECT_TRUE(DataSize::bytes(kInfinity).IsInfinite()); >+} >+ >+TEST(DataSizeTest, MathOperations) { >+ const int64_t kValueA = 450; >+ const int64_t kValueB = 267; >+ const DataSize size_a = DataSize::bytes(kValueA); >+ const DataSize size_b = DataSize::bytes(kValueB); >+ EXPECT_EQ((size_a + size_b).bytes(), kValueA + kValueB); >+ EXPECT_EQ((size_a - size_b).bytes(), kValueA - kValueB); >+ >+ const int32_t kInt32Value = 123; >+ const double kFloatValue = 123.0; >+ EXPECT_EQ((size_a * kValueB).bytes(), kValueA * kValueB); >+ EXPECT_EQ((size_a * kInt32Value).bytes(), kValueA * kInt32Value); >+ EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue); >+ >+ EXPECT_EQ((size_a / 10).bytes(), kValueA / 10); >+ EXPECT_EQ(size_a / size_b, static_cast<double>(kValueA) / kValueB); >+ >+ DataSize mutable_size = DataSize::bytes(kValueA); >+ mutable_size += size_b; >+ EXPECT_EQ(mutable_size.bytes(), kValueA + kValueB); >+ mutable_size -= size_a; >+ EXPECT_EQ(mutable_size.bytes(), kValueB); >+} >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.cc >new file mode 100644 >index 00000000000..398df776598 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.cc >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/time_delta.h" >+ >+#include "rtc_base/strings/string_builder.h" >+ >+namespace webrtc { >+ >+std::string ToString(const TimeDelta& value) { >+ char buf[64]; >+ rtc::SimpleStringBuilder sb(buf); >+ if (value.IsPlusInfinity()) { >+ sb << "+inf ms"; >+ } else if (value.IsMinusInfinity()) { >+ sb << "-inf ms"; >+ } else { >+ sb << value.ms() << " ms"; >+ } >+ return sb.str(); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.h >new file mode 100644 >index 00000000000..1155eb526be >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta.h >@@ -0,0 +1,258 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_UNITS_TIME_DELTA_H_ >+#define API_UNITS_TIME_DELTA_H_ >+ >+#include <stdint.h> >+#include <cmath> >+#include <limits> >+#include <string> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/numerics/safe_conversions.h" >+ >+namespace webrtc { >+namespace timedelta_impl { >+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max(); >+constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min(); >+} // namespace timedelta_impl >+ >+// TimeDelta represents the difference between two timestamps. Commonly this can >+// be a duration. However since two Timestamps are not guaranteed to have the >+// same epoch (they might come from different computers, making exact >+// synchronisation infeasible), the duration covered by a TimeDelta can be >+// undefined. To simplify usage, it can be constructed and converted to >+// different units, specifically seconds (s), milliseconds (ms) and >+// microseconds (us). >+class TimeDelta { >+ public: >+ TimeDelta() = delete; >+ static constexpr TimeDelta Zero() { return TimeDelta(0); } >+ static constexpr TimeDelta PlusInfinity() { >+ return TimeDelta(timedelta_impl::kPlusInfinityVal); >+ } >+ static constexpr TimeDelta MinusInfinity() { >+ return TimeDelta(timedelta_impl::kMinusInfinityVal); >+ } >+ template <int64_t seconds> >+ static constexpr TimeDelta Seconds() { >+ static_assert(seconds > timedelta_impl::kMinusInfinityVal / 1000000, ""); >+ static_assert(seconds < timedelta_impl::kPlusInfinityVal / 1000000, ""); >+ return TimeDelta(seconds * 1000000); >+ } >+ template <int64_t ms> >+ static constexpr TimeDelta Millis() { >+ static_assert(ms > timedelta_impl::kMinusInfinityVal / 1000, ""); >+ static_assert(ms < timedelta_impl::kPlusInfinityVal / 1000, ""); >+ return TimeDelta(ms * 1000); >+ } >+ template <int64_t us> >+ static constexpr TimeDelta Micros() { >+ static_assert(us > timedelta_impl::kMinusInfinityVal, ""); >+ static_assert(us < timedelta_impl::kPlusInfinityVal, ""); >+ return TimeDelta(us); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static TimeDelta seconds(T seconds) { >+ RTC_DCHECK_GT(seconds, timedelta_impl::kMinusInfinityVal / 1000000); >+ RTC_DCHECK_LT(seconds, timedelta_impl::kPlusInfinityVal / 1000000); >+ return TimeDelta(rtc::dchecked_cast<int64_t>(seconds) * 1000000); >+ } >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static TimeDelta ms(T milliseconds) { >+ RTC_DCHECK_GT(milliseconds, timedelta_impl::kMinusInfinityVal / 1000); >+ RTC_DCHECK_LT(milliseconds, timedelta_impl::kPlusInfinityVal / 1000); >+ return TimeDelta(rtc::dchecked_cast<int64_t>(milliseconds) * 1000); >+ } >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static TimeDelta us(T microseconds) { >+ RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal); >+ RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal); >+ return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds)); >+ } >+ >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static TimeDelta seconds(T seconds) { >+ return TimeDelta::us(seconds * 1e6); >+ } >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static TimeDelta ms(T milliseconds) { >+ return TimeDelta::us(milliseconds * 1e3); >+ } >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static TimeDelta us(T microseconds) { >+ if (microseconds == std::numeric_limits<T>::infinity()) { >+ return PlusInfinity(); >+ } else if (microseconds == -std::numeric_limits<T>::infinity()) { >+ return MinusInfinity(); >+ } else { >+ RTC_DCHECK(!std::isnan(microseconds)); >+ RTC_DCHECK_GT(microseconds, timedelta_impl::kMinusInfinityVal); >+ RTC_DCHECK_LT(microseconds, timedelta_impl::kPlusInfinityVal); >+ return TimeDelta(rtc::dchecked_cast<int64_t>(microseconds)); >+ } >+ } >+ >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(UnsafeSeconds()); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type ms() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(UnsafeMillis()); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type us() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(microseconds_); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type ns() const { >+ RTC_DCHECK_GE(us(), std::numeric_limits<T>::min() / 1000); >+ RTC_DCHECK_LE(us(), std::numeric_limits<T>::max() / 1000); >+ return rtc::dchecked_cast<T>(us() * 1000); >+ } >+ >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ seconds() const { >+ return us<T>() * 1e-6; >+ } >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ ms() const { >+ return us<T>() * 1e-3; >+ } >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ us() const { >+ return IsPlusInfinity() >+ ? std::numeric_limits<T>::infinity() >+ : IsMinusInfinity() ? -std::numeric_limits<T>::infinity() >+ : microseconds_; >+ } >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ ns() const { >+ return us<T>() * 1e3; >+ } >+ >+ constexpr int64_t seconds_or(int64_t fallback_value) const { >+ return IsFinite() ? UnsafeSeconds() : fallback_value; >+ } >+ constexpr int64_t ms_or(int64_t fallback_value) const { >+ return IsFinite() ? UnsafeMillis() : fallback_value; >+ } >+ constexpr int64_t us_or(int64_t fallback_value) const { >+ return IsFinite() ? microseconds_ : fallback_value; >+ } >+ >+ TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); } >+ constexpr bool IsZero() const { return microseconds_ == 0; } >+ constexpr bool IsFinite() const { return !IsInfinite(); } >+ constexpr bool IsInfinite() const { >+ return microseconds_ == timedelta_impl::kPlusInfinityVal || >+ microseconds_ == timedelta_impl::kMinusInfinityVal; >+ } >+ constexpr bool IsPlusInfinity() const { >+ return microseconds_ == timedelta_impl::kPlusInfinityVal; >+ } >+ constexpr bool IsMinusInfinity() const { >+ return microseconds_ == timedelta_impl::kMinusInfinityVal; >+ } >+ TimeDelta operator+(const TimeDelta& other) const { >+ return TimeDelta::us(us() + other.us()); >+ } >+ TimeDelta operator-(const TimeDelta& other) const { >+ return TimeDelta::us(us() - other.us()); >+ } >+ TimeDelta& operator-=(const TimeDelta& other) { >+ microseconds_ -= other.us(); >+ return *this; >+ } >+ TimeDelta& operator+=(const TimeDelta& other) { >+ microseconds_ += other.us(); >+ return *this; >+ } >+ constexpr double operator/(const TimeDelta& other) const { >+ return us<double>() / other.us<double>(); >+ } >+ constexpr bool operator==(const TimeDelta& other) const { >+ return microseconds_ == other.microseconds_; >+ } >+ constexpr bool operator!=(const TimeDelta& other) const { >+ return microseconds_ != other.microseconds_; >+ } >+ constexpr bool operator<=(const TimeDelta& other) const { >+ return microseconds_ <= other.microseconds_; >+ } >+ constexpr bool operator>=(const TimeDelta& other) const { >+ return microseconds_ >= other.microseconds_; >+ } >+ constexpr bool operator>(const TimeDelta& other) const { >+ return microseconds_ > other.microseconds_; >+ } >+ constexpr bool operator<(const TimeDelta& other) const { >+ return microseconds_ < other.microseconds_; >+ } >+ >+ private: >+ explicit constexpr TimeDelta(int64_t us) : microseconds_(us) {} >+ constexpr int64_t UnsafeSeconds() const { >+ return (microseconds_ + (microseconds_ >= 0 ? 500000 : -500000)) / 1000000; >+ } >+ constexpr int64_t UnsafeMillis() const { >+ return (microseconds_ + (microseconds_ >= 0 ? 500 : -500)) / 1000; >+ } >+ int64_t microseconds_; >+}; >+ >+inline TimeDelta operator*(const TimeDelta& delta, const double& scalar) { >+ return TimeDelta::us(std::round(delta.us() * scalar)); >+} >+inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) { >+ return delta * scalar; >+} >+inline TimeDelta operator*(const TimeDelta& delta, const int64_t& scalar) { >+ return TimeDelta::us(delta.us() * scalar); >+} >+inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) { >+ return delta * scalar; >+} >+inline TimeDelta operator*(const TimeDelta& delta, const int32_t& scalar) { >+ return TimeDelta::us(delta.us() * scalar); >+} >+inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) { >+ return delta * scalar; >+} >+ >+inline TimeDelta operator/(const TimeDelta& delta, const int64_t& scalar) { >+ return TimeDelta::us(delta.us() / scalar); >+} >+std::string ToString(const TimeDelta& value); >+} // namespace webrtc >+ >+#endif // API_UNITS_TIME_DELTA_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta_unittest.cc >new file mode 100644 >index 00000000000..9eddee73adf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/time_delta_unittest.cc >@@ -0,0 +1,169 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/time_delta.h" >+ >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace test { >+TEST(TimeDeltaTest, ConstExpr) { >+ constexpr int64_t kValue = -12345; >+ constexpr TimeDelta kTimeDeltaZero = TimeDelta::Zero(); >+ constexpr TimeDelta kTimeDeltaPlusInf = TimeDelta::PlusInfinity(); >+ constexpr TimeDelta kTimeDeltaMinusInf = TimeDelta::MinusInfinity(); >+ static_assert(kTimeDeltaZero.IsZero(), ""); >+ static_assert(kTimeDeltaPlusInf.IsPlusInfinity(), ""); >+ static_assert(kTimeDeltaMinusInf.IsMinusInfinity(), ""); >+ static_assert(kTimeDeltaPlusInf.ms_or(-1) == -1, ""); >+ >+ static_assert(kTimeDeltaPlusInf > kTimeDeltaZero, ""); >+ >+ constexpr TimeDelta kTimeDeltaSeconds = TimeDelta::Seconds<kValue>(); >+ constexpr TimeDelta kTimeDeltaMs = TimeDelta::Millis<kValue>(); >+ constexpr TimeDelta kTimeDeltaUs = TimeDelta::Micros<kValue>(); >+ >+ static_assert(kTimeDeltaSeconds.seconds_or(0) == kValue, ""); >+ static_assert(kTimeDeltaMs.ms_or(0) == kValue, ""); >+ static_assert(kTimeDeltaUs.us_or(0) == kValue, ""); >+} >+ >+TEST(TimeDeltaTest, GetBackSameValues) { >+ const int64_t kValue = 499; >+ for (int sign = -1; sign <= 1; ++sign) { >+ int64_t value = kValue * sign; >+ EXPECT_EQ(TimeDelta::ms(value).ms(), value); >+ EXPECT_EQ(TimeDelta::us(value).us(), value); >+ EXPECT_EQ(TimeDelta::seconds(value).seconds(), value); >+ EXPECT_EQ(TimeDelta::seconds(value).seconds(), value); >+ } >+ EXPECT_EQ(TimeDelta::Zero().us(), 0); >+} >+ >+TEST(TimeDeltaTest, GetDifferentPrefix) { >+ const int64_t kValue = 3000000; >+ EXPECT_EQ(TimeDelta::us(kValue).seconds(), kValue / 1000000); >+ EXPECT_EQ(TimeDelta::ms(kValue).seconds(), kValue / 1000); >+ EXPECT_EQ(TimeDelta::us(kValue).ms(), kValue / 1000); >+ >+ EXPECT_EQ(TimeDelta::ms(kValue).us(), kValue * 1000); >+ EXPECT_EQ(TimeDelta::seconds(kValue).ms(), kValue * 1000); >+ EXPECT_EQ(TimeDelta::seconds(kValue).us(), kValue * 1000000); >+} >+ >+TEST(TimeDeltaTest, IdentityChecks) { >+ const int64_t kValue = 3000; >+ EXPECT_TRUE(TimeDelta::Zero().IsZero()); >+ EXPECT_FALSE(TimeDelta::ms(kValue).IsZero()); >+ >+ EXPECT_TRUE(TimeDelta::PlusInfinity().IsInfinite()); >+ EXPECT_TRUE(TimeDelta::MinusInfinity().IsInfinite()); >+ EXPECT_FALSE(TimeDelta::Zero().IsInfinite()); >+ EXPECT_FALSE(TimeDelta::ms(-kValue).IsInfinite()); >+ EXPECT_FALSE(TimeDelta::ms(kValue).IsInfinite()); >+ >+ EXPECT_FALSE(TimeDelta::PlusInfinity().IsFinite()); >+ EXPECT_FALSE(TimeDelta::MinusInfinity().IsFinite()); >+ EXPECT_TRUE(TimeDelta::ms(-kValue).IsFinite()); >+ EXPECT_TRUE(TimeDelta::ms(kValue).IsFinite()); >+ EXPECT_TRUE(TimeDelta::Zero().IsFinite()); >+} >+ >+TEST(TimeDeltaTest, ComparisonOperators) { >+ const int64_t kSmall = 450; >+ const int64_t kLarge = 451; >+ const TimeDelta small = TimeDelta::ms(kSmall); >+ const TimeDelta large = TimeDelta::ms(kLarge); >+ >+ EXPECT_EQ(TimeDelta::Zero(), TimeDelta::ms(0)); >+ EXPECT_EQ(TimeDelta::PlusInfinity(), TimeDelta::PlusInfinity()); >+ EXPECT_EQ(small, TimeDelta::ms(kSmall)); >+ EXPECT_LE(small, TimeDelta::ms(kSmall)); >+ EXPECT_GE(small, TimeDelta::ms(kSmall)); >+ EXPECT_NE(small, TimeDelta::ms(kLarge)); >+ EXPECT_LE(small, TimeDelta::ms(kLarge)); >+ EXPECT_LT(small, TimeDelta::ms(kLarge)); >+ EXPECT_GE(large, TimeDelta::ms(kSmall)); >+ EXPECT_GT(large, TimeDelta::ms(kSmall)); >+ EXPECT_LT(TimeDelta::Zero(), small); >+ EXPECT_GT(TimeDelta::Zero(), TimeDelta::ms(-kSmall)); >+ EXPECT_GT(TimeDelta::Zero(), TimeDelta::ms(-kSmall)); >+ >+ EXPECT_GT(TimeDelta::PlusInfinity(), large); >+ EXPECT_LT(TimeDelta::MinusInfinity(), TimeDelta::Zero()); >+} >+ >+TEST(TimeDeltaTest, CanBeInititializedFromLargeInt) { >+ const int kMaxInt = std::numeric_limits<int>::max(); >+ EXPECT_EQ(TimeDelta::seconds(kMaxInt).us(), >+ static_cast<int64_t>(kMaxInt) * 1000000); >+ EXPECT_EQ(TimeDelta::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000); >+} >+ >+TEST(TimeDeltaTest, ConvertsToAndFromDouble) { >+ const int64_t kMicros = 17017; >+ const double kNanosDouble = kMicros * 1e3; >+ const double kMicrosDouble = kMicros; >+ const double kMillisDouble = kMicros * 1e-3; >+ const double kSecondsDouble = kMillisDouble * 1e-3; >+ >+ EXPECT_EQ(TimeDelta::us(kMicros).seconds<double>(), kSecondsDouble); >+ EXPECT_EQ(TimeDelta::seconds(kSecondsDouble).us(), kMicros); >+ >+ EXPECT_EQ(TimeDelta::us(kMicros).ms<double>(), kMillisDouble); >+ EXPECT_EQ(TimeDelta::ms(kMillisDouble).us(), kMicros); >+ >+ EXPECT_EQ(TimeDelta::us(kMicros).us<double>(), kMicrosDouble); >+ EXPECT_EQ(TimeDelta::us(kMicrosDouble).us(), kMicros); >+ >+ EXPECT_NEAR(TimeDelta::us(kMicros).ns<double>(), kNanosDouble, 1); >+ >+ const double kPlusInfinity = std::numeric_limits<double>::infinity(); >+ const double kMinusInfinity = -kPlusInfinity; >+ >+ EXPECT_EQ(TimeDelta::PlusInfinity().seconds<double>(), kPlusInfinity); >+ EXPECT_EQ(TimeDelta::MinusInfinity().seconds<double>(), kMinusInfinity); >+ EXPECT_EQ(TimeDelta::PlusInfinity().ms<double>(), kPlusInfinity); >+ EXPECT_EQ(TimeDelta::MinusInfinity().ms<double>(), kMinusInfinity); >+ EXPECT_EQ(TimeDelta::PlusInfinity().us<double>(), kPlusInfinity); >+ EXPECT_EQ(TimeDelta::MinusInfinity().us<double>(), kMinusInfinity); >+ EXPECT_EQ(TimeDelta::PlusInfinity().ns<double>(), kPlusInfinity); >+ EXPECT_EQ(TimeDelta::MinusInfinity().ns<double>(), kMinusInfinity); >+ >+ EXPECT_TRUE(TimeDelta::seconds(kPlusInfinity).IsPlusInfinity()); >+ EXPECT_TRUE(TimeDelta::seconds(kMinusInfinity).IsMinusInfinity()); >+ EXPECT_TRUE(TimeDelta::ms(kPlusInfinity).IsPlusInfinity()); >+ EXPECT_TRUE(TimeDelta::ms(kMinusInfinity).IsMinusInfinity()); >+ EXPECT_TRUE(TimeDelta::us(kPlusInfinity).IsPlusInfinity()); >+ EXPECT_TRUE(TimeDelta::us(kMinusInfinity).IsMinusInfinity()); >+} >+ >+TEST(TimeDeltaTest, MathOperations) { >+ const int64_t kValueA = 267; >+ const int64_t kValueB = 450; >+ const TimeDelta delta_a = TimeDelta::ms(kValueA); >+ const TimeDelta delta_b = TimeDelta::ms(kValueB); >+ EXPECT_EQ((delta_a + delta_b).ms(), kValueA + kValueB); >+ EXPECT_EQ((delta_a - delta_b).ms(), kValueA - kValueB); >+ >+ const int32_t kInt32Value = 123; >+ const double kFloatValue = 123.0; >+ EXPECT_EQ((TimeDelta::us(kValueA) * kValueB).us(), kValueA * kValueB); >+ EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value); >+ EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue); >+ >+ EXPECT_EQ((delta_b / 10).ms(), kValueB / 10); >+ EXPECT_EQ(delta_b / delta_a, static_cast<double>(kValueB) / kValueA); >+ >+ EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA); >+ EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA); >+} >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.cc >new file mode 100644 >index 00000000000..4b2c44b9a73 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.cc >@@ -0,0 +1,26 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/timestamp.h" >+ >+#include "rtc_base/strings/string_builder.h" >+ >+namespace webrtc { >+std::string ToString(const Timestamp& value) { >+ char buf[64]; >+ rtc::SimpleStringBuilder sb(buf); >+ if (value.IsInfinite()) { >+ sb << "inf ms"; >+ } else { >+ sb << value.ms() << " ms"; >+ } >+ return sb.str(); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.h >new file mode 100644 >index 00000000000..1b5e84ff601 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp.h >@@ -0,0 +1,208 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_UNITS_TIMESTAMP_H_ >+#define API_UNITS_TIMESTAMP_H_ >+ >+#include <stdint.h> >+#include <limits> >+#include <string> >+ >+#include "api/units/time_delta.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/numerics/safe_conversions.h" >+ >+namespace webrtc { >+namespace timestamp_impl { >+constexpr int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max(); >+constexpr int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min(); >+} // namespace timestamp_impl >+ >+// Timestamp represents the time that has passed since some unspecified epoch. >+// The epoch is assumed to be before any represented timestamps, this means that >+// negative values are not valid. The most notable feature is that the >+// difference of two Timestamps results in a TimeDelta. >+class Timestamp { >+ public: >+ Timestamp() = delete; >+ static constexpr Timestamp Infinity() { >+ return Timestamp(timestamp_impl::kPlusInfinityVal); >+ } >+ template <int64_t seconds> >+ static constexpr Timestamp Seconds() { >+ static_assert(seconds >= 0, ""); >+ static_assert(seconds < timestamp_impl::kPlusInfinityVal / 1000000, ""); >+ return Timestamp(seconds * 1000000); >+ } >+ template <int64_t ms> >+ static constexpr Timestamp Millis() { >+ static_assert(ms >= 0, ""); >+ static_assert(ms < timestamp_impl::kPlusInfinityVal / 1000, ""); >+ return Timestamp(ms * 1000); >+ } >+ template <int64_t us> >+ static constexpr Timestamp Micros() { >+ static_assert(us >= 0, ""); >+ static_assert(us < timestamp_impl::kPlusInfinityVal, ""); >+ return Timestamp(us); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static Timestamp seconds(T seconds) { >+ RTC_DCHECK_GE(seconds, 0); >+ RTC_DCHECK_LT(seconds, timestamp_impl::kPlusInfinityVal / 1000000); >+ return Timestamp(rtc::dchecked_cast<int64_t>(seconds) * 1000000); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static Timestamp ms(T milliseconds) { >+ RTC_DCHECK_GE(milliseconds, 0); >+ RTC_DCHECK_LT(milliseconds, timestamp_impl::kPlusInfinityVal / 1000); >+ return Timestamp(rtc::dchecked_cast<int64_t>(milliseconds) * 1000); >+ } >+ >+ template < >+ typename T, >+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr> >+ static Timestamp us(T microseconds) { >+ RTC_DCHECK_GE(microseconds, 0); >+ RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal); >+ return Timestamp(rtc::dchecked_cast<int64_t>(microseconds)); >+ } >+ >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static Timestamp seconds(T seconds) { >+ return Timestamp::us(seconds * 1e6); >+ } >+ >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static Timestamp ms(T milliseconds) { >+ return Timestamp::us(milliseconds * 1e3); >+ } >+ template <typename T, >+ typename std::enable_if<std::is_floating_point<T>::value>::type* = >+ nullptr> >+ static Timestamp us(T microseconds) { >+ if (microseconds == std::numeric_limits<double>::infinity()) { >+ return Infinity(); >+ } else { >+ RTC_DCHECK(!std::isnan(microseconds)); >+ RTC_DCHECK_GE(microseconds, 0); >+ RTC_DCHECK_LT(microseconds, timestamp_impl::kPlusInfinityVal); >+ return Timestamp(rtc::dchecked_cast<int64_t>(microseconds)); >+ } >+ } >+ >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type seconds() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(UnsafeSeconds()); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type ms() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(UnsafeMillis()); >+ } >+ template <typename T = int64_t> >+ typename std::enable_if<std::is_integral<T>::value, T>::type us() const { >+ RTC_DCHECK(IsFinite()); >+ return rtc::dchecked_cast<T>(microseconds_); >+ } >+ >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ seconds() const { >+ return us<T>() * 1e-6; >+ } >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ ms() const { >+ return us<T>() * 1e-3; >+ } >+ template <typename T> >+ constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type >+ us() const { >+ return IsInfinite() ? std::numeric_limits<T>::infinity() : microseconds_; >+ } >+ >+ constexpr int64_t seconds_or(int64_t fallback_value) const { >+ return IsFinite() ? UnsafeSeconds() : fallback_value; >+ } >+ constexpr int64_t ms_or(int64_t fallback_value) const { >+ return IsFinite() ? UnsafeMillis() : fallback_value; >+ } >+ constexpr int64_t us_or(int64_t fallback_value) const { >+ return IsFinite() ? microseconds_ : fallback_value; >+ } >+ >+ constexpr bool IsInfinite() const { >+ return microseconds_ == timestamp_impl::kPlusInfinityVal; >+ } >+ constexpr bool IsFinite() const { return !IsInfinite(); } >+ TimeDelta operator-(const Timestamp& other) const { >+ return TimeDelta::us(us() - other.us()); >+ } >+ Timestamp operator-(const TimeDelta& delta) const { >+ return Timestamp::us(us() - delta.us()); >+ } >+ Timestamp operator+(const TimeDelta& delta) const { >+ return Timestamp::us(us() + delta.us()); >+ } >+ Timestamp& operator-=(const TimeDelta& other) { >+ microseconds_ -= other.us(); >+ return *this; >+ } >+ Timestamp& operator+=(const TimeDelta& other) { >+ microseconds_ += other.us(); >+ return *this; >+ } >+ constexpr bool operator==(const Timestamp& other) const { >+ return microseconds_ == other.microseconds_; >+ } >+ constexpr bool operator!=(const Timestamp& other) const { >+ return microseconds_ != other.microseconds_; >+ } >+ constexpr bool operator<=(const Timestamp& other) const { >+ return microseconds_ <= other.microseconds_; >+ } >+ constexpr bool operator>=(const Timestamp& other) const { >+ return microseconds_ >= other.microseconds_; >+ } >+ constexpr bool operator>(const Timestamp& other) const { >+ return microseconds_ > other.microseconds_; >+ } >+ constexpr bool operator<(const Timestamp& other) const { >+ return microseconds_ < other.microseconds_; >+ } >+ >+ private: >+ explicit constexpr Timestamp(int64_t us) : microseconds_(us) {} >+ constexpr int64_t UnsafeSeconds() const { >+ return (microseconds_ + 500000) / 1000000; >+ } >+ constexpr int64_t UnsafeMillis() const { >+ return (microseconds_ + 500) / 1000; >+ } >+ int64_t microseconds_; >+}; >+ >+std::string ToString(const Timestamp& value); >+ >+} // namespace webrtc >+ >+#endif // API_UNITS_TIMESTAMP_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp_unittest.cc >new file mode 100644 >index 00000000000..db894cca447 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/units/timestamp_unittest.cc >@@ -0,0 +1,127 @@ >+/* >+ * Copyright (c) 2018 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 "api/units/timestamp.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace test { >+TEST(TimestampTest, ConstExpr) { >+ constexpr int64_t kValue = 12345; >+ constexpr Timestamp kTimestampInf = Timestamp::Infinity(); >+ static_assert(kTimestampInf.IsInfinite(), ""); >+ static_assert(kTimestampInf.ms_or(-1) == -1, ""); >+ >+ constexpr Timestamp kTimestampSeconds = Timestamp::Seconds<kValue>(); >+ constexpr Timestamp kTimestampMs = Timestamp::Millis<kValue>(); >+ constexpr Timestamp kTimestampUs = Timestamp::Micros<kValue>(); >+ >+ static_assert(kTimestampSeconds.seconds_or(0) == kValue, ""); >+ static_assert(kTimestampMs.ms_or(0) == kValue, ""); >+ static_assert(kTimestampUs.us_or(0) == kValue, ""); >+ >+ static_assert(kTimestampMs > kTimestampUs, ""); >+ >+ EXPECT_EQ(kTimestampSeconds.seconds(), kValue); >+ EXPECT_EQ(kTimestampMs.ms(), kValue); >+ EXPECT_EQ(kTimestampUs.us(), kValue); >+} >+ >+TEST(TimestampTest, GetBackSameValues) { >+ const int64_t kValue = 499; >+ EXPECT_EQ(Timestamp::ms(kValue).ms(), kValue); >+ EXPECT_EQ(Timestamp::us(kValue).us(), kValue); >+ EXPECT_EQ(Timestamp::seconds(kValue).seconds(), kValue); >+} >+ >+TEST(TimestampTest, GetDifferentPrefix) { >+ const int64_t kValue = 3000000; >+ EXPECT_EQ(Timestamp::us(kValue).seconds(), kValue / 1000000); >+ EXPECT_EQ(Timestamp::ms(kValue).seconds(), kValue / 1000); >+ EXPECT_EQ(Timestamp::us(kValue).ms(), kValue / 1000); >+ >+ EXPECT_EQ(Timestamp::ms(kValue).us(), kValue * 1000); >+ EXPECT_EQ(Timestamp::seconds(kValue).ms(), kValue * 1000); >+ EXPECT_EQ(Timestamp::seconds(kValue).us(), kValue * 1000000); >+} >+ >+TEST(TimestampTest, IdentityChecks) { >+ const int64_t kValue = 3000; >+ >+ EXPECT_TRUE(Timestamp::Infinity().IsInfinite()); >+ EXPECT_FALSE(Timestamp::ms(kValue).IsInfinite()); >+ >+ EXPECT_FALSE(Timestamp::Infinity().IsFinite()); >+ EXPECT_TRUE(Timestamp::ms(kValue).IsFinite()); >+} >+ >+TEST(TimestampTest, ComparisonOperators) { >+ const int64_t kSmall = 450; >+ const int64_t kLarge = 451; >+ >+ EXPECT_EQ(Timestamp::Infinity(), Timestamp::Infinity()); >+ EXPECT_GE(Timestamp::Infinity(), Timestamp::Infinity()); >+ EXPECT_GT(Timestamp::Infinity(), Timestamp::ms(kLarge)); >+ EXPECT_EQ(Timestamp::ms(kSmall), Timestamp::ms(kSmall)); >+ EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kSmall)); >+ EXPECT_GE(Timestamp::ms(kSmall), Timestamp::ms(kSmall)); >+ EXPECT_NE(Timestamp::ms(kSmall), Timestamp::ms(kLarge)); >+ EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kLarge)); >+ EXPECT_LT(Timestamp::ms(kSmall), Timestamp::ms(kLarge)); >+ EXPECT_GE(Timestamp::ms(kLarge), Timestamp::ms(kSmall)); >+ EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall)); >+} >+ >+TEST(TimestampTest, CanBeInititializedFromLargeInt) { >+ const int kMaxInt = std::numeric_limits<int>::max(); >+ EXPECT_EQ(Timestamp::seconds(kMaxInt).us(), >+ static_cast<int64_t>(kMaxInt) * 1000000); >+ EXPECT_EQ(Timestamp::ms(kMaxInt).us(), static_cast<int64_t>(kMaxInt) * 1000); >+} >+ >+TEST(TimestampTest, ConvertsToAndFromDouble) { >+ const int64_t kMicros = 17017; >+ const double kMicrosDouble = kMicros; >+ const double kMillisDouble = kMicros * 1e-3; >+ const double kSecondsDouble = kMillisDouble * 1e-3; >+ >+ EXPECT_EQ(Timestamp::us(kMicros).seconds<double>(), kSecondsDouble); >+ EXPECT_EQ(Timestamp::seconds(kSecondsDouble).us(), kMicros); >+ >+ EXPECT_EQ(Timestamp::us(kMicros).ms<double>(), kMillisDouble); >+ EXPECT_EQ(Timestamp::ms(kMillisDouble).us(), kMicros); >+ >+ EXPECT_EQ(Timestamp::us(kMicros).us<double>(), kMicrosDouble); >+ EXPECT_EQ(Timestamp::us(kMicrosDouble).us(), kMicros); >+ >+ const double kPlusInfinity = std::numeric_limits<double>::infinity(); >+ >+ EXPECT_EQ(Timestamp::Infinity().seconds<double>(), kPlusInfinity); >+ EXPECT_EQ(Timestamp::Infinity().ms<double>(), kPlusInfinity); >+ EXPECT_EQ(Timestamp::Infinity().us<double>(), kPlusInfinity); >+ >+ EXPECT_TRUE(Timestamp::seconds(kPlusInfinity).IsInfinite()); >+ EXPECT_TRUE(Timestamp::ms(kPlusInfinity).IsInfinite()); >+ EXPECT_TRUE(Timestamp::us(kPlusInfinity).IsInfinite()); >+} >+ >+TEST(UnitConversionTest, TimestampAndTimeDeltaMath) { >+ const int64_t kValueA = 267; >+ const int64_t kValueB = 450; >+ const Timestamp time_a = Timestamp::ms(kValueA); >+ const Timestamp time_b = Timestamp::ms(kValueB); >+ const TimeDelta delta_a = TimeDelta::ms(kValueA); >+ >+ EXPECT_EQ((time_a - time_b), TimeDelta::ms(kValueA - kValueB)); >+ EXPECT_EQ((time_b - delta_a), Timestamp::ms(kValueB - kValueA)); >+ EXPECT_EQ((time_b + delta_a), Timestamp::ms(kValueB + kValueA)); >+} >+} // namespace test >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/BUILD.gn >new file mode 100644 >index 00000000000..d5480dd250e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/BUILD.gn >@@ -0,0 +1,182 @@ >+# Copyright (c) 2018 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. >+ >+import("../../webrtc.gni") >+ >+rtc_source_set("video_frame") { >+ visibility = [ "*" ] >+ sources = [ >+ "color_space.cc", >+ "color_space.h", >+ "video_content_type.cc", >+ "video_content_type.h", >+ "video_frame.cc", >+ "video_frame.h", >+ "video_frame_buffer.cc", >+ "video_frame_buffer.h", >+ "video_rotation.h", >+ "video_sink_interface.h", >+ "video_source_interface.cc", >+ "video_source_interface.h", >+ "video_timing.cc", >+ "video_timing.h", >+ ] >+ >+ deps = [ >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("video_frame_i420") { >+ visibility = [ "*" ] >+ sources = [ >+ "i420_buffer.cc", >+ "i420_buffer.h", >+ ] >+ deps = [ >+ ":video_frame", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base", >+ "../../rtc_base/memory:aligned_malloc", >+ "//third_party/libyuv", >+ ] >+} >+ >+rtc_source_set("video_frame_i010") { >+ visibility = [ "*" ] >+ sources = [ >+ "i010_buffer.cc", >+ "i010_buffer.h", >+ ] >+ deps = [ >+ ":video_frame", >+ ":video_frame_i420", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base", >+ "../../rtc_base/memory:aligned_malloc", >+ "//third_party/libyuv", >+ ] >+} >+ >+rtc_source_set("encoded_frame") { >+ visibility = [ "*" ] >+ sources = [ >+ "encoded_frame.cc", >+ "encoded_frame.h", >+ ] >+ >+ deps = [ >+ "../../modules/video_coding:encoded_frame", >+ ] >+} >+ >+rtc_source_set("video_bitrate_allocation") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_bitrate_allocation.cc", >+ "video_bitrate_allocation.h", >+ ] >+ deps = [ >+ "../../rtc_base:checks", >+ "../../rtc_base:safe_conversions", >+ "../../rtc_base:stringutils", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("video_bitrate_allocator") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_bitrate_allocator.h", >+ ] >+ deps = [ >+ ":video_bitrate_allocation", >+ ] >+} >+ >+rtc_source_set("video_bitrate_allocator_factory") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_bitrate_allocator_factory.h", >+ ] >+ deps = [ >+ ":video_bitrate_allocator", >+ "../../media:rtc_media_base", >+ ] >+} >+ >+rtc_source_set("video_stream_decoder") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_stream_decoder.h", >+ ] >+ >+ deps = [ >+ ":encoded_frame", >+ ":video_frame", >+ "../video_codecs:video_codecs_api", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("video_stream_decoder_create") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_stream_decoder_create.cc", >+ "video_stream_decoder_create.h", >+ ] >+ >+ deps = [ >+ ":video_stream_decoder", >+ "../../rtc_base:rtc_base_approved", >+ "../../video:video_stream_decoder_impl", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("video_stream_encoder") { >+ visibility = [ "*" ] >+ sources = [ >+ "video_stream_encoder_interface.h", >+ "video_stream_encoder_observer.h", >+ "video_stream_encoder_settings.h", >+ ] >+ >+ deps = [ >+ ":video_frame", >+ >+ # For rtpparameters.h >+ "..:libjingle_peerconnection_api", >+ "../video_codecs:video_codecs_api", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("video_stream_encoder_create") { >+ visibility = [ "*" ] >+ allow_poison = [ "software_video_codecs" ] # TODO(bugs.webrtc.org/7925): Remove. >+ sources = [ >+ "video_stream_encoder_create.cc", >+ "video_stream_encoder_create.h", >+ ] >+ >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ >+ deps = [ >+ ":video_stream_encoder", >+ "../../rtc_base:ptr_util", >+ "../../video:video_stream_encoder_impl", >+ "../video_codecs:video_codecs_api", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/DEPS >new file mode 100644 >index 00000000000..aec927baaa9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/DEPS >@@ -0,0 +1,14 @@ >+specific_include_rules = { >+ # Until the new VideoStreamDecoder is implemented the current decoding >+ # pipeline will be used, and therefore EncodedFrame needs to inherit >+ # VCMEncodedFrame. >+ "encoded_frame.h": [ >+ "+modules/video_coding/encoded_frame.h", >+ ], >+ "video_stream_decoder_create.cc": [ >+ "+video/video_stream_decoder_impl.h", >+ ], >+ "video_stream_encoder_create.cc": [ >+ "+video/video_stream_encoder.h", >+ ], >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/OWNERS >index 8327124e236..315f85e7d00 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/OWNERS >@@ -1,3 +1,4 @@ > magjed@webrtc.org >+nisse@webrtc.org > > per-file video_timing.h=ilnik@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.cc >new file mode 100644 >index 00000000000..a8be5cd8280 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.cc >@@ -0,0 +1,42 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/color_space.h" >+ >+namespace webrtc { >+ >+ColorSpace::ColorSpace() = default; >+ >+ColorSpace::ColorSpace(PrimaryID primaries, >+ TransferID transfer, >+ MatrixID matrix, >+ RangeID range) >+ : primaries_(primaries), >+ transfer_(transfer), >+ matrix_(matrix), >+ range_(range) {} >+ >+ColorSpace::PrimaryID ColorSpace::primaries() const { >+ return primaries_; >+} >+ >+ColorSpace::TransferID ColorSpace::transfer() const { >+ return transfer_; >+} >+ >+ColorSpace::MatrixID ColorSpace::matrix() const { >+ return matrix_; >+} >+ >+ColorSpace::RangeID ColorSpace::range() const { >+ return range_; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.h >new file mode 100644 >index 00000000000..8102647b6ff >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/color_space.h >@@ -0,0 +1,107 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_COLOR_SPACE_H_ >+#define API_VIDEO_COLOR_SPACE_H_ >+ >+namespace webrtc { >+ >+// Used to represent a color space for the purpose of color conversion. This >+// class only represents color information that can be transferred through the >+// bitstream of WebRTC's internal supported codecs: >+// - VP9 supports color profiles, see VP9 Bitstream & Decoding Process >+// Specification Version 0.6 Section 7.2.2 "Color config semantics" available >+// from https://www.webmproject.org. >+// TODO(emircan): Extract these values from decode and add to the existing ones. >+// - VP8 only supports BT.601, see >+// https://tools.ietf.org/html/rfc6386#section-9.2 >+// - H264 supports different color primaries, transfer characteristics, matrix >+// coefficients and range. See T-REC-H.264 E.2.1, "VUI parameters semantics", >+// available from https://www.itu.int/rec/T-REC-H.264. >+class ColorSpace { >+ public: >+ enum class PrimaryID { >+ kInvalid, >+ kBT709, >+ kBT470M, >+ kBT470BG, >+ kSMPTE170M, // Identical to BT601 >+ kSMPTE240M, >+ kFILM, >+ kBT2020, >+ kSMPTEST428, >+ kSMPTEST431, >+ kSMPTEST432, >+ kJEDECP22, >+ }; >+ >+ enum class TransferID { >+ kInvalid, >+ kBT709, >+ kGAMMA22, >+ kGAMMA28, >+ kSMPTE170M, >+ kSMPTE240M, >+ kLINEAR, >+ kLOG, >+ kLOG_SQRT, >+ kIEC61966_2_4, >+ kBT1361_ECG, >+ kIEC61966_2_1, >+ kBT2020_10, >+ kBT2020_12, >+ kSMPTEST2084, >+ kSMPTEST428, >+ kARIB_STD_B67, >+ }; >+ >+ enum class MatrixID { >+ kInvalid, >+ kRGB, >+ kBT709, >+ kFCC, >+ kBT470BG, >+ kSMPTE170M, >+ kSMPTE240M, >+ kYCOCG, >+ kBT2020_NCL, >+ kBT2020_CL, >+ kSMPTE2085, >+ }; >+ >+ enum class RangeID { >+ kInvalid, >+ // Limited Rec. 709 color range with RGB values ranging from 16 to 235. >+ kLimited, >+ // Full RGB color range with RGB valees from 0 to 255. >+ kFull, >+ }; >+ >+ ColorSpace(); >+ ColorSpace(PrimaryID primaries, >+ TransferID transfer, >+ MatrixID matrix, >+ RangeID full_range); >+ >+ PrimaryID primaries() const; >+ TransferID transfer() const; >+ MatrixID matrix() const; >+ RangeID range() const; >+ >+ private: >+ PrimaryID primaries_ = PrimaryID::kInvalid; >+ TransferID transfer_ = TransferID::kInvalid; >+ MatrixID matrix_ = MatrixID::kInvalid; >+ RangeID range_ = RangeID::kInvalid; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_COLOR_SPACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.cc >new file mode 100644 >index 00000000000..f9152b23f12 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.cc >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/encoded_frame.h" >+ >+namespace webrtc { >+namespace video_coding { >+ >+bool EncodedFrame::delayed_by_retransmission() const { >+ return 0; >+} >+ >+uint32_t EncodedFrame::Timestamp() const { >+ return timestamp; >+} >+ >+void EncodedFrame::SetTimestamp(uint32_t rtp_timestamp) { >+ timestamp = rtp_timestamp; >+} >+ >+} // namespace video_coding >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.h >new file mode 100644 >index 00000000000..1b0a26a5fc2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/encoded_frame.h >@@ -0,0 +1,93 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+ >+#ifndef API_VIDEO_ENCODED_FRAME_H_ >+#define API_VIDEO_ENCODED_FRAME_H_ >+ >+#include "modules/video_coding/encoded_frame.h" >+ >+namespace webrtc { >+namespace video_coding { >+ >+// NOTE: This class is still under development and may change without notice. >+struct VideoLayerFrameId { >+ // TODO(philipel): The default ctor is currently used internaly, but have a >+ // look if we can remove it. >+ VideoLayerFrameId() : picture_id(-1), spatial_layer(0) {} >+ VideoLayerFrameId(int64_t picture_id, uint8_t spatial_layer) >+ : picture_id(picture_id), spatial_layer(spatial_layer) {} >+ >+ bool operator==(const VideoLayerFrameId& rhs) const { >+ return picture_id == rhs.picture_id && spatial_layer == rhs.spatial_layer; >+ } >+ >+ bool operator!=(const VideoLayerFrameId& rhs) const { >+ return !(*this == rhs); >+ } >+ >+ bool operator<(const VideoLayerFrameId& rhs) const { >+ if (picture_id == rhs.picture_id) >+ return spatial_layer < rhs.spatial_layer; >+ return picture_id < rhs.picture_id; >+ } >+ >+ bool operator<=(const VideoLayerFrameId& rhs) const { return !(rhs < *this); } >+ bool operator>(const VideoLayerFrameId& rhs) const { return rhs < *this; } >+ bool operator>=(const VideoLayerFrameId& rhs) const { return rhs <= *this; } >+ >+ int64_t picture_id; >+ uint8_t spatial_layer; >+}; >+ >+// TODO(philipel): Remove webrtc::VCMEncodedFrame inheritance. >+// TODO(philipel): Move transport specific info out of EncodedFrame. >+// NOTE: This class is still under development and may change without notice. >+class EncodedFrame : public webrtc::VCMEncodedFrame { >+ public: >+ static const uint8_t kMaxFrameReferences = 5; >+ >+ EncodedFrame() = default; >+ virtual ~EncodedFrame() {} >+ >+ virtual bool GetBitstream(uint8_t* destination) const = 0; >+ >+ // The capture timestamp of this frame, using the 90 kHz RTP clock. >+ virtual uint32_t Timestamp() const; >+ virtual void SetTimestamp(uint32_t rtp_timestamp); >+ >+ // When this frame was received. >+ virtual int64_t ReceivedTime() const = 0; >+ >+ // When this frame should be rendered. >+ virtual int64_t RenderTime() const = 0; >+ >+ // This information is currently needed by the timing calculation class. >+ // TODO(philipel): Remove this function when a new timing class has >+ // been implemented. >+ virtual bool delayed_by_retransmission() const; >+ >+ size_t size() const { return _length; } >+ >+ bool is_keyframe() const { return num_references == 0; } >+ >+ VideoLayerFrameId id; >+ uint32_t timestamp = 0; >+ >+ // TODO(philipel): Add simple modify/access functions to prevent adding too >+ // many |references|. >+ size_t num_references = 0; >+ int64_t references[kMaxFrameReferences]; >+ bool inter_layer_predicted = false; >+}; >+ >+} // namespace video_coding >+} // namespace webrtc >+ >+#endif // API_VIDEO_ENCODED_FRAME_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.cc >new file mode 100644 >index 00000000000..adb5a5e95ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.cc >@@ -0,0 +1,237 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/i010_buffer.h" >+ >+#include <algorithm> >+#include <utility> >+ >+#include "api/video/i420_buffer.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/refcountedobject.h" >+#include "third_party/libyuv/include/libyuv/convert.h" >+#include "third_party/libyuv/include/libyuv/planar_functions.h" >+#include "third_party/libyuv/include/libyuv/scale.h" >+ >+// Aligning pointer to 64 bytes for improved performance, e.g. use SIMD. >+static const int kBufferAlignment = 64; >+static const int kBytesPerPixel = 2; >+ >+namespace webrtc { >+ >+namespace { >+ >+int I010DataSize(int height, int stride_y, int stride_u, int stride_v) { >+ return kBytesPerPixel * >+ (stride_y * height + (stride_u + stride_v) * ((height + 1) / 2)); >+} >+ >+} // namespace >+ >+I010Buffer::I010Buffer(int width, >+ int height, >+ int stride_y, >+ int stride_u, >+ int stride_v) >+ : width_(width), >+ height_(height), >+ stride_y_(stride_y), >+ stride_u_(stride_u), >+ stride_v_(stride_v), >+ data_(static_cast<uint16_t*>( >+ AlignedMalloc(I010DataSize(height, stride_y, stride_u, stride_v), >+ kBufferAlignment))) { >+ RTC_DCHECK_GT(width, 0); >+ RTC_DCHECK_GT(height, 0); >+ RTC_DCHECK_GE(stride_y, width); >+ RTC_DCHECK_GE(stride_u, (width + 1) / 2); >+ RTC_DCHECK_GE(stride_v, (width + 1) / 2); >+} >+ >+I010Buffer::~I010Buffer() {} >+ >+// static >+rtc::scoped_refptr<I010Buffer> I010Buffer::Create(int width, int height) { >+ return new rtc::RefCountedObject<I010Buffer>( >+ width, height, width, (width + 1) / 2, (width + 1) / 2); >+} >+ >+// static >+rtc::scoped_refptr<I010Buffer> I010Buffer::Copy( >+ const I010BufferInterface& source) { >+ const int width = source.width(); >+ const int height = source.height(); >+ rtc::scoped_refptr<I010Buffer> buffer = Create(width, height); >+ RTC_CHECK_EQ( >+ 0, libyuv::I010Copy( >+ source.DataY(), source.StrideY(), source.DataU(), source.StrideU(), >+ source.DataV(), source.StrideV(), buffer->MutableDataY(), >+ buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), >+ buffer->MutableDataV(), buffer->StrideV(), width, height)); >+ return buffer; >+} >+ >+// static >+rtc::scoped_refptr<I010Buffer> I010Buffer::Copy( >+ const I420BufferInterface& source) { >+ const int width = source.width(); >+ const int height = source.height(); >+ rtc::scoped_refptr<I010Buffer> buffer = Create(width, height); >+ RTC_CHECK_EQ( >+ 0, libyuv::I420ToI010( >+ source.DataY(), source.StrideY(), source.DataU(), source.StrideU(), >+ source.DataV(), source.StrideV(), buffer->MutableDataY(), >+ buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), >+ buffer->MutableDataV(), buffer->StrideV(), width, height)); >+ return buffer; >+} >+ >+// static >+rtc::scoped_refptr<I010Buffer> I010Buffer::Rotate( >+ const I010BufferInterface& src, >+ VideoRotation rotation) { >+ if (rotation == webrtc::kVideoRotation_0) >+ return Copy(src); >+ >+ RTC_CHECK(src.DataY()); >+ RTC_CHECK(src.DataU()); >+ RTC_CHECK(src.DataV()); >+ int rotated_width = src.width(); >+ int rotated_height = src.height(); >+ if (rotation == webrtc::kVideoRotation_90 || >+ rotation == webrtc::kVideoRotation_270) { >+ std::swap(rotated_width, rotated_height); >+ } >+ >+ rtc::scoped_refptr<webrtc::I010Buffer> buffer = >+ Create(rotated_width, rotated_height); >+ // TODO(emircan): Remove this when there is libyuv::I010Rotate(). >+ for (int x = 0; x < src.width(); x++) { >+ for (int y = 0; y < src.height(); y++) { >+ int dest_x = x; >+ int dest_y = y; >+ switch (rotation) { >+ // This case is covered by the early return. >+ case webrtc::kVideoRotation_0: >+ RTC_NOTREACHED(); >+ break; >+ case webrtc::kVideoRotation_90: >+ dest_x = src.height() - y - 1; >+ dest_y = x; >+ break; >+ case webrtc::kVideoRotation_180: >+ dest_x = src.width() - x - 1; >+ dest_y = src.height() - y - 1; >+ break; >+ case webrtc::kVideoRotation_270: >+ dest_x = y; >+ dest_y = src.width() - x - 1; >+ break; >+ } >+ buffer->MutableDataY()[dest_x + buffer->StrideY() * dest_y] = >+ src.DataY()[x + src.StrideY() * y]; >+ dest_x /= 2; >+ dest_y /= 2; >+ int src_x = x / 2; >+ int src_y = y / 2; >+ buffer->MutableDataU()[dest_x + buffer->StrideU() * dest_y] = >+ src.DataU()[src_x + src.StrideU() * src_y]; >+ buffer->MutableDataV()[dest_x + buffer->StrideV() * dest_y] = >+ src.DataV()[src_x + src.StrideV() * src_y]; >+ } >+ } >+ return buffer; >+} >+ >+rtc::scoped_refptr<I420BufferInterface> I010Buffer::ToI420() { >+ rtc::scoped_refptr<I420Buffer> i420_buffer = >+ I420Buffer::Create(width(), height()); >+ libyuv::I010ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(), >+ i420_buffer->MutableDataY(), i420_buffer->StrideY(), >+ i420_buffer->MutableDataU(), i420_buffer->StrideU(), >+ i420_buffer->MutableDataV(), i420_buffer->StrideV(), >+ width(), height()); >+ return i420_buffer; >+} >+ >+int I010Buffer::width() const { >+ return width_; >+} >+ >+int I010Buffer::height() const { >+ return height_; >+} >+ >+const uint16_t* I010Buffer::DataY() const { >+ return data_.get(); >+} >+const uint16_t* I010Buffer::DataU() const { >+ return data_.get() + stride_y_ * height_; >+} >+const uint16_t* I010Buffer::DataV() const { >+ return data_.get() + stride_y_ * height_ + stride_u_ * ((height_ + 1) / 2); >+} >+ >+int I010Buffer::StrideY() const { >+ return stride_y_; >+} >+int I010Buffer::StrideU() const { >+ return stride_u_; >+} >+int I010Buffer::StrideV() const { >+ return stride_v_; >+} >+ >+uint16_t* I010Buffer::MutableDataY() { >+ return const_cast<uint16_t*>(DataY()); >+} >+uint16_t* I010Buffer::MutableDataU() { >+ return const_cast<uint16_t*>(DataU()); >+} >+uint16_t* I010Buffer::MutableDataV() { >+ return const_cast<uint16_t*>(DataV()); >+} >+ >+void I010Buffer::CropAndScaleFrom(const I010BufferInterface& src, >+ int offset_x, >+ int offset_y, >+ int crop_width, >+ int crop_height) { >+ RTC_CHECK_LE(crop_width, src.width()); >+ RTC_CHECK_LE(crop_height, src.height()); >+ RTC_CHECK_LE(crop_width + offset_x, src.width()); >+ RTC_CHECK_LE(crop_height + offset_y, src.height()); >+ RTC_CHECK_GE(offset_x, 0); >+ RTC_CHECK_GE(offset_y, 0); >+ >+ // Make sure offset is even so that u/v plane becomes aligned. >+ const int uv_offset_x = offset_x / 2; >+ const int uv_offset_y = offset_y / 2; >+ offset_x = uv_offset_x * 2; >+ offset_y = uv_offset_y * 2; >+ >+ const uint16_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x; >+ const uint16_t* u_plane = >+ src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x; >+ const uint16_t* v_plane = >+ src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x; >+ int res = libyuv::I420Scale_16( >+ y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane, src.StrideV(), >+ crop_width, crop_height, MutableDataY(), StrideY(), MutableDataU(), >+ StrideU(), MutableDataV(), StrideV(), width(), height(), >+ libyuv::kFilterBox); >+ >+ RTC_DCHECK_EQ(res, 0); >+} >+ >+void I010Buffer::ScaleFrom(const I010BufferInterface& src) { >+ CropAndScaleFrom(src, 0, 0, src.width(), src.height()); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.h >new file mode 100644 >index 00000000000..1208b318525 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i010_buffer.h >@@ -0,0 +1,81 @@ >+/* >+ * Copyright (c) 2015 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. >+ */ >+ >+#ifndef API_VIDEO_I010_BUFFER_H_ >+#define API_VIDEO_I010_BUFFER_H_ >+ >+#include <memory> >+ >+#include "api/video/video_frame_buffer.h" >+#include "api/video/video_rotation.h" >+#include "rtc_base/memory/aligned_malloc.h" >+ >+namespace webrtc { >+ >+// Plain I010 buffer in standard memory. >+class I010Buffer : public I010BufferInterface { >+ public: >+ // Create a new buffer. >+ static rtc::scoped_refptr<I010Buffer> Create(int width, int height); >+ >+ // Create a new buffer and copy the pixel data. >+ static rtc::scoped_refptr<I010Buffer> Copy(const I010BufferInterface& buffer); >+ >+ // Convert and put I420 buffer into a new buffer. >+ static rtc::scoped_refptr<I010Buffer> Copy(const I420BufferInterface& buffer); >+ >+ // Return a rotated copy of |src|. >+ static rtc::scoped_refptr<I010Buffer> Rotate(const I010BufferInterface& src, >+ VideoRotation rotation); >+ >+ // VideoFrameBuffer implementation. >+ rtc::scoped_refptr<I420BufferInterface> ToI420() override; >+ >+ // PlanarYuv16BBuffer implementation. >+ int width() const override; >+ int height() const override; >+ const uint16_t* DataY() const override; >+ const uint16_t* DataU() const override; >+ const uint16_t* DataV() const override; >+ int StrideY() const override; >+ int StrideU() const override; >+ int StrideV() const override; >+ >+ uint16_t* MutableDataY(); >+ uint16_t* MutableDataU(); >+ uint16_t* MutableDataV(); >+ >+ // Scale the cropped area of |src| to the size of |this| buffer, and >+ // write the result into |this|. >+ void CropAndScaleFrom(const I010BufferInterface& src, >+ int offset_x, >+ int offset_y, >+ int crop_width, >+ int crop_height); >+ >+ // Scale all of |src| to the size of |this| buffer, with no cropping. >+ void ScaleFrom(const I010BufferInterface& src); >+ >+ protected: >+ I010Buffer(int width, int height, int stride_y, int stride_u, int stride_v); >+ ~I010Buffer() override; >+ >+ private: >+ const int width_; >+ const int height_; >+ const int stride_y_; >+ const int stride_u_; >+ const int stride_v_; >+ const std::unique_ptr<uint16_t, AlignedFreeDeleter> data_; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_I010_BUFFER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.cc >index 66071e1ec0d..8d239f320dc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.cc >@@ -34,8 +34,7 @@ int I420DataSize(int height, int stride_y, int stride_u, int stride_v) { > } // namespace > > I420Buffer::I420Buffer(int width, int height) >- : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) { >-} >+ : I420Buffer(width, height, width, (width + 1) / 2, (width + 1) / 2) {} > > I420Buffer::I420Buffer(int width, > int height, >@@ -47,9 +46,9 @@ I420Buffer::I420Buffer(int width, > stride_y_(stride_y), > stride_u_(stride_u), > stride_v_(stride_v), >- data_(static_cast<uint8_t*>(AlignedMalloc( >- I420DataSize(height, stride_y, stride_u, stride_v), >- kBufferAlignment))) { >+ data_(static_cast<uint8_t*>( >+ AlignedMalloc(I420DataSize(height, stride_y, stride_u, stride_v), >+ kBufferAlignment))) { > RTC_DCHECK_GT(width, 0); > RTC_DCHECK_GT(height, 0); > RTC_DCHECK_GE(stride_y, width); >@@ -57,8 +56,7 @@ I420Buffer::I420Buffer(int width, > RTC_DCHECK_GE(stride_v, (width + 1) / 2); > } > >-I420Buffer::~I420Buffer() { >-} >+I420Buffer::~I420Buffer() {} > > // static > rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, int height) { >@@ -71,34 +69,34 @@ rtc::scoped_refptr<I420Buffer> I420Buffer::Create(int width, > int stride_y, > int stride_u, > int stride_v) { >- return new rtc::RefCountedObject<I420Buffer>( >- width, height, stride_y, stride_u, stride_v); >+ return new rtc::RefCountedObject<I420Buffer>(width, height, stride_y, >+ stride_u, stride_v); > } > > // static > rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( > const I420BufferInterface& source) { >- return Copy(source.width(), source.height(), >- source.DataY(), source.StrideY(), >- source.DataU(), source.StrideU(), >- source.DataV(), source.StrideV()); >+ return Copy(source.width(), source.height(), source.DataY(), source.StrideY(), >+ source.DataU(), source.StrideU(), source.DataV(), >+ source.StrideV()); > } > > // static >-rtc::scoped_refptr<I420Buffer> I420Buffer::Copy( >- int width, int height, >- const uint8_t* data_y, int stride_y, >- const uint8_t* data_u, int stride_u, >- const uint8_t* data_v, int stride_v) { >+rtc::scoped_refptr<I420Buffer> I420Buffer::Copy(int width, >+ int height, >+ const uint8_t* data_y, >+ int stride_y, >+ const uint8_t* data_u, >+ int stride_u, >+ const uint8_t* data_v, >+ int stride_v) { > // Note: May use different strides than the input data. > rtc::scoped_refptr<I420Buffer> buffer = Create(width, height); >- RTC_CHECK_EQ(0, libyuv::I420Copy(data_y, stride_y, >- data_u, stride_u, >- data_v, stride_v, >- buffer->MutableDataY(), buffer->StrideY(), >- buffer->MutableDataU(), buffer->StrideU(), >- buffer->MutableDataV(), buffer->StrideV(), >- width, height)); >+ RTC_CHECK_EQ(0, libyuv::I420Copy(data_y, stride_y, data_u, stride_u, data_v, >+ stride_v, buffer->MutableDataY(), >+ buffer->StrideY(), buffer->MutableDataU(), >+ buffer->StrideU(), buffer->MutableDataV(), >+ buffer->StrideV(), width, height)); > return buffer; > } > >@@ -120,14 +118,13 @@ rtc::scoped_refptr<I420Buffer> I420Buffer::Rotate( > rtc::scoped_refptr<webrtc::I420Buffer> buffer = > I420Buffer::Create(rotated_width, rotated_height); > >- RTC_CHECK_EQ(0, libyuv::I420Rotate( >- src.DataY(), src.StrideY(), >- src.DataU(), src.StrideU(), >- src.DataV(), src.StrideV(), >- buffer->MutableDataY(), buffer->StrideY(), buffer->MutableDataU(), >- buffer->StrideU(), buffer->MutableDataV(), buffer->StrideV(), >- src.width(), src.height(), >- static_cast<libyuv::RotationMode>(rotation))); >+ RTC_CHECK_EQ(0, >+ libyuv::I420Rotate( >+ src.DataY(), src.StrideY(), src.DataU(), src.StrideU(), >+ src.DataV(), src.StrideV(), buffer->MutableDataY(), >+ buffer->StrideY(), buffer->MutableDataU(), buffer->StrideU(), >+ buffer->MutableDataV(), buffer->StrideV(), src.width(), >+ src.height(), static_cast<libyuv::RotationMode>(rotation))); > > return buffer; > } >@@ -179,9 +176,9 @@ uint8_t* I420Buffer::MutableDataV() { > void I420Buffer::SetBlack(I420Buffer* buffer) { > RTC_CHECK(libyuv::I420Rect(buffer->MutableDataY(), buffer->StrideY(), > buffer->MutableDataU(), buffer->StrideU(), >- buffer->MutableDataV(), buffer->StrideV(), >- 0, 0, buffer->width(), buffer->height(), >- 0, 128, 128) == 0); >+ buffer->MutableDataV(), buffer->StrideV(), 0, 0, >+ buffer->width(), buffer->height(), 0, 128, >+ 128) == 0); > } > > void I420Buffer::CropAndScaleFrom(const I420BufferInterface& src, >@@ -202,20 +199,16 @@ void I420Buffer::CropAndScaleFrom(const I420BufferInterface& src, > offset_x = uv_offset_x * 2; > offset_y = uv_offset_y * 2; > >- const uint8_t* y_plane = >- src.DataY() + src.StrideY() * offset_y + offset_x; >+ const uint8_t* y_plane = src.DataY() + src.StrideY() * offset_y + offset_x; > const uint8_t* u_plane = > src.DataU() + src.StrideU() * uv_offset_y + uv_offset_x; > const uint8_t* v_plane = > src.DataV() + src.StrideV() * uv_offset_y + uv_offset_x; >- int res = libyuv::I420Scale(y_plane, src.StrideY(), >- u_plane, src.StrideU(), >- v_plane, src.StrideV(), >- crop_width, crop_height, >- MutableDataY(), StrideY(), >- MutableDataU(), StrideU(), >- MutableDataV(), StrideV(), >- width(), height(), libyuv::kFilterBox); >+ int res = >+ libyuv::I420Scale(y_plane, src.StrideY(), u_plane, src.StrideU(), v_plane, >+ src.StrideV(), crop_width, crop_height, MutableDataY(), >+ StrideY(), MutableDataU(), StrideU(), MutableDataV(), >+ StrideV(), width(), height(), libyuv::kFilterBox); > > RTC_DCHECK_EQ(res, 0); > } >@@ -226,10 +219,8 @@ void I420Buffer::CropAndScaleFrom(const I420BufferInterface& src) { > const int crop_height = > std::min(src.height(), height() * src.width() / width()); > >- CropAndScaleFrom( >- src, >- (src.width() - crop_width) / 2, (src.height() - crop_height) / 2, >- crop_width, crop_height); >+ CropAndScaleFrom(src, (src.width() - crop_width) / 2, >+ (src.height() - crop_height) / 2, crop_width, crop_height); > } > > void I420Buffer::ScaleFrom(const I420BufferInterface& src) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.h >index bdac80bbc10..282b2426ca3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/i420_buffer.h >@@ -13,9 +13,9 @@ > > #include <memory> > >-#include "api/video/video_rotation.h" > #include "api/video/video_frame_buffer.h" >-#include "system_wrappers/include/aligned_malloc.h" >+#include "api/video/video_rotation.h" >+#include "rtc_base/memory/aligned_malloc.h" > > namespace webrtc { > >@@ -36,11 +36,14 @@ class I420Buffer : public I420BufferInterface { > return Copy(*buffer.GetI420()); > } > >- static rtc::scoped_refptr<I420Buffer> Copy( >- int width, int height, >- const uint8_t* data_y, int stride_y, >- const uint8_t* data_u, int stride_u, >- const uint8_t* data_v, int stride_v); >+ static rtc::scoped_refptr<I420Buffer> Copy(int width, >+ int height, >+ const uint8_t* data_y, >+ int stride_y, >+ const uint8_t* data_u, >+ int stride_u, >+ const uint8_t* data_v, >+ int stride_v); > > // Returns a rotated copy of |src|. > static rtc::scoped_refptr<I420Buffer> Rotate(const I420BufferInterface& src, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/valgrind/memcheck/suppressions_mac.txt b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/BUILD.gn >similarity index 51% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/valgrind/memcheck/suppressions_mac.txt >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/BUILD.gn >index ec20df46d8b..cba42458d22 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/valgrind/memcheck/suppressions_mac.txt >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/BUILD.gn >@@ -1,4 +1,4 @@ >-# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. >+# Copyright (c) 2018 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 >@@ -6,6 +6,15 @@ > # in the file PATENTS. All contributing project authors may > # be found in the AUTHORS file in the root of the source tree. > >-# This file is used in addition to the one already maintained in Chrome. >-# It acts as a place holder for future additions for WebRTC. >-# It must exist for the Python wrapper script to work properly. >+import("../../../webrtc.gni") >+ >+rtc_source_set("rtc_api_video_unittests") { >+ testonly = true >+ sources = [ >+ "video_bitrate_allocation_unittest.cc", >+ ] >+ deps = [ >+ "..:video_bitrate_allocation", >+ "../../../test:test_support", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/video_bitrate_allocation_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/video_bitrate_allocation_unittest.cc >new file mode 100644 >index 00000000000..f22957b562e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/test/video_bitrate_allocation_unittest.cc >@@ -0,0 +1,63 @@ >+/* >+ * Copyright (c) 2018 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 <memory> >+#include <string> >+ >+#include "api/video/video_bitrate_allocation.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+TEST(VideoBitrateAllocation, SimulcastTargetBitrate) { >+ VideoBitrateAllocation bitrate; >+ bitrate.SetBitrate(0, 0, 10000); >+ bitrate.SetBitrate(0, 1, 20000); >+ bitrate.SetBitrate(1, 0, 40000); >+ bitrate.SetBitrate(1, 1, 80000); >+ >+ VideoBitrateAllocation layer0_bitrate; >+ layer0_bitrate.SetBitrate(0, 0, 10000); >+ layer0_bitrate.SetBitrate(0, 1, 20000); >+ >+ VideoBitrateAllocation layer1_bitrate; >+ layer1_bitrate.SetBitrate(0, 0, 40000); >+ layer1_bitrate.SetBitrate(0, 1, 80000); >+ >+ std::vector<absl::optional<VideoBitrateAllocation>> layer_allocations = >+ bitrate.GetSimulcastAllocations(); >+ >+ EXPECT_EQ(layer0_bitrate, layer_allocations[0]); >+ EXPECT_EQ(layer1_bitrate, layer_allocations[1]); >+} >+ >+TEST(VideoBitrateAllocation, SimulcastTargetBitrateWithInactiveStream) { >+ // Create bitrate allocation with bitrate only for the first and third stream. >+ VideoBitrateAllocation bitrate; >+ bitrate.SetBitrate(0, 0, 10000); >+ bitrate.SetBitrate(0, 1, 20000); >+ bitrate.SetBitrate(2, 0, 40000); >+ bitrate.SetBitrate(2, 1, 80000); >+ >+ VideoBitrateAllocation layer0_bitrate; >+ layer0_bitrate.SetBitrate(0, 0, 10000); >+ layer0_bitrate.SetBitrate(0, 1, 20000); >+ >+ VideoBitrateAllocation layer2_bitrate; >+ layer2_bitrate.SetBitrate(0, 0, 40000); >+ layer2_bitrate.SetBitrate(0, 1, 80000); >+ >+ std::vector<absl::optional<VideoBitrateAllocation>> layer_allocations = >+ bitrate.GetSimulcastAllocations(); >+ >+ EXPECT_EQ(layer0_bitrate, layer_allocations[0]); >+ EXPECT_FALSE(layer_allocations[1]); >+ EXPECT_EQ(layer2_bitrate, layer_allocations[2]); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.cc >new file mode 100644 >index 00000000000..6c5ad1eae5f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.cc >@@ -0,0 +1,185 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/video_bitrate_allocation.h" >+ >+#include <limits> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/numerics/safe_conversions.h" >+#include "rtc_base/strings/string_builder.h" >+#include "rtc_base/stringutils.h" >+ >+namespace webrtc { >+ >+VideoBitrateAllocation::VideoBitrateAllocation() : sum_(0) {} >+ >+bool VideoBitrateAllocation::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); >+ int64_t new_bitrate_sum_bps = sum_; >+ absl::optional<uint32_t>& layer_bitrate = >+ bitrates_[spatial_index][temporal_index]; >+ if (layer_bitrate) { >+ RTC_DCHECK_LE(*layer_bitrate, sum_); >+ new_bitrate_sum_bps -= *layer_bitrate; >+ } >+ new_bitrate_sum_bps += bitrate_bps; >+ if (new_bitrate_sum_bps > kMaxBitrateBps) >+ return false; >+ >+ layer_bitrate = bitrate_bps; >+ sum_ = rtc::dchecked_cast<uint32_t>(new_bitrate_sum_bps); >+ return true; >+} >+ >+bool VideoBitrateAllocation::HasBitrate(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].has_value(); >+} >+ >+uint32_t VideoBitrateAllocation::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].value_or(0); >+} >+ >+// Whether the specific spatial layers has the bitrate set in any of its >+// temporal layers. >+bool VideoBitrateAllocation::IsSpatialLayerUsed(size_t spatial_index) const { >+ RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >+ for (size_t i = 0; i < kMaxTemporalStreams; ++i) { >+ if (bitrates_[spatial_index][i].has_value()) >+ return true; >+ } >+ return false; >+} >+ >+// Get the sum of all the temporal layer for a specific spatial layer. >+uint32_t VideoBitrateAllocation::GetSpatialLayerSum( >+ size_t spatial_index) const { >+ RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >+ return GetTemporalLayerSum(spatial_index, kMaxTemporalStreams - 1); >+} >+ >+uint32_t VideoBitrateAllocation::GetTemporalLayerSum( >+ size_t spatial_index, >+ size_t temporal_index) const { >+ RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >+ RTC_CHECK_LT(temporal_index, kMaxTemporalStreams); >+ uint32_t sum = 0; >+ for (size_t i = 0; i <= temporal_index; ++i) { >+ sum += bitrates_[spatial_index][i].value_or(0); >+ } >+ return sum; >+} >+ >+std::vector<uint32_t> VideoBitrateAllocation::GetTemporalLayerAllocation( >+ size_t spatial_index) const { >+ RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >+ std::vector<uint32_t> temporal_rates; >+ >+ // Find the highest temporal layer with a defined bitrate in order to >+ // determine the size of the temporal layer allocation. >+ for (size_t i = kMaxTemporalStreams; i > 0; --i) { >+ if (bitrates_[spatial_index][i - 1].has_value()) { >+ temporal_rates.resize(i); >+ break; >+ } >+ } >+ >+ for (size_t i = 0; i < temporal_rates.size(); ++i) { >+ temporal_rates[i] = bitrates_[spatial_index][i].value_or(0); >+ } >+ >+ return temporal_rates; >+} >+ >+std::vector<absl::optional<VideoBitrateAllocation>> >+VideoBitrateAllocation::GetSimulcastAllocations() const { >+ std::vector<absl::optional<VideoBitrateAllocation>> bitrates; >+ for (size_t si = 0; si < kMaxSpatialLayers; ++si) { >+ absl::optional<VideoBitrateAllocation> layer_bitrate; >+ if (IsSpatialLayerUsed(si)) { >+ layer_bitrate = VideoBitrateAllocation(); >+ for (int tl = 0; tl < kMaxTemporalStreams; ++tl) { >+ if (HasBitrate(si, tl)) >+ layer_bitrate->SetBitrate(0, tl, GetBitrate(si, tl)); >+ } >+ } >+ bitrates.push_back(layer_bitrate); >+ } >+ return bitrates; >+} >+ >+bool VideoBitrateAllocation::operator==( >+ const VideoBitrateAllocation& other) const { >+ for (size_t si = 0; si < kMaxSpatialLayers; ++si) { >+ for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) { >+ if (bitrates_[si][ti] != other.bitrates_[si][ti]) >+ return false; >+ } >+ } >+ return true; >+} >+ >+std::string VideoBitrateAllocation::ToString() const { >+ if (sum_ == 0) >+ return "VideoBitrateAllocation [ [] ]"; >+ >+ // Max string length in practice is 260, but let's have some overhead and >+ // round up to nearest power of two. >+ char string_buf[512]; >+ rtc::SimpleStringBuilder ssb(string_buf); >+ >+ ssb << "VideoBitrateAllocation ["; >+ uint32_t spatial_cumulator = 0; >+ for (size_t 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_) { >+ ssb << " ["; >+ } else { >+ if (si > 0) >+ ssb << ","; >+ ssb << '\n' << " ["; >+ } >+ spatial_cumulator += layer_sum; >+ >+ uint32_t temporal_cumulator = 0; >+ for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) { >+ RTC_DCHECK_LE(temporal_cumulator, layer_sum); >+ if (temporal_cumulator == layer_sum) >+ break; >+ >+ if (ti > 0) >+ ssb << ", "; >+ >+ uint32_t bitrate = bitrates_[si][ti].value_or(0); >+ ssb << bitrate; >+ temporal_cumulator += bitrate; >+ } >+ ssb << "]"; >+ } >+ >+ RTC_DCHECK_EQ(spatial_cumulator, sum_); >+ ssb << " ]"; >+ return ssb.str(); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.h >new file mode 100644 >index 00000000000..9e2501d85a0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocation.h >@@ -0,0 +1,90 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_BITRATE_ALLOCATION_H_ >+#define API_VIDEO_VIDEO_BITRATE_ALLOCATION_H_ >+ >+#include <limits> >+#include <string> >+#include <vector> >+ >+#include "absl/types/optional.h" >+ >+namespace webrtc { >+ >+// TODO(sprang): Move back to common_types when include of this is removed. >+enum : int { kMaxSimulcastStreams = 4 }; >+enum : int { kMaxSpatialLayers = 5 }; >+enum : int { kMaxTemporalStreams = 4 }; >+ >+// Class that describes how video bitrate, in bps, is allocated across temporal >+// and spatial layers. Not that bitrates are NOT cumulative. Depending on if >+// layers are dependent or not, it is up to the user to aggregate. >+// For each index, the bitrate can also both set and unset. This is used with a >+// set bps = 0 to signal an explicit "turn off" signal. >+class VideoBitrateAllocation { >+ public: >+ static constexpr uint32_t kMaxBitrateBps = >+ std::numeric_limits<uint32_t>::max(); >+ VideoBitrateAllocation(); >+ >+ bool SetBitrate(size_t spatial_index, >+ size_t temporal_index, >+ uint32_t bitrate_bps); >+ >+ bool HasBitrate(size_t spatial_index, size_t temporal_index) const; >+ >+ uint32_t GetBitrate(size_t spatial_index, size_t temporal_index) const; >+ >+ // Whether the specific spatial layers has the bitrate set in any of its >+ // temporal layers. >+ bool IsSpatialLayerUsed(size_t spatial_index) const; >+ >+ // Get the sum of all the temporal layer for a specific spatial layer. >+ uint32_t GetSpatialLayerSum(size_t spatial_index) const; >+ >+ // Sum of bitrates of temporal layers, from layer 0 to |temporal_index| >+ // inclusive, of specified spatial layer |spatial_index|. Bitrates of lower >+ // spatial layers are not included. >+ uint32_t GetTemporalLayerSum(size_t spatial_index, >+ size_t temporal_index) const; >+ >+ // Returns a vector of the temporal layer bitrates for the specific spatial >+ // layer. Length of the returned vector is cropped to the highest temporal >+ // layer with a defined bitrate. >+ std::vector<uint32_t> GetTemporalLayerAllocation(size_t spatial_index) const; >+ >+ // Returns one VideoBitrateAllocation for each spatial layer. This is used to >+ // configure simulcast streams. Note that the length of the returned vector is >+ // always kMaxSpatialLayers, the optional is unset for unused layers. >+ std::vector<absl::optional<VideoBitrateAllocation>> GetSimulcastAllocations() >+ const; >+ >+ uint32_t get_sum_bps() const { return sum_; } // Sum of all bitrates. >+ uint32_t get_sum_kbps() const { >+ // Round down to not exceed the allocated bitrate. >+ return sum_ / 1000; >+ } >+ >+ bool operator==(const VideoBitrateAllocation& other) const; >+ inline bool operator!=(const VideoBitrateAllocation& other) const { >+ return !(*this == other); >+ } >+ >+ std::string ToString() const; >+ >+ private: >+ uint32_t sum_; >+ absl::optional<uint32_t> bitrates_[kMaxSpatialLayers][kMaxTemporalStreams]; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_BITRATE_ALLOCATION_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator.h >new file mode 100644 >index 00000000000..f85c633d0ff >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator.h >@@ -0,0 +1,38 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_BITRATE_ALLOCATOR_H_ >+#define API_VIDEO_VIDEO_BITRATE_ALLOCATOR_H_ >+ >+#include "api/video/video_bitrate_allocation.h" >+ >+namespace webrtc { >+ >+class VideoBitrateAllocator { >+ public: >+ VideoBitrateAllocator() {} >+ virtual ~VideoBitrateAllocator() {} >+ >+ virtual VideoBitrateAllocation GetAllocation(uint32_t total_bitrate_bps, >+ uint32_t framerate) = 0; >+}; >+ >+class VideoBitrateAllocationObserver { >+ public: >+ VideoBitrateAllocationObserver() {} >+ virtual ~VideoBitrateAllocationObserver() {} >+ >+ virtual void OnBitrateAllocationUpdated( >+ const VideoBitrateAllocation& allocation) = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_BITRATE_ALLOCATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator_factory.h >new file mode 100644 >index 00000000000..bb1d8b60a14 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_bitrate_allocator_factory.h >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_ >+#define API_VIDEO_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_ >+ >+#include <memory> >+#include "api/video/video_bitrate_allocator.h" >+#include "media/base/codec.h" >+ >+namespace webrtc { >+ >+// A factory that creates VideoBitrateAllocator. >+// NOTE: This class is still under development and may change without notice. >+class VideoBitrateAllocatorFactory { >+ public: >+ virtual ~VideoBitrateAllocatorFactory() = default; >+ // Creates a VideoBitrateAllocator for a specific video codec. >+ virtual std::unique_ptr<VideoBitrateAllocator> CreateVideoBitrateAllocator( >+ const VideoCodec& codec) = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_BITRATE_ALLOCATOR_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_content_type.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_content_type.cc >index 149b4f9926b..9ba3ece79b6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_content_type.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_content_type.cc >@@ -68,19 +68,16 @@ bool SetSimulcastId(VideoContentType* content_type, uint8_t simulcast_id) { > return true; > } > >-uint8_t GetExperimentId( >- const VideoContentType& content_type) { >+uint8_t GetExperimentId(const VideoContentType& content_type) { > return (static_cast<uint8_t>(content_type) & kExperimentBitsMask) >> > kExperimentShift; > } >-uint8_t GetSimulcastId( >- const VideoContentType& content_type) { >+uint8_t GetSimulcastId(const VideoContentType& content_type) { > return (static_cast<uint8_t>(content_type) & kSimulcastBitsMask) >> > kSimulcastShift; > } > >-bool IsScreenshare( >- const VideoContentType& content_type) { >+bool IsScreenshare(const VideoContentType& content_type) { > return (static_cast<uint8_t>(content_type) & kScreenshareBitsMask) > 0; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.cc >index 93b3c9c6b97..5521ad8a587 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.cc >@@ -15,6 +15,55 @@ > > namespace webrtc { > >+VideoFrame::Builder::Builder() = default; >+ >+VideoFrame::Builder::~Builder() = default; >+ >+VideoFrame VideoFrame::Builder::build() { >+ return VideoFrame(video_frame_buffer_, timestamp_us_, timestamp_rtp_, >+ ntp_time_ms_, rotation_, color_space_); >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_video_frame_buffer( >+ const rtc::scoped_refptr<VideoFrameBuffer>& buffer) { >+ video_frame_buffer_ = buffer; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_ms( >+ int64_t timestamp_ms) { >+ timestamp_us_ = timestamp_ms * rtc::kNumMicrosecsPerMillisec; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_us( >+ int64_t timestamp_us) { >+ timestamp_us_ = timestamp_us; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_timestamp_rtp( >+ uint32_t timestamp_rtp) { >+ timestamp_rtp_ = timestamp_rtp; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_ntp_time_ms(int64_t ntp_time_ms) { >+ ntp_time_ms_ = ntp_time_ms; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_rotation(VideoRotation rotation) { >+ rotation_ = rotation; >+ return *this; >+} >+ >+VideoFrame::Builder& VideoFrame::Builder::set_color_space( >+ const ColorSpace& color_space) { >+ color_space_ = color_space; >+ return *this; >+} >+ > VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, > webrtc::VideoRotation rotation, > int64_t timestamp_us) >@@ -25,17 +74,30 @@ VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, > rotation_(rotation) {} > > VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, >- uint32_t timestamp, >+ uint32_t timestamp_rtp, > int64_t render_time_ms, > VideoRotation rotation) > : video_frame_buffer_(buffer), >- timestamp_rtp_(timestamp), >+ timestamp_rtp_(timestamp_rtp), > ntp_time_ms_(0), > timestamp_us_(render_time_ms * rtc::kNumMicrosecsPerMillisec), > rotation_(rotation) { > RTC_DCHECK(buffer); > } > >+VideoFrame::VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, >+ int64_t timestamp_us, >+ uint32_t timestamp_rtp, >+ int64_t ntp_time_ms, >+ VideoRotation rotation, >+ const absl::optional<ColorSpace>& color_space) >+ : video_frame_buffer_(buffer), >+ timestamp_rtp_(timestamp_rtp), >+ ntp_time_ms_(ntp_time_ms), >+ timestamp_us_(timestamp_us), >+ rotation_(rotation), >+ color_space_(color_space) {} >+ > VideoFrame::~VideoFrame() = default; > > VideoFrame::VideoFrame(const VideoFrame&) = default; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.h >index a72bef1d32e..dcb533e29f0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame.h >@@ -13,23 +13,46 @@ > > #include <stdint.h> > >-#include "api/video/video_rotation.h" >+#include "absl/types/optional.h" >+#include "api/video/color_space.h" > #include "api/video/video_frame_buffer.h" >+#include "api/video/video_rotation.h" > > namespace webrtc { > > class VideoFrame { > public: >- // TODO(nisse): This constructor is consistent with the now deleted >- // cricket::WebRtcVideoFrame. We should consider whether or not we >- // want to stick to this style and deprecate the other constructor. >+ // Preferred way of building VideoFrame objects. >+ class Builder { >+ public: >+ Builder(); >+ ~Builder(); >+ >+ VideoFrame build(); >+ Builder& set_video_frame_buffer( >+ const rtc::scoped_refptr<VideoFrameBuffer>& buffer); >+ Builder& set_timestamp_ms(int64_t timestamp_ms); >+ Builder& set_timestamp_us(int64_t timestamp_us); >+ Builder& set_timestamp_rtp(uint32_t timestamp_rtp); >+ Builder& set_ntp_time_ms(int64_t ntp_time_ms); >+ Builder& set_rotation(VideoRotation rotation); >+ Builder& set_color_space(const ColorSpace& color_space); >+ >+ private: >+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_; >+ int64_t timestamp_us_ = 0; >+ uint32_t timestamp_rtp_ = 0; >+ int64_t ntp_time_ms_ = 0; >+ VideoRotation rotation_ = kVideoRotation_0; >+ absl::optional<ColorSpace> color_space_; >+ }; >+ >+ // To be deprecated. Migrate all use to Builder. > VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, > webrtc::VideoRotation rotation, > int64_t timestamp_us); >- >- // Preferred constructor. > VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, >- uint32_t timestamp, >+ uint32_t timestamp_rtp, > int64_t render_time_ms, > VideoRotation rotation); > >@@ -87,6 +110,9 @@ class VideoFrame { > VideoRotation rotation() const { return rotation_; } > void set_rotation(VideoRotation rotation) { rotation_ = rotation; } > >+ // Set Color space when available. >+ absl::optional<ColorSpace> color_space() const { return color_space_; } >+ > // Get render time in milliseconds. > // TODO(nisse): Deprecated. Migrate all users to timestamp_us(). > int64_t render_time_ms() const; >@@ -102,12 +128,20 @@ class VideoFrame { > } > > private: >+ VideoFrame(const rtc::scoped_refptr<VideoFrameBuffer>& buffer, >+ int64_t timestamp_us, >+ uint32_t timestamp_rtp, >+ int64_t ntp_time_ms, >+ VideoRotation rotation, >+ const absl::optional<ColorSpace>& color_space); >+ > // An opaque reference counted handle that stores the pixel data. > rtc::scoped_refptr<webrtc::VideoFrameBuffer> video_frame_buffer_; > uint32_t timestamp_rtp_; > int64_t ntp_time_ms_; > int64_t timestamp_us_; > VideoRotation rotation_; >+ absl::optional<ColorSpace> color_space_; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.cc >index 867f249fe63..41276bec270 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.cc >@@ -45,6 +45,16 @@ const I444BufferInterface* VideoFrameBuffer::GetI444() const { > return static_cast<const I444BufferInterface*>(this); > } > >+I010BufferInterface* VideoFrameBuffer::GetI010() { >+ RTC_CHECK(type() == Type::kI010); >+ return static_cast<I010BufferInterface*>(this); >+} >+ >+const I010BufferInterface* VideoFrameBuffer::GetI010() const { >+ RTC_CHECK(type() == Type::kI010); >+ return static_cast<const I010BufferInterface*>(this); >+} >+ > VideoFrameBuffer::Type I420BufferInterface::type() const { > return Type::kI420; > } >@@ -77,4 +87,16 @@ int I444BufferInterface::ChromaHeight() const { > return height(); > } > >+VideoFrameBuffer::Type I010BufferInterface::type() const { >+ return Type::kI010; >+} >+ >+int I010BufferInterface::ChromaWidth() const { >+ return (width() + 1) / 2; >+} >+ >+int I010BufferInterface::ChromaHeight() const { >+ return (height() + 1) / 2; >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.h >index 2be7e0bb9f6..1e8169ac57c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_frame_buffer.h >@@ -21,6 +21,7 @@ namespace webrtc { > class I420BufferInterface; > class I420ABufferInterface; > class I444BufferInterface; >+class I010BufferInterface; > > // Base class for frame buffers of different types of pixel format and storage. > // The tag in type() indicates how the data is represented, and each type is >@@ -47,6 +48,7 @@ class VideoFrameBuffer : public rtc::RefCountInterface { > kI420, > kI420A, > kI444, >+ kI010, > }; > > // This function specifies in what pixel format the data is stored in. >@@ -73,33 +75,44 @@ class VideoFrameBuffer : public rtc::RefCountInterface { > const I420ABufferInterface* GetI420A() const; > I444BufferInterface* GetI444(); > const I444BufferInterface* GetI444() const; >+ I010BufferInterface* GetI010(); >+ const I010BufferInterface* GetI010() const; > > protected: > ~VideoFrameBuffer() override {} > }; > >-// This interface represents Type::kI420 and Type::kI444. >+// This interface represents planar formats. > class PlanarYuvBuffer : public VideoFrameBuffer { > public: > virtual int ChromaWidth() const = 0; > virtual int ChromaHeight() const = 0; > >+ // Returns the number of steps(in terms of Data*() return type) between >+ // successive rows for a given plane. >+ virtual int StrideY() const = 0; >+ virtual int StrideU() const = 0; >+ virtual int StrideV() const = 0; >+ >+ protected: >+ ~PlanarYuvBuffer() override {} >+}; >+ >+// This interface represents 8-bit color depth formats: Type::kI420, >+// Type::kI420A and Type::kI444. >+class PlanarYuv8Buffer : public PlanarYuvBuffer { >+ public: > // Returns pointer to the pixel data for a given plane. The memory is owned by > // the VideoFrameBuffer object and must not be freed by the caller. > virtual const uint8_t* DataY() const = 0; > virtual const uint8_t* DataU() const = 0; > virtual const uint8_t* DataV() const = 0; > >- // Returns the number of bytes between successive rows for a given plane. >- virtual int StrideY() const = 0; >- virtual int StrideU() const = 0; >- virtual int StrideV() const = 0; >- > protected: >- ~PlanarYuvBuffer() override {} >+ ~PlanarYuv8Buffer() override {} > }; > >-class I420BufferInterface : public PlanarYuvBuffer { >+class I420BufferInterface : public PlanarYuv8Buffer { > public: > Type type() const override; > >@@ -122,7 +135,7 @@ class I420ABufferInterface : public I420BufferInterface { > ~I420ABufferInterface() override {} > }; > >-class I444BufferInterface : public PlanarYuvBuffer { >+class I444BufferInterface : public PlanarYuv8Buffer { > public: > Type type() const final; > >@@ -133,6 +146,32 @@ class I444BufferInterface : public PlanarYuvBuffer { > ~I444BufferInterface() override {} > }; > >+// This interface represents 8-bit to 16-bit color depth formats: Type::kI010. >+class PlanarYuv16BBuffer : public PlanarYuvBuffer { >+ public: >+ // Returns pointer to the pixel data for a given plane. The memory is owned by >+ // the VideoFrameBuffer object and must not be freed by the caller. >+ virtual const uint16_t* DataY() const = 0; >+ virtual const uint16_t* DataU() const = 0; >+ virtual const uint16_t* DataV() const = 0; >+ >+ protected: >+ ~PlanarYuv16BBuffer() override {} >+}; >+ >+// Represents Type::kI010, allocates 16 bits per pixel and fills 10 least >+// significant bits with color information. >+class I010BufferInterface : public PlanarYuv16BBuffer { >+ public: >+ Type type() const override; >+ >+ int ChromaWidth() const final; >+ int ChromaHeight() const final; >+ >+ protected: >+ ~I010BufferInterface() override {} >+}; >+ > } // namespace webrtc > > #endif // API_VIDEO_VIDEO_FRAME_BUFFER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosinkinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_sink_interface.h >similarity index 81% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/api/videosinkinterface.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_sink_interface.h >index 23993205417..aac8b4ac38a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosinkinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_sink_interface.h >@@ -8,8 +8,8 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef API_VIDEOSINKINTERFACE_H_ >-#define API_VIDEOSINKINTERFACE_H_ >+#ifndef API_VIDEO_VIDEO_SINK_INTERFACE_H_ >+#define API_VIDEO_VIDEO_SINK_INTERFACE_H_ > > #include <rtc_base/checks.h> > >@@ -18,7 +18,7 @@ namespace rtc { > template <typename VideoFrameT> > class VideoSinkInterface { > public: >- virtual ~VideoSinkInterface() {} >+ virtual ~VideoSinkInterface() = default; > > virtual void OnFrame(const VideoFrameT& frame) = 0; > >@@ -29,4 +29,4 @@ class VideoSinkInterface { > > } // namespace rtc > >-#endif // API_VIDEOSINKINTERFACE_H_ >+#endif // API_VIDEO_VIDEO_SINK_INTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.cc >similarity index 83% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.cc >index 5eda369df08..70a86c3d645 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.cc >@@ -8,11 +8,12 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "api/videosourceinterface.h" >+#include "api/video/video_source_interface.h" > > namespace rtc { > > VideoSinkWants::VideoSinkWants() = default; >+VideoSinkWants::VideoSinkWants(const VideoSinkWants&) = default; > VideoSinkWants::~VideoSinkWants() = default; > > } // namespace rtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.h >similarity index 84% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.h >index ffb017ad51d..4ee47194552 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_source_interface.h >@@ -8,13 +8,13 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef API_VIDEOSOURCEINTERFACE_H_ >-#define API_VIDEOSOURCEINTERFACE_H_ >+#ifndef API_VIDEO_VIDEO_SOURCE_INTERFACE_H_ >+#define API_VIDEO_VIDEO_SOURCE_INTERFACE_H_ > > #include <limits> > >-#include "api/optional.h" >-#include "api/videosinkinterface.h" >+#include "absl/types/optional.h" >+#include "api/video/video_sink_interface.h" > > namespace rtc { > >@@ -22,6 +22,7 @@ namespace rtc { > // should have when it is delivered to a certain sink. > struct VideoSinkWants { > VideoSinkWants(); >+ VideoSinkWants(const VideoSinkWants&); > ~VideoSinkWants(); > // Tells the source whether the sink wants frames with rotation applied. > // By default, any rotation must be applied by the sink. >@@ -37,7 +38,7 @@ struct VideoSinkWants { > // have improved after an earlier downgrade. The source should select the > // closest resolution to this pixel count, but if max_pixel_count is set, it > // still sets the absolute upper bound. >- rtc::Optional<int> target_pixel_count; >+ absl::optional<int> target_pixel_count; > // Tells the source the maximum framerate the sink wants. > int max_framerate_fps = std::numeric_limits<int>::max(); > }; >@@ -52,8 +53,9 @@ class VideoSourceInterface { > virtual void RemoveSink(VideoSinkInterface<VideoFrameT>* sink) = 0; > > protected: >+ // Non-public, since one shouldn't own sources via this interface. > virtual ~VideoSourceInterface() {} > }; > > } // namespace rtc >-#endif // API_VIDEOSOURCEINTERFACE_H_ >+#endif // API_VIDEO_VIDEO_SOURCE_INTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder.h >new file mode 100644 >index 00000000000..dff60d87e63 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder.h >@@ -0,0 +1,51 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_DECODER_H_ >+#define API_VIDEO_VIDEO_STREAM_DECODER_H_ >+ >+#include <map> >+#include <memory> >+#include <utility> >+ >+#include "api/video/encoded_frame.h" >+#include "api/video/video_frame.h" >+#include "api/video_codecs/sdp_video_format.h" >+#include "api/video_codecs/video_decoder_factory.h" >+ >+namespace webrtc { >+// NOTE: This class is still under development and may change without notice. >+class VideoStreamDecoder { >+ public: >+ class Callbacks { >+ public: >+ virtual ~Callbacks() = default; >+ >+ // Called when the VideoStreamDecoder enters a non-decodable state. >+ virtual void OnNonDecodableState() = 0; >+ >+ // Called with the last continuous frame. >+ virtual void OnContinuousUntil( >+ const video_coding::VideoLayerFrameId& key) = 0; >+ >+ // Called with the decoded frame. >+ virtual void OnDecodedFrame(VideoFrame decodedImage, >+ absl::optional<int> decode_time_ms, >+ absl::optional<int> qp) = 0; >+ }; >+ >+ virtual ~VideoStreamDecoder() = default; >+ >+ virtual void OnFrame(std::unique_ptr<video_coding::EncodedFrame> frame) = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_STREAM_DECODER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.cc >new file mode 100644 >index 00000000000..d57925524bc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.cc >@@ -0,0 +1,24 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/video_stream_decoder_create.h" >+ >+#include "absl/memory/memory.h" >+#include "video/video_stream_decoder_impl.h" >+ >+namespace webrtc { >+std::unique_ptr<VideoStreamDecoder> CreateVideoStreamDecoder( >+ VideoStreamDecoder::Callbacks* callbacks, >+ VideoDecoderFactory* decoder_factory, >+ std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings) { >+ return absl::make_unique<VideoStreamDecoderImpl>(callbacks, decoder_factory, >+ std::move(decoder_settings)); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.h >new file mode 100644 >index 00000000000..04682901da1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_decoder_create.h >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_DECODER_CREATE_H_ >+#define API_VIDEO_VIDEO_STREAM_DECODER_CREATE_H_ >+ >+#include <map> >+#include <memory> >+#include <utility> >+ >+#include "api/video/video_stream_decoder.h" >+ >+namespace webrtc { >+// The |decoder_settings| parameter is a map between: >+// <payload type> --> <<video format>, <number of cores>>. >+// The video format is used when instantiating a decoder, and >+// the number of cores is used when initializing the decoder. >+std::unique_ptr<VideoStreamDecoder> CreateVideoStreamDecoder( >+ VideoStreamDecoder::Callbacks* callbacks, >+ VideoDecoderFactory* decoder_factory, >+ std::map<int, std::pair<SdpVideoFormat, int>> decoder_settings); >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_STREAM_DECODER_CREATE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.cc >new file mode 100644 >index 00000000000..3147d34eea7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.cc >@@ -0,0 +1,27 @@ >+/* >+ * Copyright (c) 2018 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 "api/video/video_stream_encoder_create.h" >+ >+#include "absl/memory/memory.h" >+#include "video/video_stream_encoder.h" >+ >+namespace webrtc { >+std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( >+ uint32_t number_of_cores, >+ VideoStreamEncoderObserver* encoder_stats_observer, >+ const VideoStreamEncoderSettings& settings, >+ // Deprecated, used for tests only. >+ rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback) { >+ return absl::make_unique<VideoStreamEncoder>( >+ number_of_cores, encoder_stats_observer, settings, pre_encode_callback, >+ absl::make_unique<OveruseFrameDetector>(encoder_stats_observer)); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.h >new file mode 100644 >index 00000000000..911727327cf >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_create.h >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_ >+#define API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_ >+ >+#include <map> >+#include <memory> >+#include <utility> >+ >+#include "api/video/video_stream_encoder_interface.h" >+#include "api/video/video_stream_encoder_observer.h" >+#include "api/video/video_stream_encoder_settings.h" >+ >+namespace webrtc { >+ >+std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( >+ uint32_t number_of_cores, >+ VideoStreamEncoderObserver* encoder_stats_observer, >+ const VideoStreamEncoderSettings& settings, >+ // Deprecated, used for tests only. >+ rtc::VideoSinkInterface<VideoFrame>* pre_encode_callback); >+ >+inline std::unique_ptr<VideoStreamEncoderInterface> CreateVideoStreamEncoder( >+ uint32_t number_of_cores, >+ VideoStreamEncoderObserver* encoder_stats_observer, >+ const VideoStreamEncoderSettings& settings) { >+ return CreateVideoStreamEncoder(number_of_cores, encoder_stats_observer, >+ settings, nullptr); >+} >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_STREAM_ENCODER_CREATE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_interface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_interface.h >new file mode 100644 >index 00000000000..2f95e5851e1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_interface.h >@@ -0,0 +1,105 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_ >+#define API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_ >+ >+#include <vector> >+ >+#include "api/rtpparameters.h" // For DegradationPreference. >+#include "api/video/video_sink_interface.h" >+#include "api/video/video_source_interface.h" >+#include "api/video_codecs/video_encoder.h" >+#include "api/video_codecs/video_encoder_config.h" >+ >+namespace webrtc { >+ >+// TODO(nisse): Move full declaration to api/. >+class VideoBitrateAllocationObserver; >+ >+// This interface represents a class responsible for creating and driving the >+// encoder(s) for a single video stream. It is also responsible for adaptation >+// decisions related to video quality, requesting reduced frame rate or >+// resolution from the VideoSource when needed. >+// TODO(bugs.webrtc.org/8830): This interface is under development. Changes >+// under consideration include: >+// >+// 1. Taking out responsibility for adaptation decisions, instead only reporting >+// per-frame measurements to the decision maker. >+// >+// 2. Moving responsibility for simulcast and for software fallback into this >+// class. >+class VideoStreamEncoderInterface : public rtc::VideoSinkInterface<VideoFrame> { >+ public: >+ // Interface for receiving encoded video frames and notifications about >+ // configuration changes. >+ class EncoderSink : public EncodedImageCallback { >+ public: >+ virtual void OnEncoderConfigurationChanged( >+ std::vector<VideoStream> streams, >+ int min_transmit_bitrate_bps) = 0; >+ }; >+ >+ // Sets the source that will provide video frames to the VideoStreamEncoder's >+ // OnFrame method. |degradation_preference| control whether or not resolution >+ // or frame rate may be reduced. The VideoStreamEncoder registers itself with >+ // |source|, and signals adaptation decisions to the source in the form of >+ // VideoSinkWants. >+ // TODO(nisse): When adaptation logic is extracted from this class, >+ // it no longer needs to know the source. >+ virtual void SetSource( >+ rtc::VideoSourceInterface<VideoFrame>* source, >+ const DegradationPreference& degradation_preference) = 0; >+ >+ // Sets the |sink| that gets the encoded frames. |rotation_applied| means >+ // that the source must support rotation. Only set |rotation_applied| if the >+ // remote side does not support the rotation extension. >+ virtual void SetSink(EncoderSink* sink, bool rotation_applied) = 0; >+ >+ // Sets an initial bitrate, later overriden by OnBitrateUpdated. Mainly >+ // affects the resolution of the initial key frame: If incoming frames are >+ // larger than reasonable for the start bitrate, and scaling is enabled, >+ // VideoStreamEncoder asks the source to scale down and drops a few initial >+ // frames. >+ // TODO(nisse): This is a poor interface, and mixes bandwidth estimation and >+ // codec configuration in an undesired way. For the actual send bandwidth, we >+ // should always be somewhat conservative, but we may nevertheless want to let >+ // the application configure a more optimistic quality for the initial >+ // resolution. Should be replaced by a construction time setting. >+ virtual void SetStartBitrate(int start_bitrate_bps) = 0; >+ >+ // Request a key frame. Used for signalling from the remote receiver. >+ virtual void SendKeyFrame() = 0; >+ >+ // Set the currently estimated network properties. A |bitrate_bps| >+ // of zero pauses the encoder. >+ virtual void OnBitrateUpdated(uint32_t bitrate_bps, >+ uint8_t fraction_lost, >+ int64_t round_trip_time_ms) = 0; >+ >+ // Register observer for the bitrate allocation between the temporal >+ // and spatial layers. >+ virtual void SetBitrateAllocationObserver( >+ VideoBitrateAllocationObserver* bitrate_observer) = 0; >+ >+ // Creates and configures an encoder with the given |config|. The >+ // |max_data_payload_length| is used to support single NAL unit >+ // packetization for H.264. >+ virtual void ConfigureEncoder(VideoEncoderConfig config, >+ size_t max_data_payload_length) = 0; >+ >+ // Permanently stop encoding. After this method has returned, it is >+ // guaranteed that no encoded frames will be delivered to the sink. >+ virtual void Stop() = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_STREAM_ENCODER_INTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_observer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_observer.h >new file mode 100644 >index 00000000000..ac5c8a1f5be >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_observer.h >@@ -0,0 +1,94 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_ >+#define API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_ >+ >+#include <vector> >+ >+#include "absl/types/optional.h" >+#include "api/video_codecs/video_encoder.h" >+#include "api/video_codecs/video_encoder_config.h" >+ >+namespace webrtc { >+ >+// TODO(nisse): Used for the OnSendEncodedImage callback below. The callback >+// wants metadata such as size, encode timing, qp, but doesn't need actual >+// encoded data. So use some other type to represent that. >+class EncodedImage; >+ >+// Broken out into a base class, with public inheritance below, only to ease >+// unit testing of the internal class OveruseFrameDetector. >+class CpuOveruseMetricsObserver { >+ public: >+ virtual ~CpuOveruseMetricsObserver() = default; >+ virtual void OnEncodedFrameTimeMeasured(int encode_duration_ms, >+ int encode_usage_percent) = 0; >+}; >+ >+class VideoStreamEncoderObserver : public CpuOveruseMetricsObserver { >+ public: >+ // Number of resolution and framerate reductions (unset if disabled). >+ struct AdaptationSteps { >+ absl::optional<int> num_resolution_reductions = 0; >+ absl::optional<int> num_framerate_reductions = 0; >+ }; >+ >+ // TODO(nisse): There are too many enums to represent this. Besides >+ // this one, see AdaptationObserverInterface::AdaptReason and >+ // WebRtcVideoChannel::AdaptReason. >+ enum class AdaptationReason { >+ kNone, // Used for reset of counters. >+ kCpu, >+ kQuality, >+ }; >+ >+ // TODO(nisse): Duplicates enum EncodedImageCallback::DropReason. >+ enum class DropReason { >+ kSource, >+ kEncoderQueue, >+ kEncoder, >+ kMediaOptimization >+ }; >+ >+ virtual ~VideoStreamEncoderObserver() = default; >+ >+ virtual void OnIncomingFrame(int width, int height) = 0; >+ >+ // TODO(nisse): Merge into one callback per encoded frame. >+ using CpuOveruseMetricsObserver::OnEncodedFrameTimeMeasured; >+ virtual void OnSendEncodedImage(const EncodedImage& encoded_image, >+ const CodecSpecificInfo* codec_info) = 0; >+ >+ virtual void OnFrameDropped(DropReason reason) = 0; >+ >+ // Used to indicate change in content type, which may require a change in >+ // how stats are collected and set the configured preferred media bitrate. >+ virtual void OnEncoderReconfigured( >+ const VideoEncoderConfig& encoder_config, >+ const std::vector<VideoStream>& streams) = 0; >+ >+ virtual void OnAdaptationChanged(AdaptationReason reason, >+ const AdaptationSteps& cpu_steps, >+ const AdaptationSteps& quality_steps) = 0; >+ virtual void OnMinPixelLimitReached() = 0; >+ virtual void OnInitialQualityResolutionAdaptDown() = 0; >+ >+ virtual void OnSuspendChange(bool is_suspended) = 0; >+ >+ // TODO(nisse): VideoStreamEncoder wants to query the stats, which makes this >+ // not a pure observer. GetInputFrameRate is needed for the cpu adaptation, so >+ // can be deleted if that responsibility is moved out to a VideoStreamAdaptor >+ // class. >+ virtual int GetInputFrameRate() const = 0; >+}; >+ >+} // namespace webrtc >+#endif // API_VIDEO_VIDEO_STREAM_ENCODER_OBSERVER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_settings.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_settings.h >new file mode 100644 >index 00000000000..b67f33c982d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_stream_encoder_settings.h >@@ -0,0 +1,31 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_ >+#define API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_ >+ >+#include "api/video_codecs/video_encoder_factory.h" >+ >+namespace webrtc { >+ >+struct VideoStreamEncoderSettings { >+ VideoStreamEncoderSettings() = default; >+ >+ // Enables the new method to estimate the cpu load from encoding, used for >+ // cpu adaptation. >+ bool experiment_cpu_load_estimator = false; >+ >+ // Ownership stays with WebrtcVideoEngine (delegated from PeerConnection). >+ VideoEncoderFactory* encoder_factory = nullptr; >+}; >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_VIDEO_STREAM_ENCODER_SETTINGS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.cc >index 3ccbe4eae5b..40de011f0cc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.cc >@@ -10,7 +10,7 @@ > > #include "api/video/video_timing.h" > >-#include <sstream> >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > >@@ -28,7 +28,7 @@ TimingFrameInfo::TimingFrameInfo() > decode_start_ms(-1), > decode_finish_ms(-1), > render_time_ms(-1), >- flags(TimingFrameFlags::kDefault) {} >+ flags(VideoSendTiming::kNotTriggered) {} > > int64_t TimingFrameInfo::EndToEndDelay() const { > return capture_time_ms >= 0 ? decode_finish_ms - capture_time_ms : -1; >@@ -48,31 +48,34 @@ bool TimingFrameInfo::operator<=(const TimingFrameInfo& other) const { > } > > bool TimingFrameInfo::IsOutlier() const { >- return !IsInvalid() && (flags & TimingFrameFlags::kTriggeredBySize); >+ return !IsInvalid() && (flags & VideoSendTiming::kTriggeredBySize); > } > > bool TimingFrameInfo::IsTimerTriggered() const { >- return !IsInvalid() && (flags & TimingFrameFlags::kTriggeredByTimer); >+ return !IsInvalid() && (flags & VideoSendTiming::kTriggeredByTimer); > } > > bool TimingFrameInfo::IsInvalid() const { >- return flags == TimingFrameFlags::kInvalid; >+ return flags == VideoSendTiming::kInvalid; > } > > std::string TimingFrameInfo::ToString() const { >- std::stringstream out; > if (IsInvalid()) { >- out << ""; >- } else { >- out << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms >- << ',' << encode_finish_ms << ',' << packetization_finish_ms << ',' >- << pacer_exit_ms << ',' << network_timestamp_ms << ',' >- << network2_timestamp_ms << ',' << receive_start_ms << ',' >- << receive_finish_ms << ',' << decode_start_ms << ',' >- << decode_finish_ms << ',' << render_time_ms << ',' >- << IsOutlier() << ',' << IsTimerTriggered(); >+ return ""; > } >- return out.str(); >+ >+ char buf[1024]; >+ rtc::SimpleStringBuilder sb(buf); >+ >+ sb << rtp_timestamp << ',' << capture_time_ms << ',' << encode_start_ms << ',' >+ << encode_finish_ms << ',' << packetization_finish_ms << ',' >+ << pacer_exit_ms << ',' << network_timestamp_ms << ',' >+ << network2_timestamp_ms << ',' << receive_start_ms << ',' >+ << receive_finish_ms << ',' << decode_start_ms << ',' << decode_finish_ms >+ << ',' << render_time_ms << ',' << IsOutlier() << ',' >+ << IsTimerTriggered(); >+ >+ return sb.str(); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.h >index ab8cd99136f..e787a4541f4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video/video_timing.h >@@ -21,20 +21,17 @@ > > namespace webrtc { > >-enum TimingFrameFlags : uint8_t { >- kNotTriggered = 0, // Timing info valid, but not to be transmitted. >- // Used on send-side only. >- // TODO(ilnik): Delete compatibility alias. >- // Used to be sent over the wire, for the old protocol. >- kDefault = 0, // Old name, for API compatibility. >- kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer. >- kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size. >- kInvalid = std::numeric_limits<uint8_t>::max() // Invalid, ignore! >-}; >- > // Video timing timestamps in ms counted from capture_time_ms of a frame. > // This structure represents data sent in video-timing RTP header extension. > struct VideoSendTiming { >+ enum TimingFrameFlags : uint8_t { >+ kNotTriggered = 0, // Timing info valid, but not to be transmitted. >+ // Used on send-side only. >+ kTriggeredByTimer = 1 << 0, // Frame marked for tracing by periodic timer. >+ kTriggeredBySize = 1 << 1, // Frame marked for tracing due to size. >+ kInvalid = std::numeric_limits<uint8_t>::max() // Invalid, ignore! >+ }; >+ > // Offsets of the fields in the RTP header extension, counting from the first > // byte after the one-byte header. > static constexpr uint8_t kFlagsOffset = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/BUILD.gn >index 5da89807561..e523191082b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/BUILD.gn >@@ -15,21 +15,95 @@ if (is_android) { > rtc_source_set("video_codecs_api") { > visibility = [ "*" ] > sources = [ >+ "sdp_video_format.cc", > "sdp_video_format.h", >+ "video_codec.cc", >+ "video_codec.h", >+ "video_decoder.cc", > "video_decoder.h", > "video_decoder_factory.h", > "video_encoder.cc", > "video_encoder.h", >+ "video_encoder_config.cc", >+ "video_encoder_config.h", > "video_encoder_factory.h", > ] > > deps = [ >- "..:optional", >- "..:video_frame_api", > "../..:webrtc_common", >- "../../:typedefs", > "../../common_video", > "../../rtc_base:checks", > "../../rtc_base:rtc_base_approved", >+ "../video:video_bitrate_allocation", >+ "../video:video_frame", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_static_library("builtin_video_decoder_factory") { >+ visibility = [ "*" ] >+ allow_poison = [ >+ "audio_codecs", # TODO(bugs.webrtc.org/8396): Remove. >+ "software_video_codecs", >+ ] >+ sources = [ >+ "builtin_video_decoder_factory.cc", >+ "builtin_video_decoder_factory.h", >+ ] >+ >+ deps = [ >+ ":video_codecs_api", >+ "../../media:rtc_internal_video_codecs", >+ "../../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_static_library("builtin_video_encoder_factory") { >+ visibility = [ "*" ] >+ allow_poison = [ >+ "audio_codecs", # TODO(bugs.webrtc.org/8396): Remove. >+ "software_video_codecs", >+ ] >+ sources = [ >+ "builtin_video_encoder_factory.cc", >+ "builtin_video_encoder_factory.h", >+ ] >+ >+ deps = [ >+ ":video_codecs_api", >+ "../../media:rtc_internal_video_codecs", >+ "../../media:rtc_media_base", >+ "../../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_static_library("rtc_software_fallback_wrappers") { >+ visibility = [ "*" ] >+ >+ sources = [ >+ "video_decoder_software_fallback_wrapper.cc", >+ "video_decoder_software_fallback_wrapper.h", >+ "video_encoder_software_fallback_wrapper.cc", >+ "video_encoder_software_fallback_wrapper.h", >+ ] >+ >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ >+ deps = [ >+ ":video_codecs_api", >+ "../../media:rtc_h264_profile_id", >+ "../../media:rtc_media_base", >+ "../../modules/video_coding:video_codec_interface", >+ "../../rtc_base:checks", >+ "../../rtc_base:rtc_base_approved", >+ "../../rtc_base/system:fallthrough", >+ "../../system_wrappers:field_trial_api", >+ "../video:video_bitrate_allocation", >+ "//third_party/abseil-cpp/absl/memory", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.cc >new file mode 100644 >index 00000000000..883c1ebd2e4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.cc >@@ -0,0 +1,22 @@ >+/* >+ * Copyright (c) 2018 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 "api/video_codecs/builtin_video_decoder_factory.h" >+ >+#include "absl/memory/memory.h" >+#include "media/engine/internaldecoderfactory.h" >+ >+namespace webrtc { >+ >+std::unique_ptr<VideoDecoderFactory> CreateBuiltinVideoDecoderFactory() { >+ return absl::make_unique<InternalDecoderFactory>(); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.h >new file mode 100644 >index 00000000000..1f8e75c9ae7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_decoder_factory.h >@@ -0,0 +1,25 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_CODECS_BUILTIN_VIDEO_DECODER_FACTORY_H_ >+#define API_VIDEO_CODECS_BUILTIN_VIDEO_DECODER_FACTORY_H_ >+ >+#include <memory> >+ >+#include "api/video_codecs/video_decoder_factory.h" >+ >+namespace webrtc { >+ >+// Creates a new factory that can create the built-in types of video decoders. >+std::unique_ptr<VideoDecoderFactory> CreateBuiltinVideoDecoderFactory(); >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_CODECS_BUILTIN_VIDEO_DECODER_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.cc >new file mode 100644 >index 00000000000..ca389b99e3b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.cc >@@ -0,0 +1,85 @@ >+/* >+ * Copyright (c) 2018 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 "api/video_codecs/builtin_video_encoder_factory.h" >+ >+#include <vector> >+ >+#include "absl/memory/memory.h" >+#include "api/video_codecs/sdp_video_format.h" >+#include "media/base/codec.h" >+#include "media/base/mediaconstants.h" >+#include "media/engine/internalencoderfactory.h" >+#include "media/engine/vp8_encoder_simulcast_proxy.h" >+ >+namespace webrtc { >+ >+namespace { >+ >+bool IsFormatSupported(const std::vector<SdpVideoFormat>& supported_formats, >+ const SdpVideoFormat& format) { >+ for (const SdpVideoFormat& supported_format : supported_formats) { >+ if (cricket::IsSameCodec(format.name, format.parameters, >+ supported_format.name, >+ supported_format.parameters)) { >+ return true; >+ } >+ } >+ return false; >+} >+ >+// This class wraps the internal factory and adds simulcast. >+class BuiltinVideoEncoderFactory : public VideoEncoderFactory { >+ public: >+ BuiltinVideoEncoderFactory() >+ : internal_encoder_factory_(new InternalEncoderFactory()) {} >+ >+ VideoEncoderFactory::CodecInfo QueryVideoEncoder( >+ const SdpVideoFormat& format) const override { >+ // Format must be one of the internal formats. >+ RTC_DCHECK(IsFormatSupported( >+ internal_encoder_factory_->GetSupportedFormats(), format)); >+ VideoEncoderFactory::CodecInfo info; >+ info.has_internal_source = false; >+ info.is_hardware_accelerated = false; >+ return info; >+ } >+ >+ std::unique_ptr<VideoEncoder> CreateVideoEncoder( >+ const SdpVideoFormat& format) override { >+ // Try creating internal encoder. >+ std::unique_ptr<VideoEncoder> internal_encoder; >+ if (IsFormatSupported(internal_encoder_factory_->GetSupportedFormats(), >+ format)) { >+ internal_encoder = >+ cricket::CodecNamesEq(format.name.c_str(), cricket::kVp8CodecName) >+ ? absl::make_unique<VP8EncoderSimulcastProxy>( >+ internal_encoder_factory_.get(), format) >+ : internal_encoder_factory_->CreateVideoEncoder(format); >+ } >+ >+ return internal_encoder; >+ } >+ >+ std::vector<SdpVideoFormat> GetSupportedFormats() const override { >+ return internal_encoder_factory_->GetSupportedFormats(); >+ } >+ >+ private: >+ const std::unique_ptr<VideoEncoderFactory> internal_encoder_factory_; >+}; >+ >+} // namespace >+ >+std::unique_ptr<VideoEncoderFactory> CreateBuiltinVideoEncoderFactory() { >+ return absl::make_unique<BuiltinVideoEncoderFactory>(); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.h >new file mode 100644 >index 00000000000..6a6618fb327 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/builtin_video_encoder_factory.h >@@ -0,0 +1,26 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_CODECS_BUILTIN_VIDEO_ENCODER_FACTORY_H_ >+#define API_VIDEO_CODECS_BUILTIN_VIDEO_ENCODER_FACTORY_H_ >+ >+#include <memory> >+ >+#include "api/video_codecs/video_encoder_factory.h" >+ >+namespace webrtc { >+ >+// Creates a new factory that can create the built-in types of video encoders. >+// The factory has simulcast support for VP8. >+std::unique_ptr<VideoEncoderFactory> CreateBuiltinVideoEncoderFactory(); >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_CODECS_BUILTIN_VIDEO_ENCODER_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.cc >new file mode 100644 >index 00000000000..909904c19c0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.cc >@@ -0,0 +1,32 @@ >+/* >+ * Copyright (c) 2018 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 "api/video_codecs/sdp_video_format.h" >+ >+namespace webrtc { >+ >+SdpVideoFormat::SdpVideoFormat(const std::string& name) : name(name) {} >+ >+SdpVideoFormat::SdpVideoFormat(const std::string& name, >+ const Parameters& parameters) >+ : name(name), parameters(parameters) {} >+ >+SdpVideoFormat::SdpVideoFormat(const SdpVideoFormat&) = default; >+SdpVideoFormat::SdpVideoFormat(SdpVideoFormat&&) = default; >+SdpVideoFormat& SdpVideoFormat::operator=(const SdpVideoFormat&) = default; >+SdpVideoFormat& SdpVideoFormat::operator=(SdpVideoFormat&&) = default; >+ >+SdpVideoFormat::~SdpVideoFormat() = default; >+ >+bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b) { >+ return a.name == b.name && a.parameters == b.parameters; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.h >index 542353aea7e..c25b857fde7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/sdp_video_format.h >@@ -21,14 +21,16 @@ namespace webrtc { > struct SdpVideoFormat { > using Parameters = std::map<std::string, std::string>; > >- explicit SdpVideoFormat(const std::string& name) : name(name) {} >- SdpVideoFormat(const std::string& name, const Parameters& parameters) >- : name(name), parameters(parameters) {} >+ explicit SdpVideoFormat(const std::string& name); >+ SdpVideoFormat(const std::string& name, const Parameters& parameters); >+ SdpVideoFormat(const SdpVideoFormat&); >+ SdpVideoFormat(SdpVideoFormat&&); >+ SdpVideoFormat& operator=(const SdpVideoFormat&); >+ SdpVideoFormat& operator=(SdpVideoFormat&&); > >- friend bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b) { >- return a.name == b.name && a.parameters == b.parameters; >- } >+ ~SdpVideoFormat(); > >+ friend bool operator==(const SdpVideoFormat& a, const SdpVideoFormat& b); > friend bool operator!=(const SdpVideoFormat& a, const SdpVideoFormat& b) { > return !(a == b); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/BUILD.gn >new file mode 100644 >index 00000000000..18943095f56 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/BUILD.gn >@@ -0,0 +1,37 @@ >+# Copyright (c) 2018 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. >+ >+import("../../../webrtc.gni") >+ >+if (rtc_include_tests) { >+ rtc_source_set("video_codecs_api_unittests") { >+ testonly = true >+ sources = [ >+ "builtin_video_encoder_factory_unittest.cc", >+ "video_decoder_software_fallback_wrapper_unittest.cc", >+ "video_encoder_software_fallback_wrapper_unittest.cc", >+ ] >+ >+ deps = [ >+ "..:builtin_video_encoder_factory", >+ "..:rtc_software_fallback_wrappers", >+ "..:video_codecs_api", >+ "../../../modules/video_coding:video_codec_interface", >+ "../../../modules/video_coding:video_coding_utility", >+ "../../../modules/video_coding:webrtc_vp8", >+ "../../../rtc_base:checks", >+ "../../../rtc_base:rtc_base_tests_utils", >+ "../../../system_wrappers:metrics_default", >+ "../../../test:field_trial", >+ "../../../test:test_support", >+ "../../video:video_bitrate_allocation", >+ "../../video:video_frame_i420", >+ "//testing/gtest", >+ ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/builtin_video_encoder_factory_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/builtin_video_encoder_factory_unittest.cc >new file mode 100644 >index 00000000000..73957c999f0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/builtin_video_encoder_factory_unittest.cc >@@ -0,0 +1,37 @@ >+/* >+ * Copyright (c) 2018 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 "api/video_codecs/builtin_video_encoder_factory.h" >+ >+#include <memory> >+ >+#include "api/video_codecs/sdp_video_format.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+ >+TEST(BuiltinVideoEncoderFactoryTest, AnnouncesVp9AccordingToBuildFlags) { >+ std::unique_ptr<VideoEncoderFactory> factory = >+ CreateBuiltinVideoEncoderFactory(); >+ bool claims_vp9_support = false; >+ for (const SdpVideoFormat& format : factory->GetSupportedFormats()) { >+ if (format.name == "VP9") { >+ claims_vp9_support = true; >+ break; >+ } >+ } >+#if defined(RTC_DISABLE_VP9) >+ EXPECT_FALSE(claims_vp9_support); >+#else >+ EXPECT_TRUE(claims_vp9_support); >+#endif // defined(RTC_DISABLE_VP9) >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_decoder_software_fallback_wrapper_unittest.cc >similarity index 62% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_decoder_software_fallback_wrapper_unittest.cc >index 367527eff79..d2d0e2b62b2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_decoder_software_fallback_wrapper_unittest.cc >@@ -8,7 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "media/engine/videodecodersoftwarefallbackwrapper.h" >+#include "api/video_codecs/video_decoder_software_fallback_wrapper.h" > #include "api/video_codecs/video_decoder.h" > #include "modules/video_coding/codecs/vp8/include/vp8.h" > #include "modules/video_coding/include/video_error_codes.h" >@@ -21,8 +21,9 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { > protected: > VideoDecoderSoftwareFallbackWrapperTest() > : fake_decoder_(new CountingFakeDecoder()), >- fallback_wrapper_(std::unique_ptr<VideoDecoder>(VP8Decoder::Create()), >- std::unique_ptr<VideoDecoder>(fake_decoder_)) {} >+ fallback_wrapper_(CreateVideoDecoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoDecoder>(VP8Decoder::Create()), >+ std::unique_ptr<VideoDecoder>(fake_decoder_))) {} > > class CountingFakeDecoder : public VideoDecoder { > public: >@@ -34,7 +35,6 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { > > int32_t Decode(const EncodedImage& input_image, > bool missing_frames, >- const RTPFragmentationHeader* fragmentation, > const CodecSpecificInfo* codec_specific_info, > int64_t render_time_ms) override { > ++decode_count_; >@@ -52,9 +52,7 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { > return WEBRTC_VIDEO_CODEC_OK; > } > >- const char* ImplementationName() const override { >- return "fake-decoder"; >- } >+ const char* ImplementationName() const override { return "fake-decoder"; } > > int init_decode_count_ = 0; > int decode_count_ = 0; >@@ -66,17 +64,17 @@ class VideoDecoderSoftwareFallbackWrapperTest : public ::testing::Test { > }; > // |fake_decoder_| is owned and released by |fallback_wrapper_|. > CountingFakeDecoder* fake_decoder_; >- VideoDecoderSoftwareFallbackWrapper fallback_wrapper_; >+ std::unique_ptr<VideoDecoder> fallback_wrapper_; > }; > > TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) { > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >+ fallback_wrapper_->InitDecode(&codec, 2); > EXPECT_EQ(1, fake_decoder_->init_decode_count_); > > EncodedImage encoded_image; > encoded_image._frameType = kVideoFrameKey; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); > EXPECT_EQ(1, fake_decoder_->init_decode_count_) > << "Initialized decoder should not be reinitialized."; > EXPECT_EQ(1, fake_decoder_->decode_count_); >@@ -85,16 +83,15 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, InitializesDecoder) { > TEST_F(VideoDecoderSoftwareFallbackWrapperTest, > UsesFallbackDecoderAfterAnyInitDecodeFailure) { > VideoCodec codec = {}; >- fake_decoder_->init_decode_return_code_ = >- WEBRTC_VIDEO_CODEC_UNINITIALIZED; >- fallback_wrapper_.InitDecode(&codec, 2); >+ fake_decoder_->init_decode_return_code_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED; >+ fallback_wrapper_->InitDecode(&codec, 2); > EXPECT_EQ(1, fake_decoder_->init_decode_count_); > > EncodedImage encoded_image; > encoded_image._frameType = kVideoFrameKey; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- EXPECT_EQ(2, fake_decoder_->init_decode_count_) >- << "Should have attempted reinitializing the fallback decoder on " >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); >+ EXPECT_EQ(1, fake_decoder_->init_decode_count_) >+ << "Should not have attempted reinitializing the fallback decoder on " > "keyframe."; > // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW > // decoder. >@@ -102,62 +99,70 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, > << "Decoder used even though no InitDecode had succeeded."; > } > >-TEST_F(VideoDecoderSoftwareFallbackWrapperTest, >- CanRecoverFromSoftwareFallback) { >+TEST_F(VideoDecoderSoftwareFallbackWrapperTest, IsSoftwareFallbackSticky) { > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >- // Unfortunately faking a VP8 frame is hard. Rely on no Decode -> using SW >- // decoder. >+ fallback_wrapper_->InitDecode(&codec, 2); >+ > fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; > EncodedImage encoded_image; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); > EXPECT_EQ(1, fake_decoder_->decode_count_); > >- // Fail -> fake_decoder shouldn't be used anymore. >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- EXPECT_EQ(1, fake_decoder_->decode_count_) >- << "Decoder used even though fallback should be active."; >- >- // Should be able to recover on a keyframe. >+ // Software fallback should be sticky, fake_decoder_ shouldn't be used. > encoded_image._frameType = kVideoFrameKey; >- fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- EXPECT_EQ(2, fake_decoder_->decode_count_) >- << "Wrapper did not try to decode a keyframe using registered decoder."; >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); >+ EXPECT_EQ(1, fake_decoder_->decode_count_) >+ << "Decoder shouldn't be used after failure."; > >- encoded_image._frameType = kVideoFrameDelta; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- EXPECT_EQ(3, fake_decoder_->decode_count_) >- << "Decoder not used on future delta frames."; >+ // fake_decoder_ should have only been initialized once during the test. >+ EXPECT_EQ(1, fake_decoder_->init_decode_count_); > } > > TEST_F(VideoDecoderSoftwareFallbackWrapperTest, DoesNotFallbackOnEveryError) { > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >+ fallback_wrapper_->InitDecode(&codec, 2); > fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR; > EncodedImage encoded_image; >- EXPECT_EQ( >- fake_decoder_->decode_return_code_, >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1)); >+ EXPECT_EQ(fake_decoder_->decode_return_code_, >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1)); > EXPECT_EQ(1, fake_decoder_->decode_count_); > >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); > EXPECT_EQ(2, fake_decoder_->decode_count_) > << "Decoder should be active even though previous decode failed."; > } > >+TEST_F(VideoDecoderSoftwareFallbackWrapperTest, UsesHwDecoderAfterReinit) { >+ VideoCodec codec = {}; >+ fallback_wrapper_->InitDecode(&codec, 2); >+ >+ fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; >+ EncodedImage encoded_image; >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); >+ EXPECT_EQ(1, fake_decoder_->decode_count_); >+ >+ fallback_wrapper_->Release(); >+ fallback_wrapper_->InitDecode(&codec, 2); >+ >+ fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK; >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); >+ EXPECT_EQ(2, fake_decoder_->decode_count_) >+ << "Should not be using fallback after reinit."; >+} >+ > TEST_F(VideoDecoderSoftwareFallbackWrapperTest, ForwardsReleaseCall) { > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >- fallback_wrapper_.Release(); >+ fallback_wrapper_->InitDecode(&codec, 2); >+ fallback_wrapper_->Release(); > EXPECT_EQ(1, fake_decoder_->release_count_); > >+ fallback_wrapper_->InitDecode(&codec, 2); > fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; > EncodedImage encoded_image; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- EXPECT_EQ(1, fake_decoder_->release_count_) >- << "Decoder should not be released during fallback."; >- fallback_wrapper_.Release(); >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); >+ EXPECT_EQ(2, fake_decoder_->release_count_) >+ << "Decoder should be released during fallback."; >+ fallback_wrapper_->Release(); > EXPECT_EQ(2, fake_decoder_->release_count_); > } > >@@ -167,43 +172,37 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest, > ForwardsRegisterDecodeCompleteCallback) { > class FakeDecodedImageCallback : public DecodedImageCallback { > int32_t Decoded(VideoFrame& decodedImage) override { return 0; } >- int32_t Decoded( >- webrtc::VideoFrame& decodedImage, int64_t decode_time_ms) override { >+ int32_t Decoded(webrtc::VideoFrame& decodedImage, >+ int64_t decode_time_ms) override { > RTC_NOTREACHED(); > return -1; > } > void Decoded(webrtc::VideoFrame& decodedImage, >- rtc::Optional<int32_t> decode_time_ms, >- rtc::Optional<uint8_t> qp) override { >+ absl::optional<int32_t> decode_time_ms, >+ absl::optional<uint8_t> qp) override { > RTC_NOTREACHED(); > } >- } callback, callback2; >+ } callback; > > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >- fallback_wrapper_.RegisterDecodeCompleteCallback(&callback); >+ fallback_wrapper_->InitDecode(&codec, 2); >+ fallback_wrapper_->RegisterDecodeCompleteCallback(&callback); > EXPECT_EQ(&callback, fake_decoder_->decode_complete_callback_); >- >- fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; >- EncodedImage encoded_image; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >- fallback_wrapper_.RegisterDecodeCompleteCallback(&callback2); >- EXPECT_EQ(&callback2, fake_decoder_->decode_complete_callback_); > } > > TEST_F(VideoDecoderSoftwareFallbackWrapperTest, > ReportsFallbackImplementationName) { > VideoCodec codec = {}; >- fallback_wrapper_.InitDecode(&codec, 2); >+ fallback_wrapper_->InitDecode(&codec, 2); > > fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; > EncodedImage encoded_image; >- fallback_wrapper_.Decode(encoded_image, false, nullptr, nullptr, -1); >+ fallback_wrapper_->Decode(encoded_image, false, nullptr, -1); > // Hard coded expected value since libvpx is the software implementation name > // for VP8. Change accordingly if the underlying implementation does. > EXPECT_STREQ("libvpx (fallback from: fake-decoder)", >- fallback_wrapper_.ImplementationName()); >- fallback_wrapper_.Release(); >+ fallback_wrapper_->ImplementationName()); >+ fallback_wrapper_->Release(); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc >similarity index 82% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc >index e39b02f71ce..a1a43b42027 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/test/video_encoder_software_fallback_wrapper_unittest.cc >@@ -8,16 +8,17 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "media/engine/videoencodersoftwarefallbackwrapper.h" >+#include "api/video_codecs/video_encoder_software_fallback_wrapper.h" > > #include <utility> > > #include "api/video/i420_buffer.h" >+#include "api/video/video_bitrate_allocation.h" > #include "modules/video_coding/codecs/vp8/include/vp8.h" >-#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h" > #include "modules/video_coding/codecs/vp8/temporal_layers.h" > #include "modules/video_coding/include/video_codec_interface.h" > #include "modules/video_coding/include/video_error_codes.h" >+#include "modules/video_coding/utility/simulcast_rate_allocator.h" > #include "rtc_base/checks.h" > #include "rtc_base/fakeclock.h" > #include "test/field_trial.h" >@@ -43,8 +44,9 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { > const std::string& field_trials) > : override_field_trials_(field_trials), > fake_encoder_(new CountingFakeEncoder()), >- fallback_wrapper_(std::unique_ptr<VideoEncoder>(VP8Encoder::Create()), >- std::unique_ptr<VideoEncoder>(fake_encoder_)) {} >+ fallback_wrapper_(CreateVideoEncoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoEncoder>(VP8Encoder::Create()), >+ std::unique_ptr<VideoEncoder>(fake_encoder_))) {} > > class CountingFakeEncoder : public VideoEncoder { > public: >@@ -84,7 +86,7 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { > return WEBRTC_VIDEO_CODEC_OK; > } > >- int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation, >+ int32_t SetRateAllocation(const VideoBitrateAllocation& bitrate_allocation, > uint32_t framerate) override { > ++set_rates_count_; > return WEBRTC_VIDEO_CODEC_OK; >@@ -95,12 +97,10 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { > return supports_native_handle_; > } > >- const char* ImplementationName() const override { >- return "fake-encoder"; >- } >+ const char* ImplementationName() const override { return "fake-encoder"; } > > VideoEncoder::ScalingSettings GetScalingSettings() const override { >- return VideoEncoder::ScalingSettings(true, kLowThreshold, kHighThreshold); >+ return VideoEncoder::ScalingSettings(kLowThreshold, kHighThreshold); > } > > int init_encode_count_ = 0; >@@ -141,7 +141,7 @@ class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test { > FakeEncodedImageCallback callback_; > // |fake_encoder_| is owned and released by |fallback_wrapper_|. > CountingFakeEncoder* fake_encoder_; >- VideoEncoderSoftwareFallbackWrapper fallback_wrapper_; >+ std::unique_ptr<VideoEncoder> fallback_wrapper_; > VideoCodec codec_ = {}; > std::unique_ptr<VideoFrame> frame_; > std::unique_ptr<SimulcastRateAllocator> rate_allocator_; >@@ -157,12 +157,13 @@ void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame(int expected_ret) { > I420Buffer::SetBlack(buffer); > std::vector<FrameType> types(1, kVideoFrameKey); > >- frame_.reset(new VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0)); >- EXPECT_EQ(expected_ret, fallback_wrapper_.Encode(*frame_, nullptr, &types)); >+ frame_.reset( >+ new VideoFrame(buffer, webrtc::kVideoRotation_0, 0 /* timestamp_us */)); >+ EXPECT_EQ(expected_ret, fallback_wrapper_->Encode(*frame_, nullptr, &types)); > } > > void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() { >- fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); >+ fallback_wrapper_->RegisterEncodeCompleteCallback(&callback_); > EXPECT_EQ(&callback_, fake_encoder_->encode_complete_callback_); > > // Register with failing fake encoder. Should succeed with VP8 fallback. >@@ -171,18 +172,14 @@ void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() { > codec_.width = kWidth; > codec_.height = kHeight; > codec_.VP8()->numberOfTemporalLayers = 1; >- std::unique_ptr<TemporalLayersFactory> tl_factory( >- new TemporalLayersFactory()); >- codec_.VP8()->tl_factory = tl_factory.get(); >- rate_allocator_.reset( >- new SimulcastRateAllocator(codec_, std::move(tl_factory))); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); > > fake_encoder_->init_encode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR; > EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, >- fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize)); >+ fallback_wrapper_->InitEncode(&codec_, kNumCores, kMaxPayloadSize)); > EXPECT_EQ( > WEBRTC_VIDEO_CODEC_OK, >- fallback_wrapper_.SetRateAllocation( >+ fallback_wrapper_->SetRateAllocation( > rate_allocator_->GetAllocation(300000, kFramerate), kFramerate)); > > int callback_count = callback_.callback_count_; >@@ -193,21 +190,17 @@ void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() { > } > > void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() { >- fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); >+ fallback_wrapper_->RegisterEncodeCompleteCallback(&callback_); > codec_.codecType = kVideoCodecVP8; > codec_.maxFramerate = kFramerate; > codec_.width = kWidth; > codec_.height = kHeight; > codec_.VP8()->numberOfTemporalLayers = 1; >- std::unique_ptr<TemporalLayersFactory> tl_factory( >- new TemporalLayersFactory()); >- codec_.VP8()->tl_factory = tl_factory.get(); >- rate_allocator_.reset( >- new SimulcastRateAllocator(codec_, std::move(tl_factory))); >- fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); >+ fallback_wrapper_->InitEncode(&codec_, 2, kMaxPayloadSize); > EXPECT_EQ( > WEBRTC_VIDEO_CODEC_OK, >- fallback_wrapper_.SetRateAllocation( >+ fallback_wrapper_->SetRateAllocation( > rate_allocator_->GetAllocation(300000, kFramerate), kFramerate)); > EXPECT_EQ(1, fake_encoder_->init_encode_count_); > >@@ -223,7 +216,7 @@ void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() { > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) { > VideoCodec codec = {}; >- fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize); >+ fallback_wrapper_->InitEncode(&codec, 2, kMaxPayloadSize); > EXPECT_EQ(1, fake_encoder_->init_encode_count_); > } > >@@ -237,7 +230,7 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EncodeRequestsFallback) { > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) { > UtilizeFallbackEncoder(); >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, >@@ -245,7 +238,7 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > EXPECT_EQ(0, fake_encoder_->release_count_); > UtilizeFallbackEncoder(); > EXPECT_EQ(1, fake_encoder_->release_count_); >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > // No extra release when the fallback is released. > EXPECT_EQ(1, fake_encoder_->release_count_); > } >@@ -257,7 +250,7 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > EncodeFrame(); > EXPECT_EQ(encode_count, fake_encoder_->encode_count_); > >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, >@@ -266,55 +259,55 @@ TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > // Registering an encode-complete callback should still work when fallback > // encoder is being used. > FakeEncodedImageCallback callback2; >- fallback_wrapper_.RegisterEncodeCompleteCallback(&callback2); >+ fallback_wrapper_->RegisterEncodeCompleteCallback(&callback2); > EXPECT_EQ(&callback2, fake_encoder_->encode_complete_callback_); > > // Encoding a frame using the fallback should arrive at the new callback. > std::vector<FrameType> types(1, kVideoFrameKey); > frame_->set_timestamp(frame_->timestamp() + 1000); > EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, >- fallback_wrapper_.Encode(*frame_, nullptr, &types)); >+ fallback_wrapper_->Encode(*frame_, nullptr, &types)); > >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > SetChannelParametersForwardedDuringFallback) { > UtilizeFallbackEncoder(); > EXPECT_EQ(0, fake_encoder_->set_channel_parameters_count_); >- fallback_wrapper_.SetChannelParameters(1, 1); >+ fallback_wrapper_->SetChannelParameters(1, 1); > EXPECT_EQ(1, fake_encoder_->set_channel_parameters_count_); >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > SetRatesForwardedDuringFallback) { > UtilizeFallbackEncoder(); > EXPECT_EQ(1, fake_encoder_->set_rates_count_); >- fallback_wrapper_.SetRateAllocation(BitrateAllocation(), 1); >+ fallback_wrapper_->SetRateAllocation(VideoBitrateAllocation(), 1); > EXPECT_EQ(2, fake_encoder_->set_rates_count_); >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > SupportsNativeHandleForwardedWithoutFallback) { >- fallback_wrapper_.SupportsNativeHandle(); >+ fallback_wrapper_->SupportsNativeHandle(); > EXPECT_EQ(1, fake_encoder_->supports_native_handle_count_); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, > SupportsNativeHandleNotForwardedDuringFallback) { > UtilizeFallbackEncoder(); >- fallback_wrapper_.SupportsNativeHandle(); >+ fallback_wrapper_->SupportsNativeHandle(); > EXPECT_EQ(0, fake_encoder_->supports_native_handle_count_); >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > TEST_F(VideoEncoderSoftwareFallbackWrapperTest, ReportsImplementationName) { > codec_.width = kWidth; > codec_.height = kHeight; >- fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); >- fallback_wrapper_.InitEncode(&codec_, kNumCores, kMaxPayloadSize); >+ fallback_wrapper_->RegisterEncodeCompleteCallback(&callback_); >+ fallback_wrapper_->InitEncode(&codec_, kNumCores, kMaxPayloadSize); > EncodeFrame(); > CheckLastEncoderName("fake-encoder"); > } >@@ -347,13 +340,11 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { > } > > void TearDown() override { >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release()); >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->Release()); > } > > void ConfigureVp8Codec() { >- fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_); >- std::unique_ptr<TemporalLayersFactory> tl_factory( >- new TemporalLayersFactory()); >+ fallback_wrapper_->RegisterEncodeCompleteCallback(&callback_); > codec_.codecType = kVideoCodecVP8; > codec_.maxFramerate = kFramerate; > codec_.width = kWidth; >@@ -361,21 +352,19 @@ class ForcedFallbackTest : public VideoEncoderSoftwareFallbackWrapperTest { > codec_.VP8()->numberOfTemporalLayers = 1; > codec_.VP8()->automaticResizeOn = true; > codec_.VP8()->frameDroppingOn = true; >- codec_.VP8()->tl_factory = tl_factory.get(); >- rate_allocator_.reset( >- new SimulcastRateAllocator(codec_, std::move(tl_factory))); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); > } > > void InitEncode(int width, int height) { > codec_.width = width; > codec_.height = height; >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.InitEncode( >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->InitEncode( > &codec_, kNumCores, kMaxPayloadSize)); > SetRateAllocation(kBitrateKbps); > } > > void SetRateAllocation(uint32_t bitrate_kbps) { >- EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRateAllocation( >+ EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_->SetRateAllocation( > rate_allocator_->GetAllocation( > bitrate_kbps * 1000, kFramerate), > kFramerate)); >@@ -500,8 +489,8 @@ TEST_F(ForcedFallbackTestDisabled, GetScaleSettings) { > EncodeFrameAndVerifyLastName("fake-encoder"); > > // Default min pixels per frame should be used. >- const auto settings = fallback_wrapper_.GetScalingSettings(); >- EXPECT_TRUE(settings.enabled); >+ const auto settings = fallback_wrapper_->GetScalingSettings(); >+ EXPECT_TRUE(settings.thresholds.has_value()); > EXPECT_EQ(kDefaultMinPixelsPerFrame, settings.min_pixels_per_frame); > } > >@@ -511,8 +500,7 @@ TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithNoFallback) { > EncodeFrameAndVerifyLastName("fake-encoder"); > > // Configured min pixels per frame should be used. >- const auto settings = fallback_wrapper_.GetScalingSettings(); >- EXPECT_TRUE(settings.enabled); >+ const auto settings = fallback_wrapper_->GetScalingSettings(); > EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame); > ASSERT_TRUE(settings.thresholds); > EXPECT_EQ(kLowThreshold, settings.thresholds->low); >@@ -525,8 +513,8 @@ TEST_F(ForcedFallbackTestEnabled, GetScaleSettingsWithFallback) { > EncodeFrameAndVerifyLastName("libvpx"); > > // Configured min pixels per frame should be used. >- const auto settings = fallback_wrapper_.GetScalingSettings(); >- EXPECT_TRUE(settings.enabled); >+ const auto settings = fallback_wrapper_->GetScalingSettings(); >+ EXPECT_TRUE(settings.thresholds.has_value()); > EXPECT_EQ(kMinPixelsPerFrame, settings.min_pixels_per_frame); > } > >@@ -537,8 +525,8 @@ TEST_F(ForcedFallbackTestEnabled, ScalingDisabledIfResizeOff) { > EncodeFrameAndVerifyLastName("libvpx"); > > // Should be disabled for automatic resize off. >- const auto settings = fallback_wrapper_.GetScalingSettings(); >- EXPECT_FALSE(settings.enabled); >+ const auto settings = fallback_wrapper_->GetScalingSettings(); >+ EXPECT_FALSE(settings.thresholds.has_value()); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.cc >new file mode 100644 >index 00000000000..d36535b3100 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.cc >@@ -0,0 +1,155 @@ >+/* >+ * 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 "api/video_codecs/video_codec.h" >+ >+#include <string.h> >+#include <algorithm> >+#include <limits> >+#include <string> >+#include <type_traits> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/strings/string_builder.h" >+#include "rtc_base/stringutils.h" >+ >+namespace webrtc { >+ >+bool VideoCodecVP8::operator==(const VideoCodecVP8& other) const { >+ return (complexity == other.complexity && >+ numberOfTemporalLayers == other.numberOfTemporalLayers && >+ denoisingOn == other.denoisingOn && >+ automaticResizeOn == other.automaticResizeOn && >+ frameDroppingOn == other.frameDroppingOn && >+ keyFrameInterval == other.keyFrameInterval); >+} >+ >+bool VideoCodecVP9::operator==(const VideoCodecVP9& other) const { >+ return (complexity == other.complexity && >+ numberOfTemporalLayers == other.numberOfTemporalLayers && >+ denoisingOn == other.denoisingOn && >+ frameDroppingOn == other.frameDroppingOn && >+ keyFrameInterval == other.keyFrameInterval && >+ adaptiveQpMode == other.adaptiveQpMode && >+ automaticResizeOn == other.automaticResizeOn && >+ numberOfSpatialLayers == other.numberOfSpatialLayers && >+ flexibleMode == other.flexibleMode); >+} >+ >+bool VideoCodecH264::operator==(const VideoCodecH264& other) const { >+ return (frameDroppingOn == other.frameDroppingOn && >+ keyFrameInterval == other.keyFrameInterval && >+ spsLen == other.spsLen && ppsLen == other.ppsLen && >+ profile == other.profile && >+ (spsLen == 0 || memcmp(spsData, other.spsData, spsLen) == 0) && >+ (ppsLen == 0 || memcmp(ppsData, other.ppsData, ppsLen) == 0)); >+} >+ >+bool SpatialLayer::operator==(const SpatialLayer& other) const { >+ return (width == other.width && height == other.height && >+ numberOfTemporalLayers == other.numberOfTemporalLayers && >+ maxBitrate == other.maxBitrate && >+ targetBitrate == other.targetBitrate && >+ minBitrate == other.minBitrate && qpMax == other.qpMax && >+ active == other.active); >+} >+ >+VideoCodec::VideoCodec() >+ : codecType(kVideoCodecGeneric), >+ plType(0), >+ width(0), >+ height(0), >+ startBitrate(0), >+ maxBitrate(0), >+ minBitrate(0), >+ targetBitrate(0), >+ maxFramerate(0), >+ active(true), >+ qpMax(0), >+ numberOfSimulcastStreams(0), >+ simulcastStream(), >+ spatialLayers(), >+ mode(VideoCodecMode::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* kPayloadNameGeneric = "Generic"; >+static const char* kPayloadNameMultiplex = "Multiplex"; >+ >+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; >+ // Other codecs default to generic. >+ default: >+ 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(), kPayloadNameMultiplex)) >+ return kVideoCodecMultiplex; >+ return kVideoCodecGeneric; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.h >new file mode 100644 >index 00000000000..5b4ebb25c07 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_codec.h >@@ -0,0 +1,166 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef API_VIDEO_CODECS_VIDEO_CODEC_H_ >+#define API_VIDEO_CODECS_VIDEO_CODEC_H_ >+ >+#include <string> >+ >+#include "common_types.h" // NOLINT(build/include) >+ >+namespace webrtc { >+ >+// The VideoCodec class represents an old defacto-apis, which we're migrating >+// away from slowly. >+ >+// Video codec >+enum class VideoCodecComplexity { >+ kComplexityNormal = 0, >+ kComplexityHigh = 1, >+ kComplexityHigher = 2, >+ kComplexityMax = 3 >+}; >+ >+// VP8 specific >+struct VideoCodecVP8 { >+ bool operator==(const VideoCodecVP8& other) const; >+ bool operator!=(const VideoCodecVP8& other) const { >+ return !(*this == other); >+ } >+ VideoCodecComplexity complexity; >+ unsigned char numberOfTemporalLayers; >+ bool denoisingOn; >+ bool automaticResizeOn; >+ bool frameDroppingOn; >+ int keyFrameInterval; >+}; >+ >+enum class InterLayerPredMode { >+ kOn, // Allow inter-layer prediction for all frames. >+ // Frame of low spatial layer can be used for >+ // prediction of next spatial layer frame. >+ kOff, // Encoder produces independent spatial layers. >+ kOnKeyPic // Allow inter-layer prediction only for frames >+ // within key picture. >+}; >+ >+// VP9 specific. >+struct VideoCodecVP9 { >+ bool operator==(const VideoCodecVP9& other) const; >+ bool operator!=(const VideoCodecVP9& other) const { >+ return !(*this == other); >+ } >+ VideoCodecComplexity complexity; >+ unsigned char numberOfTemporalLayers; >+ bool denoisingOn; >+ bool frameDroppingOn; >+ int keyFrameInterval; >+ bool adaptiveQpMode; >+ bool automaticResizeOn; >+ unsigned char numberOfSpatialLayers; >+ bool flexibleMode; >+ InterLayerPredMode interLayerPred; >+}; >+ >+// H264 specific. >+struct VideoCodecH264 { >+ bool operator==(const VideoCodecH264& other) const; >+ bool operator!=(const VideoCodecH264& other) const { >+ return !(*this == other); >+ } >+ bool frameDroppingOn; >+ int keyFrameInterval; >+ // These are NULL/0 if not externally negotiated. >+ const uint8_t* spsData; >+ size_t spsLen; >+ const uint8_t* ppsData; >+ size_t ppsLen; >+ H264::Profile profile; >+}; >+ >+// Translates from name of codec to codec type and vice versa. >+const char* CodecTypeToPayloadString(VideoCodecType type); >+VideoCodecType PayloadStringToCodecType(const std::string& name); >+ >+union VideoCodecUnion { >+ VideoCodecVP8 VP8; >+ VideoCodecVP9 VP9; >+ VideoCodecH264 H264; >+}; >+ >+enum class VideoCodecMode { kRealtimeVideo, kScreensharing }; >+ >+// Common video codec properties >+class VideoCodec { >+ public: >+ VideoCodec(); >+ >+ // Public variables. TODO(hta): Make them private with accessors. >+ VideoCodecType codecType; >+ unsigned char plType; >+ >+ // TODO(nisse): Change to int, for consistency. >+ uint16_t width; >+ uint16_t height; >+ >+ unsigned int startBitrate; // kilobits/sec. >+ unsigned int maxBitrate; // kilobits/sec. >+ unsigned int minBitrate; // kilobits/sec. >+ unsigned int targetBitrate; // kilobits/sec. >+ >+ uint32_t maxFramerate; >+ >+ // This enables/disables encoding and sending when there aren't multiple >+ // simulcast streams,by allocating 0 bitrate if inactive. >+ bool active; >+ >+ unsigned int qpMax; >+ unsigned char numberOfSimulcastStreams; >+ SimulcastStream simulcastStream[kMaxSimulcastStreams]; >+ SpatialLayer spatialLayers[kMaxSpatialLayers]; >+ >+ VideoCodecMode mode; >+ bool expect_encode_from_texture; >+ >+ // Timing frames configuration. There is delay of delay_ms between two >+ // consequent timing frames, excluding outliers. Frame is always made a >+ // timing frame if it's at least outlier_ratio in percent of "ideal" average >+ // frame given bitrate and framerate, i.e. if it's bigger than >+ // |outlier_ratio / 100.0 * bitrate_bps / fps| in bits. This way, timing >+ // frames will not be sent too often usually. Yet large frames will always >+ // have timing information for debug purposes because they are more likely to >+ // cause extra delays. >+ struct TimingFrameTriggerThresholds { >+ int64_t delay_ms; >+ uint16_t outlier_ratio_percent; >+ } timing_frame_thresholds; >+ >+ bool operator==(const VideoCodec& other) const = delete; >+ bool operator!=(const VideoCodec& other) const = delete; >+ >+ // Accessors for codec specific information. >+ // There is a const version of each that returns a reference, >+ // and a non-const version that returns a pointer, in order >+ // to allow modification of the parameters. >+ VideoCodecVP8* VP8(); >+ const VideoCodecVP8& VP8() const; >+ VideoCodecVP9* VP9(); >+ const VideoCodecVP9& VP9() const; >+ VideoCodecH264* H264(); >+ const VideoCodecH264& H264() const; >+ >+ private: >+ // TODO(hta): Consider replacing the union with a pointer type. >+ // This will allow removing the VideoCodec* types from this file. >+ VideoCodecUnion codec_specific_; >+}; >+ >+} // namespace webrtc >+#endif // API_VIDEO_CODECS_VIDEO_CODEC_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.cc >new file mode 100644 >index 00000000000..b5fff32e5fe >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.cc >@@ -0,0 +1,44 @@ >+/* >+ * Copyright (c) 2018 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 "api/video_codecs/video_decoder.h" >+ >+namespace webrtc { >+ >+int32_t DecodedImageCallback::Decoded(VideoFrame& decodedImage, >+ int64_t decode_time_ms) { >+ // The default implementation ignores custom decode time value. >+ return Decoded(decodedImage); >+} >+ >+void DecodedImageCallback::Decoded(VideoFrame& decodedImage, >+ absl::optional<int32_t> decode_time_ms, >+ absl::optional<uint8_t> qp) { >+ Decoded(decodedImage, decode_time_ms.value_or(-1)); >+} >+ >+int32_t DecodedImageCallback::ReceivedDecodedReferenceFrame( >+ const uint64_t pictureId) { >+ return -1; >+} >+ >+int32_t DecodedImageCallback::ReceivedDecodedFrame(const uint64_t pictureId) { >+ return -1; >+} >+ >+bool VideoDecoder::PrefersLateDecoding() const { >+ return true; >+} >+ >+const char* VideoDecoder::ImplementationName() const { >+ return "unknown"; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.h >index 7d3a7f59781..7995fccb056 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder.h >@@ -16,13 +16,11 @@ > #include <vector> > > #include "api/video/video_frame.h" >-#include "common_types.h" // NOLINT(build/include) >+#include "api/video_codecs/video_codec.h" > #include "common_video/include/video_frame.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >-class RTPFragmentationHeader; > // TODO(pbos): Expose these through a public (root) header or change these APIs. > struct CodecSpecificInfo; > class VideoCodec; >@@ -36,24 +34,17 @@ class DecodedImageCallback { > // decode time excluding waiting time for any previous pending frame to > // return. This is necessary for breaking positive feedback in the delay > // estimation when the decoder has a single output buffer. >- virtual int32_t Decoded(VideoFrame& decodedImage, int64_t /* decode_time_ms */) { >- // The default implementation ignores custom decode time value. >- return Decoded(decodedImage); >- } >+ virtual int32_t Decoded(VideoFrame& decodedImage, int64_t decode_time_ms); >+ > // TODO(sakal): Remove other implementations when upstream projects have been > // updated. > virtual void Decoded(VideoFrame& decodedImage, >- rtc::Optional<int32_t> decode_time_ms, >- rtc::Optional<uint8_t> /* qp */) { >- Decoded(decodedImage, >- decode_time_ms ? static_cast<int32_t>(*decode_time_ms) : -1); >- } >+ absl::optional<int32_t> decode_time_ms, >+ absl::optional<uint8_t> qp); > >- virtual int32_t ReceivedDecodedReferenceFrame(const uint64_t /* pictureId */) { >- return -1; >- } >+ virtual int32_t ReceivedDecodedReferenceFrame(const uint64_t pictureId); > >- virtual int32_t ReceivedDecodedFrame(const uint64_t /* pictureId */) { return -1; } >+ virtual int32_t ReceivedDecodedFrame(const uint64_t pictureId); > }; > > class VideoDecoder { >@@ -65,9 +56,8 @@ class VideoDecoder { > > virtual int32_t Decode(const EncodedImage& input_image, > bool missing_frames, >- const RTPFragmentationHeader* fragmentation, >- const CodecSpecificInfo* codec_specific_info = NULL, >- int64_t render_time_ms = -1) = 0; >+ const CodecSpecificInfo* codec_specific_info, >+ int64_t render_time_ms) = 0; > > virtual int32_t RegisterDecodeCompleteCallback( > DecodedImageCallback* callback) = 0; >@@ -77,9 +67,9 @@ class VideoDecoder { > // Returns true if the decoder prefer to decode frames late. > // That is, it can not decode infinite number of frames before the decoded > // frame is consumed. >- virtual bool PrefersLateDecoding() const { return true; } >+ virtual bool PrefersLateDecoding() const; > >- virtual const char* ImplementationName() const { return "unknown"; } >+ virtual const char* ImplementationName() const; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.cc >new file mode 100644 >index 00000000000..1666bc32773 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.cc >@@ -0,0 +1,224 @@ >+/* >+ * Copyright (c) 2016 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 "api/video_codecs/video_decoder_software_fallback_wrapper.h" >+ >+#include <string> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "modules/video_coding/include/video_error_codes.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/logging.h" >+#include "rtc_base/system/fallthrough.h" >+#include "rtc_base/trace_event.h" >+ >+namespace webrtc { >+ >+namespace { >+ >+class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder { >+ public: >+ VideoDecoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoDecoder> sw_fallback_decoder, >+ std::unique_ptr<VideoDecoder> hw_decoder); >+ ~VideoDecoderSoftwareFallbackWrapper() override; >+ >+ int32_t InitDecode(const VideoCodec* codec_settings, >+ int32_t number_of_cores) override; >+ >+ int32_t Decode(const EncodedImage& input_image, >+ bool missing_frames, >+ const CodecSpecificInfo* codec_specific_info, >+ int64_t render_time_ms) override; >+ >+ int32_t RegisterDecodeCompleteCallback( >+ DecodedImageCallback* callback) override; >+ >+ int32_t Release() override; >+ bool PrefersLateDecoding() const override; >+ >+ const char* ImplementationName() const override; >+ >+ private: >+ bool InitFallbackDecoder(); >+ int32_t InitHwDecoder(); >+ >+ VideoDecoder& active_decoder() const; >+ >+ // Determines if we are trying to use the HW or SW decoder. >+ enum class DecoderType { >+ kNone, >+ kHardware, >+ kFallback, >+ } decoder_type_; >+ std::unique_ptr<VideoDecoder> hw_decoder_; >+ >+ VideoCodec codec_settings_; >+ int32_t number_of_cores_; >+ const std::unique_ptr<VideoDecoder> fallback_decoder_; >+ const std::string fallback_implementation_name_; >+ DecodedImageCallback* callback_; >+}; >+ >+VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoDecoder> sw_fallback_decoder, >+ std::unique_ptr<VideoDecoder> hw_decoder) >+ : decoder_type_(DecoderType::kNone), >+ hw_decoder_(std::move(hw_decoder)), >+ fallback_decoder_(std::move(sw_fallback_decoder)), >+ fallback_implementation_name_( >+ std::string(fallback_decoder_->ImplementationName()) + >+ " (fallback from: " + hw_decoder_->ImplementationName() + ")"), >+ callback_(nullptr) {} >+VideoDecoderSoftwareFallbackWrapper::~VideoDecoderSoftwareFallbackWrapper() = >+ default; >+ >+int32_t VideoDecoderSoftwareFallbackWrapper::InitDecode( >+ const VideoCodec* codec_settings, >+ int32_t number_of_cores) { >+ codec_settings_ = *codec_settings; >+ number_of_cores_ = number_of_cores; >+ >+ int32_t status = InitHwDecoder(); >+ if (status == WEBRTC_VIDEO_CODEC_OK) { >+ return WEBRTC_VIDEO_CODEC_OK; >+ } >+ >+ RTC_DCHECK(decoder_type_ == DecoderType::kNone); >+ if (InitFallbackDecoder()) { >+ return WEBRTC_VIDEO_CODEC_OK; >+ } >+ >+ return status; >+} >+ >+int32_t VideoDecoderSoftwareFallbackWrapper::InitHwDecoder() { >+ RTC_DCHECK(decoder_type_ == DecoderType::kNone); >+ int32_t status = hw_decoder_->InitDecode(&codec_settings_, number_of_cores_); >+ if (status != WEBRTC_VIDEO_CODEC_OK) { >+ return status; >+ } >+ >+ decoder_type_ = DecoderType::kHardware; >+ if (callback_) >+ hw_decoder_->RegisterDecodeCompleteCallback(callback_); >+ return status; >+} >+ >+bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() { >+ RTC_DCHECK(decoder_type_ == DecoderType::kNone || >+ decoder_type_ == DecoderType::kHardware); >+ RTC_LOG(LS_WARNING) << "Decoder falling back to software decoding."; >+ int32_t status = >+ fallback_decoder_->InitDecode(&codec_settings_, number_of_cores_); >+ if (status != WEBRTC_VIDEO_CODEC_OK) { >+ RTC_LOG(LS_ERROR) << "Failed to initialize software-decoder fallback."; >+ return false; >+ } >+ >+ if (decoder_type_ == DecoderType::kHardware) { >+ hw_decoder_->Release(); >+ } >+ decoder_type_ = DecoderType::kFallback; >+ >+ if (callback_) >+ fallback_decoder_->RegisterDecodeCompleteCallback(callback_); >+ return true; >+} >+ >+int32_t VideoDecoderSoftwareFallbackWrapper::Decode( >+ const EncodedImage& input_image, >+ bool missing_frames, >+ const CodecSpecificInfo* codec_specific_info, >+ int64_t render_time_ms) { >+ TRACE_EVENT0("webrtc", "VideoDecoderSoftwareFallbackWrapper::Decode"); >+ switch (decoder_type_) { >+ case DecoderType::kNone: >+ return WEBRTC_VIDEO_CODEC_UNINITIALIZED; >+ case DecoderType::kHardware: { >+ int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; >+ ret = hw_decoder_->Decode(input_image, missing_frames, >+ codec_specific_info, render_time_ms); >+ if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) { >+ return ret; >+ } >+ >+ // HW decoder returned WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE or >+ // initialization failed, fallback to software. >+ if (!InitFallbackDecoder()) { >+ return ret; >+ } >+ >+ // Fallback decoder initialized, fall-through. >+ RTC_FALLTHROUGH(); >+ } >+ case DecoderType::kFallback: >+ return fallback_decoder_->Decode(input_image, missing_frames, >+ codec_specific_info, render_time_ms); >+ default: >+ RTC_NOTREACHED(); >+ return WEBRTC_VIDEO_CODEC_ERROR; >+ } >+} >+ >+int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback( >+ DecodedImageCallback* callback) { >+ callback_ = callback; >+ return active_decoder().RegisterDecodeCompleteCallback(callback); >+} >+ >+int32_t VideoDecoderSoftwareFallbackWrapper::Release() { >+ int32_t status; >+ switch (decoder_type_) { >+ case DecoderType::kHardware: >+ status = hw_decoder_->Release(); >+ break; >+ case DecoderType::kFallback: >+ RTC_LOG(LS_INFO) << "Releasing software fallback decoder."; >+ status = fallback_decoder_->Release(); >+ break; >+ case DecoderType::kNone: >+ status = WEBRTC_VIDEO_CODEC_OK; >+ break; >+ default: >+ RTC_NOTREACHED(); >+ status = WEBRTC_VIDEO_CODEC_ERROR; >+ } >+ >+ decoder_type_ = DecoderType::kNone; >+ return status; >+} >+ >+bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const { >+ return active_decoder().PrefersLateDecoding(); >+} >+ >+const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const { >+ return decoder_type_ == DecoderType::kFallback >+ ? fallback_implementation_name_.c_str() >+ : hw_decoder_->ImplementationName(); >+} >+ >+VideoDecoder& VideoDecoderSoftwareFallbackWrapper::active_decoder() const { >+ return decoder_type_ == DecoderType::kFallback ? *fallback_decoder_ >+ : *hw_decoder_; >+} >+ >+} // namespace >+ >+std::unique_ptr<VideoDecoder> CreateVideoDecoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoDecoder> sw_fallback_decoder, >+ std::unique_ptr<VideoDecoder> hw_decoder) { >+ return absl::make_unique<VideoDecoderSoftwareFallbackWrapper>( >+ std::move(sw_fallback_decoder), std::move(hw_decoder)); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.h >new file mode 100644 >index 00000000000..0608715182f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_decoder_software_fallback_wrapper.h >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+ >+#ifndef API_VIDEO_CODECS_VIDEO_DECODER_SOFTWARE_FALLBACK_WRAPPER_H_ >+#define API_VIDEO_CODECS_VIDEO_DECODER_SOFTWARE_FALLBACK_WRAPPER_H_ >+ >+#include <memory> >+ >+#include "api/video_codecs/video_decoder.h" >+ >+namespace webrtc { >+ >+// Used to wrap external VideoDecoders to provide a fallback option on >+// software decoding when a hardware decoder fails to decode a stream due to >+// hardware restrictions, such as max resolution. >+std::unique_ptr<VideoDecoder> CreateVideoDecoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoDecoder> sw_fallback_decoder, >+ std::unique_ptr<VideoDecoder> hw_decoder); >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_CODECS_VIDEO_DECODER_SOFTWARE_FALLBACK_WRAPPER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.cc >index e1cc0cfac7c..008780e38c4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.cc >@@ -17,10 +17,8 @@ VideoCodecVP8 VideoEncoder::GetDefaultVp8Settings() { > VideoCodecVP8 vp8_settings; > memset(&vp8_settings, 0, sizeof(vp8_settings)); > >- vp8_settings.resilience = kResilientStream; > vp8_settings.numberOfTemporalLayers = 1; > vp8_settings.denoisingOn = true; >- vp8_settings.errorConcealmentOn = false; > vp8_settings.automaticResizeOn = false; > vp8_settings.frameDroppingOn = true; > vp8_settings.keyFrameInterval = 3000; >@@ -32,7 +30,6 @@ VideoCodecVP9 VideoEncoder::GetDefaultVp9Settings() { > VideoCodecVP9 vp9_settings; > memset(&vp9_settings, 0, sizeof(vp9_settings)); > >- vp9_settings.resilienceOn = true; > vp9_settings.numberOfTemporalLayers = 1; > vp9_settings.denoisingOn = true; > vp9_settings.frameDroppingOn = true; >@@ -41,6 +38,7 @@ VideoCodecVP9 VideoEncoder::GetDefaultVp9Settings() { > vp9_settings.automaticResizeOn = true; > vp9_settings.numberOfSpatialLayers = 1; > vp9_settings.flexibleMode = false; >+ vp9_settings.interLayerPred = InterLayerPredMode::kOn; > > return vp9_settings; > } >@@ -60,24 +58,26 @@ VideoCodecH264 VideoEncoder::GetDefaultH264Settings() { > return h264_settings; > } > >-VideoEncoder::ScalingSettings::ScalingSettings(bool on, int low, int high) >- : enabled(on), thresholds(QpThresholds(low, high)) {} >+VideoEncoder::ScalingSettings::ScalingSettings() = default; > >-VideoEncoder::ScalingSettings::ScalingSettings(bool on, >- int low, >+VideoEncoder::ScalingSettings::ScalingSettings(KOff) : ScalingSettings() {} >+ >+VideoEncoder::ScalingSettings::ScalingSettings(int low, int high) >+ : thresholds(QpThresholds(low, high)) {} >+ >+VideoEncoder::ScalingSettings::ScalingSettings(int low, > int high, > int min_pixels) >- : enabled(on), >- thresholds(QpThresholds(low, high)), >- min_pixels_per_frame(min_pixels) {} >- >-VideoEncoder::ScalingSettings::ScalingSettings(bool on, int min_pixels) >- : enabled(on), min_pixels_per_frame(min_pixels) {} >+ : thresholds(QpThresholds(low, high)), min_pixels_per_frame(min_pixels) {} > >-VideoEncoder::ScalingSettings::ScalingSettings(bool on) : enabled(on) {} >+VideoEncoder::ScalingSettings::ScalingSettings(const ScalingSettings&) = >+ default; > > VideoEncoder::ScalingSettings::~ScalingSettings() {} > >+// static >+constexpr VideoEncoder::ScalingSettings::KOff >+ VideoEncoder::ScalingSettings::kOff; > > int32_t VideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) { > RTC_NOTREACHED() << "SetRate(uint32_t, uint32_t) is deprecated."; >@@ -85,17 +85,13 @@ int32_t VideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) { > } > > int32_t VideoEncoder::SetRateAllocation( >- const BitrateAllocation& allocation, >+ const VideoBitrateAllocation& allocation, > uint32_t framerate) { > return SetRates(allocation.get_sum_kbps(), framerate); > } > > VideoEncoder::ScalingSettings VideoEncoder::GetScalingSettings() const { >- return ScalingSettings(false); >-} >- >-int32_t VideoEncoder::SetPeriodicKeyFrames(bool enable) { >- return -1; >+ return ScalingSettings::kOff; > } > > bool VideoEncoder::SupportsNativeHandle() const { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.h >index 64e33069099..68d9b445580 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder.h >@@ -15,19 +15,18 @@ > #include <string> > #include <vector> > >-#include "api/optional.h" >+#include "absl/types/optional.h" >+#include "api/video/video_bitrate_allocation.h" > #include "api/video/video_frame.h" >-#include "common_types.h" // NOLINT(build/include) >+#include "api/video_codecs/video_codec.h" > #include "common_video/include/video_frame.h" > #include "rtc_base/checks.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > > class RTPFragmentationHeader; > // TODO(pbos): Expose these through a public (root) header or change these APIs. > struct CodecSpecificInfo; >-class VideoCodec; > > class EncodedImageCallback { > public: >@@ -71,10 +70,7 @@ class EncodedImageCallback { > const CodecSpecificInfo* codec_specific_info, > const RTPFragmentationHeader* fragmentation) = 0; > >- // Deprecated. TODO(ilnik): Remove this in few weeks. >- virtual void OnDroppedFrame() {} >- >- virtual void OnDroppedFrame(DropReason) {} >+ virtual void OnDroppedFrame(DropReason reason) {} > }; > > class VideoEncoder { >@@ -85,22 +81,39 @@ class VideoEncoder { > int low; > int high; > }; >+ // Quality scaling is enabled if thresholds are provided. > struct ScalingSettings { >- ScalingSettings(bool on, int low, int high); >- ScalingSettings(bool on, int low, int high, int min_pixels); >- ScalingSettings(bool on, int min_pixels); >- explicit ScalingSettings(bool on); >+ private: >+ // Private magic type for kOff, implicitly convertible to >+ // ScalingSettings. >+ struct KOff {}; >+ >+ public: >+ // TODO(nisse): Would be nicer if kOff were a constant ScalingSettings >+ // rather than a magic value. However, absl::optional is not trivially copy >+ // constructible, and hence a constant ScalingSettings needs a static >+ // initializer, which is strongly discouraged in Chrome. We can hopefully >+ // fix this when we switch to absl::optional or std::optional. >+ static constexpr KOff kOff = {}; >+ >+ ScalingSettings(int low, int high); >+ ScalingSettings(int low, int high, int min_pixels); > ScalingSettings(const ScalingSettings&); >+ ScalingSettings(KOff); // NOLINT(runtime/explicit) > ~ScalingSettings(); > >- const bool enabled; >- const rtc::Optional<QpThresholds> thresholds; >+ const absl::optional<QpThresholds> thresholds; > > // We will never ask for a resolution lower than this. > // TODO(kthelgason): Lower this limit when better testing > // on MediaCodec and fallback implementations are in place. > // See https://bugs.chromium.org/p/webrtc/issues/detail?id=7206 > const int min_pixels_per_frame = 320 * 180; >+ >+ private: >+ // Private constructor; to get an object without thresholds, use >+ // the magic constant ScalingSettings::kOff. >+ ScalingSettings(); > }; > > static VideoCodecVP8 GetDefaultVp8Settings(); >@@ -180,14 +193,13 @@ class VideoEncoder { > > // Default fallback: Just use the sum of bitrates as the single target rate. > // TODO(sprang): Remove this default implementation when we remove SetRates(). >- virtual int32_t SetRateAllocation(const BitrateAllocation& allocation, >+ virtual int32_t SetRateAllocation(const VideoBitrateAllocation& allocation, > uint32_t framerate); > > // Any encoder implementation wishing to use the WebRTC provided > // quality scaler must implement this method. > virtual ScalingSettings GetScalingSettings() const; > >- virtual int32_t SetPeriodicKeyFrames(bool enable); > virtual bool SupportsNativeHandle() const; > virtual const char* ImplementationName() const; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.cc >similarity index 87% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.cc >index 85140515f79..74977eaea3f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.cc >@@ -7,13 +7,13 @@ > * in the file PATENTS. All contributing project authors may > * be found in the AUTHORS file in the root of the source tree. > */ >-#include "call/video_config.h" >+#include "api/video_codecs/video_encoder_config.h" > > #include <algorithm> >-#include <sstream> > #include <string> > > #include "rtc_base/checks.h" >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > VideoStream::VideoStream() >@@ -30,7 +30,8 @@ VideoStream::VideoStream(const VideoStream& other) = default; > VideoStream::~VideoStream() = default; > > std::string VideoStream::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{width: " << width; > ss << ", height: " << height; > ss << ", max_framerate: " << max_framerate; >@@ -38,22 +39,17 @@ std::string VideoStream::ToString() const { > ss << ", target_bitrate_bps:" << target_bitrate_bps; > ss << ", max_bitrate_bps:" << max_bitrate_bps; > ss << ", max_qp: " << max_qp; >+ ss << ", num_temporal_layers: " << num_temporal_layers.value_or(0); >+ ss << ", bitrate_priority: " << bitrate_priority.value_or(0); > ss << ", active: " << active; > >- ss << ", temporal_layer_thresholds_bps: ["; >- for (size_t i = 0; i < temporal_layer_thresholds_bps.size(); ++i) { >- ss << temporal_layer_thresholds_bps[i]; >- if (i != temporal_layer_thresholds_bps.size() - 1) >- ss << ", "; >- } >- ss << ']'; >- >- ss << '}'; > return ss.str(); > } > > VideoEncoderConfig::VideoEncoderConfig() >- : content_type(ContentType::kRealtimeVideo), >+ : codec_type(kVideoCodecGeneric), >+ video_format("Unset"), >+ content_type(ContentType::kRealtimeVideo), > encoder_specific_settings(nullptr), > min_transmit_bitrate_bps(0), > max_bitrate_bps(0), >@@ -65,8 +61,11 @@ VideoEncoderConfig::VideoEncoderConfig(VideoEncoderConfig&&) = default; > VideoEncoderConfig::~VideoEncoderConfig() = default; > > std::string VideoEncoderConfig::ToString() const { >- std::stringstream ss; >- ss << "{content_type: "; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); >+ ss << "{codec_type: "; >+ ss << CodecTypeToPayloadString(codec_type); >+ ss << ", content_type: "; > switch (content_type) { > case ContentType::kRealtimeVideo: > ss << "kRealtimeVideo"; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.h >similarity index 81% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.h >index 038cdb2b5b0..e10f08190c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_config.h >@@ -8,18 +8,17 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef CALL_VIDEO_CONFIG_H_ >-#define CALL_VIDEO_CONFIG_H_ >+#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_CONFIG_H_ >+#define API_VIDEO_CODECS_VIDEO_ENCODER_CONFIG_H_ > > #include <string> > #include <vector> > >-#include "api/optional.h" >-#include "common_types.h" // NOLINT(build/include) >-#include "rtc_base/basictypes.h" >+#include "absl/types/optional.h" >+#include "api/video_codecs/sdp_video_format.h" >+#include "api/video_codecs/video_codec.h" > #include "rtc_base/refcount.h" > #include "rtc_base/scoped_ref_ptr.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -36,24 +35,14 @@ struct VideoStream { > int min_bitrate_bps; > int target_bitrate_bps; > int max_bitrate_bps; >- rtc::Optional<double> bitrate_priority; >- > int max_qp; > >+ absl::optional<size_t> num_temporal_layers; >+ >+ absl::optional<double> bitrate_priority; >+ > // TODO(bugs.webrtc.org/8653): Support active per-simulcast layer. > bool active; >- >- // Bitrate thresholds for enabling additional temporal layers. Since these are >- // thresholds in between layers, we have one additional layer. One threshold >- // gives two temporal layers, one below the threshold and one above, two give >- // three, and so on. >- // The VideoEncoder may redistribute bitrates over the temporal layers so a >- // bitrate threshold of 100k and an estimate of 105k does not imply that we >- // get 100k in one temporal layer and 5k in the other, just that the bitrate >- // in the first temporal layer should not exceed 100k. >- // TODO(kthelgason): Apart from a special case for two-layer screencast these >- // thresholds are not propagated to the VideoEncoder. To be implemented. >- std::vector<int> temporal_layer_thresholds_bps; > }; > > class VideoEncoderConfig { >@@ -61,7 +50,7 @@ class VideoEncoderConfig { > // These are reference counted to permit copying VideoEncoderConfig and be > // kept alive until all encoder_specific_settings go out of scope. > // TODO(kthelgason): Consider removing the need for copying VideoEncoderConfig >- // and use rtc::Optional for encoder_specific_settings instead. >+ // and use absl::optional for encoder_specific_settings instead. > class EncoderSpecificSettings : public rtc::RefCountInterface { > public: > // TODO(pbos): Remove FillEncoderSpecificSettings as soon as VideoCodec is >@@ -136,6 +125,10 @@ class VideoEncoderConfig { > ~VideoEncoderConfig(); > std::string ToString() const; > >+ // TODO(nisse): Consolidate on one of these. >+ VideoCodecType codec_type; >+ SdpVideoFormat video_format; >+ > rtc::scoped_refptr<VideoStreamFactoryInterface> video_stream_factory; > std::vector<SpatialLayer> spatial_layers; > ContentType content_type; >@@ -153,6 +146,8 @@ class VideoEncoderConfig { > // The simulcast layer's configurations set by the application for this video > // sender. These are modified by the video_stream_factory before being passed > // down to lower layers for the video encoding. >+ // |simulcast_layers| is also used for configuring non-simulcast (when there >+ // is a single VideoStream). > std::vector<VideoStream> simulcast_layers; > > // Max number of encoded VideoStreams to produce. >@@ -166,4 +161,4 @@ class VideoEncoderConfig { > > } // namespace webrtc > >-#endif // CALL_VIDEO_CONFIG_H_ >+#endif // API_VIDEO_CODECS_VIDEO_ENCODER_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.cc >similarity index 72% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.cc >index 69254f5fb50..99f29707e44 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.cc >@@ -8,12 +8,16 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "media/engine/videoencodersoftwarefallbackwrapper.h" >+#include "api/video_codecs/video_encoder_software_fallback_wrapper.h" > >+#include <cstdio> >+#include <string> > #include <utility> >+#include <vector> > >+#include "absl/memory/memory.h" >+#include "media/base/codec.h" > #include "media/base/h264_profile_level_id.h" >-#include "media/engine/internalencoderfactory.h" > #include "modules/video_coding/include/video_error_codes.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" >@@ -21,7 +25,9 @@ > #include "system_wrappers/include/field_trial.h" > > namespace webrtc { >+ > namespace { >+ > const char kVp8ForceFallbackEncoderFieldTrial[] = > "WebRTC-VP8-Forced-Fallback-Encoder-v2"; > >@@ -62,7 +68,81 @@ void GetForcedFallbackParamsFromFieldTrialGroup(int* param_min_pixels, > *param_min_pixels = min_pixels; > *param_max_pixels = max_pixels; > } >-} // namespace >+ >+class VideoEncoderSoftwareFallbackWrapper final : public VideoEncoder { >+ public: >+ VideoEncoderSoftwareFallbackWrapper( >+ std::unique_ptr<webrtc::VideoEncoder> sw_encoder, >+ std::unique_ptr<webrtc::VideoEncoder> hw_encoder); >+ ~VideoEncoderSoftwareFallbackWrapper() override; >+ >+ int32_t InitEncode(const VideoCodec* codec_settings, >+ int32_t number_of_cores, >+ size_t max_payload_size) override; >+ >+ int32_t RegisterEncodeCompleteCallback( >+ EncodedImageCallback* callback) override; >+ >+ int32_t Release() override; >+ int32_t Encode(const VideoFrame& frame, >+ const CodecSpecificInfo* codec_specific_info, >+ const std::vector<FrameType>* frame_types) override; >+ int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; >+ int32_t SetRateAllocation(const VideoBitrateAllocation& bitrate_allocation, >+ uint32_t framerate) override; >+ bool SupportsNativeHandle() const override; >+ ScalingSettings GetScalingSettings() const override; >+ const char* ImplementationName() const override; >+ >+ private: >+ bool InitFallbackEncoder(); >+ >+ // If |forced_fallback_possible_| is true: >+ // The forced fallback is requested if the resolution is less than or equal to >+ // |max_pixels_|. The resolution is allowed to be scaled down to >+ // |min_pixels_|. >+ class ForcedFallbackParams { >+ public: >+ bool IsValid(const VideoCodec& codec) const { >+ return codec.width * codec.height <= max_pixels_; >+ } >+ >+ bool active_ = false; >+ int min_pixels_ = 320 * 180; >+ int max_pixels_ = 320 * 240; >+ }; >+ >+ bool TryInitForcedFallbackEncoder(); >+ bool TryReInitForcedFallbackEncoder(); >+ void ValidateSettingsForForcedFallback(); >+ bool IsForcedFallbackActive() const; >+ void MaybeModifyCodecForFallback(); >+ >+ // Settings used in the last InitEncode call and used if a dynamic fallback to >+ // software is required. >+ VideoCodec codec_settings_; >+ int32_t number_of_cores_; >+ size_t max_payload_size_; >+ >+ // The last bitrate/framerate set, and a flag for noting they are set. >+ bool rates_set_; >+ VideoBitrateAllocation bitrate_allocation_; >+ uint32_t framerate_; >+ >+ // The last channel parameters set, and a flag for noting they are set. >+ bool channel_parameters_set_; >+ uint32_t packet_loss_; >+ int64_t rtt_; >+ >+ bool use_fallback_encoder_; >+ const std::unique_ptr<webrtc::VideoEncoder> encoder_; >+ >+ const std::unique_ptr<webrtc::VideoEncoder> fallback_encoder_; >+ EncodedImageCallback* callback_; >+ >+ bool forced_fallback_possible_; >+ ForcedFallbackParams forced_fallback_; >+}; > > VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( > std::unique_ptr<webrtc::VideoEncoder> sw_encoder, >@@ -86,6 +166,8 @@ VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper( > 1); // No HW below. > } > } >+VideoEncoderSoftwareFallbackWrapper::~VideoEncoderSoftwareFallbackWrapper() = >+ default; > > bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() { > RTC_LOG(LS_WARNING) << "Encoder falling back to software encoding."; >@@ -182,13 +264,6 @@ int32_t VideoEncoderSoftwareFallbackWrapper::Encode( > // If requested, try a software fallback. > bool fallback_requested = (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); > if (fallback_requested && InitFallbackEncoder()) { >- if (frame.video_frame_buffer()->type() == VideoFrameBuffer::Type::kNative && >- !fallback_encoder_->SupportsNativeHandle()) { >- RTC_LOG(LS_WARNING) << "Fallback encoder doesn't support native frames, " >- << "dropping one frame."; >- return WEBRTC_VIDEO_CODEC_ERROR; >- } >- > // Start using the fallback with this frame. > return fallback_encoder_->Encode(frame, codec_specific_info, frame_types); > } >@@ -208,7 +283,7 @@ int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters( > } > > int32_t VideoEncoderSoftwareFallbackWrapper::SetRateAllocation( >- const BitrateAllocation& bitrate_allocation, >+ const VideoBitrateAllocation& bitrate_allocation, > uint32_t framerate) { > rates_set_ = true; > bitrate_allocation_ = bitrate_allocation; >@@ -227,19 +302,14 @@ bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const { > VideoEncoder::ScalingSettings > VideoEncoderSoftwareFallbackWrapper::GetScalingSettings() const { > if (forced_fallback_possible_) { >- if (forced_fallback_.active_) { >- return VideoEncoder::ScalingSettings( >- codec_settings_.VP8().automaticResizeOn, >- forced_fallback_.min_pixels_); >- } >- const auto settings = encoder_->GetScalingSettings(); >- if (settings.thresholds) { >- return VideoEncoder::ScalingSettings( >- settings.enabled, settings.thresholds->low, settings.thresholds->high, >- forced_fallback_.min_pixels_); >- } >- return VideoEncoder::ScalingSettings(settings.enabled, >- forced_fallback_.min_pixels_); >+ const auto settings = forced_fallback_.active_ >+ ? fallback_encoder_->GetScalingSettings() >+ : encoder_->GetScalingSettings(); >+ return settings.thresholds >+ ? VideoEncoder::ScalingSettings(settings.thresholds->low, >+ settings.thresholds->high, >+ forced_fallback_.min_pixels_) >+ : VideoEncoder::ScalingSettings::kOff; > } > return encoder_->GetScalingSettings(); > } >@@ -305,4 +375,13 @@ void VideoEncoderSoftwareFallbackWrapper::ValidateSettingsForForcedFallback() { > } > } > >+} // namespace >+ >+std::unique_ptr<VideoEncoder> CreateVideoEncoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoEncoder> sw_fallback_encoder, >+ std::unique_ptr<VideoEncoder> hw_encoder) { >+ return absl::make_unique<VideoEncoderSoftwareFallbackWrapper>( >+ std::move(sw_fallback_encoder), std::move(hw_encoder)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.h >new file mode 100644 >index 00000000000..0f46ad41bad >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/video_codecs/video_encoder_software_fallback_wrapper.h >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+ >+#ifndef API_VIDEO_CODECS_VIDEO_ENCODER_SOFTWARE_FALLBACK_WRAPPER_H_ >+#define API_VIDEO_CODECS_VIDEO_ENCODER_SOFTWARE_FALLBACK_WRAPPER_H_ >+ >+#include <memory> >+ >+#include "api/video_codecs/video_encoder.h" >+ >+namespace webrtc { >+ >+// Used to wrap external VideoEncoders to provide a fallback option on >+// software encoding when a hardware encoder fails to encode a stream due to >+// hardware restrictions, such as max resolution. >+std::unique_ptr<VideoEncoder> CreateVideoEncoderSoftwareFallbackWrapper( >+ std::unique_ptr<VideoEncoder> sw_fallback_encoder, >+ std::unique_ptr<VideoEncoder> hw_encoder); >+ >+} // namespace webrtc >+ >+#endif // API_VIDEO_CODECS_VIDEO_ENCODER_SOFTWARE_FALLBACK_WRAPPER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceproxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceproxy.h >index f2d8be06813..dbd9045be87 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceproxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/api/videosourceproxy.h >@@ -11,8 +11,8 @@ > #ifndef API_VIDEOSOURCEPROXY_H_ > #define API_VIDEOSOURCEPROXY_H_ > >-#include "api/proxy.h" > #include "api/mediastreaminterface.h" >+#include "api/proxy.h" > > namespace webrtc { > >@@ -21,19 +21,19 @@ namespace webrtc { > // TODO(deadbeef): Move this to .cc file and out of api/. What threads methods > // are called on is an implementation detail. > BEGIN_PROXY_MAP(VideoTrackSource) >- PROXY_SIGNALING_THREAD_DESTRUCTOR() >- PROXY_CONSTMETHOD0(SourceState, state) >- PROXY_CONSTMETHOD0(bool, remote) >- PROXY_CONSTMETHOD0(bool, is_screencast) >- PROXY_CONSTMETHOD0(rtc::Optional<bool>, needs_denoising) >- PROXY_METHOD1(bool, GetStats, Stats*) >- PROXY_WORKER_METHOD2(void, >- AddOrUpdateSink, >- rtc::VideoSinkInterface<VideoFrame>*, >- const rtc::VideoSinkWants&) >- PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) >- PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >- PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) >+PROXY_SIGNALING_THREAD_DESTRUCTOR() >+PROXY_CONSTMETHOD0(SourceState, state) >+PROXY_CONSTMETHOD0(bool, remote) >+PROXY_CONSTMETHOD0(bool, is_screencast) >+PROXY_CONSTMETHOD0(absl::optional<bool>, needs_denoising) >+PROXY_METHOD1(bool, GetStats, Stats*) >+PROXY_WORKER_METHOD2(void, >+ AddOrUpdateSink, >+ rtc::VideoSinkInterface<VideoFrame>*, >+ const rtc::VideoSinkWants&) >+PROXY_WORKER_METHOD1(void, RemoveSink, rtc::VideoSinkInterface<VideoFrame>*) >+PROXY_METHOD1(void, RegisterObserver, ObserverInterface*) >+PROXY_METHOD1(void, UnregisterObserver, ObserverInterface*) > END_PROXY_MAP() > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/BUILD.gn >index d3af836947e..2aaacc75a09 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/BUILD.gn >@@ -14,6 +14,8 @@ if (is_android) { > > rtc_static_library("audio") { > sources = [ >+ "audio_level.cc", >+ "audio_level.h", > "audio_receive_stream.cc", > "audio_receive_stream.h", > "audio_send_stream.cc", >@@ -22,11 +24,19 @@ rtc_static_library("audio") { > "audio_state.h", > "audio_transport_impl.cc", > "audio_transport_impl.h", >+ "channel.cc", >+ "channel.h", >+ "channel_proxy.cc", >+ "channel_proxy.h", > "conversion.h", > "null_audio_poller.cc", > "null_audio_poller.h", >+ "remix_resample.cc", >+ "remix_resample.h", > "time_interval.cc", > "time_interval.h", >+ "transport_feedback_packet_loss_tracker.cc", >+ "transport_feedback_packet_loss_tracker.h", > ] > > if (!build_with_chromium && is_clang) { >@@ -36,32 +46,47 @@ rtc_static_library("audio") { > > deps = [ > "..:webrtc_common", >- "../api:audio_mixer_api", >+ "../api:array_view", > "../api:call_api", >- "../api:optional", >+ "../api:libjingle_peerconnection_api", >+ "../api:transport_api", >+ "../api/audio:aec3_factory", >+ "../api/audio:audio_frame_api", >+ "../api/audio:audio_mixer_api", > "../api/audio_codecs:audio_codecs_api", >- "../api/audio_codecs:builtin_audio_encoder_factory", > "../call:bitrate_allocator", > "../call:call_interfaces", > "../call:rtp_interfaces", > "../common_audio", >+ "../common_audio:common_audio_c", >+ "../logging:rtc_event_audio", >+ "../logging:rtc_event_log_api", >+ "../modules/audio_coding", >+ "../modules/audio_coding:audio_format_conversion", >+ "../modules/audio_coding:audio_network_adaptor_config", > "../modules/audio_coding:cng", > "../modules/audio_device", > "../modules/audio_processing", > "../modules/bitrate_controller:bitrate_controller", >- "../modules/congestion_controller:congestion_controller", > "../modules/pacing:pacing", > "../modules/remote_bitrate_estimator:remote_bitrate_estimator", > "../modules/rtp_rtcp", >+ "../modules/rtp_rtcp:rtp_rtcp_format", >+ "../modules/utility", >+ "../rtc_base:audio_format_to_string", > "../rtc_base:checks", >+ "../rtc_base:rate_limiter", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_task_queue", >+ "../rtc_base:safe_minmax", >+ "../rtc_base:stringutils", > "../system_wrappers", > "../system_wrappers:field_trial_api", >- "../voice_engine", >- "../voice_engine:audio_level", >+ "../system_wrappers:metrics_api", > "utility:audio_frame_operations", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > if (rtc_include_tests) { >@@ -75,7 +100,6 @@ if (rtc_include_tests) { > deps = [ > ":audio", > "../system_wrappers:system_wrappers", >- "../test:fake_audio_device", > "../test:test_common", > "../test:test_support", > ] >@@ -94,28 +118,33 @@ if (rtc_include_tests) { > "audio_send_stream_tests.cc", > "audio_send_stream_unittest.cc", > "audio_state_unittest.cc", >+ "mock_voe_channel_proxy.h", >+ "remix_resample_unittest.cc", >+ "test/audio_stats_test.cc", > "time_interval_unittest.cc", >+ "transport_feedback_packet_loss_tracker_unittest.cc", > ] > deps = [ > ":audio", > ":audio_end_to_end_test", > "../api:mock_audio_mixer", >+ "../api/audio:audio_frame_api", >+ "../api/units:time_delta", > "../call:mock_call_interfaces", > "../call:mock_rtp_interfaces", > "../call:rtp_interfaces", > "../call:rtp_receiver", >+ "../common_audio", > "../logging:mocks", > "../modules/audio_device:mock_audio_device", > "../modules/audio_mixer:audio_mixer_impl", > "../modules/audio_processing:audio_processing_statistics", > "../modules/audio_processing:mocks", > "../modules/bitrate_controller:mocks", >- "../modules/congestion_controller:congestion_controller", >- "../modules/congestion_controller:mock_congestion_controller", >- "../modules/pacing:mock_paced_sender", > "../modules/pacing:pacing", > "../modules/rtp_rtcp:mock_rtp_rtcp", > "../modules/rtp_rtcp:rtp_rtcp_format", >+ "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_base_tests_utils", > "../rtc_base:rtc_task_queue", >@@ -125,17 +154,11 @@ if (rtc_include_tests) { > "../test:rtp_test_utils", > "../test:test_common", > "../test:test_support", >- "../voice_engine", > "utility:utility_tests", >- "//testing/gmock", > "//testing/gtest", >+ "//third_party/abseil-cpp/absl/memory", > ] > >- if (!rtc_use_memcheck) { >- # This test is timing dependent, which rules out running on memcheck bots. >- sources += [ "test/audio_stats_test.cc" ] >- } >- > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >@@ -155,10 +178,9 @@ if (rtc_include_tests) { > "../common_audio", > "../rtc_base:rtc_base_approved", > "../system_wrappers", >- "../test:fake_audio_device", >+ "../test:fileutils", > "../test:test_common", > "../test:test_main", >- "//testing/gmock", > "//testing/gtest", > ] > if (is_android) { >@@ -166,11 +188,34 @@ if (rtc_include_tests) { > } > > data = [ >- "../resources/voice_engine/audio_dtx16.wav", > "../resources/voice_engine/audio_tiny16.wav", > "../resources/voice_engine/audio_tiny48.wav", >+ ] >+ >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163) >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ } >+ >+ group("low_bandwidth_audio_perf_test") { >+ testonly = true >+ >+ deps = [ >+ ":low_bandwidth_audio_test", >+ ] >+ >+ data = [ > "test/low_bandwidth_audio_test.py", >+ "../resources/voice_engine/audio_tiny16.wav", >+ "../resources/voice_engine/audio_tiny48.wav", > ] >+ if (is_win) { >+ data += [ "${root_out_dir}/low_bandwidth_audio_test.exe" ] >+ } else { >+ data += [ "${root_out_dir}/low_bandwidth_audio_test" ] >+ } >+ > if (is_linux || is_android) { > data += [ > "../tools_webrtc/audio_quality/linux/PolqaOem64", >@@ -189,10 +234,7 @@ if (rtc_include_tests) { > data += [ "../tools_webrtc/audio_quality/mac/pesq" ] > } > >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163) >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >+ write_runtime_deps = "${root_out_dir}/${target_name}.runtime_deps" > } > } > >@@ -207,13 +249,13 @@ if (rtc_include_tests) { > "../common_audio", > "../rtc_base:rtc_base_approved", > "../system_wrappers", >- "../test:fake_audio_device", > "../test:field_trial", >+ "../test:fileutils", > "../test:single_threaded_task_queue", > "../test:test_common", > "../test:test_main", >- "//testing/gmock", > "//testing/gtest", >+ "//third_party/abseil-cpp/absl/memory", > ] > > data = [ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/DEPS >index 70e33469df9..8bb1f808052 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/DEPS >@@ -5,14 +5,15 @@ include_rules = [ > "+modules/audio_coding", > "+modules/audio_device", > "+modules/audio_mixer", >+ "+modules/audio_processing", > "+modules/audio_processing/include", > "+modules/bitrate_controller", > "+modules/congestion_controller", > "+modules/pacing", > "+modules/remote_bitrate_estimator", > "+modules/rtp_rtcp", >+ "+modules/utility", > "+system_wrappers", >- "+voice_engine", > ] > > specific_include_rules = { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.cc >similarity index 65% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.cc >index 57b485546be..3b8df9778eb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.cc >@@ -8,33 +8,21 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "voice_engine/audio_level.h" >+#include "audio/audio_level.h" > >+#include "api/audio/audio_frame.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" >-#include "modules/include/module_common_types.h" > > namespace webrtc { > namespace voe { > >-// Number of bars on the indicator. >-// Note that the number of elements is specified because we are indexing it >-// in the range of 0-32 >-constexpr int8_t kPermutation[33] = {0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 6, >- 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, >- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9}; >- > AudioLevel::AudioLevel() >- : abs_max_(0), count_(0), current_level_(0), current_level_full_range_(0) { >+ : abs_max_(0), count_(0), current_level_full_range_(0) { > WebRtcSpl_Init(); > } > > AudioLevel::~AudioLevel() {} > >-int8_t AudioLevel::Level() const { >- rtc::CritScope cs(&crit_sect_); >- return current_level_; >-} >- > int16_t AudioLevel::LevelFullRange() const { > rtc::CritScope cs(&crit_sect_); > return current_level_full_range_; >@@ -44,7 +32,6 @@ void AudioLevel::Clear() { > rtc::CritScope cs(&crit_sect_); > abs_max_ = 0; > count_ = 0; >- current_level_ = 0; > current_level_full_range_ = 0; > } > >@@ -60,10 +47,12 @@ double AudioLevel::TotalDuration() const { > > void AudioLevel::ComputeLevel(const AudioFrame& audioFrame, double duration) { > // Check speech level (works for 2 channels as well) >- int16_t abs_value = audioFrame.muted() ? 0 : >- WebRtcSpl_MaxAbsValueW16( >- audioFrame.data(), >- audioFrame.samples_per_channel_ * audioFrame.num_channels_); >+ int16_t abs_value = >+ audioFrame.muted() >+ ? 0 >+ : WebRtcSpl_MaxAbsValueW16( >+ audioFrame.data(), >+ audioFrame.samples_per_channel_ * audioFrame.num_channels_); > > // Protect member access using a lock since this method is called on a > // dedicated audio thread in the RecordedDataIsAvailable() callback. >@@ -78,18 +67,6 @@ void AudioLevel::ComputeLevel(const AudioFrame& audioFrame, double duration) { > > count_ = 0; > >- // Highest value for a int16_t is 0x7fff = 32767 >- // Divide with 1000 to get in the range of 0-32 which is the range of the >- // permutation vector >- int32_t position = abs_max_ / 1000; >- >- // Make it less likely that the bar stays at position 0. I.e. only if it's >- // in the range 0-250 (instead of 0-1000) >- if ((position == 0) && (abs_max_ > 250)) { >- position = 1; >- } >- current_level_ = kPermutation[position]; >- > // Decay the absolute maximum (divide by 4) > abs_max_ >>= 2; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.h >similarity index 84% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.h >index a1951edba90..3bbe5fdd201 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/audio_level.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_level.h >@@ -8,12 +8,11 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef VOICE_ENGINE_AUDIO_LEVEL_H_ >-#define VOICE_ENGINE_AUDIO_LEVEL_H_ >+#ifndef AUDIO_AUDIO_LEVEL_H_ >+#define AUDIO_AUDIO_LEVEL_H_ > > #include "rtc_base/criticalsection.h" > #include "rtc_base/thread_annotations.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -26,8 +25,7 @@ class AudioLevel { > ~AudioLevel(); > > // Called on "API thread(s)" from APIs like VoEBase::CreateChannel(), >- // VoEBase::StopSend(), VoEVolumeControl::GetSpeechOutputLevel(). >- int8_t Level() const; >+ // VoEBase::StopSend() > int16_t LevelFullRange() const; > void Clear(); > // See the description for "totalAudioEnergy" in the WebRTC stats spec >@@ -47,7 +45,6 @@ class AudioLevel { > > int16_t abs_max_ RTC_GUARDED_BY(crit_sect_); > int16_t count_ RTC_GUARDED_BY(crit_sect_); >- int8_t current_level_ RTC_GUARDED_BY(crit_sect_); > int16_t current_level_full_range_ RTC_GUARDED_BY(crit_sect_); > > double total_energy_ RTC_GUARDED_BY(crit_sect_) = 0.0; >@@ -57,4 +54,4 @@ class AudioLevel { > } // namespace voe > } // namespace webrtc > >-#endif // VOICE_ENGINE_AUDIO_LEVEL_H_ >+#endif // AUDIO_AUDIO_LEVEL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.cc >index 294dad0094b..b507afc1676 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.cc >@@ -16,20 +16,21 @@ > #include "api/call/audio_sink.h" > #include "audio/audio_send_stream.h" > #include "audio/audio_state.h" >+#include "audio/channel_proxy.h" > #include "audio/conversion.h" > #include "call/rtp_stream_receiver_controller_interface.h" > #include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" >-#include "modules/rtp_rtcp/include/rtp_receiver.h" > #include "modules/rtp_rtcp/include/rtp_rtcp.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" >+#include "rtc_base/strings/string_builder.h" > #include "rtc_base/timeutils.h" >-#include "voice_engine/channel_proxy.h" > > namespace webrtc { > > std::string AudioReceiveStream::Config::Rtp::ToString() const { >- std::stringstream ss; >+ char ss_buf[1024]; >+ rtc::SimpleStringBuilder ss(ss_buf); > ss << "{remote_ssrc: " << remote_ssrc; > ss << ", local_ssrc: " << local_ssrc; > ss << ", transport_cc: " << (transport_cc ? "on" : "off"); >@@ -47,7 +48,8 @@ std::string AudioReceiveStream::Config::Rtp::ToString() const { > } > > std::string AudioReceiveStream::Config::ToString() const { >- std::stringstream ss; >+ char ss_buf[1024]; >+ rtc::SimpleStringBuilder ss(ss_buf); > ss << "{rtp: " << rtp.ToString(); > ss << ", rtcp_send_transport: " > << (rtcp_send_transport ? "(Transport)" : "null"); >@@ -63,17 +65,16 @@ namespace { > std::unique_ptr<voe::ChannelProxy> CreateChannelAndProxy( > webrtc::AudioState* audio_state, > ProcessThread* module_process_thread, >- const webrtc::AudioReceiveStream::Config& config) { >+ const webrtc::AudioReceiveStream::Config& config, >+ RtcEventLog* event_log) { > RTC_DCHECK(audio_state); > internal::AudioState* internal_audio_state = > static_cast<internal::AudioState*>(audio_state); >- return std::unique_ptr<voe::ChannelProxy>(new voe::ChannelProxy( >- std::unique_ptr<voe::Channel>(new voe::Channel( >- module_process_thread, >- internal_audio_state->audio_device_module(), >- config.jitter_buffer_max_packets, >- config.jitter_buffer_fast_accelerate, >- config.decoder_factory)))); >+ return absl::make_unique<voe::ChannelProxy>(absl::make_unique<voe::Channel>( >+ module_process_thread, internal_audio_state->audio_device_module(), >+ nullptr /* RtcpRttStats */, event_log, config.rtp.remote_ssrc, >+ config.jitter_buffer_max_packets, config.jitter_buffer_fast_accelerate, >+ config.decoder_factory, config.codec_pair_id)); > } > } // namespace > >@@ -91,7 +92,8 @@ AudioReceiveStream::AudioReceiveStream( > event_log, > CreateChannelAndProxy(audio_state.get(), > module_process_thread, >- config)) {} >+ config, >+ event_log)) {} > > AudioReceiveStream::AudioReceiveStream( > RtpStreamReceiverControllerInterface* receiver_controller, >@@ -100,9 +102,8 @@ AudioReceiveStream::AudioReceiveStream( > const rtc::scoped_refptr<webrtc::AudioState>& audio_state, > webrtc::RtcEventLog* event_log, > std::unique_ptr<voe::ChannelProxy> channel_proxy) >- : audio_state_(audio_state), >- channel_proxy_(std::move(channel_proxy)) { >- RTC_LOG(LS_INFO) << "AudioReceiveStream: " << config.ToString(); >+ : audio_state_(audio_state), channel_proxy_(std::move(channel_proxy)) { >+ RTC_LOG(LS_INFO) << "AudioReceiveStream: " << config.rtp.remote_ssrc; > RTC_DCHECK(receiver_controller); > RTC_DCHECK(packet_router); > RTC_DCHECK(config.decoder_factory); >@@ -111,34 +112,30 @@ AudioReceiveStream::AudioReceiveStream( > > module_process_thread_checker_.DetachFromThread(); > >- channel_proxy_->SetRtcEventLog(event_log); > channel_proxy_->RegisterTransport(config.rtcp_send_transport); > > // Configure bandwidth estimation. > channel_proxy_->RegisterReceiverCongestionControlObjects(packet_router); > > // Register with transport. >- rtp_stream_receiver_ = >- receiver_controller->CreateReceiver(config.rtp.remote_ssrc, >- channel_proxy_.get()); >+ rtp_stream_receiver_ = receiver_controller->CreateReceiver( >+ config.rtp.remote_ssrc, channel_proxy_.get()); > > ConfigureStream(this, config, true); > } > > AudioReceiveStream::~AudioReceiveStream() { > RTC_DCHECK_RUN_ON(&worker_thread_checker_); >- RTC_LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString(); >+ RTC_LOG(LS_INFO) << "~AudioReceiveStream: " << config_.rtp.remote_ssrc; > Stop(); > channel_proxy_->DisassociateSendChannel(); > channel_proxy_->RegisterTransport(nullptr); > channel_proxy_->ResetReceiverCongestionControlObjects(); >- channel_proxy_->SetRtcEventLog(nullptr); > } > > void AudioReceiveStream::Reconfigure( > const webrtc::AudioReceiveStream::Config& config) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- RTC_LOG(LS_INFO) << "AudioReceiveStream::Reconfigure: " << config_.ToString(); > ConfigureStream(this, config, false); > } > >@@ -222,11 +219,6 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const { > return stats; > } > >-int AudioReceiveStream::GetOutputLevel() const { >- RTC_DCHECK_RUN_ON(&worker_thread_checker_); >- return channel_proxy_->GetSpeechOutputLevel(); >-} >- > void AudioReceiveStream::SetSink(AudioSinkInterface* sink) { > RTC_DCHECK_RUN_ON(&worker_thread_checker_); > channel_proxy_->SetSink(sink); >@@ -261,30 +253,14 @@ int AudioReceiveStream::id() const { > return config_.rtp.remote_ssrc; > } > >-rtc::Optional<Syncable::Info> AudioReceiveStream::GetInfo() const { >+absl::optional<Syncable::Info> AudioReceiveStream::GetInfo() const { > RTC_DCHECK_RUN_ON(&module_process_thread_checker_); >- Syncable::Info info; >- >- RtpRtcp* rtp_rtcp = nullptr; >- RtpReceiver* rtp_receiver = nullptr; >- channel_proxy_->GetRtpRtcp(&rtp_rtcp, &rtp_receiver); >- RTC_DCHECK(rtp_rtcp); >- RTC_DCHECK(rtp_receiver); >- >- if (!rtp_receiver->GetLatestTimestamps( >- &info.latest_received_capture_timestamp, >- &info.latest_receive_time_ms)) { >- return rtc::nullopt; >- } >- if (rtp_rtcp->RemoteNTP(&info.capture_time_ntp_secs, >- &info.capture_time_ntp_frac, >- nullptr, >- nullptr, >- &info.capture_time_source_clock) != 0) { >- return rtc::nullopt; >- } >+ absl::optional<Syncable::Info> info = channel_proxy_->GetSyncInfo(); >+ >+ if (!info) >+ return absl::nullopt; > >- info.current_delay_ms = channel_proxy_->GetDelayEstimate(); >+ info->current_delay_ms = channel_proxy_->GetDelayEstimate(); > return info; > } > >@@ -333,8 +309,8 @@ const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const { > return config_; > } > >-const AudioSendStream* >- AudioReceiveStream::GetAssociatedSendStreamForTesting() const { >+const AudioSendStream* AudioReceiveStream::GetAssociatedSendStreamForTesting() >+ const { > RTC_DCHECK_RUN_ON(&worker_thread_checker_); > return associated_send_stream_; > } >@@ -348,6 +324,8 @@ internal::AudioState* AudioReceiveStream::audio_state() const { > void AudioReceiveStream::ConfigureStream(AudioReceiveStream* stream, > const Config& new_config, > bool first_time) { >+ RTC_LOG(LS_INFO) << "AudioReceiveStream::ConfigureStream: " >+ << new_config.ToString(); > RTC_DCHECK(stream); > const auto& channel_proxy = stream->channel_proxy_; > const auto& old_config = stream->config_; >@@ -365,6 +343,12 @@ void AudioReceiveStream::ConfigureStream(AudioReceiveStream* stream, > if (first_time || old_config.rtp.local_ssrc != new_config.rtp.local_ssrc) { > channel_proxy->SetLocalSSRC(new_config.rtp.local_ssrc); > } >+ >+ if (!first_time) { >+ // Remote ssrc can't be changed mid-stream. >+ RTC_DCHECK_EQ(old_config.rtp.remote_ssrc, new_config.rtp.remote_ssrc); >+ } >+ > // TODO(solenberg): Config NACK history window (which is a packet count), > // using the actual packet size for the configured codec. > if (first_time || old_config.rtp.nack.rtp_history_ms != >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.h >index 7d0eed9cb21..64552e35c0d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream.h >@@ -15,6 +15,7 @@ > #include <vector> > > #include "api/audio/audio_mixer.h" >+#include "api/rtp_headers.h" > #include "audio/audio_state.h" > #include "call/audio_receive_stream.h" > #include "call/rtp_packet_sink_interface.h" >@@ -61,7 +62,6 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream, > void Start() override; > void Stop() override; > webrtc::AudioReceiveStream::Stats GetStats() const override; >- int GetOutputLevel() const override; > void SetSink(AudioSinkInterface* sink) override; > void SetGain(float gain) override; > std::vector<webrtc::RtpSource> GetSources() const override; >@@ -80,7 +80,7 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream, > > // Syncable > int id() const override; >- rtc::Optional<Syncable::Info> GetInfo() const override; >+ absl::optional<Syncable::Info> GetInfo() const override; > uint32_t GetPlayoutTimestamp() const override; > void SetMinimumPlayoutDelay(int delay_ms) override; > >@@ -104,7 +104,7 @@ class AudioReceiveStream final : public webrtc::AudioReceiveStream, > std::unique_ptr<voe::ChannelProxy> channel_proxy_; > AudioSendStream* associated_send_stream_ = nullptr; > >- bool playing_ RTC_ACCESS_ON(worker_thread_checker_) = false; >+ bool playing_ RTC_GUARDED_BY(worker_thread_checker_) = false; > > std::unique_ptr<RtpStreamReceiverInterface> rtp_stream_receiver_; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream_unittest.cc >index c8318aa967c..eb93bd0aa5d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_receive_stream_unittest.cc >@@ -15,6 +15,7 @@ > #include "api/test/mock_audio_mixer.h" > #include "audio/audio_receive_stream.h" > #include "audio/conversion.h" >+#include "audio/mock_voe_channel_proxy.h" > #include "call/rtp_stream_receiver_controller.h" > #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" > #include "modules/audio_device/include/mock_audio_device.h" >@@ -24,7 +25,6 @@ > #include "modules/rtp_rtcp/source/byte_io.h" > #include "test/gtest.h" > #include "test/mock_audio_decoder_factory.h" >-#include "test/mock_voe_channel_proxy.h" > > namespace webrtc { > namespace test { >@@ -59,18 +59,16 @@ const unsigned int kSpeechOutputLevel = 99; > const double kTotalOutputEnergy = 0.25; > const double kTotalOutputDuration = 0.5; > >-const CallStatistics kCallStats = { >- 345, 678, 901, 234, -12, 3456, 7890, 567, 890, 123}; >-const CodecInst kCodecInst = { >- 123, "codec_name_recv", 96000, -187, 0, -103}; >+const CallStatistics kCallStats = {345, 678, 901, 234, -12, >+ 3456, 7890, 567, 890, 123}; >+const CodecInst kCodecInst = {123, "codec_name_recv", 96000, -187, 0, -103}; > const NetworkStatistics kNetworkStats = { > 123, 456, false, 789012, 3456, 123, 456, 0, {}, 789, 12, > 345, 678, 901, 0, -1, -1, -1, -1, -1, 0}; > const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest(); > > struct ConfigHelper { >- ConfigHelper() >- : ConfigHelper(new rtc::RefCountedObject<MockAudioMixer>()) {} >+ ConfigHelper() : ConfigHelper(new rtc::RefCountedObject<MockAudioMixer>()) {} > > explicit ConfigHelper(rtc::scoped_refptr<MockAudioMixer> audio_mixer) > : audio_mixer_(audio_mixer) { >@@ -87,23 +85,16 @@ struct ConfigHelper { > EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kLocalSsrc)).Times(1); > EXPECT_CALL(*channel_proxy_, SetNACKStatus(true, 15)).Times(1); > EXPECT_CALL(*channel_proxy_, >- RegisterReceiverCongestionControlObjects(&packet_router_)) >- .Times(1); >+ RegisterReceiverCongestionControlObjects(&packet_router_)) >+ .Times(1); > EXPECT_CALL(*channel_proxy_, ResetReceiverCongestionControlObjects()) > .Times(1); > EXPECT_CALL(*channel_proxy_, RegisterTransport(nullptr)).Times(2); >- testing::Expectation expect_set = >- EXPECT_CALL(*channel_proxy_, SetRtcEventLog(&event_log_)) >- .Times(1); >- EXPECT_CALL(*channel_proxy_, SetRtcEventLog(testing::IsNull())) >- .Times(1) >- .After(expect_set); > EXPECT_CALL(*channel_proxy_, DisassociateSendChannel()).Times(1); > EXPECT_CALL(*channel_proxy_, SetReceiveCodecs(_)) >- .WillRepeatedly( >- Invoke([](const std::map<int, SdpAudioFormat>& codecs) { >- EXPECT_THAT(codecs, testing::IsEmpty()); >- })); >+ .WillRepeatedly(Invoke([](const std::map<int, SdpAudioFormat>& codecs) { >+ EXPECT_THAT(codecs, testing::IsEmpty()); >+ })); > > stream_config_.rtp.local_ssrc = kLocalSsrc; > stream_config_.rtp.remote_ssrc = kRemoteSsrc; >@@ -119,11 +110,8 @@ struct ConfigHelper { > std::unique_ptr<internal::AudioReceiveStream> CreateAudioReceiveStream() { > return std::unique_ptr<internal::AudioReceiveStream>( > new internal::AudioReceiveStream( >- &rtp_stream_receiver_controller_, >- &packet_router_, >- stream_config_, >- audio_state_, >- &event_log_, >+ &rtp_stream_receiver_controller_, &packet_router_, stream_config_, >+ audio_state_, &event_log_, > std::unique_ptr<voe::ChannelProxy>(channel_proxy_))); > } > >@@ -242,11 +230,11 @@ TEST(AudioReceiveStreamTest, ReceiveRtpPacket) { > const int kTransportSequenceNumberValue = 1234; > std::vector<uint8_t> rtp_packet = CreateRtpHeaderWithOneByteExtension( > kTransportSequenceNumberId, kTransportSequenceNumberValue, 2); >- PacketTime packet_time(5678000, 0); >+ constexpr int64_t packet_time_us = 5678000; > > RtpPacketReceived parsed_packet; > ASSERT_TRUE(parsed_packet.Parse(&rtp_packet[0], rtp_packet.size())); >- parsed_packet.set_arrival_time_ms((packet_time.timestamp + 500) / 1000); >+ parsed_packet.set_arrival_time_ms((packet_time_us + 500) / 1000); > > EXPECT_CALL(*helper.channel_proxy(), > OnRtpPacket(testing::Ref(parsed_packet))); >@@ -322,7 +310,7 @@ TEST(AudioReceiveStreamTest, SetGain) { > ConfigHelper helper; > auto recv_stream = helper.CreateAudioReceiveStream(); > EXPECT_CALL(*helper.channel_proxy(), >- SetChannelOutputVolumeScaling(FloatEq(0.765f))); >+ SetChannelOutputVolumeScaling(FloatEq(0.765f))); > recv_stream->SetGain(0.765f); > } > >@@ -370,10 +358,10 @@ TEST(AudioReceiveStreamTest, ReconfigureWithUpdatedConfig) { > new_config.rtp.nack.rtp_history_ms = 300 + 20; > new_config.rtp.extensions.clear(); > new_config.rtp.extensions.push_back( >- RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId + 1)); >- new_config.rtp.extensions.push_back(RtpExtension( >- RtpExtension::kTransportSequenceNumberUri, >- kTransportSequenceNumberId + 1)); >+ RtpExtension(RtpExtension::kAudioLevelUri, kAudioLevelId + 1)); >+ new_config.rtp.extensions.push_back( >+ RtpExtension(RtpExtension::kTransportSequenceNumberUri, >+ kTransportSequenceNumberId + 1)); > new_config.decoder_map.emplace(1, SdpAudioFormat("foo", 8000, 1)); > > MockVoEChannelProxy& channel_proxy = *helper.channel_proxy(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.cc >index 053302e22b8..0f725c4da17 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.cc >@@ -14,21 +14,21 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" >+ > #include "audio/audio_state.h" >+#include "audio/channel_proxy.h" > #include "audio/conversion.h" > #include "call/rtp_transport_controller_send_interface.h" > #include "modules/audio_coding/codecs/cng/audio_encoder_cng.h" >-#include "modules/bitrate_controller/include/bitrate_controller.h" >-#include "modules/congestion_controller/include/send_side_congestion_controller.h" >-#include "modules/pacing/paced_sender.h" > #include "rtc_base/checks.h" > #include "rtc_base/event.h" > #include "rtc_base/function_view.h" > #include "rtc_base/logging.h" >+#include "rtc_base/strings/audio_format_to_string.h" > #include "rtc_base/task_queue.h" > #include "rtc_base/timeutils.h" > #include "system_wrappers/include/field_trial.h" >-#include "voice_engine/channel_proxy.h" > > namespace webrtc { > namespace internal { >@@ -49,15 +49,15 @@ void CallEncoder(const std::unique_ptr<voe::ChannelProxy>& channel_proxy, > std::unique_ptr<voe::ChannelProxy> CreateChannelAndProxy( > webrtc::AudioState* audio_state, > rtc::TaskQueue* worker_queue, >- ProcessThread* module_process_thread) { >+ ProcessThread* module_process_thread, >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcEventLog* event_log) { > RTC_DCHECK(audio_state); > internal::AudioState* internal_audio_state = > static_cast<internal::AudioState*>(audio_state); >- return std::unique_ptr<voe::ChannelProxy>(new voe::ChannelProxy( >- std::unique_ptr<voe::Channel>(new voe::Channel( >- worker_queue, >- module_process_thread, >- internal_audio_state->audio_device_module())))); >+ return absl::make_unique<voe::ChannelProxy>(absl::make_unique<voe::Channel>( >+ worker_queue, module_process_thread, >+ internal_audio_state->audio_device_module(), rtcp_rtt_stats, event_log)); > } > } // namespace > >@@ -93,7 +93,7 @@ AudioSendStream::AudioSendStream( > BitrateAllocator* bitrate_allocator, > RtcEventLog* event_log, > RtcpRttStats* rtcp_rtt_stats, >- const rtc::Optional<RtpState>& suspended_rtp_state, >+ const absl::optional<RtpState>& suspended_rtp_state, > TimeInterval* overall_call_lifetime) > : AudioSendStream(config, > audio_state, >@@ -106,7 +106,9 @@ AudioSendStream::AudioSendStream( > overall_call_lifetime, > CreateChannelAndProxy(audio_state.get(), > worker_queue, >- module_process_thread)) {} >+ module_process_thread, >+ rtcp_rtt_stats, >+ event_log)) {} > > AudioSendStream::AudioSendStream( > const webrtc::AudioSendStream::Config& config, >@@ -116,7 +118,7 @@ AudioSendStream::AudioSendStream( > BitrateAllocator* bitrate_allocator, > RtcEventLog* event_log, > RtcpRttStats* rtcp_rtt_stats, >- const rtc::Optional<RtpState>& suspended_rtp_state, >+ const absl::optional<RtpState>& suspended_rtp_state, > TimeInterval* overall_call_lifetime, > std::unique_ptr<voe::ChannelProxy> channel_proxy) > : worker_queue_(worker_queue), >@@ -132,38 +134,32 @@ AudioSendStream::AudioSendStream( > rtp_rtcp_module_(nullptr), > suspended_rtp_state_(suspended_rtp_state), > overall_call_lifetime_(overall_call_lifetime) { >- RTC_LOG(LS_INFO) << "AudioSendStream: " << config.ToString(); >+ RTC_LOG(LS_INFO) << "AudioSendStream: " << config.rtp.ssrc; > RTC_DCHECK(worker_queue_); > RTC_DCHECK(audio_state_); > RTC_DCHECK(channel_proxy_); > RTC_DCHECK(bitrate_allocator_); > RTC_DCHECK(transport); >- RTC_DCHECK(transport->send_side_cc()); > RTC_DCHECK(overall_call_lifetime_); > >- channel_proxy_->SetRtcEventLog(event_log_); >- channel_proxy_->SetRtcpRttStats(rtcp_rtt_stats); > channel_proxy_->SetRTCPStatus(true); >- RtpReceiver* rtpReceiver = nullptr; // Unused, but required for call. >- channel_proxy_->GetRtpRtcp(&rtp_rtcp_module_, &rtpReceiver); >+ rtp_rtcp_module_ = channel_proxy_->GetRtpRtcp(); > RTC_DCHECK(rtp_rtcp_module_); > > ConfigureStream(this, config, true); > > pacer_thread_checker_.DetachFromThread(); > // Signal congestion controller this object is ready for OnPacket* callbacks. >- transport_->send_side_cc()->RegisterPacketFeedbackObserver(this); >+ transport_->RegisterPacketFeedbackObserver(this); > } > > AudioSendStream::~AudioSendStream() { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- RTC_LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString(); >+ RTC_LOG(LS_INFO) << "~AudioSendStream: " << config_.rtp.ssrc; > RTC_DCHECK(!sending_); >- transport_->send_side_cc()->DeRegisterPacketFeedbackObserver(this); >+ transport_->DeRegisterPacketFeedbackObserver(this); > channel_proxy_->RegisterTransport(nullptr); > channel_proxy_->ResetSenderCongestionControlObjects(); >- channel_proxy_->SetRtcEventLog(nullptr); >- channel_proxy_->SetRtcpRttStats(nullptr); > // Lifetime can only be updated after deregistering > // |timed_send_transport_adapter_| in the underlying channel object to avoid > // data races in |active_lifetime_|. >@@ -189,6 +185,8 @@ AudioSendStream::ExtensionIds AudioSendStream::FindExtensionIds( > ids.audio_level = extension.id; > } else if (extension.uri == RtpExtension::kTransportSequenceNumberUri) { > ids.transport_sequence_number = extension.id; >+ } else if (extension.uri == RtpExtension::kMidUri) { >+ ids.mid = extension.id; > } > } > return ids; >@@ -198,7 +196,8 @@ void AudioSendStream::ConfigureStream( > webrtc::internal::AudioSendStream* stream, > const webrtc::AudioSendStream::Config& new_config, > bool first_time) { >- RTC_LOG(LS_INFO) << "AudioSendStream::Configuring: " << new_config.ToString(); >+ RTC_LOG(LS_INFO) << "AudioSendStream::ConfigureStream: " >+ << new_config.ToString(); > const auto& channel_proxy = stream->channel_proxy_; > const auto& old_config = stream->config_; > >@@ -219,8 +218,7 @@ void AudioSendStream::ConfigureStream( > new_config.rtp.nack.rtp_history_ms / 20); > } > >- if (first_time || >- new_config.send_transport != old_config.send_transport) { >+ if (first_time || new_config.send_transport != old_config.send_transport) { > if (old_config.send_transport) { > channel_proxy->RegisterTransport(nullptr); > } >@@ -243,28 +241,38 @@ void AudioSendStream::ConfigureStream( > } > bool transport_seq_num_id_changed = > new_ids.transport_sequence_number != old_ids.transport_sequence_number; >- if (first_time || transport_seq_num_id_changed) { >+ if (first_time || >+ (transport_seq_num_id_changed && >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"))) { > if (!first_time) { > channel_proxy->ResetSenderCongestionControlObjects(); > } > > RtcpBandwidthObserver* bandwidth_observer = nullptr; >- bool has_transport_sequence_number = new_ids.transport_sequence_number != 0; >+ bool has_transport_sequence_number = >+ new_ids.transport_sequence_number != 0 && >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"); > if (has_transport_sequence_number) { > channel_proxy->EnableSendTransportSequenceNumber( > new_ids.transport_sequence_number); > // Probing in application limited region is only used in combination with > // send side congestion control, wich depends on feedback packets which > // requires transport sequence numbers to be enabled. >- stream->transport_->send_side_cc()->EnablePeriodicAlrProbing(true); >- bandwidth_observer = >- stream->transport_->send_side_cc()->GetBandwidthObserver(); >+ stream->transport_->EnablePeriodicAlrProbing(true); >+ bandwidth_observer = stream->transport_->GetBandwidthObserver(); > } > > channel_proxy->RegisterSenderCongestionControlObjects(stream->transport_, > bandwidth_observer); > } > >+ // MID RTP header extension. >+ if ((first_time || new_ids.mid != old_ids.mid || >+ new_config.rtp.mid != old_config.rtp.mid) && >+ new_ids.mid != 0 && !new_config.rtp.mid.empty()) { >+ channel_proxy->SetMid(new_config.rtp.mid, new_ids.mid); >+ } >+ > if (!ReconfigureSendCodec(stream, new_config)) { > RTC_LOG(LS_ERROR) << "Failed to set up send codec state."; > } >@@ -281,14 +289,18 @@ void AudioSendStream::Start() { > return; > } > >+ bool has_transport_sequence_number = >+ FindExtensionIds(config_.rtp.extensions).transport_sequence_number != 0 && >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-ForceNoTWCC"); > if (config_.min_bitrate_bps != -1 && config_.max_bitrate_bps != -1 && >- (FindExtensionIds(config_.rtp.extensions).transport_sequence_number != >- 0 || >- !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) { >+ (has_transport_sequence_number || >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe") || >+ webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC"))) { > // Audio BWE is enabled. > transport_->packet_sender()->SetAccountForAudioPackets(true); > ConfigureBitrateObserver(config_.min_bitrate_bps, config_.max_bitrate_bps, >- config_.bitrate_priority); >+ config_.bitrate_priority, >+ has_transport_sequence_number); > } > channel_proxy_->StartSend(); > sending_ = true; >@@ -314,7 +326,8 @@ void AudioSendStream::SendAudioData(std::unique_ptr<AudioFrame> audio_frame) { > } > > bool AudioSendStream::SendTelephoneEvent(int payload_type, >- int payload_frequency, int event, >+ int payload_frequency, >+ int event, > int duration_ms) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type, >@@ -397,14 +410,19 @@ uint32_t AudioSendStream::OnBitrateUpdated(uint32_t bitrate_bps, > uint8_t fraction_loss, > int64_t rtt, > int64_t bwe_period_ms) { >+ // Audio transport feedback will not be reported in this mode, instead update >+ // acknowledged bitrate estimator with the bitrate allocated for audio. >+ if (webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC")) { >+ transport_->SetAllocatedBitrateWithoutFeedback(bitrate_bps); >+ } >+ > // A send stream may be allocated a bitrate of zero if the allocator decides > // to disable it. For now we ignore this decision and keep sending on min > // bitrate. > if (bitrate_bps == 0) { > bitrate_bps = config_.min_bitrate_bps; > } >- RTC_DCHECK_GE(bitrate_bps, >- static_cast<uint32_t>(config_.min_bitrate_bps)); >+ RTC_DCHECK_GE(bitrate_bps, static_cast<uint32_t>(config_.min_bitrate_bps)); > // The bitrate allocator might allocate an higher than max configured bitrate > // if there is room, to allow for, as example, extra FEC. Ignore that for now. > const uint32_t max_bitrate_bps = config_.max_bitrate_bps; >@@ -433,8 +451,8 @@ void AudioSendStream::OnPacketAdded(uint32_t ssrc, uint16_t seq_num) { > void AudioSendStream::OnPacketFeedbackVector( > const std::vector<PacketFeedback>& packet_feedback_vector) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- rtc::Optional<float> plr; >- rtc::Optional<float> rplr; >+ absl::optional<float> plr; >+ absl::optional<float> rplr; > { > rtc::CritScope lock(&packet_loss_tracker_cs_); > packet_loss_tracker_.OnPacketFeedbackVector(packet_feedback_vector); >@@ -454,8 +472,6 @@ void AudioSendStream::OnPacketFeedbackVector( > > void AudioSendStream::SetTransportOverhead(int transport_overhead_per_packet) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- transport_->send_side_cc()->SetTransportOverhead( >- transport_overhead_per_packet); > channel_proxy_->SetTransportOverhead(transport_overhead_per_packet); > } > >@@ -501,16 +517,25 @@ bool AudioSendStream::SetupSendCodec(AudioSendStream* stream, > > RTC_DCHECK(new_config.encoder_factory); > std::unique_ptr<AudioEncoder> encoder = >- new_config.encoder_factory->MakeAudioEncoder(spec.payload_type, >- spec.format); >+ new_config.encoder_factory->MakeAudioEncoder( >+ spec.payload_type, spec.format, new_config.codec_pair_id); > > if (!encoder) { >- RTC_LOG(LS_ERROR) << "Unable to create encoder for " << spec.format; >+ RTC_DLOG(LS_ERROR) << "Unable to create encoder for " >+ << rtc::ToString(spec.format); > return false; > } >+ >+ // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is >+ // not enabled, do not update target audio bitrate if we are in >+ // WebRTC-Audio-SendSideBwe-For-Video experiment >+ const bool do_not_update_target_bitrate = >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") && >+ webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") && >+ !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number; > // If a bitrate has been specified for the codec, use it over the > // codec's default. >- if (spec.target_bitrate_bps) { >+ if (!do_not_update_target_bitrate && spec.target_bitrate_bps) { > encoder->OnReceivedTargetAudioBitrate(*spec.target_bitrate_bps); > } > >@@ -518,8 +543,8 @@ bool AudioSendStream::SetupSendCodec(AudioSendStream* stream, > if (new_config.audio_network_adaptor_config) { > if (encoder->EnableAudioNetworkAdaptor( > *new_config.audio_network_adaptor_config, stream->event_log_)) { >- RTC_LOG(LS_INFO) << "Audio network adaptor enabled on SSRC " >- << new_config.rtp.ssrc; >+ RTC_DLOG(LS_INFO) << "Audio network adaptor enabled on SSRC " >+ << new_config.rtp.ssrc; > } else { > RTC_NOTREACHED(); > } >@@ -573,11 +598,19 @@ bool AudioSendStream::ReconfigureSendCodec(AudioSendStream* stream, > return SetupSendCodec(stream, new_config); > } > >- const rtc::Optional<int>& new_target_bitrate_bps = >+ // If other side does not support audio TWCC and WebRTC-Audio-ABWENoTWCC is >+ // not enabled, do not update target audio bitrate if we are in >+ // WebRTC-Audio-SendSideBwe-For-Video experiment >+ const bool do_not_update_target_bitrate = >+ !webrtc::field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC") && >+ webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe-For-Video") && >+ !FindExtensionIds(new_config.rtp.extensions).transport_sequence_number; >+ >+ const absl::optional<int>& new_target_bitrate_bps = > new_config.send_codec_spec->target_bitrate_bps; > // If a bitrate has been specified for the codec, use it over the > // codec's default. >- if (new_target_bitrate_bps && >+ if (!do_not_update_target_bitrate && new_target_bitrate_bps && > new_target_bitrate_bps != > old_config.send_codec_spec->target_bitrate_bps) { > CallEncoder(stream->channel_proxy_, [&](AudioEncoder* encoder) { >@@ -601,8 +634,8 @@ void AudioSendStream::ReconfigureANA(AudioSendStream* stream, > CallEncoder(stream->channel_proxy_, [&](AudioEncoder* encoder) { > if (encoder->EnableAudioNetworkAdaptor( > *new_config.audio_network_adaptor_config, stream->event_log_)) { >- RTC_LOG(LS_INFO) << "Audio network adaptor enabled on SSRC " >- << new_config.rtp.ssrc; >+ RTC_DLOG(LS_INFO) << "Audio network adaptor enabled on SSRC " >+ << new_config.rtp.ssrc; > } else { > RTC_NOTREACHED(); > } >@@ -611,8 +644,8 @@ void AudioSendStream::ReconfigureANA(AudioSendStream* stream, > CallEncoder(stream->channel_proxy_, [&](AudioEncoder* encoder) { > encoder->DisableAudioNetworkAdaptor(); > }); >- RTC_LOG(LS_INFO) << "Audio network adaptor disabled on SSRC " >- << new_config.rtp.ssrc; >+ RTC_DLOG(LS_INFO) << "Audio network adaptor disabled on SSRC " >+ << new_config.rtp.ssrc; > } > } > >@@ -676,12 +709,13 @@ void AudioSendStream::ReconfigureBitrateObserver( > return; > } > >+ bool has_transport_sequence_number = new_transport_seq_num_id != 0; > if (new_config.min_bitrate_bps != -1 && new_config.max_bitrate_bps != -1 && >- (new_transport_seq_num_id != 0 || >+ (has_transport_sequence_number || > !webrtc::field_trial::IsEnabled("WebRTC-Audio-SendSideBwe"))) { >- stream->ConfigureBitrateObserver(new_config.min_bitrate_bps, >- new_config.max_bitrate_bps, >- new_config.bitrate_priority); >+ stream->ConfigureBitrateObserver( >+ new_config.min_bitrate_bps, new_config.max_bitrate_bps, >+ new_config.bitrate_priority, has_transport_sequence_number); > } else { > stream->RemoveBitrateObserver(); > } >@@ -689,7 +723,8 @@ void AudioSendStream::ReconfigureBitrateObserver( > > void AudioSendStream::ConfigureBitrateObserver(int min_bitrate_bps, > int max_bitrate_bps, >- double bitrate_priority) { >+ double bitrate_priority, >+ bool has_packet_feedback) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > RTC_DCHECK_GE(max_bitrate_bps, min_bitrate_bps); > rtc::Event thread_sync_event(false /* manual_reset */, false); >@@ -700,8 +735,11 @@ void AudioSendStream::ConfigureBitrateObserver(int min_bitrate_bps, > config_.max_bitrate_bps = max_bitrate_bps; > config_.bitrate_priority = bitrate_priority; > // This either updates the current observer or adds a new observer. >- bitrate_allocator_->AddObserver(this, min_bitrate_bps, max_bitrate_bps, 0, >- true, config_.track_id, bitrate_priority); >+ bitrate_allocator_->AddObserver( >+ this, MediaStreamAllocationConfig{ >+ static_cast<uint32_t>(min_bitrate_bps), >+ static_cast<uint32_t>(max_bitrate_bps), 0, true, >+ config_.track_id, bitrate_priority, has_packet_feedback}); > thread_sync_event.Set(); > }); > thread_sync_event.Wait(rtc::Event::kForever); >@@ -723,8 +761,8 @@ void AudioSendStream::RegisterCngPayloadType(int payload_type, > if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { > rtp_rtcp_module_->DeRegisterSendPayload(codec.pltype); > if (rtp_rtcp_module_->RegisterSendPayload(codec) != 0) { >- RTC_LOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to " >- "RTP/RTCP module"; >+ RTC_DLOG(LS_ERROR) << "RegisterCngPayloadType() failed to register CN to " >+ "RTP/RTCP module"; > } > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.h >index b2bcac54537..ba87202bbe3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream.h >@@ -15,6 +15,7 @@ > #include <vector> > > #include "audio/time_interval.h" >+#include "audio/transport_feedback_packet_loss_tracker.h" > #include "call/audio_send_stream.h" > #include "call/audio_state.h" > #include "call/bitrate_allocator.h" >@@ -22,7 +23,6 @@ > #include "rtc_base/constructormagic.h" > #include "rtc_base/race_checker.h" > #include "rtc_base/thread_checker.h" >-#include "voice_engine/transport_feedback_packet_loss_tracker.h" > > namespace webrtc { > class RtcEventLog; >@@ -49,7 +49,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, > BitrateAllocator* bitrate_allocator, > RtcEventLog* event_log, > RtcpRttStats* rtcp_rtt_stats, >- const rtc::Optional<RtpState>& suspended_rtp_state, >+ const absl::optional<RtpState>& suspended_rtp_state, > TimeInterval* overall_call_lifetime); > // For unit tests, which need to supply a mock channel proxy. > AudioSendStream(const webrtc::AudioSendStream::Config& config, >@@ -59,7 +59,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, > BitrateAllocator* bitrate_allocator, > RtcEventLog* event_log, > RtcpRttStats* rtcp_rtt_stats, >- const rtc::Optional<RtpState>& suspended_rtp_state, >+ const absl::optional<RtpState>& suspended_rtp_state, > TimeInterval* overall_call_lifetime, > std::unique_ptr<voe::ChannelProxy> channel_proxy); > ~AudioSendStream() override; >@@ -70,7 +70,9 @@ class AudioSendStream final : public webrtc::AudioSendStream, > void Start() override; > void Stop() override; > void SendAudioData(std::unique_ptr<AudioFrame> audio_frame) override; >- bool SendTelephoneEvent(int payload_type, int payload_frequency, int event, >+ bool SendTelephoneEvent(int payload_type, >+ int payload_frequency, >+ int event, > int duration_ms) override; > void SetMuted(bool muted) override; > webrtc::AudioSendStream::Stats GetStats() const override; >@@ -119,7 +121,8 @@ class AudioSendStream final : public webrtc::AudioSendStream, > > void ConfigureBitrateObserver(int min_bitrate_bps, > int max_bitrate_bps, >- double bitrate_priority); >+ double bitrate_priority, >+ bool has_packet_feedback); > void RemoveBitrateObserver(); > > void RegisterCngPayloadType(int payload_type, int clockrate_hz); >@@ -145,7 +148,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, > RTC_GUARDED_BY(&packet_loss_tracker_cs_); > > RtpRtcp* rtp_rtcp_module_; >- rtc::Optional<RtpState> const suspended_rtp_state_; >+ absl::optional<RtpState> const suspended_rtp_state_; > > std::unique_ptr<TimedTransport> timed_send_transport_adapter_; > TimeInterval active_lifetime_; >@@ -157,6 +160,7 @@ class AudioSendStream final : public webrtc::AudioSendStream, > struct ExtensionIds { > int audio_level = 0; > int transport_sequence_number = 0; >+ int mid = 0; > }; > static ExtensionIds FindExtensionIds( > const std::vector<RtpExtension>& extensions); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_tests.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_tests.cc >index 3f96c3350ff..7deeff3b4d1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_tests.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_tests.cc >@@ -20,15 +20,9 @@ class AudioSendTest : public SendTest { > public: > AudioSendTest() : SendTest(CallTest::kDefaultTimeoutMs) {} > >- size_t GetNumVideoStreams() const override { >- return 0; >- } >- size_t GetNumAudioStreams() const override { >- return 1; >- } >- size_t GetNumFlexfecStreams() const override { >- return 0; >- } >+ size_t GetNumVideoStreams() const override { return 0; } >+ size_t GetNumAudioStreams() const override { return 1; } >+ size_t GetNumFlexfecStreams() const override { return 0; } > }; > } // namespace > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_unittest.cc >index 109f15d1b2a..f5d6796af5e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_send_stream_unittest.cc >@@ -12,30 +12,27 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" >+#include "api/units/time_delta.h" > #include "audio/audio_send_stream.h" > #include "audio/audio_state.h" > #include "audio/conversion.h" >-#include "call/fake_rtp_transport_controller_send.h" >-#include "call/rtp_transport_controller_send_interface.h" >+#include "audio/mock_voe_channel_proxy.h" >+#include "call/test/mock_rtp_transport_controller_send.h" > #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" > #include "modules/audio_device/include/mock_audio_device.h" > #include "modules/audio_mixer/audio_mixer_impl.h" > #include "modules/audio_processing/include/audio_processing_statistics.h" > #include "modules/audio_processing/include/mock_audio_processing.h" >-#include "modules/congestion_controller/include/mock/mock_congestion_observer.h" >-#include "modules/congestion_controller/include/send_side_congestion_controller.h" >-#include "modules/pacing/mock/mock_paced_sender.h" >+#include "modules/rtp_rtcp/mocks/mock_rtcp_bandwidth_observer.h" > #include "modules/rtp_rtcp/mocks/mock_rtcp_rtt_stats.h" > #include "modules/rtp_rtcp/mocks/mock_rtp_rtcp.h" > #include "rtc_base/fakeclock.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/task_queue.h" >-#include "rtc_base/timedelta.h" > #include "test/gtest.h" > #include "test/mock_audio_encoder.h" > #include "test/mock_audio_encoder_factory.h" > #include "test/mock_transport.h" >-#include "test/mock_voe_channel_proxy.h" > > namespace webrtc { > namespace test { >@@ -59,8 +56,8 @@ const double kEchoReturnLoss = -65; > const double kEchoReturnLossEnhancement = 101; > const double kResidualEchoLikelihood = -1.0f; > const double kResidualEchoLikelihoodMax = 23.0f; >-const CallStatistics kCallStats = { >- 1345, 1678, 1901, 1234, 112, 13456, 17890, 1567, -1890, -1123}; >+const CallStatistics kCallStats = {1345, 1678, 1901, 1234, 112, >+ 13456, 17890, 1567, -1890, -1123}; > const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354}; > const int kTelephoneEventPayloadType = 123; > const int kTelephoneEventPayloadFrequency = 65432; >@@ -78,9 +75,11 @@ const AudioCodecSpec kCodecSpecs[] = { > > class MockLimitObserver : public BitrateAllocator::LimitObserver { > public: >- MOCK_METHOD2(OnAllocationLimitsChanged, >+ MOCK_METHOD4(OnAllocationLimitsChanged, > void(uint32_t min_send_bitrate_bps, >- uint32_t max_padding_bitrate_bps)); >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps, >+ bool has_packet_feedback)); > }; > > std::unique_ptr<MockAudioEncoder> SetupAudioEncoderMock( >@@ -88,7 +87,8 @@ std::unique_ptr<MockAudioEncoder> SetupAudioEncoderMock( > const SdpAudioFormat& format) { > for (const auto& spec : kCodecSpecs) { > if (format == spec.format) { >- std::unique_ptr<MockAudioEncoder> encoder(new MockAudioEncoder); >+ std::unique_ptr<MockAudioEncoder> encoder( >+ new testing::NiceMock<MockAudioEncoder>()); > ON_CALL(*encoder.get(), SampleRateHz()) > .WillByDefault(Return(spec.info.sample_rate_hz)); > ON_CALL(*encoder.get(), NumChannels()) >@@ -109,16 +109,17 @@ rtc::scoped_refptr<MockAudioEncoderFactory> SetupEncoderFactoryMock() { > std::begin(kCodecSpecs), std::end(kCodecSpecs)))); > ON_CALL(*factory.get(), QueryAudioEncoder(_)) > .WillByDefault(Invoke( >- [](const SdpAudioFormat& format) -> rtc::Optional<AudioCodecInfo> { >+ [](const SdpAudioFormat& format) -> absl::optional<AudioCodecInfo> { > for (const auto& spec : kCodecSpecs) { > if (format == spec.format) { > return spec.info; > } > } >- return rtc::nullopt; >+ return absl::nullopt; > })); >- ON_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _)) >+ ON_CALL(*factory.get(), MakeAudioEncoderMock(_, _, _, _)) > .WillByDefault(Invoke([](int payload_type, const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id, > std::unique_ptr<AudioEncoder>* return_value) { > *return_value = SetupAudioEncoderMock(payload_type, format); > })); >@@ -129,13 +130,6 @@ struct ConfigHelper { > ConfigHelper(bool audio_bwe_enabled, bool expect_set_encoder_call) > : stream_config_(nullptr), > audio_processing_(new rtc::RefCountedObject<MockAudioProcessing>()), >- simulated_clock_(123456), >- send_side_cc_(rtc::MakeUnique<SendSideCongestionController>( >- &simulated_clock_, >- nullptr /* observer */, >- &event_log_, >- &pacer_)), >- fake_transport_(&packet_router_, &pacer_, send_side_cc_.get()), > bitrate_allocator_(&limit_observer_), > worker_queue_("ConfigHelper_worker_queue"), > audio_encoder_(nullptr) { >@@ -171,8 +165,8 @@ struct ConfigHelper { > std::unique_ptr<internal::AudioSendStream> CreateAudioSendStream() { > return std::unique_ptr<internal::AudioSendStream>( > new internal::AudioSendStream( >- stream_config_, audio_state_, &worker_queue_, &fake_transport_, >- &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, rtc::nullopt, >+ stream_config_, audio_state_, &worker_queue_, &rtp_transport_, >+ &bitrate_allocator_, &event_log_, &rtcp_rtt_stats_, absl::nullopt, > &active_lifetime_, > std::unique_ptr<voe::ChannelProxy>(channel_proxy_))); > } >@@ -183,24 +177,21 @@ struct ConfigHelper { > stream_config_.encoder_factory.get()); > } > MockVoEChannelProxy* channel_proxy() { return channel_proxy_; } >- RtpTransportControllerSendInterface* transport() { return &fake_transport_; } >+ RtpTransportControllerSendInterface* transport() { return &rtp_transport_; } > TimeInterval* active_lifetime() { return &active_lifetime_; } > > static void AddBweToConfig(AudioSendStream::Config* config) { >- config->rtp.extensions.push_back( >- RtpExtension(RtpExtension::kTransportSequenceNumberUri, >- kTransportSequenceNumberId)); >+ config->rtp.extensions.push_back(RtpExtension( >+ RtpExtension::kTransportSequenceNumberUri, kTransportSequenceNumberId)); > config->send_codec_spec->transport_cc_enabled = true; > } > > void SetupDefaultChannelProxy(bool audio_bwe_enabled) { >+ EXPECT_TRUE(channel_proxy_ == nullptr); > channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>(); >- EXPECT_CALL(*channel_proxy_, GetRtpRtcp(_, _)) >- .WillRepeatedly(Invoke( >- [this](RtpRtcp** rtp_rtcp_module, RtpReceiver** rtp_receiver) { >- *rtp_rtcp_module = &this->rtp_rtcp_; >- *rtp_receiver = nullptr; // Not deemed necessary for tests yet. >- })); >+ EXPECT_CALL(*channel_proxy_, GetRtpRtcp()).WillRepeatedly(Invoke([this]() { >+ return &this->rtp_rtcp_; >+ })); > EXPECT_CALL(*channel_proxy_, SetRTCPStatus(true)).Times(1); > EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kSsrc)).Times(1); > EXPECT_CALL(*channel_proxy_, SetRTCP_CNAME(StrEq(kCName))).Times(1); >@@ -208,16 +199,19 @@ struct ConfigHelper { > EXPECT_CALL(*channel_proxy_, > SetSendAudioLevelIndicationStatus(true, kAudioLevelId)) > .Times(1); >+ EXPECT_CALL(rtp_transport_, GetBandwidthObserver()) >+ .WillRepeatedly(Return(&bandwidth_observer_)); > if (audio_bwe_enabled) { > EXPECT_CALL(*channel_proxy_, > EnableSendTransportSequenceNumber(kTransportSequenceNumberId)) > .Times(1); >- EXPECT_CALL(*channel_proxy_, RegisterSenderCongestionControlObjects( >- &fake_transport_, Ne(nullptr))) >+ EXPECT_CALL(*channel_proxy_, >+ RegisterSenderCongestionControlObjects( >+ &rtp_transport_, Eq(&bandwidth_observer_))) > .Times(1); > } else { > EXPECT_CALL(*channel_proxy_, RegisterSenderCongestionControlObjects( >- &fake_transport_, Eq(nullptr))) >+ &rtp_transport_, Eq(nullptr))) > .Times(1); > } > EXPECT_CALL(*channel_proxy_, ResetSenderCongestionControlObjects()) >@@ -227,12 +221,6 @@ struct ConfigHelper { > EXPECT_CALL(*channel_proxy_, RegisterTransport(_)).Times(1); > EXPECT_CALL(*channel_proxy_, RegisterTransport(nullptr)).Times(1); > } >- EXPECT_CALL(*channel_proxy_, SetRtcEventLog(testing::NotNull())).Times(1); >- EXPECT_CALL(*channel_proxy_, SetRtcEventLog(testing::IsNull())) >- .Times(1); // Destructor resets the event log >- EXPECT_CALL(*channel_proxy_, SetRtcpRttStats(&rtcp_rtt_stats_)).Times(1); >- EXPECT_CALL(*channel_proxy_, SetRtcpRttStats(testing::IsNull())) >- .Times(1); // Destructor resets the rtt stats. > } > > void SetupMockForSetupSendCodec(bool expect_set_encoder_call) { >@@ -259,13 +247,14 @@ struct ConfigHelper { > > void SetupMockForSendTelephoneEvent() { > EXPECT_TRUE(channel_proxy_); >- EXPECT_CALL(*channel_proxy_, >- SetSendTelephoneEventPayloadType(kTelephoneEventPayloadType, >- kTelephoneEventPayloadFrequency)) >- .WillOnce(Return(true)); >- EXPECT_CALL(*channel_proxy_, >+ EXPECT_CALL(*channel_proxy_, SetSendTelephoneEventPayloadType( >+ kTelephoneEventPayloadType, >+ kTelephoneEventPayloadFrequency)) >+ .WillOnce(Return(true)); >+ EXPECT_CALL( >+ *channel_proxy_, > SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration)) >- .WillOnce(Return(true)); >+ .WillOnce(Return(true)); > } > > void SetupMockForGetStats() { >@@ -310,14 +299,11 @@ struct ConfigHelper { > testing::StrictMock<MockVoEChannelProxy>* channel_proxy_ = nullptr; > rtc::scoped_refptr<MockAudioProcessing> audio_processing_; > AudioProcessingStats audio_processing_stats_; >- SimulatedClock simulated_clock_; > TimeInterval active_lifetime_; >- PacketRouter packet_router_; >- testing::NiceMock<MockPacedSender> pacer_; >- std::unique_ptr<SendSideCongestionController> send_side_cc_; >- FakeRtpTransportControllerSend fake_transport_; >- MockRtcEventLog event_log_; >- MockRtpRtcp rtp_rtcp_; >+ testing::StrictMock<MockRtcpBandwidthObserver> bandwidth_observer_; >+ testing::NiceMock<MockRtcEventLog> event_log_; >+ testing::NiceMock<MockRtpTransportControllerSend> rtp_transport_; >+ testing::NiceMock<MockRtpRtcp> rtp_rtcp_; > MockRtcpRttStats rtcp_rtt_stats_; > testing::NiceMock<MockLimitObserver> limit_observer_; > BitrateAllocator bitrate_allocator_; >@@ -363,9 +349,9 @@ TEST(AudioSendStreamTest, SendTelephoneEvent) { > ConfigHelper helper(false, true); > auto send_stream = helper.CreateAudioSendStream(); > helper.SetupMockForSendTelephoneEvent(); >- EXPECT_TRUE(send_stream->SendTelephoneEvent(kTelephoneEventPayloadType, >- kTelephoneEventPayloadFrequency, kTelephoneEventCode, >- kTelephoneEventDuration)); >+ EXPECT_TRUE(send_stream->SendTelephoneEvent( >+ kTelephoneEventPayloadType, kTelephoneEventPayloadFrequency, >+ kTelephoneEventCode, kTelephoneEventDuration)); > } > > TEST(AudioSendStreamTest, SetMuted) { >@@ -393,8 +379,7 @@ TEST(AudioSendStreamTest, GetStats) { > EXPECT_EQ(kSsrc, stats.local_ssrc); > EXPECT_EQ(static_cast<int64_t>(kCallStats.bytesSent), stats.bytes_sent); > EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent); >- EXPECT_EQ(static_cast<int32_t>(kReportBlock.cumulative_num_packets_lost), >- stats.packets_lost); >+ EXPECT_EQ(kReportBlock.cumulative_num_packets_lost, stats.packets_lost); > EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost); > EXPECT_EQ(std::string(kIsacCodec.plname), stats.codec_name); > EXPECT_EQ(static_cast<int32_t>(kReportBlock.extended_highest_sequence_number), >@@ -429,9 +414,10 @@ TEST(AudioSendStreamTest, SendCodecAppliesAudioNetworkAdaptor) { > > helper.config().audio_network_adaptor_config = kAnaConfigString; > >- EXPECT_CALL(helper.mock_encoder_factory(), MakeAudioEncoderMock(_, _, _)) >+ EXPECT_CALL(helper.mock_encoder_factory(), MakeAudioEncoderMock(_, _, _, _)) > .WillOnce(Invoke([&kAnaConfigString, &kAnaReconfigString]( > int payload_type, const SdpAudioFormat& format, >+ absl::optional<AudioCodecPairId> codec_pair_id, > std::unique_ptr<AudioEncoder>* return_value) { > auto mock_encoder = SetupAudioEncoderMock(payload_type, format); > EXPECT_CALL(*mock_encoder, >@@ -525,7 +511,7 @@ TEST(AudioSendStreamTest, ReconfigureTransportCcResetsFirst) { > EXPECT_CALL(*helper.channel_proxy(), ResetSenderCongestionControlObjects()) > .Times(1); > EXPECT_CALL(*helper.channel_proxy(), RegisterSenderCongestionControlObjects( >- helper.transport(), Ne(nullptr))) >+ helper.transport(), Ne(nullptr))) > .Times(1); > } > send_stream->Reconfigure(new_config); >@@ -552,8 +538,7 @@ TEST(AudioSendStreamTest, UpdateLifetime) { > EXPECT_CALL(mock_transport, SendRtp(_, _, _)).Times(2); > const PacketOptions options; > registered_transport->SendRtp(nullptr, 0, options); >- fake_clock.AdvanceTime( >- rtc::TimeDelta::FromMilliseconds(kTimeBetweenSendRtpCallsMs)); >+ fake_clock.AdvanceTime(TimeDelta::ms(kTimeBetweenSendRtpCallsMs)); > registered_transport->SendRtp(nullptr, 0, options); > } > EXPECT_TRUE(!helper.active_lifetime()->Empty()); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.cc >index 24a7ce801ed..35ea03d3840 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.cc >@@ -14,12 +14,12 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" > #include "audio/audio_receive_stream.h" > #include "modules/audio_device/include/audio_device.h" > #include "rtc_base/atomicops.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/thread.h" > > namespace webrtc { >@@ -27,9 +27,7 @@ namespace internal { > > AudioState::AudioState(const AudioState::Config& config) > : config_(config), >- audio_transport_(config_.audio_mixer, >- config_.audio_processing.get(), >- config_.audio_device_module.get()) { >+ audio_transport_(config_.audio_mixer, config_.audio_processing.get()) { > process_thread_checker_.DetachFromThread(); > RTC_DCHECK(config_.audio_mixer); > RTC_DCHECK(config_.audio_device_module); >@@ -51,8 +49,8 @@ void AudioState::AddReceivingStream(webrtc::AudioReceiveStream* stream) { > RTC_DCHECK_EQ(0, receiving_streams_.count(stream)); > receiving_streams_.insert(stream); > if (!config_.audio_mixer->AddSource( >- static_cast<internal::AudioReceiveStream*>(stream))) { >- RTC_LOG(LS_ERROR) << "Failed to add source to mixer."; >+ static_cast<internal::AudioReceiveStream*>(stream))) { >+ RTC_DLOG(LS_ERROR) << "Failed to add source to mixer."; > } > > // Make sure playback is initialized; start playing if enabled. >@@ -80,7 +78,8 @@ void AudioState::RemoveReceivingStream(webrtc::AudioReceiveStream* stream) { > } > > void AudioState::AddSendingStream(webrtc::AudioSendStream* stream, >- int sample_rate_hz, size_t num_channels) { >+ int sample_rate_hz, >+ size_t num_channels) { > RTC_DCHECK(thread_checker_.CalledOnValidThread()); > auto& properties = sending_streams_[stream]; > properties.sample_rate_hz = sample_rate_hz; >@@ -123,7 +122,7 @@ void AudioState::SetPlayout(bool enabled) { > } else { > config_.audio_device_module->StopPlayout(); > null_audio_poller_ = >- rtc::MakeUnique<NullAudioPoller>(&audio_transport_); >+ absl::make_unique<NullAudioPoller>(&audio_transport_); > } > } > } >@@ -150,9 +149,6 @@ AudioState::Stats AudioState::GetAudioInputStats() const { > result.audio_level = audio_level.LevelFullRange(); > RTC_DCHECK_LE(0, result.audio_level); > RTC_DCHECK_GE(32767, result.audio_level); >- result.quantized_audio_level = audio_level.Level(); >- RTC_DCHECK_LE(0, result.quantized_audio_level); >- RTC_DCHECK_GE(9, result.quantized_audio_level); > result.total_energy = audio_level.TotalEnergy(); > result.total_duration = audio_level.TotalDuration(); > return result; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.h >index d4e4e3fd3ce..689534b0eec 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state.h >@@ -39,9 +39,7 @@ class AudioState final : public webrtc::AudioState { > RTC_DCHECK(config_.audio_processing); > return config_.audio_processing.get(); > } >- AudioTransport* audio_transport() override { >- return &audio_transport_; >- } >+ AudioTransport* audio_transport() override { return &audio_transport_; } > > void SetPlayout(bool enabled) override; > void SetRecording(bool enabled) override; >@@ -60,7 +58,8 @@ class AudioState final : public webrtc::AudioState { > void RemoveReceivingStream(webrtc::AudioReceiveStream* stream); > > void AddSendingStream(webrtc::AudioSendStream* stream, >- int sample_rate_hz, size_t num_channels); >+ int sample_rate_hz, >+ size_t num_channels); > void RemoveSendingStream(webrtc::AudioSendStream* stream); > > private: >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state_unittest.cc >index b4452add9a1..dc622df00de 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_state_unittest.cc >@@ -71,8 +71,7 @@ std::vector<int16_t> Create10msTestData(int sample_rate_hz, > const float inc = (2 * 3.14159265f * 1000) / sample_rate_hz; > float w = 0.f; > for (int i = 0; i < samples_per_channel; ++i) { >- audio_data[i * num_channels] = >- static_cast<int16_t>(32767.f * std::sin(w)); >+ audio_data[i * num_channels] = static_cast<int16_t>(32767.f * std::sin(w)); > w += inc; > } > return audio_data; >@@ -111,16 +110,18 @@ TEST(AudioStateTest, RecordedAudioArrivesAtSingleStream) { > MockAudioSendStream stream; > audio_state->AddSendingStream(&stream, 8000, 2); > >- EXPECT_CALL(stream, SendAudioDataForMock(testing::AllOf( >- testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(8000)), >- testing::Field(&AudioFrame::num_channels_, testing::Eq(2u))))) >- .WillOnce( >- // Verify that channels are not swapped by default. >- testing::Invoke([](AudioFrame* audio_frame) { >- auto levels = ComputeChannelLevels(audio_frame); >- EXPECT_LT(0u, levels[0]); >- EXPECT_EQ(0u, levels[1]); >- })); >+ EXPECT_CALL( >+ stream, >+ SendAudioDataForMock(testing::AllOf( >+ testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(8000)), >+ testing::Field(&AudioFrame::num_channels_, testing::Eq(2u))))) >+ .WillOnce( >+ // Verify that channels are not swapped by default. >+ testing::Invoke([](AudioFrame* audio_frame) { >+ auto levels = ComputeChannelLevels(audio_frame); >+ EXPECT_LT(0u, levels[0]); >+ EXPECT_EQ(0u, levels[1]); >+ })); > MockAudioProcessing* ap = > static_cast<MockAudioProcessing*>(audio_state->audio_processing()); > EXPECT_CALL(*ap, set_stream_delay_ms(0)); >@@ -132,8 +133,8 @@ TEST(AudioStateTest, RecordedAudioArrivesAtSingleStream) { > auto audio_data = Create10msTestData(kSampleRate, kNumChannels); > uint32_t new_mic_level = 667; > audio_state->audio_transport()->RecordedDataIsAvailable( >- &audio_data[0], kSampleRate / 100, kNumChannels * 2, >- kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level); >+ &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels, >+ kSampleRate, 0, 0, 0, false, new_mic_level); > EXPECT_EQ(667u, new_mic_level); > > audio_state->RemoveSendingStream(&stream); >@@ -149,24 +150,28 @@ TEST(AudioStateTest, RecordedAudioArrivesAtMultipleStreams) { > audio_state->AddSendingStream(&stream_1, 8001, 2); > audio_state->AddSendingStream(&stream_2, 32000, 1); > >- EXPECT_CALL(stream_1, SendAudioDataForMock(testing::AllOf( >- testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)), >- testing::Field(&AudioFrame::num_channels_, testing::Eq(1u))))) >- .WillOnce( >- // Verify that there is output signal. >- testing::Invoke([](AudioFrame* audio_frame) { >- auto levels = ComputeChannelLevels(audio_frame); >- EXPECT_LT(0u, levels[0]); >- })); >- EXPECT_CALL(stream_2, SendAudioDataForMock(testing::AllOf( >- testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)), >- testing::Field(&AudioFrame::num_channels_, testing::Eq(1u))))) >- .WillOnce( >- // Verify that there is output signal. >- testing::Invoke([](AudioFrame* audio_frame) { >- auto levels = ComputeChannelLevels(audio_frame); >- EXPECT_LT(0u, levels[0]); >- })); >+ EXPECT_CALL( >+ stream_1, >+ SendAudioDataForMock(testing::AllOf( >+ testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)), >+ testing::Field(&AudioFrame::num_channels_, testing::Eq(1u))))) >+ .WillOnce( >+ // Verify that there is output signal. >+ testing::Invoke([](AudioFrame* audio_frame) { >+ auto levels = ComputeChannelLevels(audio_frame); >+ EXPECT_LT(0u, levels[0]); >+ })); >+ EXPECT_CALL( >+ stream_2, >+ SendAudioDataForMock(testing::AllOf( >+ testing::Field(&AudioFrame::sample_rate_hz_, testing::Eq(16000)), >+ testing::Field(&AudioFrame::num_channels_, testing::Eq(1u))))) >+ .WillOnce( >+ // Verify that there is output signal. >+ testing::Invoke([](AudioFrame* audio_frame) { >+ auto levels = ComputeChannelLevels(audio_frame); >+ EXPECT_LT(0u, levels[0]); >+ })); > MockAudioProcessing* ap = > static_cast<MockAudioProcessing*>(audio_state->audio_processing()); > EXPECT_CALL(*ap, set_stream_delay_ms(5)); >@@ -178,8 +183,8 @@ TEST(AudioStateTest, RecordedAudioArrivesAtMultipleStreams) { > auto audio_data = Create10msTestData(kSampleRate, kNumChannels); > uint32_t new_mic_level = 667; > audio_state->audio_transport()->RecordedDataIsAvailable( >- &audio_data[0], kSampleRate / 100, kNumChannels * 2, >- kNumChannels, kSampleRate, 5, 0, 0, true, new_mic_level); >+ &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels, >+ kSampleRate, 5, 0, 0, true, new_mic_level); > EXPECT_EQ(667u, new_mic_level); > > audio_state->RemoveSendingStream(&stream_1); >@@ -210,8 +215,8 @@ TEST(AudioStateTest, EnableChannelSwap) { > auto audio_data = Create10msTestData(kSampleRate, kNumChannels); > uint32_t new_mic_level = 667; > audio_state->audio_transport()->RecordedDataIsAvailable( >- &audio_data[0], kSampleRate / 100, kNumChannels * 2, >- kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level); >+ &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels, >+ kSampleRate, 0, 0, 0, false, new_mic_level); > EXPECT_EQ(667u, new_mic_level); > > audio_state->RemoveSendingStream(&stream); >@@ -230,11 +235,10 @@ TEST(AudioStateTest, InputLevelStats) { > auto audio_data = Create10msSilentTestData(kSampleRate, kNumChannels); > uint32_t new_mic_level = 667; > audio_state->audio_transport()->RecordedDataIsAvailable( >- &audio_data[0], kSampleRate / 100, kNumChannels * 2, >- kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level); >+ &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels, >+ kSampleRate, 0, 0, 0, false, new_mic_level); > auto stats = audio_state->GetAudioInputStats(); > EXPECT_EQ(0, stats.audio_level); >- EXPECT_EQ(0, stats.quantized_audio_level); > EXPECT_THAT(stats.total_energy, testing::DoubleEq(0.0)); > EXPECT_THAT(stats.total_duration, testing::DoubleEq(0.01)); > } >@@ -245,12 +249,11 @@ TEST(AudioStateTest, InputLevelStats) { > uint32_t new_mic_level = 667; > for (int i = 0; i < 10; ++i) { > audio_state->audio_transport()->RecordedDataIsAvailable( >- &audio_data[0], kSampleRate / 100, kNumChannels * 2, >- kNumChannels, kSampleRate, 0, 0, 0, false, new_mic_level); >+ &audio_data[0], kSampleRate / 100, kNumChannels * 2, kNumChannels, >+ kSampleRate, 0, 0, 0, false, new_mic_level); > } > auto stats = audio_state->GetAudioInputStats(); > EXPECT_EQ(32767, stats.audio_level); >- EXPECT_EQ(9, stats.quantized_audio_level); > EXPECT_THAT(stats.total_energy, testing::DoubleEq(0.01)); > EXPECT_THAT(stats.total_duration, testing::DoubleEq(0.11)); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.cc >index 586fc4660b4..44e95aa909a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.cc >@@ -14,10 +14,10 @@ > #include <memory> > #include <utility> > >+#include "audio/remix_resample.h" > #include "audio/utility/audio_frame_operations.h" > #include "call/audio_send_stream.h" > #include "rtc_base/logging.h" >-#include "voice_engine/utility.h" > > namespace webrtc { > >@@ -43,8 +43,7 @@ void InitializeCaptureFrame(int input_sample_rate, > audio_frame->num_channels_ = std::min(input_num_channels, send_num_channels); > } > >-void ProcessCaptureFrame(int analog_level, >- uint32_t delay_ms, >+void ProcessCaptureFrame(uint32_t delay_ms, > bool key_pressed, > bool swap_stereo_channels, > AudioProcessing* audio_processing, >@@ -53,13 +52,9 @@ void ProcessCaptureFrame(int analog_level, > RTC_DCHECK(audio_frame); > RTC_DCHECK( > !audio_processing->echo_cancellation()->is_drift_compensation_enabled()); >- GainControl* agc = audio_processing->gain_control(); >- int error = agc->set_stream_analog_level(analog_level); >- RTC_DCHECK_EQ(0, error) << >- "set_stream_analog_level failed: analog_level = " << analog_level; > audio_processing->set_stream_delay_ms(delay_ms); > audio_processing->set_stream_key_pressed(key_pressed); >- error = audio_processing->ProcessStream(audio_frame); >+ int error = audio_processing->ProcessStream(audio_frame); > RTC_DCHECK_EQ(0, error) << "ProcessStream() error: " << error; > if (swap_stereo_channels) { > AudioFrameOperations::SwapStereoChannels(audio_frame); >@@ -87,14 +82,10 @@ int Resample(const AudioFrame& frame, > } // namespace > > AudioTransportImpl::AudioTransportImpl(AudioMixer* mixer, >- AudioProcessing* audio_processing, >- AudioDeviceModule* audio_device_module) >- : audio_processing_(audio_processing), >- audio_device_module_(audio_device_module), >- mixer_(mixer) { >+ AudioProcessing* audio_processing) >+ : audio_processing_(audio_processing), mixer_(mixer) { > RTC_DCHECK(mixer); > RTC_DCHECK(audio_processing); >- RTC_DCHECK(audio_device_module); > } > > AudioTransportImpl::~AudioTransportImpl() {} >@@ -109,7 +100,7 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable( > const uint32_t sample_rate, > const uint32_t audio_delay_milliseconds, > const int32_t /*clock_drift*/, >- const uint32_t volume, >+ const uint32_t /*volume*/, > const bool key_pressed, > uint32_t& /*new_mic_volume*/) { // NOLINT: to avoid changing APIs > RTC_DCHECK(audio_data); >@@ -122,35 +113,6 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable( > RTC_DCHECK_LE(bytes_per_sample * number_of_frames * number_of_channels, > AudioFrame::kMaxDataSizeBytes); > >- // TODO(solenberg): Remove volume handling since it is now always 0. >- uint16_t voe_mic_level = 0; >- { >- constexpr uint32_t kMaxVolumeLevel = 255; >- uint32_t max_volume = 0; >- >- // Check for zero to skip this calculation; the consumer may use this to >- // indicate no volume is available. >- if (volume != 0) { >- // Scale from ADM to VoE level range >- if (audio_device_module_->MaxMicrophoneVolume(&max_volume) == 0) { >- if (max_volume != 0) { >- voe_mic_level = static_cast<uint16_t>( >- (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) / >- max_volume); >- } >- } >- // We learned that on certain systems (e.g Linux) the voe_mic_level >- // can be greater than the maxVolumeLevel therefore >- // we are going to cap the voe_mic_level to the maxVolumeLevel >- // and change the maxVolume to volume if it turns out that >- // the voe_mic_level is indeed greater than the maxVolumeLevel. >- if (voe_mic_level > kMaxVolumeLevel) { >- voe_mic_level = kMaxVolumeLevel; >- max_volume = volume; >- } >- } >- } >- > int send_sample_rate_hz = 0; > size_t send_num_channels = 0; > bool swap_stereo_channels = false; >@@ -162,13 +124,12 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable( > } > > std::unique_ptr<AudioFrame> audio_frame(new AudioFrame()); >- InitializeCaptureFrame(sample_rate, send_sample_rate_hz, >- number_of_channels, send_num_channels, >- audio_frame.get()); >+ InitializeCaptureFrame(sample_rate, send_sample_rate_hz, number_of_channels, >+ send_num_channels, audio_frame.get()); > voe::RemixAndResample(static_cast<const int16_t*>(audio_data), > number_of_frames, number_of_channels, sample_rate, > &capture_resampler_, audio_frame.get()); >- ProcessCaptureFrame(voe_mic_level, audio_delay_milliseconds, key_pressed, >+ ProcessCaptureFrame(audio_delay_milliseconds, key_pressed, > swap_stereo_channels, audio_processing_, > audio_frame.get()); > >@@ -212,13 +173,13 @@ int32_t AudioTransportImpl::RecordedDataIsAvailable( > // Mix all received streams, feed the result to the AudioProcessing module, then > // resample the result to the requested output rate. > int32_t AudioTransportImpl::NeedMorePlayData(const size_t nSamples, >- const size_t nBytesPerSample, >- const size_t nChannels, >- const uint32_t samplesPerSec, >- void* audioSamples, >- size_t& nSamplesOut, >- int64_t* elapsed_time_ms, >- int64_t* ntp_time_ms) { >+ const size_t nBytesPerSample, >+ const size_t nChannels, >+ const uint32_t samplesPerSec, >+ void* audioSamples, >+ size_t& nSamplesOut, >+ int64_t* elapsed_time_ms, >+ int64_t* ntp_time_ms) { > RTC_DCHECK_EQ(sizeof(int16_t) * nChannels, nBytesPerSample); > RTC_DCHECK_GE(nChannels, 1); > RTC_DCHECK_LE(nChannels, 2); >@@ -247,12 +208,12 @@ int32_t AudioTransportImpl::NeedMorePlayData(const size_t nSamples, > // Used by Chromium - same as NeedMorePlayData() but because Chrome has its > // own APM instance, does not call audio_processing_->ProcessReverseStream(). > void AudioTransportImpl::PullRenderData(int bits_per_sample, >- int sample_rate, >- size_t number_of_channels, >- size_t number_of_frames, >- void* audio_data, >- int64_t* elapsed_time_ms, >- int64_t* ntp_time_ms) { >+ int sample_rate, >+ size_t number_of_channels, >+ size_t number_of_frames, >+ void* audio_data, >+ int64_t* elapsed_time_ms, >+ int64_t* ntp_time_ms) { > RTC_DCHECK_EQ(bits_per_sample, 16); > RTC_DCHECK_GE(number_of_channels, 1); > RTC_DCHECK_LE(number_of_channels, 2); >@@ -274,7 +235,8 @@ void AudioTransportImpl::PullRenderData(int bits_per_sample, > } > > void AudioTransportImpl::UpdateSendingStreams( >- std::vector<AudioSendStream*> streams, int send_sample_rate_hz, >+ std::vector<AudioSendStream*> streams, >+ int send_sample_rate_hz, > size_t send_num_channels) { > rtc::CritScope lock(&capture_lock_); > sending_streams_ = std::move(streams); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.h >index e7de7e9f485..3a3155cdbd4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/audio_transport_impl.h >@@ -14,6 +14,7 @@ > #include <vector> > > #include "api/audio/audio_mixer.h" >+#include "audio/audio_level.h" > #include "common_audio/resampler/include/push_resampler.h" > #include "modules/audio_device/include/audio_device.h" > #include "modules/audio_processing/include/audio_processing.h" >@@ -22,7 +23,6 @@ > #include "rtc_base/criticalsection.h" > #include "rtc_base/scoped_ref_ptr.h" > #include "rtc_base/thread_annotations.h" >-#include "voice_engine/audio_level.h" > > namespace webrtc { > >@@ -30,9 +30,7 @@ class AudioSendStream; > > class AudioTransportImpl : public AudioTransport { > public: >- AudioTransportImpl(AudioMixer* mixer, >- AudioProcessing* audio_processing, >- AudioDeviceModule* audio_device_module); >+ AudioTransportImpl(AudioMixer* mixer, AudioProcessing* audio_processing); > ~AudioTransportImpl() override; > > int32_t RecordedDataIsAvailable(const void* audioSamples, >@@ -64,12 +62,11 @@ class AudioTransportImpl : public AudioTransport { > int64_t* ntp_time_ms) override; > > void UpdateSendingStreams(std::vector<AudioSendStream*> streams, >- int send_sample_rate_hz, size_t send_num_channels); >+ int send_sample_rate_hz, >+ size_t send_num_channels); > void SetStereoChannelSwapping(bool enable); > bool typing_noise_detected() const; >- const voe::AudioLevel& audio_level() const { >- return audio_level_; >- } >+ const voe::AudioLevel& audio_level() const { return audio_level_; } > > private: > // Shared. >@@ -82,7 +79,6 @@ class AudioTransportImpl : public AudioTransport { > size_t send_num_channels_ RTC_GUARDED_BY(capture_lock_) = 1; > bool typing_noise_detected_ RTC_GUARDED_BY(capture_lock_) = false; > bool swap_stereo_channels_ RTC_GUARDED_BY(capture_lock_) = false; >- AudioDeviceModule* audio_device_module_ = nullptr; > PushResampler<int16_t> capture_resampler_; > voe::AudioLevel audio_level_; > TypingDetection typing_detection_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.cc >similarity index 84% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.cc >index efc76bdcab4..90443645aed 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.cc >@@ -8,7 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "voice_engine/channel.h" >+#include "audio/channel.h" > > #include <algorithm> > #include <map> >@@ -17,20 +17,18 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" > #include "api/array_view.h" > #include "audio/utility/audio_frame_operations.h" > #include "call/rtp_transport_controller_send_interface.h" >-#include "logging/rtc_event_log/rtc_event_log.h" > #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" >+#include "logging/rtc_event_log/rtc_event_log.h" > #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" > #include "modules/audio_coding/codecs/audio_format_conversion.h" > #include "modules/audio_device/include/audio_device.h" > #include "modules/audio_processing/include/audio_processing.h" >-#include "modules/include/module_common_types.h" > #include "modules/pacing/packet_router.h" > #include "modules/rtp_rtcp/include/receive_statistics.h" >-#include "modules/rtp_rtcp/include/rtp_payload_registry.h" >-#include "modules/rtp_rtcp/include/rtp_receiver.h" > #include "modules/rtp_rtcp/source/rtp_packet_received.h" > #include "modules/rtp_rtcp/source/rtp_receiver_strategy.h" > #include "modules/utility/include/process_thread.h" >@@ -39,7 +37,6 @@ > #include "rtc_base/format_macros.h" > #include "rtc_base/location.h" > #include "rtc_base/logging.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/rate_limiter.h" > #include "rtc_base/task_queue.h" > #include "rtc_base/thread_checker.h" >@@ -64,64 +61,6 @@ constexpr int kVoiceEngineMaxMinPlayoutDelayMs = 10000; > > const int kTelephoneEventAttenuationdB = 10; > >-class RtcEventLogProxy final : public webrtc::RtcEventLog { >- public: >- RtcEventLogProxy() : event_log_(nullptr) {} >- >- bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, >- int64_t output_period_ms) override { >- RTC_NOTREACHED(); >- return false; >- } >- >- void StopLogging() override { RTC_NOTREACHED(); } >- >- void Log(std::unique_ptr<RtcEvent> event) override { >- rtc::CritScope lock(&crit_); >- if (event_log_) { >- event_log_->Log(std::move(event)); >- } >- } >- >- void SetEventLog(RtcEventLog* event_log) { >- rtc::CritScope lock(&crit_); >- event_log_ = event_log; >- } >- >- private: >- rtc::CriticalSection crit_; >- RtcEventLog* event_log_ RTC_GUARDED_BY(crit_); >- RTC_DISALLOW_COPY_AND_ASSIGN(RtcEventLogProxy); >-}; >- >-class RtcpRttStatsProxy final : public RtcpRttStats { >- public: >- RtcpRttStatsProxy() : rtcp_rtt_stats_(nullptr) {} >- >- void OnRttUpdate(int64_t rtt) override { >- rtc::CritScope lock(&crit_); >- if (rtcp_rtt_stats_) >- rtcp_rtt_stats_->OnRttUpdate(rtt); >- } >- >- int64_t LastProcessedRtt() const override { >- rtc::CritScope lock(&crit_); >- if (!rtcp_rtt_stats_) >- return 0; >- return rtcp_rtt_stats_->LastProcessedRtt(); >- } >- >- void SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats) { >- rtc::CritScope lock(&crit_); >- rtcp_rtt_stats_ = rtcp_rtt_stats; >- } >- >- private: >- rtc::CriticalSection crit_; >- RtcpRttStats* rtcp_rtt_stats_ RTC_GUARDED_BY(crit_); >- RTC_DISALLOW_COPY_AND_ASSIGN(RtcpRttStatsProxy); >-}; >- > class TransportFeedbackProxy : public TransportFeedbackObserver { > public: > TransportFeedbackProxy() : feedback_observer_(nullptr) { >@@ -153,10 +92,6 @@ class TransportFeedbackProxy : public TransportFeedbackObserver { > if (feedback_observer_) > feedback_observer_->OnTransportFeedback(feedback); > } >- std::vector<PacketFeedback> GetTransportFeedbackVector() const override { >- RTC_NOTREACHED(); >- return std::vector<PacketFeedback>(); >- } > > private: > rtc::CriticalSection crit_; >@@ -345,7 +280,7 @@ int32_t Channel::SendData(FrameType frameType, > // received from the capture device as > // undefined for voice for now. > -1, payloadData, payloadSize, fragmentation, nullptr, nullptr)) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "Channel::SendData() failed to send data to RTP/RTCP module"; > return -1; > } >@@ -359,17 +294,14 @@ bool Channel::SendRtp(const uint8_t* data, > rtc::CritScope cs(&_callbackCritSect); > > if (_transportPtr == NULL) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "Channel::SendPacket() failed to send RTP packet due to" > << " invalid transport object"; > return false; > } > >- uint8_t* bufferToSendPtr = (uint8_t*)data; >- size_t bufferLength = len; >- >- if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) { >- RTC_LOG(LS_ERROR) << "Channel::SendPacket() RTP transmission failed"; >+ if (!_transportPtr->SendRtp(data, len, options)) { >+ RTC_DLOG(LS_ERROR) << "Channel::SendPacket() RTP transmission failed"; > return false; > } > return true; >@@ -378,44 +310,20 @@ bool Channel::SendRtp(const uint8_t* data, > bool Channel::SendRtcp(const uint8_t* data, size_t len) { > rtc::CritScope cs(&_callbackCritSect); > if (_transportPtr == NULL) { >- RTC_LOG(LS_ERROR) << "Channel::SendRtcp() failed to send RTCP packet due to" >- << " invalid transport object"; >+ RTC_DLOG(LS_ERROR) >+ << "Channel::SendRtcp() failed to send RTCP packet due to" >+ << " invalid transport object"; > return false; > } > >- uint8_t* bufferToSendPtr = (uint8_t*)data; >- size_t bufferLength = len; >- >- int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength); >+ int n = _transportPtr->SendRtcp(data, len); > if (n < 0) { >- RTC_LOG(LS_ERROR) << "Channel::SendRtcp() transmission failed"; >+ RTC_DLOG(LS_ERROR) << "Channel::SendRtcp() transmission failed"; > return false; > } > return true; > } > >-void Channel::OnIncomingSSRCChanged(uint32_t ssrc) { >- // Update ssrc so that NTP for AV sync can be updated. >- _rtpRtcpModule->SetRemoteSSRC(ssrc); >-} >- >-void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) { >- // TODO(saza): remove. >-} >- >-int32_t Channel::OnInitializeDecoder(int payload_type, >- const SdpAudioFormat& audio_format, >- uint32_t rate) { >- if (!audio_coding_->RegisterReceiveCodec(payload_type, audio_format)) { >- RTC_LOG(LS_WARNING) << "Channel::OnInitializeDecoder() invalid codec (pt=" >- << payload_type << ", " << audio_format >- << ") received -1"; >- return -1; >- } >- >- return 0; >-} >- > int32_t Channel::OnReceivedPayloadData(const uint8_t* payloadData, > size_t payloadSize, > const WebRtcRTPHeader* rtpHeader) { >@@ -428,14 +336,13 @@ int32_t Channel::OnReceivedPayloadData(const uint8_t* payloadData, > // Push the incoming payload (parsed and ready for decoding) into the ACM > if (audio_coding_->IncomingPacket(payloadData, payloadSize, *rtpHeader) != > 0) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "Channel::OnReceivedPayloadData() unable to push data to the ACM"; > return -1; > } > > int64_t round_trip_time = 0; >- _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time, NULL, NULL, >- NULL); >+ _rtpRtcpModule->RTT(remote_ssrc_, &round_trip_time, NULL, NULL, NULL); > > std::vector<uint16_t> nack_list = audio_coding_->GetNackList(round_trip_time); > if (!nack_list.empty()) { >@@ -453,12 +360,12 @@ AudioMixer::Source::AudioFrameInfo Channel::GetAudioFrameWithInfo( > > unsigned int ssrc; > RTC_CHECK_EQ(GetRemoteSSRC(ssrc), 0); >- event_log_proxy_->Log(rtc::MakeUnique<RtcEventAudioPlayout>(ssrc)); >+ event_log_->Log(absl::make_unique<RtcEventAudioPlayout>(ssrc)); > // Get 10ms raw PCM data from the ACM (mixer limits output frequency) > bool muted; > if (audio_coding_->PlayoutData10Ms(audio_frame->sample_rate_hz_, audio_frame, > &muted) == -1) { >- RTC_LOG(LS_ERROR) << "Channel::GetAudioFrame() PlayoutData10Ms() failed!"; >+ RTC_DLOG(LS_ERROR) << "Channel::GetAudioFrame() PlayoutData10Ms() failed!"; > // In all likelihood, the audio in this frame is garbage. We return an > // error so that the audio mixer module doesn't add it to the mix. As > // a result, it won't be played out and the actions skipped here are >@@ -561,32 +468,35 @@ int Channel::PreferredSampleRate() const { > > Channel::Channel(rtc::TaskQueue* encoder_queue, > ProcessThread* module_process_thread, >- AudioDeviceModule* audio_device_module) >+ AudioDeviceModule* audio_device_module, >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcEventLog* rtc_event_log) > : Channel(module_process_thread, > audio_device_module, >+ rtcp_rtt_stats, >+ rtc_event_log, >+ 0, > 0, > false, >- rtc::scoped_refptr<AudioDecoderFactory>()) { >+ rtc::scoped_refptr<AudioDecoderFactory>(), >+ absl::nullopt) { > RTC_DCHECK(encoder_queue); > encoder_queue_ = encoder_queue; > } > > Channel::Channel(ProcessThread* module_process_thread, > AudioDeviceModule* audio_device_module, >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcEventLog* rtc_event_log, >+ uint32_t remote_ssrc, > size_t jitter_buffer_max_packets, > bool jitter_buffer_fast_playout, >- rtc::scoped_refptr<AudioDecoderFactory> decoder_factory) >- : event_log_proxy_(new RtcEventLogProxy()), >- rtcp_rtt_stats_proxy_(new RtcpRttStatsProxy()), >- rtp_payload_registry_(new RTPPayloadRegistry()), >+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, >+ absl::optional<AudioCodecPairId> codec_pair_id) >+ : event_log_(rtc_event_log), > rtp_receive_statistics_( > ReceiveStatistics::Create(Clock::GetRealTimeClock())), >- rtp_receiver_( >- RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(), >- this, >- this, >- rtp_payload_registry_.get())), >- telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()), >+ remote_ssrc_(remote_ssrc), > _outputAudioLevel(), > _timeStamp(0), // This is just an offset, RTP module will add it's own > // random offset >@@ -619,6 +529,7 @@ Channel::Channel(ProcessThread* module_process_thread, > RTC_DCHECK(audio_device_module); > AudioCodingModule::Config acm_config; > acm_config.decoder_factory = decoder_factory; >+ acm_config.neteq_config.codec_pair_id = codec_pair_id; > acm_config.neteq_config.max_packets_in_buffer = jitter_buffer_max_packets; > acm_config.neteq_config.enable_fast_accelerate = jitter_buffer_fast_playout; > acm_config.neteq_config.enable_muted_state = true; >@@ -638,14 +549,14 @@ Channel::Channel(ProcessThread* module_process_thread, > seq_num_allocator_proxy_.get(); > configuration.transport_feedback_callback = feedback_observer_proxy_.get(); > } >- configuration.event_log = &(*event_log_proxy_); >- configuration.rtt_stats = &(*rtcp_rtt_stats_proxy_); >+ configuration.event_log = event_log_; >+ configuration.rtt_stats = rtcp_rtt_stats; > configuration.retransmission_rate_limiter = > retransmission_rate_limiter_.get(); > > _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration)); > _rtpRtcpModule->SetSendingMediaStatus(false); >- >+ _rtpRtcpModule->SetRemoteSSRC(remote_ssrc_); > Init(); > } > >@@ -672,7 +583,6 @@ void Channel::Init() { > // disabled by the user. > // After StopListen (when no sockets exists), RTCP packets will no longer > // be transmitted since the Transport object will then be invalid. >- telephone_event_handler_->SetTelephoneEventForwardToDecoder(true); > // RTCP is enabled by default. > _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound); > >@@ -742,7 +652,7 @@ int32_t Channel::StartSend() { > } > _rtpRtcpModule->SetSendingMediaStatus(true); > if (_rtpRtcpModule->SetSendingStatus(true) != 0) { >- RTC_LOG(LS_ERROR) << "StartSend() RTP/RTCP failed to start sending"; >+ RTC_DLOG(LS_ERROR) << "StartSend() RTP/RTCP failed to start sending"; > _rtpRtcpModule->SetSendingMediaStatus(false); > rtc::CritScope cs(&_callbackCritSect); > channel_state_.SetSending(false); >@@ -791,7 +701,7 @@ void Channel::StopSend() { > // Reset sending SSRC and sequence number and triggers direct transmission > // of RTCP BYE > if (_rtpRtcpModule->SetSendingStatus(false) == -1) { >- RTC_LOG(LS_ERROR) << "StartSend() RTP/RTCP failed to stop sending"; >+ RTC_DLOG(LS_ERROR) << "StartSend() RTP/RTCP failed to stop sending"; > } > _rtpRtcpModule->SetSendingMediaStatus(false); > } >@@ -822,7 +732,7 @@ bool Channel::SetEncoder(int payload_type, > if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) { > _rtpRtcpModule->DeRegisterSendPayload(payload_type); > if (_rtpRtcpModule->RegisterSendPayload(rtp_codec) != 0) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "SetEncoder() failed to register codec to RTP/RTCP module"; > return false; > } >@@ -870,6 +780,22 @@ void Channel::OnRecoverableUplinkPacketLossRate( > }); > } > >+std::vector<webrtc::RtpSource> Channel::GetSources() const { >+ int64_t now_ms = rtc::TimeMillis(); >+ std::vector<RtpSource> sources; >+ { >+ rtc::CritScope cs(&rtp_sources_lock_); >+ sources = contributing_sources_.GetSources(now_ms); >+ if (last_received_rtp_system_time_ms_ >= >+ now_ms - ContributingSources::kHistoryMs) { >+ sources.emplace_back(*last_received_rtp_system_time_ms_, remote_ssrc_, >+ RtpSourceType::SSRC); >+ sources.back().set_audio_level(last_received_rtp_audio_level_); >+ } >+ } >+ return sources; >+} >+ > void Channel::OnUplinkPacketLossRate(float packet_loss_rate) { > if (use_twcc_plr_for_ana_) > return; >@@ -881,7 +807,10 @@ void Channel::OnUplinkPacketLossRate(float packet_loss_rate) { > } > > void Channel::SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) { >- rtp_payload_registry_->SetAudioReceivePayloads(codecs); >+ for (const auto& kv : codecs) { >+ RTC_DCHECK_GE(kv.second.clockrate_hz, 1000); >+ payload_type_frequencies_[kv.first] = kv.second.clockrate_hz; >+ } > audio_coding_->SetReceiveCodecs(codecs); > } > >@@ -889,8 +818,8 @@ bool Channel::EnableAudioNetworkAdaptor(const std::string& config_string) { > bool success = false; > audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { > if (*encoder) { >- success = (*encoder)->EnableAudioNetworkAdaptor(config_string, >- event_log_proxy_.get()); >+ success = >+ (*encoder)->EnableAudioNetworkAdaptor(config_string, event_log_); > } > }); > return success; >@@ -918,23 +847,39 @@ void Channel::RegisterTransport(Transport* transport) { > _transportPtr = transport; > } > >+// TODO(nisse): Move receive logic up to AudioReceiveStream. > void Channel::OnRtpPacket(const RtpPacketReceived& packet) { >+ int64_t now_ms = rtc::TimeMillis(); >+ uint8_t audio_level; >+ bool voice_activity; >+ bool has_audio_level = >+ packet.GetExtension<::webrtc::AudioLevel>(&voice_activity, &audio_level); >+ >+ { >+ rtc::CritScope cs(&rtp_sources_lock_); >+ last_received_rtp_timestamp_ = packet.Timestamp(); >+ last_received_rtp_system_time_ms_ = now_ms; >+ if (has_audio_level) >+ last_received_rtp_audio_level_ = audio_level; >+ std::vector<uint32_t> csrcs = packet.Csrcs(); >+ contributing_sources_.Update(now_ms, csrcs); >+ } >+ > RTPHeader header; > packet.GetHeader(&header); > > // Store playout timestamp for the received RTP packet > UpdatePlayoutTimestamp(false); > >- header.payload_type_frequency = >- rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType); >- if (header.payload_type_frequency >= 0) { >- bool in_order = IsPacketInOrder(header); >- rtp_receive_statistics_->IncomingPacket( >- header, packet.size(), IsPacketRetransmitted(header, in_order)); >- rtp_payload_registry_->SetIncomingPayloadType(header); >+ const auto& it = payload_type_frequencies_.find(header.payloadType); >+ if (it == payload_type_frequencies_.end()) >+ return; >+ header.payload_type_frequency = it->second; > >- ReceivePacket(packet.data(), packet.size(), header); >- } >+ rtp_receive_statistics_->IncomingPacket(header, packet.size(), >+ IsPacketRetransmitted(header)); >+ >+ ReceivePacket(packet.data(), packet.size(), header); > } > > bool Channel::ReceivePacket(const uint8_t* packet, >@@ -943,33 +888,25 @@ bool Channel::ReceivePacket(const uint8_t* packet, > const uint8_t* payload = packet + header.headerLength; > assert(packet_length >= header.headerLength); > size_t payload_length = packet_length - header.headerLength; >- const auto pl = >- rtp_payload_registry_->PayloadTypeToPayload(header.payloadType); >- if (!pl) { >- return false; >- } >- return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length, >- pl->typeSpecific); >-} >+ WebRtcRTPHeader webrtc_rtp_header = {}; >+ webrtc_rtp_header.header = header; > >-bool Channel::IsPacketInOrder(const RTPHeader& header) const { >- StreamStatistician* statistician = >- rtp_receive_statistics_->GetStatistician(header.ssrc); >- if (!statistician) >- return false; >- return statistician->IsPacketInOrder(header.sequenceNumber); >+ const size_t payload_data_length = payload_length - header.paddingLength; >+ if (payload_data_length == 0) { >+ webrtc_rtp_header.frameType = kEmptyFrame; >+ return OnReceivedPayloadData(nullptr, 0, &webrtc_rtp_header); >+ } >+ return OnReceivedPayloadData(payload, payload_data_length, >+ &webrtc_rtp_header); > } > >-bool Channel::IsPacketRetransmitted(const RTPHeader& header, >- bool in_order) const { >+bool Channel::IsPacketRetransmitted(const RTPHeader& header) const { > StreamStatistician* statistician = > rtp_receive_statistics_->GetStatistician(header.ssrc); > if (!statistician) > return false; > // Check if this is a retransmission. >- int64_t min_rtt = 0; >- _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL); >- return !in_order && statistician->IsRetransmitOfOldPacket(header, min_rtt); >+ return statistician->IsRetransmitOfOldPacket(header); > } > > int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) { >@@ -1002,9 +939,8 @@ int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) { > uint32_t ntp_secs = 0; > uint32_t ntp_frac = 0; > uint32_t rtp_timestamp = 0; >- if (0 != >- _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL, >- &rtp_timestamp)) { >+ if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL, >+ &rtp_timestamp)) { > // Waiting for RTCP. > return 0; > } >@@ -1016,10 +952,6 @@ int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) { > return 0; > } > >-int Channel::GetSpeechOutputLevel() const { >- return _outputAudioLevel.Level(); >-} >- > int Channel::GetSpeechOutputLevelFullRange() const { > return _outputAudioLevel.LevelFullRange(); > } >@@ -1056,8 +988,8 @@ int Channel::SendTelephoneEventOutband(int event, int duration_ms) { > return -1; > } > if (_rtpRtcpModule->SendTelephoneEventOutband( >- event, duration_ms, kTelephoneEventAttenuationdB) != 0) { >- RTC_LOG(LS_ERROR) << "SendTelephoneEventOutband() failed to send event"; >+ event, duration_ms, kTelephoneEventAttenuationdB) != 0) { >+ RTC_DLOG(LS_ERROR) << "SendTelephoneEventOutband() failed to send event"; > return -1; > } > return 0; >@@ -1074,7 +1006,7 @@ int Channel::SetSendTelephoneEventPayloadType(int payload_type, > if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) { > _rtpRtcpModule->DeRegisterSendPayload(codec.pltype); > if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "SetSendTelephoneEventPayloadType() failed to register " > "send payload type"; > return -1; >@@ -1085,15 +1017,22 @@ int Channel::SetSendTelephoneEventPayloadType(int payload_type, > > int Channel::SetLocalSSRC(unsigned int ssrc) { > if (channel_state_.Get().sending) { >- RTC_LOG(LS_ERROR) << "SetLocalSSRC() already sending"; >+ RTC_DLOG(LS_ERROR) << "SetLocalSSRC() already sending"; > return -1; > } > _rtpRtcpModule->SetSSRC(ssrc); > return 0; > } > >+void Channel::SetMid(const std::string& mid, int extension_id) { >+ int ret = SetSendRtpHeaderExtension(true, kRtpExtensionMid, extension_id); >+ RTC_DCHECK_EQ(0, ret); >+ _rtpRtcpModule->SetMid(mid); >+} >+ >+// TODO(nisse): Pass ssrc in return value instead. > int Channel::GetRemoteSSRC(unsigned int& ssrc) { >- ssrc = rtp_receiver_->SSRC(); >+ ssrc = remote_ssrc_; > return 0; > } > >@@ -1163,7 +1102,7 @@ void Channel::SetRTCPStatus(bool enable) { > > int Channel::SetRTCP_CNAME(const char cName[256]) { > if (_rtpRtcpModule->SetCNAME(cName) != 0) { >- RTC_LOG(LS_ERROR) << "SetRTCP_CNAME() failed to set RTCP CNAME"; >+ RTC_DLOG(LS_ERROR) << "SetRTCP_CNAME() failed to set RTCP CNAME"; > return -1; > } > return 0; >@@ -1172,7 +1111,7 @@ int Channel::SetRTCP_CNAME(const char cName[256]) { > int Channel::GetRemoteRTCPReportBlocks( > std::vector<ReportBlock>* report_blocks) { > if (report_blocks == NULL) { >- RTC_LOG(LS_ERROR) << "GetRemoteRTCPReportBlock()s invalid report_blocks."; >+ RTC_DLOG(LS_ERROR) << "GetRemoteRTCPReportBlock()s invalid report_blocks."; > return -1; > } > >@@ -1207,14 +1146,16 @@ int Channel::GetRemoteRTCPReportBlocks( > int Channel::GetRTPStatistics(CallStatistics& stats) { > // --- RtcpStatistics > >- // The jitter statistics is updated for each received RTP packet and is >- // based on received packets. >+ // Jitter, cumulative loss, and extended max sequence number is updated for >+ // each received RTP packet. > RtcpStatistics statistics; > StreamStatistician* statistician = >- rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC()); >+ rtp_receive_statistics_->GetStatistician(remote_ssrc_); > if (statistician) { >- statistician->GetStatistics(&statistics, >- _rtpRtcpModule->RTCP() == RtcpMode::kOff); >+ // Recompute |fraction_lost| only if RTCP is off. If it's on, then >+ // |fraction_lost| should only be recomputed when an RTCP SR or RR is sent. >+ bool update_fraction_lost = _rtpRtcpModule->RTCP() == RtcpMode::kOff; >+ statistician->GetStatistics(&statistics, update_fraction_lost); > } > > stats.fractionLost = statistics.fraction_lost; >@@ -1237,7 +1178,7 @@ int Channel::GetRTPStatistics(CallStatistics& stats) { > } > > if (_rtpRtcpModule->DataCountersRTP(&bytesSent, &packetsSent) != 0) { >- RTC_LOG(LS_WARNING) >+ RTC_DLOG(LS_WARNING) > << "GetRTPStatistics() failed to retrieve RTP datacounters" > << " => output will not be complete"; > } >@@ -1320,7 +1261,7 @@ void Channel::ProcessAndEncodeAudioOnTaskQueue(AudioFrame* audio_input) { > // is done and payload is ready for packetization and transmission. > // Otherwise, it will return without invoking the callback. > if (audio_coding_->Add10MsData(*audio_input) < 0) { >- RTC_LOG(LS_ERROR) << "ACM::Add10MsData() failed."; >+ RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed."; > return; > } > >@@ -1333,14 +1274,6 @@ void Channel::SetAssociatedSendChannel(Channel* channel) { > associated_send_channel_ = channel; > } > >-void Channel::SetRtcEventLog(RtcEventLog* event_log) { >- event_log_proxy_->SetEventLog(event_log); >-} >- >-void Channel::SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats) { >- rtcp_rtt_stats_proxy_->SetRtcpRttStats(rtcp_rtt_stats); >-} >- > void Channel::UpdateOverheadForEncoder() { > size_t overhead_per_packet = > transport_overhead_per_packet_ + rtp_overhead_per_packet_; >@@ -1384,11 +1317,11 @@ uint32_t Channel::GetDelayEstimate() const { > int Channel::SetMinimumPlayoutDelay(int delayMs) { > if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) || > (delayMs > kVoiceEngineMaxMinPlayoutDelayMs)) { >- RTC_LOG(LS_ERROR) << "SetMinimumPlayoutDelay() invalid min delay"; >+ RTC_DLOG(LS_ERROR) << "SetMinimumPlayoutDelay() invalid min delay"; > return -1; > } > if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0) { >- RTC_LOG(LS_ERROR) >+ RTC_DLOG(LS_ERROR) > << "SetMinimumPlayoutDelay() failed to set min playout delay"; > return -1; > } >@@ -1402,18 +1335,33 @@ int Channel::GetPlayoutTimestamp(unsigned int& timestamp) { > playout_timestamp_rtp = playout_timestamp_rtp_; > } > if (playout_timestamp_rtp == 0) { >- RTC_LOG(LS_ERROR) << "GetPlayoutTimestamp() failed to retrieve timestamp"; >+ RTC_DLOG(LS_ERROR) << "GetPlayoutTimestamp() failed to retrieve timestamp"; > return -1; > } > timestamp = playout_timestamp_rtp; > return 0; > } > >-int Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, >- RtpReceiver** rtp_receiver) const { >- *rtpRtcpModule = _rtpRtcpModule.get(); >- *rtp_receiver = rtp_receiver_.get(); >- return 0; >+RtpRtcp* Channel::GetRtpRtcp() const { >+ return _rtpRtcpModule.get(); >+} >+ >+absl::optional<Syncable::Info> Channel::GetSyncInfo() const { >+ Syncable::Info info; >+ if (_rtpRtcpModule->RemoteNTP(&info.capture_time_ntp_secs, >+ &info.capture_time_ntp_frac, nullptr, nullptr, >+ &info.capture_time_source_clock) != 0) { >+ return absl::nullopt; >+ } >+ { >+ rtc::CritScope cs(&rtp_sources_lock_); >+ if (!last_received_rtp_timestamp_ || !last_received_rtp_system_time_ms_) { >+ return absl::nullopt; >+ } >+ info.latest_received_capture_timestamp = *last_received_rtp_timestamp_; >+ info.latest_receive_time_ms = *last_received_rtp_system_time_ms_; >+ } >+ return info; > } > > void Channel::UpdatePlayoutTimestamp(bool rtcp) { >@@ -1427,8 +1375,8 @@ void Channel::UpdatePlayoutTimestamp(bool rtcp) { > > uint16_t delay_ms = 0; > if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) { >- RTC_LOG(LS_WARNING) << "Channel::UpdatePlayoutTimestamp() failed to read" >- << " playout delay from the ADM"; >+ RTC_DLOG(LS_WARNING) << "Channel::UpdatePlayoutTimestamp() failed to read" >+ << " playout delay from the ADM"; > return; > } > >@@ -1493,25 +1441,23 @@ int64_t Channel::GetRTT(bool allow_associate_channel) const { > return rtt; > } > >- uint32_t remoteSSRC = rtp_receiver_->SSRC(); > std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin(); > for (; it != report_blocks.end(); ++it) { >- if (it->sender_ssrc == remoteSSRC) >+ if (it->sender_ssrc == remote_ssrc_) > break; > } >- if (it == report_blocks.end()) { >- // We have not received packets with SSRC matching the report blocks. >- // To calculate RTT we try with the SSRC of the first report block. >- // This is very important for send-only channels where we don't know >- // the SSRC of the other end. >- remoteSSRC = report_blocks[0].sender_ssrc; >- } >+ >+ // If we have not received packets with SSRC matching the report blocks, use >+ // the SSRC of the first report block for calculating the RTT. This is very >+ // important for send-only channels where we don't know the SSRC of the other >+ // end. >+ uint32_t ssrc = >+ (it == report_blocks.end()) ? report_blocks[0].sender_ssrc : remote_ssrc_; > > int64_t avg_rtt = 0; > int64_t max_rtt = 0; > int64_t min_rtt = 0; >- if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt) != >- 0) { >+ if (_rtpRtcpModule->RTT(ssrc, &rtt, &avg_rtt, &min_rtt, &max_rtt) != 0) { > return 0; > } > return rtt; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.h >similarity index 83% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.h >index 3d6dd8f226c..98f26134925 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel.h >@@ -8,28 +8,37 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef VOICE_ENGINE_CHANNEL_H_ >-#define VOICE_ENGINE_CHANNEL_H_ >+#ifndef AUDIO_CHANNEL_H_ >+#define AUDIO_CHANNEL_H_ > >+#include <map> > #include <memory> >+#include <string> >+#include <vector> > >+#include "absl/types/optional.h" > #include "api/audio/audio_mixer.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/call/audio_sink.h" > #include "api/call/transport.h" >-#include "api/optional.h" >+#include "api/rtpreceiverinterface.h" >+#include "audio/audio_level.h" >+#include "call/syncable.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/audio_coding/include/audio_coding_module.h" > #include "modules/audio_processing/rms_level.h" > #include "modules/rtp_rtcp/include/remote_ntp_time_estimator.h" > #include "modules/rtp_rtcp/include/rtp_header_parser.h" >-#include "modules/rtp_rtcp/include/rtp_receiver.h" > #include "modules/rtp_rtcp/include/rtp_rtcp.h" >+#include "modules/rtp_rtcp/source/contributing_sources.h" > #include "rtc_base/criticalsection.h" > #include "rtc_base/event.h" > #include "rtc_base/task_queue.h" > #include "rtc_base/thread_checker.h" >-#include "voice_engine/audio_level.h" >+ >+// TODO(solenberg, nisse): This file contains a few NOLINT marks, to silence >+// warnings about use of unsigned short, and non-const reference arguments. >+// These need cleanup, in a separate cl. > > namespace rtc { > class TimestampWrapAroundHandler; >@@ -44,17 +53,14 @@ class RateLimiter; > class ReceiveStatistics; > class RemoteNtpTimeEstimator; > class RtcEventLog; >-class RTPPayloadRegistry; >-class RTPReceiverAudio; > class RtpPacketReceived; > class RtpRtcp; > class RtpTransportControllerSendInterface; >-class TelephoneEventHandler; > > struct SenderInfo; > > struct CallStatistics { >- unsigned short fractionLost; >+ unsigned short fractionLost; // NOLINT > unsigned int cumulativeLost; > unsigned int extendedMax; > unsigned int jitterSamples; >@@ -73,7 +79,7 @@ struct ReportBlock { > uint32_t sender_SSRC; // SSRC of sender > uint32_t source_SSRC; > uint8_t fraction_lost; >- uint32_t cumulative_num_packets_lost; >+ int32_t cumulative_num_packets_lost; > uint32_t extended_highest_sequence_number; > uint32_t interarrival_jitter; > uint32_t last_SR_timestamp; >@@ -82,8 +88,6 @@ struct ReportBlock { > > namespace voe { > >-class RtcEventLogProxy; >-class RtcpRttStatsProxy; > class RtpPacketSenderProxy; > class TransportFeedbackProxy; > class TransportSequenceNumberProxy; >@@ -131,7 +135,6 @@ class ChannelState { > > class Channel > : public RtpData, >- public RtpFeedback, > public Transport, > public AudioPacketizationCallback, // receive encoded packets from the > // ACM >@@ -144,13 +147,19 @@ class Channel > // Used for send streams. > Channel(rtc::TaskQueue* encoder_queue, > ProcessThread* module_process_thread, >- AudioDeviceModule* audio_device_module); >+ AudioDeviceModule* audio_device_module, >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcEventLog* rtc_event_log); > // Used for receive streams. > Channel(ProcessThread* module_process_thread, > AudioDeviceModule* audio_device_module, >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcEventLog* rtc_event_log, >+ uint32_t remote_ssrc, > size_t jitter_buffer_max_packets, > bool jitter_buffer_fast_playout, >- rtc::scoped_refptr<AudioDecoderFactory> decoder_factory); >+ rtc::scoped_refptr<AudioDecoderFactory> decoder_factory, >+ absl::optional<AudioCodecPairId> codec_pair_id); > virtual ~Channel(); > > void SetSink(AudioSinkInterface* sink); >@@ -171,7 +180,7 @@ class Channel > void StopSend(); > > // Codecs >- int32_t GetRecCodec(CodecInst& codec); >+ int32_t GetRecCodec(CodecInst& codec); // NOLINT > void SetBitRate(int bitrate_bps, int64_t probing_interval_ms); > bool EnableAudioNetworkAdaptor(const std::string& config_string); > void DisableAudioNetworkAdaptor(); >@@ -187,7 +196,6 @@ class Channel > // Muting, Volume and Level. > void SetInputMute(bool enable); > void SetChannelOutputVolumeScaling(float scaling); >- int GetSpeechOutputLevel() const; > int GetSpeechOutputLevelFullRange() const; > // See description of "totalAudioEnergy" in the WebRTC stats spec: > // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy >@@ -195,22 +203,28 @@ class Channel > double GetTotalOutputDuration() const; > > // Stats. >- int GetNetworkStatistics(NetworkStatistics& stats); >+ int GetNetworkStatistics(NetworkStatistics& stats); // NOLINT > void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const; > ANAStats GetANAStatistics() const; > > // Audio+Video Sync. > uint32_t GetDelayEstimate() const; > int SetMinimumPlayoutDelay(int delayMs); >- int GetPlayoutTimestamp(unsigned int& timestamp); >- int GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const; >+ int GetPlayoutTimestamp(unsigned int& timestamp); // NOLINT >+ >+ // Used by AudioSendStream. >+ RtpRtcp* GetRtpRtcp() const; > >+ // Produces the transport-related timestamps; current_delay_ms is left unset. >+ absl::optional<Syncable::Info> GetSyncInfo() const; > // DTMF. > int SendTelephoneEventOutband(int event, int duration_ms); > int SetSendTelephoneEventPayloadType(int payload_type, int payload_frequency); > > // RTP+RTCP > int SetLocalSSRC(unsigned int ssrc); >+ >+ void SetMid(const std::string& mid, int extension_id); > int SetSendAudioLevelIndicationStatus(bool enable, unsigned char id); > void EnableSendTransportSequenceNumber(int id); > >@@ -223,7 +237,7 @@ class Channel > void SetRTCPStatus(bool enable); > int SetRTCP_CNAME(const char cName[256]); > int GetRemoteRTCPReportBlocks(std::vector<ReportBlock>* report_blocks); >- int GetRTPStatistics(CallStatistics& stats); >+ int GetRTPStatistics(CallStatistics& stats); // NOLINT > void SetNACKStatus(bool enable, int maxNumberOfPackets); > > // From AudioPacketizationCallback in the ACM >@@ -239,13 +253,6 @@ class Channel > size_t payloadSize, > const WebRtcRTPHeader* rtpHeader) override; > >- // From RtpFeedback in the RTP/RTCP module >- int32_t OnInitializeDecoder(int payload_type, >- const SdpAudioFormat& audio_format, >- uint32_t rate) override; >- void OnIncomingSSRCChanged(uint32_t ssrc) override; >- void OnIncomingCSRCChanged(uint32_t CSRC, bool added) override; >- > // From Transport (called by the RTP/RTCP module) > bool SendRtp(const uint8_t* data, > size_t len, >@@ -262,7 +269,6 @@ class Channel > bool Playing() const { return channel_state_.Get().playing; } > bool Sending() const { return channel_state_.Get().sending; } > RtpRtcp* RtpRtcpModulePtr() const { return _rtpRtcpModule.get(); } >- int8_t OutputEnergyLevel() const { return _outputAudioLevel.Level(); } > > // ProcessAndEncodeAudio() posts a task on the shared encoder task queue, > // which in turn calls (on the queue) ProcessAndEncodeAudioOnTaskQueue() where >@@ -279,10 +285,6 @@ class Channel > // Used for obtaining RTT for a receive-only channel. > void SetAssociatedSendChannel(Channel* channel); > >- // Set a RtcEventLog logging object. >- void SetRtcEventLog(RtcEventLog* event_log); >- >- void SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats); > void SetTransportOverhead(size_t transport_overhead_per_packet); > > // From OverheadObserver in the RTP/RTCP module >@@ -296,9 +298,7 @@ class Channel > > void OnRecoverableUplinkPacketLossRate(float recoverable_packet_loss_rate); > >- std::vector<RtpSource> GetSources() const { >- return rtp_receiver_->GetSources(); >- } >+ std::vector<RtpSource> GetSources() const; > > private: > class ProcessAndEncodeAudioTask; >@@ -306,15 +306,14 @@ class Channel > void Init(); > void Terminate(); > >- int GetRemoteSSRC(unsigned int& ssrc); >+ int GetRemoteSSRC(unsigned int& ssrc); // NOLINT > void OnUplinkPacketLossRate(float packet_loss_rate); > bool InputMute() const; > > bool ReceivePacket(const uint8_t* packet, > size_t packet_length, > const RTPHeader& header); >- bool IsPacketInOrder(const RTPHeader& header) const; >- bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const; >+ bool IsPacketRetransmitted(const RTPHeader& header) const; > int ResendPackets(const uint16_t* sequence_numbers, int length); > void UpdatePlayoutTimestamp(bool rtcp); > >@@ -337,23 +336,35 @@ class Channel > > ChannelState channel_state_; > >- std::unique_ptr<voe::RtcEventLogProxy> event_log_proxy_; >- std::unique_ptr<voe::RtcpRttStatsProxy> rtcp_rtt_stats_proxy_; >+ RtcEventLog* const event_log_; >+ >+ // Indexed by payload type. >+ std::map<uint8_t, int> payload_type_frequencies_; > >- std::unique_ptr<RTPPayloadRegistry> rtp_payload_registry_; > std::unique_ptr<ReceiveStatistics> rtp_receive_statistics_; >- std::unique_ptr<RtpReceiver> rtp_receiver_; >- TelephoneEventHandler* telephone_event_handler_; > std::unique_ptr<RtpRtcp> _rtpRtcpModule; >+ const uint32_t remote_ssrc_; >+ >+ // Info for GetSources and GetSyncInfo is updated on network or worker thread, >+ // queried on the worker thread. >+ rtc::CriticalSection rtp_sources_lock_; >+ ContributingSources contributing_sources_ RTC_GUARDED_BY(&rtp_sources_lock_); >+ absl::optional<uint32_t> last_received_rtp_timestamp_ >+ RTC_GUARDED_BY(&rtp_sources_lock_); >+ absl::optional<int64_t> last_received_rtp_system_time_ms_ >+ RTC_GUARDED_BY(&rtp_sources_lock_); >+ absl::optional<uint8_t> last_received_rtp_audio_level_ >+ RTC_GUARDED_BY(&rtp_sources_lock_); >+ > std::unique_ptr<AudioCodingModule> audio_coding_; > AudioSinkInterface* audio_sink_ = nullptr; > AudioLevel _outputAudioLevel; >- uint32_t _timeStamp RTC_ACCESS_ON(encoder_queue_); >+ uint32_t _timeStamp RTC_GUARDED_BY(encoder_queue_); > > RemoteNtpTimeEstimator ntp_estimator_ RTC_GUARDED_BY(ts_stats_lock_); > > // Timestamp of the audio pulled from NetEq. >- rtc::Optional<uint32_t> jitter_buffer_playout_timestamp_; >+ absl::optional<uint32_t> jitter_buffer_playout_timestamp_; > > rtc::CriticalSection video_sync_lock_; > uint32_t playout_timestamp_rtp_ RTC_GUARDED_BY(video_sync_lock_); >@@ -373,9 +384,9 @@ class Channel > ProcessThread* _moduleProcessThreadPtr; > AudioDeviceModule* _audioDeviceModulePtr; > Transport* _transportPtr; // WebRtc socket or external transport >- RmsLevel rms_level_ RTC_ACCESS_ON(encoder_queue_); >+ RmsLevel rms_level_ RTC_GUARDED_BY(encoder_queue_); > bool input_mute_ RTC_GUARDED_BY(volume_settings_critsect_); >- bool previous_frame_muted_ RTC_ACCESS_ON(encoder_queue_); >+ bool previous_frame_muted_ RTC_GUARDED_BY(encoder_queue_); > float _outputGain RTC_GUARDED_BY(volume_settings_critsect_); > // VoeRTP_RTCP > // TODO(henrika): can today be accessed on the main thread and on the >@@ -410,4 +421,4 @@ class Channel > } // namespace voe > } // namespace webrtc > >-#endif // VOICE_ENGINE_CHANNEL_H_ >+#endif // AUDIO_CHANNEL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.cc >similarity index 91% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.cc >index 70564d4c911..5e8181a7031 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.cc >@@ -8,7 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "voice_engine/channel_proxy.h" >+#include "audio/channel_proxy.h" > > #include <utility> > >@@ -22,8 +22,8 @@ namespace webrtc { > namespace voe { > ChannelProxy::ChannelProxy() {} > >-ChannelProxy::ChannelProxy(std::unique_ptr<Channel> channel) : >- channel_(std::move(channel)) { >+ChannelProxy::ChannelProxy(std::unique_ptr<Channel> channel) >+ : channel_(std::move(channel)) { > RTC_DCHECK(channel_); > module_process_thread_checker_.DetachFromThread(); > } >@@ -53,6 +53,11 @@ void ChannelProxy::SetLocalSSRC(uint32_t ssrc) { > RTC_DCHECK_EQ(0, error); > } > >+void ChannelProxy::SetMid(const std::string& mid, int extension_id) { >+ RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >+ channel_->SetMid(mid, extension_id); >+} >+ > void ChannelProxy::SetRTCP_CNAME(const std::string& c_name) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > // Note: VoERTP_RTCP::SetRTCP_CNAME() accepts a char[256] array. >@@ -82,7 +87,7 @@ void ChannelProxy::RegisterSenderCongestionControlObjects( > RtcpBandwidthObserver* bandwidth_observer) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > channel_->RegisterSenderCongestionControlObjects(transport, >- bandwidth_observer); >+ bandwidth_observer); > } > > void ChannelProxy::RegisterReceiverCongestionControlObjects( >@@ -137,11 +142,6 @@ ANAStats ChannelProxy::GetANAStatistics() const { > return channel_->GetANAStatistics(); > } > >-int ChannelProxy::GetSpeechOutputLevel() const { >- RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- return channel_->GetSpeechOutputLevel(); >-} >- > int ChannelProxy::GetSpeechOutputLevelFullRange() const { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > return channel_->GetSpeechOutputLevelFullRange(); >@@ -167,7 +167,7 @@ bool ChannelProxy::SetSendTelephoneEventPayloadType(int payload_type, > int payload_frequency) { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > return channel_->SetSendTelephoneEventPayloadType(payload_type, >- payload_frequency) == 0; >+ payload_frequency) == 0; > } > > bool ChannelProxy::SendTelephoneEventOutband(int event, int duration_ms) { >@@ -221,11 +221,6 @@ void ChannelProxy::SetChannelOutputVolumeScaling(float scaling) { > channel_->SetChannelOutputVolumeScaling(scaling); > } > >-void ChannelProxy::SetRtcEventLog(RtcEventLog* event_log) { >- RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- channel_->SetRtcEventLog(event_log); >-} >- > AudioMixer::Source::AudioFrameInfo ChannelProxy::GetAudioFrameWithInfo( > int sample_rate_hz, > AudioFrame* audio_frame) { >@@ -260,13 +255,14 @@ void ChannelProxy::DisassociateSendChannel() { > channel_->SetAssociatedSendChannel(nullptr); > } > >-void ChannelProxy::GetRtpRtcp(RtpRtcp** rtp_rtcp, >- RtpReceiver** rtp_receiver) const { >+RtpRtcp* ChannelProxy::GetRtpRtcp() const { > RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); >- RTC_DCHECK(rtp_rtcp); >- RTC_DCHECK(rtp_receiver); >- int error = channel_->GetRtpRtcp(rtp_rtcp, rtp_receiver); >- RTC_DCHECK_EQ(0, error); >+ return channel_->GetRtpRtcp(); >+} >+ >+absl::optional<Syncable::Info> ChannelProxy::GetSyncInfo() const { >+ RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); >+ return channel_->GetSyncInfo(); > } > > uint32_t ChannelProxy::GetPlayoutTimestamp() const { >@@ -288,11 +284,6 @@ void ChannelProxy::SetMinimumPlayoutDelay(int delay_ms) { > } > } > >-void ChannelProxy::SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats) { >- RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); >- channel_->SetRtcpRttStats(rtcp_rtt_stats); >-} >- > bool ChannelProxy::GetRecCodec(CodecInst* codec_inst) const { > RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); > return channel_->GetRecCodec(*codec_inst) == 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.h >similarity index 92% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.h >index ef81174c0ea..f82c1fd2811 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/channel_proxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/channel_proxy.h >@@ -8,9 +8,10 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef VOICE_ENGINE_CHANNEL_PROXY_H_ >-#define VOICE_ENGINE_CHANNEL_PROXY_H_ >+#ifndef AUDIO_CHANNEL_PROXY_H_ >+#define AUDIO_CHANNEL_PROXY_H_ > >+#include <map> > #include <memory> > #include <string> > #include <vector> >@@ -18,11 +19,11 @@ > #include "api/audio/audio_mixer.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/rtpreceiverinterface.h" >+#include "audio/channel.h" > #include "call/rtp_packet_sink_interface.h" > #include "rtc_base/constructormagic.h" > #include "rtc_base/race_checker.h" > #include "rtc_base/thread_checker.h" >-#include "voice_engine/channel.h" > > namespace webrtc { > >@@ -33,7 +34,6 @@ class RtcpBandwidthObserver; > class RtcpRttStats; > class RtpPacketSender; > class RtpPacketReceived; >-class RtpReceiver; > class RtpRtcp; > class RtpTransportControllerSendInterface; > class Transport; >@@ -61,6 +61,7 @@ class ChannelProxy : public RtpPacketSinkInterface { > > virtual void SetRTCPStatus(bool enable); > virtual void SetLocalSSRC(uint32_t ssrc); >+ virtual void SetMid(const std::string& mid, int extension_id); > virtual void SetRTCP_CNAME(const std::string& c_name); > virtual void SetNACKStatus(bool enable, int max_packets); > virtual void SetSendAudioLevelIndicationStatus(bool enable, int id); >@@ -77,7 +78,6 @@ class ChannelProxy : public RtpPacketSinkInterface { > virtual NetworkStatistics GetNetworkStatistics() const; > virtual AudioDecodingCallStats GetDecodingCallStatistics() const; > virtual ANAStats GetANAStatistics() const; >- virtual int GetSpeechOutputLevel() const; > virtual int GetSpeechOutputLevelFullRange() const; > // See description of "totalAudioEnergy" in the WebRTC stats spec: > // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy >@@ -97,7 +97,6 @@ class ChannelProxy : public RtpPacketSinkInterface { > void OnRtpPacket(const RtpPacketReceived& packet) override; > virtual bool ReceivedRTCPPacket(const uint8_t* packet, size_t length); > virtual void SetChannelOutputVolumeScaling(float scaling); >- virtual void SetRtcEventLog(RtcEventLog* event_log); > virtual AudioMixer::Source::AudioFrameInfo GetAudioFrameWithInfo( > int sample_rate_hz, > AudioFrame* audio_frame); >@@ -106,11 +105,12 @@ class ChannelProxy : public RtpPacketSinkInterface { > virtual void SetTransportOverhead(int transport_overhead_per_packet); > virtual void AssociateSendChannel(const ChannelProxy& send_channel_proxy); > virtual void DisassociateSendChannel(); >- virtual void GetRtpRtcp(RtpRtcp** rtp_rtcp, >- RtpReceiver** rtp_receiver) const; >+ virtual RtpRtcp* GetRtpRtcp() const; >+ >+ // Produces the transport-related timestamps; current_delay_ms is left unset. >+ absl::optional<Syncable::Info> GetSyncInfo() const; > virtual uint32_t GetPlayoutTimestamp() const; > virtual void SetMinimumPlayoutDelay(int delay_ms); >- virtual void SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats); > virtual bool GetRecCodec(CodecInst* codec_inst) const; > virtual void OnTwccBasedUplinkPacketLossRate(float packet_loss_rate); > virtual void OnRecoverableUplinkPacketLossRate( >@@ -141,4 +141,4 @@ class ChannelProxy : public RtpPacketSinkInterface { > } // namespace voe > } // namespace webrtc > >-#endif // VOICE_ENGINE_CHANNEL_PROXY_H_ >+#endif // AUDIO_CHANNEL_PROXY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/test/mock_voe_channel_proxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/mock_voe_channel_proxy.h >similarity index 71% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/test/mock_voe_channel_proxy.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/mock_voe_channel_proxy.h >index 9bc48b10a09..f6a2637c420 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/test/mock_voe_channel_proxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/mock_voe_channel_proxy.h >@@ -8,28 +8,30 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef TEST_MOCK_VOE_CHANNEL_PROXY_H_ >-#define TEST_MOCK_VOE_CHANNEL_PROXY_H_ >+#ifndef AUDIO_MOCK_VOE_CHANNEL_PROXY_H_ >+#define AUDIO_MOCK_VOE_CHANNEL_PROXY_H_ > >+#include <map> >+#include <memory> > #include <string> >+#include <vector> > >+#include "audio/channel_proxy.h" > #include "modules/rtp_rtcp/source/rtp_packet_received.h" > #include "test/gmock.h" >-#include "voice_engine/channel_proxy.h" > > namespace webrtc { > namespace test { > > class MockVoEChannelProxy : public voe::ChannelProxy { > public: >- // GTest doesn't like move-only types, like std::unique_ptr >- bool SetEncoder(int payload_type, >- std::unique_ptr<AudioEncoder> encoder) { >+ // GMock doesn't like move-only types, like std::unique_ptr. >+ virtual bool SetEncoder(int payload_type, >+ std::unique_ptr<AudioEncoder> encoder) { > return SetEncoderForMock(payload_type, &encoder); > } > MOCK_METHOD2(SetEncoderForMock, >- bool(int payload_type, >- std::unique_ptr<AudioEncoder>* encoder)); >+ bool(int payload_type, std::unique_ptr<AudioEncoder>* encoder)); > MOCK_METHOD1( > ModifyEncoder, > void(rtc::FunctionView<void(std::unique_ptr<AudioEncoder>*)> modifier)); >@@ -38,9 +40,7 @@ class MockVoEChannelProxy : public voe::ChannelProxy { > MOCK_METHOD1(SetRTCP_CNAME, void(const std::string& c_name)); > MOCK_METHOD2(SetNACKStatus, void(bool enable, int max_packets)); > MOCK_METHOD2(SetSendAudioLevelIndicationStatus, void(bool enable, int id)); >- MOCK_METHOD2(SetReceiveAudioLevelIndicationStatus, void(bool enable, int id)); > MOCK_METHOD1(EnableSendTransportSequenceNumber, void(int id)); >- MOCK_METHOD1(EnableReceiveTransportSequenceNumber, void(int id)); > MOCK_METHOD2(RegisterSenderCongestionControlObjects, > void(RtpTransportControllerSendInterface* transport, > RtcpBandwidthObserver* bandwidth_observer)); >@@ -53,36 +53,35 @@ class MockVoEChannelProxy : public voe::ChannelProxy { > MOCK_CONST_METHOD0(GetNetworkStatistics, NetworkStatistics()); > MOCK_CONST_METHOD0(GetDecodingCallStatistics, AudioDecodingCallStats()); > MOCK_CONST_METHOD0(GetANAStatistics, ANAStats()); >- MOCK_CONST_METHOD0(GetSpeechOutputLevel, int()); > MOCK_CONST_METHOD0(GetSpeechOutputLevelFullRange, int()); > MOCK_CONST_METHOD0(GetTotalOutputEnergy, double()); > MOCK_CONST_METHOD0(GetTotalOutputDuration, double()); > MOCK_CONST_METHOD0(GetDelayEstimate, uint32_t()); >- MOCK_METHOD2(SetSendTelephoneEventPayloadType, bool(int payload_type, >- int payload_frequency)); >+ MOCK_METHOD2(SetSendTelephoneEventPayloadType, >+ bool(int payload_type, int payload_frequency)); > MOCK_METHOD2(SendTelephoneEventOutband, bool(int event, int duration_ms)); > MOCK_METHOD2(SetBitrate, void(int bitrate_bps, int64_t probing_interval_ms)); >- // TODO(solenberg): Talk the compiler into accepting this mock method: >- // MOCK_METHOD1(SetSink, void(std::unique_ptr<AudioSinkInterface> sink)); >+ MOCK_METHOD1(SetSink, void(AudioSinkInterface* sink)); > MOCK_METHOD1(SetInputMute, void(bool muted)); > MOCK_METHOD1(RegisterTransport, void(Transport* transport)); > MOCK_METHOD1(OnRtpPacket, void(const RtpPacketReceived& packet)); > MOCK_METHOD2(ReceivedRTCPPacket, bool(const uint8_t* packet, size_t length)); >- MOCK_CONST_METHOD0(GetAudioDecoderFactory, >- const rtc::scoped_refptr<AudioDecoderFactory>&()); > MOCK_METHOD1(SetChannelOutputVolumeScaling, void(float scaling)); >- MOCK_METHOD1(SetRtcEventLog, void(RtcEventLog* event_log)); >- MOCK_METHOD1(SetRtcpRttStats, void(RtcpRttStats* rtcp_rtt_stats)); > MOCK_METHOD2(GetAudioFrameWithInfo, >- AudioMixer::Source::AudioFrameInfo(int sample_rate_hz, >- AudioFrame* audio_frame)); >+ AudioMixer::Source::AudioFrameInfo(int sample_rate_hz, >+ AudioFrame* audio_frame)); > MOCK_CONST_METHOD0(PreferredSampleRate, int()); >+ // GMock doesn't like move-only types, like std::unique_ptr. >+ virtual void ProcessAndEncodeAudio(std::unique_ptr<AudioFrame> audio_frame) { >+ ProcessAndEncodeAudioForMock(&audio_frame); >+ } >+ MOCK_METHOD1(ProcessAndEncodeAudioForMock, >+ void(std::unique_ptr<AudioFrame>* audio_frame)); > MOCK_METHOD1(SetTransportOverhead, void(int transport_overhead_per_packet)); > MOCK_METHOD1(AssociateSendChannel, > void(const ChannelProxy& send_channel_proxy)); > MOCK_METHOD0(DisassociateSendChannel, void()); >- MOCK_CONST_METHOD2(GetRtpRtcp, void(RtpRtcp** rtp_rtcp, >- RtpReceiver** rtp_receiver)); >+ MOCK_CONST_METHOD0(GetRtpRtcp, RtpRtcp*()); > MOCK_CONST_METHOD0(GetPlayoutTimestamp, uint32_t()); > MOCK_METHOD1(SetMinimumPlayoutDelay, void(int delay_ms)); > MOCK_CONST_METHOD1(GetRecCodec, bool(CodecInst* codec_inst)); >@@ -92,8 +91,12 @@ class MockVoEChannelProxy : public voe::ChannelProxy { > MOCK_METHOD1(OnRecoverableUplinkPacketLossRate, > void(float recoverable_packet_loss_rate)); > MOCK_CONST_METHOD0(GetSources, std::vector<RtpSource>()); >+ MOCK_METHOD0(StartSend, void()); >+ MOCK_METHOD0(StopSend, void()); >+ MOCK_METHOD0(StartPlayout, void()); >+ MOCK_METHOD0(StopPlayout, void()); > }; > } // namespace test > } // namespace webrtc > >-#endif // TEST_MOCK_VOE_CHANNEL_PROXY_H_ >+#endif // AUDIO_MOCK_VOE_CHANNEL_PROXY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.cc >similarity index 92% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.cc >index 5caa73ae451..97222e947a4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.cc >@@ -8,13 +8,13 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "voice_engine/utility.h" >+#include "audio/remix_resample.h" > >+#include "api/audio/audio_frame.h" > #include "audio/utility/audio_frame_operations.h" > #include "common_audio/resampler/include/push_resampler.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" > #include "common_types.h" // NOLINT(build/include) >-#include "modules/include/module_common_types.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" > >@@ -68,9 +68,9 @@ void RemixAndResample(const int16_t* src_data, > // how much to zero here; or 2) make resampler accept a hint that the input is > // zeroed. > const size_t src_length = samples_per_channel * audio_ptr_num_channels; >- int out_length = resampler->Resample(audio_ptr, src_length, >- dst_frame->mutable_data(), >- AudioFrame::kMaxDataSizeSamples); >+ int out_length = >+ resampler->Resample(audio_ptr, src_length, dst_frame->mutable_data(), >+ AudioFrame::kMaxDataSizeSamples); > if (out_length == -1) { > RTC_FATAL() << "Resample failed: audio_ptr = " << audio_ptr > << ", src_length = " << src_length >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.h >similarity index 86% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.h >index dc23e1667dc..a45270b39a6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample.h >@@ -8,20 +8,13 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-/* >- * Contains functions often used by different parts of VoiceEngine. >- */ >- >-#ifndef VOICE_ENGINE_UTILITY_H_ >-#define VOICE_ENGINE_UTILITY_H_ >+#ifndef AUDIO_REMIX_RESAMPLE_H_ >+#define AUDIO_REMIX_RESAMPLE_H_ > >+#include "api/audio/audio_frame.h" > #include "common_audio/resampler/include/push_resampler.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { >- >-class AudioFrame; >- > namespace voe { > > // Upmix or downmix and resample the audio to |dst_frame|. Expects |dst_frame| >@@ -48,4 +41,4 @@ void RemixAndResample(const int16_t* src_data, > } // namespace voe > } // namespace webrtc > >-#endif // VOICE_ENGINE_UTILITY_H_ >+#endif // AUDIO_REMIX_RESAMPLE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample_unittest.cc >similarity index 94% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample_unittest.cc >index c798582d4b0..f1fb5f7dd05 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/utility_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/remix_resample_unittest.cc >@@ -10,12 +10,12 @@ > > #include <math.h> > >+#include "audio/remix_resample.h" > #include "common_audio/resampler/include/push_resampler.h" >-#include "modules/include/module_common_types.h" > #include "rtc_base/arraysize.h" >+#include "rtc_base/checks.h" > #include "rtc_base/format_macros.h" > #include "test/gtest.h" >-#include "voice_engine/utility.h" > > namespace webrtc { > namespace voe { >@@ -113,7 +113,8 @@ void VerifyParams(const AudioFrame& ref_frame, const AudioFrame& test_frame) { > // Computes the best SNR based on the error between |ref_frame| and > // |test_frame|. It allows for up to a |max_delay| in samples between the > // signals to compensate for the resampling delay. >-float ComputeSNR(const AudioFrame& ref_frame, const AudioFrame& test_frame, >+float ComputeSNR(const AudioFrame& ref_frame, >+ const AudioFrame& test_frame, > size_t max_delay) { > VerifyParams(ref_frame, test_frame); > float best_snr = 0; >@@ -123,8 +124,9 @@ float ComputeSNR(const AudioFrame& ref_frame, const AudioFrame& test_frame, > float variance = 0; > const int16_t* ref_frame_data = ref_frame.data(); > const int16_t* test_frame_data = test_frame.data(); >- for (size_t i = 0; i < ref_frame.samples_per_channel_ * >- ref_frame.num_channels_ - delay; i++) { >+ for (size_t i = 0; >+ i < ref_frame.samples_per_channel_ * ref_frame.num_channels_ - delay; >+ i++) { > int error = ref_frame_data[i] - test_frame_data[i + delay]; > mse += error * error; > variance += ref_frame_data[i] * ref_frame_data[i]; >@@ -145,7 +147,7 @@ void VerifyFramesAreEqual(const AudioFrame& ref_frame, > const AudioFrame& test_frame) { > VerifyParams(ref_frame, test_frame); > const int16_t* ref_frame_data = ref_frame.data(); >- const int16_t* test_frame_data = test_frame.data(); >+ const int16_t* test_frame_data = test_frame.data(); > for (size_t i = 0; > i < ref_frame.samples_per_channel_ * ref_frame.num_channels_; i++) { > EXPECT_EQ(ref_frame_data[i], test_frame_data[i]); >@@ -161,8 +163,8 @@ void UtilityTest::RunResampleTest(int src_channels, > const int16_t kSrcCh2 = 15; > const int16_t kSrcCh3 = 22; > const int16_t kSrcCh4 = 8; >- const float resampling_factor = (1.0 * src_sample_rate_hz) / >- dst_sample_rate_hz; >+ const float resampling_factor = >+ (1.0 * src_sample_rate_hz) / dst_sample_rate_hz; > const float dst_ch1 = resampling_factor * kSrcCh1; > const float dst_ch2 = resampling_factor * kSrcCh2; > const float dst_ch3 = resampling_factor * kSrcCh3; >@@ -206,7 +208,7 @@ void UtilityTest::RunResampleTest(int src_channels, > static_cast<double>(dst_sample_rate_hz) / src_sample_rate_hz * > kInputKernelDelaySamples * dst_channels * 2); > printf("(%d, %d Hz) -> (%d, %d Hz) ", // SNR reported on the same line later. >- src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); >+ src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); > RemixAndResample(src_frame_, &resampler, &dst_frame_); > > if (src_sample_rate_hz == 96000 && dst_sample_rate_hz == 8000) { >@@ -258,8 +260,7 @@ TEST_F(UtilityTest, RemixAndResampleSucceeds) { > > for (int src_rate = 0; src_rate < kSampleRatesSize; src_rate++) { > for (int dst_rate = 0; dst_rate < kSampleRatesSize; dst_rate++) { >- for (int src_channel = 0; src_channel < kSrcChannelsSize; >- src_channel++) { >+ for (int src_channel = 0; src_channel < kSrcChannelsSize; src_channel++) { > for (int dst_channel = 0; dst_channel < kDstChannelsSize; > dst_channel++) { > RunResampleTest(kSrcChannels[src_channel], kSampleRates[src_rate], >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.cc >index f89ced97f4d..4d8ac804c87 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.cc >@@ -10,8 +10,8 @@ > > #include "audio/test/audio_bwe_integration_test.h" > >+#include "absl/memory/memory.h" > #include "common_audio/wav_file.h" >-#include "rtc_base/ptr_util.h" > #include "system_wrappers/include/sleep.h" > #include "test/field_trial.h" > #include "test/gtest.h" >@@ -37,14 +37,14 @@ size_t AudioBweTest::GetNumFlexfecStreams() const { > return 0; > } > >-std::unique_ptr<test::FakeAudioDevice::Capturer> >+std::unique_ptr<TestAudioDeviceModule::Capturer> > AudioBweTest::CreateCapturer() { >- return test::FakeAudioDevice::CreateWavFileReader(AudioInputFile()); >+ return TestAudioDeviceModule::CreateWavFileReader(AudioInputFile()); > } > > void AudioBweTest::OnFakeAudioDevicesCreated( >- test::FakeAudioDevice* send_audio_device, >- test::FakeAudioDevice* recv_audio_device) { >+ TestAudioDeviceModule* send_audio_device, >+ TestAudioDeviceModule* recv_audio_device) { > send_audio_device_ = send_audio_device; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.h >index 0b0cb6c73bd..a88b047993c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_bwe_integration_test.h >@@ -14,7 +14,6 @@ > #include <string> > > #include "test/call_test.h" >-#include "test/fake_audio_device.h" > #include "test/single_threaded_task_queue.h" > > namespace webrtc { >@@ -33,11 +32,11 @@ class AudioBweTest : public test::EndToEndTest { > size_t GetNumAudioStreams() const override; > size_t GetNumFlexfecStreams() const override; > >- std::unique_ptr<test::FakeAudioDevice::Capturer> CreateCapturer() override; >+ std::unique_ptr<TestAudioDeviceModule::Capturer> CreateCapturer() override; > > void OnFakeAudioDevicesCreated( >- test::FakeAudioDevice* send_audio_device, >- test::FakeAudioDevice* recv_audio_device) override; >+ TestAudioDeviceModule* send_audio_device, >+ TestAudioDeviceModule* recv_audio_device) override; > > test::PacketTransport* CreateSendTransport( > SingleThreadedTaskQueueForTesting* task_queue, >@@ -48,7 +47,7 @@ class AudioBweTest : public test::EndToEndTest { > void PerformTest() override; > > private: >- test::FakeAudioDevice* send_audio_device_; >+ TestAudioDeviceModule* send_audio_device_; > }; > > } // namespace test >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.cc >index 44bf3f775ac..820b46444e7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.cc >@@ -12,7 +12,6 @@ > > #include "audio/test/audio_end_to_end_test.h" > #include "system_wrappers/include/sleep.h" >-#include "test/fake_audio_device.h" > #include "test/gtest.h" > > namespace webrtc { >@@ -43,19 +42,19 @@ size_t AudioEndToEndTest::GetNumFlexfecStreams() const { > return 0; > } > >-std::unique_ptr<test::FakeAudioDevice::Capturer> >- AudioEndToEndTest::CreateCapturer() { >- return test::FakeAudioDevice::CreatePulsedNoiseCapturer(32000, kSampleRate); >+std::unique_ptr<TestAudioDeviceModule::Capturer> >+AudioEndToEndTest::CreateCapturer() { >+ return TestAudioDeviceModule::CreatePulsedNoiseCapturer(32000, kSampleRate); > } > >-std::unique_ptr<test::FakeAudioDevice::Renderer> >- AudioEndToEndTest::CreateRenderer() { >- return test::FakeAudioDevice::CreateDiscardRenderer(kSampleRate); >+std::unique_ptr<TestAudioDeviceModule::Renderer> >+AudioEndToEndTest::CreateRenderer() { >+ return TestAudioDeviceModule::CreateDiscardRenderer(kSampleRate); > } > > void AudioEndToEndTest::OnFakeAudioDevicesCreated( >- test::FakeAudioDevice* send_audio_device, >- test::FakeAudioDevice* recv_audio_device) { >+ TestAudioDeviceModule* send_audio_device, >+ TestAudioDeviceModule* recv_audio_device) { > send_audio_device_ = send_audio_device; > } > >@@ -68,15 +67,15 @@ test::PacketTransport* AudioEndToEndTest::CreateSendTransport( > } > > test::PacketTransport* AudioEndToEndTest::CreateReceiveTransport( >- SingleThreadedTaskQueueForTesting* task_queue) { >+ SingleThreadedTaskQueueForTesting* task_queue) { > return new test::PacketTransport( > task_queue, nullptr, this, test::PacketTransport::kReceiver, > test::CallTest::payload_type_map_, GetNetworkPipeConfig()); > } > > void AudioEndToEndTest::ModifyAudioConfigs( >- AudioSendStream::Config* send_config, >- std::vector<AudioReceiveStream::Config>* receive_configs) { >+ AudioSendStream::Config* send_config, >+ std::vector<AudioReceiveStream::Config>* receive_configs) { > // Large bitrate by default. > const webrtc::SdpAudioFormat kDefaultFormat("opus", 48000, 2, > {{"stereo", "1"}}); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.h >index 921de844833..cbe25f5b3a9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/audio_end_to_end_test.h >@@ -24,7 +24,7 @@ class AudioEndToEndTest : public test::EndToEndTest { > AudioEndToEndTest(); > > protected: >- test::FakeAudioDevice* send_audio_device() { return send_audio_device_; } >+ TestAudioDeviceModule* send_audio_device() { return send_audio_device_; } > const AudioSendStream* send_stream() const { return send_stream_; } > const AudioReceiveStream* receive_stream() const { return receive_stream_; } > >@@ -34,12 +34,12 @@ class AudioEndToEndTest : public test::EndToEndTest { > size_t GetNumAudioStreams() const override; > size_t GetNumFlexfecStreams() const override; > >- std::unique_ptr<test::FakeAudioDevice::Capturer> CreateCapturer() override; >- std::unique_ptr<test::FakeAudioDevice::Renderer> CreateRenderer() override; >+ std::unique_ptr<TestAudioDeviceModule::Capturer> CreateCapturer() override; >+ std::unique_ptr<TestAudioDeviceModule::Renderer> CreateRenderer() override; > > void OnFakeAudioDevicesCreated( >- test::FakeAudioDevice* send_audio_device, >- test::FakeAudioDevice* recv_audio_device) override; >+ TestAudioDeviceModule* send_audio_device, >+ TestAudioDeviceModule* recv_audio_device) override; > > test::PacketTransport* CreateSendTransport( > SingleThreadedTaskQueueForTesting* task_queue, >@@ -57,7 +57,7 @@ class AudioEndToEndTest : public test::EndToEndTest { > void PerformTest() override; > > private: >- test::FakeAudioDevice* send_audio_device_ = nullptr; >+ TestAudioDeviceModule* send_audio_device_ = nullptr; > AudioSendStream* send_stream_ = nullptr; > AudioReceiveStream* receive_stream_ = nullptr; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.cc >index cf84e19924b..169f4bf592c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.cc >@@ -13,10 +13,12 @@ > #include "system_wrappers/include/sleep.h" > #include "test/testsupport/fileutils.h" > >-DEFINE_int(sample_rate_hz, 16000, >+DEFINE_int(sample_rate_hz, >+ 16000, > "Sample rate (Hz) of the produced audio files."); > >-DEFINE_bool(quick, false, >+DEFINE_bool(quick, >+ false, > "Don't do the full audio recording. " > "Used to quickly check that the test runs without crashing."); > >@@ -42,15 +44,15 @@ class AudioQualityTest : public AudioEndToEndTest { > const ::testing::TestInfo* const test_info = > ::testing::UnitTest::GetInstance()->current_test_info(); > return webrtc::test::OutputPath() + "LowBandwidth_" + test_info->name() + >- "_" + FileSampleRateSuffix() + ".wav"; >+ "_" + FileSampleRateSuffix() + ".wav"; > } > >- std::unique_ptr<test::FakeAudioDevice::Capturer> CreateCapturer() override { >- return test::FakeAudioDevice::CreateWavFileReader(AudioInputFile()); >+ std::unique_ptr<TestAudioDeviceModule::Capturer> CreateCapturer() override { >+ return TestAudioDeviceModule::CreateWavFileReader(AudioInputFile()); > } > >- std::unique_ptr<test::FakeAudioDevice::Renderer> CreateRenderer() override { >- return test::FakeAudioDevice::CreateBoundedWavFileWriter( >+ std::unique_ptr<TestAudioDeviceModule::Renderer> CreateRenderer() override { >+ return TestAudioDeviceModule::CreateBoundedWavFileWriter( > AudioOutputFile(), FLAG_sample_rate_hz); > } > >@@ -69,22 +71,21 @@ class AudioQualityTest : public AudioEndToEndTest { > > // Output information about the input and output audio files so that further > // processing can be done by an external process. >- printf("TEST %s %s %s\n", test_info->name(), >- AudioInputFile().c_str(), AudioOutputFile().c_str()); >+ printf("TEST %s %s %s\n", test_info->name(), AudioInputFile().c_str(), >+ AudioOutputFile().c_str()); > } > }; > > class Mobile2GNetworkTest : public AudioQualityTest { >- void ModifyAudioConfigs(AudioSendStream::Config* send_config, >+ void ModifyAudioConfigs( >+ AudioSendStream::Config* send_config, > std::vector<AudioReceiveStream::Config>* receive_configs) override { > send_config->send_codec_spec = AudioSendStream::Config::SendCodecSpec( > test::CallTest::kAudioSendPayloadType, > {"OPUS", > 48000, > 2, >- {{"maxaveragebitrate", "6000"}, >- {"ptime", "60"}, >- {"stereo", "1"}}}); >+ {{"maxaveragebitrate", "6000"}, {"ptime", "60"}, {"stereo", "1"}}}); > } > > FakeNetworkPipe::Config GetNetworkPipeConfig() const override { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.py b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.py >index 9e2597741b9..b81a0476faf 100755 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.py >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/test/low_bandwidth_audio_test.py >@@ -55,13 +55,15 @@ def _ParseArgs(): > parser.add_argument('--android', action='store_true', > help='Perform the test on a connected Android device instead.') > parser.add_argument('--adb-path', help='Path to adb binary.', default='adb') >- parser.add_argument('--chartjson-result-file', >+ parser.add_argument('--num-retries', default='0', >+ help='Number of times to retry the test on Android.') >+ parser.add_argument('--isolated-script-test-perf-output', > help='Where to store perf results in chartjson format.', default=None) > > # Ignore Chromium-specific flags > parser.add_argument('--isolated-script-test-output', > type=str, default=None) >- parser.add_argument('--isolated-script-test-perf-output', >+ parser.add_argument('--test-launcher-summary-output', > type=str, default=None) > args = parser.parse_args() > >@@ -221,7 +223,8 @@ def main(): > out_dir = os.path.join(args.build_dir, '..') > if args.android: > test_command = [os.path.join(args.build_dir, 'bin', >- 'run_low_bandwidth_audio_test'), '-v'] >+ 'run_low_bandwidth_audio_test'), >+ '-v', '--num-retries', args.num_retries] > else: > test_command = [os.path.join(args.build_dir, 'low_bandwidth_audio_test')] > >@@ -267,8 +270,8 @@ def main(): > finally: > test_process.terminate() > >- if args.chartjson_result_file: >- with open(args.chartjson_result_file, 'w') as f: >+ if args.isolated_script_test_perf_output: >+ with open(args.isolated_script_test_perf_output, 'w') as f: > json.dump({"format_version": "1.0", "charts": charts}, f) > > return test_process.wait() >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval.h >index 88b2f7dd4f5..79fe29d9d56 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval.h >@@ -13,7 +13,7 @@ > > #include <stdint.h> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > > namespace webrtc { > >@@ -57,7 +57,7 @@ class TimeInterval { > > int64_t first, last; > }; >- rtc::Optional<Interval> interval_; >+ absl::optional<Interval> interval_; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval_unittest.cc >index 7f8b44ecec5..deff6e363da 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/time_interval_unittest.cc >@@ -9,8 +9,8 @@ > */ > > #include "audio/time_interval.h" >+#include "api/units/time_delta.h" > #include "rtc_base/fakeclock.h" >-#include "rtc_base/timedelta.h" > #include "test/gtest.h" > > namespace webrtc { >@@ -19,7 +19,7 @@ TEST(TimeIntervalTest, TimeInMs) { > rtc::ScopedFakeClock fake_clock; > TimeInterval interval; > interval.Extend(); >- fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(100)); >+ fake_clock.AdvanceTime(TimeDelta::ms(100)); > interval.Extend(); > EXPECT_EQ(interval.Length(), 100); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.cc >similarity index 96% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.cc >index 774faf5219b..7e0c5c542f8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.cc >@@ -8,7 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "voice_engine/transport_feedback_packet_loss_tracker.h" >+#include "audio/transport_feedback_packet_loss_tracker.h" > > #include <limits> > #include <utility> >@@ -116,12 +116,12 @@ void TransportFeedbackPacketLossTracker::OnPacketFeedbackVector( > } > } > >-rtc::Optional<float> >-TransportFeedbackPacketLossTracker::GetPacketLossRate() const { >+absl::optional<float> TransportFeedbackPacketLossTracker::GetPacketLossRate() >+ const { > return plr_state_.GetMetric(); > } > >-rtc::Optional<float> >+absl::optional<float> > TransportFeedbackPacketLossTracker::GetRecoverablePacketLossRate() const { > return rplr_state_.GetMetric(); > } >@@ -344,20 +344,20 @@ void TransportFeedbackPacketLossTracker::Validate() const { // Testing only! > RTC_CHECK_EQ(rplr_state_.num_recoverable_losses_, recoverable_losses); > } > >-rtc::Optional<float> >-TransportFeedbackPacketLossTracker::PlrState::GetMetric() const { >+absl::optional<float> TransportFeedbackPacketLossTracker::PlrState::GetMetric() >+ const { > const size_t total = num_lost_packets_ + num_received_packets_; > if (total < min_num_acked_packets_) { >- return rtc::nullopt; >+ return absl::nullopt; > } else { > return static_cast<float>(num_lost_packets_) / total; > } > } > >-rtc::Optional<float> >-TransportFeedbackPacketLossTracker::RplrState::GetMetric() const { >+absl::optional<float> TransportFeedbackPacketLossTracker::RplrState::GetMetric() >+ const { > if (num_acked_pairs_ < min_num_acked_pairs_) { >- return rtc::nullopt; >+ return absl::nullopt; > } else { > return static_cast<float>(num_recoverable_losses_) / num_acked_pairs_; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.h >similarity index 91% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.h >index d7420785f7b..7d58d6c4bd3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker.h >@@ -8,13 +8,13 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#ifndef VOICE_ENGINE_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ >-#define VOICE_ENGINE_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ >+#ifndef AUDIO_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ >+#define AUDIO_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ > > #include <map> >+#include <vector> > >-#include "api/optional.h" >-#include "modules/include/module_common_types.h" >+#include "absl/types/optional.h" > > namespace webrtc { > >@@ -43,11 +43,11 @@ class TransportFeedbackPacketLossTracker final { > > // Returns the packet loss rate, if the window has enough packet statuses to > // reliably compute it. Otherwise, returns empty. >- rtc::Optional<float> GetPacketLossRate() const; >+ absl::optional<float> GetPacketLossRate() const; > > // Returns the first-order-FEC recoverable packet loss rate, if the window has > // enough status pairs to reliably compute it. Otherwise, returns empty. >- rtc::Optional<float> GetRecoverablePacketLossRate() const; >+ absl::optional<float> GetRecoverablePacketLossRate() const; > > // Verifies that the internal states are correct. Only used for tests. > void Validate() const; >@@ -108,7 +108,7 @@ class TransportFeedbackPacketLossTracker final { > num_received_packets_ = 0; > num_lost_packets_ = 0; > } >- rtc::Optional<float> GetMetric() const; >+ absl::optional<float> GetMetric() const; > const size_t min_num_acked_packets_; > size_t num_received_packets_; > size_t num_lost_packets_; >@@ -124,7 +124,7 @@ class TransportFeedbackPacketLossTracker final { > num_acked_pairs_ = 0; > num_recoverable_losses_ = 0; > } >- rtc::Optional<float> GetMetric() const; >+ absl::optional<float> GetMetric() const; > // Recoverable packets are those which were lost, but immediately followed > // by a properly received packet. If that second packet carried FEC, > // the data from the former (lost) packet could be recovered. >@@ -138,4 +138,4 @@ class TransportFeedbackPacketLossTracker final { > > } // namespace webrtc > >-#endif // VOICE_ENGINE_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ >+#endif // AUDIO_TRANSPORT_FEEDBACK_PACKET_LOSS_TRACKER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker_unittest.cc >similarity index 93% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker_unittest.cc >index 55626bedd0f..2f9bf68444f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/voice_engine/transport_feedback_packet_loss_tracker_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/transport_feedback_packet_loss_tracker_unittest.cc >@@ -13,12 +13,12 @@ > #include <numeric> > #include <vector> > >+#include "audio/transport_feedback_packet_loss_tracker.h" > #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" > #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" > #include "rtc_base/checks.h" > #include "test/gmock.h" > #include "test/gtest.h" >-#include "voice_engine/transport_feedback_packet_loss_tracker.h" > > namespace webrtc { > >@@ -94,18 +94,18 @@ class TransportFeedbackPacketLossTrackerTest > // value is as expected. > void ValidatePacketLossStatistics( > const TransportFeedbackPacketLossTracker& tracker, >- rtc::Optional<float> expected_plr, >- rtc::Optional<float> expected_rplr) { >- // TODO(eladalon): Comparing the rtc::Optional<float> directly would have >+ absl::optional<float> expected_plr, >+ absl::optional<float> expected_rplr) { >+ // TODO(eladalon): Comparing the absl::optional<float> directly would have > // given concise code, but less readable error messages. If we modify >- // the way rtc::Optional is printed, we can get rid of this. >- rtc::Optional<float> plr = tracker.GetPacketLossRate(); >+ // the way absl::optional is printed, we can get rid of this. >+ absl::optional<float> plr = tracker.GetPacketLossRate(); > EXPECT_EQ(static_cast<bool>(expected_plr), static_cast<bool>(plr)); > if (expected_plr && plr) { > EXPECT_EQ(*expected_plr, *plr); > } > >- rtc::Optional<float> rplr = tracker.GetRecoverablePacketLossRate(); >+ absl::optional<float> rplr = tracker.GetRecoverablePacketLossRate(); > EXPECT_EQ(static_cast<bool>(expected_rplr), static_cast<bool>(rplr)); > if (expected_rplr && rplr) { > EXPECT_EQ(*expected_rplr, *rplr); >@@ -127,7 +127,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindow) { > TransportFeedbackPacketLossTracker tracker(kDefaultMaxWindowSizeMs, 5, 5); > > // PLR and RPLR reported as unknown before reception of first feedback. >- ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt); > } > > // A feedback received for an empty window has no effect. >@@ -136,7 +136,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, EmptyWindowFeedback) { > > // Feedback doesn't correspond to any packets - ignored. > AddTransportFeedbackAndValidate(&tracker, base_, {true, false, true}); >- ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt); > > // After the packets are transmitted, acking them would have an effect. > SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs); >@@ -153,7 +153,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, PartiallyFilledWindow) { > // Expected window contents: [] -> [1001]. > SendPackets(&tracker, base_, 3, kDefaultSendIntervalMs); > AddTransportFeedbackAndValidate(&tracker, base_, {true, false, false, true}); >- ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt); > } > > // Sanity check on minimum filled window - PLR known, RPLR unknown. >@@ -166,7 +166,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, PlrMinimumFilledWindow) { > SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs); > AddTransportFeedbackAndValidate(&tracker, base_, > {true, false, false, true, true}); >- ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, absl::nullopt); > } > > // Sanity check on minimum filled window - PLR unknown, RPLR known. >@@ -179,7 +179,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, RplrMinimumFilledWindow) { > SendPackets(&tracker, base_, 5, kDefaultSendIntervalMs); > AddTransportFeedbackAndValidate(&tracker, base_, > {true, false, false, true, true}); >- ValidatePacketLossStatistics(tracker, rtc::nullopt, 1.0f / 4.0f); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, 1.0f / 4.0f); > } > > // If packets are sent close enough together that the clock reading for both >@@ -203,7 +203,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, ExtendWindow) { > // Expected window contents: [] -> [10011]. > AddTransportFeedbackAndValidate(&tracker, base_, > {true, false, false, true, true}); >- ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, 2.0f / 5.0f, absl::nullopt); > > // Expected window contents: [10011] -> [1001110101]. > AddTransportFeedbackAndValidate(&tracker, base_ + 5, >@@ -412,34 +412,30 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, InsertionCompletesTwoPairs) { > TEST_P(TransportFeedbackPacketLossTrackerTest, SanityGapsInSequenceNumbers) { > TransportFeedbackPacketLossTracker tracker(50 * kDefaultSendIntervalMs, 5, 1); > >- SendPackets(&tracker, >- {static_cast<uint16_t>(base_), >- static_cast<uint16_t>(base_ + 2), >- static_cast<uint16_t>(base_ + 4), >- static_cast<uint16_t>(base_ + 6), >- static_cast<uint16_t>(base_ + 8)}, >- kDefaultSendIntervalMs); >+ SendPackets( >+ &tracker, >+ {static_cast<uint16_t>(base_), static_cast<uint16_t>(base_ + 2), >+ static_cast<uint16_t>(base_ + 4), static_cast<uint16_t>(base_ + 6), >+ static_cast<uint16_t>(base_ + 8)}, >+ kDefaultSendIntervalMs); > > // Gaps in sequence numbers not considered as gaps in window, because only > // those sequence numbers which were associated with the stream count. > // Expected window contents: [] -> [11011]. > AddTransportFeedbackAndValidate( > // Note: Left packets belong to this stream, right ones ignored. >- &tracker, base_, {true, false, >- true, false, >- false, false, >- true, false, >- true, true}); >+ &tracker, base_, >+ {true, false, true, false, false, false, true, false, true, true}); > ValidatePacketLossStatistics(tracker, 1.0f / 5.0f, 1.0f / 4.0f); > > // Create gap by sending [base + 10] but not acking it. > // Note: Acks for [base + 11] and [base + 13] ignored (other stream). > // Expected window contents: [11011] -> [11011-GAP-01]. >- SendPackets(&tracker, >- {static_cast<uint16_t>(base_ + 10), >- static_cast<uint16_t>(base_ + 12), >- static_cast<uint16_t>(base_ + 14)}, >- kDefaultSendIntervalMs); >+ SendPackets( >+ &tracker, >+ {static_cast<uint16_t>(base_ + 10), static_cast<uint16_t>(base_ + 12), >+ static_cast<uint16_t>(base_ + 14)}, >+ kDefaultSendIntervalMs); > AddTransportFeedbackAndValidate(&tracker, base_ + 11, > {false, false, false, true, true}); > ValidatePacketLossStatistics(tracker, 2.0f / 7.0f, 2.0f / 5.0f); >@@ -520,7 +516,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, RepeatedSeqNumResetsWindow) { > // A reset occurs. > SendPackets(&tracker, {static_cast<uint16_t>(base_ + 2)}, > kDefaultSendIntervalMs); >- ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt); > } > > // The window is reset by the sending of a packet which is 0x8000 or more >@@ -539,7 +535,7 @@ TEST_P(TransportFeedbackPacketLossTrackerTest, > // A reset occurs. > SendPackets(&tracker, {static_cast<uint16_t>(base_ + 5 + 0x8000)}, > kDefaultSendIntervalMs); >- ValidatePacketLossStatistics(tracker, rtc::nullopt, rtc::nullopt); >+ ValidatePacketLossStatistics(tracker, absl::nullopt, absl::nullopt); > } > > #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/BUILD.gn >index aa8445c90b3..76c09a51a38 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/BUILD.gn >@@ -22,9 +22,7 @@ rtc_static_library("audio_frame_operations") { > > deps = [ > "../..:webrtc_common", >- "../../:typedefs", >- "../../modules:module_api", >- "../../modules/audio_coding:audio_format_conversion", >+ "../../api/audio:audio_frame_api", > "../../rtc_base:checks", > "../../rtc_base:rtc_base_approved", > ] >@@ -38,7 +36,6 @@ if (rtc_include_tests) { > ] > deps = [ > ":audio_frame_operations", >- "../../modules:module_api", > "../../rtc_base:checks", > "../../rtc_base:rtc_base_approved", > "../../test:test_support", >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.cc >index a7c77821f65..fb1f3b07711 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.cc >@@ -10,9 +10,9 @@ > > #include "audio/utility/audio_frame_operations.h" > >+#include <string.h> > #include <algorithm> > >-#include "modules/include/module_common_types.h" > #include "rtc_base/checks.h" > #include "rtc_base/numerics/safe_conversions.h" > >@@ -159,7 +159,8 @@ void AudioFrameOperations::QuadToMono(const int16_t* src_audio, > for (size_t i = 0; i < samples_per_channel; i++) { > dst_audio[i] = > (static_cast<int32_t>(src_audio[4 * i]) + src_audio[4 * i + 1] + >- src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> 2; >+ src_audio[4 * i + 2] + src_audio[4 * i + 3]) >> >+ 2; > } > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.h b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.h >index cd55f19fc12..599352356f6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations.h >@@ -13,12 +13,10 @@ > > #include <stddef.h> > >-#include "typedefs.h" // NOLINT(build/include) >+#include "api/audio/audio_frame.h" > > namespace webrtc { > >-class AudioFrame; >- > // TODO(andrew): consolidate this with utility.h and audio_frame_manipulator.h. > // Change reference parameters to pointers. Consider using a namespace rather > // than a class. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations_unittest.cc >index 6d23731a05d..76f1dcdb52f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/audio/utility/audio_frame_operations_unittest.cc >@@ -9,7 +9,6 @@ > */ > > #include "audio/utility/audio_frame_operations.h" >-#include "modules/include/module_common_types.h" > #include "rtc_base/checks.h" > #include "test/gtest.h" > >@@ -51,27 +50,29 @@ void SetFrameData(int16_t left, int16_t right, AudioFrame* frame) { > > void SetFrameData(int16_t data, AudioFrame* frame) { > int16_t* frame_data = frame->mutable_data(); >- for (size_t i = 0; >- i < frame->samples_per_channel_ * frame->num_channels_; i++) { >+ for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_; >+ i++) { > frame_data[i] = data; > } > } > > void VerifyFramesAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) { > EXPECT_EQ(frame1.num_channels_, frame2.num_channels_); >- EXPECT_EQ(frame1.samples_per_channel_, >- frame2.samples_per_channel_); >+ EXPECT_EQ(frame1.samples_per_channel_, frame2.samples_per_channel_); > const int16_t* frame1_data = frame1.data(); > const int16_t* frame2_data = frame2.data(); > for (size_t i = 0; i < frame1.samples_per_channel_ * frame1.num_channels_; >- i++) { >+ i++) { > EXPECT_EQ(frame1_data[i], frame2_data[i]); > } > EXPECT_EQ(frame1.muted(), frame2.muted()); > } > >-void InitFrame(AudioFrame* frame, size_t channels, size_t samples_per_channel, >- int16_t left_data, int16_t right_data) { >+void InitFrame(AudioFrame* frame, >+ size_t channels, >+ size_t samples_per_channel, >+ int16_t left_data, >+ int16_t right_data) { > RTC_DCHECK(frame); > RTC_DCHECK_GE(2, channels); > RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples, >@@ -91,7 +92,9 @@ int16_t GetChannelData(const AudioFrame& frame, size_t channel, size_t index) { > return frame.data()[index * frame.num_channels_ + channel]; > } > >-void VerifyFrameDataBounds(const AudioFrame& frame, size_t channel, int16_t max, >+void VerifyFrameDataBounds(const AudioFrame& frame, >+ size_t channel, >+ int16_t max, > int16_t min) { > for (size_t i = 0; i < frame.samples_per_channel_; ++i) { > int16_t s = GetChannelData(frame, channel, i); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/call/BUILD.gn >index f61d57c2ee1..838728ad78b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/BUILD.gn >@@ -10,12 +10,18 @@ import("../webrtc.gni") > > rtc_source_set("call_interfaces") { > sources = [ >+ "audio_receive_stream.cc", > "audio_receive_stream.h", > "audio_send_stream.h", >+ "audio_state.cc", > "audio_state.h", > "call.h", >- "callfactoryinterface.h", >+ "call_config.cc", >+ "call_config.h", >+ "flexfec_receive_stream.cc", > "flexfec_receive_stream.h", >+ "packet_receiver.cc", >+ "packet_receiver.h", > "syncable.cc", > "syncable.h", > ] >@@ -26,15 +32,19 @@ rtc_source_set("call_interfaces") { > ":rtp_interfaces", > ":video_stream_api", > "..:webrtc_common", >- "../:typedefs", >- "../api:audio_mixer_api", >+ "../api:fec_controller_api", > "../api:libjingle_peerconnection_api", >- "../api:optional", > "../api:transport_api", >+ "../api/audio:audio_mixer_api", > "../api/audio_codecs:audio_codecs_api", >+ "../api/transport:network_control", >+ "../modules/audio_device:audio_device", >+ "../modules/audio_processing:audio_processing", > "../modules/audio_processing:audio_processing_statistics", >+ "../rtc_base:audio_format_to_string", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > >@@ -51,7 +61,12 @@ rtc_source_set("rtp_interfaces") { > ] > deps = [ > "../api:array_view", >+ "../api:libjingle_peerconnection_api", >+ "../api/transport:bitrate_settings", >+ "../logging:rtc_event_log_api", >+ "../modules/rtp_rtcp:rtp_rtcp_format", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > >@@ -75,24 +90,61 @@ rtc_source_set("rtp_receiver") { > "..:webrtc_common", > "../api:array_view", > "../api:libjingle_peerconnection_api", >- "../api:optional", > "../modules/rtp_rtcp", > "../modules/rtp_rtcp:rtp_rtcp_format", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_source_set("rtp_sender") { > sources = [ >+ "rtp_payload_params.cc", >+ "rtp_payload_params.h", > "rtp_transport_controller_send.cc", > "rtp_transport_controller_send.h", >+ "rtp_video_sender.cc", >+ "rtp_video_sender.h", >+ "rtp_video_sender_interface.h", > ] > deps = [ >+ ":bitrate_configurator", > ":rtp_interfaces", > "..:webrtc_common", >+ "../api:transport_api", >+ "../api/transport:network_control", >+ "../api/video_codecs:video_codecs_api", >+ "../logging:rtc_event_log_api", > "../modules/congestion_controller", >+ "../modules/congestion_controller/rtp:congestion_controller", > "../modules/pacing", >+ "../modules/rtp_rtcp:rtp_rtcp", >+ "../modules/rtp_rtcp:rtp_rtcp_format", >+ "../modules/rtp_rtcp:rtp_video_header", >+ "../modules/utility", >+ "../modules/video_coding:video_codec_interface", >+ "../rtc_base:checks", >+ "../rtc_base:rate_limiter", >+ "../rtc_base:rtc_base", >+ "../rtc_base:rtc_base_approved", >+ "../rtc_base:rtc_task_queue", >+ "../system_wrappers:field_trial_api", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("bitrate_configurator") { >+ sources = [ >+ "rtp_bitrate_configurator.cc", >+ "rtp_bitrate_configurator.h", >+ ] >+ deps = [ >+ ":rtp_interfaces", >+ "../api:libjingle_peerconnection_api", >+ "../api/transport:bitrate_settings", >+ "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > ] > } >@@ -108,12 +160,9 @@ rtc_source_set("bitrate_allocator") { > "../rtc_base:rtc_base_approved", > "../rtc_base:sequenced_task_checker", > "../system_wrappers", >+ "../system_wrappers:field_trial_api", > "../system_wrappers:metrics_api", > ] >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } > } > > rtc_static_library("call") { >@@ -121,8 +170,12 @@ rtc_static_library("call") { > "call.cc", > "callfactory.cc", > "callfactory.h", >+ "degraded_call.cc", >+ "degraded_call.h", > "flexfec_receive_stream_impl.cc", > "flexfec_receive_stream_impl.h", >+ "receive_time_calculator.cc", >+ "receive_time_calculator.h", > ] > > if (!build_with_chromium && is_clang) { >@@ -133,36 +186,46 @@ rtc_static_library("call") { > deps = [ > ":bitrate_allocator", > ":call_interfaces", >+ ":fake_network", > ":rtp_interfaces", > ":rtp_receiver", > ":rtp_sender", > ":video_stream_api", > "..:webrtc_common", >- "../api:optional", >+ "../api:callfactory_api", > "../api:transport_api", >+ "../api/transport:network_control", > "../audio", >+ "../logging:rtc_event_audio", > "../logging:rtc_event_log_api", >- "../logging:rtc_event_log_impl", >+ "../logging:rtc_event_rtp_rtcp", >+ "../logging:rtc_event_video", >+ "../logging:rtc_stream_config", > "../modules/bitrate_controller", > "../modules/congestion_controller", > "../modules/pacing", > "../modules/rtp_rtcp", > "../modules/rtp_rtcp:rtp_rtcp_format", > "../modules/utility", >+ "../modules/video_coding:video_coding", > "../rtc_base:checks", >+ "../rtc_base:rate_limiter", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_task_queue", >+ "../rtc_base:safe_minmax", > "../rtc_base:sequenced_task_checker", >+ "../rtc_base/synchronization:rw_lock_wrapper", > "../system_wrappers", >+ "../system_wrappers:field_trial_api", > "../system_wrappers:metrics_api", > "../video", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > > rtc_source_set("video_stream_api") { > sources = [ >- "video_config.cc", >- "video_config.h", > "video_receive_stream.cc", > "video_receive_stream.h", > "video_send_stream.cc", >@@ -170,16 +233,49 @@ rtc_source_set("video_stream_api") { > ] > deps = [ > ":rtp_interfaces", >- "../:typedefs", > "../:webrtc_common", > "../api:libjingle_peerconnection_api", >- "../api:optional", > "../api:transport_api", >- "../api:video_frame_api", >+ "../api/video:video_frame", >+ "../api/video:video_stream_encoder", >+ "../api/video_codecs:video_codecs_api", > "../common_video:common_video", > "../modules/rtp_rtcp:rtp_rtcp_format", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("simulated_network") { >+ sources = [ >+ "simulated_network.cc", >+ "simulated_network.h", >+ ] >+ deps = [ >+ "../api:simulated_network_api", >+ "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("fake_network") { >+ sources = [ >+ "fake_network_pipe.cc", >+ "fake_network_pipe.h", >+ ] >+ deps = [ >+ ":call_interfaces", >+ ":simulated_network", >+ "..:webrtc_common", >+ "../api:simulated_network_api", >+ "../api:transport_api", >+ "../modules:module_api", >+ "../rtc_base:rtc_base_approved", >+ "../rtc_base:sequenced_task_checker", >+ "../system_wrappers", >+ "//third_party/abseil-cpp/absl/memory", > ] > } > >@@ -192,13 +288,18 @@ if (rtc_include_tests) { > "bitrate_estimator_tests.cc", > "call_unittest.cc", > "flexfec_receive_stream_unittest.cc", >+ "receive_time_calculator_unittest.cc", > "rtcp_demuxer_unittest.cc", >+ "rtp_bitrate_configurator_unittest.cc", > "rtp_demuxer_unittest.cc", >+ "rtp_payload_params_unittest.cc", > "rtp_rtcp_demuxer_helper_unittest.cc", >+ "rtp_video_sender_unittest.cc", > "rtx_receive_stream_unittest.cc", > ] > deps = [ > ":bitrate_allocator", >+ ":bitrate_configurator", > ":call", > ":call_interfaces", > ":mock_rtp_interfaces", >@@ -212,29 +313,33 @@ if (rtc_include_tests) { > "../api/audio_codecs:builtin_audio_decoder_factory", > "../audio:audio", > "../logging:rtc_event_log_api", >+ "../logging:rtc_event_log_impl_base", > "../modules/audio_device:mock_audio_device", > "../modules/audio_mixer", > "../modules/audio_mixer:audio_mixer_impl", > "../modules/audio_processing:mocks", > "../modules/bitrate_controller", > "../modules/congestion_controller", >- "../modules/congestion_controller:mock_congestion_controller", > "../modules/pacing", > "../modules/pacing:mock_paced_sender", > "../modules/rtp_rtcp", > "../modules/rtp_rtcp:mock_rtp_rtcp", > "../modules/rtp_rtcp:rtp_rtcp_format", > "../modules/utility:mock_process_thread", >+ "../modules/video_coding:video_codec_interface", > "../rtc_base:checks", >+ "../rtc_base:rate_limiter", > "../rtc_base:rtc_base_approved", > "../system_wrappers", > "../test:audio_codec_mocks", > "../test:direct_transport", >+ "../test:field_trial", > "../test:test_common", > "../test:test_support", > "../test:video_test_common", >- "//testing/gmock", >+ "../video:video", > "//testing/gtest", >+ "//third_party/abseil-cpp/absl/memory", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -255,8 +360,12 @@ if (rtc_include_tests) { > ":video_stream_api", > "..:webrtc_common", > "../api/audio_codecs:builtin_audio_encoder_factory", >+ "../api/video:video_bitrate_allocation", >+ "../api/video_codecs:video_codecs_api", > "../logging:rtc_event_log_api", > "../modules/audio_coding", >+ "../modules/audio_device", >+ "../modules/audio_device:audio_device_impl", > "../modules/audio_mixer:audio_mixer_impl", > "../modules/rtp_rtcp", > "../rtc_base:checks", >@@ -265,15 +374,15 @@ if (rtc_include_tests) { > "../system_wrappers:metrics_default", > "../system_wrappers:runtime_enabled_features_default", > "../test:direct_transport", >- "../test:fake_audio_device", > "../test:field_trial", >+ "../test:fileutils", > "../test:perf_test", > "../test:test_common", > "../test:test_support", > "../test:video_test_common", > "../video", >- "../voice_engine", > "//testing/gtest", >+ "//third_party/abseil-cpp/absl/memory", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -286,19 +395,30 @@ if (rtc_include_tests) { > testonly = true > > sources = [ >- "fake_rtp_transport_controller_send.h", > "test/mock_rtp_packet_sink_interface.h", >+ "test/mock_rtp_transport_controller_send.h", > ] > deps = [ > ":rtp_interfaces", >- "..:webrtc_common", >- "../modules/congestion_controller:congestion_controller", >- "../modules/pacing:pacing", >+ "../api:libjingle_peerconnection_api", >+ "../modules/congestion_controller", >+ "../modules/pacing", >+ "../rtc_base:rate_limiter", >+ "../rtc_base:rtc_base", > "../test:test_support", >- "//testing/gmock", > ] > } >+ rtc_source_set("mock_bitrate_allocator") { >+ testonly = true > >+ sources = [ >+ "test/mock_bitrate_allocator.h", >+ ] >+ deps = [ >+ ":bitrate_allocator", >+ "//test:test_support", >+ ] >+ } > rtc_source_set("mock_call_interfaces") { > testonly = true > >@@ -310,4 +430,21 @@ if (rtc_include_tests) { > "//test:test_support", > ] > } >+ >+ rtc_test("fake_network_unittests") { >+ deps = [ >+ ":call_interfaces", >+ ":fake_network", >+ ":simulated_network", >+ "../modules/rtp_rtcp", >+ "../rtc_base:rtc_base_approved", >+ "../system_wrappers", >+ "../test:test_common", >+ "../test:test_main", >+ "//testing/gtest", >+ ] >+ sources = [ >+ "test/fake_network_pipe_unittest.cc", >+ ] >+ } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/call/DEPS >index 7622e241168..f823a7b9c37 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/DEPS >@@ -7,11 +7,11 @@ include_rules = [ > "+modules/audio_processing", > "+modules/bitrate_controller", > "+modules/congestion_controller", >+ "+modules/video_coding", > "+modules/pacing", > "+modules/rtp_rtcp", > "+modules/utility", > "+system_wrappers", >- "+voice_engine", > "+video", > ] > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/call/OWNERS >index fc0487dc2ad..af7f98ae3f8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/OWNERS >@@ -1,6 +1,8 @@ > mflodman@webrtc.org >+nisse@webrtc.org > solenberg@webrtc.org > stefan@webrtc.org >+srte@webrtc.org > > # These are for the common case of adding or renaming files. If you're doing > # structural changes, please get a review from a reviewer in this file. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.cc >new file mode 100644 >index 00000000000..c3c2ac77d06 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.cc >@@ -0,0 +1,24 @@ >+/* >+ * Copyright (c) 2018 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 "call/audio_receive_stream.h" >+ >+namespace webrtc { >+ >+AudioReceiveStream::Stats::Stats() = default; >+AudioReceiveStream::Stats::~Stats() = default; >+ >+AudioReceiveStream::Config::Config() = default; >+AudioReceiveStream::Config::~Config() = default; >+ >+AudioReceiveStream::Config::Rtp::Rtp() = default; >+AudioReceiveStream::Config::Rtp::~Rtp() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.h >index f8d787cb504..9595a293dac 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_receive_stream.h >@@ -16,15 +16,14 @@ > #include <string> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/audio_codecs/audio_decoder_factory.h" > #include "api/call/transport.h" >-#include "api/optional.h" > #include "api/rtpparameters.h" > #include "api/rtpreceiverinterface.h" > #include "call/rtp_config.h" > #include "common_types.h" // NOLINT(build/include) > #include "rtc_base/scoped_ref_ptr.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > class AudioSinkInterface; >@@ -32,13 +31,15 @@ class AudioSinkInterface; > class AudioReceiveStream { > public: > struct Stats { >+ Stats(); >+ ~Stats(); > uint32_t remote_ssrc = 0; > int64_t bytes_rcvd = 0; > uint32_t packets_rcvd = 0; > uint32_t packets_lost = 0; > float fraction_lost = 0.0f; > std::string codec_name; >- rtc::Optional<int> codec_payload_type; >+ absl::optional<int> codec_payload_type; > uint32_t ext_seqnum = 0; > uint32_t jitter_ms = 0; > uint32_t jitter_buffer_ms = 0; >@@ -71,10 +72,16 @@ class AudioReceiveStream { > }; > > struct Config { >+ Config(); >+ ~Config(); >+ > std::string ToString() const; > > // Receive-stream specific RTP settings. > struct Rtp { >+ Rtp(); >+ ~Rtp(); >+ > std::string ToString() const; > > // Synchronization source (stream identifier) to be received. >@@ -98,9 +105,6 @@ class AudioReceiveStream { > > Transport* rtcp_send_transport = nullptr; > >- // TODO(solenberg): Remove once clients don't use it anymore. >- int voe_channel_id = -1; >- > // NetEq settings. > size_t jitter_buffer_max_packets = 50; > bool jitter_buffer_fast_accelerate = false; >@@ -114,6 +118,8 @@ class AudioReceiveStream { > std::map<int, SdpAudioFormat> decoder_map; > > rtc::scoped_refptr<AudioDecoderFactory> decoder_factory; >+ >+ absl::optional<AudioCodecPairId> codec_pair_id; > }; > > // Reconfigure the stream according to the Configuration. >@@ -127,8 +133,6 @@ class AudioReceiveStream { > virtual void Stop() = 0; > > virtual Stats GetStats() const = 0; >- // TODO(solenberg): Remove, once AudioMonitor is gone. >- virtual int GetOutputLevel() const = 0; > > // Sets an audio sink that receives unmixed audio from the receive stream. > // Ownership of the sink is managed by the caller. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.cc >index 274a6ebdb4d..e2cf20cf844 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.cc >@@ -9,8 +9,9 @@ > */ > > #include "call/audio_send_stream.h" >- >-#include <string> >+#include "rtc_base/stringencode.h" >+#include "rtc_base/strings/audio_format_to_string.h" >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > >@@ -23,7 +24,8 @@ AudioSendStream::Config::Config(Transport* send_transport) > AudioSendStream::Config::~Config() = default; > > std::string AudioSendStream::Config::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{rtp: " << rtp.ToString(); > ss << ", send_transport: " << (send_transport ? "(Transport)" : "null"); > ss << ", min_bitrate_bps: " << min_bitrate_bps; >@@ -39,7 +41,8 @@ AudioSendStream::Config::Rtp::Rtp() = default; > AudioSendStream::Config::Rtp::~Rtp() = default; > > std::string AudioSendStream::Config::Rtp::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{ssrc: " << ssrc; > ss << ", extensions: ["; > for (size_t i = 0; i < extensions.size(); ++i) { >@@ -62,13 +65,14 @@ AudioSendStream::Config::SendCodecSpec::SendCodecSpec( > AudioSendStream::Config::SendCodecSpec::~SendCodecSpec() = default; > > std::string AudioSendStream::Config::SendCodecSpec::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{nack_enabled: " << (nack_enabled ? "true" : "false"); > ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false"); > ss << ", cng_payload_type: " >- << (cng_payload_type ? std::to_string(*cng_payload_type) : "<unset>"); >+ << (cng_payload_type ? rtc::ToString(*cng_payload_type) : "<unset>"); > ss << ", payload_type: " << payload_type; >- ss << ", format: " << format; >+ ss << ", format: " << rtc::ToString(format); > ss << '}'; > return ss.str(); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.h >index 03f32b79e62..60909ae128b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_send_stream.h >@@ -15,16 +15,16 @@ > #include <string> > #include <vector> > >+#include "absl/types/optional.h" >+#include "api/audio_codecs/audio_codec_pair_id.h" > #include "api/audio_codecs/audio_encoder.h" > #include "api/audio_codecs/audio_encoder_factory.h" > #include "api/audio_codecs/audio_format.h" > #include "api/call/transport.h" >-#include "api/optional.h" > #include "api/rtpparameters.h" > #include "call/rtp_config.h" > #include "modules/audio_processing/include/audio_processing_statistics.h" > #include "rtc_base/scoped_ref_ptr.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -43,7 +43,7 @@ class AudioSendStream { > int32_t packets_lost = -1; > float fraction_lost = -1.0f; > std::string codec_name; >- rtc::Optional<int> codec_payload_type; >+ absl::optional<int> codec_payload_type; > int32_t ext_seqnum = -1; > int32_t jitter_ms = -1; > int64_t rtt_ms = -1; >@@ -73,6 +73,10 @@ class AudioSendStream { > // Sender SSRC. > uint32_t ssrc = 0; > >+ // The value to send in the MID RTP header extension if the extension is >+ // included in the list of extensions. >+ std::string mid; >+ > // RTP header extensions used for the sent stream. > std::vector<RtpExtension> extensions; > >@@ -87,9 +91,6 @@ class AudioSendStream { > // the entire life of the AudioSendStream and is owned by the API client. > Transport* send_transport = nullptr; > >- // TODO(solenberg): Remove once clients don't use it anymore. >- int voe_channel_id = -1; >- > // Bitrate limits used for variable audio bitrate streams. Set both to -1 to > // disable audio bitrate adaptation. > // Note: This is still an experimental feature and not ready for real usage. >@@ -100,7 +101,7 @@ class AudioSendStream { > > // Defines whether to turn on audio network adaptor, and defines its config > // string. >- rtc::Optional<std::string> audio_network_adaptor_config; >+ absl::optional<std::string> audio_network_adaptor_config; > > struct SendCodecSpec { > SendCodecSpec(int payload_type, const SdpAudioFormat& format); >@@ -116,13 +117,14 @@ class AudioSendStream { > SdpAudioFormat format; > bool nack_enabled = false; > bool transport_cc_enabled = false; >- rtc::Optional<int> cng_payload_type; >+ absl::optional<int> cng_payload_type; > // If unset, use the encoder's default target bitrate. >- rtc::Optional<int> target_bitrate_bps; >+ absl::optional<int> target_bitrate_bps; > }; > >- rtc::Optional<SendCodecSpec> send_codec_spec; >+ absl::optional<SendCodecSpec> send_codec_spec; > rtc::scoped_refptr<AudioEncoderFactory> encoder_factory; >+ absl::optional<AudioCodecPairId> codec_pair_id; > > // Track ID as specified during track creation. > std::string track_id; >@@ -147,8 +149,10 @@ class AudioSendStream { > std::unique_ptr<webrtc::AudioFrame> audio_frame) = 0; > > // TODO(solenberg): Make payload_type a config property instead. >- virtual bool SendTelephoneEvent(int payload_type, int payload_frequency, >- int event, int duration_ms) = 0; >+ virtual bool SendTelephoneEvent(int payload_type, >+ int payload_frequency, >+ int event, >+ int duration_ms) = 0; > > virtual void SetMuted(bool muted) = 0; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.cc >new file mode 100644 >index 00000000000..725d27f423d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.cc >@@ -0,0 +1,18 @@ >+/* >+ * Copyright (c) 2018 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 "call/audio_state.h" >+ >+namespace webrtc { >+ >+AudioState::Config::Config() = default; >+AudioState::Config::~Config() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.h >index a8e57f0f3f5..104f493fb6e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/audio_state.h >@@ -11,23 +11,22 @@ > #define CALL_AUDIO_STATE_H_ > > #include "api/audio/audio_mixer.h" >+#include "modules/audio_device/include/audio_device.h" >+#include "modules/audio_processing/include/audio_processing.h" > #include "rtc_base/refcount.h" > #include "rtc_base/scoped_ref_ptr.h" > > namespace webrtc { > >-class AudioDeviceModule; >-class AudioProcessing; > class AudioTransport; >-class VoiceEngine; > > // AudioState holds the state which must be shared between multiple instances of > // webrtc::Call for audio processing purposes. > class AudioState : public rtc::RefCountInterface { > public: > struct Config { >- // TODO(solenberg): Remove once clients don't use it anymore. >- VoiceEngine* voice_engine = nullptr; >+ Config(); >+ ~Config(); > > // The audio mixer connected to active receive streams. One per > // AudioState. >@@ -43,9 +42,8 @@ class AudioState : public rtc::RefCountInterface { > struct Stats { > // Audio peak level (max(abs())), linearly on the interval [0,32767]. > int32_t audio_level = -1; >- // Audio peak level (max(abs())), logarithmically on the interval [0,9]. >- int8_t quantized_audio_level = -1; >- // See: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy >+ // See: >+ // https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy > double total_energy = 0.0f; > double total_duration = 0.0f; > }; >@@ -71,7 +69,7 @@ class AudioState : public rtc::RefCountInterface { > static rtc::scoped_refptr<AudioState> Create( > const AudioState::Config& config); > >- virtual ~AudioState() {} >+ ~AudioState() override {} > }; > } // namespace webrtc > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.cc >index 0b8ce39c4b5..c7049ba2111 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.cc >@@ -20,16 +20,14 @@ > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" > #include "system_wrappers/include/clock.h" >+#include "system_wrappers/include/field_trial.h" > #include "system_wrappers/include/metrics.h" > > namespace webrtc { > > // Allow packets to be transmitted in up to 2 times max video bitrate if the > // bandwidth estimate allows it. >-// TODO(bugs.webrtc.org/8541): May be worth to refactor to keep this logic in >-// video send stream. Similar logic is implemented in >-// AudioPriorityBitrateAllocationStrategy. >-const int kTransmissionMaxBitrateMultiplier = 2; >+const uint8_t kTransmissionMaxBitrateMultiplier = 2; > const int kDefaultBitrateBps = 300000; > > // Require a bitrate increase of max(10%, 20kbps) to resume paused streams. >@@ -61,7 +59,11 @@ BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer) > last_bwe_log_time_(0), > total_requested_padding_bitrate_(0), > total_requested_min_bitrate_(0), >- bitrate_allocation_strategy_(nullptr) { >+ total_requested_max_bitrate_(0), >+ has_packet_feedback_(false), >+ bitrate_allocation_strategy_(nullptr), >+ transmission_max_bitrate_multiplier_( >+ GetTransmissionMaxBitrateMultiplier()) { > sequenced_checker_.Detach(); > } > >@@ -70,6 +72,20 @@ BitrateAllocator::~BitrateAllocator() { > num_pause_events_); > } > >+// static >+uint8_t BitrateAllocator::GetTransmissionMaxBitrateMultiplier() { >+ uint64_t multiplier = strtoul(webrtc::field_trial::FindFullName( >+ "WebRTC-TransmissionMaxBitrateMultiplier") >+ .c_str(), >+ nullptr, 10); >+ if (multiplier > 0 && multiplier <= kTransmissionMaxBitrateMultiplier) { >+ RTC_LOG(LS_INFO) << "TransmissionMaxBitrateMultiplier is set to " >+ << multiplier; >+ return static_cast<uint8_t>(multiplier); >+ } >+ return kTransmissionMaxBitrateMultiplier; >+} >+ > void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, > uint8_t fraction_loss, > int64_t rtt, >@@ -94,8 +110,7 @@ void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, > for (auto& config : bitrate_observer_configs_) { > uint32_t allocated_bitrate = allocation[config.observer]; > uint32_t protection_bitrate = config.observer->OnBitrateUpdated( >- allocated_bitrate, last_fraction_loss_, last_rtt_, >- last_bwe_period_ms_); >+ allocated_bitrate, last_fraction_loss_, last_rtt_, last_bwe_period_ms_); > > if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) { > if (target_bitrate_bps > 0) >@@ -127,28 +142,24 @@ void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, > } > > void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, >- uint32_t min_bitrate_bps, >- uint32_t max_bitrate_bps, >- uint32_t pad_up_bitrate_bps, >- bool enforce_min_bitrate, >- std::string track_id, >- double bitrate_priority) { >+ MediaStreamAllocationConfig config) { > RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); >- RTC_DCHECK_GT(bitrate_priority, 0); >- RTC_DCHECK(std::isnormal(bitrate_priority)); >+ RTC_DCHECK_GT(config.bitrate_priority, 0); >+ RTC_DCHECK(std::isnormal(config.bitrate_priority)); > auto it = FindObserverConfig(observer); > > // Update settings if the observer already exists, create a new one otherwise. > if (it != bitrate_observer_configs_.end()) { >- it->min_bitrate_bps = min_bitrate_bps; >- it->max_bitrate_bps = max_bitrate_bps; >- it->pad_up_bitrate_bps = pad_up_bitrate_bps; >- it->enforce_min_bitrate = enforce_min_bitrate; >- it->bitrate_priority = bitrate_priority; >+ it->min_bitrate_bps = config.min_bitrate_bps; >+ it->max_bitrate_bps = config.max_bitrate_bps; >+ it->pad_up_bitrate_bps = config.pad_up_bitrate_bps; >+ it->enforce_min_bitrate = config.enforce_min_bitrate; >+ it->bitrate_priority = config.bitrate_priority; > } else { > bitrate_observer_configs_.push_back(ObserverConfig( >- observer, min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, >- enforce_min_bitrate, track_id, bitrate_priority)); >+ observer, config.min_bitrate_bps, config.max_bitrate_bps, >+ config.pad_up_bitrate_bps, config.enforce_min_bitrate, config.track_id, >+ config.bitrate_priority, config.has_packet_feedback)); > } > > ObserverAllocation allocation; >@@ -176,10 +187,10 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, > } > > void BitrateAllocator::UpdateAllocationLimits() { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > uint32_t total_requested_padding_bitrate = 0; > uint32_t total_requested_min_bitrate = 0; >- >+ uint32_t total_requested_max_bitrate = 0; >+ bool has_packet_feedback = false; > for (const auto& config : bitrate_observer_configs_) { > uint32_t stream_padding = config.pad_up_bitrate_bps; > if (config.enforce_min_bitrate) { >@@ -189,22 +200,32 @@ void BitrateAllocator::UpdateAllocationLimits() { > std::max(config.MinBitrateWithHysteresis(), stream_padding); > } > total_requested_padding_bitrate += stream_padding; >+ total_requested_max_bitrate += config.max_bitrate_bps; >+ if (config.allocated_bitrate_bps > 0 && config.has_packet_feedback) >+ has_packet_feedback = true; > } > > if (total_requested_padding_bitrate == total_requested_padding_bitrate_ && >- total_requested_min_bitrate == total_requested_min_bitrate_) { >+ total_requested_min_bitrate == total_requested_min_bitrate_ && >+ total_requested_max_bitrate == total_requested_max_bitrate_ && >+ has_packet_feedback == has_packet_feedback_) { > return; > } > > total_requested_min_bitrate_ = total_requested_min_bitrate; > total_requested_padding_bitrate_ = total_requested_padding_bitrate; >+ total_requested_max_bitrate_ = total_requested_max_bitrate; >+ has_packet_feedback_ = has_packet_feedback; > > RTC_LOG(LS_INFO) << "UpdateAllocationLimits : total_requested_min_bitrate: " > << total_requested_min_bitrate > << "bps, total_requested_padding_bitrate: " >- << total_requested_padding_bitrate << "bps"; >- limit_observer_->OnAllocationLimitsChanged(total_requested_min_bitrate, >- total_requested_padding_bitrate); >+ << total_requested_padding_bitrate >+ << "bps, total_requested_max_bitrate: " >+ << total_requested_max_bitrate << "bps"; >+ limit_observer_->OnAllocationLimitsChanged( >+ total_requested_min_bitrate, total_requested_padding_bitrate, >+ total_requested_max_bitrate, has_packet_feedback); > } > > void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { >@@ -244,7 +265,6 @@ void BitrateAllocator::SetBitrateAllocationStrategy( > > BitrateAllocator::ObserverConfigs::iterator > BitrateAllocator::FindObserverConfig(const BitrateAllocatorObserver* observer) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > for (auto it = bitrate_observer_configs_.begin(); > it != bitrate_observer_configs_.end(); ++it) { > if (it->observer == observer) >@@ -255,7 +275,6 @@ BitrateAllocator::FindObserverConfig(const BitrateAllocatorObserver* observer) { > > BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates( > uint32_t bitrate) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > if (bitrate_observer_configs_.empty()) > return ObserverAllocation(); > >@@ -299,12 +318,11 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates( > if (bitrate <= sum_max_bitrates) > return NormalRateAllocation(bitrate, sum_min_bitrates); > >- // All observers will get up to kTransmissionMaxBitrateMultiplier x max. >+ // All observers will get up to transmission_max_bitrate_multiplier_ x max. > return MaxRateAllocation(bitrate, sum_max_bitrates); > } > > BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > ObserverAllocation allocation; > for (const auto& observer_config : bitrate_observer_configs_) > allocation[observer_config.observer] = 0; >@@ -313,7 +331,6 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() { > > BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( > uint32_t bitrate) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > ObserverAllocation allocation; > // Start by allocating bitrate to observers enforcing a min bitrate, hence > // remaining_bitrate might turn negative. >@@ -375,7 +392,6 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( > BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation( > uint32_t bitrate, > uint32_t sum_min_bitrates) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > ObserverAllocation allocation; > ObserverAllocation observers_capacities; > for (const auto& observer_config : bitrate_observer_configs_) { >@@ -396,14 +412,13 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation( > BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation( > uint32_t bitrate, > uint32_t sum_max_bitrates) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > ObserverAllocation allocation; > > for (const auto& observer_config : bitrate_observer_configs_) { > allocation[observer_config.observer] = observer_config.max_bitrate_bps; > bitrate -= observer_config.max_bitrate_bps; > } >- DistributeBitrateEvenly(bitrate, true, kTransmissionMaxBitrateMultiplier, >+ DistributeBitrateEvenly(bitrate, true, transmission_max_bitrate_multiplier_, > &allocation); > return allocation; > } >@@ -437,7 +452,6 @@ void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate, > bool include_zero_allocations, > int max_multiplier, > ObserverAllocation* allocation) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size()); > > ObserverSortingMap list_max_bitrates; >@@ -470,7 +484,6 @@ void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate, > > bool BitrateAllocator::EnoughBitrateForAllObservers(uint32_t bitrate, > uint32_t sum_min_bitrates) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > if (bitrate < sum_min_bitrates) > return false; > >@@ -490,7 +503,6 @@ void BitrateAllocator::DistributeBitrateRelatively( > uint32_t remaining_bitrate, > const ObserverAllocation& observers_capacities, > ObserverAllocation* allocation) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_); > RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size()); > RTC_DCHECK_EQ(observers_capacities.size(), bitrate_observer_configs_.size()); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.h >index b1afc8c424e..c29ea5e0899 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator.h >@@ -43,25 +43,62 @@ class BitrateAllocatorObserver { > virtual ~BitrateAllocatorObserver() {} > }; > >+// Struct describing parameters for how a media stream should get bitrate >+// allocated to it. |min_bitrate_bps| = 0 equals no min bitrate. >+// |max_bitrate_bps| = 0 equals no max bitrate. >+// |enforce_min_bitrate| = 'true' will allocate at least |min_bitrate_bps| for >+// this observer, even if the BWE is too low, 'false' will allocate 0 to >+// the observer if BWE doesn't allow |min_bitrate_bps|. >+// |has_packet_feedback| indicates whether the data produced by the >+// corresponding media stream will receive per packet feedback. This is >+// tracked here to communicate to limit observers whether packet feedback can >+// be expected, which is true if any of the active observers has packet >+// feedback enabled. Note that |observer|->OnBitrateUpdated() will be called >+// within the scope of this method with the current rtt, fraction_loss and >+// available bitrate and that the bitrate in OnBitrateUpdated will be zero if >+// the |observer| is currently not allowed to send data. >+struct MediaStreamAllocationConfig { >+ uint32_t min_bitrate_bps; >+ uint32_t max_bitrate_bps; >+ uint32_t pad_up_bitrate_bps; >+ bool enforce_min_bitrate; >+ std::string track_id; >+ double bitrate_priority; >+ bool has_packet_feedback; >+}; >+ >+// Interface used for mocking >+class BitrateAllocatorInterface { >+ public: >+ virtual void AddObserver(BitrateAllocatorObserver* observer, >+ MediaStreamAllocationConfig config) = 0; >+ virtual void RemoveObserver(BitrateAllocatorObserver* observer) = 0; >+ virtual int GetStartBitrate(BitrateAllocatorObserver* observer) = 0; >+ >+ protected: >+ virtual ~BitrateAllocatorInterface() = default; >+}; >+ > // Usage: this class will register multiple RtcpBitrateObserver's one at each > // RTCP module. It will aggregate the results and run one bandwidth estimation > // and push the result to the encoders via BitrateAllocatorObserver(s). >-class BitrateAllocator { >+class BitrateAllocator : public BitrateAllocatorInterface { > public: > // Used to get notified when send stream limits such as the minimum send > // bitrate and max padding bitrate is changed. > class LimitObserver { > public: >- virtual void OnAllocationLimitsChanged( >- uint32_t min_send_bitrate_bps, >- uint32_t max_padding_bitrate_bps) = 0; >+ virtual void OnAllocationLimitsChanged(uint32_t min_send_bitrate_bps, >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps, >+ bool has_packet_feedback) = 0; > > protected: >- virtual ~LimitObserver() {} >+ virtual ~LimitObserver() = default; > }; > > explicit BitrateAllocator(LimitObserver* limit_observer); >- ~BitrateAllocator(); >+ ~BitrateAllocator() override; > > // Allocate target_bitrate across the registered BitrateAllocatorObservers. > void OnNetworkChanged(uint32_t target_bitrate_bps, >@@ -69,33 +106,19 @@ class BitrateAllocator { > int64_t rtt, > int64_t bwe_period_ms); > >- // Set the start and max send bitrate used by the bandwidth management. >- // >+ // Set the configuration used by the bandwidth management. > // |observer| updates bitrates if already in use. >- // |min_bitrate_bps| = 0 equals no min bitrate. >- // |max_bitrate_bps| = 0 equals no max bitrate. >- // |enforce_min_bitrate| = 'true' will allocate at least |min_bitrate_bps| for >- // this observer, even if the BWE is too low, 'false' will allocate 0 to >- // the observer if BWE doesn't allow |min_bitrate_bps|. >- // Note that |observer|->OnBitrateUpdated() will be called within the scope of >- // this method with the current rtt, fraction_loss and available bitrate and >- // that the bitrate in OnBitrateUpdated will be zero if the |observer| is >- // currently not allowed to send data. >+ // |config| is the configuration to use for allocation. > void AddObserver(BitrateAllocatorObserver* observer, >- uint32_t min_bitrate_bps, >- uint32_t max_bitrate_bps, >- uint32_t pad_up_bitrate_bps, >- bool enforce_min_bitrate, >- std::string track_id, >- double bitrate_priority); >+ MediaStreamAllocationConfig config) override; > > // Removes a previously added observer, but will not trigger a new bitrate > // allocation. >- void RemoveObserver(BitrateAllocatorObserver* observer); >+ void RemoveObserver(BitrateAllocatorObserver* observer) override; > > // Returns initial bitrate allocated for |observer|. If |observer| is not in > // the list of added observers, a best guess is returned. >- int GetStartBitrate(BitrateAllocatorObserver* observer); >+ int GetStartBitrate(BitrateAllocatorObserver* observer) override; > > // Sets external allocation strategy. If strategy is not set default WebRTC > // allocation mechanism will be used. The strategy may be changed during call. >@@ -112,7 +135,8 @@ class BitrateAllocator { > uint32_t pad_up_bitrate_bps, > bool enforce_min_bitrate, > std::string track_id, >- double bitrate_priority) >+ double bitrate_priority, >+ bool has_packet_feedback) > : TrackConfig(min_bitrate_bps, > max_bitrate_bps, > enforce_min_bitrate, >@@ -121,7 +145,8 @@ class BitrateAllocator { > pad_up_bitrate_bps(pad_up_bitrate_bps), > allocated_bitrate_bps(-1), > media_ratio(1.0), >- bitrate_priority(bitrate_priority) {} >+ bitrate_priority(bitrate_priority), >+ has_packet_feedback(has_packet_feedback) {} > > BitrateAllocatorObserver* observer; > uint32_t pad_up_bitrate_bps; >@@ -131,6 +156,7 @@ class BitrateAllocator { > // observers. If an observer has twice the bitrate_priority of other > // observers, it should be allocated twice the bitrate above its min. > double bitrate_priority; >+ bool has_packet_feedback; > > uint32_t LastAllocatedBitrate() const; > // The minimum bitrate required by this observer, including >@@ -140,31 +166,35 @@ class BitrateAllocator { > > // Calculates the minimum requested send bitrate and max padding bitrate and > // calls LimitObserver::OnAllocationLimitsChanged. >- void UpdateAllocationLimits(); >+ void UpdateAllocationLimits() RTC_RUN_ON(&sequenced_checker_); > > typedef std::vector<ObserverConfig> ObserverConfigs; > ObserverConfigs::iterator FindObserverConfig( >- const BitrateAllocatorObserver* observer); >+ const BitrateAllocatorObserver* observer) RTC_RUN_ON(&sequenced_checker_); > > typedef std::multimap<uint32_t, const ObserverConfig*> ObserverSortingMap; > typedef std::map<BitrateAllocatorObserver*, int> ObserverAllocation; > >- ObserverAllocation AllocateBitrates(uint32_t bitrate); >+ ObserverAllocation AllocateBitrates(uint32_t bitrate) >+ RTC_RUN_ON(&sequenced_checker_); > > // Allocates zero bitrate to all observers. >- ObserverAllocation ZeroRateAllocation(); >+ ObserverAllocation ZeroRateAllocation() RTC_RUN_ON(&sequenced_checker_); > // Allocates bitrate to observers when there isn't enough to allocate the > // minimum to all observers. >- ObserverAllocation LowRateAllocation(uint32_t bitrate); >+ ObserverAllocation LowRateAllocation(uint32_t bitrate) >+ RTC_RUN_ON(&sequenced_checker_); > // Allocates bitrate to all observers when the available bandwidth is enough > // to allocate the minimum to all observers but not enough to allocate the > // max bitrate of each observer. > ObserverAllocation NormalRateAllocation(uint32_t bitrate, >- uint32_t sum_min_bitrates); >+ uint32_t sum_min_bitrates) >+ RTC_RUN_ON(&sequenced_checker_); > // Allocates bitrate to observers when there is enough available bandwidth > // for all observers to be allocated their max bitrate. > ObserverAllocation MaxRateAllocation(uint32_t bitrate, >- uint32_t sum_max_bitrates); >+ uint32_t sum_max_bitrates) >+ RTC_RUN_ON(&sequenced_checker_); > > // Splits |bitrate| evenly to observers already in |allocation|. > // |include_zero_allocations| decides if zero allocations should be part of >@@ -173,9 +203,10 @@ class BitrateAllocator { > void DistributeBitrateEvenly(uint32_t bitrate, > bool include_zero_allocations, > int max_multiplier, >- ObserverAllocation* allocation); >- bool EnoughBitrateForAllObservers(uint32_t bitrate, >- uint32_t sum_min_bitrates); >+ ObserverAllocation* allocation) >+ RTC_RUN_ON(&sequenced_checker_); >+ bool EnoughBitrateForAllObservers(uint32_t bitrate, uint32_t sum_min_bitrates) >+ RTC_RUN_ON(&sequenced_checker_); > > // From the available |bitrate|, each observer will be allocated a > // proportional amount based upon its bitrate priority. If that amount is >@@ -186,7 +217,14 @@ class BitrateAllocator { > void DistributeBitrateRelatively( > uint32_t bitrate, > const ObserverAllocation& observers_capacities, >- ObserverAllocation* allocation); >+ ObserverAllocation* allocation) RTC_RUN_ON(&sequenced_checker_); >+ >+ // Allow packets to be transmitted in up to 2 times max video bitrate if the >+ // bandwidth estimate allows it. >+ // TODO(bugs.webrtc.org/8541): May be worth to refactor to keep this logic in >+ // video send stream. Similar logic is implemented in >+ // AudioPriorityBitrateAllocationStrategy. >+ static uint8_t GetTransmissionMaxBitrateMultiplier(); > > rtc::SequencedTaskChecker sequenced_checker_; > LimitObserver* const limit_observer_ RTC_GUARDED_BY(&sequenced_checker_); >@@ -203,8 +241,11 @@ class BitrateAllocator { > int64_t last_bwe_log_time_ RTC_GUARDED_BY(&sequenced_checker_); > uint32_t total_requested_padding_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); > uint32_t total_requested_min_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); >+ uint32_t total_requested_max_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); >+ bool has_packet_feedback_ RTC_GUARDED_BY(&sequenced_checker_); > std::unique_ptr<rtc::BitrateAllocationStrategy> bitrate_allocation_strategy_ > RTC_GUARDED_BY(&sequenced_checker_); >+ const uint8_t transmission_max_bitrate_multiplier_; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator_unittest.cc >index 154d14e3d76..7814655358c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_allocator_unittest.cc >@@ -21,12 +21,28 @@ using ::testing::NiceMock; > using ::testing::_; > > namespace webrtc { >+// Emulating old interface for test suite compatibility. >+// TODO(srte): Update tests to reflect new interface. >+class LimitObserverWrapper : public BitrateAllocator::LimitObserver { >+ public: >+ void OnAllocationLimitsChanged(uint32_t min_send_bitrate_bps, >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps, >+ bool has_packet_feedback) override { >+ OnAllocationLimitsChanged(min_send_bitrate_bps, max_padding_bitrate_bps, >+ total_bitrate_bps); >+ } >+ virtual void OnAllocationLimitsChanged(uint32_t min_send_bitrate_bps, >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps) = 0; >+}; > >-class MockLimitObserver : public BitrateAllocator::LimitObserver { >+class MockLimitObserver : public LimitObserverWrapper { > public: >- MOCK_METHOD2(OnAllocationLimitsChanged, >+ MOCK_METHOD3(OnAllocationLimitsChanged, > void(uint32_t min_send_bitrate_bps, >- uint32_t max_padding_bitrate_bps)); >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps)); > }; > > class TestBitrateObserver : public BitrateAllocatorObserver { >@@ -62,7 +78,7 @@ class TestBitrateObserver : public BitrateAllocatorObserver { > namespace { > constexpr int64_t kDefaultProbingIntervalMs = 3000; > const double kDefaultBitratePriority = 1.0; >-} >+} // namespace > > class BitrateAllocatorTest : public ::testing::Test { > protected: >@@ -70,6 +86,17 @@ class BitrateAllocatorTest : public ::testing::Test { > allocator_->OnNetworkChanged(300000u, 0, 0, kDefaultProbingIntervalMs); > } > ~BitrateAllocatorTest() {} >+ void AddObserver(BitrateAllocatorObserver* observer, >+ uint32_t min_bitrate_bps, >+ uint32_t max_bitrate_bps, >+ uint32_t pad_up_bitrate_bps, >+ bool enforce_min_bitrate, >+ std::string track_id, >+ double bitrate_priority) { >+ allocator_->AddObserver( >+ observer, {min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, >+ enforce_min_bitrate, track_id, bitrate_priority, false}); >+ } > > NiceMock<MockLimitObserver> limit_observer_; > std::unique_ptr<BitrateAllocator> allocator_; >@@ -79,12 +106,13 @@ TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { > TestBitrateObserver bitrate_observer; > const uint32_t kMinSendBitrateBps = 100000; > const uint32_t kPadUpToBitrateBps = 50000; >+ const uint32_t kMaxBitrateBps = 1500000; > >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(kMinSendBitrateBps, >- kPadUpToBitrateBps)); >- allocator_->AddObserver(&bitrate_observer, kMinSendBitrateBps, 1500000, >- kPadUpToBitrateBps, true, "", >- kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, >+ OnAllocationLimitsChanged(kMinSendBitrateBps, kPadUpToBitrateBps, >+ kMaxBitrateBps)); >+ AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, >+ kPadUpToBitrateBps, true, "", kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer)); > allocator_->OnNetworkChanged(200000, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer)); >@@ -96,36 +124,49 @@ TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { > > // Expect |max_padding_bitrate_bps| to change to 0 if the observer is updated. > EXPECT_CALL(limit_observer_, >- OnAllocationLimitsChanged(kMinSendBitrateBps, 0)); >- allocator_->AddObserver(&bitrate_observer, kMinSendBitrateBps, 4000000, 0, >- true, "", kDefaultBitratePriority); >+ OnAllocationLimitsChanged(kMinSendBitrateBps, 0, _)); >+ AddObserver(&bitrate_observer, kMinSendBitrateBps, 4000000, 0, true, "", >+ kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, >+ OnAllocationLimitsChanged(kMinSendBitrateBps, 0, _)); > EXPECT_EQ(4000000, allocator_->GetStartBitrate(&bitrate_observer)); > >- allocator_->AddObserver(&bitrate_observer, kMinSendBitrateBps, 1500000, 0, >- true, "", kDefaultBitratePriority); >+ AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, 0, true, >+ "", kDefaultBitratePriority); > EXPECT_EQ(3000000, allocator_->GetStartBitrate(&bitrate_observer)); > EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_bps_); >- allocator_->OnNetworkChanged(1500000, 0, 0, kDefaultProbingIntervalMs); >+ allocator_->OnNetworkChanged(kMaxBitrateBps, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_bps_); > } > > TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { > TestBitrateObserver bitrate_observer_1; > TestBitrateObserver bitrate_observer_2; >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(100000, 0)); >- allocator_->AddObserver(&bitrate_observer_1, 100000, 300000, 0, true, "", >- kDefaultBitratePriority); >- EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); >- EXPECT_CALL(limit_observer_, >- OnAllocationLimitsChanged(100000 + 200000, 0)); >- allocator_->AddObserver(&bitrate_observer_2, 200000, 300000, 0, true, "", >- kDefaultBitratePriority); >- EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer_2)); >+ const uint32_t kObs1StartBitrateBps = 100000; >+ const uint32_t kObs2StartBitrateBps = 200000; >+ const uint32_t kObs1MaxBitrateBps = 300000; >+ const uint32_t kObs2MaxBitrateBps = 300000; >+ >+ EXPECT_CALL( >+ limit_observer_, >+ OnAllocationLimitsChanged(kObs1StartBitrateBps, 0, kObs1MaxBitrateBps)); >+ AddObserver(&bitrate_observer_1, kObs1StartBitrateBps, kObs1MaxBitrateBps, 0, >+ true, "", kDefaultBitratePriority); >+ EXPECT_EQ(static_cast<int>(kObs1MaxBitrateBps), >+ allocator_->GetStartBitrate(&bitrate_observer_1)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged( >+ kObs1StartBitrateBps + kObs2StartBitrateBps, >+ 0, kObs1MaxBitrateBps + kObs2MaxBitrateBps)); >+ AddObserver(&bitrate_observer_2, kObs2StartBitrateBps, kObs2MaxBitrateBps, 0, >+ true, "", kDefaultBitratePriority); >+ EXPECT_EQ(static_cast<int>(kObs2StartBitrateBps), >+ allocator_->GetStartBitrate(&bitrate_observer_2)); > > // Test too low start bitrate, hence lower than sum of min. Min bitrates > // will > // be allocated to all observers. >- allocator_->OnNetworkChanged(200000, 0, 50, kDefaultProbingIntervalMs); >+ allocator_->OnNetworkChanged(kObs2StartBitrateBps, 0, 50, >+ kDefaultProbingIntervalMs); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); > EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_); > EXPECT_EQ(50, bitrate_observer_1.last_rtt_ms_); >@@ -135,7 +176,8 @@ TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { > > // Test a bitrate which should be distributed equally. > allocator_->OnNetworkChanged(500000, 0, 50, kDefaultProbingIntervalMs); >- const uint32_t kBitrateToShare = 500000 - 200000 - 100000; >+ const uint32_t kBitrateToShare = >+ 500000 - kObs2StartBitrateBps - kObs1StartBitrateBps; > EXPECT_EQ(100000u + kBitrateToShare / 2, > bitrate_observer_1.last_bitrate_bps_); > EXPECT_EQ(200000u + kBitrateToShare / 2, >@@ -159,13 +201,14 @@ TEST_F(BitrateAllocatorTest, RemoveObserverTriggersLimitObserver) { > TestBitrateObserver bitrate_observer; > const uint32_t kMinSendBitrateBps = 100000; > const uint32_t kPadUpToBitrateBps = 50000; >+ const uint32_t kMaxBitrateBps = 1500000; > >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(kMinSendBitrateBps, >- kPadUpToBitrateBps)); >- allocator_->AddObserver(&bitrate_observer, kMinSendBitrateBps, 1500000, >- kPadUpToBitrateBps, true, "", >- kDefaultBitratePriority); >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0)); >+ EXPECT_CALL(limit_observer_, >+ OnAllocationLimitsChanged(kMinSendBitrateBps, kPadUpToBitrateBps, >+ kMaxBitrateBps)); >+ AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, >+ kPadUpToBitrateBps, true, "", kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); > allocator_->RemoveObserver(&bitrate_observer); > } > >@@ -176,7 +219,17 @@ class BitrateAllocatorTestNoEnforceMin : public ::testing::Test { > allocator_->OnNetworkChanged(300000u, 0, 0, kDefaultProbingIntervalMs); > } > ~BitrateAllocatorTestNoEnforceMin() {} >- >+ void AddObserver(BitrateAllocatorObserver* observer, >+ uint32_t min_bitrate_bps, >+ uint32_t max_bitrate_bps, >+ uint32_t pad_up_bitrate_bps, >+ bool enforce_min_bitrate, >+ std::string track_id, >+ double bitrate_priority) { >+ allocator_->AddObserver( >+ observer, {min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, >+ enforce_min_bitrate, track_id, bitrate_priority, false}); >+ } > NiceMock<MockLimitObserver> limit_observer_; > std::unique_ptr<BitrateAllocator> allocator_; > }; >@@ -187,9 +240,10 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) { > TestBitrateObserver bitrate_observer_1; > // Expect OnAllocationLimitsChanged with |min_send_bitrate_bps| = 0 since > // AddObserver is called with |enforce_min_bitrate| = false. >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 120000)); >- allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 120000, _)); >+ AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); > > // High BWE. >@@ -200,7 +254,7 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) { > allocator_->OnNetworkChanged(10000, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_); > >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); > allocator_->RemoveObserver(&bitrate_observer_1); > } > >@@ -209,17 +263,17 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, ThreeBitrateObservers) { > TestBitrateObserver bitrate_observer_2; > TestBitrateObserver bitrate_observer_3; > // Set up the observers with min bitrates at 100000, 200000, and 300000. >- allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); > >- allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_2, 200000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer_2)); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); > >- allocator_->AddObserver(&bitrate_observer_3, 300000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_3, 300000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(0, allocator_->GetStartBitrate(&bitrate_observer_3)); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); > EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_); >@@ -241,14 +295,14 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, ThreeBitrateObservers) { > allocator_->OnNetworkChanged(300000, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); // Min bitrate. > EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_); // Min bitrate. >- EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing. >+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing. > > // Increased BWE, but still below the sum of configured min bitrates for all > // observers and too little for observer 3. 1 and 2 will share the rest. > allocator_->OnNetworkChanged(500000, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(200000u, bitrate_observer_1.last_bitrate_bps_); // Min + split. > EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_bps_); // Min + split. >- EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing. >+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing. > > // Below min for all. > allocator_->OnNetworkChanged(10000, 0, 0, kDefaultProbingIntervalMs); >@@ -272,9 +326,10 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserverWithPacketLoss) { > TestBitrateObserver bitrate_observer; > // Expect OnAllocationLimitsChanged with |min_send_bitrate_bps| = 0 since > // AddObserver is called with |enforce_min_bitrate| = false. >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 168000)); >- allocator_->AddObserver(&bitrate_observer, 100000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 168000, _)); >+ AddObserver(&bitrate_observer, 100000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer)); > > // High BWE. >@@ -300,7 +355,7 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserverWithPacketLoss) { > EXPECT_EQ(0u, bitrate_observer.last_bitrate_bps_); > > // Just enough to enable video again. >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); > allocator_->OnNetworkChanged(168000, 0, fraction_loss, > kDefaultProbingIntervalMs); > EXPECT_EQ(168000u, bitrate_observer.last_bitrate_bps_); >@@ -313,6 +368,7 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserverWithPacketLoss) { > allocator_->OnNetworkChanged(139000, 0, 0, kDefaultProbingIntervalMs); > EXPECT_EQ(139000u, bitrate_observer.last_bitrate_bps_); > >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); > allocator_->RemoveObserver(&bitrate_observer); > } > >@@ -320,11 +376,11 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, TwoBitrateObserverWithPacketLoss) { > TestBitrateObserver bitrate_observer_1; > TestBitrateObserver bitrate_observer_2; > >- allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_1, 100000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); >- allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_2, 200000, 400000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer_2)); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); > >@@ -373,17 +429,17 @@ TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowBweEnforceMin) { > TestBitrateObserver bitrate_observer_2; > TestBitrateObserver bitrate_observer_3; > >- allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, 0, true, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_1, 100000, 400000, 0, true, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); > >- allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, 0, true, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_2, 200000, 400000, 0, true, "", >+ kDefaultBitratePriority); > EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer_2)); > EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); > >- allocator_->AddObserver(&bitrate_observer_3, 300000, 400000, 0, true, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_3, 300000, 400000, 0, true, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_3)); > EXPECT_EQ(100000, static_cast<int>(bitrate_observer_1.last_bitrate_bps_)); > EXPECT_EQ(200000, static_cast<int>(bitrate_observer_2.last_bitrate_bps_)); >@@ -402,10 +458,10 @@ TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowBweEnforceMin) { > > TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { > TestBitrateObserver bitrate_observer_1; >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000, 0)); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000, 0, _)); > >- allocator_->AddObserver(&bitrate_observer_1, 50000, 400000, 0, true, "", >- kDefaultBitratePriority); >+ AddObserver(&bitrate_observer_1, 50000, 400000, 0, true, "", >+ kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); > > // Set network down, ie, no available bitrate. >@@ -415,9 +471,9 @@ TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { > > TestBitrateObserver bitrate_observer_2; > // Adding an observer while the network is down should not affect the limits. >- EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000 + 50000, 0)); >- allocator_->AddObserver(&bitrate_observer_2, 50000, 400000, 0, true, "", >- kDefaultBitratePriority); >+ EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000 + 50000, 0, _)); >+ AddObserver(&bitrate_observer_2, 50000, 400000, 0, true, "", >+ kDefaultBitratePriority); > > // Expect the start_bitrate to be set as if the network was still up but that > // the new observer have been notified that the network is down. >@@ -433,13 +489,13 @@ TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { > > TEST_F(BitrateAllocatorTest, MixedEnforecedConfigs) { > TestBitrateObserver enforced_observer; >- allocator_->AddObserver(&enforced_observer, 6000, 30000, 0, true, "", >- kDefaultBitratePriority); >+ AddObserver(&enforced_observer, 6000, 30000, 0, true, "", >+ kDefaultBitratePriority); > EXPECT_EQ(60000, allocator_->GetStartBitrate(&enforced_observer)); > > TestBitrateObserver not_enforced_observer; >- allocator_->AddObserver(¬_enforced_observer, 30000, 2500000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(¬_enforced_observer, 30000, 2500000, 0, false, "", >+ kDefaultBitratePriority); > EXPECT_EQ(270000, allocator_->GetStartBitrate(¬_enforced_observer)); > EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_); > >@@ -477,8 +533,7 @@ TEST_F(BitrateAllocatorTest, MixedEnforecedConfigs) { > > TEST_F(BitrateAllocatorTest, AvoidToggleAbsolute) { > TestBitrateObserver observer; >- allocator_->AddObserver(&observer, 30000, 300000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&observer, 30000, 300000, 0, false, "", kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); > > allocator_->OnNetworkChanged(30000, 0, 50, kDefaultProbingIntervalMs); >@@ -504,8 +559,7 @@ TEST_F(BitrateAllocatorTest, AvoidToggleAbsolute) { > > TEST_F(BitrateAllocatorTest, AvoidTogglePercent) { > TestBitrateObserver observer; >- allocator_->AddObserver(&observer, 300000, 600000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&observer, 300000, 600000, 0, false, "", kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); > > allocator_->OnNetworkChanged(300000, 0, 50, kDefaultProbingIntervalMs); >@@ -531,8 +585,7 @@ TEST_F(BitrateAllocatorTest, AvoidTogglePercent) { > > TEST_F(BitrateAllocatorTest, PassProbingInterval) { > TestBitrateObserver observer; >- allocator_->AddObserver(&observer, 300000, 600000, 0, false, "", >- kDefaultBitratePriority); >+ AddObserver(&observer, 300000, 600000, 0, false, "", kDefaultBitratePriority); > EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); > > allocator_->OnNetworkChanged(300000, 0, 50, 5000); >@@ -547,8 +600,8 @@ TEST_F(BitrateAllocatorTest, PriorityRateOneObserverBasic) { > const uint32_t kMaxSendBitrateBps = 60; > const uint32_t kNetworkBandwidthBps = 30; > >- allocator_->AddObserver(&observer, kMinSendBitrateBps, kMaxSendBitrateBps, 0, >- true, "", 2.0); >+ AddObserver(&observer, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, "", >+ 2.0); > allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, > kDefaultProbingIntervalMs); > >@@ -565,10 +618,10 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasic) { > const uint32_t kMinSendBitrateBps = 10; > const uint32_t kMaxSendBitrateBps = 60; > const uint32_t kNetworkBandwidthBps = 60; >- allocator_->AddObserver(&observer_low_1, kMinSendBitrateBps, >- kMaxSendBitrateBps, 0, false, "low1", 2.0); >- allocator_->AddObserver(&observer_low_2, kMinSendBitrateBps, >- kMaxSendBitrateBps, 0, false, "low2", 2.0); >+ AddObserver(&observer_low_1, kMinSendBitrateBps, kMaxSendBitrateBps, 0, false, >+ "low1", 2.0); >+ AddObserver(&observer_low_2, kMinSendBitrateBps, kMaxSendBitrateBps, 0, false, >+ "low2", 2.0); > allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, > kDefaultProbingIntervalMs); > >@@ -587,10 +640,10 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasicMinEnforced) { > const uint32_t kMinSendBitrateBps = 0; > const uint32_t kMaxSendBitrateBps = 60; > const uint32_t kNetworkBandwidthBps = 60; >- allocator_->AddObserver(&observer_low_1, kMinSendBitrateBps, >- kMaxSendBitrateBps, 0, true, "low1", 2.0); >- allocator_->AddObserver(&observer_low_2, kMinSendBitrateBps, >- kMaxSendBitrateBps, 0, true, "low2", 2.0); >+ AddObserver(&observer_low_1, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, >+ "low1", 2.0); >+ AddObserver(&observer_low_2, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, >+ "low2", 2.0); > allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, > kDefaultProbingIntervalMs); > >@@ -609,10 +662,10 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBothAllocatedMax) { > const uint32_t kMinSendBitrateBps = 0; > const uint32_t kMaxSendBitrateBps = 60; > const uint32_t kNetworkBandwidthBps = kMaxSendBitrateBps * 2; >- allocator_->AddObserver(&observer_low, kMinSendBitrateBps, kMaxSendBitrateBps, >- 0, true, "low", 2.0); >- allocator_->AddObserver(&observer_mid, kMinSendBitrateBps, kMaxSendBitrateBps, >- 0, true, "mid", 4.0); >+ AddObserver(&observer_low, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, >+ "low", 2.0); >+ AddObserver(&observer_mid, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, >+ "mid", 4.0); > allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, > kDefaultProbingIntervalMs); > >@@ -629,8 +682,8 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBothAllocatedMax) { > TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversOneAllocatedToMax) { > TestBitrateObserver observer_low; > TestBitrateObserver observer_mid; >- allocator_->AddObserver(&observer_low, 10, 50, 0, false, "low", 2.0); >- allocator_->AddObserver(&observer_mid, 10, 50, 0, false, "mid", 4.0); >+ AddObserver(&observer_low, 10, 50, 0, false, "low", 2.0); >+ AddObserver(&observer_mid, 10, 50, 0, false, "mid", 4.0); > allocator_->OnNetworkChanged(90, 0, 0, kDefaultProbingIntervalMs); > > EXPECT_EQ(40u, observer_low.last_bitrate_bps_); >@@ -655,12 +708,12 @@ TEST_F(BitrateAllocatorTest, > const double kHighBitratePriority = 8.0; > const double kTotalBitratePriority = > kLowBitratePriority + kMidBitratePriority + kHighBitratePriority; >- allocator_->AddObserver(&observer_low, 0, kMaxBitrate, 0, false, "low", >- kLowBitratePriority); >- allocator_->AddObserver(&observer_mid, 0, kMaxBitrate, 0, false, "mid", >- kMidBitratePriority); >- allocator_->AddObserver(&observer_high, 0, kMaxBitrate, 0, false, "high", >- kHighBitratePriority); >+ AddObserver(&observer_low, 0, kMaxBitrate, 0, false, "low", >+ kLowBitratePriority); >+ AddObserver(&observer_mid, 0, kMaxBitrate, 0, false, "mid", >+ kMidBitratePriority); >+ AddObserver(&observer_high, 0, kMaxBitrate, 0, false, "high", >+ kHighBitratePriority); > allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, > kDefaultProbingIntervalMs); > >@@ -701,12 +754,12 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversHighAllocatedToMax) { > const uint32_t kRemainingBitrate = > kAvailableBitrate - kMaxBitrate - (2 * kMinBitrate); > >- allocator_->AddObserver(&observer_low, kMinBitrate, kMaxBitrate, 0, false, >- "low", kLowBitratePriority); >- allocator_->AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, >- "mid", kMidBitratePriority); >- allocator_->AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, >- "high", kHighBitratePriority); >+ AddObserver(&observer_low, kMinBitrate, kMaxBitrate, 0, false, "low", >+ kLowBitratePriority); >+ AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, "mid", >+ kMidBitratePriority); >+ AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, "high", >+ kHighBitratePriority); > allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0, > kDefaultProbingIntervalMs); > >@@ -745,12 +798,12 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversLowAllocatedToMax) { > // available bitrate, so 70 bps would be sufficient network bandwidth. > const uint32_t kRemainingBitrate = kAvailableBitrate - kLowMaxBitrate; > >- allocator_->AddObserver(&observer_low, kMinBitrate, kLowMaxBitrate, 0, false, >- "low", kLowBitratePriority); >- allocator_->AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, >- "mid", kMidBitratePriority); >- allocator_->AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, >- "high", kHighBitratePriority); >+ AddObserver(&observer_low, kMinBitrate, kLowMaxBitrate, 0, false, "low", >+ kLowBitratePriority); >+ AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, "mid", >+ kMidBitratePriority); >+ AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, "high", >+ kHighBitratePriority); > allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0, > kDefaultProbingIntervalMs); > >@@ -779,12 +832,12 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversTwoAllocatedToMax) { > TestBitrateObserver observer_low; > TestBitrateObserver observer_mid; > TestBitrateObserver observer_high; >- allocator_->AddObserver(&observer_low, 10, 40, 0, false, "low", 2.0); >+ AddObserver(&observer_low, 10, 40, 0, false, "low", 2.0); > // Scaled allocation above the min allocation is the same for these two, > // meaning they will get allocated their max at the same time. > // Scaled (target allocation) = (max - min) / bitrate priority >- allocator_->AddObserver(&observer_mid, 10, 30, 0, false, "mid", 4.0); >- allocator_->AddObserver(&observer_high, 10, 50, 0, false, "high", 8.0); >+ AddObserver(&observer_mid, 10, 30, 0, false, "mid", 4.0); >+ AddObserver(&observer_high, 10, 50, 0, false, "high", 8.0); > allocator_->OnNetworkChanged(110, 0, 0, kDefaultProbingIntervalMs); > > EXPECT_EQ(30u, observer_low.last_bitrate_bps_); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_estimator_tests.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_estimator_tests.cc >index 4c397875f97..b3f7856ca35 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_estimator_tests.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/bitrate_estimator_tests.cc >@@ -103,9 +103,7 @@ class BitrateEstimatorTest : public test::CallTest { > > virtual void SetUp() { > task_queue_.SendTask([this]() { >- Call::Config config(event_log_.get()); >- receiver_call_.reset(Call::Create(config)); >- sender_call_.reset(Call::Create(config)); >+ CreateCalls(); > > send_transport_.reset(new test::DirectTransport( > &task_queue_, sender_call_.get(), payload_type_map_)); >@@ -114,18 +112,20 @@ class BitrateEstimatorTest : public test::CallTest { > &task_queue_, receiver_call_.get(), payload_type_map_)); > receive_transport_->SetReceiver(sender_call_->Receiver()); > >- video_send_config_ = VideoSendStream::Config(send_transport_.get()); >- video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]); >- // Encoders will be set separately per stream. >- video_send_config_.encoder_settings.encoder = nullptr; >- video_send_config_.encoder_settings.payload_name = "FAKE"; >- video_send_config_.encoder_settings.payload_type = >- kFakeVideoSendPayloadType; >- test::FillEncoderConfiguration(1, &video_encoder_config_); >+ VideoSendStream::Config video_send_config(send_transport_.get()); >+ video_send_config.rtp.ssrcs.push_back(kVideoSendSsrcs[0]); >+ video_send_config.encoder_settings.encoder_factory = >+ &fake_encoder_factory_; >+ video_send_config.rtp.payload_name = "FAKE"; >+ video_send_config.rtp.payload_type = kFakeVideoSendPayloadType; >+ SetVideoSendConfig(video_send_config); >+ VideoEncoderConfig video_encoder_config; >+ test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config); >+ SetVideoEncoderConfig(video_encoder_config); > > receive_config_ = VideoReceiveStream::Config(receive_transport_.get()); > // receive_config_.decoders will be set by every stream separately. >- receive_config_.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[0]; >+ receive_config_.rtp.remote_ssrc = GetVideoSendConfig()->rtp.ssrcs[0]; > receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc; > receive_config_.rtp.remb = true; > receive_config_.rtp.extensions.push_back( >@@ -137,19 +137,16 @@ class BitrateEstimatorTest : public test::CallTest { > > virtual void TearDown() { > task_queue_.SendTask([this]() { >- std::for_each(streams_.begin(), streams_.end(), >- std::mem_fun(&Stream::StopSending)); >- >- while (!streams_.empty()) { >- delete streams_.back(); >- streams_.pop_back(); >+ for (auto* stream : streams_) { >+ stream->StopSending(); >+ delete stream; > } >+ streams_.clear(); > > send_transport_.reset(); > receive_transport_.reset(); > >- receiver_call_.reset(); >- sender_call_.reset(); >+ DestroyCalls(); > }); > } > >@@ -163,33 +160,28 @@ class BitrateEstimatorTest : public test::CallTest { > is_sending_receiving_(false), > send_stream_(nullptr), > frame_generator_capturer_(), >- fake_encoder_(Clock::GetRealTimeClock()), > fake_decoder_() { >- test_->video_send_config_.rtp.ssrcs[0]++; >- test_->video_send_config_.encoder_settings.encoder = &fake_encoder_; >+ test_->GetVideoSendConfig()->rtp.ssrcs[0]++; > send_stream_ = test_->sender_call_->CreateVideoSendStream( >- test_->video_send_config_.Copy(), >- test_->video_encoder_config_.Copy()); >- RTC_DCHECK_EQ(1, test_->video_encoder_config_.number_of_streams); >+ test_->GetVideoSendConfig()->Copy(), >+ test_->GetVideoEncoderConfig()->Copy()); >+ RTC_DCHECK_EQ(1, test_->GetVideoEncoderConfig()->number_of_streams); > frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( >- kDefaultWidth, kDefaultHeight, kDefaultFramerate, >- Clock::GetRealTimeClock())); >- send_stream_->SetSource( >- frame_generator_capturer_.get(), >- VideoSendStream::DegradationPreference::kMaintainFramerate); >+ kDefaultWidth, kDefaultHeight, absl::nullopt, absl::nullopt, >+ kDefaultFramerate, Clock::GetRealTimeClock())); >+ send_stream_->SetSource(frame_generator_capturer_.get(), >+ DegradationPreference::MAINTAIN_FRAMERATE); > send_stream_->Start(); > frame_generator_capturer_->Start(); > > VideoReceiveStream::Decoder decoder; > decoder.decoder = &fake_decoder_; >- decoder.payload_type = >- test_->video_send_config_.encoder_settings.payload_type; >- decoder.payload_name = >- test_->video_send_config_.encoder_settings.payload_name; >+ decoder.payload_type = test_->GetVideoSendConfig()->rtp.payload_type; >+ decoder.payload_name = test_->GetVideoSendConfig()->rtp.payload_name; > test_->receive_config_.decoders.clear(); > test_->receive_config_.decoders.push_back(decoder); > test_->receive_config_.rtp.remote_ssrc = >- test_->video_send_config_.rtp.ssrcs[0]; >+ test_->GetVideoSendConfig()->rtp.ssrcs[0]; > test_->receive_config_.rtp.local_ssrc++; > test_->receive_config_.renderer = &test->fake_renderer_; > video_receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream( >@@ -226,15 +218,12 @@ class BitrateEstimatorTest : public test::CallTest { > VideoSendStream* send_stream_; > VideoReceiveStream* video_receive_stream_; > std::unique_ptr<test::FrameGeneratorCapturer> frame_generator_capturer_; >- test::FakeEncoder fake_encoder_; > test::FakeDecoder fake_decoder_; > }; > > LogObserver receiver_log_; > std::unique_ptr<test::DirectTransport> send_transport_; > std::unique_ptr<test::DirectTransport> receive_transport_; >- std::unique_ptr<Call> sender_call_; >- std::unique_ptr<Call> receiver_call_; > VideoReceiveStream::Config receive_config_; > std::vector<Stream*> streams_; > }; >@@ -246,7 +235,7 @@ static const char* kSingleStreamLog = > > TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) { > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions.push_back( >+ GetVideoSendConfig()->rtp.extensions.push_back( > RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); >@@ -257,7 +246,7 @@ TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) { > > TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) { > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions.push_back( >+ GetVideoSendConfig()->rtp.extensions.push_back( > RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId)); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); >@@ -270,7 +259,7 @@ TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) { > > TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) { > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions.push_back( >+ GetVideoSendConfig()->rtp.extensions.push_back( > RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); >@@ -279,7 +268,7 @@ TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) { > EXPECT_TRUE(receiver_log_.Wait()); > > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions[0] = >+ GetVideoSendConfig()->rtp.extensions[0] = > RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId); > receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); > receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); >@@ -291,7 +280,7 @@ TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) { > // This test is flaky. See webrtc:5790. > TEST_F(BitrateEstimatorTest, DISABLED_SwitchesToASTThenBackToTOFForVideo) { > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions.push_back( >+ GetVideoSendConfig()->rtp.extensions.push_back( > RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); > receiver_log_.PushExpectedLogLine(kSingleStreamLog); > receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); >@@ -301,7 +290,7 @@ TEST_F(BitrateEstimatorTest, DISABLED_SwitchesToASTThenBackToTOFForVideo) { > EXPECT_TRUE(receiver_log_.Wait()); > > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions[0] = >+ GetVideoSendConfig()->rtp.extensions[0] = > RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId); > receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); > receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); >@@ -310,7 +299,7 @@ TEST_F(BitrateEstimatorTest, DISABLED_SwitchesToASTThenBackToTOFForVideo) { > EXPECT_TRUE(receiver_log_.Wait()); > > task_queue_.SendTask([this]() { >- video_send_config_.rtp.extensions[0] = >+ GetVideoSendConfig()->rtp.extensions[0] = > RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId); > receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); > receiver_log_.PushExpectedLogLine( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.cc >index 08e1d937fa6..113109a823c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.cc >@@ -16,7 +16,9 @@ > #include <utility> > #include <vector> > >-#include "api/optional.h" >+#include "absl/memory/memory.h" >+#include "absl/types/optional.h" >+#include "api/transport/network_control.h" > #include "audio/audio_receive_stream.h" > #include "audio/audio_send_stream.h" > #include "audio/audio_state.h" >@@ -24,6 +26,7 @@ > #include "call/bitrate_allocator.h" > #include "call/call.h" > #include "call/flexfec_receive_stream_impl.h" >+#include "call/receive_time_calculator.h" > #include "call/rtp_stream_receiver_controller.h" > #include "call/rtp_transport_controller_send.h" > #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" >@@ -42,20 +45,21 @@ > #include "modules/rtp_rtcp/source/byte_io.h" > #include "modules/rtp_rtcp/source/rtp_packet_received.h" > #include "modules/utility/include/process_thread.h" >-#include "rtc_base/basictypes.h" >+#include "modules/video_coding/fec_controller_default.h" > #include "rtc_base/checks.h" > #include "rtc_base/constructormagic.h" > #include "rtc_base/location.h" > #include "rtc_base/logging.h" >-#include "rtc_base/ptr_util.h" >+#include "rtc_base/numerics/safe_minmax.h" > #include "rtc_base/sequenced_task_checker.h" >+#include "rtc_base/strings/string_builder.h" >+#include "rtc_base/synchronization/rw_lock_wrapper.h" > #include "rtc_base/task_queue.h" > #include "rtc_base/thread_annotations.h" > #include "rtc_base/trace_event.h" > #include "system_wrappers/include/clock.h" > #include "system_wrappers/include/cpu_info.h" > #include "system_wrappers/include/metrics.h" >-#include "system_wrappers/include/rw_lock_wrapper.h" > #include "video/call_stats.h" > #include "video/send_delay_stats.h" > #include "video/stats_counter.h" >@@ -65,7 +69,6 @@ > namespace webrtc { > > namespace { >- > // TODO(nisse): This really begs for a shared context struct. > bool UseSendSideBwe(const std::vector<RtpExtension>& extensions, > bool transport_cc) { >@@ -100,7 +103,7 @@ const int* FindKeyByValue(const std::map<int, int>& m, int v) { > > std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > const VideoReceiveStream::Config& config) { >- auto rtclog_config = rtc::MakeUnique<rtclog::StreamConfig>(); >+ auto rtclog_config = absl::make_unique<rtclog::StreamConfig>(); > rtclog_config->remote_ssrc = config.rtp.remote_ssrc; > rtclog_config->local_ssrc = config.rtp.local_ssrc; > rtclog_config->rtx_ssrc = config.rtp.rtx_ssrc; >@@ -112,7 +115,7 @@ std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > const int* search = > FindKeyByValue(config.rtp.rtx_associated_payload_types, d.payload_type); > rtclog_config->codecs.emplace_back(d.payload_name, d.payload_type, >- search ? *search : 0); >+ search ? *search : 0); > } > return rtclog_config; > } >@@ -120,7 +123,7 @@ std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > const VideoSendStream::Config& config, > size_t ssrc_index) { >- auto rtclog_config = rtc::MakeUnique<rtclog::StreamConfig>(); >+ auto rtclog_config = absl::make_unique<rtclog::StreamConfig>(); > rtclog_config->local_ssrc = config.rtp.ssrcs[ssrc_index]; > if (ssrc_index < config.rtp.rtx.ssrcs.size()) { > rtclog_config->rtx_ssrc = config.rtp.rtx.ssrcs[ssrc_index]; >@@ -128,15 +131,15 @@ std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > rtclog_config->rtcp_mode = config.rtp.rtcp_mode; > rtclog_config->rtp_extensions = config.rtp.extensions; > >- rtclog_config->codecs.emplace_back(config.encoder_settings.payload_name, >- config.encoder_settings.payload_type, >+ rtclog_config->codecs.emplace_back(config.rtp.payload_name, >+ config.rtp.payload_type, > config.rtp.rtx.payload_type); > return rtclog_config; > } > > std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > const AudioReceiveStream::Config& config) { >- auto rtclog_config = rtc::MakeUnique<rtclog::StreamConfig>(); >+ auto rtclog_config = absl::make_unique<rtclog::StreamConfig>(); > rtclog_config->remote_ssrc = config.rtp.remote_ssrc; > rtclog_config->local_ssrc = config.rtp.local_ssrc; > rtclog_config->rtp_extensions = config.rtp.extensions; >@@ -145,7 +148,7 @@ std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > > std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > const AudioSendStream::Config& config) { >- auto rtclog_config = rtc::MakeUnique<rtclog::StreamConfig>(); >+ auto rtclog_config = absl::make_unique<rtclog::StreamConfig>(); > rtclog_config->local_ssrc = config.rtp.ssrc; > rtclog_config->rtp_extensions = config.rtp.extensions; > if (config.send_codec_spec) { >@@ -159,11 +162,11 @@ std::unique_ptr<rtclog::StreamConfig> CreateRtcLogStreamConfig( > > namespace internal { > >-class Call : public webrtc::Call, >- public PacketReceiver, >- public RecoveredPacketReceiver, >- public SendSideCongestionController::Observer, >- public BitrateAllocator::LimitObserver { >+class Call final : public webrtc::Call, >+ public PacketReceiver, >+ public RecoveredPacketReceiver, >+ public TargetTransferRateObserver, >+ public BitrateAllocator::LimitObserver { > public: > Call(const Call::Config& config, > std::unique_ptr<RtpTransportControllerSendInterface> transport_send); >@@ -184,6 +187,10 @@ class Call : public webrtc::Call, > webrtc::VideoSendStream* CreateVideoSendStream( > webrtc::VideoSendStream::Config config, > VideoEncoderConfig encoder_config) override; >+ webrtc::VideoSendStream* CreateVideoSendStream( >+ webrtc::VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller) override; > void DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) override; > > webrtc::VideoReceiveStream* CreateVideoReceiveStream( >@@ -196,22 +203,18 @@ class Call : public webrtc::Call, > void DestroyFlexfecReceiveStream( > FlexfecReceiveStream* receive_stream) override; > >+ RtpTransportControllerSendInterface* GetTransportControllerSend() override; >+ > Stats GetStats() const override; > > // Implements PacketReceiver. > DeliveryStatus DeliverPacket(MediaType media_type, > rtc::CopyOnWriteBuffer packet, >- const PacketTime& packet_time) override; >+ int64_t packet_time_us) override; > > // Implements RecoveredPacketReceiver. > void OnRecoveredPacket(const uint8_t* packet, size_t length) override; > >- void SetBitrateConfig( >- const webrtc::Call::Config::BitrateConfig& bitrate_config) override; >- >- void SetBitrateConfigMask( >- const webrtc::Call::Config::BitrateConfigMask& bitrate_config) override; >- > void SetBitrateAllocationStrategy( > std::unique_ptr<rtc::BitrateAllocationStrategy> > bitrate_allocation_strategy) override; >@@ -221,27 +224,24 @@ class Call : public webrtc::Call, > void OnTransportOverheadChanged(MediaType media, > int transport_overhead_per_packet) override; > >- void OnNetworkRouteChanged(const std::string& transport_name, >- const rtc::NetworkRoute& network_route) override; >- > void OnSentPacket(const rtc::SentPacket& sent_packet) override; > >- // Implements BitrateObserver. >- void OnNetworkChanged(uint32_t bitrate_bps, >- uint8_t fraction_loss, >- int64_t rtt_ms, >- int64_t probing_interval_ms) override; >+ // Implements TargetTransferRateObserver, >+ void OnTargetTransferRate(TargetTransferRate msg) override; > > // Implements BitrateAllocator::LimitObserver. > void OnAllocationLimitsChanged(uint32_t min_send_bitrate_bps, >- uint32_t max_padding_bitrate_bps) override; >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps, >+ bool has_packet_feedback) override; > > private: >- DeliveryStatus DeliverRtcp(MediaType media_type, const uint8_t* packet, >+ DeliveryStatus DeliverRtcp(MediaType media_type, >+ const uint8_t* packet, > size_t length); > DeliveryStatus DeliverRtp(MediaType media_type, > rtc::CopyOnWriteBuffer packet, >- const PacketTime& packet_time); >+ int64_t packet_time_us); > void ConfigureSync(const std::string& sync_group) > RTC_EXCLUSIVE_LOCKS_REQUIRED(receive_crit_); > >@@ -255,15 +255,10 @@ class Call : public webrtc::Call, > void UpdateHistograms(); > void UpdateAggregateNetworkState(); > >- // Applies update to the BitrateConfig cached in |config_|, restarting >- // bandwidth estimation from |new_start| if set. >- void UpdateCurrentBitrateConfig(const rtc::Optional<int>& new_start); >- > Clock* const clock_; > > const int num_cpu_cores_; > const std::unique_ptr<ProcessThread> module_process_thread_; >- const std::unique_ptr<ProcessThread> pacer_thread_; > const std::unique_ptr<CallStats> call_stats_; > const std::unique_ptr<BitrateAllocator> bitrate_allocator_; > Call::Config config_; >@@ -271,6 +266,8 @@ class Call : public webrtc::Call, > > NetworkState audio_network_state_; > NetworkState video_network_state_; >+ rtc::CriticalSection aggregate_network_up_crit_; >+ bool aggregate_network_up_ RTC_GUARDED_BY(aggregate_network_up_crit_); > > std::unique_ptr<RWLockWrapper> receive_crit_; > // Audio, Video, and FlexFEC receive streams are owned by the client that >@@ -295,19 +292,24 @@ class Call : public webrtc::Call, > // single mapping from ssrc to a more abstract receive stream, with > // accessor methods for all configuration we need at this level. > struct ReceiveRtpConfig { >- ReceiveRtpConfig() = default; // Needed by std::map >- ReceiveRtpConfig(const std::vector<RtpExtension>& extensions, >- bool use_send_side_bwe) >- : extensions(extensions), use_send_side_bwe(use_send_side_bwe) {} >+ explicit ReceiveRtpConfig(const webrtc::AudioReceiveStream::Config& config) >+ : extensions(config.rtp.extensions), >+ use_send_side_bwe(UseSendSideBwe(config)) {} >+ explicit ReceiveRtpConfig(const webrtc::VideoReceiveStream::Config& config) >+ : extensions(config.rtp.extensions), >+ use_send_side_bwe(UseSendSideBwe(config)) {} >+ explicit ReceiveRtpConfig(const FlexfecReceiveStream::Config& config) >+ : extensions(config.rtp_header_extensions), >+ use_send_side_bwe(UseSendSideBwe(config)) {} > > // Registered RTP header extensions for each stream. Note that RTP header > // extensions are negotiated per track ("m= line") in the SDP, but we have > // no notion of tracks at the Call level. We therefore store the RTP header > // extensions per SSRC instead, which leads to some storage overhead. >- RtpHeaderExtensionMap extensions; >+ const RtpHeaderExtensionMap extensions; > // Set if both RTP extension the RTCP feedback message needed for > // send side BWE are negotiated. >- bool use_send_side_bwe = false; >+ const bool use_send_side_bwe; > }; > std::map<uint32_t, ReceiveRtpConfig> receive_rtp_config_ > RTC_GUARDED_BY(receive_crit_); >@@ -339,12 +341,14 @@ class Call : public webrtc::Call, > RateCounter received_audio_bytes_per_second_counter_; > RateCounter received_video_bytes_per_second_counter_; > RateCounter received_rtcp_bytes_per_second_counter_; >- rtc::Optional<int64_t> first_received_rtp_audio_ms_; >- rtc::Optional<int64_t> last_received_rtp_audio_ms_; >- rtc::Optional<int64_t> first_received_rtp_video_ms_; >- rtc::Optional<int64_t> last_received_rtp_video_ms_; >+ absl::optional<int64_t> first_received_rtp_audio_ms_; >+ absl::optional<int64_t> last_received_rtp_audio_ms_; >+ absl::optional<int64_t> first_received_rtp_video_ms_; >+ absl::optional<int64_t> last_received_rtp_video_ms_; > TimeInterval sent_rtp_audio_timer_ms_; > >+ rtc::CriticalSection last_bandwidth_bps_crit_; >+ uint32_t last_bandwidth_bps_ RTC_GUARDED_BY(&last_bandwidth_bps_crit_); > // TODO(holmer): Remove this lock once BitrateController no longer calls > // OnNetworkChanged from multiple threads. > rtc::CriticalSection bitrate_crit_; >@@ -354,32 +358,28 @@ class Call : public webrtc::Call, > RTC_GUARDED_BY(&bitrate_crit_); > AvgCounter pacer_bitrate_kbps_counter_ RTC_GUARDED_BY(&bitrate_crit_); > >- std::map<std::string, rtc::NetworkRoute> network_routes_; >- >- std::unique_ptr<RtpTransportControllerSendInterface> transport_send_; > ReceiveSideCongestionController receive_side_cc_; >- const std::unique_ptr<SendDelayStats> video_send_delay_stats_; >- const int64_t start_ms_; >- // TODO(perkj): |worker_queue_| is supposed to replace >- // |module_process_thread_|. >- // |worker_queue| is defined last to ensure all pending tasks are cancelled >- // and deleted before any other members. >- rtc::TaskQueue worker_queue_; > >- // The config mask set by SetBitrateConfigMask. >- // 0 <= min <= start <= max >- Config::BitrateConfigMask bitrate_config_mask_; >+ const std::unique_ptr<ReceiveTimeCalculator> receive_time_calculator_; > >- // The config set by SetBitrateConfig. >- // min >= 0, start != 0, max == -1 || max > 0 >- Config::BitrateConfig base_bitrate_config_; >+ const std::unique_ptr<SendDelayStats> video_send_delay_stats_; >+ const int64_t start_ms_; > >+ // Caches transport_send_.get(), to avoid racing with destructor. >+ // Note that this is declared before transport_send_ to ensure that it is not >+ // invalidated until no more tasks can be running on the transport_send_ task >+ // queue. >+ RtpTransportControllerSendInterface* transport_send_ptr_; >+ // Declared last since it will issue callbacks from a task queue. Declaring it >+ // last ensures that it is destroyed first and any running tasks are finished. >+ std::unique_ptr<RtpTransportControllerSendInterface> transport_send_; > RTC_DISALLOW_COPY_AND_ASSIGN(Call); > }; > } // namespace internal > > std::string Call::Stats::ToString(int64_t time_ms) const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "Call stats: " << time_ms << ", {"; > ss << "send_bw_bps: " << send_bandwidth_bps << ", "; > ss << "recv_bw_bps: " << recv_bandwidth_bps << ", "; >@@ -391,9 +391,10 @@ std::string Call::Stats::ToString(int64_t time_ms) const { > } > > Call* Call::Create(const Call::Config& config) { >- return new internal::Call(config, >- rtc::MakeUnique<RtpTransportControllerSend>( >- Clock::GetRealTimeClock(), config.event_log)); >+ return new internal::Call( >+ config, absl::make_unique<RtpTransportControllerSend>( >+ Clock::GetRealTimeClock(), config.event_log, >+ config.network_controller_factory, config.bitrate_config)); > } > > Call* Call::Create( >@@ -402,6 +403,16 @@ Call* Call::Create( > return new internal::Call(config, std::move(transport_send)); > } > >+// This method here to avoid subclasses has to implement this method. >+// Call perf test will use Internal::Call::CreateVideoSendStream() to inject >+// FecController. >+VideoSendStream* Call::CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller) { >+ return nullptr; >+} >+ > namespace internal { > > Call::Call(const Call::Config& config, >@@ -409,12 +420,12 @@ Call::Call(const Call::Config& config, > : clock_(Clock::GetRealTimeClock()), > num_cpu_cores_(CpuInfo::DetectNumberOfCores()), > module_process_thread_(ProcessThread::Create("ModuleProcessThread")), >- pacer_thread_(ProcessThread::Create("PacerThread")), >- call_stats_(new CallStats(clock_)), >+ call_stats_(new CallStats(clock_, module_process_thread_.get())), > bitrate_allocator_(new BitrateAllocator(this)), > config_(config), > audio_network_state_(kNetworkDown), > video_network_state_(kNetworkDown), >+ aggregate_network_up_(false), > receive_crit_(RWLockWrapper::CreateRWLock()), > send_crit_(RWLockWrapper::CreateRWLock()), > event_log_(config.event_log), >@@ -422,45 +433,27 @@ Call::Call(const Call::Config& config, > received_audio_bytes_per_second_counter_(clock_, nullptr, true), > received_video_bytes_per_second_counter_(clock_, nullptr, true), > received_rtcp_bytes_per_second_counter_(clock_, nullptr, true), >+ last_bandwidth_bps_(0), > min_allocated_send_bitrate_bps_(0), > configured_max_padding_bitrate_bps_(0), > estimated_send_bitrate_kbps_counter_(clock_, nullptr, true), > pacer_bitrate_kbps_counter_(clock_, nullptr, true), > receive_side_cc_(clock_, transport_send->packet_router()), >+ receive_time_calculator_(ReceiveTimeCalculator::CreateFromFieldTrial()), > video_send_delay_stats_(new SendDelayStats(clock_)), >- start_ms_(clock_->TimeInMilliseconds()), >- worker_queue_("call_worker_queue"), >- base_bitrate_config_(config.bitrate_config) { >+ start_ms_(clock_->TimeInMilliseconds()) { > RTC_DCHECK(config.event_log != nullptr); >- RTC_DCHECK_GE(config.bitrate_config.min_bitrate_bps, 0); >- RTC_DCHECK_GE(config.bitrate_config.start_bitrate_bps, >- config.bitrate_config.min_bitrate_bps); >- if (config.bitrate_config.max_bitrate_bps != -1) { >- RTC_DCHECK_GE(config.bitrate_config.max_bitrate_bps, >- config.bitrate_config.start_bitrate_bps); >- } >- transport_send->send_side_cc()->RegisterNetworkObserver(this); >+ transport_send->RegisterTargetTransferRateObserver(this); > transport_send_ = std::move(transport_send); >- transport_send_->send_side_cc()->SignalNetworkState(kNetworkDown); >- transport_send_->send_side_cc()->SetBweBitrates( >- config_.bitrate_config.min_bitrate_bps, >- config_.bitrate_config.start_bitrate_bps, >- config_.bitrate_config.max_bitrate_bps); >+ transport_send_ptr_ = transport_send_.get(); >+ > call_stats_->RegisterStatsObserver(&receive_side_cc_); >- call_stats_->RegisterStatsObserver(transport_send_->send_side_cc()); >+ call_stats_->RegisterStatsObserver(transport_send_->GetCallStatsObserver()); > >- // We have to attach the pacer to the pacer thread before starting the >- // module process thread to avoid a race accessing the process thread >- // both from the process thread and the pacer thread. >- pacer_thread_->RegisterModule(transport_send_->pacer(), RTC_FROM_HERE); >- pacer_thread_->RegisterModule( >+ module_process_thread_->RegisterModule( > receive_side_cc_.GetRemoteBitrateEstimator(true), RTC_FROM_HERE); >- pacer_thread_->Start(); >- > module_process_thread_->RegisterModule(call_stats_.get(), RTC_FROM_HERE); > module_process_thread_->RegisterModule(&receive_side_cc_, RTC_FROM_HERE); >- module_process_thread_->RegisterModule(transport_send_->send_side_cc(), >- RTC_FROM_HERE); > module_process_thread_->Start(); > } > >@@ -473,23 +466,15 @@ Call::~Call() { > RTC_CHECK(audio_receive_streams_.empty()); > RTC_CHECK(video_receive_streams_.empty()); > >- // The send-side congestion controller must be de-registered prior to >- // the pacer thread being stopped to avoid a race when accessing the >- // pacer thread object on the module process thread at the same time as >- // the pacer thread is stopped. >- module_process_thread_->DeRegisterModule(transport_send_->send_side_cc()); >- pacer_thread_->Stop(); >- pacer_thread_->DeRegisterModule(transport_send_->pacer()); >- pacer_thread_->DeRegisterModule( >+ module_process_thread_->DeRegisterModule( > receive_side_cc_.GetRemoteBitrateEstimator(true)); > module_process_thread_->DeRegisterModule(&receive_side_cc_); > module_process_thread_->DeRegisterModule(call_stats_.get()); > module_process_thread_->Stop(); > call_stats_->DeregisterStatsObserver(&receive_side_cc_); >- call_stats_->DeregisterStatsObserver(transport_send_->send_side_cc()); >+ call_stats_->DeregisterStatsObserver(transport_send_->GetCallStatsObserver()); > >- int64_t first_sent_packet_ms = >- transport_send_->send_side_cc()->GetFirstPacketTimeMs(); >+ int64_t first_sent_packet_ms = transport_send_->GetFirstPacketTimeMs(); > // Only update histograms after process threads have been shut down, so that > // they won't try to concurrently update stats. > { >@@ -592,10 +577,10 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream( > const webrtc::AudioSendStream::Config& config) { > TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream"); > RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); >- event_log_->Log(rtc::MakeUnique<RtcEventAudioSendStreamConfig>( >+ event_log_->Log(absl::make_unique<RtcEventAudioSendStreamConfig>( > CreateRtcLogStreamConfig(config))); > >- rtc::Optional<RtpState> suspended_rtp_state; >+ absl::optional<RtpState> suspended_rtp_state; > { > const auto& iter = suspended_audio_send_ssrcs_.find(config.rtp.ssrc); > if (iter != suspended_audio_send_ssrcs_.end()) { >@@ -603,11 +588,14 @@ webrtc::AudioSendStream* Call::CreateAudioSendStream( > } > } > >+ // TODO(srte): AudioSendStream should call GetWorkerQueue directly rather than >+ // having it injected. >+ > AudioSendStream* send_stream = new AudioSendStream( >- config, config_.audio_state, &worker_queue_, module_process_thread_.get(), >- transport_send_.get(), bitrate_allocator_.get(), event_log_, >- call_stats_->rtcp_rtt_stats(), suspended_rtp_state, >- &sent_rtp_audio_timer_ms_); >+ config, config_.audio_state, transport_send_ptr_->GetWorkerQueue(), >+ module_process_thread_.get(), transport_send_ptr_, >+ bitrate_allocator_.get(), event_log_, call_stats_.get(), >+ suspended_rtp_state, &sent_rtp_audio_timer_ms_); > { > WriteLockScoped write_lock(*send_crit_); > RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) == >@@ -659,15 +647,15 @@ webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream( > const webrtc::AudioReceiveStream::Config& config) { > TRACE_EVENT0("webrtc", "Call::CreateAudioReceiveStream"); > RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); >- event_log_->Log(rtc::MakeUnique<RtcEventAudioReceiveStreamConfig>( >+ event_log_->Log(absl::make_unique<RtcEventAudioReceiveStreamConfig>( > CreateRtcLogStreamConfig(config))); > AudioReceiveStream* receive_stream = new AudioReceiveStream( >- &audio_receiver_controller_, transport_send_->packet_router(), >+ &audio_receiver_controller_, transport_send_ptr_->packet_router(), > module_process_thread_.get(), config, config_.audio_state, event_log_); > { > WriteLockScoped write_lock(*receive_crit_); >- receive_rtp_config_[config.rtp.remote_ssrc] = >- ReceiveRtpConfig(config.rtp.extensions, UseSendSideBwe(config)); >+ receive_rtp_config_.emplace(config.rtp.remote_ssrc, >+ ReceiveRtpConfig(config)); > audio_receive_streams_.insert(receive_stream); > > ConfigureSync(config.sync_group); >@@ -711,16 +699,18 @@ void Call::DestroyAudioReceiveStream( > delete audio_receive_stream; > } > >+// This method can be used for Call tests with external fec controller factory. > webrtc::VideoSendStream* Call::CreateVideoSendStream( > webrtc::VideoSendStream::Config config, >- VideoEncoderConfig encoder_config) { >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller) { > TRACE_EVENT0("webrtc", "Call::CreateVideoSendStream"); > RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); > > video_send_delay_stats_->AddSsrcs(config); > for (size_t ssrc_index = 0; ssrc_index < config.rtp.ssrcs.size(); > ++ssrc_index) { >- event_log_->Log(rtc::MakeUnique<RtcEventVideoSendStreamConfig>( >+ event_log_->Log(absl::make_unique<RtcEventVideoSendStreamConfig>( > CreateRtcLogStreamConfig(config, ssrc_index))); > } > >@@ -728,12 +718,16 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( > // the call has already started. > // Copy ssrcs from |config| since |config| is moved. > std::vector<uint32_t> ssrcs = config.rtp.ssrcs; >+ >+ // TODO(srte): VideoSendStream should call GetWorkerQueue directly rather than >+ // having it injected. > VideoSendStream* send_stream = new VideoSendStream( >- num_cpu_cores_, module_process_thread_.get(), &worker_queue_, >- call_stats_.get(), transport_send_.get(), bitrate_allocator_.get(), >+ num_cpu_cores_, module_process_thread_.get(), >+ transport_send_ptr_->GetWorkerQueue(), call_stats_.get(), >+ transport_send_ptr_, bitrate_allocator_.get(), > video_send_delay_stats_.get(), event_log_, std::move(config), > std::move(encoder_config), suspended_video_send_ssrcs_, >- suspended_video_payload_states_); >+ suspended_video_payload_states_, std::move(fec_controller)); > > { > WriteLockScoped write_lock(*send_crit_); >@@ -743,12 +737,25 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream( > } > video_send_streams_.insert(send_stream); > } >- send_stream->SignalNetworkState(video_network_state_); > UpdateAggregateNetworkState(); > > return send_stream; > } > >+webrtc::VideoSendStream* Call::CreateVideoSendStream( >+ webrtc::VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config) { >+ if (config_.fec_controller_factory) { >+ RTC_LOG(LS_INFO) << "External FEC Controller will be used."; >+ } >+ std::unique_ptr<FecController> fec_controller = >+ config_.fec_controller_factory >+ ? config_.fec_controller_factory->CreateFecController() >+ : absl::make_unique<FecControllerDefault>(Clock::GetRealTimeClock()); >+ return CreateVideoSendStream(std::move(config), std::move(encoder_config), >+ std::move(fec_controller)); >+} >+ > void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) { > TRACE_EVENT0("webrtc", "Call::DestroyVideoSendStream"); > RTC_DCHECK(send_stream != nullptr); >@@ -794,12 +801,10 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream( > > VideoReceiveStream* receive_stream = new VideoReceiveStream( > &video_receiver_controller_, num_cpu_cores_, >- transport_send_->packet_router(), std::move(configuration), >+ transport_send_ptr_->packet_router(), std::move(configuration), > module_process_thread_.get(), call_stats_.get()); > > const webrtc::VideoReceiveStream::Config& config = receive_stream->config(); >- ReceiveRtpConfig receive_config(config.rtp.extensions, >- UseSendSideBwe(config)); > { > WriteLockScoped write_lock(*receive_crit_); > if (config.rtp.rtx_ssrc) { >@@ -807,15 +812,17 @@ webrtc::VideoReceiveStream* Call::CreateVideoReceiveStream( > // stream. Since the transport_send_cc negotiation is per payload > // type, we may get an incorrect value for the rtx stream, but > // that is unlikely to matter in practice. >- receive_rtp_config_[config.rtp.rtx_ssrc] = receive_config; >+ receive_rtp_config_.emplace(config.rtp.rtx_ssrc, >+ ReceiveRtpConfig(config)); > } >- receive_rtp_config_[config.rtp.remote_ssrc] = receive_config; >+ receive_rtp_config_.emplace(config.rtp.remote_ssrc, >+ ReceiveRtpConfig(config)); > video_receive_streams_.insert(receive_stream); > ConfigureSync(config.sync_group); > } > receive_stream->SignalNetworkState(video_network_state_); > UpdateAggregateNetworkState(); >- event_log_->Log(rtc::MakeUnique<RtcEventVideoReceiveStreamConfig>( >+ event_log_->Log(absl::make_unique<RtcEventVideoReceiveStreamConfig>( > CreateRtcLogStreamConfig(config))); > return receive_stream; > } >@@ -868,12 +875,11 @@ FlexfecReceiveStream* Call::CreateFlexfecReceiveStream( > // this locked scope. > receive_stream = new FlexfecReceiveStreamImpl( > &video_receiver_controller_, config, recovered_packet_receiver, >- call_stats_->rtcp_rtt_stats(), module_process_thread_.get()); >+ call_stats_.get(), module_process_thread_.get()); > > RTC_DCHECK(receive_rtp_config_.find(config.remote_ssrc) == > receive_rtp_config_.end()); >- receive_rtp_config_[config.remote_ssrc] = >- ReceiveRtpConfig(config.rtp_header_extensions, UseSendSideBwe(config)); >+ receive_rtp_config_.emplace(config.remote_ssrc, ReceiveRtpConfig(config)); > } > > // TODO(brandtr): Store config in RtcEventLog here. >@@ -902,23 +908,36 @@ void Call::DestroyFlexfecReceiveStream(FlexfecReceiveStream* receive_stream) { > delete receive_stream; > } > >+RtpTransportControllerSendInterface* Call::GetTransportControllerSend() { >+ return transport_send_ptr_; >+} >+ > Call::Stats Call::GetStats() const { > // TODO(solenberg): Some test cases in EndToEndTest use this from a different > // thread. Re-enable once that is fixed. > // RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); > Stats stats; > // Fetch available send/receive bitrates. >- uint32_t send_bandwidth = 0; >- transport_send_->send_side_cc()->AvailableBandwidth(&send_bandwidth); > std::vector<unsigned int> ssrcs; > uint32_t recv_bandwidth = 0; > receive_side_cc_.GetRemoteBitrateEstimator(false)->LatestEstimate( > &ssrcs, &recv_bandwidth); >- stats.send_bandwidth_bps = send_bandwidth; >+ >+ { >+ rtc::CritScope cs(&last_bandwidth_bps_crit_); >+ stats.send_bandwidth_bps = last_bandwidth_bps_; >+ } > stats.recv_bandwidth_bps = recv_bandwidth; >- stats.pacer_delay_ms = >- transport_send_->send_side_cc()->GetPacerQueuingDelayMs(); >- stats.rtt_ms = call_stats_->rtcp_rtt_stats()->LastProcessedRtt(); >+ // TODO(srte): It is unclear if we only want to report queues if network is >+ // available. >+ { >+ rtc::CritScope cs(&aggregate_network_up_crit_); >+ stats.pacer_delay_ms = aggregate_network_up_ >+ ? transport_send_ptr_->GetPacerQueuingDelayMs() >+ : 0; >+ } >+ >+ stats.rtt_ms = call_stats_->LastProcessedRtt(); > { > rtc::CritScope cs(&bitrate_crit_); > stats.max_padding_bitrate_bps = configured_max_padding_bitrate_bps_; >@@ -926,103 +945,22 @@ Call::Stats Call::GetStats() const { > return stats; > } > >-void Call::SetBitrateConfig( >- const webrtc::Call::Config::BitrateConfig& bitrate_config) { >- TRACE_EVENT0("webrtc", "Call::SetBitrateConfig"); >- RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); >- RTC_DCHECK_GE(bitrate_config.min_bitrate_bps, 0); >- RTC_DCHECK_NE(bitrate_config.start_bitrate_bps, 0); >- if (bitrate_config.max_bitrate_bps != -1) { >- RTC_DCHECK_GT(bitrate_config.max_bitrate_bps, 0); >- } >- >- rtc::Optional<int> new_start; >- // Only update the "start" bitrate if it's set, and different from the old >- // value. In practice, this value comes from the x-google-start-bitrate codec >- // parameter in SDP, and setting the same remote description twice shouldn't >- // restart bandwidth estimation. >- if (bitrate_config.start_bitrate_bps != -1 && >- bitrate_config.start_bitrate_bps != >- base_bitrate_config_.start_bitrate_bps) { >- new_start.emplace(bitrate_config.start_bitrate_bps); >- } >- base_bitrate_config_ = bitrate_config; >- UpdateCurrentBitrateConfig(new_start); >-} >- >-void Call::SetBitrateConfigMask( >- const webrtc::Call::Config::BitrateConfigMask& mask) { >- TRACE_EVENT0("webrtc", "Call::SetBitrateConfigMask"); >- RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); >- >- bitrate_config_mask_ = mask; >- UpdateCurrentBitrateConfig(mask.start_bitrate_bps); >-} >- >-void Call::UpdateCurrentBitrateConfig(const rtc::Optional<int>& new_start) { >- Config::BitrateConfig updated; >- updated.min_bitrate_bps = >- std::max(bitrate_config_mask_.min_bitrate_bps.value_or(0), >- base_bitrate_config_.min_bitrate_bps); >- >- updated.max_bitrate_bps = >- MinPositive(bitrate_config_mask_.max_bitrate_bps.value_or(-1), >- base_bitrate_config_.max_bitrate_bps); >- >- // If the combined min ends up greater than the combined max, the max takes >- // priority. >- if (updated.max_bitrate_bps != -1 && >- updated.min_bitrate_bps > updated.max_bitrate_bps) { >- updated.min_bitrate_bps = updated.max_bitrate_bps; >- } >- >- // If there is nothing to update (min/max unchanged, no new bandwidth >- // estimation start value), return early. >- if (updated.min_bitrate_bps == config_.bitrate_config.min_bitrate_bps && >- updated.max_bitrate_bps == config_.bitrate_config.max_bitrate_bps && >- !new_start) { >- RTC_LOG(LS_VERBOSE) << "WebRTC.Call.UpdateCurrentBitrateConfig: " >- << "nothing to update"; >- return; >- } >- >- if (new_start) { >- // Clamp start by min and max. >- updated.start_bitrate_bps = MinPositive( >- std::max(*new_start, updated.min_bitrate_bps), updated.max_bitrate_bps); >- } else { >- updated.start_bitrate_bps = -1; >- } >- >- RTC_LOG(INFO) << "WebRTC.Call.UpdateCurrentBitrateConfig: " >- << "calling SetBweBitrates with args (" >- << updated.min_bitrate_bps << ", " << updated.start_bitrate_bps >- << ", " << updated.max_bitrate_bps << ")"; >- transport_send_->send_side_cc()->SetBweBitrates(updated.min_bitrate_bps, >- updated.start_bitrate_bps, >- updated.max_bitrate_bps); >- if (!new_start) { >- updated.start_bitrate_bps = config_.bitrate_config.start_bitrate_bps; >- } >- config_.bitrate_config = updated; >-} >- > void Call::SetBitrateAllocationStrategy( > std::unique_ptr<rtc::BitrateAllocationStrategy> > bitrate_allocation_strategy) { >- if (!worker_queue_.IsCurrent()) { >- rtc::BitrateAllocationStrategy* strategy_raw = >- bitrate_allocation_strategy.release(); >- auto functor = [this, strategy_raw]() { >- SetBitrateAllocationStrategy( >- rtc::WrapUnique<rtc::BitrateAllocationStrategy>(strategy_raw)); >- }; >- worker_queue_.PostTask([functor] { functor(); }); >- return; >- } >- RTC_DCHECK_RUN_ON(&worker_queue_); >- bitrate_allocator_->SetBitrateAllocationStrategy( >- std::move(bitrate_allocation_strategy)); >+ // TODO(srte): This function should be moved to RtpTransportControllerSend >+ // when BitrateAllocator is moved there. >+ struct Functor { >+ void operator()() { >+ bitrate_allocator_->SetBitrateAllocationStrategy( >+ std::move(bitrate_allocation_strategy_)); >+ } >+ BitrateAllocator* bitrate_allocator_; >+ std::unique_ptr<rtc::BitrateAllocationStrategy> >+ bitrate_allocation_strategy_; >+ }; >+ transport_send_ptr_->GetWorkerQueue()->PostTask(Functor{ >+ bitrate_allocator_.get(), std::move(bitrate_allocation_strategy)}); > } > > void Call::SignalChannelNetworkState(MediaType media, NetworkState state) { >@@ -1046,9 +984,6 @@ void Call::SignalChannelNetworkState(MediaType media, NetworkState state) { > for (auto& kv : audio_send_ssrcs_) { > kv.second->SignalNetworkState(audio_network_state_); > } >- for (auto& kv : video_send_ssrcs_) { >- kv.second->SignalNetworkState(video_network_state_); >- } > } > { > ReadLockScoped read_lock(*receive_crit_); >@@ -1085,45 +1020,6 @@ void Call::OnTransportOverheadChanged(MediaType media, > } > } > >-// TODO(honghaiz): Add tests for this method. >-void Call::OnNetworkRouteChanged(const std::string& transport_name, >- const rtc::NetworkRoute& network_route) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); >- // Check if the network route is connected. >- if (!network_route.connected) { >- RTC_LOG(LS_INFO) << "Transport " << transport_name << " is disconnected"; >- // TODO(honghaiz): Perhaps handle this in SignalChannelNetworkState and >- // consider merging these two methods. >- return; >- } >- >- // Check whether the network route has changed on each transport. >- auto result = >- network_routes_.insert(std::make_pair(transport_name, network_route)); >- auto kv = result.first; >- bool inserted = result.second; >- if (inserted) { >- // No need to reset BWE if this is the first time the network connects. >- return; >- } >- if (kv->second != network_route) { >- kv->second = network_route; >- RTC_LOG(LS_INFO) >- << "Network route changed on transport " << transport_name >- << ": new local network id " << network_route.local_network_id >- << " new remote network id " << network_route.remote_network_id >- << " Reset bitrates to min: " << config_.bitrate_config.min_bitrate_bps >- << " bps, start: " << config_.bitrate_config.start_bitrate_bps >- << " bps, max: " << config_.bitrate_config.start_bitrate_bps >- << " bps."; >- RTC_DCHECK_GT(config_.bitrate_config.start_bitrate_bps, 0); >- transport_send_->send_side_cc()->OnNetworkRouteChanged( >- network_route, config_.bitrate_config.start_bitrate_bps, >- config_.bitrate_config.min_bitrate_bps, >- config_.bitrate_config.max_bitrate_bps); >- } >-} >- > void Call::UpdateAggregateNetworkState() { > RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); > >@@ -1144,39 +1040,37 @@ void Call::UpdateAggregateNetworkState() { > have_video = true; > } > >- NetworkState aggregate_state = kNetworkDown; >- if ((have_video && video_network_state_ == kNetworkUp) || >- (have_audio && audio_network_state_ == kNetworkUp)) { >- aggregate_state = kNetworkUp; >- } >+ bool aggregate_network_up = >+ ((have_video && video_network_state_ == kNetworkUp) || >+ (have_audio && audio_network_state_ == kNetworkUp)); > > RTC_LOG(LS_INFO) << "UpdateAggregateNetworkState: aggregate_state=" >- << (aggregate_state == kNetworkUp ? "up" : "down"); >- >- transport_send_->send_side_cc()->SignalNetworkState(aggregate_state); >+ << (aggregate_network_up ? "up" : "down"); >+ { >+ rtc::CritScope cs(&aggregate_network_up_crit_); >+ aggregate_network_up_ = aggregate_network_up; >+ } >+ transport_send_ptr_->OnNetworkAvailability(aggregate_network_up); > } > > void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { > video_send_delay_stats_->OnSentPacket(sent_packet.packet_id, > clock_->TimeInMilliseconds()); >- transport_send_->send_side_cc()->OnSentPacket(sent_packet); >+ transport_send_ptr_->OnSentPacket(sent_packet); > } > >-void Call::OnNetworkChanged(uint32_t target_bitrate_bps, >- uint8_t fraction_loss, >- int64_t rtt_ms, >- int64_t probing_interval_ms) { >- // TODO(perkj): Consider making sure CongestionController operates on >- // |worker_queue_|. >- if (!worker_queue_.IsCurrent()) { >- worker_queue_.PostTask( >- [this, target_bitrate_bps, fraction_loss, rtt_ms, probing_interval_ms] { >- OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt_ms, >- probing_interval_ms); >- }); >- return; >+void Call::OnTargetTransferRate(TargetTransferRate msg) { >+ uint32_t target_bitrate_bps = msg.target_rate.bps(); >+ int loss_ratio_255 = msg.network_estimate.loss_rate_ratio * 255; >+ uint8_t fraction_loss = >+ rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255)); >+ int64_t rtt_ms = msg.network_estimate.round_trip_time.ms(); >+ int64_t probing_interval_ms = msg.network_estimate.bwe_period.ms(); >+ uint32_t bandwidth_bps = msg.network_estimate.bandwidth.bps(); >+ { >+ rtc::CritScope cs(&last_bandwidth_bps_crit_); >+ last_bandwidth_bps_ = bandwidth_bps; > } >- RTC_DCHECK_RUN_ON(&worker_queue_); > // For controlling the rate of feedback messages. > receive_side_cc_.OnBitrateChanged(target_bitrate_bps); > bitrate_allocator_->OnNetworkChanged(target_bitrate_bps, fraction_loss, >@@ -1211,9 +1105,12 @@ void Call::OnNetworkChanged(uint32_t target_bitrate_bps, > } > > void Call::OnAllocationLimitsChanged(uint32_t min_send_bitrate_bps, >- uint32_t max_padding_bitrate_bps) { >- transport_send_->SetAllocatedSendBitrateLimits(min_send_bitrate_bps, >- max_padding_bitrate_bps); >+ uint32_t max_padding_bitrate_bps, >+ uint32_t total_bitrate_bps, >+ bool has_packet_feedback) { >+ transport_send_ptr_->SetAllocatedSendBitrateLimits( >+ min_send_bitrate_bps, max_padding_bitrate_bps, total_bitrate_bps); >+ transport_send_ptr_->SetPerPacketFeedbackAvailable(has_packet_feedback); > rtc::CritScope lock(&bitrate_crit_); > min_allocated_send_bitrate_bps_ = min_send_bitrate_bps; > configured_max_padding_bitrate_bps_ = max_padding_bitrate_bps; >@@ -1312,7 +1209,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type, > } > > if (rtcp_delivered) { >- event_log_->Log(rtc::MakeUnique<RtcEventRtcpPacketIncoming>( >+ event_log_->Log(absl::make_unique<RtcEventRtcpPacketIncoming>( > rtc::MakeArrayView(packet, length))); > } > >@@ -1321,15 +1218,19 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type, > > PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, > rtc::CopyOnWriteBuffer packet, >- const PacketTime& packet_time) { >+ int64_t packet_time_us) { > TRACE_EVENT0("webrtc", "Call::DeliverRtp"); > > RtpPacketReceived parsed_packet; > if (!parsed_packet.Parse(std::move(packet))) > return DELIVERY_PACKET_ERROR; > >- if (packet_time.timestamp != -1) { >- parsed_packet.set_arrival_time_ms((packet_time.timestamp + 500) / 1000); >+ if (packet_time_us != -1) { >+ if (receive_time_calculator_) { >+ packet_time_us = receive_time_calculator_->ReconcileReceiveTimes( >+ packet_time_us, clock_->TimeInMicroseconds()); >+ } >+ parsed_packet.set_arrival_time_ms((packet_time_us + 500) / 1000); > } else { > parsed_packet.set_arrival_time_ms(clock_->TimeInMilliseconds()); > } >@@ -1367,7 +1268,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, > received_bytes_per_second_counter_.Add(length); > received_audio_bytes_per_second_counter_.Add(length); > event_log_->Log( >- rtc::MakeUnique<RtcEventRtpPacketIncoming>(parsed_packet)); >+ absl::make_unique<RtcEventRtpPacketIncoming>(parsed_packet)); > const int64_t arrival_time_ms = parsed_packet.arrival_time_ms(); > if (!first_received_rtp_audio_ms_) { > first_received_rtp_audio_ms_.emplace(arrival_time_ms); >@@ -1376,11 +1277,12 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, > return DELIVERY_OK; > } > } else if (media_type == MediaType::VIDEO) { >+ parsed_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency); > if (video_receiver_controller_.OnRtpPacket(parsed_packet)) { > received_bytes_per_second_counter_.Add(length); > received_video_bytes_per_second_counter_.Add(length); > event_log_->Log( >- rtc::MakeUnique<RtcEventRtpPacketIncoming>(parsed_packet)); >+ absl::make_unique<RtcEventRtpPacketIncoming>(parsed_packet)); > const int64_t arrival_time_ms = parsed_packet.arrival_time_ms(); > if (!first_received_rtp_video_ms_) { > first_received_rtp_video_ms_.emplace(arrival_time_ms); >@@ -1395,12 +1297,12 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, > PacketReceiver::DeliveryStatus Call::DeliverPacket( > MediaType media_type, > rtc::CopyOnWriteBuffer packet, >- const PacketTime& packet_time) { >+ int64_t packet_time_us) { > RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_); > if (RtpHeaderParser::IsRtcp(packet.cdata(), packet.size())) > return DeliverRtcp(media_type, packet.cdata(), packet.size()); > >- return DeliverRtp(media_type, std::move(packet), packet_time); >+ return DeliverRtp(media_type, std::move(packet), packet_time_us); > } > > void Call::OnRecoveredPacket(const uint8_t* packet, size_t length) { >@@ -1420,12 +1322,13 @@ void Call::OnRecoveredPacket(const uint8_t* packet, size_t length) { > // deregistering in the |receive_rtp_config_| map is protected by that lock. > // So by not passing the packet on to demuxing in this case, we prevent > // incoming packets to be passed on via the demuxer to a receive stream >- // which is being torned down. >+ // which is being torn down. > return; > } > parsed_packet.IdentifyExtensions(it->second.extensions); > > // TODO(brandtr): Update here when we support protecting audio packets too. >+ parsed_packet.set_payload_type_frequency(kVideoPayloadTypeFrequency); > video_receiver_controller_.OnRtpPacket(parsed_packet); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.h >index b6e0aeabbfb..d8b1b5777db 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call.h >@@ -15,11 +15,12 @@ > #include <string> > #include <vector> > >-#include "api/rtcerror.h" >+#include "api/mediatypes.h" > #include "call/audio_receive_stream.h" > #include "call/audio_send_stream.h" >-#include "call/audio_state.h" >+#include "call/call_config.h" > #include "call/flexfec_receive_stream.h" >+#include "call/packet_receiver.h" > #include "call/rtp_transport_controller_send_interface.h" > #include "call/video_receive_stream.h" > #include "call/video_send_stream.h" >@@ -27,93 +28,16 @@ > #include "rtc_base/bitrateallocationstrategy.h" > #include "rtc_base/copyonwritebuffer.h" > #include "rtc_base/networkroute.h" >-#include "rtc_base/platform_file.h" > #include "rtc_base/socket.h" > > namespace webrtc { > >-class AudioProcessing; >-class RtcEventLog; >- >-enum class MediaType { >- ANY, >- AUDIO, >- VIDEO, >- DATA >-}; >- >-// Like std::min, but considers non-positive values to be unset. >-// TODO(zstein): Remove once all callers use rtc::Optional. >-template <typename T> >-static T MinPositive(T a, T b) { >- if (a <= 0) { >- return b; >- } >- if (b <= 0) { >- return a; >- } >- return std::min(a, b); >-} >- >-class PacketReceiver { >- public: >- enum DeliveryStatus { >- DELIVERY_OK, >- DELIVERY_UNKNOWN_SSRC, >- DELIVERY_PACKET_ERROR, >- }; >- >- virtual DeliveryStatus DeliverPacket(MediaType media_type, >- rtc::CopyOnWriteBuffer packet, >- const PacketTime& packet_time) = 0; >- >- protected: >- virtual ~PacketReceiver() {} >-}; >- > // A Call instance can contain several send and/or receive streams. All streams > // are assumed to have the same remote endpoint and will share bitrate estimates > // etc. > class Call { > public: >- struct Config { >- explicit Config(RtcEventLog* event_log) : event_log(event_log) { >- RTC_DCHECK(event_log); >- } >- >- static constexpr int kDefaultStartBitrateBps = 300000; >- >- // Bitrate config used until valid bitrate estimates are calculated. Also >- // used to cap total bitrate used. This comes from the remote connection. >- struct BitrateConfig { >- int min_bitrate_bps = 0; >- int start_bitrate_bps = kDefaultStartBitrateBps; >- int max_bitrate_bps = -1; >- } bitrate_config; >- >- // The local client's bitrate preferences. The actual configuration used >- // is a combination of this and |bitrate_config|. The combination is >- // currently more complicated than a simple mask operation (see >- // SetBitrateConfig and SetBitrateConfigMask). Assumes that 0 <= min <= >- // start <= max holds for set parameters. >- struct BitrateConfigMask { >- rtc::Optional<int> min_bitrate_bps; >- rtc::Optional<int> start_bitrate_bps; >- rtc::Optional<int> max_bitrate_bps; >- }; >- >- // AudioState which is possibly shared between multiple calls. >- // TODO(solenberg): Change this to a shared_ptr once we can use C++11. >- rtc::scoped_refptr<AudioState> audio_state; >- >- // Audio Processing Module to be used in this call. >- // TODO(solenberg): Change this to a shared_ptr once we can use C++11. >- AudioProcessing* audio_processing = nullptr; >- >- // RtcEventLog to use for this call. Required. >- // Use webrtc::RtcEventLog::CreateNull() for a null implementation. >- RtcEventLog* event_log = nullptr; >- }; >+ using Config = CallConfig; > > struct Stats { > std::string ToString(int64_t time_ms) const; >@@ -144,6 +68,10 @@ class Call { > virtual VideoSendStream* CreateVideoSendStream( > VideoSendStream::Config config, > VideoEncoderConfig encoder_config) = 0; >+ virtual VideoSendStream* CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller); > virtual void DestroyVideoSendStream(VideoSendStream* send_stream) = 0; > > virtual VideoReceiveStream* CreateVideoReceiveStream( >@@ -164,26 +92,17 @@ class Call { > // Call instance exists. > virtual PacketReceiver* Receiver() = 0; > >+ // This is used to access the transport controller send instance owned by >+ // Call. The send transport controller is currently owned by Call for legacy >+ // reasons. (for instance variants of call tests are built on this assumtion) >+ // TODO(srte): Move ownership of transport controller send out of Call and >+ // remove this method interface. >+ virtual RtpTransportControllerSendInterface* GetTransportControllerSend() = 0; >+ > // Returns the call statistics, such as estimated send and receive bandwidth, > // pacing delay, etc. > virtual Stats GetStats() const = 0; > >- // The greater min and smaller max set by this and SetBitrateConfigMask will >- // be used. The latest non-negative start value from either call will be used. >- // Specifying a start bitrate (>0) will reset the current bitrate estimate. >- // This is due to how the 'x-google-start-bitrate' flag is currently >- // implemented. Passing -1 leaves the start bitrate unchanged. Behavior is not >- // guaranteed for other negative values or 0. >- virtual void SetBitrateConfig( >- const Config::BitrateConfig& bitrate_config) = 0; >- >- // The greater min and smaller max set by this and SetBitrateConfig will be >- // used. The latest non-negative start value form either call will be used. >- // Specifying a start bitrate will reset the current bitrate estimate. >- // Assumes 0 <= min <= start <= max holds for set parameters. >- virtual void SetBitrateConfigMask( >- const Config::BitrateConfigMask& bitrate_mask) = 0; >- > virtual void SetBitrateAllocationStrategy( > std::unique_ptr<rtc::BitrateAllocationStrategy> > bitrate_allocation_strategy) = 0; >@@ -198,10 +117,6 @@ class Call { > MediaType media, > int transport_overhead_per_packet) = 0; > >- virtual void OnNetworkRouteChanged( >- const std::string& transport_name, >- const rtc::NetworkRoute& network_route) = 0; >- > virtual void OnSentPacket(const rtc::SentPacket& sent_packet) = 0; > > virtual ~Call() {} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.cc >new file mode 100644 >index 00000000000..ca5fb60b341 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.cc >@@ -0,0 +1,20 @@ >+/* >+ * Copyright (c) 2018 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 "call/call_config.h" >+ >+namespace webrtc { >+ >+CallConfig::CallConfig(RtcEventLog* event_log) : event_log(event_log) { >+ RTC_DCHECK(event_log); >+} >+CallConfig::~CallConfig() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.h >new file mode 100644 >index 00000000000..438929f4d38 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_config.h >@@ -0,0 +1,56 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+#ifndef CALL_CALL_CONFIG_H_ >+#define CALL_CALL_CONFIG_H_ >+ >+#include "api/bitrate_constraints.h" >+#include "api/fec_controller.h" >+#include "api/rtcerror.h" >+#include "api/transport/network_control.h" >+#include "call/audio_state.h" >+#include "rtc_base/platform_file.h" >+ >+namespace webrtc { >+ >+class AudioProcessing; >+class RtcEventLog; >+ >+struct CallConfig { >+ explicit CallConfig(RtcEventLog* event_log); >+ ~CallConfig(); >+ >+ RTC_DEPRECATED static constexpr int kDefaultStartBitrateBps = 300000; >+ >+ // Bitrate config used until valid bitrate estimates are calculated. Also >+ // used to cap total bitrate used. This comes from the remote connection. >+ BitrateConstraints bitrate_config; >+ >+ // AudioState which is possibly shared between multiple calls. >+ // TODO(solenberg): Change this to a shared_ptr once we can use C++11. >+ rtc::scoped_refptr<AudioState> audio_state; >+ >+ // Audio Processing Module to be used in this call. >+ // TODO(solenberg): Change this to a shared_ptr once we can use C++11. >+ AudioProcessing* audio_processing = nullptr; >+ >+ // RtcEventLog to use for this call. Required. >+ // Use webrtc::RtcEventLog::CreateNull() for a null implementation. >+ RtcEventLog* event_log = nullptr; >+ >+ // FecController to use for this call. >+ FecControllerFactoryInterface* fec_controller_factory = nullptr; >+ >+ // Network controller factory to use for this call. >+ NetworkControllerFactoryInterface* network_controller_factory = nullptr; >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_CALL_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_perf_tests.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_perf_tests.cc >index e9747a4fe6c..54e01b12324 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_perf_tests.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_perf_tests.cc >@@ -13,23 +13,25 @@ > #include <memory> > #include <string> > >+#include "absl/memory/memory.h" > #include "api/audio_codecs/builtin_audio_encoder_factory.h" >+#include "api/video/video_bitrate_allocation.h" >+#include "api/video_codecs/video_encoder_config.h" > #include "call/call.h" >-#include "call/video_config.h" > #include "logging/rtc_event_log/rtc_event_log.h" > #include "modules/audio_coding/include/audio_coding_module.h" >+#include "modules/audio_device/include/test_audio_device.h" > #include "modules/audio_mixer/audio_mixer_impl.h" > #include "modules/rtp_rtcp/include/rtp_header_parser.h" > #include "rtc_base/bitrateallocationstrategy.h" > #include "rtc_base/checks.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/thread_annotations.h" > #include "system_wrappers/include/metrics_default.h" > #include "test/call_test.h" > #include "test/direct_transport.h" > #include "test/drifting_clock.h" >+#include "test/encoder_proxy_factory.h" > #include "test/encoder_settings.h" >-#include "test/fake_audio_device.h" > #include "test/fake_encoder.h" > #include "test/field_trial.h" > #include "test/frame_generator.h" >@@ -42,18 +44,13 @@ > #include "video/transport_adapter.h" > > using webrtc::test::DriftingClock; >-using webrtc::test::FakeAudioDevice; > > namespace webrtc { > > class CallPerfTest : public test::CallTest { > protected: >- enum class FecMode { >- kOn, kOff >- }; >- enum class CreateOrder { >- kAudioFirst, kVideoFirst >- }; >+ enum class FecMode { kOn, kOff }; >+ enum class CreateOrder { kAudioFirst, kVideoFirst }; > void TestAudioVideoSync(FecMode fec, > CreateOrder create_first, > float video_ntp_speed, >@@ -170,10 +167,11 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > > task_queue_.SendTask([&]() { > metrics::Reset(); >- rtc::scoped_refptr<FakeAudioDevice> fake_audio_device = >- new rtc::RefCountedObject<FakeAudioDevice>( >- FakeAudioDevice::CreatePulsedNoiseCapturer(256, 48000), >- FakeAudioDevice::CreateDiscardRenderer(48000), audio_rtp_speed); >+ rtc::scoped_refptr<TestAudioDeviceModule> fake_audio_device = >+ TestAudioDeviceModule::CreateTestAudioDeviceModule( >+ TestAudioDeviceModule::CreatePulsedNoiseCapturer(256, 48000), >+ TestAudioDeviceModule::CreateDiscardRenderer(48000), >+ audio_rtp_speed); > EXPECT_EQ(0, fake_audio_device->Init()); > > AudioState::Config send_audio_state_config; >@@ -181,12 +179,12 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > send_audio_state_config.audio_processing = > AudioProcessingBuilder().Create(); > send_audio_state_config.audio_device_module = fake_audio_device; >- Call::Config sender_config(event_log_.get()); >+ Call::Config sender_config(send_event_log_.get()); > > auto audio_state = AudioState::Create(send_audio_state_config); > fake_audio_device->RegisterAudioCallback(audio_state->audio_transport()); > sender_config.audio_state = audio_state; >- Call::Config receiver_config(event_log_.get()); >+ Call::Config receiver_config(recv_event_log_.get()); > receiver_config.audio_state = audio_state; > CreateCalls(sender_config, receiver_config); > >@@ -201,18 +199,18 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > return pair.second == MediaType::VIDEO; > }); > >- audio_send_transport = rtc::MakeUnique<test::PacketTransport>( >+ audio_send_transport = absl::make_unique<test::PacketTransport>( > &task_queue_, sender_call_.get(), &observer, > test::PacketTransport::kSender, audio_pt_map, audio_net_config); > audio_send_transport->SetReceiver(receiver_call_->Receiver()); > >- video_send_transport = rtc::MakeUnique<test::PacketTransport>( >+ video_send_transport = absl::make_unique<test::PacketTransport>( > &task_queue_, sender_call_.get(), &observer, > test::PacketTransport::kSender, video_pt_map, > FakeNetworkPipe::Config()); > video_send_transport->SetReceiver(receiver_call_->Receiver()); > >- receive_transport = rtc::MakeUnique<test::PacketTransport>( >+ receive_transport = absl::make_unique<test::PacketTransport>( > &task_queue_, receiver_call_.get(), &observer, > test::PacketTransport::kReceiver, payload_type_map_, > FakeNetworkPipe::Config()); >@@ -228,10 +226,10 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > audio_send_config.encoder_factory = CreateBuiltinAudioEncoderFactory(); > audio_send_stream = sender_call_->CreateAudioSendStream(audio_send_config); > >- video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; >+ GetVideoSendConfig()->rtp.nack.rtp_history_ms = kNackRtpHistoryMs; > if (fec == FecMode::kOn) { >- video_send_config_.rtp.ulpfec.red_payload_type = kRedPayloadType; >- video_send_config_.rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; >+ GetVideoSendConfig()->rtp.ulpfec.red_payload_type = kRedPayloadType; >+ GetVideoSendConfig()->rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType; > video_receive_configs_[0].rtp.red_payload_type = kRedPayloadType; > video_receive_configs_[0].rtp.ulpfec_payload_type = kUlpfecPayloadType; > } >@@ -243,7 +241,7 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > audio_recv_config.rtp.remote_ssrc = kAudioSendSsrc; > audio_recv_config.rtp.local_ssrc = kAudioRecvSsrc; > audio_recv_config.sync_group = kSyncGroup; >- audio_recv_config.decoder_factory = decoder_factory_; >+ audio_recv_config.decoder_factory = audio_decoder_factory_; > audio_recv_config.decoder_map = { > {kAudioSendPayloadType, {"ISAC", 16000, 1}}}; > >@@ -258,7 +256,7 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > } > EXPECT_EQ(1u, video_receive_streams_.size()); > observer.set_receive_stream(video_receive_streams_[0]); >- drifting_clock = rtc::MakeUnique<DriftingClock>(clock_, video_ntp_speed); >+ drifting_clock = absl::make_unique<DriftingClock>(clock_, video_ntp_speed); > CreateFrameGeneratorCapturerWithDrift(drifting_clock.get(), video_rtp_speed, > kDefaultFramerate, kDefaultWidth, > kDefaultHeight); >@@ -298,6 +296,12 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec, > } > } > >+TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithoutClockDrift) { >+ TestAudioVideoSync(FecMode::kOff, CreateOrder::kAudioFirst, >+ DriftingClock::kNoDrift, DriftingClock::kNoDrift, >+ DriftingClock::kNoDrift, "_video_no_drift"); >+} >+ > TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithVideoNtpDrift) { > TestAudioVideoSync(FecMode::kOff, CreateOrder::kAudioFirst, > DriftingClock::PercentsFaster(10.0f), >@@ -543,8 +547,7 @@ TEST_F(CallPerfTest, ReceivesCpuOveruseAndUnderuse) { > void ModifyVideoConfigs( > VideoSendStream::Config* send_config, > std::vector<VideoReceiveStream::Config>* receive_configs, >- VideoEncoderConfig* encoder_config) override { >- } >+ VideoEncoderConfig* encoder_config) override {} > > void PerformTest() override { > EXPECT_TRUE(Wait()) << "Timed out before receiving an overuse callback."; >@@ -637,20 +640,29 @@ void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) { > std::vector<double> bitrate_kbps_list_; > } test(pad_to_min_bitrate); > >- fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps); >+ fake_encoder_max_bitrate_ = kMaxEncodeBitrateKbps; > RunBaseTest(&test); > } > >-TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); } >+TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { >+ TestMinTransmitBitrate(true); >+} > > TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) { > TestMinTransmitBitrate(false); > } > >-TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { >+// TODO(bugs.webrtc.org/8878) >+#if defined(WEBRTC_MAC) >+#define MAYBE_KeepsHighBitrateWhenReconfiguringSender \ >+ DISABLED_KeepsHighBitrateWhenReconfiguringSender >+#else >+#define MAYBE_KeepsHighBitrateWhenReconfiguringSender \ >+ KeepsHighBitrateWhenReconfiguringSender >+#endif >+TEST_F(CallPerfTest, MAYBE_KeepsHighBitrateWhenReconfiguringSender) { > static const uint32_t kInitialBitrateKbps = 400; > static const uint32_t kReconfigureThresholdKbps = 600; >- static const uint32_t kPermittedReconfiguredBitrateDiffKbps = 100; > > class VideoStreamFactory > : public VideoEncoderConfig::VideoStreamFactoryInterface { >@@ -679,7 +691,8 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { > encoder_inits_(0), > last_set_bitrate_kbps_(0), > send_stream_(nullptr), >- frame_generator_(nullptr) {} >+ frame_generator_(nullptr), >+ encoder_factory_(this) {} > > int32_t InitEncode(const VideoCodec* config, > int32_t number_of_cores, >@@ -700,16 +713,14 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { > EXPECT_EQ(2 * kDefaultWidth, config->width); > EXPECT_EQ(2 * kDefaultHeight, config->height); > EXPECT_GE(last_set_bitrate_kbps_, kReconfigureThresholdKbps); >- EXPECT_GT( >- config->startBitrate, >- last_set_bitrate_kbps_ - kPermittedReconfiguredBitrateDiffKbps) >+ EXPECT_GT(config->startBitrate, kReconfigureThresholdKbps) > << "Encoder reconfigured with bitrate too far away from last set."; > observation_complete_.Set(); > } > return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size); > } > >- int32_t SetRateAllocation(const BitrateAllocation& rate_allocation, >+ int32_t SetRateAllocation(const VideoBitrateAllocation& rate_allocation, > uint32_t framerate) override { > last_set_bitrate_kbps_ = rate_allocation.get_sum_kbps(); > if (encoder_inits_ == 1 && >@@ -719,18 +730,15 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { > return FakeEncoder::SetRateAllocation(rate_allocation, framerate); > } > >- Call::Config GetSenderCallConfig() override { >- Call::Config config = EndToEndTest::GetSenderCallConfig(); >- config.event_log = event_log_.get(); >- config.bitrate_config.start_bitrate_bps = kInitialBitrateKbps * 1000; >- return config; >+ void ModifySenderCallConfig(Call::Config* config) override { >+ config->bitrate_config.start_bitrate_bps = kInitialBitrateKbps * 1000; > } > > void ModifyVideoConfigs( > VideoSendStream::Config* send_config, > std::vector<VideoReceiveStream::Config>* receive_configs, > VideoEncoderConfig* encoder_config) override { >- send_config->encoder_settings.encoder = this; >+ send_config->encoder_settings.encoder_factory = &encoder_factory_; > encoder_config->max_bitrate_bps = 2 * kReconfigureThresholdKbps * 1000; > encoder_config->video_stream_factory = > new rtc::RefCountedObject<VideoStreamFactory>(); >@@ -765,6 +773,7 @@ TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { > uint32_t last_set_bitrate_kbps_; > VideoSendStream* send_stream_; > test::FrameGeneratorCapturer* frame_generator_; >+ test::EncoderProxyFactory encoder_factory_; > VideoEncoderConfig encoder_config_; > } test; > >@@ -880,11 +889,12 @@ void CallPerfTest::TestMinAudioVideoBitrate( > > void OnCallsCreated(Call* sender_call, Call* receiver_call) override { > sender_call_ = sender_call; >- Call::Config::BitrateConfig bitrate_config; >+ BitrateConstraints bitrate_config; > bitrate_config.min_bitrate_bps = min_bwe_; > bitrate_config.start_bitrate_bps = start_bwe_; > bitrate_config.max_bitrate_bps = max_bwe_; >- sender_call->SetBitrateConfig(bitrate_config); >+ sender_call->GetTransportControllerSend()->SetSdpBitrateParameters( >+ bitrate_config); > if (use_bitrate_allocation_strategy_) { > sender_call->SetBitrateAllocationStrategy( > std::move(allocation_strategy_)); >@@ -904,7 +914,7 @@ void CallPerfTest::TestMinAudioVideoBitrate( > send_config->max_bitrate_bps = kOpusBitrateFbBps; > } else { > send_config->send_codec_spec->target_bitrate_bps = >- rtc::Optional<int>(kOpusBitrateFbBps); >+ absl::optional<int>(kOpusBitrateFbBps); > } > } > >@@ -926,7 +936,13 @@ void CallPerfTest::TestMinAudioVideoBitrate( > RunBaseTest(&test); > } > >-TEST_F(CallPerfTest, MinVideoAndAudioBitrate) { >+// TODO(bugs.webrtc.org/8878) >+#if defined(WEBRTC_MAC) >+#define MAYBE_MinVideoAndAudioBitrate DISABLED_MinVideoAndAudioBitrate >+#else >+#define MAYBE_MinVideoAndAudioBitrate MinVideoAndAudioBitrate >+#endif >+TEST_F(CallPerfTest, MAYBE_MinVideoAndAudioBitrate) { > TestMinAudioVideoBitrate(false, 110, 40, -10, 10000, 70000, 200000); > } > TEST_F(CallPerfTest, MinVideoAndAudioBitrateWStrategy) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_unittest.cc >index dc36ce20720..1084bcfb46e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/call_unittest.cc >@@ -13,20 +13,18 @@ > #include <memory> > #include <utility> > >+#include "absl/memory/memory.h" > #include "api/audio_codecs/builtin_audio_decoder_factory.h" > #include "api/test/mock_audio_mixer.h" >-#include "audio/audio_send_stream.h" > #include "audio/audio_receive_stream.h" >+#include "audio/audio_send_stream.h" > #include "call/audio_state.h" > #include "call/call.h" >-#include "call/fake_rtp_transport_controller_send.h" > #include "logging/rtc_event_log/rtc_event_log.h" > #include "modules/audio_device/include/mock_audio_device.h" > #include "modules/audio_processing/include/mock_audio_processing.h" >-#include "modules/congestion_controller/include/mock/mock_send_side_congestion_controller.h" > #include "modules/pacing/mock/mock_paced_sender.h" > #include "modules/rtp_rtcp/include/rtp_rtcp.h" >-#include "rtc_base/ptr_util.h" > #include "test/fake_encoder.h" > #include "test/gtest.h" > #include "test/mock_audio_decoder_factory.h" >@@ -252,115 +250,6 @@ TEST(CallTest, MultipleFlexfecReceiveStreamsProtectingSingleVideoStream) { > } > } > >-namespace { >-struct CallBitrateHelper { >- CallBitrateHelper() : CallBitrateHelper(Call::Config::BitrateConfig()) {} >- >- explicit CallBitrateHelper(const Call::Config::BitrateConfig& bitrate_config) >- : mock_cc_(Clock::GetRealTimeClock(), &event_log_, &pacer_) { >- Call::Config config(&event_log_); >- config.bitrate_config = bitrate_config; >- call_.reset( >- Call::Create(config, rtc::MakeUnique<FakeRtpTransportControllerSend>( >- &packet_router_, &pacer_, &mock_cc_))); >- } >- >- webrtc::Call* operator->() { return call_.get(); } >- testing::NiceMock<test::MockSendSideCongestionController>& mock_cc() { >- return mock_cc_; >- } >- >- private: >- webrtc::RtcEventLogNullImpl event_log_; >- PacketRouter packet_router_; >- testing::NiceMock<MockPacedSender> pacer_; >- testing::NiceMock<test::MockSendSideCongestionController> mock_cc_; >- std::unique_ptr<Call> call_; >-}; >-} // namespace >- >-TEST(CallBitrateTest, SetBitrateConfigWithValidConfigCallsSetBweBitrates) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 1; >- bitrate_config.start_bitrate_bps = 2; >- bitrate_config.max_bitrate_bps = 3; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1, 2, 3)); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, SetBitrateConfigWithDifferentMinCallsSetBweBitrates) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 10; >- bitrate_config.start_bitrate_bps = 20; >- bitrate_config.max_bitrate_bps = 30; >- call->SetBitrateConfig(bitrate_config); >- >- bitrate_config.min_bitrate_bps = 11; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(11, -1, 30)); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, SetBitrateConfigWithDifferentStartCallsSetBweBitrates) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 10; >- bitrate_config.start_bitrate_bps = 20; >- bitrate_config.max_bitrate_bps = 30; >- call->SetBitrateConfig(bitrate_config); >- >- bitrate_config.start_bitrate_bps = 21; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(10, 21, 30)); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, SetBitrateConfigWithDifferentMaxCallsSetBweBitrates) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 10; >- bitrate_config.start_bitrate_bps = 20; >- bitrate_config.max_bitrate_bps = 30; >- call->SetBitrateConfig(bitrate_config); >- >- bitrate_config.max_bitrate_bps = 31; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(10, -1, 31)); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, SetBitrateConfigWithSameConfigElidesSecondCall) { >- CallBitrateHelper call; >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 1; >- bitrate_config.start_bitrate_bps = 2; >- bitrate_config.max_bitrate_bps = 3; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1, 2, 3)).Times(1); >- call->SetBitrateConfig(bitrate_config); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, >- SetBitrateConfigWithSameMinMaxAndNegativeStartElidesSecondCall) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 1; >- bitrate_config.start_bitrate_bps = 2; >- bitrate_config.max_bitrate_bps = 3; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1, 2, 3)).Times(1); >- call->SetBitrateConfig(bitrate_config); >- >- bitrate_config.start_bitrate_bps = -1; >- call->SetBitrateConfig(bitrate_config); >-} >- > TEST(CallTest, RecreatingAudioStreamWithSameSsrcReusesRtpState) { > constexpr uint32_t kSSRC = 12345; > CallHelper call; >@@ -387,222 +276,4 @@ TEST(CallTest, RecreatingAudioStreamWithSameSsrcReusesRtpState) { > EXPECT_EQ(rtp_state1.media_has_been_sent, rtp_state2.media_has_been_sent); > } > >-TEST(CallBitrateTest, BiggerMaskMinUsed) { >- CallBitrateHelper call; >- Call::Config::BitrateConfigMask mask; >- mask.min_bitrate_bps = 1234; >- >- EXPECT_CALL(call.mock_cc(), >- SetBweBitrates(*mask.min_bitrate_bps, testing::_, testing::_)); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, BiggerConfigMinUsed) { >- CallBitrateHelper call; >- Call::Config::BitrateConfigMask mask; >- mask.min_bitrate_bps = 1000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1000, testing::_, testing::_)); >- call->SetBitrateConfigMask(mask); >- >- Call::Config::BitrateConfig config; >- config.min_bitrate_bps = 1234; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1234, testing::_, testing::_)); >- call->SetBitrateConfig(config); >-} >- >-// The last call to set start should be used. >-TEST(CallBitrateTest, LatestStartMaskPreferred) { >- CallBitrateHelper call; >- Call::Config::BitrateConfigMask mask; >- mask.start_bitrate_bps = 1300; >- >- EXPECT_CALL(call.mock_cc(), >- SetBweBitrates(testing::_, *mask.start_bitrate_bps, testing::_)); >- call->SetBitrateConfigMask(mask); >- >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.start_bitrate_bps = 1200; >- >- EXPECT_CALL( >- call.mock_cc(), >- SetBweBitrates(testing::_, bitrate_config.start_bitrate_bps, testing::_)); >- call->SetBitrateConfig(bitrate_config); >-} >- >-TEST(CallBitrateTest, SmallerMaskMaxUsed) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; >- CallBitrateHelper call(bitrate_config); >- >- Call::Config::BitrateConfigMask mask; >- mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; >- >- EXPECT_CALL(call.mock_cc(), >- SetBweBitrates(testing::_, testing::_, *mask.max_bitrate_bps)); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, SmallerConfigMaxUsed) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; >- CallBitrateHelper call(bitrate_config); >- >- Call::Config::BitrateConfigMask mask; >- mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; >- >- // Expect no calls because nothing changes >- EXPECT_CALL(call.mock_cc(), >- SetBweBitrates(testing::_, testing::_, testing::_)) >- .Times(0); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, MaskStartLessThanConfigMinClamped) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 2000; >- CallBitrateHelper call(bitrate_config); >- >- Call::Config::BitrateConfigMask mask; >- mask.start_bitrate_bps = 1000; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(2000, 2000, testing::_)); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, MaskStartGreaterThanConfigMaxClamped) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.start_bitrate_bps = 2000; >- CallBitrateHelper call(bitrate_config); >- >- Call::Config::BitrateConfigMask mask; >- mask.max_bitrate_bps = 1000; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(testing::_, -1, 1000)); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, MaskMinGreaterThanConfigMaxClamped) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.min_bitrate_bps = 2000; >- CallBitrateHelper call(bitrate_config); >- >- Call::Config::BitrateConfigMask mask; >- mask.max_bitrate_bps = 1000; >- >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1000, testing::_, 1000)); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, SettingMaskStartForcesUpdate) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfigMask mask; >- mask.start_bitrate_bps = 1000; >- >- // SetBweBitrates should be called twice with the same params since >- // start_bitrate_bps is set. >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(testing::_, 1000, testing::_)) >- .Times(2); >- call->SetBitrateConfigMask(mask); >- call->SetBitrateConfigMask(mask); >-} >- >-TEST(CallBitrateTest, SetBitrateConfigWithNoChangesDoesNotCallSetBweBitrates) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig config1; >- config1.min_bitrate_bps = 0; >- config1.start_bitrate_bps = 1000; >- config1.max_bitrate_bps = -1; >- >- Call::Config::BitrateConfig config2; >- config2.min_bitrate_bps = 0; >- config2.start_bitrate_bps = -1; >- config2.max_bitrate_bps = -1; >- >- // The second call should not call SetBweBitrates because it doesn't >- // change any values. >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(0, 1000, -1)); >- call->SetBitrateConfig(config1); >- call->SetBitrateConfig(config2); >-} >- >-// If SetBitrateConfig changes the max, but not the effective max, >-// SetBweBitrates shouldn't be called, to avoid unnecessary encoder >-// reconfigurations. >-TEST(CallBitrateTest, SetBweBitratesNotCalledWhenEffectiveMaxUnchanged) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfig config; >- config.min_bitrate_bps = 0; >- config.start_bitrate_bps = -1; >- config.max_bitrate_bps = 2000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(testing::_, testing::_, 2000)); >- call->SetBitrateConfig(config); >- >- // Reduce effective max to 1000 with the mask. >- Call::Config::BitrateConfigMask mask; >- mask.max_bitrate_bps = 1000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(testing::_, testing::_, 1000)); >- call->SetBitrateConfigMask(mask); >- >- // This leaves the effective max unchanged, so SetBweBitrates shouldn't be >- // called again. >- config.max_bitrate_bps = 1000; >- call->SetBitrateConfig(config); >-} >- >-// When the "start bitrate" mask is removed, SetBweBitrates shouldn't be called >-// again, since nothing's changing. >-TEST(CallBitrateTest, SetBweBitratesNotCalledWhenStartMaskRemoved) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfigMask mask; >- mask.start_bitrate_bps = 1000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(0, 1000, -1)); >- call->SetBitrateConfigMask(mask); >- >- mask.start_bitrate_bps.reset(); >- call->SetBitrateConfigMask(mask); >-} >- >-// Test that if SetBitrateConfig is called after SetBitrateConfigMask applies a >-// "start" value, the SetBitrateConfig call won't apply that start value a >-// second time. >-TEST(CallBitrateTest, SetBitrateConfigAfterSetBitrateConfigMaskWithStart) { >- CallBitrateHelper call; >- >- Call::Config::BitrateConfigMask mask; >- mask.start_bitrate_bps = 1000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(0, 1000, -1)); >- call->SetBitrateConfigMask(mask); >- >- Call::Config::BitrateConfig config; >- config.min_bitrate_bps = 0; >- config.start_bitrate_bps = -1; >- config.max_bitrate_bps = 5000; >- // The start value isn't changing, so SetBweBitrates should be called with >- // -1. >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(0, -1, 5000)); >- call->SetBitrateConfig(config); >-} >- >-TEST(CallBitrateTest, SetBweBitratesNotCalledWhenClampedMinUnchanged) { >- Call::Config::BitrateConfig bitrate_config; >- bitrate_config.start_bitrate_bps = 500; >- bitrate_config.max_bitrate_bps = 1000; >- CallBitrateHelper call(bitrate_config); >- >- // Set min to 2000; it is clamped to the max (1000). >- Call::Config::BitrateConfigMask mask; >- mask.min_bitrate_bps = 2000; >- EXPECT_CALL(call.mock_cc(), SetBweBitrates(1000, -1, 1000)); >- call->SetBitrateConfigMask(mask); >- >- // Set min to 3000; the clamped value stays the same so nothing happens. >- mask.min_bitrate_bps = 3000; >- call->SetBitrateConfigMask(mask); >-} >- > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.cc >index 82acb6533c0..b5c28d2e456 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.cc >@@ -11,10 +11,74 @@ > #include "call/callfactory.h" > > #include <memory> >+#include <string> >+#include <utility> >+ >+#include "absl/types/optional.h" >+#include "call/call.h" >+#include "call/degraded_call.h" >+#include "call/fake_network_pipe.h" >+#include "system_wrappers/include/field_trial.h" > > namespace webrtc { >+namespace { >+bool ParseConfigParam(std::string exp_name, int* field) { >+ std::string group = field_trial::FindFullName(exp_name); >+ if (group == "") >+ return false; >+ >+ return (sscanf(group.c_str(), "%d", field) == 1); >+} >+ >+absl::optional<webrtc::FakeNetworkPipe::Config> ParseDegradationConfig( >+ bool send) { >+ std::string exp_prefix = "WebRTCFakeNetwork"; >+ if (send) { >+ exp_prefix += "Send"; >+ } else { >+ exp_prefix += "Receive"; >+ } >+ >+ webrtc::FakeNetworkPipe::Config config; >+ bool configured = false; >+ configured |= >+ ParseConfigParam(exp_prefix + "DelayMs", &config.queue_delay_ms); >+ configured |= ParseConfigParam(exp_prefix + "DelayStdDevMs", >+ &config.delay_standard_deviation_ms); >+ int queue_length = 0; >+ if (ParseConfigParam(exp_prefix + "QueueLength", &queue_length)) { >+ RTC_CHECK_GE(queue_length, 0); >+ config.queue_length_packets = queue_length; >+ configured = true; >+ } >+ configured |= >+ ParseConfigParam(exp_prefix + "CapacityKbps", &config.link_capacity_kbps); >+ configured |= >+ ParseConfigParam(exp_prefix + "LossPercent", &config.loss_percent); >+ int allow_reordering = 0; >+ if (ParseConfigParam(exp_prefix + "AllowReordering", &allow_reordering)) { >+ config.allow_reordering = true; >+ configured = true; >+ } >+ configured |= ParseConfigParam(exp_prefix + "AvgBurstLossLength", >+ &config.avg_burst_loss_length); >+ return configured ? absl::optional<webrtc::FakeNetworkPipe::Config>(config) >+ : absl::nullopt; >+} >+} // namespace > > Call* CallFactory::CreateCall(const Call::Config& config) { >+ absl::optional<webrtc::FakeNetworkPipe::Config> send_degradation_config = >+ ParseDegradationConfig(true); >+ absl::optional<webrtc::FakeNetworkPipe::Config> receive_degradation_config = >+ ParseDegradationConfig(false); >+ >+ if (send_degradation_config || receive_degradation_config) { >+ return new DegradedCall(std::unique_ptr<Call>(Call::Create(config)), >+ send_degradation_config, >+ receive_degradation_config); >+ } >+ > return Call::Create(config); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.h >index 167b82ad541..1c57bd435f8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/callfactory.h >@@ -11,14 +11,14 @@ > #ifndef CALL_CALLFACTORY_H_ > #define CALL_CALLFACTORY_H_ > >-#include "call/callfactoryinterface.h" >+#include "api/call/callfactoryinterface.h" > > namespace webrtc { > > class CallFactory : public CallFactoryInterface { > ~CallFactory() override {} > >- Call* CreateCall(const Call::Config& config) override; >+ Call* CreateCall(const CallConfig& config) override; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.cc >new file mode 100644 >index 00000000000..f24ef594144 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.cc >@@ -0,0 +1,209 @@ >+/* >+ * Copyright (c) 2018 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 <utility> >+ >+#include "call/degraded_call.h" >+ >+#include "absl/memory/memory.h" >+ >+namespace webrtc { >+DegradedCall::DegradedCall( >+ std::unique_ptr<Call> call, >+ absl::optional<FakeNetworkPipe::Config> send_config, >+ absl::optional<FakeNetworkPipe::Config> receive_config) >+ : clock_(Clock::GetRealTimeClock()), >+ call_(std::move(call)), >+ send_config_(send_config), >+ send_process_thread_( >+ send_config_ ? ProcessThread::Create("DegradedSendThread") : nullptr), >+ num_send_streams_(0), >+ receive_config_(receive_config) { >+ if (receive_config_) { >+ receive_pipe_ = >+ absl::make_unique<webrtc::FakeNetworkPipe>(clock_, *receive_config_); >+ receive_pipe_->SetReceiver(call_->Receiver()); >+ } >+ if (send_process_thread_) { >+ send_process_thread_->Start(); >+ } >+} >+ >+DegradedCall::~DegradedCall() { >+ if (send_pipe_) { >+ send_process_thread_->DeRegisterModule(send_pipe_.get()); >+ } >+ if (send_process_thread_) { >+ send_process_thread_->Stop(); >+ } >+} >+ >+AudioSendStream* DegradedCall::CreateAudioSendStream( >+ const AudioSendStream::Config& config) { >+ return call_->CreateAudioSendStream(config); >+} >+ >+void DegradedCall::DestroyAudioSendStream(AudioSendStream* send_stream) { >+ call_->DestroyAudioSendStream(send_stream); >+} >+ >+AudioReceiveStream* DegradedCall::CreateAudioReceiveStream( >+ const AudioReceiveStream::Config& config) { >+ return call_->CreateAudioReceiveStream(config); >+} >+ >+void DegradedCall::DestroyAudioReceiveStream( >+ AudioReceiveStream* receive_stream) { >+ call_->DestroyAudioReceiveStream(receive_stream); >+} >+ >+VideoSendStream* DegradedCall::CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config) { >+ if (send_config_ && !send_pipe_) { >+ send_pipe_ = absl::make_unique<FakeNetworkPipe>(clock_, *send_config_, >+ config.send_transport); >+ config.send_transport = this; >+ send_process_thread_->RegisterModule(send_pipe_.get(), RTC_FROM_HERE); >+ } >+ ++num_send_streams_; >+ return call_->CreateVideoSendStream(std::move(config), >+ std::move(encoder_config)); >+} >+ >+VideoSendStream* DegradedCall::CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller) { >+ if (send_config_ && !send_pipe_) { >+ send_pipe_ = absl::make_unique<FakeNetworkPipe>(clock_, *send_config_, >+ config.send_transport); >+ config.send_transport = this; >+ send_process_thread_->RegisterModule(send_pipe_.get(), RTC_FROM_HERE); >+ } >+ ++num_send_streams_; >+ return call_->CreateVideoSendStream( >+ std::move(config), std::move(encoder_config), std::move(fec_controller)); >+} >+ >+void DegradedCall::DestroyVideoSendStream(VideoSendStream* send_stream) { >+ call_->DestroyVideoSendStream(send_stream); >+ if (send_pipe_ && num_send_streams_ > 0) { >+ --num_send_streams_; >+ if (num_send_streams_ == 0) { >+ send_process_thread_->DeRegisterModule(send_pipe_.get()); >+ send_pipe_.reset(); >+ } >+ } >+} >+ >+VideoReceiveStream* DegradedCall::CreateVideoReceiveStream( >+ VideoReceiveStream::Config configuration) { >+ return call_->CreateVideoReceiveStream(std::move(configuration)); >+} >+ >+void DegradedCall::DestroyVideoReceiveStream( >+ VideoReceiveStream* receive_stream) { >+ call_->DestroyVideoReceiveStream(receive_stream); >+} >+ >+FlexfecReceiveStream* DegradedCall::CreateFlexfecReceiveStream( >+ const FlexfecReceiveStream::Config& config) { >+ return call_->CreateFlexfecReceiveStream(config); >+} >+ >+void DegradedCall::DestroyFlexfecReceiveStream( >+ FlexfecReceiveStream* receive_stream) { >+ call_->DestroyFlexfecReceiveStream(receive_stream); >+} >+ >+PacketReceiver* DegradedCall::Receiver() { >+ if (receive_config_) { >+ return this; >+ } >+ return call_->Receiver(); >+} >+ >+RtpTransportControllerSendInterface* >+DegradedCall::GetTransportControllerSend() { >+ return call_->GetTransportControllerSend(); >+} >+ >+Call::Stats DegradedCall::GetStats() const { >+ return call_->GetStats(); >+} >+ >+void DegradedCall::SetBitrateAllocationStrategy( >+ std::unique_ptr<rtc::BitrateAllocationStrategy> >+ bitrate_allocation_strategy) { >+ call_->SetBitrateAllocationStrategy(std::move(bitrate_allocation_strategy)); >+} >+ >+void DegradedCall::SignalChannelNetworkState(MediaType media, >+ NetworkState state) { >+ call_->SignalChannelNetworkState(media, state); >+} >+ >+void DegradedCall::OnTransportOverheadChanged( >+ MediaType media, >+ int transport_overhead_per_packet) { >+ call_->OnTransportOverheadChanged(media, transport_overhead_per_packet); >+} >+ >+void DegradedCall::OnSentPacket(const rtc::SentPacket& sent_packet) { >+ if (send_config_) { >+ // If we have a degraded send-transport, we have already notified call >+ // about the supposed network send time. Discard the actual network send >+ // time in order to properly fool the BWE. >+ return; >+ } >+ call_->OnSentPacket(sent_packet); >+} >+ >+bool DegradedCall::SendRtp(const uint8_t* packet, >+ size_t length, >+ const PacketOptions& options) { >+ // A call here comes from the RTP stack (probably pacer). We intercept it and >+ // put it in the fake network pipe instead, but report to Call that is has >+ // been sent, so that the bandwidth estimator sees the delay we add. >+ send_pipe_->SendRtp(packet, length, options); >+ if (options.packet_id != -1) { >+ rtc::SentPacket packet_info; >+ packet_info.packet_id = options.packet_id; >+ packet_info.send_time_ms = clock_->TimeInMilliseconds(); >+ call_->OnSentPacket(packet_info); >+ } >+ return true; >+} >+ >+bool DegradedCall::SendRtcp(const uint8_t* packet, size_t length) { >+ send_pipe_->SendRtcp(packet, length); >+ return true; >+} >+ >+PacketReceiver::DeliveryStatus DegradedCall::DeliverPacket( >+ MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) { >+ PacketReceiver::DeliveryStatus status = receive_pipe_->DeliverPacket( >+ media_type, std::move(packet), packet_time_us); >+ // This is not optimal, but there are many places where there are thread >+ // checks that fail if we're not using the worker thread call into this >+ // method. If we want to fix this we probably need a task queue to do handover >+ // of all overriden methods, which feels like overikill for the current use >+ // case. >+ // By just having this thread call out via the Process() method we work around >+ // that, with the tradeoff that a non-zero delay may become a little larger >+ // than anticipated at very low packet rates. >+ receive_pipe_->Process(); >+ return status; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.h >new file mode 100644 >index 00000000000..b1e22495874 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/degraded_call.h >@@ -0,0 +1,104 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef CALL_DEGRADED_CALL_H_ >+#define CALL_DEGRADED_CALL_H_ >+ >+#include <memory> >+ >+#include "absl/types/optional.h" >+#include "api/call/transport.h" >+#include "call/call.h" >+#include "call/fake_network_pipe.h" >+#include "modules/utility/include/process_thread.h" >+#include "system_wrappers/include/clock.h" >+ >+namespace webrtc { >+ >+class DegradedCall : public Call, private Transport, private PacketReceiver { >+ public: >+ explicit DegradedCall(std::unique_ptr<Call> call, >+ absl::optional<FakeNetworkPipe::Config> send_config, >+ absl::optional<FakeNetworkPipe::Config> receive_config); >+ ~DegradedCall() override; >+ >+ // Implements Call. >+ AudioSendStream* CreateAudioSendStream( >+ const AudioSendStream::Config& config) override; >+ void DestroyAudioSendStream(AudioSendStream* send_stream) override; >+ >+ AudioReceiveStream* CreateAudioReceiveStream( >+ const AudioReceiveStream::Config& config) override; >+ void DestroyAudioReceiveStream(AudioReceiveStream* receive_stream) override; >+ >+ VideoSendStream* CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config) override; >+ VideoSendStream* CreateVideoSendStream( >+ VideoSendStream::Config config, >+ VideoEncoderConfig encoder_config, >+ std::unique_ptr<FecController> fec_controller) override; >+ void DestroyVideoSendStream(VideoSendStream* send_stream) override; >+ >+ VideoReceiveStream* CreateVideoReceiveStream( >+ VideoReceiveStream::Config configuration) override; >+ void DestroyVideoReceiveStream(VideoReceiveStream* receive_stream) override; >+ >+ FlexfecReceiveStream* CreateFlexfecReceiveStream( >+ const FlexfecReceiveStream::Config& config) override; >+ void DestroyFlexfecReceiveStream( >+ FlexfecReceiveStream* receive_stream) override; >+ >+ PacketReceiver* Receiver() override; >+ >+ RtpTransportControllerSendInterface* GetTransportControllerSend() override; >+ >+ Stats GetStats() const override; >+ >+ void SetBitrateAllocationStrategy( >+ std::unique_ptr<rtc::BitrateAllocationStrategy> >+ bitrate_allocation_strategy) override; >+ >+ void SignalChannelNetworkState(MediaType media, NetworkState state) override; >+ >+ void OnTransportOverheadChanged(MediaType media, >+ int transport_overhead_per_packet) override; >+ >+ void OnSentPacket(const rtc::SentPacket& sent_packet) override; >+ >+ protected: >+ // Implements Transport. >+ bool SendRtp(const uint8_t* packet, >+ size_t length, >+ const PacketOptions& options) override; >+ >+ bool SendRtcp(const uint8_t* packet, size_t length) override; >+ >+ // Implements PacketReceiver. >+ DeliveryStatus DeliverPacket(MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) override; >+ >+ private: >+ Clock* const clock_; >+ const std::unique_ptr<Call> call_; >+ >+ const absl::optional<FakeNetworkPipe::Config> send_config_; >+ const std::unique_ptr<ProcessThread> send_process_thread_; >+ std::unique_ptr<FakeNetworkPipe> send_pipe_; >+ size_t num_send_streams_; >+ >+ const absl::optional<FakeNetworkPipe::Config> receive_config_; >+ std::unique_ptr<FakeNetworkPipe> receive_pipe_; >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_DEGRADED_CALL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.cc >new file mode 100644 >index 00000000000..55af767cb2f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.cc >@@ -0,0 +1,422 @@ >+/* >+ * 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 <assert.h> >+#include <math.h> >+#include <string.h> >+ >+#include <algorithm> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "call/call.h" >+#include "call/fake_network_pipe.h" >+#include "call/simulated_network.h" >+#include "rtc_base/logging.h" >+#include "system_wrappers/include/clock.h" >+ >+namespace webrtc { >+ >+namespace { >+constexpr int64_t kDefaultProcessIntervalMs = 5; >+constexpr int64_t kLogIntervalMs = 5000; >+} // namespace >+ >+NetworkPacket::NetworkPacket(rtc::CopyOnWriteBuffer packet, >+ int64_t send_time, >+ int64_t arrival_time, >+ absl::optional<PacketOptions> packet_options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<int64_t> packet_time_us) >+ : packet_(std::move(packet)), >+ send_time_(send_time), >+ arrival_time_(arrival_time), >+ packet_options_(packet_options), >+ is_rtcp_(is_rtcp), >+ media_type_(media_type), >+ packet_time_us_(packet_time_us) {} >+ >+NetworkPacket::NetworkPacket(rtc::CopyOnWriteBuffer packet, >+ int64_t send_time, >+ int64_t arrival_time, >+ absl::optional<PacketOptions> packet_options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<PacketTime> packet_time) >+ : NetworkPacket(packet, >+ send_time, >+ arrival_time, >+ packet_options, >+ is_rtcp, >+ media_type, >+ packet_time >+ ? absl::optional<int64_t>(packet_time->timestamp) >+ : absl::nullopt) {} >+ >+NetworkPacket::NetworkPacket(NetworkPacket&& o) >+ : packet_(std::move(o.packet_)), >+ send_time_(o.send_time_), >+ arrival_time_(o.arrival_time_), >+ packet_options_(o.packet_options_), >+ is_rtcp_(o.is_rtcp_), >+ media_type_(o.media_type_), >+ packet_time_us_(o.packet_time_us_) {} >+ >+NetworkPacket::~NetworkPacket() = default; >+ >+NetworkPacket& NetworkPacket::operator=(NetworkPacket&& o) { >+ packet_ = std::move(o.packet_); >+ send_time_ = o.send_time_; >+ arrival_time_ = o.arrival_time_; >+ packet_options_ = o.packet_options_; >+ is_rtcp_ = o.is_rtcp_; >+ media_type_ = o.media_type_; >+ packet_time_us_ = o.packet_time_us_; >+ >+ return *this; >+} >+ >+FakeNetworkPipe::FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config) >+ : FakeNetworkPipe(clock, config, nullptr, 1) {} >+ >+FakeNetworkPipe::FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ PacketReceiver* receiver) >+ : FakeNetworkPipe(clock, config, receiver, 1) {} >+ >+FakeNetworkPipe::FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ PacketReceiver* receiver, >+ uint64_t seed) >+ : clock_(clock), >+ network_simulation_(absl::make_unique<SimulatedNetwork>(config, seed)), >+ receiver_(receiver), >+ transport_(nullptr), >+ clock_offset_ms_(0), >+ dropped_packets_(0), >+ sent_packets_(0), >+ total_packet_delay_us_(0), >+ next_process_time_us_(clock_->TimeInMicroseconds()), >+ last_log_time_us_(clock_->TimeInMicroseconds()) {} >+ >+FakeNetworkPipe::FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ Transport* transport) >+ : clock_(clock), >+ network_simulation_(absl::make_unique<SimulatedNetwork>(config, 1)), >+ receiver_(nullptr), >+ transport_(transport), >+ clock_offset_ms_(0), >+ dropped_packets_(0), >+ sent_packets_(0), >+ total_packet_delay_us_(0), >+ next_process_time_us_(clock_->TimeInMicroseconds()), >+ last_log_time_us_(clock_->TimeInMicroseconds()) {} >+ >+FakeNetworkPipe::FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation) >+ : FakeNetworkPipe(clock, std::move(network_simulation), nullptr, 1) {} >+ >+FakeNetworkPipe::FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ PacketReceiver* receiver) >+ : FakeNetworkPipe(clock, std::move(network_simulation), receiver, 1) {} >+ >+FakeNetworkPipe::FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ PacketReceiver* receiver, >+ uint64_t seed) >+ : clock_(clock), >+ network_simulation_(std::move(network_simulation)), >+ receiver_(receiver), >+ transport_(nullptr), >+ clock_offset_ms_(0), >+ dropped_packets_(0), >+ sent_packets_(0), >+ total_packet_delay_us_(0), >+ next_process_time_us_(clock_->TimeInMicroseconds()), >+ last_log_time_us_(clock_->TimeInMicroseconds()) {} >+ >+FakeNetworkPipe::FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ Transport* transport) >+ : clock_(clock), >+ network_simulation_(std::move(network_simulation)), >+ receiver_(nullptr), >+ transport_(transport), >+ clock_offset_ms_(0), >+ dropped_packets_(0), >+ sent_packets_(0), >+ total_packet_delay_us_(0), >+ next_process_time_us_(clock_->TimeInMicroseconds()), >+ last_log_time_us_(clock_->TimeInMicroseconds()) {} >+ >+FakeNetworkPipe::~FakeNetworkPipe() = default; >+ >+void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) { >+ rtc::CritScope crit(&config_lock_); >+ receiver_ = receiver; >+} >+ >+bool FakeNetworkPipe::SendRtp(const uint8_t* packet, >+ size_t length, >+ const PacketOptions& options) { >+ RTC_DCHECK(HasTransport()); >+ EnqueuePacket(rtc::CopyOnWriteBuffer(packet, length), options, false, >+ MediaType::ANY); >+ return true; >+} >+ >+bool FakeNetworkPipe::SendRtcp(const uint8_t* packet, size_t length) { >+ RTC_DCHECK(HasTransport()); >+ EnqueuePacket(rtc::CopyOnWriteBuffer(packet, length), absl::nullopt, true, >+ MediaType::ANY); >+ return true; >+} >+ >+PacketReceiver::DeliveryStatus FakeNetworkPipe::DeliverPacket( >+ MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) { >+ return EnqueuePacket(std::move(packet), absl::nullopt, false, media_type, >+ packet_time_us) >+ ? PacketReceiver::DELIVERY_OK >+ : PacketReceiver::DELIVERY_PACKET_ERROR; >+} >+ >+void FakeNetworkPipe::SetClockOffset(int64_t offset_ms) { >+ rtc::CritScope crit(&config_lock_); >+ clock_offset_ms_ = offset_ms; >+} >+ >+void FakeNetworkPipe::SetConfig(const FakeNetworkPipe::Config& config) { >+ network_simulation_->SetConfig(config); >+} >+ >+ >+FakeNetworkPipe::StoredPacket::StoredPacket(NetworkPacket&& packet) >+ : packet(std::move(packet)) {} >+ >+bool FakeNetworkPipe::EnqueuePacket(rtc::CopyOnWriteBuffer packet, >+ absl::optional<PacketOptions> options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<int64_t> packet_time_us) { >+ absl::optional<PacketTime> packet_time; >+ if (packet_time_us) { >+ packet_time = PacketTime(*packet_time_us, -1); >+ } >+ return EnqueuePacket(packet, options, is_rtcp, media_type, packet_time); >+} >+ >+bool FakeNetworkPipe::EnqueuePacket(rtc::CopyOnWriteBuffer packet, >+ absl::optional<PacketOptions> options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<PacketTime> packet_time) { >+ int64_t time_now_us = clock_->TimeInMicroseconds(); >+ rtc::CritScope crit(&process_lock_); >+ size_t packet_size = packet.size(); >+ NetworkPacket net_packet( >+ std::move(packet), time_now_us, time_now_us, options, is_rtcp, media_type, >+ packet_time ? absl::optional<int64_t>(packet_time->timestamp) >+ : absl::nullopt); >+ >+ packets_in_flight_.emplace_back(StoredPacket(std::move(net_packet))); >+ int64_t packet_id = reinterpret_cast<uint64_t>(&packets_in_flight_.back()); >+ bool sent = network_simulation_->EnqueuePacket( >+ PacketInFlightInfo(packet_size, time_now_us, packet_id)); >+ >+ if (!sent) { >+ packets_in_flight_.pop_back(); >+ ++dropped_packets_; >+ } >+ return sent; >+} >+ >+float FakeNetworkPipe::PercentageLoss() { >+ rtc::CritScope crit(&process_lock_); >+ if (sent_packets_ == 0) >+ return 0; >+ >+ return static_cast<float>(dropped_packets_) / >+ (sent_packets_ + dropped_packets_); >+} >+ >+int FakeNetworkPipe::AverageDelay() { >+ rtc::CritScope crit(&process_lock_); >+ if (sent_packets_ == 0) >+ return 0; >+ >+ return static_cast<int>(total_packet_delay_us_ / >+ (1000 * static_cast<int64_t>(sent_packets_))); >+} >+ >+size_t FakeNetworkPipe::DroppedPackets() { >+ rtc::CritScope crit(&process_lock_); >+ return dropped_packets_; >+} >+ >+size_t FakeNetworkPipe::SentPackets() { >+ rtc::CritScope crit(&process_lock_); >+ return sent_packets_; >+} >+ >+void FakeNetworkPipe::Process() { >+ int64_t time_now_us = clock_->TimeInMicroseconds(); >+ std::queue<NetworkPacket> packets_to_deliver; >+ { >+ rtc::CritScope crit(&process_lock_); >+ if (time_now_us - last_log_time_us_ > kLogIntervalMs * 1000) { >+ int64_t queueing_delay_us = 0; >+ if (!packets_in_flight_.empty()) >+ queueing_delay_us = >+ time_now_us - packets_in_flight_.front().packet.send_time(); >+ >+ RTC_LOG(LS_INFO) << "Network queue: " << queueing_delay_us / 1000 >+ << " ms."; >+ last_log_time_us_ = time_now_us; >+ } >+ >+ std::vector<PacketDeliveryInfo> delivery_infos = >+ network_simulation_->DequeueDeliverablePackets(time_now_us); >+ for (auto& delivery_info : delivery_infos) { >+ // In the common case where no reordering happens, find will return early >+ // as the first packet will be a match. >+ auto packet_it = >+ std::find_if(packets_in_flight_.begin(), packets_in_flight_.end(), >+ [&delivery_info](StoredPacket& packet_ref) { >+ return reinterpret_cast<uint64_t>(&packet_ref) == >+ delivery_info.packet_id; >+ }); >+ // Check that the packet is in the deque of packets in flight. >+ RTC_CHECK(packet_it != packets_in_flight_.end()); >+ // Check that the packet is not already removed. >+ RTC_DCHECK(!packet_it->removed); >+ >+ NetworkPacket packet = std::move(packet_it->packet); >+ packet_it->removed = true; >+ >+ // Cleanup of removed packets at the beginning of the deque. >+ while (!packets_in_flight_.empty() && >+ packets_in_flight_.front().removed) { >+ packets_in_flight_.pop_front(); >+ } >+ >+ if (delivery_info.receive_time_us != PacketDeliveryInfo::kNotReceived) { >+ int64_t added_delay_us = >+ delivery_info.receive_time_us - packet.send_time(); >+ packet.IncrementArrivalTime(added_delay_us); >+ packets_to_deliver.emplace(std::move(packet)); >+ // |time_now_us| might be later than when the packet should have >+ // arrived, due to NetworkProcess being called too late. For stats, use >+ // the time it should have been on the link. >+ total_packet_delay_us_ += added_delay_us; >+ } >+ } >+ sent_packets_ += packets_to_deliver.size(); >+ } >+ >+ rtc::CritScope crit(&config_lock_); >+ while (!packets_to_deliver.empty()) { >+ NetworkPacket packet = std::move(packets_to_deliver.front()); >+ packets_to_deliver.pop(); >+ DeliverNetworkPacket(&packet); >+ } >+ absl::optional<int64_t> delivery_us = >+ network_simulation_->NextDeliveryTimeUs(); >+ next_process_time_us_ = delivery_us >+ ? *delivery_us >+ : time_now_us + kDefaultProcessIntervalMs * 1000; >+} >+ >+void FakeNetworkPipe::DeliverNetworkPacket(NetworkPacket* packet) { >+ if (transport_) { >+ RTC_DCHECK(!receiver_); >+ if (packet->is_rtcp()) { >+ transport_->SendRtcp(packet->data(), packet->data_length()); >+ } else { >+ transport_->SendRtp(packet->data(), packet->data_length(), >+ packet->packet_options()); >+ } >+ } else if (receiver_) { >+ int64_t packet_time_us = packet->packet_time_us().value_or(-1); >+ if (packet_time_us != -1) { >+ int64_t queue_time_us = packet->arrival_time() - packet->send_time(); >+ RTC_CHECK(queue_time_us >= 0); >+ packet_time_us += queue_time_us; >+ packet_time_us += (clock_offset_ms_ * 1000); >+ } >+ receiver_->DeliverPacket(packet->media_type(), >+ std::move(*packet->raw_packet()), packet_time_us); >+ } >+} >+ >+int64_t FakeNetworkPipe::TimeUntilNextProcess() { >+ rtc::CritScope crit(&process_lock_); >+ int64_t delay_us = next_process_time_us_ - clock_->TimeInMicroseconds(); >+ return std::max<int64_t>((delay_us + 500) / 1000, 0); >+} >+ >+bool FakeNetworkPipe::HasTransport() const { >+ rtc::CritScope crit(&config_lock_); >+ return transport_ != nullptr; >+} >+bool FakeNetworkPipe::HasReceiver() const { >+ rtc::CritScope crit(&config_lock_); >+ return receiver_ != nullptr; >+} >+ >+void FakeNetworkPipe::DeliverPacketWithLock(NetworkPacket* packet) { >+ rtc::CritScope crit(&config_lock_); >+ DeliverNetworkPacket(packet); >+} >+ >+void FakeNetworkPipe::ResetStats() { >+ rtc::CritScope crit(&process_lock_); >+ dropped_packets_ = 0; >+ sent_packets_ = 0; >+ total_packet_delay_us_ = 0; >+} >+ >+void FakeNetworkPipe::AddToPacketDropCount() { >+ rtc::CritScope crit(&process_lock_); >+ ++dropped_packets_; >+} >+ >+void FakeNetworkPipe::AddToPacketSentCount(int count) { >+ rtc::CritScope crit(&process_lock_); >+ sent_packets_ += count; >+} >+ >+void FakeNetworkPipe::AddToTotalDelay(int delay_us) { >+ rtc::CritScope crit(&process_lock_); >+ total_packet_delay_us_ += delay_us; >+} >+ >+int64_t FakeNetworkPipe::GetTimeInMicroseconds() const { >+ return clock_->TimeInMicroseconds(); >+} >+ >+bool FakeNetworkPipe::ShouldProcess(int64_t time_now_us) const { >+ return time_now_us >= next_process_time_us_; >+} >+ >+void FakeNetworkPipe::SetTimeToNextProcess(int64_t skip_us) { >+ next_process_time_us_ += skip_us; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.h >new file mode 100644 >index 00000000000..1f660b80636 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_network_pipe.h >@@ -0,0 +1,274 @@ >+/* >+ * 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. >+ */ >+ >+#ifndef CALL_FAKE_NETWORK_PIPE_H_ >+#define CALL_FAKE_NETWORK_PIPE_H_ >+ >+#include <deque> >+#include <map> >+#include <memory> >+#include <queue> >+#include <set> >+#include <string> >+#include <vector> >+ >+#include "api/call/transport.h" >+#include "api/test/simulated_network.h" >+#include "call/call.h" >+#include "common_types.h" // NOLINT(build/include) >+#include "modules/include/module.h" >+#include "rtc_base/constructormagic.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/thread_annotations.h" >+ >+namespace webrtc { >+ >+class Clock; >+class PacketReceiver; >+enum class MediaType; >+ >+class NetworkPacket { >+ public: >+ NetworkPacket(rtc::CopyOnWriteBuffer packet, >+ int64_t send_time, >+ int64_t arrival_time, >+ absl::optional<PacketOptions> packet_options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<int64_t> packet_time_us); >+ // TODO(nisse): Deprecated. >+ NetworkPacket(rtc::CopyOnWriteBuffer packet, >+ int64_t send_time, >+ int64_t arrival_time, >+ absl::optional<PacketOptions> packet_options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<PacketTime> packet_time); >+ >+ // Disallow copy constructor and copy assignment (no deep copies of |data_|). >+ NetworkPacket(const NetworkPacket&) = delete; >+ ~NetworkPacket(); >+ NetworkPacket& operator=(const NetworkPacket&) = delete; >+ // Allow move constructor/assignment, so that we can use in stl containers. >+ NetworkPacket(NetworkPacket&&); >+ NetworkPacket& operator=(NetworkPacket&&); >+ >+ const uint8_t* data() const { return packet_.data(); } >+ size_t data_length() const { return packet_.size(); } >+ rtc::CopyOnWriteBuffer* raw_packet() { return &packet_; } >+ int64_t send_time() const { return send_time_; } >+ int64_t arrival_time() const { return arrival_time_; } >+ void IncrementArrivalTime(int64_t extra_delay) { >+ arrival_time_ += extra_delay; >+ } >+ PacketOptions packet_options() const { >+ return packet_options_.value_or(PacketOptions()); >+ } >+ bool is_rtcp() const { return is_rtcp_; } >+ MediaType media_type() const { return media_type_; } >+ absl::optional<int64_t> packet_time_us() const { return packet_time_us_; } >+ // TODO(nisse): Deprecated. >+ PacketTime packet_time() const { >+ return PacketTime(packet_time_us_.value_or(-1), -1); >+ } >+ >+ private: >+ rtc::CopyOnWriteBuffer packet_; >+ // The time the packet was sent out on the network. >+ int64_t send_time_; >+ // The time the packet should arrive at the receiver. >+ int64_t arrival_time_; >+ // If using a Transport for outgoing degradation, populate with >+ // PacketOptions (transport-wide sequence number) for RTP. >+ absl::optional<PacketOptions> packet_options_; >+ bool is_rtcp_; >+ // If using a PacketReceiver for incoming degradation, populate with >+ // appropriate MediaType and PacketTime. This type/timing will be kept and >+ // forwarded. The PacketTime might be altered to reflect time spent in fake >+ // network pipe. >+ MediaType media_type_; >+ absl::optional<int64_t> packet_time_us_; >+}; >+ >+// Class faking a network link, internally is uses an implementation of a >+// SimulatedNetworkInterface to simulate network behavior. >+class FakeNetworkPipe : public Transport, public PacketReceiver, public Module { >+ public: >+ using Config = NetworkSimulationInterface::SimulatedNetworkConfig; >+ >+ // Deprecated. DO NOT USE. To be removed. Use corresponding version with >+ // NetworkSimulationInterface instance instead. >+ // Use these constructors if you plan to insert packets using DeliverPacket(). >+ FakeNetworkPipe(Clock* clock, const FakeNetworkPipe::Config& config); >+ // Will keep |network_simulation| alive while pipe is alive itself. >+ // Use these constructors if you plan to insert packets using DeliverPacket(). >+ FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation); >+ // Deprecated. DO NOT USE. To be removed. Use corresponding version with >+ // NetworkSimulationInterface instance instead. >+ FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ PacketReceiver* receiver); >+ FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ PacketReceiver* receiver); >+ // Deprecated. DO NOT USE. To be removed. Use corresponding version with >+ // NetworkSimulationInterface instance instead. >+ FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ PacketReceiver* receiver, >+ uint64_t seed); >+ FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ PacketReceiver* receiver, >+ uint64_t seed); >+ >+ // Deprecated. DO NOT USE. To be removed. Use corresponding version with >+ // NetworkSimulationInterface instance instead. >+ // Use this constructor if you plan to insert packets using SendRt[c?]p(). >+ FakeNetworkPipe(Clock* clock, >+ const FakeNetworkPipe::Config& config, >+ Transport* transport); >+ // Use this constructor if you plan to insert packets using SendRt[c?]p(). >+ FakeNetworkPipe( >+ Clock* clock, >+ std::unique_ptr<NetworkSimulationInterface> network_simulation, >+ Transport* transport); >+ >+ ~FakeNetworkPipe() override; >+ >+ void SetClockOffset(int64_t offset_ms); >+ >+ // Deprecated. DO NOT USE. Hold direct reference on NetworkSimulationInterface >+ // instead and call SetConfig on that object directly. Will be removed soon. >+ // Sets a new configuration. This won't affect packets already in the pipe. >+ void SetConfig(const FakeNetworkPipe::Config& config); >+ >+ // Must not be called in parallel with DeliverPacket or Process. >+ void SetReceiver(PacketReceiver* receiver); >+ >+ // Implements Transport interface. When/if packets are delivered, they will >+ // be passed to the transport instance given in SetReceiverTransport(). These >+ // methods should only be called if a Transport instance was provided in the >+ // constructor. >+ bool SendRtp(const uint8_t* packet, >+ size_t length, >+ const PacketOptions& options) override; >+ bool SendRtcp(const uint8_t* packet, size_t length) override; >+ >+ // Implements the PacketReceiver interface. When/if packets are delivered, >+ // they will be passed directly to the receiver instance given in >+ // SetReceiver(), without passing through a Demuxer. The receive time in >+ // PacketTime will be increased by the amount of time the packet spent in the >+ // fake network pipe. >+ PacketReceiver::DeliveryStatus DeliverPacket(MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) override; >+ >+ // TODO(bugs.webrtc.org/9584): Needed to inherit the alternative signature for >+ // this method. >+ using PacketReceiver::DeliverPacket; >+ >+ // Processes the network queues and trigger PacketReceiver::IncomingPacket for >+ // packets ready to be delivered. >+ void Process() override; >+ int64_t TimeUntilNextProcess() override; >+ >+ // Get statistics. >+ float PercentageLoss(); >+ int AverageDelay(); >+ size_t DroppedPackets(); >+ size_t SentPackets(); >+ void ResetStats(); >+ >+ protected: >+ void DeliverPacketWithLock(NetworkPacket* packet); >+ void AddToPacketDropCount(); >+ void AddToPacketSentCount(int count); >+ void AddToTotalDelay(int delay_us); >+ int64_t GetTimeInMicroseconds() const; >+ bool ShouldProcess(int64_t time_now_us) const; >+ void SetTimeToNextProcess(int64_t skip_us); >+ >+ private: >+ struct StoredPacket { >+ NetworkPacket packet; >+ bool removed = false; >+ explicit StoredPacket(NetworkPacket&& packet); >+ StoredPacket(StoredPacket&&) = default; >+ StoredPacket(const StoredPacket&) = delete; >+ StoredPacket& operator=(const StoredPacket&) = delete; >+ StoredPacket() = delete; >+ }; >+ >+ // Returns true if enqueued, or false if packet was dropped. >+ virtual bool EnqueuePacket(rtc::CopyOnWriteBuffer packet, >+ absl::optional<PacketOptions> options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<int64_t> packet_time_us); >+ >+ // TODO(nisse): Deprecated. Delete as soon as overrides in downstream code are >+ // updated. >+ virtual bool EnqueuePacket(rtc::CopyOnWriteBuffer packet, >+ absl::optional<PacketOptions> options, >+ bool is_rtcp, >+ MediaType media_type, >+ absl::optional<PacketTime> packet_time); >+ bool EnqueuePacket(rtc::CopyOnWriteBuffer packet, >+ absl::optional<PacketOptions> options, >+ bool is_rtcp, >+ MediaType media_type) { >+ return EnqueuePacket(packet, options, is_rtcp, media_type, >+ absl::optional<PacketTime>()); >+ } >+ void DeliverNetworkPacket(NetworkPacket* packet) >+ RTC_EXCLUSIVE_LOCKS_REQUIRED(config_lock_); >+ bool HasTransport() const; >+ bool HasReceiver() const; >+ >+ Clock* const clock_; >+ // |config_lock| guards the mostly constant things like the callbacks. >+ rtc::CriticalSection config_lock_; >+ const std::unique_ptr<NetworkSimulationInterface> network_simulation_; >+ PacketReceiver* receiver_ RTC_GUARDED_BY(config_lock_); >+ Transport* const transport_ RTC_GUARDED_BY(config_lock_); >+ >+ // |process_lock| guards the data structures involved in delay and loss >+ // processes, such as the packet queues. >+ rtc::CriticalSection process_lock_; >+ >+ // Packets are added at the back of the deque, this makes the deque ordered >+ // by increasing send time. The common case when removing packets from the >+ // deque is removing early packets, which will be close to the front of the >+ // deque. This makes finding the packets in the deque efficient in the common >+ // case. >+ std::deque<StoredPacket> packets_in_flight_ RTC_GUARDED_BY(process_lock_); >+ >+ int64_t clock_offset_ms_ RTC_GUARDED_BY(config_lock_); >+ >+ // Statistics. >+ size_t dropped_packets_ RTC_GUARDED_BY(process_lock_); >+ size_t sent_packets_ RTC_GUARDED_BY(process_lock_); >+ int64_t total_packet_delay_us_ RTC_GUARDED_BY(process_lock_); >+ >+ int64_t next_process_time_us_; >+ >+ int64_t last_log_time_us_; >+ >+ RTC_DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe); >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_FAKE_NETWORK_PIPE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_rtp_transport_controller_send.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_rtp_transport_controller_send.h >deleted file mode 100644 >index dda2e5f645c..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/fake_rtp_transport_controller_send.h >+++ /dev/null >@@ -1,68 +0,0 @@ >-/* >- * Copyright (c) 2015 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. >- */ >- >-#ifndef CALL_FAKE_RTP_TRANSPORT_CONTROLLER_SEND_H_ >-#define CALL_FAKE_RTP_TRANSPORT_CONTROLLER_SEND_H_ >- >-#include "call/rtp_transport_controller_send_interface.h" >-#include "common_types.h" // NOLINT(build/include) >-#include "modules/congestion_controller/include/send_side_congestion_controller.h" >-#include "modules/pacing/packet_router.h" >- >-namespace webrtc { >- >-class FakeRtpTransportControllerSend >- : public RtpTransportControllerSendInterface { >- public: >- explicit FakeRtpTransportControllerSend( >- PacketRouter* packet_router, >- PacedSender* paced_sender, >- SendSideCongestionController* send_side_cc) >- : packet_router_(packet_router), >- paced_sender_(paced_sender), >- send_side_cc_(send_side_cc) { >- RTC_DCHECK(send_side_cc); >- } >- >- PacketRouter* packet_router() override { return packet_router_; } >- >- SendSideCongestionController* send_side_cc() override { >- return send_side_cc_; >- } >- >- TransportFeedbackObserver* transport_feedback_observer() override { >- return send_side_cc_; >- } >- >- PacedSender* pacer() override { return paced_sender_; } >- >- RtpPacketSender* packet_sender() override { return paced_sender_; } >- >- const RtpKeepAliveConfig& keepalive_config() const override { >- return keepalive_; >- } >- >- void SetAllocatedSendBitrateLimits(int min_send_bitrate_bps, >- int max_padding_bitrate_bps) override {} >- >- void set_keepalive_config(const RtpKeepAliveConfig& keepalive_config) { >- keepalive_ = keepalive_config; >- } >- >- private: >- PacketRouter* packet_router_; >- PacedSender* paced_sender_; >- SendSideCongestionController* send_side_cc_; >- RtpKeepAliveConfig keepalive_; >-}; >- >-} // namespace webrtc >- >-#endif // CALL_FAKE_RTP_TRANSPORT_CONTROLLER_SEND_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.cc >new file mode 100644 >index 00000000000..86c000623d3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.cc >@@ -0,0 +1,21 @@ >+/* >+ * Copyright (c) 2018 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 "call/flexfec_receive_stream.h" >+ >+namespace webrtc { >+ >+FlexfecReceiveStream::Config::Config(Transport* rtcp_send_transport) >+ : rtcp_send_transport(rtcp_send_transport) { >+ RTC_DCHECK(rtcp_send_transport); >+} >+FlexfecReceiveStream::Config::~Config() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.h >index 98ce3510959..d64cb26f707 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream.h >@@ -16,8 +16,8 @@ > #include <string> > #include <vector> > >-#include "api/rtp_headers.h" > #include "api/call/transport.h" >+#include "api/rtp_headers.h" > #include "api/rtpparameters.h" > #include "call/rtp_packet_sink_interface.h" > #include "common_types.h" // NOLINT(build/include) >@@ -36,10 +36,8 @@ class FlexfecReceiveStream : public RtpPacketSinkInterface { > }; > > struct Config { >- explicit Config(Transport* rtcp_send_transport) >- : rtcp_send_transport(rtcp_send_transport) { >- RTC_DCHECK(rtcp_send_transport); >- } >+ explicit Config(Transport* rtcp_send_transport); >+ ~Config(); > > std::string ToString() const; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_impl.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_impl.cc >index 038c1f6a1b7..973df661643 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_impl.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_impl.cc >@@ -21,19 +21,22 @@ > #include "rtc_base/checks.h" > #include "rtc_base/location.h" > #include "rtc_base/logging.h" >+#include "rtc_base/strings/string_builder.h" > #include "system_wrappers/include/clock.h" > > namespace webrtc { > > std::string FlexfecReceiveStream::Stats::ToString(int64_t time_ms) const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "FlexfecReceiveStream stats: " << time_ms > << ", {flexfec_bitrate_bps: " << flexfec_bitrate_bps << "}"; > return ss.str(); > } > > std::string FlexfecReceiveStream::Config::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{payload_type: " << payload_type; > ss << ", remote_ssrc: " << remote_ssrc; > ss << ", local_ssrc: " << local_ssrc; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_unittest.cc >index 21dbeb7609d..da87c685d1c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/flexfec_receive_stream_unittest.cc >@@ -13,6 +13,7 @@ > #include <stdint.h> > #include <memory> > >+#include "absl/memory/memory.h" > #include "api/array_view.h" > #include "call/rtp_stream_receiver_controller.h" > #include "modules/pacing/packet_router.h" >@@ -22,7 +23,6 @@ > #include "modules/rtp_rtcp/source/byte_io.h" > #include "modules/rtp_rtcp/source/rtp_header_extensions.h" > #include "modules/utility/include/mock/mock_process_thread.h" >-#include "rtc_base/ptr_util.h" > #include "test/gmock.h" > #include "test/gtest.h" > #include "test/mock_transport.h" >@@ -84,7 +84,7 @@ class FlexfecReceiveStreamTest : public ::testing::Test { > FlexfecReceiveStreamTest() > : config_(CreateDefaultConfig(&rtcp_send_transport_)) { > EXPECT_CALL(process_thread_, RegisterModule(_, _)).Times(1); >- receive_stream_ = rtc::MakeUnique<FlexfecReceiveStreamImpl>( >+ receive_stream_ = absl::make_unique<FlexfecReceiveStreamImpl>( > &rtp_stream_receiver_controller_, config_, &recovered_packet_receiver_, > &rtt_stats_, &process_thread_); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.cc >new file mode 100644 >index 00000000000..d6786d29a7d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.cc >@@ -0,0 +1,31 @@ >+/* >+ * Copyright (c) 2018 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 "call/packet_receiver.h" >+ >+namespace webrtc { >+ >+PacketReceiver::DeliveryStatus PacketReceiver::DeliverPacket( >+ MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) { >+ return DeliverPacket(media_type, packet, PacketTime(packet_time_us, -1)); >+} >+ >+// TODO(bugs.webrtc.org/9584): Deprecated. Over the transition, default >+// implementations are used, and subclasses must override one or the other. >+PacketReceiver::DeliveryStatus PacketReceiver::DeliverPacket( >+ MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ const PacketTime& packet_time) { >+ return DeliverPacket(media_type, packet, packet_time.timestamp); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.h >new file mode 100644 >index 00000000000..2a0e3ef7b3b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/packet_receiver.h >@@ -0,0 +1,48 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+#ifndef CALL_PACKET_RECEIVER_H_ >+#define CALL_PACKET_RECEIVER_H_ >+ >+#include <algorithm> >+#include <memory> >+#include <string> >+#include <vector> >+ >+#include "api/mediatypes.h" >+#include "common_types.h" // NOLINT(build/include) >+#include "rtc_base/copyonwritebuffer.h" >+ >+namespace webrtc { >+ >+class PacketReceiver { >+ public: >+ enum DeliveryStatus { >+ DELIVERY_OK, >+ DELIVERY_UNKNOWN_SSRC, >+ DELIVERY_PACKET_ERROR, >+ }; >+ >+ virtual DeliveryStatus DeliverPacket(MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us); >+ >+ // TODO(bugs.webrtc.org/9584): Deprecated. Over the transition, default >+ // implementations are used, and subclasses must override one or the other. >+ virtual DeliveryStatus DeliverPacket(MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ const PacketTime& packet_time); >+ >+ protected: >+ virtual ~PacketReceiver() {} >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_PACKET_RECEIVER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.cc >index d0354168cfe..fcf32ad4793 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.cc >@@ -13,6 +13,7 @@ > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" > #include "rtc_base/platform_thread.h" >+#include "rtc_base/stringencode.h" > #include "test/encoder_settings.h" > #include "test/gtest.h" > #include "test/testsupport/perf_test.h" >@@ -24,7 +25,9 @@ static const int64_t kPollIntervalMs = 20; > static const int kExpectedHighVideoBitrateBps = 80000; > static const int kExpectedHighAudioBitrateBps = 30000; > static const int kLowBandwidthLimitBps = 20000; >-static const int kExpectedLowBitrateBps = 20000; >+// Set target detected bitrate to slightly larger than the target bitrate to >+// avoid flakiness. >+static const int kLowBitrateMarginBps = 2000; > > std::vector<uint32_t> GenerateSsrcs(size_t num_streams, uint32_t ssrc_offset) { > std::vector<uint32_t> ssrcs; >@@ -72,16 +75,13 @@ RampUpTester::RampUpTester(size_t num_video_streams, > EXPECT_LE(num_audio_streams_, 1u); > } > >-RampUpTester::~RampUpTester() { >-} >+RampUpTester::~RampUpTester() {} > >-Call::Config RampUpTester::GetSenderCallConfig() { >- Call::Config call_config(&event_log_); >+void RampUpTester::ModifySenderCallConfig(Call::Config* config) { > if (start_bitrate_bps_ != 0) { >- call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps_; >+ config->bitrate_config.start_bitrate_bps = start_bitrate_bps_; > } >- call_config.bitrate_config.min_bitrate_bps = 10000; >- return call_config; >+ config->bitrate_config.min_bitrate_bps = 10000; > } > > void RampUpTester::OnVideoStreamsCreated( >@@ -217,7 +217,7 @@ void RampUpTester::ModifyVideoConfigs( > recv_config.rtp.rtx_ssrc = video_rtx_ssrcs_[i]; > recv_config.rtp > .rtx_associated_payload_types[send_config->rtp.rtx.payload_type] = >- send_config->encoder_settings.payload_type; >+ send_config->rtp.payload_type; > } > ++i; > } >@@ -436,26 +436,20 @@ void RampUpDownUpTester::PollStats() { > } while (!stop_event_.Wait(kPollIntervalMs)); > } > >-Call::Config RampUpDownUpTester::GetReceiverCallConfig() { >- Call::Config config(&event_log_); >- config.bitrate_config.min_bitrate_bps = 10000; >- return config; >+void RampUpDownUpTester::ModifyReceiverCallConfig(Call::Config* config) { >+ config->bitrate_config.min_bitrate_bps = 10000; > } > > std::string RampUpDownUpTester::GetModifierString() const { > std::string str("_"); > if (num_video_streams_ > 0) { >- std::ostringstream s; >- s << num_video_streams_; >- str += s.str(); >+ str += rtc::ToString(num_video_streams_); > str += "stream"; > str += (num_video_streams_ > 1 ? "s" : ""); > str += "_"; > } > if (num_audio_streams_ > 0) { >- std::ostringstream s; >- s << num_audio_streams_; >- str += s.str(); >+ str += rtc::ToString(num_audio_streams_); > str += "stream"; > str += (num_audio_streams_ > 1 ? "s" : ""); > str += "_"; >@@ -510,7 +504,7 @@ void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) { > case kLowRate: { > // Audio streams are never suspended. > bool check_suspend_state = num_video_streams_ > 0; >- if (bitrate_bps < kExpectedLowBitrateBps && >+ if (bitrate_bps < kLowBandwidthLimitBps + kLowBitrateMarginBps && > suspended == check_suspend_state) { > if (report_perf_stats_) { > webrtc::test::PrintResult("ramp_up_down_up", GetModifierString(), >@@ -561,11 +555,6 @@ void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) { > class RampUpTest : public test::CallTest { > public: > RampUpTest() {} >- >- virtual ~RampUpTest() { >- EXPECT_EQ(nullptr, video_send_stream_); >- EXPECT_TRUE(video_receive_streams_.empty()); >- } > }; > > static const uint32_t kStartBitrateBps = 60000; >@@ -578,7 +567,15 @@ TEST_F(RampUpTest, UpDownUpAbsSendTimeSimulcastRedRtx) { > RunBaseTest(&test); > } > >-TEST_F(RampUpTest, UpDownUpTransportSequenceNumberRtx) { >+// TODO(bugs.webrtc.org/8878) >+#if defined(WEBRTC_MAC) >+#define MAYBE_UpDownUpTransportSequenceNumberRtx \ >+ DISABLED_UpDownUpTransportSequenceNumberRtx >+#else >+#define MAYBE_UpDownUpTransportSequenceNumberRtx \ >+ UpDownUpTransportSequenceNumberRtx >+#endif >+TEST_F(RampUpTest, MAYBE_UpDownUpTransportSequenceNumberRtx) { > std::vector<int> loss_rates = {0, 0, 0, 0}; > RampUpDownUpTester test(3, 0, 0, kStartBitrateBps, > RtpExtension::kTransportSequenceNumberUri, true, >@@ -598,7 +595,15 @@ TEST_F(RampUpTest, DISABLED_UpDownUpTransportSequenceNumberPacketLoss) { > RunBaseTest(&test); > } > >-TEST_F(RampUpTest, UpDownUpAudioVideoTransportSequenceNumberRtx) { >+// TODO(bugs.webrtc.org/8878) >+#if defined(WEBRTC_MAC) >+#define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \ >+ DISABLED_UpDownUpAudioVideoTransportSequenceNumberRtx >+#else >+#define MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx \ >+ UpDownUpAudioVideoTransportSequenceNumberRtx >+#endif >+TEST_F(RampUpTest, MAYBE_UpDownUpAudioVideoTransportSequenceNumberRtx) { > std::vector<int> loss_rates = {0, 0, 0, 0}; > RampUpDownUpTester test(3, 1, 0, kStartBitrateBps, > RtpExtension::kTransportSequenceNumberUri, true, >@@ -650,7 +655,13 @@ TEST_F(RampUpTest, TransportSequenceNumberSimulcastRedRtx) { > RunBaseTest(&test); > } > >-TEST_F(RampUpTest, AudioTransportSequenceNumber) { >+// TODO(bugs.webrtc.org/8878) >+#if defined(WEBRTC_MAC) >+#define MAYBE_AudioTransportSequenceNumber DISABLED_AudioTransportSequenceNumber >+#else >+#define MAYBE_AudioTransportSequenceNumber AudioTransportSequenceNumber >+#endif >+TEST_F(RampUpTest, MAYBE_AudioTransportSequenceNumber) { > RampUpTester test(0, 1, 0, 300000, 10000, > RtpExtension::kTransportSequenceNumberUri, false, false, > false); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.h >index 1339f1f2dc7..a22dfc9934c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rampup_tests.h >@@ -62,7 +62,6 @@ class RampUpTester : public test::EndToEndTest { > const std::string& units) const; > void TriggerTestDone(); > >- webrtc::RtcEventLogNullImpl event_log_; > rtc::Event stop_event_; > Clock* const clock_; > FakeNetworkPipe::Config forward_transport_config_; >@@ -80,7 +79,7 @@ class RampUpTester : public test::EndToEndTest { > typedef std::map<uint32_t, uint32_t> SsrcMap; > class VideoStreamFactory; > >- Call::Config GetSenderCallConfig() override; >+ void ModifySenderCallConfig(Call::Config* config) override; > void OnVideoStreamsCreated( > VideoSendStream* send_stream, > const std::vector<VideoReceiveStream*>& receive_streams) override; >@@ -139,7 +138,7 @@ class RampUpDownUpTester : public RampUpTester { > kTransitionToNextState, > }; > >- Call::Config GetReceiverCallConfig() override; >+ void ModifyReceiverCallConfig(Call::Config* config); > > std::string GetModifierString() const; > int GetExpectedHighBitrate() const; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.cc >new file mode 100644 >index 00000000000..16c6a43cc3f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.cc >@@ -0,0 +1,67 @@ >+/* >+ * Copyright (c) 2018 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 "call/receive_time_calculator.h" >+#include "absl/memory/memory.h" >+#include "rtc_base/logging.h" >+#include "system_wrappers/include/field_trial.h" >+ >+namespace webrtc { >+namespace { >+using ::webrtc::field_trial::FindFullName; >+using ::webrtc::field_trial::IsEnabled; >+ >+const char kBweReceiveTimeCorrection[] = "WebRTC-BweReceiveTimeCorrection"; >+} // namespace >+ >+ReceiveTimeCalculator::ReceiveTimeCalculator(int64_t min_delta_ms, >+ int64_t max_delta_diff_ms) >+ : min_delta_us_(min_delta_ms * 1000), >+ max_delta_diff_us_(max_delta_diff_ms * 1000) {} >+ >+std::unique_ptr<ReceiveTimeCalculator> >+ReceiveTimeCalculator::CreateFromFieldTrial() { >+ if (!IsEnabled(kBweReceiveTimeCorrection)) >+ return nullptr; >+ int min, max; >+ if (sscanf(FindFullName(kBweReceiveTimeCorrection).c_str(), "Enabled,%d,%d", >+ &min, &max) != 2) { >+ RTC_LOG(LS_WARNING) << "Invalid number of parameters provided."; >+ return nullptr; >+ } >+ return absl::make_unique<ReceiveTimeCalculator>(min, max); >+} >+ >+int64_t ReceiveTimeCalculator::ReconcileReceiveTimes(int64_t packet_time_us_, >+ int64_t safe_time_us_) { >+ if (!receive_time_offset_us_) { >+ receive_time_offset_us_ = safe_time_us_ - packet_time_us_; >+ } else { >+ int64_t safe_delta_us = safe_time_us_ - last_safe_time_us_; >+ int64_t packet_delta_us_ = packet_time_us_ - last_packet_time_us_; >+ int64_t delta_diff = packet_delta_us_ - safe_delta_us; >+ // Packet time should not decrease significantly, a large decrease indicates >+ // a reset of the packet time clock and we should reset the offest >+ // parameter. The safe reference time can increase in large jumps if the >+ // thread measuring it is backgrounded for longer periods. But if the packet >+ // time increases significantly more than the safe time, it indicates a >+ // clock reset and we should reset the offset. >+ >+ if (packet_delta_us_ < min_delta_us_ || delta_diff > max_delta_diff_us_) { >+ RTC_LOG(LS_WARNING) << "Received a clock jump of " << delta_diff >+ << " resetting offset"; >+ receive_time_offset_us_ = safe_time_us_ - packet_time_us_; >+ } >+ } >+ last_packet_time_us_ = packet_time_us_; >+ last_safe_time_us_ = safe_time_us_; >+ return packet_time_us_ + *receive_time_offset_us_; >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.h >new file mode 100644 >index 00000000000..a8217cd1012 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator.h >@@ -0,0 +1,47 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+#ifndef CALL_RECEIVE_TIME_CALCULATOR_H_ >+#define CALL_RECEIVE_TIME_CALCULATOR_H_ >+ >+#include <stdint.h> >+#include <memory> >+ >+#include "absl/types/optional.h" >+ >+namespace webrtc { >+ >+// The receive time calculator serves the purpose of combining packet time >+// stamps with a safely incremental clock. This assumes that the packet time >+// stamps are based on lower layer timestamps that have more accurate time >+// increments since they are based on the exact receive time. They might >+// however, have large jumps due to clock resets in the system. To compensate >+// this they are combined with a safe clock source that is guaranteed to be >+// consistent, but it will not be able to measure the exact time when a packet >+// is received. >+class ReceiveTimeCalculator { >+ public: >+ static std::unique_ptr<ReceiveTimeCalculator> CreateFromFieldTrial(); >+ // The min delta is used to correct for jumps backwards in time, to allow some >+ // packet reordering a small negative value is appropriate to use. The max >+ // delta difference is used as margin when detecting when packet time >+ // increases more than the safe clock. This should be larger than the largest >+ // expected sysmtem induced delay in the safe clock timestamp. >+ ReceiveTimeCalculator(int64_t min_delta_ms, int64_t max_delta_diff_ms); >+ int64_t ReconcileReceiveTimes(int64_t packet_time_us_, int64_t safe_time_us_); >+ >+ private: >+ const int64_t min_delta_us_; >+ const int64_t max_delta_diff_us_; >+ absl::optional<int64_t> receive_time_offset_us_; >+ int64_t last_packet_time_us_ = 0; >+ int64_t last_safe_time_us_ = 0; >+}; >+} // namespace webrtc >+#endif // CALL_RECEIVE_TIME_CALCULATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator_unittest.cc >new file mode 100644 >index 00000000000..92d5a279eae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/receive_time_calculator_unittest.cc >@@ -0,0 +1,74 @@ >+/* >+ * Copyright (c) 2018 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 "call/receive_time_calculator.h" >+ >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace test { >+namespace { >+ >+int64_t ReconcileMs(ReceiveTimeCalculator* calc, >+ int64_t packet_time_ms, >+ int64_t safe_time_ms) { >+ return calc->ReconcileReceiveTimes(packet_time_ms * 1000, >+ safe_time_ms * 1000) / >+ 1000; >+} >+} // namespace >+ >+TEST(ReceiveTimeCalculatorTest, UsesSmallerIncrements) { >+ int64_t kMinDeltaMs = -20; >+ int64_t kMaxDeltaDiffMs = 100; >+ ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs); >+ // Initialize offset. >+ ReconcileMs(&calc, 10000, 20000); >+ >+ EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010); >+ EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020); >+ EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030); >+ >+ EXPECT_EQ(ReconcileMs(&calc, 10110, 20200), 20110); >+ EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120); >+ EXPECT_EQ(ReconcileMs(&calc, 10130, 20200), 20130); >+ >+ // Small jumps backwards are let trough, they might be due to reordering. >+ EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120); >+ // The safe clock might be smaller than the packet clock. >+ EXPECT_EQ(ReconcileMs(&calc, 10210, 20200), 20210); >+ EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20240); >+} >+ >+TEST(ReceiveTimeCalculatorTest, CorrectsJumps) { >+ int64_t kMinDeltaMs = -20; >+ int64_t kMaxDeltaDiffMs = 100; >+ ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs); >+ // Initialize offset. >+ ReconcileMs(&calc, 10000, 20000); >+ >+ EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010); >+ EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020); >+ EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030); >+ >+ // Jump forward in time. >+ EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20200); >+ EXPECT_EQ(ReconcileMs(&calc, 10250, 20200), 20210); >+ EXPECT_EQ(ReconcileMs(&calc, 10260, 20200), 20220); >+ >+ // Jump backward in time. >+ EXPECT_EQ(ReconcileMs(&calc, 10230, 20300), 20300); >+ EXPECT_EQ(ReconcileMs(&calc, 10240, 20300), 20310); >+ EXPECT_EQ(ReconcileMs(&calc, 10250, 20300), 20320); >+} >+ >+} // namespace test >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.cc >index 0e78ddea186..d441c05b3db 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.cc >@@ -35,7 +35,7 @@ void RtcpDemuxer::AddSink(uint32_t sender_ssrc, RtcpPacketSinkInterface* sink) { > > void RtcpDemuxer::AddSink(const std::string& rsid, > RtcpPacketSinkInterface* sink) { >- RTC_DCHECK(StreamId::IsLegalName(rsid)); >+ RTC_DCHECK(StreamId::IsLegalRsidName(rsid)); > RTC_DCHECK(sink); > RTC_DCHECK(!ContainerHasKey(broadcast_sinks_, sink)); > RTC_DCHECK(!MultimapAssociationExists(rsid_sinks_, rsid, sink)); >@@ -66,7 +66,7 @@ void RtcpDemuxer::RemoveBroadcastSink(const RtcpPacketSinkInterface* sink) { > > void RtcpDemuxer::OnRtcpPacket(rtc::ArrayView<const uint8_t> packet) { > // Perform sender-SSRC-based demuxing for packets with a sender-SSRC. >- rtc::Optional<uint32_t> sender_ssrc = ParseRtcpPacketSenderSsrc(packet); >+ absl::optional<uint32_t> sender_ssrc = ParseRtcpPacketSenderSsrc(packet); > if (sender_ssrc) { > auto it_range = ssrc_sinks_.equal_range(*sender_ssrc); > for (auto it = it_range.first; it != it_range.second; ++it) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.h >index 87b5816282a..494e0cea4b5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer.h >@@ -17,7 +17,6 @@ > > #include "api/array_view.h" > #include "call/ssrc_binding_observer.h" >-#include "rtc_base/basictypes.h" > > namespace webrtc { > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer_unittest.cc >index 0e1c95b9f5c..808364acc5e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtcp_demuxer_unittest.cc >@@ -13,14 +13,13 @@ > #include <memory> > #include <set> > >+#include "absl/memory/memory.h" > #include "api/rtp_headers.h" > #include "call/rtcp_packet_sink_interface.h" > #include "common_types.h" // NOLINT(build/include) > #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" > #include "rtc_base/arraysize.h" >-#include "rtc_base/basictypes.h" > #include "rtc_base/checks.h" >-#include "rtc_base/ptr_util.h" > #include "test/gmock.h" > #include "test/gtest.h" > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.cc >new file mode 100644 >index 00000000000..fafd8ec9972 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.cc >@@ -0,0 +1,107 @@ >+/* >+ * Copyright (c) 2018 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 "call/rtp_bitrate_configurator.h" >+ >+#include <algorithm> >+ >+#include "rtc_base/checks.h" >+ >+namespace webrtc { >+RtpBitrateConfigurator::RtpBitrateConfigurator( >+ const BitrateConstraints& bitrate_config) >+ : bitrate_config_(bitrate_config), base_bitrate_config_(bitrate_config) { >+ RTC_DCHECK_GE(bitrate_config.min_bitrate_bps, 0); >+ RTC_DCHECK_GE(bitrate_config.start_bitrate_bps, >+ bitrate_config.min_bitrate_bps); >+ if (bitrate_config.max_bitrate_bps != -1) { >+ RTC_DCHECK_GE(bitrate_config.max_bitrate_bps, >+ bitrate_config.start_bitrate_bps); >+ } >+} >+ >+RtpBitrateConfigurator::~RtpBitrateConfigurator() = default; >+ >+BitrateConstraints RtpBitrateConfigurator::GetConfig() const { >+ return bitrate_config_; >+} >+ >+absl::optional<BitrateConstraints> >+RtpBitrateConfigurator::UpdateWithSdpParameters( >+ const BitrateConstraints& bitrate_config) { >+ RTC_DCHECK_GE(bitrate_config.min_bitrate_bps, 0); >+ RTC_DCHECK_NE(bitrate_config.start_bitrate_bps, 0); >+ if (bitrate_config.max_bitrate_bps != -1) { >+ RTC_DCHECK_GT(bitrate_config.max_bitrate_bps, 0); >+ } >+ >+ absl::optional<int> new_start; >+ // Only update the "start" bitrate if it's set, and different from the old >+ // value. In practice, this value comes from the x-google-start-bitrate codec >+ // parameter in SDP, and setting the same remote description twice shouldn't >+ // restart bandwidth estimation. >+ if (bitrate_config.start_bitrate_bps != -1 && >+ bitrate_config.start_bitrate_bps != >+ base_bitrate_config_.start_bitrate_bps) { >+ new_start.emplace(bitrate_config.start_bitrate_bps); >+ } >+ base_bitrate_config_ = bitrate_config; >+ return UpdateConstraints(new_start); >+} >+ >+absl::optional<BitrateConstraints> >+RtpBitrateConfigurator::UpdateWithClientPreferences( >+ const BitrateSettings& bitrate_mask) { >+ bitrate_config_mask_ = bitrate_mask; >+ return UpdateConstraints(bitrate_mask.start_bitrate_bps); >+} >+ >+absl::optional<BitrateConstraints> RtpBitrateConfigurator::UpdateConstraints( >+ const absl::optional<int>& new_start) { >+ BitrateConstraints updated; >+ updated.min_bitrate_bps = >+ std::max(bitrate_config_mask_.min_bitrate_bps.value_or(0), >+ base_bitrate_config_.min_bitrate_bps); >+ >+ updated.max_bitrate_bps = >+ MinPositive(bitrate_config_mask_.max_bitrate_bps.value_or(-1), >+ base_bitrate_config_.max_bitrate_bps); >+ >+ // If the combined min ends up greater than the combined max, the max takes >+ // priority. >+ if (updated.max_bitrate_bps != -1 && >+ updated.min_bitrate_bps > updated.max_bitrate_bps) { >+ updated.min_bitrate_bps = updated.max_bitrate_bps; >+ } >+ >+ // If there is nothing to update (min/max unchanged, no new bandwidth >+ // estimation start value), return early. >+ if (updated.min_bitrate_bps == bitrate_config_.min_bitrate_bps && >+ updated.max_bitrate_bps == bitrate_config_.max_bitrate_bps && >+ !new_start) { >+ return absl::nullopt; >+ } >+ >+ if (new_start) { >+ // Clamp start by min and max. >+ updated.start_bitrate_bps = MinPositive( >+ std::max(*new_start, updated.min_bitrate_bps), updated.max_bitrate_bps); >+ } else { >+ updated.start_bitrate_bps = -1; >+ } >+ BitrateConstraints config_to_return = updated; >+ if (!new_start) { >+ updated.start_bitrate_bps = bitrate_config_.start_bitrate_bps; >+ } >+ bitrate_config_ = updated; >+ return config_to_return; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.h >new file mode 100644 >index 00000000000..07fe8d41a65 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator.h >@@ -0,0 +1,69 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef CALL_RTP_BITRATE_CONFIGURATOR_H_ >+#define CALL_RTP_BITRATE_CONFIGURATOR_H_ >+ >+#include "api/bitrate_constraints.h" >+#include "api/transport/bitrate_settings.h" >+#include "rtc_base/constructormagic.h" >+ >+namespace webrtc { >+ >+// RtpBitrateConfigurator calculates the bitrate configuration based on received >+// remote configuration combined with local overrides. >+class RtpBitrateConfigurator { >+ public: >+ explicit RtpBitrateConfigurator(const BitrateConstraints& bitrate_config); >+ ~RtpBitrateConfigurator(); >+ BitrateConstraints GetConfig() const; >+ >+ // The greater min and smaller max set by this and SetClientBitratePreferences >+ // will be used. The latest non-negative start value from either call will be >+ // used. Specifying a start bitrate (>0) will reset the current bitrate >+ // estimate. This is due to how the 'x-google-start-bitrate' flag is currently >+ // implemented. Passing -1 leaves the start bitrate unchanged. Behavior is not >+ // guaranteed for other negative values or 0. >+ // The optional return value is set with new configuration if it was updated. >+ absl::optional<BitrateConstraints> UpdateWithSdpParameters( >+ const BitrateConstraints& bitrate_config_); >+ >+ // The greater min and smaller max set by this and SetSdpBitrateParameters >+ // will be used. The latest non-negative start value form either call will be >+ // used. Specifying a start bitrate will reset the current bitrate estimate. >+ // Assumes 0 <= min <= start <= max holds for set parameters. >+ // Update the bitrate configuration >+ // The optional return value is set with new configuration if it was updated. >+ absl::optional<BitrateConstraints> UpdateWithClientPreferences( >+ const BitrateSettings& bitrate_mask); >+ >+ private: >+ // Applies update to the BitrateConstraints cached in |config_|, resetting >+ // with |new_start| if set. >+ absl::optional<BitrateConstraints> UpdateConstraints( >+ const absl::optional<int>& new_start); >+ >+ // Bitrate config used until valid bitrate estimates are calculated. Also >+ // used to cap total bitrate used. This comes from the remote connection. >+ BitrateConstraints bitrate_config_; >+ >+ // The config mask set by SetClientBitratePreferences. >+ // 0 <= min <= start <= max >+ BitrateSettings bitrate_config_mask_; >+ >+ // The config set by SetSdpBitrateParameters. >+ // min >= 0, start != 0, max == -1 || max > 0 >+ BitrateConstraints base_bitrate_config_; >+ >+ RTC_DISALLOW_COPY_AND_ASSIGN(RtpBitrateConfigurator); >+}; >+} // namespace webrtc >+ >+#endif // CALL_RTP_BITRATE_CONFIGURATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator_unittest.cc >new file mode 100644 >index 00000000000..b177db7a8f6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_bitrate_configurator_unittest.cc >@@ -0,0 +1,299 @@ >+/* >+ * Copyright (c) 2018 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 <memory> >+ >+#include "call/rtp_bitrate_configurator.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+using absl::nullopt; >+ >+class RtpBitrateConfiguratorTest : public testing::Test { >+ public: >+ RtpBitrateConfiguratorTest() >+ : configurator_(new RtpBitrateConfigurator(BitrateConstraints())) {} >+ std::unique_ptr<RtpBitrateConfigurator> configurator_; >+ void UpdateConfigMatches(BitrateConstraints bitrate_config, >+ absl::optional<int> min_bitrate_bps, >+ absl::optional<int> start_bitrate_bps, >+ absl::optional<int> max_bitrate_bps) { >+ absl::optional<BitrateConstraints> result = >+ configurator_->UpdateWithSdpParameters(bitrate_config); >+ EXPECT_TRUE(result.has_value()); >+ if (start_bitrate_bps.has_value()) >+ EXPECT_EQ(result->start_bitrate_bps, start_bitrate_bps); >+ if (min_bitrate_bps.has_value()) >+ EXPECT_EQ(result->min_bitrate_bps, min_bitrate_bps); >+ if (max_bitrate_bps.has_value()) >+ EXPECT_EQ(result->max_bitrate_bps, max_bitrate_bps); >+ } >+ >+ void UpdateMaskMatches(BitrateSettings bitrate_mask, >+ absl::optional<int> min_bitrate_bps, >+ absl::optional<int> start_bitrate_bps, >+ absl::optional<int> max_bitrate_bps) { >+ absl::optional<BitrateConstraints> result = >+ configurator_->UpdateWithClientPreferences(bitrate_mask); >+ EXPECT_TRUE(result.has_value()); >+ if (start_bitrate_bps.has_value()) >+ EXPECT_EQ(result->start_bitrate_bps, start_bitrate_bps); >+ if (min_bitrate_bps.has_value()) >+ EXPECT_EQ(result->min_bitrate_bps, min_bitrate_bps); >+ if (max_bitrate_bps.has_value()) >+ EXPECT_EQ(result->max_bitrate_bps, max_bitrate_bps); >+ } >+}; >+ >+TEST_F(RtpBitrateConfiguratorTest, NewConfigWithValidConfigReturnsNewConfig) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 1; >+ bitrate_config.start_bitrate_bps = 2; >+ bitrate_config.max_bitrate_bps = 3; >+ >+ UpdateConfigMatches(bitrate_config, 1, 2, 3); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, NewConfigWithDifferentMinReturnsNewConfig) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 10; >+ bitrate_config.start_bitrate_bps = 20; >+ bitrate_config.max_bitrate_bps = 30; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ bitrate_config.min_bitrate_bps = 11; >+ UpdateConfigMatches(bitrate_config, 11, -1, 30); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, >+ NewConfigWithDifferentStartReturnsNewConfig) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 10; >+ bitrate_config.start_bitrate_bps = 20; >+ bitrate_config.max_bitrate_bps = 30; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ bitrate_config.start_bitrate_bps = 21; >+ UpdateConfigMatches(bitrate_config, 10, 21, 30); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, NewConfigWithDifferentMaxReturnsNewConfig) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 10; >+ bitrate_config.start_bitrate_bps = 20; >+ bitrate_config.max_bitrate_bps = 30; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ bitrate_config.max_bitrate_bps = 31; >+ UpdateConfigMatches(bitrate_config, 10, -1, 31); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, NewConfigWithSameConfigElidesSecondCall) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 1; >+ bitrate_config.start_bitrate_bps = 2; >+ bitrate_config.max_bitrate_bps = 3; >+ >+ UpdateConfigMatches(bitrate_config, 1, 2, 3); >+ EXPECT_FALSE( >+ configurator_->UpdateWithSdpParameters(bitrate_config).has_value()); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, >+ NewConfigWithSameMinMaxAndNegativeStartElidesSecondCall) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 1; >+ bitrate_config.start_bitrate_bps = 2; >+ bitrate_config.max_bitrate_bps = 3; >+ >+ UpdateConfigMatches(bitrate_config, 1, 2, 3); >+ >+ bitrate_config.start_bitrate_bps = -1; >+ EXPECT_FALSE( >+ configurator_->UpdateWithSdpParameters(bitrate_config).has_value()); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, BiggerMaskMinUsed) { >+ BitrateSettings mask; >+ mask.min_bitrate_bps = 1234; >+ UpdateMaskMatches(mask, *mask.min_bitrate_bps, nullopt, nullopt); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, BiggerConfigMinUsed) { >+ BitrateSettings mask; >+ mask.min_bitrate_bps = 1000; >+ UpdateMaskMatches(mask, 1000, nullopt, nullopt); >+ >+ BitrateConstraints config; >+ config.min_bitrate_bps = 1234; >+ UpdateConfigMatches(config, 1234, nullopt, nullopt); >+} >+ >+// The last call to set start should be used. >+TEST_F(RtpBitrateConfiguratorTest, LatestStartMaskPreferred) { >+ BitrateSettings mask; >+ mask.start_bitrate_bps = 1300; >+ UpdateMaskMatches(mask, nullopt, *mask.start_bitrate_bps, nullopt); >+ >+ BitrateConstraints bitrate_config; >+ bitrate_config.start_bitrate_bps = 1200; >+ >+ UpdateConfigMatches(bitrate_config, nullopt, bitrate_config.start_bitrate_bps, >+ nullopt); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, SmallerMaskMaxUsed) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ BitrateSettings mask; >+ mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; >+ >+ UpdateMaskMatches(mask, nullopt, nullopt, *mask.max_bitrate_bps); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, SmallerConfigMaxUsed) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.max_bitrate_bps = bitrate_config.start_bitrate_bps + 1000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ BitrateSettings mask; >+ mask.max_bitrate_bps = bitrate_config.start_bitrate_bps + 2000; >+ >+ // Expect no return because nothing changes >+ EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, MaskStartLessThanConfigMinClamped) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 2000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ BitrateSettings mask; >+ mask.start_bitrate_bps = 1000; >+ UpdateMaskMatches(mask, 2000, 2000, nullopt); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, MaskStartGreaterThanConfigMaxClamped) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.start_bitrate_bps = 2000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ BitrateSettings mask; >+ mask.max_bitrate_bps = 1000; >+ >+ UpdateMaskMatches(mask, nullopt, -1, 1000); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, MaskMinGreaterThanConfigMaxClamped) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.min_bitrate_bps = 2000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ BitrateSettings mask; >+ mask.max_bitrate_bps = 1000; >+ >+ UpdateMaskMatches(mask, 1000, nullopt, 1000); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, SettingMaskStartForcesUpdate) { >+ BitrateSettings mask; >+ mask.start_bitrate_bps = 1000; >+ >+ // Config should be returned twice with the same params since >+ // start_bitrate_bps is set. >+ UpdateMaskMatches(mask, nullopt, 1000, nullopt); >+ UpdateMaskMatches(mask, nullopt, 1000, nullopt); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, NewConfigWithNoChangesDoesNotCallNewConfig) { >+ BitrateConstraints config1; >+ config1.min_bitrate_bps = 0; >+ config1.start_bitrate_bps = 1000; >+ config1.max_bitrate_bps = -1; >+ >+ BitrateConstraints config2; >+ config2.min_bitrate_bps = 0; >+ config2.start_bitrate_bps = -1; >+ config2.max_bitrate_bps = -1; >+ >+ // The second call should not return anything because it doesn't >+ // change any values. >+ UpdateConfigMatches(config1, 0, 1000, -1); >+ EXPECT_FALSE(configurator_->UpdateWithSdpParameters(config2).has_value()); >+} >+ >+// If config changes the max, but not the effective max, >+// new config shouldn't be returned, to avoid unnecessary encoder >+// reconfigurations. >+TEST_F(RtpBitrateConfiguratorTest, >+ NewConfigNotReturnedWhenEffectiveMaxUnchanged) { >+ BitrateConstraints config; >+ config.min_bitrate_bps = 0; >+ config.start_bitrate_bps = -1; >+ config.max_bitrate_bps = 2000; >+ UpdateConfigMatches(config, nullopt, nullopt, 2000); >+ >+ // Reduce effective max to 1000 with the mask. >+ BitrateSettings mask; >+ mask.max_bitrate_bps = 1000; >+ UpdateMaskMatches(mask, nullopt, nullopt, 1000); >+ >+ // This leaves the effective max unchanged, so new config shouldn't be >+ // returned again. >+ config.max_bitrate_bps = 1000; >+ EXPECT_FALSE(configurator_->UpdateWithSdpParameters(config).has_value()); >+} >+ >+// When the "start bitrate" mask is removed, new config shouldn't be returned >+// again, since nothing's changing. >+TEST_F(RtpBitrateConfiguratorTest, NewConfigNotReturnedWhenStartMaskRemoved) { >+ BitrateSettings mask; >+ mask.start_bitrate_bps = 1000; >+ UpdateMaskMatches(mask, 0, 1000, -1); >+ >+ mask.start_bitrate_bps.reset(); >+ EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); >+} >+ >+// Test that if a new config is returned after BitrateSettings applies a >+// "start" value, the new config won't return that start value a >+// second time. >+TEST_F(RtpBitrateConfiguratorTest, NewConfigAfterBitrateConfigMaskWithStart) { >+ BitrateSettings mask; >+ mask.start_bitrate_bps = 1000; >+ UpdateMaskMatches(mask, 0, 1000, -1); >+ >+ BitrateConstraints config; >+ config.min_bitrate_bps = 0; >+ config.start_bitrate_bps = -1; >+ config.max_bitrate_bps = 5000; >+ // The start value isn't changing, so new config should be returned with >+ // -1. >+ UpdateConfigMatches(config, 0, -1, 5000); >+} >+ >+TEST_F(RtpBitrateConfiguratorTest, >+ NewConfigNotReturnedWhenClampedMinUnchanged) { >+ BitrateConstraints bitrate_config; >+ bitrate_config.start_bitrate_bps = 500; >+ bitrate_config.max_bitrate_bps = 1000; >+ configurator_.reset(new RtpBitrateConfigurator(bitrate_config)); >+ >+ // Set min to 2000; it is clamped to the max (1000). >+ BitrateSettings mask; >+ mask.min_bitrate_bps = 2000; >+ UpdateMaskMatches(mask, 1000, -1, 1000); >+ >+ // Set min to 3000; the clamped value stays the same so nothing happens. >+ mask.min_bitrate_bps = 3000; >+ EXPECT_FALSE(configurator_->UpdateWithClientPreferences(mask).has_value()); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.cc >index 3621f728903..1445c2552e4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.cc >@@ -10,19 +10,21 @@ > > #include "call/rtp_config.h" > >-#include <sstream> >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > > std::string NackConfig::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{rtp_history_ms: " << rtp_history_ms; > ss << '}'; > return ss.str(); > } > > std::string UlpfecConfig::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{ulpfec_payload_type: " << ulpfec_payload_type; > ss << ", red_payload_type: " << red_payload_type; > ss << ", red_rtx_payload_type: " << red_rtx_payload_type; >@@ -35,4 +37,89 @@ bool UlpfecConfig::operator==(const UlpfecConfig& other) const { > red_payload_type == other.red_payload_type && > red_rtx_payload_type == other.red_rtx_payload_type; > } >+ >+RtpConfig::RtpConfig() = default; >+RtpConfig::RtpConfig(const RtpConfig&) = default; >+RtpConfig::~RtpConfig() = default; >+ >+RtpConfig::Flexfec::Flexfec() = default; >+RtpConfig::Flexfec::Flexfec(const Flexfec&) = default; >+RtpConfig::Flexfec::~Flexfec() = default; >+ >+std::string RtpConfig::ToString() const { >+ char buf[2 * 1024]; >+ rtc::SimpleStringBuilder ss(buf); >+ ss << "{ssrcs: ["; >+ for (size_t i = 0; i < ssrcs.size(); ++i) { >+ ss << ssrcs[i]; >+ if (i != ssrcs.size() - 1) >+ ss << ", "; >+ } >+ ss << ']'; >+ ss << ", rtcp_mode: " >+ << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound" >+ : "RtcpMode::kReducedSize"); >+ ss << ", max_packet_size: " << max_packet_size; >+ ss << ", extensions: ["; >+ for (size_t i = 0; i < extensions.size(); ++i) { >+ ss << extensions[i].ToString(); >+ if (i != extensions.size() - 1) >+ ss << ", "; >+ } >+ ss << ']'; >+ >+ ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}'; >+ ss << ", ulpfec: " << ulpfec.ToString(); >+ ss << ", payload_name: " << payload_name; >+ ss << ", payload_type: " << payload_type; >+ >+ ss << ", flexfec: {payload_type: " << flexfec.payload_type; >+ ss << ", ssrc: " << flexfec.ssrc; >+ ss << ", protected_media_ssrcs: ["; >+ for (size_t i = 0; i < flexfec.protected_media_ssrcs.size(); ++i) { >+ ss << flexfec.protected_media_ssrcs[i]; >+ if (i != flexfec.protected_media_ssrcs.size() - 1) >+ ss << ", "; >+ } >+ ss << "]}"; >+ >+ ss << ", rtx: " << rtx.ToString(); >+ ss << ", c_name: " << c_name; >+ ss << '}'; >+ return ss.str(); >+} >+ >+RtpConfig::Rtx::Rtx() = default; >+RtpConfig::Rtx::Rtx(const Rtx&) = default; >+RtpConfig::Rtx::~Rtx() = default; >+ >+std::string RtpConfig::Rtx::ToString() const { >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); >+ ss << "{ssrcs: ["; >+ for (size_t i = 0; i < ssrcs.size(); ++i) { >+ ss << ssrcs[i]; >+ if (i != ssrcs.size() - 1) >+ ss << ", "; >+ } >+ ss << ']'; >+ >+ ss << ", payload_type: " << payload_type; >+ ss << '}'; >+ return ss.str(); >+} >+ >+RtcpConfig::RtcpConfig() = default; >+RtcpConfig::RtcpConfig(const RtcpConfig&) = default; >+RtcpConfig::~RtcpConfig() = default; >+ >+std::string RtcpConfig::ToString() const { >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); >+ ss << "{video_report_interval_ms: " << video_report_interval_ms; >+ ss << ", audio_report_interval_ms: " << audio_report_interval_ms; >+ ss << '}'; >+ return ss.str(); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.h >index 86d32ac104d..8f8d03a3a82 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_config.h >@@ -12,8 +12,18 @@ > #define CALL_RTP_CONFIG_H_ > > #include <string> >+#include <vector> >+ >+#include "api/rtp_headers.h" >+#include "api/rtpparameters.h" > > namespace webrtc { >+// Currently only VP8/VP9 specific. >+struct RtpPayloadState { >+ int16_t picture_id = -1; >+ uint8_t tl0_pic_idx = 0; >+ int64_t shared_frame_id = 0; >+}; > // Settings for NACK, see RFC 4585 for details. > struct NackConfig { > NackConfig() : rtp_history_ms(0) {} >@@ -44,5 +54,92 @@ struct UlpfecConfig { > // RTX payload type for RED payload. > int red_rtx_payload_type; > }; >+ >+static const size_t kDefaultMaxPacketSize = 1500 - 40; // TCP over IPv4. >+struct RtpConfig { >+ RtpConfig(); >+ RtpConfig(const RtpConfig&); >+ ~RtpConfig(); >+ std::string ToString() const; >+ >+ std::vector<uint32_t> ssrcs; >+ >+ // The value to send in the MID RTP header extension if the extension is >+ // included in the list of extensions. >+ std::string mid; >+ >+ // See RtcpMode for description. >+ RtcpMode rtcp_mode = RtcpMode::kCompound; >+ >+ // Max RTP packet size delivered to send transport from VideoEngine. >+ size_t max_packet_size = kDefaultMaxPacketSize; >+ >+ // RTP header extensions to use for this send stream. >+ std::vector<RtpExtension> extensions; >+ >+ // TODO(nisse): For now, these are fixed, but we'd like to support >+ // changing codec without recreating the VideoSendStream. Then these >+ // fields must be removed, and association between payload type and codec >+ // must move above the per-stream level. Ownership could be with >+ // RtpTransportControllerSend, with a reference from PayloadRouter, where >+ // the latter would be responsible for mapping the codec type of encoded >+ // images to the right payload type. >+ std::string payload_name; >+ int payload_type = -1; >+ >+ // See NackConfig for description. >+ NackConfig nack; >+ >+ // See UlpfecConfig for description. >+ UlpfecConfig ulpfec; >+ >+ struct Flexfec { >+ Flexfec(); >+ Flexfec(const Flexfec&); >+ ~Flexfec(); >+ // Payload type of FlexFEC. Set to -1 to disable sending FlexFEC. >+ int payload_type = -1; >+ >+ // SSRC of FlexFEC stream. >+ uint32_t ssrc = 0; >+ >+ // Vector containing a single element, corresponding to the SSRC of the >+ // media stream being protected by this FlexFEC stream. >+ // The vector MUST have size 1. >+ // >+ // TODO(brandtr): Update comment above when we support >+ // multistream protection. >+ std::vector<uint32_t> protected_media_ssrcs; >+ } flexfec; >+ >+ // Settings for RTP retransmission payload format, see RFC 4588 for >+ // details. >+ struct Rtx { >+ Rtx(); >+ Rtx(const Rtx&); >+ ~Rtx(); >+ std::string ToString() const; >+ // SSRCs to use for the RTX streams. >+ std::vector<uint32_t> ssrcs; >+ >+ // Payload type to use for the RTX stream. >+ int payload_type = -1; >+ } rtx; >+ >+ // RTCP CNAME, see RFC 3550. >+ std::string c_name; >+}; >+ >+struct RtcpConfig { >+ RtcpConfig(); >+ RtcpConfig(const RtcpConfig&); >+ ~RtcpConfig(); >+ std::string ToString() const; >+ >+ // Time interval between RTCP report for video >+ int64_t video_report_interval_ms = 1000; >+ // Time interval between RTCP report for audio >+ int64_t audio_report_interval_ms = 5000; >+}; > } // namespace webrtc > #endif // CALL_RTP_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.cc >index 6a9cae8f77a..8f0e2e529d2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.cc >@@ -38,8 +38,8 @@ bool RtpDemuxer::AddSink(const RtpDemuxerCriteria& criteria, > RtpPacketSinkInterface* sink) { > RTC_DCHECK(!criteria.payload_types.empty() || !criteria.ssrcs.empty() || > !criteria.mid.empty() || !criteria.rsid.empty()); >- RTC_DCHECK(criteria.mid.empty() || Mid::IsLegalName(criteria.mid)); >- RTC_DCHECK(criteria.rsid.empty() || StreamId::IsLegalName(criteria.rsid)); >+ RTC_DCHECK(criteria.mid.empty() || Mid::IsLegalMidName(criteria.mid)); >+ RTC_DCHECK(criteria.rsid.empty() || StreamId::IsLegalRsidName(criteria.rsid)); > RTC_DCHECK(sink); > > // We return false instead of DCHECKing for logical conflicts with the new >@@ -168,7 +168,7 @@ RtpPacketSinkInterface* RtpDemuxer::ResolveSink( > // RSID and RRID are routed to the same sinks. If an RSID is specified on a > // repair packet, it should be ignored and the RRID should be used. > std::string packet_mid, packet_rsid; >- bool has_mid = packet.GetExtension<RtpMid>(&packet_mid); >+ bool has_mid = use_mid_ && packet.GetExtension<RtpMid>(&packet_mid); > bool has_rsid = packet.GetExtension<RepairedRtpStreamId>(&packet_rsid); > if (!has_rsid) { > has_rsid = packet.GetExtension<RtpStreamId>(&packet_rsid); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.h >index 971c1516480..0a8acc27bb6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer.h >@@ -137,6 +137,10 @@ class RtpDemuxer { > // Deprecated: Use the above method. > void DeregisterRsidResolutionObserver(const SsrcBindingObserver* observer); > >+ // Configure whether to look at the MID header extension when demuxing >+ // incoming RTP packets. By default this is enabled. >+ void set_use_mid(bool use_mid) { use_mid_ = use_mid; } >+ > private: > // Returns true if adding a sink with the given criteria would cause conflicts > // with the existing criteria and should be rejected. >@@ -197,6 +201,8 @@ class RtpDemuxer { > // Observers which will be notified when an RSID association to an SSRC is > // resolved by this object. > std::vector<SsrcBindingObserver*> ssrc_binding_observers_; >+ >+ bool use_mid_ = true; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer_unittest.cc >index ef092ee98f4..b5ede3cd03a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_demuxer_unittest.cc >@@ -14,6 +14,7 @@ > #include <set> > #include <string> > >+#include "absl/memory/memory.h" > #include "call/ssrc_binding_observer.h" > #include "call/test/mock_rtp_packet_sink_interface.h" > #include "common_types.h" // NOLINT(build/include) >@@ -21,10 +22,8 @@ > #include "modules/rtp_rtcp/source/rtp_header_extensions.h" > #include "modules/rtp_rtcp/source/rtp_packet_received.h" > #include "rtc_base/arraysize.h" >-#include "rtc_base/basictypes.h" > #include "rtc_base/checks.h" > #include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" > #include "test/gmock.h" > #include "test/gtest.h" > >@@ -136,7 +135,7 @@ class RtpDemuxerTest : public testing::Test { > std::unique_ptr<RtpPacketReceived> CreatePacket( > uint32_t ssrc, > RtpPacketReceived::ExtensionManager* extension_manager) { >- auto packet = rtc::MakeUnique<RtpPacketReceived>(extension_manager); >+ auto packet = absl::make_unique<RtpPacketReceived>(extension_manager); > packet->SetSsrc(ssrc); > packet->SetSequenceNumber(next_sequence_number_++); > return packet; >@@ -347,8 +346,8 @@ TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByRsid) { > } > > for (size_t i = 0; i < arraysize(rsids); i++) { >- auto packet = CreatePacketWithSsrcRsid(rtc::checked_cast<uint32_t>(i), >- rsids[i]); >+ auto packet = >+ CreatePacketWithSsrcRsid(rtc::checked_cast<uint32_t>(i), rsids[i]); > EXPECT_CALL(sinks[i], OnRtpPacket(SamePacketAs(*packet))).Times(1); > EXPECT_TRUE(demuxer_.OnRtpPacket(*packet)); > } >@@ -362,8 +361,8 @@ TEST_F(RtpDemuxerTest, OnRtpPacketCalledOnCorrectSinkByMid) { > } > > for (size_t i = 0; i < arraysize(mids); i++) { >- auto packet = CreatePacketWithSsrcMid(rtc::checked_cast<uint32_t>(i), >- mids[i]); >+ auto packet = >+ CreatePacketWithSsrcMid(rtc::checked_cast<uint32_t>(i), mids[i]); > EXPECT_CALL(sinks[i], OnRtpPacket(SamePacketAs(*packet))).Times(1); > EXPECT_TRUE(demuxer_.OnRtpPacket(*packet)); > } >@@ -1492,9 +1491,9 @@ TEST_F(RtpDemuxerTest, RsidMustBeAlphaNumeric) { > EXPECT_DEATH(AddSinkOnlyRsid("a_3", &sink), ""); > } > >-TEST_F(RtpDemuxerTest, MidMustBeAlphaNumeric) { >+TEST_F(RtpDemuxerTest, MidMustBeToken) { > MockRtpPacketSink sink; >- EXPECT_DEATH(AddSinkOnlyMid("a_3", &sink), ""); >+ EXPECT_DEATH(AddSinkOnlyMid("a(3)", &sink), ""); > } > > TEST_F(RtpDemuxerTest, RsidMustNotExceedMaximumLength) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.cc >new file mode 100644 >index 00000000000..d61d40fc8bb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.cc >@@ -0,0 +1,183 @@ >+/* >+ * Copyright (c) 2018 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 "call/rtp_payload_params.h" >+ >+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/random.h" >+#include "rtc_base/timeutils.h" >+ >+namespace webrtc { >+ >+namespace { >+void PopulateRtpWithCodecSpecifics(const CodecSpecificInfo& info, >+ RTPVideoHeader* rtp) { >+ rtp->codec = info.codecType; >+ switch (info.codecType) { >+ case kVideoCodecVP8: { >+ rtp->vp8().InitRTPVideoHeaderVP8(); >+ rtp->vp8().nonReference = info.codecSpecific.VP8.nonReference; >+ rtp->vp8().temporalIdx = info.codecSpecific.VP8.temporalIdx; >+ rtp->vp8().layerSync = info.codecSpecific.VP8.layerSync; >+ rtp->vp8().keyIdx = info.codecSpecific.VP8.keyIdx; >+ rtp->simulcastIdx = info.codecSpecific.VP8.simulcastIdx; >+ return; >+ } >+ case kVideoCodecVP9: { >+ auto& vp9_header = rtp->video_type_header.emplace<RTPVideoHeaderVP9>(); >+ vp9_header.InitRTPVideoHeaderVP9(); >+ vp9_header.inter_pic_predicted = >+ info.codecSpecific.VP9.inter_pic_predicted; >+ vp9_header.flexible_mode = info.codecSpecific.VP9.flexible_mode; >+ vp9_header.ss_data_available = info.codecSpecific.VP9.ss_data_available; >+ vp9_header.non_ref_for_inter_layer_pred = >+ info.codecSpecific.VP9.non_ref_for_inter_layer_pred; >+ vp9_header.temporal_idx = info.codecSpecific.VP9.temporal_idx; >+ vp9_header.spatial_idx = info.codecSpecific.VP9.spatial_idx; >+ vp9_header.temporal_up_switch = info.codecSpecific.VP9.temporal_up_switch; >+ vp9_header.inter_layer_predicted = >+ info.codecSpecific.VP9.inter_layer_predicted; >+ vp9_header.gof_idx = info.codecSpecific.VP9.gof_idx; >+ vp9_header.num_spatial_layers = info.codecSpecific.VP9.num_spatial_layers; >+ >+ if (info.codecSpecific.VP9.ss_data_available) { >+ vp9_header.spatial_layer_resolution_present = >+ info.codecSpecific.VP9.spatial_layer_resolution_present; >+ if (info.codecSpecific.VP9.spatial_layer_resolution_present) { >+ for (size_t i = 0; i < info.codecSpecific.VP9.num_spatial_layers; >+ ++i) { >+ vp9_header.width[i] = info.codecSpecific.VP9.width[i]; >+ vp9_header.height[i] = info.codecSpecific.VP9.height[i]; >+ } >+ } >+ vp9_header.gof.CopyGofInfoVP9(info.codecSpecific.VP9.gof); >+ } >+ >+ vp9_header.num_ref_pics = info.codecSpecific.VP9.num_ref_pics; >+ for (int i = 0; i < info.codecSpecific.VP9.num_ref_pics; ++i) { >+ vp9_header.pid_diff[i] = info.codecSpecific.VP9.p_diff[i]; >+ } >+ vp9_header.end_of_picture = info.codecSpecific.VP9.end_of_picture; >+ return; >+ } >+ case kVideoCodecH264: { >+ auto& h264_header = rtp->video_type_header.emplace<RTPVideoHeaderH264>(); >+ h264_header.packetization_mode = >+ info.codecSpecific.H264.packetization_mode; >+ rtp->simulcastIdx = info.codecSpecific.H264.simulcast_idx; >+ return; >+ } >+ case kVideoCodecMultiplex: >+ case kVideoCodecGeneric: >+ rtp->codec = kVideoCodecGeneric; >+ rtp->simulcastIdx = info.codecSpecific.generic.simulcast_idx; >+ return; >+ default: >+ return; >+ } >+} >+ >+void SetVideoTiming(const EncodedImage& image, VideoSendTiming* timing) { >+ if (image.timing_.flags == VideoSendTiming::TimingFrameFlags::kInvalid || >+ image.timing_.flags == VideoSendTiming::TimingFrameFlags::kNotTriggered) { >+ timing->flags = VideoSendTiming::TimingFrameFlags::kInvalid; >+ return; >+ } >+ >+ timing->encode_start_delta_ms = VideoSendTiming::GetDeltaCappedMs( >+ image.capture_time_ms_, image.timing_.encode_start_ms); >+ timing->encode_finish_delta_ms = VideoSendTiming::GetDeltaCappedMs( >+ image.capture_time_ms_, image.timing_.encode_finish_ms); >+ timing->packetization_finish_delta_ms = 0; >+ timing->pacer_exit_delta_ms = 0; >+ timing->network_timestamp_delta_ms = 0; >+ timing->network2_timestamp_delta_ms = 0; >+ timing->flags = image.timing_.flags; >+} >+} // namespace >+ >+RtpPayloadParams::RtpPayloadParams(const uint32_t ssrc, >+ const RtpPayloadState* state) >+ : ssrc_(ssrc) { >+ Random random(rtc::TimeMicros()); >+ state_.picture_id = >+ state ? state->picture_id : (random.Rand<int16_t>() & 0x7FFF); >+ state_.tl0_pic_idx = state ? state->tl0_pic_idx : (random.Rand<uint8_t>()); >+} >+RtpPayloadParams::~RtpPayloadParams() {} >+ >+RTPVideoHeader RtpPayloadParams::GetRtpVideoHeader( >+ const EncodedImage& image, >+ const CodecSpecificInfo* codec_specific_info) { >+ RTPVideoHeader rtp_video_header; >+ if (codec_specific_info) { >+ PopulateRtpWithCodecSpecifics(*codec_specific_info, &rtp_video_header); >+ } >+ rtp_video_header.rotation = image.rotation_; >+ rtp_video_header.content_type = image.content_type_; >+ rtp_video_header.playout_delay = image.playout_delay_; >+ >+ SetVideoTiming(image, &rtp_video_header.video_timing); >+ >+ // Sets picture id and tl0 pic idx. >+ const bool first_frame_in_picture = >+ (codec_specific_info && codec_specific_info->codecType == kVideoCodecVP9) >+ ? codec_specific_info->codecSpecific.VP9.first_frame_in_picture >+ : true; >+ Set(&rtp_video_header, first_frame_in_picture); >+ return rtp_video_header; >+} >+ >+uint32_t RtpPayloadParams::ssrc() const { >+ return ssrc_; >+} >+ >+RtpPayloadState RtpPayloadParams::state() const { >+ return state_; >+} >+ >+void RtpPayloadParams::Set(RTPVideoHeader* rtp_video_header, >+ bool first_frame_in_picture) { >+ // Always set picture id. Set tl0_pic_idx iff temporal index is set. >+ if (first_frame_in_picture) { >+ state_.picture_id = (static_cast<uint16_t>(state_.picture_id) + 1) & 0x7FFF; >+ } >+ if (rtp_video_header->codec == kVideoCodecVP8) { >+ rtp_video_header->vp8().pictureId = state_.picture_id; >+ >+ if (rtp_video_header->vp8().temporalIdx != kNoTemporalIdx) { >+ if (rtp_video_header->vp8().temporalIdx == 0) { >+ ++state_.tl0_pic_idx; >+ } >+ rtp_video_header->vp8().tl0PicIdx = state_.tl0_pic_idx; >+ } >+ } >+ if (rtp_video_header->codec == kVideoCodecVP9) { >+ auto& vp9_header = >+ absl::get<RTPVideoHeaderVP9>(rtp_video_header->video_type_header); >+ vp9_header.picture_id = state_.picture_id; >+ >+ // Note that in the case that we have no temporal layers but we do have >+ // spatial layers, packets will carry layering info with a temporal_idx of >+ // zero, and we then have to set and increment tl0_pic_idx. >+ if (vp9_header.temporal_idx != kNoTemporalIdx || >+ vp9_header.spatial_idx != kNoSpatialIdx) { >+ if (first_frame_in_picture && >+ (vp9_header.temporal_idx == 0 || >+ vp9_header.temporal_idx == kNoTemporalIdx)) { >+ ++state_.tl0_pic_idx; >+ } >+ vp9_header.tl0_pic_idx = state_.tl0_pic_idx; >+ } >+ } >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.h >new file mode 100644 >index 00000000000..0c71a7b5f55 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params.h >@@ -0,0 +1,49 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef CALL_RTP_PAYLOAD_PARAMS_H_ >+#define CALL_RTP_PAYLOAD_PARAMS_H_ >+ >+#include <map> >+#include <vector> >+ >+#include "api/video_codecs/video_encoder.h" >+#include "call/rtp_config.h" >+#include "common_types.h" // NOLINT(build/include) >+#include "modules/rtp_rtcp/source/rtp_video_header.h" >+ >+namespace webrtc { >+ >+class RTPFragmentationHeader; >+class RtpRtcp; >+ >+// State for setting picture id and tl0 pic idx, for VP8 and VP9 >+// TODO(nisse): Make these properties not codec specific. >+class RtpPayloadParams final { >+ public: >+ RtpPayloadParams(const uint32_t ssrc, const RtpPayloadState* state); >+ ~RtpPayloadParams(); >+ >+ RTPVideoHeader GetRtpVideoHeader( >+ const EncodedImage& image, >+ const CodecSpecificInfo* codec_specific_info); >+ >+ uint32_t ssrc() const; >+ >+ RtpPayloadState state() const; >+ >+ private: >+ void Set(RTPVideoHeader* rtp_video_header, bool first_frame_in_picture); >+ >+ const uint32_t ssrc_; >+ RtpPayloadState state_; >+}; >+} // namespace webrtc >+#endif // CALL_RTP_PAYLOAD_PARAMS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params_unittest.cc >new file mode 100644 >index 00000000000..b2339cd3b52 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_payload_params_unittest.cc >@@ -0,0 +1,256 @@ >+/* >+ * Copyright (c) 2018 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 <memory> >+ >+#include "call/rtp_payload_params.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+namespace { >+const uint32_t kSsrc1 = 12345; >+const uint32_t kSsrc2 = 23456; >+const int16_t kPictureId = 123; >+const int16_t kTl0PicIdx = 20; >+const uint8_t kTemporalIdx = 1; >+const int16_t kInitialPictureId1 = 222; >+const int16_t kInitialTl0PicIdx1 = 99; >+} // namespace >+ >+TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp8) { >+ RtpPayloadState state2; >+ state2.picture_id = kPictureId; >+ state2.tl0_pic_idx = kTl0PicIdx; >+ std::map<uint32_t, RtpPayloadState> states = {{kSsrc2, state2}}; >+ >+ RtpPayloadParams params(kSsrc2, &state2); >+ EncodedImage encoded_image; >+ encoded_image.rotation_ = kVideoRotation_90; >+ encoded_image.content_type_ = VideoContentType::SCREENSHARE; >+ >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP8; >+ codec_info.codecSpecific.VP8.simulcastIdx = 1; >+ codec_info.codecSpecific.VP8.temporalIdx = kTemporalIdx; >+ codec_info.codecSpecific.VP8.keyIdx = kNoKeyIdx; >+ codec_info.codecSpecific.VP8.layerSync = true; >+ codec_info.codecSpecific.VP8.nonReference = true; >+ >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoRotation_90, header.rotation); >+ EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type); >+ EXPECT_EQ(1, header.simulcastIdx); >+ EXPECT_EQ(kVideoCodecVP8, header.codec); >+ EXPECT_EQ(kPictureId + 1, header.vp8().pictureId); >+ EXPECT_EQ(kTemporalIdx, header.vp8().temporalIdx); >+ EXPECT_EQ(kTl0PicIdx, header.vp8().tl0PicIdx); >+ EXPECT_EQ(kNoKeyIdx, header.vp8().keyIdx); >+ EXPECT_TRUE(header.vp8().layerSync); >+ EXPECT_TRUE(header.vp8().nonReference); >+} >+ >+TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_Vp9) { >+ RtpPayloadState state; >+ state.picture_id = kPictureId; >+ state.tl0_pic_idx = kTl0PicIdx; >+ RtpPayloadParams params(kSsrc1, &state); >+ >+ EncodedImage encoded_image; >+ encoded_image.rotation_ = kVideoRotation_90; >+ encoded_image.content_type_ = VideoContentType::SCREENSHARE; >+ >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP9; >+ codec_info.codecSpecific.VP9.num_spatial_layers = 3; >+ codec_info.codecSpecific.VP9.first_frame_in_picture = true; >+ codec_info.codecSpecific.VP9.spatial_idx = 0; >+ codec_info.codecSpecific.VP9.temporal_idx = 2; >+ codec_info.codecSpecific.VP9.end_of_picture = false; >+ >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoRotation_90, header.rotation); >+ EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type); >+ EXPECT_EQ(kVideoCodecVP9, header.codec); >+ const auto& vp9_header = >+ absl::get<RTPVideoHeaderVP9>(header.video_type_header); >+ EXPECT_EQ(kPictureId + 1, vp9_header.picture_id); >+ EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx); >+ EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx); >+ EXPECT_EQ(vp9_header.spatial_idx, codec_info.codecSpecific.VP9.spatial_idx); >+ EXPECT_EQ(vp9_header.num_spatial_layers, >+ codec_info.codecSpecific.VP9.num_spatial_layers); >+ EXPECT_EQ(vp9_header.end_of_picture, >+ codec_info.codecSpecific.VP9.end_of_picture); >+ >+ // Next spatial layer. >+ codec_info.codecSpecific.VP9.first_frame_in_picture = false; >+ codec_info.codecSpecific.VP9.spatial_idx += 1; >+ codec_info.codecSpecific.VP9.end_of_picture = true; >+ >+ header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoRotation_90, header.rotation); >+ EXPECT_EQ(VideoContentType::SCREENSHARE, header.content_type); >+ EXPECT_EQ(kVideoCodecVP9, header.codec); >+ EXPECT_EQ(kPictureId + 1, vp9_header.picture_id); >+ EXPECT_EQ(kTl0PicIdx, vp9_header.tl0_pic_idx); >+ EXPECT_EQ(vp9_header.temporal_idx, codec_info.codecSpecific.VP9.temporal_idx); >+ EXPECT_EQ(vp9_header.spatial_idx, codec_info.codecSpecific.VP9.spatial_idx); >+ EXPECT_EQ(vp9_header.num_spatial_layers, >+ codec_info.codecSpecific.VP9.num_spatial_layers); >+ EXPECT_EQ(vp9_header.end_of_picture, >+ codec_info.codecSpecific.VP9.end_of_picture); >+} >+ >+TEST(RtpPayloadParamsTest, InfoMappedToRtpVideoHeader_H264) { >+ RtpPayloadParams params(kSsrc1, {}); >+ >+ EncodedImage encoded_image; >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecH264; >+ codec_info.codecSpecific.H264.packetization_mode = >+ H264PacketizationMode::SingleNalUnit; >+ >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(0, header.simulcastIdx); >+ EXPECT_EQ(kVideoCodecH264, header.codec); >+ const auto& h264 = absl::get<RTPVideoHeaderH264>(header.video_type_header); >+ EXPECT_EQ(H264PacketizationMode::SingleNalUnit, h264.packetization_mode); >+} >+ >+TEST(RtpPayloadParamsTest, PictureIdIsSetForVp8) { >+ RtpPayloadState state; >+ state.picture_id = kInitialPictureId1; >+ state.tl0_pic_idx = kInitialTl0PicIdx1; >+ >+ EncodedImage encoded_image; >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP8; >+ codec_info.codecSpecific.VP8.simulcastIdx = 0; >+ >+ RtpPayloadParams params(kSsrc1, &state); >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ EXPECT_EQ(kVideoCodecVP8, header.codec); >+ EXPECT_EQ(kInitialPictureId1 + 1, header.vp8().pictureId); >+ >+ // State should hold latest used picture id and tl0_pic_idx. >+ state = params.state(); >+ EXPECT_EQ(kInitialPictureId1 + 1, state.picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, state.tl0_pic_idx); >+} >+ >+TEST(RtpPayloadParamsTest, PictureIdWraps) { >+ RtpPayloadState state; >+ state.picture_id = kMaxTwoBytePictureId; >+ state.tl0_pic_idx = kInitialTl0PicIdx1; >+ >+ EncodedImage encoded_image; >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP8; >+ codec_info.codecSpecific.VP8.temporalIdx = kNoTemporalIdx; >+ >+ RtpPayloadParams params(kSsrc1, &state); >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ EXPECT_EQ(kVideoCodecVP8, header.codec); >+ EXPECT_EQ(0, header.vp8().pictureId); >+ >+ // State should hold latest used picture id and tl0_pic_idx. >+ EXPECT_EQ(0, params.state().picture_id); // Wrapped. >+ EXPECT_EQ(kInitialTl0PicIdx1, params.state().tl0_pic_idx); >+} >+ >+TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp8) { >+ RtpPayloadState state; >+ state.picture_id = kInitialPictureId1; >+ state.tl0_pic_idx = kInitialTl0PicIdx1; >+ >+ EncodedImage encoded_image; >+ // Modules are sending for this test. >+ // OnEncodedImage, temporalIdx: 1. >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP8; >+ codec_info.codecSpecific.VP8.temporalIdx = 1; >+ >+ RtpPayloadParams params(kSsrc1, &state); >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoCodecVP8, header.codec); >+ EXPECT_EQ(kInitialPictureId1 + 1, header.vp8().pictureId); >+ EXPECT_EQ(kInitialTl0PicIdx1, header.vp8().tl0PicIdx); >+ >+ // OnEncodedImage, temporalIdx: 0. >+ codec_info.codecSpecific.VP8.temporalIdx = 0; >+ >+ header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ EXPECT_EQ(kVideoCodecVP8, header.codec); >+ EXPECT_EQ(kInitialPictureId1 + 2, header.vp8().pictureId); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, header.vp8().tl0PicIdx); >+ >+ // State should hold latest used picture id and tl0_pic_idx. >+ EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx); >+} >+ >+TEST(RtpPayloadParamsTest, Tl0PicIdxUpdatedForVp9) { >+ RtpPayloadState state; >+ state.picture_id = kInitialPictureId1; >+ state.tl0_pic_idx = kInitialTl0PicIdx1; >+ >+ EncodedImage encoded_image; >+ // Modules are sending for this test. >+ // OnEncodedImage, temporalIdx: 1. >+ CodecSpecificInfo codec_info; >+ memset(&codec_info, 0, sizeof(CodecSpecificInfo)); >+ codec_info.codecType = kVideoCodecVP9; >+ codec_info.codecSpecific.VP9.temporal_idx = 1; >+ codec_info.codecSpecific.VP9.first_frame_in_picture = true; >+ >+ RtpPayloadParams params(kSsrc1, &state); >+ RTPVideoHeader header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoCodecVP9, header.codec); >+ const auto& vp9_header = >+ absl::get<RTPVideoHeaderVP9>(header.video_type_header); >+ EXPECT_EQ(kInitialPictureId1 + 1, vp9_header.picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1, vp9_header.tl0_pic_idx); >+ >+ // OnEncodedImage, temporalIdx: 0. >+ codec_info.codecSpecific.VP9.temporal_idx = 0; >+ >+ header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoCodecVP9, header.codec); >+ EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx); >+ >+ // OnEncodedImage, first_frame_in_picture = false >+ codec_info.codecSpecific.VP9.first_frame_in_picture = false; >+ >+ header = params.GetRtpVideoHeader(encoded_image, &codec_info); >+ >+ EXPECT_EQ(kVideoCodecVP9, header.codec); >+ EXPECT_EQ(kInitialPictureId1 + 2, vp9_header.picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, vp9_header.tl0_pic_idx); >+ >+ // State should hold latest used picture id and tl0_pic_idx. >+ EXPECT_EQ(kInitialPictureId1 + 2, params.state().picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1 + 1, params.state().tl0_pic_idx); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.cc >index deabe738424..125169b0772 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.cc >@@ -21,13 +21,13 @@ > > namespace webrtc { > >-rtc::Optional<uint32_t> ParseRtcpPacketSenderSsrc( >+absl::optional<uint32_t> ParseRtcpPacketSenderSsrc( > rtc::ArrayView<const uint8_t> packet) { > rtcp::CommonHeader header; > for (const uint8_t* next_packet = packet.begin(); next_packet < packet.end(); > next_packet = header.NextPacket()) { > if (!header.Parse(next_packet, packet.end() - next_packet)) { >- return rtc::nullopt; >+ return absl::nullopt; > } > > switch (header.type()) { >@@ -43,13 +43,13 @@ rtc::Optional<uint32_t> ParseRtcpPacketSenderSsrc( > ByteReader<uint32_t>::ReadBigEndian(header.payload()); > return ssrc_sender; > } else { >- return rtc::nullopt; >+ return absl::nullopt; > } > } > } > } > >- return rtc::nullopt; >+ return absl::nullopt; > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.h >index 32408e8a7a0..4b66713538e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper.h >@@ -15,9 +15,8 @@ > #include <map> > #include <utility> > >+#include "absl/types/optional.h" > #include "api/array_view.h" >-#include "api/optional.h" >-#include "rtc_base/basictypes.h" > > namespace webrtc { > >@@ -90,7 +89,7 @@ bool MultimapHasKey(const Container& c, > return it_range.first != it_range.second; > } > >-rtc::Optional<uint32_t> ParseRtcpPacketSenderSsrc( >+absl::optional<uint32_t> ParseRtcpPacketSenderSsrc( > rtc::ArrayView<const uint8_t> packet); > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper_unittest.cc >index cb8a092616a..9f378864a13 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_rtcp_demuxer_helper_unittest.cc >@@ -20,7 +20,6 @@ > #include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" > #include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" > #include "rtc_base/arraysize.h" >-#include "rtc_base/basictypes.h" > #include "rtc_base/buffer.h" > #include "test/gtest.h" > >@@ -35,7 +34,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_ByePacket) { > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -45,7 +44,7 @@ TEST(RtpRtcpDemuxerHelperTest, > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -54,7 +53,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_PsfbPacket) { > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -63,7 +62,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_ReceiverReportPacket) { > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -73,7 +72,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_RtpfbPacket) { > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -82,7 +81,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_SenderReportPacket) { > rtcp_packet.SetSenderSsrc(kSsrc); > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_EQ(ssrc, kSsrc); > } > >@@ -90,7 +89,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_MalformedRtcpPacket) { > uint8_t garbage[100]; > memset(&garbage[0], 0, arraysize(garbage)); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(garbage); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(garbage); > EXPECT_FALSE(ssrc); > } > >@@ -99,7 +98,7 @@ TEST(RtpRtcpDemuxerHelperTest, > webrtc::rtcp::ExtendedJitterReport rtcp_packet; // Has no sender SSRC. > rtc::Buffer raw_packet = rtcp_packet.Build(); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc(raw_packet); > EXPECT_FALSE(ssrc); > } > >@@ -111,7 +110,7 @@ TEST(RtpRtcpDemuxerHelperTest, ParseRtcpPacketSenderSsrc_TruncatedRtcpMessage) { > constexpr size_t rtcp_length_bytes = 8; > ASSERT_EQ(rtcp_length_bytes, raw_packet.size()); > >- rtc::Optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc( >+ absl::optional<uint32_t> ssrc = ParseRtcpPacketSenderSsrc( > rtc::ArrayView<const uint8_t>(raw_packet.data(), rtcp_length_bytes - 1)); > EXPECT_FALSE(ssrc); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_stream_receiver_controller.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_stream_receiver_controller.cc >index a5d73f5784f..3fae021188b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_stream_receiver_controller.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_stream_receiver_controller.cc >@@ -10,8 +10,8 @@ > > #include "call/rtp_stream_receiver_controller.h" > >+#include "absl/memory/memory.h" > #include "rtc_base/logging.h" >-#include "rtc_base/ptr_util.h" > > namespace webrtc { > >@@ -35,14 +35,18 @@ RtpStreamReceiverController::Receiver::~Receiver() { > controller_->RemoveSink(sink_); > } > >-RtpStreamReceiverController::RtpStreamReceiverController() = default; >+RtpStreamReceiverController::RtpStreamReceiverController() { >+ // At this level the demuxer is only configured to demux by SSRC, so don't >+ // worry about MIDs (MIDs are handled by upper layers). >+ demuxer_.set_use_mid(false); >+} >+ > RtpStreamReceiverController::~RtpStreamReceiverController() = default; > > std::unique_ptr<RtpStreamReceiverInterface> >-RtpStreamReceiverController::CreateReceiver( >- uint32_t ssrc, >- RtpPacketSinkInterface* sink) { >- return rtc::MakeUnique<Receiver>(this, ssrc, sink); >+RtpStreamReceiverController::CreateReceiver(uint32_t ssrc, >+ RtpPacketSinkInterface* sink) { >+ return absl::make_unique<Receiver>(this, ssrc, sink); > } > > bool RtpStreamReceiverController::OnRtpPacket(const RtpPacketReceived& packet) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.cc >index 090c261e4e5..b0dd8d8e295 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.cc >@@ -7,32 +7,159 @@ > * in the file PATENTS. All contributing project authors may > * be found in the AUTHORS file in the root of the source tree. > */ >+#include <utility> >+#include <vector> > >+#include "absl/memory/memory.h" > #include "call/rtp_transport_controller_send.h" >+#include "modules/congestion_controller/include/send_side_congestion_controller.h" >+#include "modules/congestion_controller/rtp/include/send_side_congestion_controller.h" >+#include "rtc_base/location.h" >+#include "rtc_base/logging.h" >+#include "rtc_base/rate_limiter.h" >+#include "system_wrappers/include/field_trial.h" > > namespace webrtc { >+namespace { >+static const int64_t kRetransmitWindowSizeMs = 500; >+const char kTaskQueueExperiment[] = "WebRTC-TaskQueueCongestionControl"; >+using TaskQueueController = webrtc::webrtc_cc::SendSideCongestionController; >+ >+bool TaskQueueExperimentEnabled() { >+ std::string trial = webrtc::field_trial::FindFullName(kTaskQueueExperiment); >+ return trial.find("Enable") == 0; >+} >+ >+std::unique_ptr<SendSideCongestionControllerInterface> CreateController( >+ Clock* clock, >+ rtc::TaskQueue* task_queue, >+ webrtc::RtcEventLog* event_log, >+ PacedSender* pacer, >+ const BitrateConstraints& bitrate_config, >+ bool task_queue_controller, >+ NetworkControllerFactoryInterface* controller_factory) { >+ if (task_queue_controller) { >+ RTC_LOG(LS_INFO) << "Using TaskQueue based SSCC"; >+ return absl::make_unique<webrtc::webrtc_cc::SendSideCongestionController>( >+ clock, task_queue, event_log, pacer, bitrate_config.start_bitrate_bps, >+ bitrate_config.min_bitrate_bps, bitrate_config.max_bitrate_bps, >+ controller_factory); >+ } >+ RTC_LOG(LS_INFO) << "Using Legacy SSCC"; >+ auto cc = absl::make_unique<webrtc::SendSideCongestionController>( >+ clock, nullptr /* observer */, event_log, pacer); >+ cc->SignalNetworkState(kNetworkDown); >+ cc->SetBweBitrates(bitrate_config.min_bitrate_bps, >+ bitrate_config.start_bitrate_bps, >+ bitrate_config.max_bitrate_bps); >+ return std::move(cc); >+} >+} // namespace > > RtpTransportControllerSend::RtpTransportControllerSend( > Clock* clock, >- webrtc::RtcEventLog* event_log) >- : pacer_(clock, &packet_router_, event_log), >- send_side_cc_(clock, nullptr /* observer */, event_log, &pacer_) {} >+ webrtc::RtcEventLog* event_log, >+ NetworkControllerFactoryInterface* controller_factory, >+ const BitrateConstraints& bitrate_config) >+ : clock_(clock), >+ pacer_(clock, &packet_router_, event_log), >+ bitrate_configurator_(bitrate_config), >+ process_thread_(ProcessThread::Create("SendControllerThread")), >+ observer_(nullptr), >+ retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs), >+ task_queue_("rtp_send_controller") { >+ // Created after task_queue to be able to post to the task queue internally. >+ send_side_cc_ = >+ CreateController(clock, &task_queue_, event_log, &pacer_, bitrate_config, >+ TaskQueueExperimentEnabled(), controller_factory); > >-PacketRouter* RtpTransportControllerSend::packet_router() { >- return &packet_router_; >+ process_thread_->RegisterModule(&pacer_, RTC_FROM_HERE); >+ process_thread_->RegisterModule(send_side_cc_.get(), RTC_FROM_HERE); >+ process_thread_->Start(); > } > >-PacedSender* RtpTransportControllerSend::pacer() { >- return &pacer_; >+RtpTransportControllerSend::~RtpTransportControllerSend() { >+ process_thread_->Stop(); >+ process_thread_->DeRegisterModule(send_side_cc_.get()); >+ process_thread_->DeRegisterModule(&pacer_); > } > >-SendSideCongestionController* RtpTransportControllerSend::send_side_cc() { >- return &send_side_cc_; >+RtpVideoSenderInterface* RtpTransportControllerSend::CreateRtpVideoSender( >+ const std::vector<uint32_t>& ssrcs, >+ std::map<uint32_t, RtpState> suspended_ssrcs, >+ const std::map<uint32_t, RtpPayloadState>& states, >+ const RtpConfig& rtp_config, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ const RtpSenderObservers& observers, >+ RtcEventLog* event_log) { >+ video_rtp_senders_.push_back(absl::make_unique<RtpVideoSender>( >+ ssrcs, suspended_ssrcs, states, rtp_config, rtcp_config, send_transport, >+ observers, >+ // TODO(holmer): Remove this circular dependency by injecting >+ // the parts of RtpTransportControllerSendInterface that are really used. >+ this, event_log, &retransmission_rate_limiter_)); >+ return video_rtp_senders_.back().get(); >+} >+ >+void RtpTransportControllerSend::DestroyRtpVideoSender( >+ RtpVideoSenderInterface* rtp_video_sender) { >+ std::vector<std::unique_ptr<RtpVideoSenderInterface>>::iterator it = >+ video_rtp_senders_.end(); >+ for (it = video_rtp_senders_.begin(); it != video_rtp_senders_.end(); ++it) { >+ if (it->get() == rtp_video_sender) { >+ break; >+ } >+ } >+ RTC_DCHECK(it != video_rtp_senders_.end()); >+ video_rtp_senders_.erase(it); >+} >+ >+void RtpTransportControllerSend::OnNetworkChanged(uint32_t bitrate_bps, >+ uint8_t fraction_loss, >+ int64_t rtt_ms, >+ int64_t probing_interval_ms) { >+ // TODO(srte): Skip this step when old SendSideCongestionController is >+ // deprecated. >+ TargetTransferRate msg; >+ msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds()); >+ msg.target_rate = DataRate::bps(bitrate_bps); >+ msg.network_estimate.at_time = msg.at_time; >+ msg.network_estimate.bwe_period = TimeDelta::ms(probing_interval_ms); >+ uint32_t bandwidth_bps; >+ if (send_side_cc_->AvailableBandwidth(&bandwidth_bps)) >+ msg.network_estimate.bandwidth = DataRate::bps(bandwidth_bps); >+ msg.network_estimate.loss_rate_ratio = fraction_loss / 255.0; >+ msg.network_estimate.round_trip_time = TimeDelta::ms(rtt_ms); >+ >+ retransmission_rate_limiter_.SetMaxRate(bandwidth_bps); >+ >+ if (!task_queue_.IsCurrent()) { >+ task_queue_.PostTask([this, msg] { >+ rtc::CritScope cs(&observer_crit_); >+ // We won't register as observer until we have an observers. >+ RTC_DCHECK(observer_ != nullptr); >+ observer_->OnTargetTransferRate(msg); >+ }); >+ } else { >+ rtc::CritScope cs(&observer_crit_); >+ // We won't register as observer until we have an observers. >+ RTC_DCHECK(observer_ != nullptr); >+ observer_->OnTargetTransferRate(msg); >+ } >+} >+ >+rtc::TaskQueue* RtpTransportControllerSend::GetWorkerQueue() { >+ return &task_queue_; >+} >+ >+PacketRouter* RtpTransportControllerSend::packet_router() { >+ return &packet_router_; > } > > TransportFeedbackObserver* > RtpTransportControllerSend::transport_feedback_observer() { >- return &send_side_cc_; >+ return send_side_cc_.get(); > } > > RtpPacketSender* RtpTransportControllerSend::packet_sender() { >@@ -45,13 +172,141 @@ const RtpKeepAliveConfig& RtpTransportControllerSend::keepalive_config() const { > > void RtpTransportControllerSend::SetAllocatedSendBitrateLimits( > int min_send_bitrate_bps, >- int max_padding_bitrate_bps) { >- pacer_.SetSendBitrateLimits(min_send_bitrate_bps, max_padding_bitrate_bps); >+ int max_padding_bitrate_bps, >+ int max_total_bitrate_bps) { >+ send_side_cc_->SetAllocatedSendBitrateLimits( >+ min_send_bitrate_bps, max_padding_bitrate_bps, max_total_bitrate_bps); > } > > void RtpTransportControllerSend::SetKeepAliveConfig( > const RtpKeepAliveConfig& config) { > keepalive_ = config; > } >+void RtpTransportControllerSend::SetPacingFactor(float pacing_factor) { >+ send_side_cc_->SetPacingFactor(pacing_factor); >+} >+void RtpTransportControllerSend::SetQueueTimeLimit(int limit_ms) { >+ pacer_.SetQueueTimeLimit(limit_ms); >+} >+CallStatsObserver* RtpTransportControllerSend::GetCallStatsObserver() { >+ return send_side_cc_.get(); >+} >+void RtpTransportControllerSend::RegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) { >+ send_side_cc_->RegisterPacketFeedbackObserver(observer); >+} >+void RtpTransportControllerSend::DeRegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) { >+ send_side_cc_->DeRegisterPacketFeedbackObserver(observer); >+} >+ >+void RtpTransportControllerSend::RegisterTargetTransferRateObserver( >+ TargetTransferRateObserver* observer) { >+ { >+ rtc::CritScope cs(&observer_crit_); >+ RTC_DCHECK(observer_ == nullptr); >+ observer_ = observer; >+ } >+ send_side_cc_->RegisterNetworkObserver(this); >+} >+void RtpTransportControllerSend::OnNetworkRouteChanged( >+ const std::string& transport_name, >+ const rtc::NetworkRoute& network_route) { >+ // Check if the network route is connected. >+ if (!network_route.connected) { >+ RTC_LOG(LS_INFO) << "Transport " << transport_name << " is disconnected"; >+ // TODO(honghaiz): Perhaps handle this in SignalChannelNetworkState and >+ // consider merging these two methods. >+ return; >+ } >+ >+ // Check whether the network route has changed on each transport. >+ auto result = >+ network_routes_.insert(std::make_pair(transport_name, network_route)); >+ auto kv = result.first; >+ bool inserted = result.second; >+ if (inserted) { >+ // No need to reset BWE if this is the first time the network connects. >+ return; >+ } >+ if (kv->second != network_route) { >+ kv->second = network_route; >+ BitrateConstraints bitrate_config = bitrate_configurator_.GetConfig(); >+ RTC_LOG(LS_INFO) << "Network route changed on transport " << transport_name >+ << ": new local network id " >+ << network_route.local_network_id >+ << " new remote network id " >+ << network_route.remote_network_id >+ << " Reset bitrates to min: " >+ << bitrate_config.min_bitrate_bps >+ << " bps, start: " << bitrate_config.start_bitrate_bps >+ << " bps, max: " << bitrate_config.max_bitrate_bps >+ << " bps."; >+ RTC_DCHECK_GT(bitrate_config.start_bitrate_bps, 0); >+ send_side_cc_->OnNetworkRouteChanged( >+ network_route, bitrate_config.start_bitrate_bps, >+ bitrate_config.min_bitrate_bps, bitrate_config.max_bitrate_bps); >+ } >+} >+void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) { >+ send_side_cc_->SignalNetworkState(network_available ? kNetworkUp >+ : kNetworkDown); >+ for (auto& rtp_sender : video_rtp_senders_) { >+ rtp_sender->OnNetworkAvailability(network_available); >+ } >+} >+RtcpBandwidthObserver* RtpTransportControllerSend::GetBandwidthObserver() { >+ return send_side_cc_->GetBandwidthObserver(); >+} >+int64_t RtpTransportControllerSend::GetPacerQueuingDelayMs() const { >+ return pacer_.QueueInMs(); >+} >+int64_t RtpTransportControllerSend::GetFirstPacketTimeMs() const { >+ return pacer_.FirstSentPacketTimeMs(); >+} >+void RtpTransportControllerSend::SetPerPacketFeedbackAvailable(bool available) { >+ send_side_cc_->SetPerPacketFeedbackAvailable(available); >+} >+void RtpTransportControllerSend::EnablePeriodicAlrProbing(bool enable) { >+ send_side_cc_->EnablePeriodicAlrProbing(enable); >+} >+void RtpTransportControllerSend::OnSentPacket( >+ const rtc::SentPacket& sent_packet) { >+ send_side_cc_->OnSentPacket(sent_packet); >+} > >+void RtpTransportControllerSend::SetSdpBitrateParameters( >+ const BitrateConstraints& constraints) { >+ absl::optional<BitrateConstraints> updated = >+ bitrate_configurator_.UpdateWithSdpParameters(constraints); >+ if (updated.has_value()) { >+ send_side_cc_->SetBweBitrates(updated->min_bitrate_bps, >+ updated->start_bitrate_bps, >+ updated->max_bitrate_bps); >+ } else { >+ RTC_LOG(LS_VERBOSE) >+ << "WebRTC.RtpTransportControllerSend.SetSdpBitrateParameters: " >+ << "nothing to update"; >+ } >+} >+ >+void RtpTransportControllerSend::SetClientBitratePreferences( >+ const BitrateSettings& preferences) { >+ absl::optional<BitrateConstraints> updated = >+ bitrate_configurator_.UpdateWithClientPreferences(preferences); >+ if (updated.has_value()) { >+ send_side_cc_->SetBweBitrates(updated->min_bitrate_bps, >+ updated->start_bitrate_bps, >+ updated->max_bitrate_bps); >+ } else { >+ RTC_LOG(LS_VERBOSE) >+ << "WebRTC.RtpTransportControllerSend.SetClientBitratePreferences: " >+ << "nothing to update"; >+ } >+} >+ >+void RtpTransportControllerSend::SetAllocatedBitrateWithoutFeedback( >+ uint32_t bitrate_bps) { >+ send_side_cc_->SetAllocatedBitrateWithoutFeedback(bitrate_bps); >+} > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.h >index 45d6db0feee..496a00ede5f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send.h >@@ -11,11 +11,22 @@ > #ifndef CALL_RTP_TRANSPORT_CONTROLLER_SEND_H_ > #define CALL_RTP_TRANSPORT_CONTROLLER_SEND_H_ > >+#include <map> >+#include <memory> >+#include <string> >+#include <vector> >+ >+#include "api/transport/network_control.h" >+#include "call/rtp_bitrate_configurator.h" > #include "call/rtp_transport_controller_send_interface.h" >+#include "call/rtp_video_sender.h" > #include "common_types.h" // NOLINT(build/include) >-#include "modules/congestion_controller/include/send_side_congestion_controller.h" >+#include "modules/congestion_controller/include/send_side_congestion_controller_interface.h" > #include "modules/pacing/packet_router.h" >+#include "modules/utility/include/process_thread.h" > #include "rtc_base/constructormagic.h" >+#include "rtc_base/networkroute.h" >+#include "rtc_base/task_queue.h" > > namespace webrtc { > class Clock; >@@ -24,33 +35,91 @@ class RtcEventLog; > // TODO(nisse): When we get the underlying transports here, we should > // have one object implementing RtpTransportControllerSendInterface > // per transport, sharing the same congestion controller. >-class RtpTransportControllerSend : public RtpTransportControllerSendInterface { >+class RtpTransportControllerSend final >+ : public RtpTransportControllerSendInterface, >+ public NetworkChangedObserver { > public: >- RtpTransportControllerSend(Clock* clock, webrtc::RtcEventLog* event_log); >+ RtpTransportControllerSend( >+ Clock* clock, >+ RtcEventLog* event_log, >+ NetworkControllerFactoryInterface* controller_factory, >+ const BitrateConstraints& bitrate_config); >+ ~RtpTransportControllerSend() override; >+ >+ RtpVideoSenderInterface* CreateRtpVideoSender( >+ const std::vector<uint32_t>& ssrcs, >+ std::map<uint32_t, RtpState> suspended_ssrcs, >+ const std::map<uint32_t, RtpPayloadState>& >+ states, // move states into RtpTransportControllerSend >+ const RtpConfig& rtp_config, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ const RtpSenderObservers& observers, >+ RtcEventLog* event_log) override; >+ void DestroyRtpVideoSender( >+ RtpVideoSenderInterface* rtp_video_sender) override; >+ >+ // Implements NetworkChangedObserver interface. >+ void OnNetworkChanged(uint32_t bitrate_bps, >+ uint8_t fraction_loss, >+ int64_t rtt_ms, >+ int64_t probing_interval_ms) override; > > // Implements RtpTransportControllerSendInterface >+ rtc::TaskQueue* GetWorkerQueue() override; > PacketRouter* packet_router() override; >- // TODO(holmer): Temporarily exposed, should be removed and the >- // appropriate methods should be added to this class instead. >- // In addition the PacedSender should be driven by this class, either >- // by owning the process thread, or later by using a task queue. >- PacedSender* pacer() override; >- SendSideCongestionController* send_side_cc() override; >+ > TransportFeedbackObserver* transport_feedback_observer() override; > RtpPacketSender* packet_sender() override; > const RtpKeepAliveConfig& keepalive_config() const override; > > void SetAllocatedSendBitrateLimits(int min_send_bitrate_bps, >- int max_padding_bitrate_bps) override; >+ int max_padding_bitrate_bps, >+ int max_total_bitrate_bps) override; > > void SetKeepAliveConfig(const RtpKeepAliveConfig& config); >+ void SetPacingFactor(float pacing_factor) override; >+ void SetQueueTimeLimit(int limit_ms) override; >+ CallStatsObserver* GetCallStatsObserver() override; >+ void RegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) override; >+ void DeRegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) override; >+ void RegisterTargetTransferRateObserver( >+ TargetTransferRateObserver* observer) override; >+ void OnNetworkRouteChanged(const std::string& transport_name, >+ const rtc::NetworkRoute& network_route) override; >+ void OnNetworkAvailability(bool network_available) override; >+ RtcpBandwidthObserver* GetBandwidthObserver() override; >+ int64_t GetPacerQueuingDelayMs() const override; >+ int64_t GetFirstPacketTimeMs() const override; >+ void SetPerPacketFeedbackAvailable(bool available) override; >+ void EnablePeriodicAlrProbing(bool enable) override; >+ void OnSentPacket(const rtc::SentPacket& sent_packet) override; >+ >+ void SetSdpBitrateParameters(const BitrateConstraints& constraints) override; >+ void SetClientBitratePreferences(const BitrateSettings& preferences) override; >+ >+ void SetAllocatedBitrateWithoutFeedback(uint32_t bitrate_bps) override; > > private: >+ const Clock* const clock_; > PacketRouter packet_router_; >+ std::vector<std::unique_ptr<RtpVideoSenderInterface>> video_rtp_senders_; > PacedSender pacer_; >- SendSideCongestionController send_side_cc_; > RtpKeepAliveConfig keepalive_; >+ RtpBitrateConfigurator bitrate_configurator_; >+ std::map<std::string, rtc::NetworkRoute> network_routes_; >+ const std::unique_ptr<ProcessThread> process_thread_; >+ rtc::CriticalSection observer_crit_; >+ TargetTransferRateObserver* observer_ RTC_GUARDED_BY(observer_crit_); >+ std::unique_ptr<SendSideCongestionControllerInterface> send_side_cc_; >+ RateLimiter retransmission_rate_limiter_; > >+ // TODO(perkj): |task_queue_| is supposed to replace |process_thread_|. >+ // |task_queue_| is defined last to ensure all pending tasks are cancelled >+ // and deleted before any other members. >+ rtc::TaskQueue task_queue_; > RTC_DISALLOW_COPY_AND_ASSIGN(RtpTransportControllerSend); > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send_interface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send_interface.h >index 7b0dbefd14f..828fec40cf0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send_interface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_transport_controller_send_interface.h >@@ -10,16 +10,57 @@ > > #ifndef CALL_RTP_TRANSPORT_CONTROLLER_SEND_INTERFACE_H_ > #define CALL_RTP_TRANSPORT_CONTROLLER_SEND_INTERFACE_H_ >+#include <stddef.h> >+#include <stdint.h> > >+#include <map> >+#include <string> >+#include <vector> >+ >+#include "absl/types/optional.h" >+#include "api/bitrate_constraints.h" >+#include "api/transport/bitrate_settings.h" >+#include "call/rtp_config.h" >+#include "logging/rtc_event_log/rtc_event_log.h" >+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >+ >+namespace rtc { >+struct SentPacket; >+struct NetworkRoute; >+class TaskQueue; >+} // namespace rtc > namespace webrtc { > >+class CallStats; >+class CallStatsObserver; >+class TargetTransferRateObserver; >+class Transport; >+class Module; > class PacedSender; >+class PacketFeedbackObserver; > class PacketRouter; >+class RtpVideoSenderInterface; >+class RateLimiter; >+class RtcpBandwidthObserver; > class RtpPacketSender; > struct RtpKeepAliveConfig; >-class SendSideCongestionController; >+class SendDelayStats; >+class SendStatisticsProxy; > class TransportFeedbackObserver; > >+struct RtpSenderObservers { >+ RtcpRttStats* rtcp_rtt_stats; >+ RtcpIntraFrameObserver* intra_frame_callback; >+ RtcpStatisticsCallback* rtcp_stats; >+ StreamDataCountersCallback* rtp_stats; >+ BitrateStatisticsObserver* bitrate_observer; >+ FrameCountObserver* frame_count_observer; >+ RtcpPacketTypeCounterObserver* rtcp_type_observer; >+ SendSideDelayObserver* send_delay_observer; >+ SendPacketObserver* send_packet_observer; >+ OverheadObserver* overhead_observer; >+}; >+ > // An RtpTransportController should own everything related to the RTP > // transport to/from a remote endpoint. We should have separate > // interfaces for send and receive side, even if they are implemented >@@ -46,10 +87,22 @@ class TransportFeedbackObserver; > class RtpTransportControllerSendInterface { > public: > virtual ~RtpTransportControllerSendInterface() {} >+ virtual rtc::TaskQueue* GetWorkerQueue() = 0; > virtual PacketRouter* packet_router() = 0; >- virtual PacedSender* pacer() = 0; >- // Currently returning the same pointer, but with different types. >- virtual SendSideCongestionController* send_side_cc() = 0; >+ >+ virtual RtpVideoSenderInterface* CreateRtpVideoSender( >+ const std::vector<uint32_t>& ssrcs, >+ std::map<uint32_t, RtpState> suspended_ssrcs, >+ // TODO(holmer): Move states into RtpTransportControllerSend. >+ const std::map<uint32_t, RtpPayloadState>& states, >+ const RtpConfig& rtp_config, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ const RtpSenderObservers& observers, >+ RtcEventLog* event_log) = 0; >+ virtual void DestroyRtpVideoSender( >+ RtpVideoSenderInterface* rtp_video_sender) = 0; >+ > virtual TransportFeedbackObserver* transport_feedback_observer() = 0; > > virtual RtpPacketSender* packet_sender() = 0; >@@ -65,7 +118,37 @@ class RtpTransportControllerSendInterface { > // current network estimate and tells the PacedSender how much it should max > // pad unless there is real packets to send. > virtual void SetAllocatedSendBitrateLimits(int min_send_bitrate_bps, >- int max_padding_bitrate_bps) = 0; >+ int max_padding_bitrate_bps, >+ int total_bitrate_bps) = 0; >+ >+ virtual void SetPacingFactor(float pacing_factor) = 0; >+ virtual void SetQueueTimeLimit(int limit_ms) = 0; >+ >+ virtual CallStatsObserver* GetCallStatsObserver() = 0; >+ >+ virtual void RegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) = 0; >+ virtual void DeRegisterPacketFeedbackObserver( >+ PacketFeedbackObserver* observer) = 0; >+ virtual void RegisterTargetTransferRateObserver( >+ TargetTransferRateObserver* observer) = 0; >+ virtual void OnNetworkRouteChanged( >+ const std::string& transport_name, >+ const rtc::NetworkRoute& network_route) = 0; >+ virtual void OnNetworkAvailability(bool network_available) = 0; >+ virtual RtcpBandwidthObserver* GetBandwidthObserver() = 0; >+ virtual int64_t GetPacerQueuingDelayMs() const = 0; >+ virtual int64_t GetFirstPacketTimeMs() const = 0; >+ virtual void EnablePeriodicAlrProbing(bool enable) = 0; >+ virtual void OnSentPacket(const rtc::SentPacket& sent_packet) = 0; >+ virtual void SetPerPacketFeedbackAvailable(bool available) = 0; >+ >+ virtual void SetSdpBitrateParameters( >+ const BitrateConstraints& constraints) = 0; >+ virtual void SetClientBitratePreferences( >+ const BitrateSettings& preferences) = 0; >+ >+ virtual void SetAllocatedBitrateWithoutFeedback(uint32_t bitrate_bps) = 0; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.cc >new file mode 100644 >index 00000000000..d9dcb87eb8c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.cc >@@ -0,0 +1,553 @@ >+/* >+ * Copyright (c) 2015 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 "call/rtp_video_sender.h" >+ >+#include <algorithm> >+#include <memory> >+#include <string> >+#include <utility> >+ >+#include "call/rtp_transport_controller_send_interface.h" >+#include "modules/pacing/packet_router.h" >+#include "modules/rtp_rtcp/include/rtp_rtcp.h" >+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >+#include "modules/rtp_rtcp/source/rtp_sender.h" >+#include "modules/utility/include/process_thread.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/location.h" >+#include "rtc_base/logging.h" >+#include "system_wrappers/include/field_trial.h" >+ >+namespace webrtc { >+ >+namespace { >+static const int kMinSendSidePacketHistorySize = 600; >+ >+std::vector<std::unique_ptr<RtpRtcp>> CreateRtpRtcpModules( >+ const std::vector<uint32_t>& ssrcs, >+ const std::vector<uint32_t>& protected_media_ssrcs, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ RtcpIntraFrameObserver* intra_frame_callback, >+ RtcpBandwidthObserver* bandwidth_callback, >+ RtpTransportControllerSendInterface* transport, >+ RtcpRttStats* rtt_stats, >+ FlexfecSender* flexfec_sender, >+ BitrateStatisticsObserver* bitrate_observer, >+ FrameCountObserver* frame_count_observer, >+ RtcpPacketTypeCounterObserver* rtcp_type_observer, >+ SendSideDelayObserver* send_delay_observer, >+ SendPacketObserver* send_packet_observer, >+ RtcEventLog* event_log, >+ RateLimiter* retransmission_rate_limiter, >+ OverheadObserver* overhead_observer, >+ RtpKeepAliveConfig keepalive_config) { >+ RTC_DCHECK_GT(ssrcs.size(), 0); >+ RtpRtcp::Configuration configuration; >+ configuration.audio = false; >+ configuration.receiver_only = false; >+ configuration.outgoing_transport = send_transport; >+ configuration.intra_frame_callback = intra_frame_callback; >+ configuration.bandwidth_callback = bandwidth_callback; >+ configuration.transport_feedback_callback = >+ transport->transport_feedback_observer(); >+ configuration.rtt_stats = rtt_stats; >+ configuration.rtcp_packet_type_counter_observer = rtcp_type_observer; >+ configuration.paced_sender = transport->packet_sender(); >+ configuration.transport_sequence_number_allocator = >+ transport->packet_router(); >+ configuration.send_bitrate_observer = bitrate_observer; >+ configuration.send_frame_count_observer = frame_count_observer; >+ configuration.send_side_delay_observer = send_delay_observer; >+ configuration.send_packet_observer = send_packet_observer; >+ configuration.event_log = event_log; >+ configuration.retransmission_rate_limiter = retransmission_rate_limiter; >+ configuration.overhead_observer = overhead_observer; >+ configuration.keepalive_config = keepalive_config; >+ configuration.rtcp_interval_config.video_interval_ms = >+ rtcp_config.video_report_interval_ms; >+ configuration.rtcp_interval_config.audio_interval_ms = >+ rtcp_config.audio_report_interval_ms; >+ std::vector<std::unique_ptr<RtpRtcp>> modules; >+ const std::vector<uint32_t>& flexfec_protected_ssrcs = protected_media_ssrcs; >+ for (uint32_t ssrc : ssrcs) { >+ bool enable_flexfec = flexfec_sender != nullptr && >+ std::find(flexfec_protected_ssrcs.begin(), >+ flexfec_protected_ssrcs.end(), >+ ssrc) != flexfec_protected_ssrcs.end(); >+ configuration.flexfec_sender = enable_flexfec ? flexfec_sender : nullptr; >+ std::unique_ptr<RtpRtcp> rtp_rtcp = >+ std::unique_ptr<RtpRtcp>(RtpRtcp::CreateRtpRtcp(configuration)); >+ rtp_rtcp->SetSendingStatus(false); >+ rtp_rtcp->SetSendingMediaStatus(false); >+ rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound); >+ modules.push_back(std::move(rtp_rtcp)); >+ } >+ return modules; >+} >+ >+absl::optional<size_t> GetSimulcastIdx(const CodecSpecificInfo* info) { >+ if (!info) >+ return absl::nullopt; >+ switch (info->codecType) { >+ case kVideoCodecVP8: >+ return absl::optional<size_t>(info->codecSpecific.VP8.simulcastIdx); >+ case kVideoCodecH264: >+ return absl::optional<size_t>(info->codecSpecific.H264.simulcast_idx); >+ case kVideoCodecMultiplex: >+ case kVideoCodecGeneric: >+ return absl::optional<size_t>(info->codecSpecific.generic.simulcast_idx); >+ default: >+ return absl::nullopt; >+ } >+} >+bool PayloadTypeSupportsSkippingFecPackets(const std::string& payload_name) { >+ const VideoCodecType codecType = PayloadStringToCodecType(payload_name); >+ if (codecType == kVideoCodecVP8 || codecType == kVideoCodecVP9) { >+ return true; >+ } >+ return false; >+} >+ >+// TODO(brandtr): Update this function when we support multistream protection. >+std::unique_ptr<FlexfecSender> MaybeCreateFlexfecSender( >+ const RtpConfig& rtp, >+ const std::map<uint32_t, RtpState>& suspended_ssrcs) { >+ if (rtp.flexfec.payload_type < 0) { >+ return nullptr; >+ } >+ RTC_DCHECK_GE(rtp.flexfec.payload_type, 0); >+ RTC_DCHECK_LE(rtp.flexfec.payload_type, 127); >+ if (rtp.flexfec.ssrc == 0) { >+ RTC_LOG(LS_WARNING) << "FlexFEC is enabled, but no FlexFEC SSRC given. " >+ "Therefore disabling FlexFEC."; >+ return nullptr; >+ } >+ if (rtp.flexfec.protected_media_ssrcs.empty()) { >+ RTC_LOG(LS_WARNING) >+ << "FlexFEC is enabled, but no protected media SSRC given. " >+ "Therefore disabling FlexFEC."; >+ return nullptr; >+ } >+ >+ if (rtp.flexfec.protected_media_ssrcs.size() > 1) { >+ RTC_LOG(LS_WARNING) >+ << "The supplied FlexfecConfig contained multiple protected " >+ "media streams, but our implementation currently only " >+ "supports protecting a single media stream. " >+ "To avoid confusion, disabling FlexFEC completely."; >+ return nullptr; >+ } >+ >+ const RtpState* rtp_state = nullptr; >+ auto it = suspended_ssrcs.find(rtp.flexfec.ssrc); >+ if (it != suspended_ssrcs.end()) { >+ rtp_state = &it->second; >+ } >+ >+ RTC_DCHECK_EQ(1U, rtp.flexfec.protected_media_ssrcs.size()); >+ return absl::make_unique<FlexfecSender>( >+ rtp.flexfec.payload_type, rtp.flexfec.ssrc, >+ rtp.flexfec.protected_media_ssrcs[0], rtp.mid, rtp.extensions, >+ RTPSender::FecExtensionSizes(), rtp_state, Clock::GetRealTimeClock()); >+} >+} // namespace >+ >+RtpVideoSender::RtpVideoSender( >+ const std::vector<uint32_t>& ssrcs, >+ std::map<uint32_t, RtpState> suspended_ssrcs, >+ const std::map<uint32_t, RtpPayloadState>& states, >+ const RtpConfig& rtp_config, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ const RtpSenderObservers& observers, >+ RtpTransportControllerSendInterface* transport, >+ RtcEventLog* event_log, >+ RateLimiter* retransmission_limiter) >+ : active_(false), >+ module_process_thread_(nullptr), >+ suspended_ssrcs_(std::move(suspended_ssrcs)), >+ flexfec_sender_(MaybeCreateFlexfecSender(rtp_config, suspended_ssrcs_)), >+ rtp_modules_( >+ CreateRtpRtcpModules(ssrcs, >+ rtp_config.flexfec.protected_media_ssrcs, >+ rtcp_config, >+ send_transport, >+ observers.intra_frame_callback, >+ transport->GetBandwidthObserver(), >+ transport, >+ observers.rtcp_rtt_stats, >+ flexfec_sender_.get(), >+ observers.bitrate_observer, >+ observers.frame_count_observer, >+ observers.rtcp_type_observer, >+ observers.send_delay_observer, >+ observers.send_packet_observer, >+ event_log, >+ retransmission_limiter, >+ observers.overhead_observer, >+ transport->keepalive_config())), >+ rtp_config_(rtp_config), >+ transport_(transport) { >+ RTC_DCHECK_EQ(ssrcs.size(), rtp_modules_.size()); >+ module_process_thread_checker_.DetachFromThread(); >+ // SSRCs are assumed to be sorted in the same order as |rtp_modules|. >+ for (uint32_t ssrc : ssrcs) { >+ // Restore state if it previously existed. >+ const RtpPayloadState* state = nullptr; >+ auto it = states.find(ssrc); >+ if (it != states.end()) { >+ state = &it->second; >+ shared_frame_id_ = std::max(shared_frame_id_, state->shared_frame_id); >+ } >+ params_.push_back(RtpPayloadParams(ssrc, state)); >+ } >+ >+ // RTP/RTCP initialization. >+ >+ // We add the highest spatial layer first to ensure it'll be prioritized >+ // when sending padding, with the hope that the packet rate will be smaller, >+ // and that it's more important to protect than the lower layers. >+ >+ // TODO(nisse): Consider moving registration with PacketRouter last, after the >+ // modules are fully configured. >+ for (auto& rtp_rtcp : rtp_modules_) { >+ constexpr bool remb_candidate = true; >+ transport->packet_router()->AddSendRtpModule(rtp_rtcp.get(), >+ remb_candidate); >+ } >+ >+ for (size_t i = 0; i < rtp_config_.extensions.size(); ++i) { >+ const std::string& extension = rtp_config_.extensions[i].uri; >+ int id = rtp_config_.extensions[i].id; >+ // One-byte-extension local identifiers are in the range 1-14 inclusive. >+ RTC_DCHECK_GE(id, 1); >+ RTC_DCHECK_LE(id, 14); >+ RTC_DCHECK(RtpExtension::IsSupportedForVideo(extension)); >+ for (auto& rtp_rtcp : rtp_modules_) { >+ RTC_CHECK_EQ(0, rtp_rtcp->RegisterSendRtpHeaderExtension( >+ StringToRtpExtensionType(extension), id)); >+ } >+ } >+ >+ ConfigureProtection(rtp_config); >+ ConfigureSsrcs(rtp_config); >+ >+ if (!rtp_config.mid.empty()) { >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->SetMid(rtp_config.mid); >+ } >+ } >+ >+ // TODO(pbos): Should we set CNAME on all RTP modules? >+ rtp_modules_.front()->SetCNAME(rtp_config.c_name.c_str()); >+ >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->RegisterRtcpStatisticsCallback(observers.rtcp_stats); >+ rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(observers.rtp_stats); >+ rtp_rtcp->SetMaxRtpPacketSize(rtp_config.max_packet_size); >+ rtp_rtcp->RegisterVideoSendPayload(rtp_config.payload_type, >+ rtp_config.payload_name.c_str()); >+ } >+} >+ >+RtpVideoSender::~RtpVideoSender() { >+ for (auto& rtp_rtcp : rtp_modules_) { >+ transport_->packet_router()->RemoveSendRtpModule(rtp_rtcp.get()); >+ } >+} >+ >+void RtpVideoSender::RegisterProcessThread( >+ ProcessThread* module_process_thread) { >+ RTC_DCHECK_RUN_ON(&module_process_thread_checker_); >+ RTC_DCHECK(!module_process_thread_); >+ module_process_thread_ = module_process_thread; >+ >+ for (auto& rtp_rtcp : rtp_modules_) >+ module_process_thread_->RegisterModule(rtp_rtcp.get(), RTC_FROM_HERE); >+} >+ >+void RtpVideoSender::DeRegisterProcessThread() { >+ RTC_DCHECK_RUN_ON(&module_process_thread_checker_); >+ for (auto& rtp_rtcp : rtp_modules_) >+ module_process_thread_->DeRegisterModule(rtp_rtcp.get()); >+} >+ >+void RtpVideoSender::SetActive(bool active) { >+ rtc::CritScope lock(&crit_); >+ if (active_ == active) >+ return; >+ const std::vector<bool> active_modules(rtp_modules_.size(), active); >+ SetActiveModules(active_modules); >+} >+ >+void RtpVideoSender::SetActiveModules(const std::vector<bool> active_modules) { >+ rtc::CritScope lock(&crit_); >+ RTC_DCHECK_EQ(rtp_modules_.size(), active_modules.size()); >+ active_ = false; >+ for (size_t i = 0; i < active_modules.size(); ++i) { >+ if (active_modules[i]) { >+ active_ = true; >+ } >+ // Sends a kRtcpByeCode when going from true to false. >+ rtp_modules_[i]->SetSendingStatus(active_modules[i]); >+ // If set to false this module won't send media. >+ rtp_modules_[i]->SetSendingMediaStatus(active_modules[i]); >+ } >+} >+ >+bool RtpVideoSender::IsActive() { >+ rtc::CritScope lock(&crit_); >+ return active_ && !rtp_modules_.empty(); >+} >+ >+EncodedImageCallback::Result RtpVideoSender::OnEncodedImage( >+ const EncodedImage& encoded_image, >+ const CodecSpecificInfo* codec_specific_info, >+ const RTPFragmentationHeader* fragmentation) { >+ rtc::CritScope lock(&crit_); >+ RTC_DCHECK(!rtp_modules_.empty()); >+ if (!active_) >+ return Result(Result::ERROR_SEND_FAILED); >+ >+ size_t stream_index = GetSimulcastIdx(codec_specific_info).value_or(0); >+ RTC_DCHECK_LT(stream_index, rtp_modules_.size()); >+ RTPVideoHeader rtp_video_header = params_[stream_index].GetRtpVideoHeader( >+ encoded_image, codec_specific_info); >+ >+ uint32_t frame_id; >+ if (!rtp_modules_[stream_index]->Sending()) { >+ // The payload router could be active but this module isn't sending. >+ return Result(Result::ERROR_SEND_FAILED); >+ } >+ bool send_result = rtp_modules_[stream_index]->SendOutgoingData( >+ encoded_image._frameType, rtp_config_.payload_type, >+ encoded_image._timeStamp, encoded_image.capture_time_ms_, >+ encoded_image._buffer, encoded_image._length, fragmentation, >+ &rtp_video_header, &frame_id); >+ if (!send_result) >+ return Result(Result::ERROR_SEND_FAILED); >+ >+ return Result(Result::OK, frame_id); >+} >+ >+void RtpVideoSender::OnBitrateAllocationUpdated( >+ const VideoBitrateAllocation& bitrate) { >+ rtc::CritScope lock(&crit_); >+ if (IsActive()) { >+ if (rtp_modules_.size() == 1) { >+ // If spatial scalability is enabled, it is covered by a single stream. >+ rtp_modules_[0]->SetVideoBitrateAllocation(bitrate); >+ } else { >+ std::vector<absl::optional<VideoBitrateAllocation>> layer_bitrates = >+ bitrate.GetSimulcastAllocations(); >+ // Simulcast is in use, split the VideoBitrateAllocation into one struct >+ // per rtp stream, moving over the temporal layer allocation. >+ for (size_t i = 0; i < rtp_modules_.size(); ++i) { >+ // The next spatial layer could be used if the current one is >+ // inactive. >+ if (layer_bitrates[i]) { >+ rtp_modules_[i]->SetVideoBitrateAllocation(*layer_bitrates[i]); >+ } >+ } >+ } >+ } >+} >+ >+void RtpVideoSender::ConfigureProtection(const RtpConfig& rtp_config) { >+ // Consistency of FlexFEC parameters is checked in MaybeCreateFlexfecSender. >+ const bool flexfec_enabled = (flexfec_sender_ != nullptr); >+ >+ // Consistency of NACK and RED+ULPFEC parameters is checked in this function. >+ const bool nack_enabled = rtp_config.nack.rtp_history_ms > 0; >+ int red_payload_type = rtp_config.ulpfec.red_payload_type; >+ int ulpfec_payload_type = rtp_config.ulpfec.ulpfec_payload_type; >+ >+ // Shorthands. >+ auto IsRedEnabled = [&]() { return red_payload_type >= 0; }; >+ auto IsUlpfecEnabled = [&]() { return ulpfec_payload_type >= 0; }; >+ auto DisableRedAndUlpfec = [&]() { >+ red_payload_type = -1; >+ ulpfec_payload_type = -1; >+ }; >+ >+ if (webrtc::field_trial::IsEnabled("WebRTC-DisableUlpFecExperiment")) { >+ RTC_LOG(LS_INFO) << "Experiment to disable sending ULPFEC is enabled."; >+ DisableRedAndUlpfec(); >+ } >+ >+ // If enabled, FlexFEC takes priority over RED+ULPFEC. >+ if (flexfec_enabled) { >+ if (IsUlpfecEnabled()) { >+ RTC_LOG(LS_INFO) >+ << "Both FlexFEC and ULPFEC are configured. Disabling ULPFEC."; >+ } >+ DisableRedAndUlpfec(); >+ } >+ >+ // Payload types without picture ID cannot determine that a stream is complete >+ // without retransmitting FEC, so using ULPFEC + NACK for H.264 (for instance) >+ // is a waste of bandwidth since FEC packets still have to be transmitted. >+ // Note that this is not the case with FlexFEC. >+ if (nack_enabled && IsUlpfecEnabled() && >+ !PayloadTypeSupportsSkippingFecPackets(rtp_config.payload_name)) { >+ RTC_LOG(LS_WARNING) >+ << "Transmitting payload type without picture ID using " >+ "NACK+ULPFEC is a waste of bandwidth since ULPFEC packets " >+ "also have to be retransmitted. Disabling ULPFEC."; >+ DisableRedAndUlpfec(); >+ } >+ >+ // Verify payload types. >+ if (IsUlpfecEnabled() ^ IsRedEnabled()) { >+ RTC_LOG(LS_WARNING) >+ << "Only RED or only ULPFEC enabled, but not both. Disabling both."; >+ DisableRedAndUlpfec(); >+ } >+ >+ for (auto& rtp_rtcp : rtp_modules_) { >+ // Set NACK. >+ rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize); >+ // Set RED/ULPFEC information. >+ rtp_rtcp->SetUlpfecConfig(red_payload_type, ulpfec_payload_type); >+ } >+} >+ >+bool RtpVideoSender::FecEnabled() const { >+ const bool flexfec_enabled = (flexfec_sender_ != nullptr); >+ int ulpfec_payload_type = rtp_config_.ulpfec.ulpfec_payload_type; >+ return flexfec_enabled || ulpfec_payload_type >= 0; >+} >+ >+bool RtpVideoSender::NackEnabled() const { >+ const bool nack_enabled = rtp_config_.nack.rtp_history_ms > 0; >+ return nack_enabled; >+} >+ >+void RtpVideoSender::DeliverRtcp(const uint8_t* packet, size_t length) { >+ // Runs on a network thread. >+ for (auto& rtp_rtcp : rtp_modules_) >+ rtp_rtcp->IncomingRtcpPacket(packet, length); >+} >+ >+void RtpVideoSender::ProtectionRequest(const FecProtectionParams* delta_params, >+ const FecProtectionParams* key_params, >+ uint32_t* sent_video_rate_bps, >+ uint32_t* sent_nack_rate_bps, >+ uint32_t* sent_fec_rate_bps) { >+ *sent_video_rate_bps = 0; >+ *sent_nack_rate_bps = 0; >+ *sent_fec_rate_bps = 0; >+ for (auto& rtp_rtcp : rtp_modules_) { >+ uint32_t not_used = 0; >+ uint32_t module_video_rate = 0; >+ uint32_t module_fec_rate = 0; >+ uint32_t module_nack_rate = 0; >+ rtp_rtcp->SetFecParameters(*delta_params, *key_params); >+ rtp_rtcp->BitrateSent(¬_used, &module_video_rate, &module_fec_rate, >+ &module_nack_rate); >+ *sent_video_rate_bps += module_video_rate; >+ *sent_nack_rate_bps += module_nack_rate; >+ *sent_fec_rate_bps += module_fec_rate; >+ } >+} >+ >+void RtpVideoSender::SetMaxRtpPacketSize(size_t max_rtp_packet_size) { >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->SetMaxRtpPacketSize(max_rtp_packet_size); >+ } >+} >+ >+void RtpVideoSender::ConfigureSsrcs(const RtpConfig& rtp_config) { >+ // Configure regular SSRCs. >+ for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) { >+ uint32_t ssrc = rtp_config.ssrcs[i]; >+ RtpRtcp* const rtp_rtcp = rtp_modules_[i].get(); >+ rtp_rtcp->SetSSRC(ssrc); >+ >+ // Restore RTP state if previous existed. >+ auto it = suspended_ssrcs_.find(ssrc); >+ if (it != suspended_ssrcs_.end()) >+ rtp_rtcp->SetRtpState(it->second); >+ } >+ >+ // Set up RTX if available. >+ if (rtp_config.rtx.ssrcs.empty()) >+ return; >+ >+ // Configure RTX SSRCs. >+ RTC_DCHECK_EQ(rtp_config.rtx.ssrcs.size(), rtp_config.ssrcs.size()); >+ for (size_t i = 0; i < rtp_config.rtx.ssrcs.size(); ++i) { >+ uint32_t ssrc = rtp_config.rtx.ssrcs[i]; >+ RtpRtcp* const rtp_rtcp = rtp_modules_[i].get(); >+ rtp_rtcp->SetRtxSsrc(ssrc); >+ auto it = suspended_ssrcs_.find(ssrc); >+ if (it != suspended_ssrcs_.end()) >+ rtp_rtcp->SetRtxState(it->second); >+ } >+ >+ // Configure RTX payload types. >+ RTC_DCHECK_GE(rtp_config.rtx.payload_type, 0); >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->SetRtxSendPayloadType(rtp_config.rtx.payload_type, >+ rtp_config.payload_type); >+ rtp_rtcp->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads); >+ } >+ if (rtp_config.ulpfec.red_payload_type != -1 && >+ rtp_config.ulpfec.red_rtx_payload_type != -1) { >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->SetRtxSendPayloadType(rtp_config.ulpfec.red_rtx_payload_type, >+ rtp_config.ulpfec.red_payload_type); >+ } >+ } >+} >+ >+void RtpVideoSender::OnNetworkAvailability(bool network_available) { >+ for (auto& rtp_rtcp : rtp_modules_) { >+ rtp_rtcp->SetRTCPStatus(network_available ? rtp_config_.rtcp_mode >+ : RtcpMode::kOff); >+ } >+} >+ >+std::map<uint32_t, RtpState> RtpVideoSender::GetRtpStates() const { >+ std::map<uint32_t, RtpState> rtp_states; >+ >+ for (size_t i = 0; i < rtp_config_.ssrcs.size(); ++i) { >+ uint32_t ssrc = rtp_config_.ssrcs[i]; >+ RTC_DCHECK_EQ(ssrc, rtp_modules_[i]->SSRC()); >+ rtp_states[ssrc] = rtp_modules_[i]->GetRtpState(); >+ } >+ >+ for (size_t i = 0; i < rtp_config_.rtx.ssrcs.size(); ++i) { >+ uint32_t ssrc = rtp_config_.rtx.ssrcs[i]; >+ rtp_states[ssrc] = rtp_modules_[i]->GetRtxState(); >+ } >+ >+ if (flexfec_sender_) { >+ uint32_t ssrc = rtp_config_.flexfec.ssrc; >+ rtp_states[ssrc] = flexfec_sender_->GetRtpState(); >+ } >+ >+ return rtp_states; >+} >+ >+std::map<uint32_t, RtpPayloadState> RtpVideoSender::GetRtpPayloadStates() >+ const { >+ rtc::CritScope lock(&crit_); >+ std::map<uint32_t, RtpPayloadState> payload_states; >+ for (const auto& param : params_) { >+ payload_states[param.ssrc()] = param.state(); >+ payload_states[param.ssrc()].shared_frame_id = shared_frame_id_; >+ } >+ return payload_states; >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.h >new file mode 100644 >index 00000000000..1735dc751ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender.h >@@ -0,0 +1,133 @@ >+/* >+ * Copyright (c) 2015 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. >+ */ >+ >+#ifndef CALL_RTP_VIDEO_SENDER_H_ >+#define CALL_RTP_VIDEO_SENDER_H_ >+ >+#include <map> >+#include <memory> >+#include <vector> >+ >+#include "api/call/transport.h" >+#include "api/video_codecs/video_encoder.h" >+#include "call/rtp_config.h" >+#include "call/rtp_payload_params.h" >+#include "call/rtp_transport_controller_send_interface.h" >+#include "call/rtp_video_sender_interface.h" >+#include "common_types.h" // NOLINT(build/include) >+#include "logging/rtc_event_log/rtc_event_log.h" >+#include "modules/rtp_rtcp/include/flexfec_sender.h" >+#include "modules/rtp_rtcp/source/rtp_video_header.h" >+#include "modules/utility/include/process_thread.h" >+#include "rtc_base/constructormagic.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/rate_limiter.h" >+#include "rtc_base/thread_annotations.h" >+#include "rtc_base/thread_checker.h" >+ >+namespace webrtc { >+ >+class RTPFragmentationHeader; >+class RtpRtcp; >+class RtpTransportControllerSendInterface; >+ >+// RtpVideoSender routes outgoing data to the correct sending RTP module, based >+// on the simulcast layer in RTPVideoHeader. >+class RtpVideoSender : public RtpVideoSenderInterface { >+ public: >+ // Rtp modules are assumed to be sorted in simulcast index order. >+ RtpVideoSender( >+ const std::vector<uint32_t>& ssrcs, >+ std::map<uint32_t, RtpState> suspended_ssrcs, >+ const std::map<uint32_t, RtpPayloadState>& states, >+ const RtpConfig& rtp_config, >+ const RtcpConfig& rtcp_config, >+ Transport* send_transport, >+ const RtpSenderObservers& observers, >+ RtpTransportControllerSendInterface* transport, >+ RtcEventLog* event_log, >+ RateLimiter* retransmission_limiter); // move inside RtpTransport >+ ~RtpVideoSender() override; >+ >+ // RegisterProcessThread register |module_process_thread| with those objects >+ // that use it. Registration has to happen on the thread were >+ // |module_process_thread| was created (libjingle's worker thread). >+ // TODO(perkj): Replace the use of |module_process_thread| with a TaskQueue, >+ // maybe |worker_queue|. >+ void RegisterProcessThread(ProcessThread* module_process_thread) override; >+ void DeRegisterProcessThread() override; >+ >+ // RtpVideoSender will only route packets if being active, all packets will be >+ // dropped otherwise. >+ void SetActive(bool active) override; >+ // Sets the sending status of the rtp modules and appropriately sets the >+ // payload router to active if any rtp modules are active. >+ void SetActiveModules(const std::vector<bool> active_modules) override; >+ bool IsActive() override; >+ >+ void OnNetworkAvailability(bool network_available) override; >+ std::map<uint32_t, RtpState> GetRtpStates() const override; >+ std::map<uint32_t, RtpPayloadState> GetRtpPayloadStates() const override; >+ >+ bool FecEnabled() const override; >+ >+ bool NackEnabled() const override; >+ >+ void DeliverRtcp(const uint8_t* packet, size_t length) override; >+ >+ void ProtectionRequest(const FecProtectionParams* delta_params, >+ const FecProtectionParams* key_params, >+ uint32_t* sent_video_rate_bps, >+ uint32_t* sent_nack_rate_bps, >+ uint32_t* sent_fec_rate_bps) override; >+ >+ void SetMaxRtpPacketSize(size_t max_rtp_packet_size) override; >+ >+ // Implements EncodedImageCallback. >+ // Returns 0 if the packet was routed / sent, -1 otherwise. >+ EncodedImageCallback::Result OnEncodedImage( >+ const EncodedImage& encoded_image, >+ const CodecSpecificInfo* codec_specific_info, >+ const RTPFragmentationHeader* fragmentation) override; >+ >+ void OnBitrateAllocationUpdated( >+ const VideoBitrateAllocation& bitrate) override; >+ >+ private: >+ void UpdateModuleSendingState() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); >+ void ConfigureProtection(const RtpConfig& rtp_config); >+ void ConfigureSsrcs(const RtpConfig& rtp_config); >+ >+ rtc::CriticalSection crit_; >+ bool active_ RTC_GUARDED_BY(crit_); >+ >+ ProcessThread* module_process_thread_; >+ rtc::ThreadChecker module_process_thread_checker_; >+ std::map<uint32_t, RtpState> suspended_ssrcs_; >+ >+ std::unique_ptr<FlexfecSender> flexfec_sender_; >+ // Rtp modules are assumed to be sorted in simulcast index order. >+ const std::vector<std::unique_ptr<RtpRtcp>> rtp_modules_; >+ const RtpConfig rtp_config_; >+ RtpTransportControllerSendInterface* const transport_; >+ >+ // When using the generic descriptor we want all simulcast streams to share >+ // one frame id space (so that the SFU can switch stream without having to >+ // rewrite the frame id), therefore |shared_frame_id| has to live in a place >+ // where we are aware of all the different streams. >+ int64_t shared_frame_id_ = 0; >+ std::vector<RtpPayloadParams> params_ RTC_GUARDED_BY(crit_); >+ >+ RTC_DISALLOW_COPY_AND_ASSIGN(RtpVideoSender); >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_RTP_VIDEO_SENDER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_interface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_interface.h >new file mode 100644 >index 00000000000..c69f1bab02a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_interface.h >@@ -0,0 +1,60 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef CALL_RTP_VIDEO_SENDER_INTERFACE_H_ >+#define CALL_RTP_VIDEO_SENDER_INTERFACE_H_ >+ >+#include <map> >+#include <vector> >+ >+#include "call/rtp_config.h" >+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >+#include "modules/utility/include/process_thread.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+ >+namespace webrtc { >+class VideoBitrateAllocation; >+struct FecProtectionParams; >+ >+class RtpVideoSenderInterface : public EncodedImageCallback { >+ public: >+ virtual void RegisterProcessThread(ProcessThread* module_process_thread) = 0; >+ virtual void DeRegisterProcessThread() = 0; >+ >+ // RtpVideoSender will only route packets if being active, all >+ // packets will be dropped otherwise. >+ virtual void SetActive(bool active) = 0; >+ // Sets the sending status of the rtp modules and appropriately sets the >+ // RtpVideoSender to active if any rtp modules are active. >+ virtual void SetActiveModules(const std::vector<bool> active_modules) = 0; >+ virtual bool IsActive() = 0; >+ >+ virtual void OnNetworkAvailability(bool network_available) = 0; >+ virtual std::map<uint32_t, RtpState> GetRtpStates() const = 0; >+ virtual std::map<uint32_t, RtpPayloadState> GetRtpPayloadStates() const = 0; >+ >+ virtual bool FecEnabled() const = 0; >+ >+ virtual bool NackEnabled() const = 0; >+ >+ virtual void DeliverRtcp(const uint8_t* packet, size_t length) = 0; >+ >+ virtual void ProtectionRequest(const FecProtectionParams* delta_params, >+ const FecProtectionParams* key_params, >+ uint32_t* sent_video_rate_bps, >+ uint32_t* sent_nack_rate_bps, >+ uint32_t* sent_fec_rate_bps) = 0; >+ >+ virtual void SetMaxRtpPacketSize(size_t max_rtp_packet_size) = 0; >+ virtual void OnBitrateAllocationUpdated( >+ const VideoBitrateAllocation& bitrate) = 0; >+}; >+} // namespace webrtc >+#endif // CALL_RTP_VIDEO_SENDER_INTERFACE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_unittest.cc >new file mode 100644 >index 00000000000..b819e696d93 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtp_video_sender_unittest.cc >@@ -0,0 +1,299 @@ >+/* >+ * Copyright (c) 2015 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 <memory> >+#include <string> >+ >+#include "call/rtp_transport_controller_send.h" >+#include "call/rtp_video_sender.h" >+#include "modules/video_coding/include/video_codec_interface.h" >+#include "rtc_base/rate_limiter.h" >+#include "test/field_trial.h" >+#include "test/gmock.h" >+#include "test/gtest.h" >+#include "test/mock_transport.h" >+#include "video/call_stats.h" >+#include "video/send_delay_stats.h" >+#include "video/send_statistics_proxy.h" >+ >+using ::testing::_; >+using ::testing::AnyNumber; >+using ::testing::Invoke; >+using ::testing::NiceMock; >+using ::testing::Return; >+using ::testing::Unused; >+ >+namespace webrtc { >+namespace { >+const int8_t kPayloadType = 96; >+const uint32_t kSsrc1 = 12345; >+const uint32_t kSsrc2 = 23456; >+const int16_t kInitialPictureId1 = 222; >+const int16_t kInitialPictureId2 = 44; >+const int16_t kInitialTl0PicIdx1 = 99; >+const int16_t kInitialTl0PicIdx2 = 199; >+const int64_t kRetransmitWindowSizeMs = 500; >+ >+class MockRtcpIntraFrameObserver : public RtcpIntraFrameObserver { >+ public: >+ MOCK_METHOD1(OnReceivedIntraFrameRequest, void(uint32_t)); >+}; >+ >+class MockOverheadObserver : public OverheadObserver { >+ public: >+ MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet)); >+}; >+ >+class MockCongestionObserver : public NetworkChangedObserver { >+ public: >+ MOCK_METHOD4(OnNetworkChanged, >+ void(uint32_t bitrate_bps, >+ uint8_t fraction_loss, >+ int64_t rtt_ms, >+ int64_t probing_interval_ms)); >+}; >+ >+RtpSenderObservers CreateObservers( >+ RtcpRttStats* rtcp_rtt_stats, >+ RtcpIntraFrameObserver* intra_frame_callback, >+ RtcpStatisticsCallback* rtcp_stats, >+ StreamDataCountersCallback* rtp_stats, >+ BitrateStatisticsObserver* bitrate_observer, >+ FrameCountObserver* frame_count_observer, >+ RtcpPacketTypeCounterObserver* rtcp_type_observer, >+ SendSideDelayObserver* send_delay_observer, >+ SendPacketObserver* send_packet_observer, >+ OverheadObserver* overhead_observer) { >+ RtpSenderObservers observers; >+ observers.rtcp_rtt_stats = rtcp_rtt_stats; >+ observers.intra_frame_callback = intra_frame_callback; >+ observers.rtcp_stats = rtcp_stats; >+ observers.rtp_stats = rtp_stats; >+ observers.bitrate_observer = bitrate_observer; >+ observers.frame_count_observer = frame_count_observer; >+ observers.rtcp_type_observer = rtcp_type_observer; >+ observers.send_delay_observer = send_delay_observer; >+ observers.send_packet_observer = send_packet_observer; >+ observers.overhead_observer = overhead_observer; >+ return observers; >+} >+ >+class RtpVideoSenderTestFixture { >+ public: >+ RtpVideoSenderTestFixture( >+ const std::vector<uint32_t>& ssrcs, >+ int payload_type, >+ const std::map<uint32_t, RtpPayloadState>& suspended_payload_states) >+ : clock_(0), >+ config_(&transport_), >+ send_delay_stats_(&clock_), >+ transport_controller_(&clock_, &event_log_, nullptr, bitrate_config_), >+ process_thread_(ProcessThread::Create("test_thread")), >+ call_stats_(&clock_, process_thread_.get()), >+ stats_proxy_(&clock_, >+ config_, >+ VideoEncoderConfig::ContentType::kRealtimeVideo), >+ retransmission_rate_limiter_(&clock_, kRetransmitWindowSizeMs) { >+ for (uint32_t ssrc : ssrcs) { >+ config_.rtp.ssrcs.push_back(ssrc); >+ } >+ config_.rtp.payload_type = payload_type; >+ std::map<uint32_t, RtpState> suspended_ssrcs; >+ router_ = absl::make_unique<RtpVideoSender>( >+ config_.rtp.ssrcs, suspended_ssrcs, suspended_payload_states, >+ config_.rtp, config_.rtcp, &transport_, >+ CreateObservers(&call_stats_, &encoder_feedback_, &stats_proxy_, >+ &stats_proxy_, &stats_proxy_, &stats_proxy_, >+ &stats_proxy_, &stats_proxy_, &send_delay_stats_, >+ &overhead_observer_), >+ &transport_controller_, &event_log_, &retransmission_rate_limiter_); >+ } >+ >+ RtpVideoSender* router() { return router_.get(); } >+ >+ private: >+ NiceMock<MockTransport> transport_; >+ NiceMock<MockCongestionObserver> congestion_observer_; >+ NiceMock<MockOverheadObserver> overhead_observer_; >+ NiceMock<MockRtcpIntraFrameObserver> encoder_feedback_; >+ SimulatedClock clock_; >+ RtcEventLogNullImpl event_log_; >+ VideoSendStream::Config config_; >+ SendDelayStats send_delay_stats_; >+ BitrateConstraints bitrate_config_; >+ RtpTransportControllerSend transport_controller_; >+ std::unique_ptr<ProcessThread> process_thread_; >+ CallStats call_stats_; >+ SendStatisticsProxy stats_proxy_; >+ RateLimiter retransmission_rate_limiter_; >+ std::unique_ptr<RtpVideoSender> router_; >+}; >+} // namespace >+ >+TEST(RtpVideoSenderTest, SendOnOneModule) { >+ uint8_t payload = 'a'; >+ EncodedImage encoded_image; >+ encoded_image._timeStamp = 1; >+ encoded_image.capture_time_ms_ = 2; >+ encoded_image._frameType = kVideoFrameKey; >+ encoded_image._buffer = &payload; >+ encoded_image._length = 1; >+ >+ RtpVideoSenderTestFixture test({kSsrc1}, kPayloadType, {}); >+ EXPECT_NE( >+ EncodedImageCallback::Result::OK, >+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); >+ >+ test.router()->SetActive(true); >+ EXPECT_EQ( >+ EncodedImageCallback::Result::OK, >+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); >+ >+ test.router()->SetActive(false); >+ EXPECT_NE( >+ EncodedImageCallback::Result::OK, >+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); >+ >+ test.router()->SetActive(true); >+ EXPECT_EQ( >+ EncodedImageCallback::Result::OK, >+ test.router()->OnEncodedImage(encoded_image, nullptr, nullptr).error); >+} >+ >+TEST(RtpVideoSenderTest, SendSimulcastSetActive) { >+ uint8_t payload = 'a'; >+ EncodedImage encoded_image; >+ encoded_image._timeStamp = 1; >+ encoded_image.capture_time_ms_ = 2; >+ encoded_image._frameType = kVideoFrameKey; >+ encoded_image._buffer = &payload; >+ encoded_image._length = 1; >+ >+ RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); >+ >+ CodecSpecificInfo codec_info_1; >+ memset(&codec_info_1, 0, sizeof(CodecSpecificInfo)); >+ codec_info_1.codecType = kVideoCodecVP8; >+ codec_info_1.codecSpecific.VP8.simulcastIdx = 0; >+ >+ test.router()->SetActive(true); >+ EXPECT_EQ(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr) >+ .error); >+ >+ CodecSpecificInfo codec_info_2; >+ memset(&codec_info_2, 0, sizeof(CodecSpecificInfo)); >+ codec_info_2.codecType = kVideoCodecVP8; >+ codec_info_2.codecSpecific.VP8.simulcastIdx = 1; >+ EXPECT_EQ(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr) >+ .error); >+ >+ // Inactive. >+ test.router()->SetActive(false); >+ EXPECT_NE(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr) >+ .error); >+ EXPECT_NE(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr) >+ .error); >+} >+ >+// Tests how setting individual rtp modules to active affects the overall >+// behavior of the payload router. First sets one module to active and checks >+// that outgoing data can be sent on this module, and checks that no data can >+// be sent if both modules are inactive. >+TEST(RtpVideoSenderTest, SendSimulcastSetActiveModules) { >+ uint8_t payload = 'a'; >+ EncodedImage encoded_image; >+ encoded_image._timeStamp = 1; >+ encoded_image.capture_time_ms_ = 2; >+ encoded_image._frameType = kVideoFrameKey; >+ encoded_image._buffer = &payload; >+ encoded_image._length = 1; >+ >+ RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); >+ CodecSpecificInfo codec_info_1; >+ memset(&codec_info_1, 0, sizeof(CodecSpecificInfo)); >+ codec_info_1.codecType = kVideoCodecVP8; >+ codec_info_1.codecSpecific.VP8.simulcastIdx = 0; >+ CodecSpecificInfo codec_info_2; >+ memset(&codec_info_2, 0, sizeof(CodecSpecificInfo)); >+ codec_info_2.codecType = kVideoCodecVP8; >+ codec_info_2.codecSpecific.VP8.simulcastIdx = 1; >+ >+ // Only setting one stream to active will still set the payload router to >+ // active and allow sending data on the active stream. >+ std::vector<bool> active_modules({true, false}); >+ test.router()->SetActiveModules(active_modules); >+ EXPECT_EQ(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr) >+ .error); >+ >+ // Setting both streams to inactive will turn the payload router to >+ // inactive. >+ active_modules = {false, false}; >+ test.router()->SetActiveModules(active_modules); >+ // An incoming encoded image will not ask the module to send outgoing data >+ // because the payload router is inactive. >+ EXPECT_NE(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_1, nullptr) >+ .error); >+ EXPECT_NE(EncodedImageCallback::Result::OK, >+ test.router() >+ ->OnEncodedImage(encoded_image, &codec_info_2, nullptr) >+ .error); >+} >+ >+TEST(RtpVideoSenderTest, CreateWithNoPreviousStates) { >+ RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, {}); >+ test.router()->SetActive(true); >+ >+ std::map<uint32_t, RtpPayloadState> initial_states = >+ test.router()->GetRtpPayloadStates(); >+ EXPECT_EQ(2u, initial_states.size()); >+ EXPECT_NE(initial_states.find(kSsrc1), initial_states.end()); >+ EXPECT_NE(initial_states.find(kSsrc2), initial_states.end()); >+} >+ >+TEST(RtpVideoSenderTest, CreateWithPreviousStates) { >+ const int64_t kState1SharedFrameId = 123; >+ const int64_t kState2SharedFrameId = 234; >+ RtpPayloadState state1; >+ state1.picture_id = kInitialPictureId1; >+ state1.tl0_pic_idx = kInitialTl0PicIdx1; >+ state1.shared_frame_id = kState1SharedFrameId; >+ RtpPayloadState state2; >+ state2.picture_id = kInitialPictureId2; >+ state2.tl0_pic_idx = kInitialTl0PicIdx2; >+ state2.shared_frame_id = kState2SharedFrameId; >+ std::map<uint32_t, RtpPayloadState> states = {{kSsrc1, state1}, >+ {kSsrc2, state2}}; >+ >+ RtpVideoSenderTestFixture test({kSsrc1, kSsrc2}, kPayloadType, states); >+ test.router()->SetActive(true); >+ >+ std::map<uint32_t, RtpPayloadState> initial_states = >+ test.router()->GetRtpPayloadStates(); >+ EXPECT_EQ(2u, initial_states.size()); >+ EXPECT_EQ(kInitialPictureId1, initial_states[kSsrc1].picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx1, initial_states[kSsrc1].tl0_pic_idx); >+ EXPECT_EQ(kInitialPictureId2, initial_states[kSsrc2].picture_id); >+ EXPECT_EQ(kInitialTl0PicIdx2, initial_states[kSsrc2].tl0_pic_idx); >+ EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc1].shared_frame_id); >+ EXPECT_EQ(kState2SharedFrameId, initial_states[kSsrc2].shared_frame_id); >+} >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream.cc >index 09200791f88..5d5fec19bda 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream.cc >@@ -63,8 +63,7 @@ void RtxReceiveStream::OnRtpPacket(const RtpPacketReceived& rtx_packet) { > media_packet.set_recovered(true); > > // Skip the RTX header. >- rtc::ArrayView<const uint8_t> rtx_payload = >- payload.subview(kRtxHeaderSize); >+ rtc::ArrayView<const uint8_t> rtx_payload = payload.subview(kRtxHeaderSize); > > uint8_t* media_payload = media_packet.AllocatePayload(rtx_payload.size()); > RTC_DCHECK(media_payload != nullptr); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream_unittest.cc >index 65ab82b0dd7..a9cfd53b3c9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/rtx_receive_stream_unittest.cc >@@ -36,7 +36,7 @@ constexpr uint8_t kRtxPacket[] = { > 0x11, 0x11, 0x11, 0x11, // Timestamp. > 0x22, 0x22, 0x22, 0x22, // SSRC. > // RTX header. >- 0x56, 0x57, // Orig seqno. >+ 0x56, 0x57, // Orig seqno. > // Payload. > 0xee, > }; >@@ -50,7 +50,7 @@ constexpr uint8_t kRtxPacketWithCVO[] = { > 0xbe, 0xde, 0x00, 0x01, // Extension header. > 0x30, 0x01, 0x00, 0x00, // 90 degree rotation. > // RTX header. >- 0x56, 0x57, // Orig seqno. >+ 0x56, 0x57, // Orig seqno. > // Payload. > 0xee, > }; >@@ -73,8 +73,8 @@ TEST(RtxReceiveStreamTest, RestoresPacketPayload) { > RtpPacketReceived rtx_packet; > EXPECT_TRUE(rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacket))); > >- EXPECT_CALL(media_sink, OnRtpPacket(_)).WillOnce(testing::Invoke( >- [](const RtpPacketReceived& packet) { >+ EXPECT_CALL(media_sink, OnRtpPacket(_)) >+ .WillOnce(testing::Invoke([](const RtpPacketReceived& packet) { > EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno); > EXPECT_EQ(packet.Ssrc(), kMediaSSRC); > EXPECT_EQ(packet.PayloadType(), kMediaPayloadType); >@@ -124,15 +124,15 @@ TEST(RtxReceiveStreamTest, CopiesRtpHeaderExtensions) { > RtpHeaderExtensionMap extension_map; > extension_map.RegisterByType(3, kRtpExtensionVideoRotation); > RtpPacketReceived rtx_packet(&extension_map); >- EXPECT_TRUE(rtx_packet.Parse( >- rtc::ArrayView<const uint8_t>(kRtxPacketWithCVO))); >+ EXPECT_TRUE( >+ rtx_packet.Parse(rtc::ArrayView<const uint8_t>(kRtxPacketWithCVO))); > > VideoRotation rotation = kVideoRotation_0; > EXPECT_TRUE(rtx_packet.GetExtension<VideoOrientation>(&rotation)); > EXPECT_EQ(kVideoRotation_90, rotation); > >- EXPECT_CALL(media_sink, OnRtpPacket(_)).WillOnce(testing::Invoke( >- [](const RtpPacketReceived& packet) { >+ EXPECT_CALL(media_sink, OnRtpPacket(_)) >+ .WillOnce(testing::Invoke([](const RtpPacketReceived& packet) { > EXPECT_EQ(packet.SequenceNumber(), kMediaSeqno); > EXPECT_EQ(packet.Ssrc(), kMediaSSRC); > EXPECT_EQ(packet.PayloadType(), kMediaPayloadType); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.cc >new file mode 100644 >index 00000000000..ee58dce7182 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.cc >@@ -0,0 +1,186 @@ >+/* >+ * Copyright 2018 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 "call/simulated_network.h" >+ >+#include <algorithm> >+#include <cmath> >+#include <utility> >+ >+namespace webrtc { >+ >+SimulatedNetwork::SimulatedNetwork(SimulatedNetwork::Config config, >+ uint64_t random_seed) >+ : random_(random_seed), bursting_(false) { >+ SetConfig(config); >+} >+ >+SimulatedNetwork::~SimulatedNetwork() = default; >+ >+void SimulatedNetwork::SetConfig(const SimulatedNetwork::Config& config) { >+ rtc::CritScope crit(&config_lock_); >+ config_ = config; // Shallow copy of the struct. >+ double prob_loss = config.loss_percent / 100.0; >+ if (config_.avg_burst_loss_length == -1) { >+ // Uniform loss >+ prob_loss_bursting_ = prob_loss; >+ prob_start_bursting_ = prob_loss; >+ } else { >+ // Lose packets according to a gilbert-elliot model. >+ int avg_burst_loss_length = config.avg_burst_loss_length; >+ int min_avg_burst_loss_length = std::ceil(prob_loss / (1 - prob_loss)); >+ >+ RTC_CHECK_GT(avg_burst_loss_length, min_avg_burst_loss_length) >+ << "For a total packet loss of " << config.loss_percent << "%% then" >+ << " avg_burst_loss_length must be " << min_avg_burst_loss_length + 1 >+ << " or higher."; >+ >+ prob_loss_bursting_ = (1.0 - 1.0 / avg_burst_loss_length); >+ prob_start_bursting_ = prob_loss / (1 - prob_loss) / avg_burst_loss_length; >+ } >+} >+ >+void SimulatedNetwork::PauseTransmissionUntil(int64_t until_us) { >+ rtc::CritScope crit(&config_lock_); >+ pause_transmission_until_us_ = until_us; >+} >+ >+bool SimulatedNetwork::EnqueuePacket(PacketInFlightInfo packet) { >+ Config config; >+ { >+ rtc::CritScope crit(&config_lock_); >+ config = config_; >+ } >+ rtc::CritScope crit(&process_lock_); >+ if (config.queue_length_packets > 0 && >+ capacity_link_.size() >= config.queue_length_packets) { >+ // Too many packet on the link, drop this one. >+ return false; >+ } >+ >+ // Delay introduced by the link capacity. >+ int64_t capacity_delay_ms = 0; >+ if (config.link_capacity_kbps > 0) { >+ // Using bytes per millisecond to avoid losing precision. >+ const int64_t bytes_per_millisecond = config.link_capacity_kbps / 8; >+ // To round to the closest millisecond we add half a milliseconds worth of >+ // bytes to the delay calculation. >+ capacity_delay_ms = (packet.size + capacity_delay_error_bytes_ + >+ bytes_per_millisecond / 2) / >+ bytes_per_millisecond; >+ capacity_delay_error_bytes_ += >+ packet.size - capacity_delay_ms * bytes_per_millisecond; >+ } >+ int64_t network_start_time_us = packet.send_time_us; >+ >+ { >+ rtc::CritScope crit(&config_lock_); >+ if (pause_transmission_until_us_) { >+ network_start_time_us = >+ std::max(network_start_time_us, *pause_transmission_until_us_); >+ pause_transmission_until_us_.reset(); >+ } >+ } >+ // Check if there already are packets on the link and change network start >+ // time forward if there is. >+ if (!capacity_link_.empty() && >+ network_start_time_us < capacity_link_.back().arrival_time_us) >+ network_start_time_us = capacity_link_.back().arrival_time_us; >+ >+ int64_t arrival_time_us = network_start_time_us + capacity_delay_ms * 1000; >+ capacity_link_.push({packet, arrival_time_us}); >+ return true; >+} >+ >+absl::optional<int64_t> SimulatedNetwork::NextDeliveryTimeUs() const { >+ if (!delay_link_.empty()) >+ return delay_link_.begin()->arrival_time_us; >+ return absl::nullopt; >+} >+std::vector<PacketDeliveryInfo> SimulatedNetwork::DequeueDeliverablePackets( >+ int64_t receive_time_us) { >+ int64_t time_now_us = receive_time_us; >+ Config config; >+ double prob_loss_bursting; >+ double prob_start_bursting; >+ { >+ rtc::CritScope crit(&config_lock_); >+ config = config_; >+ prob_loss_bursting = prob_loss_bursting_; >+ prob_start_bursting = prob_start_bursting_; >+ } >+ { >+ rtc::CritScope crit(&process_lock_); >+ // Check the capacity link first. >+ if (!capacity_link_.empty()) { >+ int64_t last_arrival_time_us = >+ delay_link_.empty() ? -1 : delay_link_.back().arrival_time_us; >+ bool needs_sort = false; >+ while (!capacity_link_.empty() && >+ time_now_us >= capacity_link_.front().arrival_time_us) { >+ // Time to get this packet. >+ PacketInfo packet = std::move(capacity_link_.front()); >+ capacity_link_.pop(); >+ >+ // Drop packets at an average rate of |config_.loss_percent| with >+ // and average loss burst length of |config_.avg_burst_loss_length|. >+ if ((bursting_ && random_.Rand<double>() < prob_loss_bursting) || >+ (!bursting_ && random_.Rand<double>() < prob_start_bursting)) { >+ bursting_ = true; >+ continue; >+ } else { >+ bursting_ = false; >+ } >+ >+ int64_t arrival_time_jitter_us = std::max( >+ random_.Gaussian(config.queue_delay_ms * 1000, >+ config.delay_standard_deviation_ms * 1000), >+ 0.0); >+ >+ // If reordering is not allowed then adjust arrival_time_jitter >+ // to make sure all packets are sent in order. >+ if (!config.allow_reordering && !delay_link_.empty() && >+ packet.arrival_time_us + arrival_time_jitter_us < >+ last_arrival_time_us) { >+ arrival_time_jitter_us = >+ last_arrival_time_us - packet.arrival_time_us; >+ } >+ packet.arrival_time_us += arrival_time_jitter_us; >+ if (packet.arrival_time_us >= last_arrival_time_us) { >+ last_arrival_time_us = packet.arrival_time_us; >+ } else { >+ needs_sort = true; >+ } >+ delay_link_.emplace_back(std::move(packet)); >+ } >+ >+ if (needs_sort) { >+ // Packet(s) arrived out of order, make sure list is sorted. >+ std::sort(delay_link_.begin(), delay_link_.end(), >+ [](const PacketInfo& p1, const PacketInfo& p2) { >+ return p1.arrival_time_us < p2.arrival_time_us; >+ }); >+ } >+ } >+ >+ std::vector<PacketDeliveryInfo> packets_to_deliver; >+ // Check the extra delay queue. >+ while (!delay_link_.empty() && >+ time_now_us >= delay_link_.front().arrival_time_us) { >+ PacketInfo packet_info = delay_link_.front(); >+ packets_to_deliver.emplace_back( >+ PacketDeliveryInfo(packet_info.packet, packet_info.arrival_time_us)); >+ delay_link_.pop_front(); >+ } >+ return packets_to_deliver; >+ } >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.h >new file mode 100644 >index 00000000000..0ddd1f85fc5 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/simulated_network.h >@@ -0,0 +1,80 @@ >+/* >+ * Copyright 2018 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. >+ */ >+#ifndef CALL_SIMULATED_NETWORK_H_ >+#define CALL_SIMULATED_NETWORK_H_ >+ >+#include <deque> >+#include <queue> >+#include <vector> >+ >+#include "absl/memory/memory.h" >+#include "absl/types/optional.h" >+#include "api/test/simulated_network.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/random.h" >+#include "rtc_base/thread_annotations.h" >+ >+namespace webrtc { >+ >+// Class simulating a network link. This is a simple and naive solution just >+// faking capacity and adding an extra transport delay in addition to the >+// capacity introduced delay. >+class SimulatedNetwork : public NetworkSimulationInterface { >+ public: >+ using Config = NetworkSimulationInterface::SimulatedNetworkConfig; >+ explicit SimulatedNetwork(Config config, uint64_t random_seed = 1); >+ ~SimulatedNetwork() override; >+ >+ // Sets a new configuration. This won't affect packets already in the pipe. >+ void SetConfig(const Config& config) override; >+ void PauseTransmissionUntil(int64_t until_us); >+ >+ // NetworkSimulationInterface >+ bool EnqueuePacket(PacketInFlightInfo packet) override; >+ std::vector<PacketDeliveryInfo> DequeueDeliverablePackets( >+ int64_t receive_time_us) override; >+ >+ absl::optional<int64_t> NextDeliveryTimeUs() const override; >+ >+ private: >+ struct PacketInfo { >+ PacketInFlightInfo packet; >+ int64_t arrival_time_us; >+ }; >+ rtc::CriticalSection config_lock_; >+ >+ // |process_lock| guards the data structures involved in delay and loss >+ // processes, such as the packet queues. >+ rtc::CriticalSection process_lock_; >+ std::queue<PacketInfo> capacity_link_ RTC_GUARDED_BY(process_lock_); >+ Random random_; >+ >+ std::deque<PacketInfo> delay_link_; >+ >+ // Link configuration. >+ Config config_ RTC_GUARDED_BY(config_lock_); >+ absl::optional<int64_t> pause_transmission_until_us_ >+ RTC_GUARDED_BY(config_lock_); >+ >+ // Are we currently dropping a burst of packets? >+ bool bursting_; >+ >+ // The probability to drop the packet if we are currently dropping a >+ // burst of packet >+ double prob_loss_bursting_ RTC_GUARDED_BY(config_lock_); >+ >+ // The probability to drop a burst of packets. >+ double prob_start_bursting_ RTC_GUARDED_BY(config_lock_); >+ int64_t capacity_delay_error_bytes_ = 0; >+}; >+ >+} // namespace webrtc >+ >+#endif // CALL_SIMULATED_NETWORK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/ssrc_binding_observer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/ssrc_binding_observer.h >index 73a8e8e5864..ada505610fa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/ssrc_binding_observer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/ssrc_binding_observer.h >@@ -12,8 +12,6 @@ > > #include <string> > >-#include "rtc_base/basictypes.h" >- > namespace webrtc { > > // With newer versions of SDP, SSRC is often not explicitly signaled and must >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/syncable.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/syncable.h >index a97990b2be0..a914793d78a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/syncable.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/syncable.h >@@ -16,7 +16,7 @@ > > #include <stdint.h> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > > namespace webrtc { > >@@ -34,7 +34,7 @@ class Syncable { > virtual ~Syncable(); > > virtual int id() const = 0; >- virtual rtc::Optional<Info> GetInfo() const = 0; >+ virtual absl::optional<Info> GetInfo() const = 0; > virtual uint32_t GetPlayoutTimestamp() const = 0; > virtual void SetMinimumPlayoutDelay(int delay_ms) = 0; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/test/fake_network_pipe_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/fake_network_pipe_unittest.cc >similarity index 62% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/test/fake_network_pipe_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/call/test/fake_network_pipe_unittest.cc >index 759003b294a..0578f33191e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/test/fake_network_pipe_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/fake_network_pipe_unittest.cc >@@ -8,12 +8,14 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include "call/fake_network_pipe.h" >+ > #include <memory> > > #include "call/call.h" >+#include "call/simulated_network.h" > #include "modules/rtp_rtcp/include/rtp_header_parser.h" > #include "system_wrappers/include/clock.h" >-#include "test/fake_network_pipe.h" > #include "test/gmock.h" > #include "test/gtest.h" > >@@ -24,37 +26,27 @@ using ::testing::Invoke; > > namespace webrtc { > >-class TestDemuxer : public Demuxer { >+class MockReceiver : public PacketReceiver { > public: >- void IncomingPacket(NetworkPacket* packet) { >- DeliverPacket(packet, PacketTime()); >- } >- >- MOCK_METHOD1(SetReceiver, void(PacketReceiver* receiver)); >- MOCK_METHOD2(DeliverPacket, >- void(const NetworkPacket* packet, >- const PacketTime& packet_time)); >+ MOCK_METHOD3(DeliverPacket, >+ DeliveryStatus(MediaType, rtc::CopyOnWriteBuffer, int64_t)); >+ virtual ~MockReceiver() = default; > }; > >-class ReorderTestDemuxer : public TestDemuxer { >+class ReorderTestReceiver : public MockReceiver { > public: >- void DeliverPacket(const NetworkPacket* packet, >- const PacketTime& packet_time) override { >- RTC_DCHECK_GE(packet->data_length(), sizeof(int)); >+ DeliveryStatus DeliverPacket(MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t /* packet_time_us */) override { >+ RTC_DCHECK_GE(packet.size(), sizeof(int)); > int seq_num; >- memcpy(&seq_num, packet->data(), sizeof(int)); >+ memcpy(&seq_num, packet.data<uint8_t>(), sizeof(int)); > delivered_sequence_numbers_.push_back(seq_num); >+ return DeliveryStatus::DELIVERY_OK; > } > std::vector<int> delivered_sequence_numbers_; > }; > >-class MockReceiver : public PacketReceiver { >- public: >- MOCK_METHOD4( >- DeliverPacket, >- DeliveryStatus(MediaType, const uint8_t*, size_t, const PacketTime&)); >-}; >- > class FakeNetworkPipeTest : public ::testing::Test { > public: > FakeNetworkPipeTest() : fake_clock_(12345) {} >@@ -67,7 +59,8 @@ class FakeNetworkPipeTest : public ::testing::Test { > // Set a sequence number for the packets by > // using the first bytes in the packet. > memcpy(packet.get(), &i, sizeof(int)); >- pipe->SendPacket(packet.get(), packet_size); >+ rtc::CopyOnWriteBuffer buffer(packet.get(), packet_size); >+ pipe->DeliverPacket(MediaType::ANY, buffer, /* packet_time_us */ -1); > } > } > >@@ -83,9 +76,9 @@ TEST_F(FakeNetworkPipeTest, CapacityTest) { > FakeNetworkPipe::Config config; > config.queue_length_packets = 20; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); > > // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to > // get through the pipe. >@@ -94,26 +87,26 @@ TEST_F(FakeNetworkPipeTest, CapacityTest) { > SendPackets(pipe.get(), kNumPackets, kPacketSize); > > // Time to get one packet through the link. >- const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, >- kPacketSize); >+ const int kPacketTimeMs = >+ PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Time haven't increased yet, so we souldn't get any packets. >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > > // Advance enough time to release one packet. > fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > > // Release all but one packet > fake_clock_.AdvanceTimeMilliseconds(9 * kPacketTimeMs - 1); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(8); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(8); > pipe->Process(); > > // And the last one. > fake_clock_.AdvanceTimeMilliseconds(1); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > >@@ -123,31 +116,31 @@ TEST_F(FakeNetworkPipeTest, ExtraDelayTest) { > config.queue_length_packets = 20; > config.queue_delay_ms = 100; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); > > const int kNumPackets = 2; > const int kPacketSize = 1000; > SendPackets(pipe.get(), kNumPackets, kPacketSize); > > // Time to get one packet through the link. >- const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, >- kPacketSize); >+ const int kPacketTimeMs = >+ PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Increase more than kPacketTimeMs, but not more than the extra delay. > fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > > // Advance the network delay to get the first packet. > fake_clock_.AdvanceTimeMilliseconds(config.queue_delay_ms); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > > // Advance one more kPacketTimeMs to get the last packet. > fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > >@@ -157,13 +150,13 @@ TEST_F(FakeNetworkPipeTest, QueueLengthTest) { > FakeNetworkPipe::Config config; > config.queue_length_packets = 2; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); > > const int kPacketSize = 1000; >- const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, >- kPacketSize); >+ const int kPacketTimeMs = >+ PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Send three packets and verify only 2 are delivered. > SendPackets(pipe.get(), 3, kPacketSize); >@@ -171,7 +164,7 @@ TEST_F(FakeNetworkPipeTest, QueueLengthTest) { > // Increase time enough to deliver all three packets, verify only two are > // delivered. > fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(2); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(2); > pipe->Process(); > } > >@@ -181,28 +174,28 @@ TEST_F(FakeNetworkPipeTest, StatisticsTest) { > config.queue_length_packets = 2; > config.queue_delay_ms = 20; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); > > const int kPacketSize = 1000; >- const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps, >- kPacketSize); >+ const int kPacketTimeMs = >+ PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Send three packets and verify only 2 are delivered. > SendPackets(pipe.get(), 3, kPacketSize); > fake_clock_.AdvanceTimeMilliseconds(3 * kPacketTimeMs + > config.queue_delay_ms); > >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(2); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(2); > pipe->Process(); > > // Packet 1: kPacketTimeMs + config.queue_delay_ms, > // packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average. > EXPECT_EQ(pipe->AverageDelay(), 170); >- EXPECT_EQ(pipe->sent_packets(), 2u); >- EXPECT_EQ(pipe->dropped_packets(), 1u); >- EXPECT_EQ(pipe->PercentageLoss(), 1/3.f); >+ EXPECT_EQ(pipe->SentPackets(), 2u); >+ EXPECT_EQ(pipe->DroppedPackets(), 1u); >+ EXPECT_EQ(pipe->PercentageLoss(), 1 / 3.f); > } > > // Change the link capacity half-way through the test and verify that the >@@ -211,9 +204,11 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) { > FakeNetworkPipe::Config config; > config.queue_length_packets = 20; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); >+ SimulatedNetwork* simulated_network = network.get(); >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); > > // Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to > // get through the pipe. >@@ -225,19 +220,19 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) { > int packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Time hasn't increased yet, so we souldn't get any packets. >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > > // Advance time in steps to release one packet at a time. > for (int i = 0; i < kNumPackets; ++i) { > fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > > // Change the capacity. > config.link_capacity_kbps /= 2; // Reduce to 50%. >- pipe->SetConfig(config); >+ simulated_network->SetConfig(config); > > // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two > // seconds to get them through the pipe. >@@ -247,20 +242,20 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithEmptyPipeTest) { > packet_time_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Time hasn't increased yet, so we souldn't get any packets. >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > > // Advance time in steps to release one packet at a time. > for (int i = 0; i < kNumPackets; ++i) { > fake_clock_.AdvanceTimeMilliseconds(packet_time_ms); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > > // Check that all the packets were sent. >- EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->sent_packets()); >+ EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->SentPackets()); > fake_clock_.AdvanceTimeMilliseconds(pipe->TimeUntilNextProcess()); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > } > >@@ -270,9 +265,11 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) { > FakeNetworkPipe::Config config; > config.queue_length_packets = 20; > config.link_capacity_kbps = 80; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ MockReceiver receiver; >+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); >+ SimulatedNetwork* simulated_network = network.get(); >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); > > // Add 10 packets of 1000 bytes, = 80 kb. > const int kNumPackets = 10; >@@ -284,7 +281,7 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) { > > // Change the capacity. > config.link_capacity_kbps *= 2; // Double the capacity. >- pipe->SetConfig(config); >+ simulated_network->SetConfig(config); > > // Add another 10 packets of 1000 bytes, = 80 kb, and verify it takes two > // seconds to get them through the pipe. >@@ -294,27 +291,27 @@ TEST_F(FakeNetworkPipeTest, ChangingCapacityWithPacketsInPipeTest) { > int packet_time_2_ms = PacketTimeMs(config.link_capacity_kbps, kPacketSize); > > // Time hasn't increased yet, so we souldn't get any packets. >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > > // Advance time in steps to release one packet at a time. > for (int i = 0; i < kNumPackets; ++i) { > fake_clock_.AdvanceTimeMilliseconds(packet_time_1_ms); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > > // Advance time in steps to release one packet at a time. > for (int i = 0; i < kNumPackets; ++i) { > fake_clock_.AdvanceTimeMilliseconds(packet_time_2_ms); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(1); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); > pipe->Process(); > } > > // Check that all the packets were sent. >- EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->sent_packets()); >+ EXPECT_EQ(static_cast<size_t>(2 * kNumPackets), pipe->SentPackets()); > fake_clock_.AdvanceTimeMilliseconds(pipe->TimeUntilNextProcess()); >- EXPECT_CALL(*demuxer, DeliverPacket(_, _)).Times(0); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); > pipe->Process(); > } > >@@ -325,9 +322,11 @@ TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) { > config.link_capacity_kbps = 800; > config.queue_delay_ms = 100; > config.delay_standard_deviation_ms = 10; >- ReorderTestDemuxer* demuxer = new ReorderTestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ ReorderTestReceiver receiver; >+ std::unique_ptr<SimulatedNetwork> network(new SimulatedNetwork(config)); >+ SimulatedNetwork* simulated_network = network.get(); >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, std::move(network), &receiver)); > > const uint32_t kNumPackets = 100; > const int kPacketSize = 10; >@@ -336,26 +335,26 @@ TEST_F(FakeNetworkPipeTest, DisallowReorderingThenAllowReordering) { > pipe->Process(); > > // Confirm that all packets have been delivered in order. >- EXPECT_EQ(kNumPackets, demuxer->delivered_sequence_numbers_.size()); >+ EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size()); > int last_seq_num = -1; >- for (int seq_num : demuxer->delivered_sequence_numbers_) { >+ for (int seq_num : receiver.delivered_sequence_numbers_) { > EXPECT_GT(seq_num, last_seq_num); > last_seq_num = seq_num; > } > > config.allow_reordering = true; >- pipe->SetConfig(config); >+ simulated_network->SetConfig(config); > SendPackets(pipe.get(), kNumPackets, kPacketSize); > fake_clock_.AdvanceTimeMilliseconds(1000); >- demuxer->delivered_sequence_numbers_.clear(); >+ receiver.delivered_sequence_numbers_.clear(); > pipe->Process(); > > // Confirm that all packets have been delivered > // and that reordering has occured. >- EXPECT_EQ(kNumPackets, demuxer->delivered_sequence_numbers_.size()); >+ EXPECT_EQ(kNumPackets, receiver.delivered_sequence_numbers_.size()); > bool reordering_has_occured = false; > last_seq_num = -1; >- for (int seq_num : demuxer->delivered_sequence_numbers_) { >+ for (int seq_num : receiver.delivered_sequence_numbers_) { > if (last_seq_num > seq_num) { > reordering_has_occured = true; > break; >@@ -375,26 +374,26 @@ TEST_F(FakeNetworkPipeTest, BurstLoss) { > config.queue_length_packets = kNumPackets; > config.loss_percent = kLossPercent; > config.avg_burst_loss_length = kAvgBurstLength; >- ReorderTestDemuxer* demuxer = new ReorderTestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >+ ReorderTestReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); > > SendPackets(pipe.get(), kNumPackets, kPacketSize); > fake_clock_.AdvanceTimeMilliseconds(1000); > pipe->Process(); > > // Check that the average loss is |kLossPercent| percent. >- int lost_packets = kNumPackets - demuxer->delivered_sequence_numbers_.size(); >+ int lost_packets = kNumPackets - receiver.delivered_sequence_numbers_.size(); > double loss_fraction = lost_packets / static_cast<double>(kNumPackets); > > EXPECT_NEAR(kLossPercent / 100.0, loss_fraction, 0.05); > > // Find the number of bursts that has occurred. >- size_t received_packets = demuxer->delivered_sequence_numbers_.size(); >+ size_t received_packets = receiver.delivered_sequence_numbers_.size(); > int num_bursts = 0; > for (size_t i = 0; i < received_packets - 1; ++i) { >- int diff = demuxer->delivered_sequence_numbers_[i + 1] - >- demuxer->delivered_sequence_numbers_[i]; >+ int diff = receiver.delivered_sequence_numbers_[i + 1] - >+ receiver.delivered_sequence_numbers_[i]; > if (diff > 1) > ++num_bursts; > } >@@ -406,40 +405,27 @@ TEST_F(FakeNetworkPipeTest, BurstLoss) { > > TEST_F(FakeNetworkPipeTest, SetReceiver) { > FakeNetworkPipe::Config config; >- TestDemuxer* demuxer = new TestDemuxer(); >- std::unique_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe( >- &fake_clock_, config, std::unique_ptr<Demuxer>(demuxer))); >- MockReceiver packet_receiver; >- EXPECT_CALL(*demuxer, SetReceiver(&packet_receiver)).Times(1); >- pipe->SetReceiver(&packet_receiver); >-} >+ config.link_capacity_kbps = 800; >+ MockReceiver receiver; >+ std::unique_ptr<FakeNetworkPipe> pipe( >+ new FakeNetworkPipe(&fake_clock_, config, &receiver)); >+ >+ const int kPacketSize = 1000; >+ const int kPacketTimeMs = >+ PacketTimeMs(config.link_capacity_kbps, kPacketSize); >+ SendPackets(pipe.get(), 1, kPacketSize); >+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(1); >+ pipe->Process(); >+ >+ MockReceiver new_receiver; >+ pipe->SetReceiver(&new_receiver); > >-TEST(DemuxerImplTest, Demuxing) { >- constexpr uint8_t kVideoPayloadType = 100; >- constexpr uint8_t kAudioPayloadType = 101; >- constexpr int64_t kTimeNow = 12345; >- constexpr int64_t kArrivalTime = kTimeNow - 1; >- constexpr size_t kPacketSize = 10; >- DemuxerImpl demuxer({{kVideoPayloadType, MediaType::VIDEO}, >- {kAudioPayloadType, MediaType::AUDIO}}); >- >- MockReceiver mock_receiver; >- demuxer.SetReceiver(&mock_receiver); >- >- std::vector<uint8_t> data(kPacketSize); >- data[1] = kVideoPayloadType; >- std::unique_ptr<NetworkPacket> packet( >- new NetworkPacket(&data[0], kPacketSize, kTimeNow, kArrivalTime)); >- EXPECT_CALL(mock_receiver, DeliverPacket(MediaType::VIDEO, _, _, _)) >- .WillOnce(Return(PacketReceiver::DELIVERY_OK)); >- demuxer.DeliverPacket(packet.get(), PacketTime()); >- >- data[1] = kAudioPayloadType; >- packet.reset( >- new NetworkPacket(&data[0], kPacketSize, kTimeNow, kArrivalTime)); >- EXPECT_CALL(mock_receiver, DeliverPacket(MediaType::AUDIO, _, _, _)) >- .WillOnce(Return(PacketReceiver::DELIVERY_OK)); >- demuxer.DeliverPacket(packet.get(), PacketTime()); >+ SendPackets(pipe.get(), 1, kPacketSize); >+ fake_clock_.AdvanceTimeMilliseconds(kPacketTimeMs); >+ EXPECT_CALL(receiver, DeliverPacket(_, _, _)).Times(0); >+ EXPECT_CALL(new_receiver, DeliverPacket(_, _, _)).Times(1); >+ pipe->Process(); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_audio_send_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_audio_send_stream.h >index 4eb11663166..489e826d0eb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_audio_send_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_audio_send_stream.h >@@ -26,14 +26,14 @@ class MockAudioSendStream : public AudioSendStream { > MOCK_METHOD0(Start, void()); > MOCK_METHOD0(Stop, void()); > // GMock doesn't like move-only types, such as std::unique_ptr. >- virtual void SendAudioData( >- std::unique_ptr<webrtc::AudioFrame> audio_frame) { >+ virtual void SendAudioData(std::unique_ptr<webrtc::AudioFrame> audio_frame) { > SendAudioDataForMock(audio_frame.get()); > } >- MOCK_METHOD1(SendAudioDataForMock, >- void(webrtc::AudioFrame* audio_frame)); >+ MOCK_METHOD1(SendAudioDataForMock, void(webrtc::AudioFrame* audio_frame)); > MOCK_METHOD4(SendTelephoneEvent, >- bool(int payload_type, int payload_frequency, int event, >+ bool(int payload_type, >+ int payload_frequency, >+ int event, > int duration_ms)); > MOCK_METHOD1(SetMuted, void(bool muted)); > MOCK_CONST_METHOD0(GetStats, Stats()); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_bitrate_allocator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_bitrate_allocator.h >new file mode 100644 >index 00000000000..714c02541f1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_bitrate_allocator.h >@@ -0,0 +1,27 @@ >+/* >+ * Copyright 2018 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. >+ */ >+#ifndef CALL_TEST_MOCK_BITRATE_ALLOCATOR_H_ >+#define CALL_TEST_MOCK_BITRATE_ALLOCATOR_H_ >+ >+#include <string> >+ >+#include "call/bitrate_allocator.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+class MockBitrateAllocator : public BitrateAllocatorInterface { >+ public: >+ MOCK_METHOD2(AddObserver, >+ void(BitrateAllocatorObserver*, MediaStreamAllocationConfig)); >+ MOCK_METHOD1(RemoveObserver, void(BitrateAllocatorObserver*)); >+ MOCK_METHOD1(GetStartBitrate, int(BitrateAllocatorObserver*)); >+}; >+} // namespace webrtc >+#endif // CALL_TEST_MOCK_BITRATE_ALLOCATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_rtp_transport_controller_send.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_rtp_transport_controller_send.h >new file mode 100644 >index 00000000000..828b030378b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/test/mock_rtp_transport_controller_send.h >@@ -0,0 +1,70 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef CALL_TEST_MOCK_RTP_TRANSPORT_CONTROLLER_SEND_H_ >+#define CALL_TEST_MOCK_RTP_TRANSPORT_CONTROLLER_SEND_H_ >+ >+#include <map> >+#include <string> >+#include <vector> >+ >+#include "api/bitrate_constraints.h" >+#include "call/rtp_transport_controller_send_interface.h" >+#include "modules/congestion_controller/include/network_changed_observer.h" >+#include "modules/pacing/packet_router.h" >+#include "rtc_base/networkroute.h" >+#include "rtc_base/rate_limiter.h" >+#include "rtc_base/socket.h" >+#include "test/gmock.h" >+ >+namespace webrtc { >+ >+class MockRtpTransportControllerSend >+ : public RtpTransportControllerSendInterface { >+ public: >+ MOCK_METHOD8( >+ CreateRtpVideoSender, >+ RtpVideoSenderInterface*(const std::vector<uint32_t>&, >+ std::map<uint32_t, RtpState>, >+ const std::map<uint32_t, RtpPayloadState>&, >+ const RtpConfig&, >+ const RtcpConfig&, >+ Transport*, >+ const RtpSenderObservers&, >+ RtcEventLog*)); >+ MOCK_METHOD1(DestroyRtpVideoSender, void(RtpVideoSenderInterface*)); >+ MOCK_METHOD0(GetWorkerQueue, rtc::TaskQueue*()); >+ MOCK_METHOD0(packet_router, PacketRouter*()); >+ MOCK_METHOD0(transport_feedback_observer, TransportFeedbackObserver*()); >+ MOCK_METHOD0(packet_sender, RtpPacketSender*()); >+ MOCK_CONST_METHOD0(keepalive_config, RtpKeepAliveConfig&()); >+ MOCK_METHOD3(SetAllocatedSendBitrateLimits, void(int, int, int)); >+ MOCK_METHOD1(SetPacingFactor, void(float)); >+ MOCK_METHOD1(SetQueueTimeLimit, void(int)); >+ MOCK_METHOD0(GetCallStatsObserver, CallStatsObserver*()); >+ MOCK_METHOD1(RegisterPacketFeedbackObserver, void(PacketFeedbackObserver*)); >+ MOCK_METHOD1(DeRegisterPacketFeedbackObserver, void(PacketFeedbackObserver*)); >+ MOCK_METHOD1(RegisterTargetTransferRateObserver, >+ void(TargetTransferRateObserver*)); >+ MOCK_METHOD2(OnNetworkRouteChanged, >+ void(const std::string&, const rtc::NetworkRoute&)); >+ MOCK_METHOD1(OnNetworkAvailability, void(bool)); >+ MOCK_METHOD0(GetBandwidthObserver, RtcpBandwidthObserver*()); >+ MOCK_CONST_METHOD0(GetPacerQueuingDelayMs, int64_t()); >+ MOCK_CONST_METHOD0(GetFirstPacketTimeMs, int64_t()); >+ MOCK_METHOD1(SetPerPacketFeedbackAvailable, void(bool)); >+ MOCK_METHOD1(EnablePeriodicAlrProbing, void(bool)); >+ MOCK_METHOD1(OnSentPacket, void(const rtc::SentPacket&)); >+ MOCK_METHOD1(SetSdpBitrateParameters, void(const BitrateConstraints&)); >+ MOCK_METHOD1(SetClientBitratePreferences, void(const BitrateSettings&)); >+ MOCK_METHOD1(SetAllocatedBitrateWithoutFeedback, void(uint32_t)); >+}; >+} // namespace webrtc >+#endif // CALL_TEST_MOCK_RTP_TRANSPORT_CONTROLLER_SEND_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.cc >index f338805746d..7662afff72d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.cc >@@ -9,6 +9,7 @@ > */ > > #include "call/video_receive_stream.h" >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > >@@ -17,7 +18,8 @@ VideoReceiveStream::Decoder::Decoder(const Decoder&) = default; > VideoReceiveStream::Decoder::~Decoder() = default; > > std::string VideoReceiveStream::Decoder::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{decoder: " << (decoder ? "(VideoDecoder)" : "nullptr"); > ss << ", payload_type: " << payload_type; > ss << ", payload_name: " << payload_name; >@@ -34,7 +36,8 @@ VideoReceiveStream::Stats::Stats() = default; > VideoReceiveStream::Stats::~Stats() = default; > > std::string VideoReceiveStream::Stats::ToString(int64_t time_ms) const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "VideoReceiveStream stats: " << time_ms << ", {ssrc: " << ssrc << ", "; > ss << "total_bps: " << total_bitrate_bps << ", "; > ss << "width: " << width << ", "; >@@ -71,7 +74,8 @@ VideoReceiveStream::Config& VideoReceiveStream::Config::operator=(Config&&) = > VideoReceiveStream::Config::Config::~Config() = default; > > std::string VideoReceiveStream::Config::ToString() const { >- std::stringstream ss; >+ char buf[4 * 1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{decoders: ["; > for (size_t i = 0; i < decoders.size(); ++i) { > ss << decoders[i].ToString(); >@@ -84,8 +88,6 @@ std::string VideoReceiveStream::Config::ToString() const { > ss << ", render_delay_ms: " << render_delay_ms; > if (!sync_group.empty()) > ss << ", sync_group: " << sync_group; >- ss << ", pre_decode_callback: " >- << (pre_decode_callback ? "(EncodedFrameObserver)" : "nullptr"); > ss << ", target_delay_ms: " << target_delay_ms; > ss << '}'; > >@@ -97,7 +99,8 @@ VideoReceiveStream::Config::Rtp::Rtp(const Rtp&) = default; > VideoReceiveStream::Config::Rtp::~Rtp() = default; > > std::string VideoReceiveStream::Config::Rtp::ToString() const { >- std::stringstream ss; >+ char buf[2 * 1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "{remote_ssrc: " << remote_ssrc; > ss << ", local_ssrc: " << local_ssrc; > ss << ", rtcp_mode: " >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.h >index 1adc696461a..5009ddb43f4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_receive_stream.h >@@ -16,12 +16,12 @@ > #include <string> > #include <vector> > >-#include "api/rtp_headers.h" > #include "api/call/transport.h" >+#include "api/rtp_headers.h" > #include "api/rtpparameters.h" > #include "api/video/video_content_type.h" >+#include "api/video/video_sink_interface.h" > #include "api/video/video_timing.h" >-#include "api/videosinkinterface.h" > #include "call/rtp_config.h" > #include "common_types.h" // NOLINT(build/include) > #include "common_video/include/frame_callback.h" >@@ -82,7 +82,7 @@ class VideoReceiveStream { > int render_delay_ms = 10; > int64_t interframe_delay_max_ms = -1; > uint32_t frames_decoded = 0; >- rtc::Optional<uint64_t> qp_sum; >+ absl::optional<uint64_t> qp_sum; > > int current_payload_type = -1; > >@@ -104,7 +104,7 @@ class VideoReceiveStream { > > // Timing frame info: all important timestamps for a full lifetime of a > // single 'timing frame'. >- rtc::Optional<webrtc::TimingFrameInfo> timing_frame_info; >+ absl::optional<webrtc::TimingFrameInfo> timing_frame_info; > }; > > struct Config { >@@ -213,11 +213,6 @@ class VideoReceiveStream { > // to one of the audio streams. > std::string sync_group; > >- // Called for each incoming video frame, i.e. in encoded state. E.g. used >- // when >- // saving the stream to a file. 'nullptr' disables the callback. >- EncodedFrameObserver* pre_decode_callback = nullptr; >- > // Target delay in milliseconds. A positive value indicates this stream is > // used for streaming instead of a real-time call. > int target_delay_ms = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.cc >index 4f8c059ee42..6b93fe28238 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.cc >@@ -9,6 +9,7 @@ > */ > > #include "call/video_send_stream.h" >+#include "rtc_base/strings/string_builder.h" > > namespace webrtc { > >@@ -16,7 +17,8 @@ VideoSendStream::StreamStats::StreamStats() = default; > VideoSendStream::StreamStats::~StreamStats() = default; > > std::string VideoSendStream::StreamStats::ToString() const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "width: " << width << ", "; > ss << "height: " << height << ", "; > ss << "key: " << frame_counts.key_frames << ", "; >@@ -37,7 +39,8 @@ VideoSendStream::Stats::Stats() = default; > VideoSendStream::Stats::~Stats() = default; > > std::string VideoSendStream::Stats::ToString(int64_t time_ms) const { >- std::stringstream ss; >+ char buf[1024]; >+ rtc::SimpleStringBuilder ss(buf); > ss << "VideoSendStream stats: " << time_ms << ", {"; > ss << "input_fps: " << input_frame_rate << ", "; > ss << "encode_fps: " << encode_frame_rate << ", "; >@@ -45,7 +48,6 @@ std::string VideoSendStream::Stats::ToString(int64_t time_ms) const { > ss << "encode_usage_perc: " << encode_usage_percent << ", "; > ss << "target_bps: " << target_media_bitrate_bps << ", "; > ss << "media_bps: " << media_bitrate_bps << ", "; >- ss << "preferred_media_bitrate_bps: " << preferred_media_bitrate_bps << ", "; > ss << "suspended: " << (suspended ? "true" : "false") << ", "; > ss << "bw_adapted: " << (bw_limited_resolution ? "true" : "false"); > ss << '}'; >@@ -68,9 +70,12 @@ VideoSendStream::Config& VideoSendStream::Config::operator=(Config&&) = default; > VideoSendStream::Config::Config::~Config() = default; > > std::string VideoSendStream::Config::ToString() const { >- std::stringstream ss; >- ss << "{encoder_settings: " << encoder_settings.ToString(); >+ char buf[2 * 1024]; >+ rtc::SimpleStringBuilder ss(buf); >+ ss << "{encoder_settings: { experiment_cpu_load_estimator: " >+ << (encoder_settings.experiment_cpu_load_estimator ? "on" : "off") << "}}"; > ss << ", rtp: " << rtp.ToString(); >+ ss << ", rtcp: " << rtcp.ToString(); > ss << ", pre_encode_callback: " > << (pre_encode_callback ? "(VideoSinkInterface)" : "nullptr"); > ss << ", post_encode_callback: " >@@ -83,80 +88,4 @@ std::string VideoSendStream::Config::ToString() const { > return ss.str(); > } > >-std::string VideoSendStream::Config::EncoderSettings::ToString() const { >- std::stringstream ss; >- ss << "{payload_name: " << payload_name; >- ss << ", payload_type: " << payload_type; >- ss << ", encoder: " << (encoder ? "(VideoEncoder)" : "nullptr"); >- ss << '}'; >- return ss.str(); >-} >- >-VideoSendStream::Config::Rtp::Rtp() = default; >-VideoSendStream::Config::Rtp::Rtp(const Rtp&) = default; >-VideoSendStream::Config::Rtp::~Rtp() = default; >- >-VideoSendStream::Config::Rtp::Flexfec::Flexfec() = default; >-VideoSendStream::Config::Rtp::Flexfec::Flexfec(const Flexfec&) = default; >-VideoSendStream::Config::Rtp::Flexfec::~Flexfec() = default; >- >-std::string VideoSendStream::Config::Rtp::ToString() const { >- std::stringstream ss; >- ss << "{ssrcs: ["; >- for (size_t i = 0; i < ssrcs.size(); ++i) { >- ss << ssrcs[i]; >- if (i != ssrcs.size() - 1) >- ss << ", "; >- } >- ss << ']'; >- ss << ", rtcp_mode: " >- << (rtcp_mode == RtcpMode::kCompound ? "RtcpMode::kCompound" >- : "RtcpMode::kReducedSize"); >- ss << ", max_packet_size: " << max_packet_size; >- ss << ", extensions: ["; >- for (size_t i = 0; i < extensions.size(); ++i) { >- ss << extensions[i].ToString(); >- if (i != extensions.size() - 1) >- ss << ", "; >- } >- ss << ']'; >- >- ss << ", nack: {rtp_history_ms: " << nack.rtp_history_ms << '}'; >- ss << ", ulpfec: " << ulpfec.ToString(); >- >- ss << ", flexfec: {payload_type: " << flexfec.payload_type; >- ss << ", ssrc: " << flexfec.ssrc; >- ss << ", protected_media_ssrcs: ["; >- for (size_t i = 0; i < flexfec.protected_media_ssrcs.size(); ++i) { >- ss << flexfec.protected_media_ssrcs[i]; >- if (i != flexfec.protected_media_ssrcs.size() - 1) >- ss << ", "; >- } >- ss << "]}"; >- >- ss << ", rtx: " << rtx.ToString(); >- ss << ", c_name: " << c_name; >- ss << '}'; >- return ss.str(); >-} >- >-VideoSendStream::Config::Rtp::Rtx::Rtx() = default; >-VideoSendStream::Config::Rtp::Rtx::Rtx(const Rtx&) = default; >-VideoSendStream::Config::Rtp::Rtx::~Rtx() = default; >- >-std::string VideoSendStream::Config::Rtp::Rtx::ToString() const { >- std::stringstream ss; >- ss << "{ssrcs: ["; >- for (size_t i = 0; i < ssrcs.size(); ++i) { >- ss << ssrcs[i]; >- if (i != ssrcs.size() - 1) >- ss << ", "; >- } >- ss << ']'; >- >- ss << ", payload_type: " << payload_type; >- ss << '}'; >- return ss.str(); >-} >- > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.h >index a3c6f4f13aa..ef98ae4094e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/call/video_send_stream.h >@@ -17,12 +17,12 @@ > #include <vector> > > #include "api/call/transport.h" >-#include "api/rtpparameters.h" >-#include "api/rtp_headers.h" >-#include "api/videosinkinterface.h" >-#include "api/videosourceinterface.h" >+#include "api/video/video_sink_interface.h" >+#include "api/video/video_source_interface.h" >+#include "api/video/video_stream_encoder_settings.h" >+#include "api/video_codecs/video_encoder_config.h" >+#include "api/video_codecs/video_encoder_factory.h" > #include "call/rtp_config.h" >-#include "call/video_config.h" > #include "common_types.h" // NOLINT(build/include) > #include "common_video/include/frame_callback.h" > #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >@@ -30,8 +30,6 @@ > > namespace webrtc { > >-class VideoEncoder; >- > class VideoSendStream { > public: > struct StreamStats { >@@ -69,15 +67,12 @@ class VideoSendStream { > uint32_t frames_dropped_by_encoder_queue = 0; > uint32_t frames_dropped_by_rate_limiter = 0; > uint32_t frames_dropped_by_encoder = 0; >- rtc::Optional<uint64_t> qp_sum; >+ absl::optional<uint64_t> qp_sum; > // Bitrate the encoder is currently configured to use due to bandwidth > // limitations. > int target_media_bitrate_bps = 0; > // Bitrate the encoder is actually producing. > int media_bitrate_bps = 0; >- // Media bitrate this VideoSendStream is configured to prefer if there are >- // no bandwidth limitations. >- int preferred_media_bitrate_bps = 0; > bool suspended = false; > bool bw_limited_resolution = false; > bool cpu_limited_resolution = false; >@@ -91,6 +86,7 @@ class VideoSendStream { > std::map<uint32_t, StreamStats> substreams; > webrtc::VideoContentType content_type = > webrtc::VideoContentType::UNSPECIFIED; >+ uint32_t huge_frames_sent = 0; > }; > > struct Config { >@@ -109,93 +105,11 @@ class VideoSendStream { > > std::string ToString() const; > >- struct EncoderSettings { >- EncoderSettings() = default; >- EncoderSettings(std::string payload_name, >- int payload_type, >- VideoEncoder* encoder) >- : payload_name(std::move(payload_name)), >- payload_type(payload_type), >- encoder(encoder) {} >- std::string ToString() const; >- >- std::string payload_name; >- int payload_type = -1; >- >- // TODO(sophiechang): Delete this field when no one is using internal >- // sources anymore. >- bool internal_source = false; >- >- // Allow 100% encoder utilization. Used for HW encoders where CPU isn't >- // expected to be the limiting factor, but a chip could be running at >- // 30fps (for example) exactly. >- bool full_overuse_time = false; >- >- // Uninitialized VideoEncoder instance to be used for encoding. Will be >- // initialized from inside the VideoSendStream. >- VideoEncoder* encoder = nullptr; >- } encoder_settings; >- >- static const size_t kDefaultMaxPacketSize = 1500 - 40; // TCP over IPv4. >- struct Rtp { >- Rtp(); >- Rtp(const Rtp&); >- ~Rtp(); >- std::string ToString() const; >- >- std::vector<uint32_t> ssrcs; >- >- // See RtcpMode for description. >- RtcpMode rtcp_mode = RtcpMode::kCompound; >- >- // Max RTP packet size delivered to send transport from VideoEngine. >- size_t max_packet_size = kDefaultMaxPacketSize; >- >- // RTP header extensions to use for this send stream. >- std::vector<RtpExtension> extensions; >- >- // See NackConfig for description. >- NackConfig nack; >- >- // See UlpfecConfig for description. >- UlpfecConfig ulpfec; >- >- struct Flexfec { >- Flexfec(); >- Flexfec(const Flexfec&); >- ~Flexfec(); >- // Payload type of FlexFEC. Set to -1 to disable sending FlexFEC. >- int payload_type = -1; >- >- // SSRC of FlexFEC stream. >- uint32_t ssrc = 0; >- >- // Vector containing a single element, corresponding to the SSRC of the >- // media stream being protected by this FlexFEC stream. >- // The vector MUST have size 1. >- // >- // TODO(brandtr): Update comment above when we support >- // multistream protection. >- std::vector<uint32_t> protected_media_ssrcs; >- } flexfec; >- >- // Settings for RTP retransmission payload format, see RFC 4588 for >- // details. >- struct Rtx { >- Rtx(); >- Rtx(const Rtx&); >- ~Rtx(); >- std::string ToString() const; >- // SSRCs to use for the RTX streams. >- std::vector<uint32_t> ssrcs; >- >- // Payload type to use for the RTX stream. >- int payload_type = -1; >- } rtx; >- >- // RTCP CNAME, see RFC 3550. >- std::string c_name; >- } rtp; >+ VideoStreamEncoderSettings encoder_settings; >+ >+ RtpConfig rtp; >+ >+ RtcpConfig rtcp; > > // Transport for outgoing packets. > Transport* send_transport = nullptr; >@@ -236,6 +150,16 @@ class VideoSendStream { > Config(const Config&); > }; > >+ // Updates the sending state for all simulcast layers that the video send >+ // stream owns. This can mean updating the activity one or for multiple >+ // layers. The ordering of active layers is the order in which the >+ // rtp modules are stored in the VideoSendStream. >+ // Note: This starts stream activity if it is inactive and one of the layers >+ // is active. This stops stream activity if it is active and all layers are >+ // inactive. >+ virtual void UpdateActiveSimulcastLayers( >+ const std::vector<bool> active_layers) = 0; >+ > // Starts stream activity. > // When a stream is active, it can receive, process and deliver packets. > virtual void Start() = 0; >@@ -243,23 +167,6 @@ class VideoSendStream { > // When a stream is stopped, it can't receive, process or deliver packets. > virtual void Stop() = 0; > >- // Based on the spec in >- // https://w3c.github.io/webrtc-pc/#idl-def-rtcdegradationpreference. >- // These options are enforced on a best-effort basis. For instance, all of >- // these options may suffer some frame drops in order to avoid queuing. >- // TODO(sprang): Look into possibility of more strictly enforcing the >- // maintain-framerate option. >- enum class DegradationPreference { >- // Don't take any actions based on over-utilization signals. >- kDegradationDisabled, >- // On over-use, request lower frame rate, possibly causing frame drops. >- kMaintainResolution, >- // On over-use, request lower resolution, possibly causing down-scaling. >- kMaintainFramerate, >- // Try to strike a "pleasing" balance between frame rate or resolution. >- kBalanced, >- }; >- > virtual void SetSource( > rtc::VideoSourceInterface<webrtc::VideoFrame>* source, > const DegradationPreference& degradation_preference) = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/BUILD.gn >index 34cdddc8036..50bd0f4022f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/BUILD.gn >@@ -6,19 +6,10 @@ > # in the file PATENTS. All contributing project authors may > # be found in the AUTHORS file in the root of the source tree. > >-import("//build/config/arm.gni") > import("../webrtc.gni") > > visibility = [ ":*" ] > >-config("common_audio_config") { >- include_dirs = [ >- "resampler/include", >- "signal_processing/include", >- "vad/include", >- ] >-} >- > rtc_static_library("common_audio") { > visibility += [ "*" ] > sources = [ >@@ -60,47 +51,27 @@ rtc_static_library("common_audio") { > ] > > deps = [ >+ ":common_audio_c", > ":sinc_resampler", > "..:webrtc_common", >- "../:typedefs", >- "../api:optional", > "../rtc_base:checks", > "../rtc_base:gtest_prod", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/memory:aligned_array", >+ "../rtc_base/memory:aligned_malloc", >+ "../rtc_base/system:arch", > "../system_wrappers", > "../system_wrappers:cpu_features_api", >- ] >- public_deps = [ >- ":common_audio_c", >+ "third_party/fft4g:fft4g", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > > defines = [] >- if (rtc_use_openmax_dl) { >- sources += [ >- "real_fourier_openmax.cc", >- "real_fourier_openmax.h", >- ] >- defines += [ "RTC_USE_OPENMAX_DL" ] >- if (rtc_build_openmax_dl) { >- deps += [ "//third_party/openmax_dl/dl" ] >- } >- } > > if (rtc_build_with_neon) { > deps += [ ":common_audio_neon" ] > } > >- if (is_win) { >- cflags = [ "/wd4334" ] # Ignore warning on shift operator promotion. >- } >- >- public_configs = [ ":common_audio_config" ] >- >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > if (current_cpu == "x86" || current_cpu == "x64") { > deps += [ ":common_audio_sse2" ] > } >@@ -121,24 +92,22 @@ rtc_source_set("mock_common_audio") { > > rtc_source_set("common_audio_c_arm_asm") { > sources = [] >+ deps = [] > if (current_cpu == "arm") { >- sources += [ >- "signal_processing/complex_bit_reverse_arm.S", >- "signal_processing/spl_sqrt_floor_arm.S", >- ] >+ sources += [ "signal_processing/complex_bit_reverse_arm.S" ] > > if (arm_version >= 7) { > sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ] > } else { > sources += [ "signal_processing/filter_ar_fast_q12.c" ] > } >+ deps += [ "../rtc_base/system:asm_defines" ] > } > } > > rtc_source_set("common_audio_c") { >+ visibility += webrtc_default_visibility > sources = [ >- "fft4g.c", >- "fft4g.h", > "ring_buffer.c", > "ring_buffer.h", > "signal_processing/auto_corr_to_refl_coef.c", >@@ -198,7 +167,6 @@ rtc_source_set("common_audio_c") { > "signal_processing/include/spl_inl_mips.h", > "signal_processing/min_max_operations_mips.c", > "signal_processing/resample_by_2_mips.c", >- "signal_processing/spl_sqrt_floor_mips.c", > ] > if (mips_dsp_rev > 0) { > sources += [ "signal_processing/vector_scaling_operations_mips.c" ] >@@ -211,26 +179,22 @@ rtc_source_set("common_audio_c") { > sources += [ > "signal_processing/complex_bit_reverse.c", > "signal_processing/filter_ar_fast_q12.c", >- "signal_processing/spl_sqrt_floor.c", > ] > } > >- if (is_win) { >- cflags = [ "/wd4334" ] # Ignore warning on shift operator promotion. >- } >- >- public_configs = [ ":common_audio_config" ] > deps = [ > ":common_audio_c_arm_asm", > ":common_audio_cc", > "..:webrtc_common", >- "../:typedefs", > "../rtc_base:checks", > "../rtc_base:compile_assert_c", > "../rtc_base:rtc_base_approved", > "../rtc_base:sanitizer", >+ "../rtc_base/system:arch", > "../system_wrappers", > "../system_wrappers:cpu_features_api", >+ "third_party/fft4g:fft4g", >+ "third_party/spl_sqrt_floor", > ] > } > >@@ -240,10 +204,8 @@ rtc_source_set("common_audio_cc") { > "signal_processing/dot_product_with_scale.h", > ] > >- public_configs = [ ":common_audio_config" ] > deps = [ > "..:webrtc_common", >- "../:typedefs", > "../rtc_base:rtc_base_approved", > "../system_wrappers", > ] >@@ -255,9 +217,10 @@ rtc_source_set("sinc_resampler") { > ] > deps = [ > "..:webrtc_common", >- "../:typedefs", > "../rtc_base:gtest_prod", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/memory:aligned_malloc", >+ "../rtc_base/system:arch", > "../system_wrappers", > ] > } >@@ -281,6 +244,7 @@ rtc_source_set("fir_filter_factory") { > ":fir_filter", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/system:arch", > "../system_wrappers:cpu_features_api", > ] > if (current_cpu == "x86" || current_cpu == "x64") { >@@ -299,20 +263,16 @@ if (current_cpu == "x86" || current_cpu == "x64") { > "resampler/sinc_resampler_sse.cc", > ] > >- if (is_posix) { >+ if (is_posix || is_fuchsia) { > cflags = [ "-msse2" ] > } > >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } > deps = [ > ":fir_filter", > ":sinc_resampler", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >- "../system_wrappers", >+ "../rtc_base/memory:aligned_malloc", > ] > } > } >@@ -326,9 +286,7 @@ if (rtc_build_with_neon) { > ] > > if (current_cpu != "arm64") { >- # Enable compilation for the NEON instruction set. This is needed >- # since //build/config/arm.gni only enables NEON for iOS, not Android. >- # This provides the same functionality as webrtc/build/arm_neon.gypi. >+ # Enable compilation for the NEON instruction set. > suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] > cflags = [ "-mfpu=neon" ] > } >@@ -342,25 +300,18 @@ if (rtc_build_with_neon) { > ] > } > >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > deps = [ >+ ":common_audio_neon_c", > ":fir_filter", > ":sinc_resampler", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >- "../system_wrappers", >- ] >- >- public_deps = [ >- ":common_audio_neon_c", >+ "../rtc_base/memory:aligned_malloc", > ] > } > > rtc_source_set("common_audio_neon_c") { >+ visibility += webrtc_default_visibility > sources = [ > "signal_processing/cross_correlation_neon.c", > "signal_processing/downsample_fast_neon.c", >@@ -368,9 +319,7 @@ if (rtc_build_with_neon) { > ] > > if (current_cpu != "arm64") { >- # Enable compilation for the NEON instruction set. This is needed >- # since //build/config/arm.gni only enables NEON for iOS, not Android. >- # This provides the same functionality as webrtc/build/arm_neon.gypi. >+ # Enable compilation for the NEON instruction set. > suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] > cflags = [ "-mfpu=neon" ] > } >@@ -384,14 +333,11 @@ if (rtc_build_with_neon) { > ] > } > >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } > deps = [ > ":common_audio_c", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/system:arch", > ] > } > } >@@ -436,28 +382,20 @@ if (rtc_include_tests) { > sources += [ "resampler/sinc_resampler_unittest.cc" ] > } > >- if (rtc_use_openmax_dl) { >- defines = [ "RTC_USE_OPENMAX_DL" ] >- } >- >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > deps = [ > ":common_audio", >+ ":common_audio_c", > ":fir_filter", > ":fir_filter_factory", > ":sinc_resampler", > "..:webrtc_common", >- "../:typedefs", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_base_tests_utils", >+ "../rtc_base/system:arch", > "../system_wrappers:cpu_features_api", >+ "../test:fileutils", > "../test:test_main", >- "//testing/gmock", > "//testing/gtest", > ] > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/DEPS >index 47ce4c32b6c..8a9adf19f97 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/DEPS >@@ -1,4 +1,3 @@ > include_rules = [ >- "+dl/sp/api", # For openmax_dl. > "+system_wrappers", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.cc >index 47d2be280ea..0f97abb86a3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.cc >@@ -26,12 +26,16 @@ namespace webrtc { > > class CopyConverter : public AudioConverter { > public: >- CopyConverter(size_t src_channels, size_t src_frames, size_t dst_channels, >+ CopyConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, > size_t dst_frames) > : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} >- ~CopyConverter() override {}; >+ ~CopyConverter() override{}; > >- void Convert(const float* const* src, size_t src_size, float* const* dst, >+ void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, > size_t dst_capacity) override { > CheckSizes(src_size, dst_capacity); > if (src != dst) { >@@ -43,12 +47,16 @@ class CopyConverter : public AudioConverter { > > class UpmixConverter : public AudioConverter { > public: >- UpmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, >+ UpmixConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, > size_t dst_frames) > : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} >- ~UpmixConverter() override {}; >+ ~UpmixConverter() override{}; > >- void Convert(const float* const* src, size_t src_size, float* const* dst, >+ void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, > size_t dst_capacity) override { > CheckSizes(src_size, dst_capacity); > for (size_t i = 0; i < dst_frames(); ++i) { >@@ -61,13 +69,16 @@ class UpmixConverter : public AudioConverter { > > class DownmixConverter : public AudioConverter { > public: >- DownmixConverter(size_t src_channels, size_t src_frames, size_t dst_channels, >+ DownmixConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, > size_t dst_frames) >- : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { >- } >- ~DownmixConverter() override {}; >+ : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} >+ ~DownmixConverter() override{}; > >- void Convert(const float* const* src, size_t src_size, float* const* dst, >+ void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, > size_t dst_capacity) override { > CheckSizes(src_size, dst_capacity); > float* dst_mono = dst[0]; >@@ -82,7 +93,9 @@ class DownmixConverter : public AudioConverter { > > class ResampleConverter : public AudioConverter { > public: >- ResampleConverter(size_t src_channels, size_t src_frames, size_t dst_channels, >+ ResampleConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, > size_t dst_frames) > : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { > resamplers_.reserve(src_channels); >@@ -90,9 +103,11 @@ class ResampleConverter : public AudioConverter { > resamplers_.push_back(std::unique_ptr<PushSincResampler>( > new PushSincResampler(src_frames, dst_frames))); > } >- ~ResampleConverter() override {}; >+ ~ResampleConverter() override{}; > >- void Convert(const float* const* src, size_t src_size, float* const* dst, >+ void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, > size_t dst_capacity) override { > CheckSizes(src_size, dst_capacity); > for (size_t i = 0; i < resamplers_.size(); ++i) >@@ -108,7 +123,7 @@ class ResampleConverter : public AudioConverter { > class CompositionConverter : public AudioConverter { > public: > explicit CompositionConverter( >- std::vector<std::unique_ptr<AudioConverter>> converters) >+ std::vector<std::unique_ptr<AudioConverter>> converters) > : converters_(std::move(converters)) { > RTC_CHECK_GE(converters_.size(), 2); > // We need an intermediate buffer after every converter. >@@ -117,19 +132,19 @@ class CompositionConverter : public AudioConverter { > std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>( > (*it)->dst_frames(), (*it)->dst_channels()))); > } >- ~CompositionConverter() override {}; >+ ~CompositionConverter() override{}; > >- void Convert(const float* const* src, size_t src_size, float* const* dst, >+ void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, > size_t dst_capacity) override { > converters_.front()->Convert(src, src_size, buffers_.front()->channels(), > buffers_.front()->size()); > for (size_t i = 2; i < converters_.size(); ++i) { > auto& src_buffer = buffers_[i - 2]; > auto& dst_buffer = buffers_[i - 1]; >- converters_[i]->Convert(src_buffer->channels(), >- src_buffer->size(), >- dst_buffer->channels(), >- dst_buffer->size()); >+ converters_[i]->Convert(src_buffer->channels(), src_buffer->size(), >+ dst_buffer->channels(), dst_buffer->size()); > } > converters_.back()->Convert(buffers_.back()->channels(), > buffers_.back()->size(), dst, dst_capacity); >@@ -175,8 +190,8 @@ std::unique_ptr<AudioConverter> AudioConverter::Create(size_t src_channels, > sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels, > dst_frames)); > } else { >- sp.reset(new CopyConverter(src_channels, src_frames, dst_channels, >- dst_frames)); >+ sp.reset( >+ new CopyConverter(src_channels, src_frames, dst_channels, dst_frames)); > } > > return sp; >@@ -184,13 +199,12 @@ std::unique_ptr<AudioConverter> AudioConverter::Create(size_t src_channels, > > // For CompositionConverter. > AudioConverter::AudioConverter() >- : src_channels_(0), >- src_frames_(0), >- dst_channels_(0), >- dst_frames_(0) {} >+ : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {} > >-AudioConverter::AudioConverter(size_t src_channels, size_t src_frames, >- size_t dst_channels, size_t dst_frames) >+AudioConverter::AudioConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, >+ size_t dst_frames) > : src_channels_(src_channels), > src_frames_(src_frames), > dst_channels_(dst_channels), >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.h >index 3f7b9a852cb..769d724e2fb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter.h >@@ -37,8 +37,10 @@ class AudioConverter { > // capacity of |dst_capacity|. Both point to a series of buffers containing > // the samples for each channel. The sizes must correspond to the format > // passed to Create(). >- virtual void Convert(const float* const* src, size_t src_size, >- float* const* dst, size_t dst_capacity) = 0; >+ virtual void Convert(const float* const* src, >+ size_t src_size, >+ float* const* dst, >+ size_t dst_capacity) = 0; > > size_t src_channels() const { return src_channels_; } > size_t src_frames() const { return src_frames_; } >@@ -47,7 +49,9 @@ class AudioConverter { > > protected: > AudioConverter(); >- AudioConverter(size_t src_channels, size_t src_frames, size_t dst_channels, >+ AudioConverter(size_t src_channels, >+ size_t src_frames, >+ size_t dst_channels, > size_t dst_frames); > > // Helper to RTC_CHECK that inputs are correctly sized. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter_unittest.cc >index e9937fd8cca..b99d825c2b5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_converter_unittest.cc >@@ -8,8 +8,8 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include <cmath> > #include <algorithm> >+#include <cmath> > #include <memory> > #include <vector> > >@@ -52,8 +52,7 @@ float ComputeSNR(const ChannelBuffer<float>& ref, > > // Search within one sample of the expected delay. > for (size_t delay = std::max(expected_delay, static_cast<size_t>(1)) - 1; >- delay <= std::min(expected_delay + 1, ref.num_frames()); >- ++delay) { >+ delay <= std::min(expected_delay + 1, ref.num_frames()); ++delay) { > float mse = 0; > float variance = 0; > float mean = 0; >@@ -92,8 +91,8 @@ void RunAudioConverterTest(size_t src_channels, > int dst_sample_rate_hz) { > const float kSrcLeft = 0.0002f; > const float kSrcRight = 0.0001f; >- const float resampling_factor = (1.f * src_sample_rate_hz) / >- dst_sample_rate_hz; >+ const float resampling_factor = >+ (1.f * src_sample_rate_hz) / dst_sample_rate_hz; > const float dst_left = resampling_factor * kSrcLeft; > const float dst_right = resampling_factor * kSrcRight; > const float dst_mono = (dst_left + dst_right) / 2; >@@ -124,13 +123,15 @@ void RunAudioConverterTest(size_t src_channels, > ScopedBuffer ref_buffer = CreateBuffer(ref_data, dst_frames); > > // The sinc resampler has a known delay, which we compute here. >- const size_t delay_frames = src_sample_rate_hz == dst_sample_rate_hz ? 0 : >- static_cast<size_t>( >- PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) * >- dst_sample_rate_hz); >+ const size_t delay_frames = >+ src_sample_rate_hz == dst_sample_rate_hz >+ ? 0 >+ : static_cast<size_t>( >+ PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) * >+ dst_sample_rate_hz); > // SNR reported on the same line later. >- printf("(%" PRIuS ", %d Hz) -> (%" PRIuS ", %d Hz) ", >- src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz); >+ printf("(%" PRIuS ", %d Hz) -> (%" PRIuS ", %d Hz) ", src_channels, >+ src_sample_rate_hz, dst_channels, dst_sample_rate_hz); > > std::unique_ptr<AudioConverter> converter = AudioConverter::Create( > src_channels, src_frames, dst_channels, dst_frames); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer.cc >index e7b5d81ac6a..b3bdc252f67 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer.cc >@@ -24,11 +24,12 @@ AudioRingBuffer::AudioRingBuffer(size_t channels, size_t max_frames) { > } > > AudioRingBuffer::~AudioRingBuffer() { >- for (auto buf : buffers_) >+ for (auto* buf : buffers_) > WebRtc_FreeBuffer(buf); > } > >-void AudioRingBuffer::Write(const float* const* data, size_t channels, >+void AudioRingBuffer::Write(const float* const* data, >+ size_t channels, > size_t frames) { > RTC_DCHECK_EQ(buffers_.size(), channels); > for (size_t i = 0; i < channels; ++i) { >@@ -57,7 +58,7 @@ size_t AudioRingBuffer::WriteFramesAvailable() const { > } > > void AudioRingBuffer::MoveReadPositionForward(size_t frames) { >- for (auto buf : buffers_) { >+ for (auto* buf : buffers_) { > const size_t moved = > static_cast<size_t>(WebRtc_MoveReadPtr(buf, static_cast<int>(frames))); > RTC_CHECK_EQ(moved, frames); >@@ -65,7 +66,7 @@ void AudioRingBuffer::MoveReadPositionForward(size_t frames) { > } > > void AudioRingBuffer::MoveReadPositionBackward(size_t frames) { >- for (auto buf : buffers_) { >+ for (auto* buf : buffers_) { > const size_t moved = static_cast<size_t>( > -WebRtc_MoveReadPtr(buf, -static_cast<int>(frames))); > RTC_CHECK_EQ(moved, frames); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer_unittest.cc >index 2fcf80035f5..d411195aa73 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_ring_buffer_unittest.cc >@@ -17,8 +17,8 @@ > > namespace webrtc { > >-class AudioRingBufferTest : >- public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > { >+class AudioRingBufferTest >+ : public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > { > }; > > void ReadAndWriteTest(const ChannelBuffer<float>& input, >@@ -72,10 +72,8 @@ TEST_P(AudioRingBufferTest, ReadDataMatchesWrittenData) { > input.channels()[i][j] = (i + 1) * (j + 1); > > ChannelBuffer<float> output(kFrames, static_cast<int>(num_channels)); >- ReadAndWriteTest(input, >- ::testing::get<0>(GetParam()), >- ::testing::get<1>(GetParam()), >- ::testing::get<2>(GetParam()), >+ ReadAndWriteTest(input, ::testing::get<0>(GetParam()), >+ ::testing::get<1>(GetParam()), ::testing::get<2>(GetParam()), > &output); > > // Verify the read data matches the input. >@@ -85,7 +83,8 @@ TEST_P(AudioRingBufferTest, ReadDataMatchesWrittenData) { > } > > INSTANTIATE_TEST_CASE_P( >- AudioRingBufferTest, AudioRingBufferTest, >+ AudioRingBufferTest, >+ AudioRingBufferTest, > ::testing::Combine(::testing::Values(10, 20, 42), // num_write_chunk_frames > ::testing::Values(1, 10, 17), // num_read_chunk_frames > ::testing::Values(100, 256), // buffer_frames >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util.cc >index b442a146f7a..735ba5f1886 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util.cc >@@ -10,8 +10,6 @@ > > #include "common_audio/include/audio_util.h" > >-#include "typedefs.h" // NOLINT(build/include) >- > namespace webrtc { > > void FloatToS16(const float* src, size_t size, int16_t* dest) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util_unittest.cc >index 7af3c369602..cf85a2d46cb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/audio_util_unittest.cc >@@ -9,9 +9,10 @@ > */ > > #include "common_audio/include/audio_util.h" >+ >+#include "rtc_base/arraysize.h" > #include "test/gmock.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > namespace { >@@ -26,84 +27,121 @@ void ExpectArraysEq(const int16_t* ref, const int16_t* test, size_t length) { > > void ExpectArraysEq(const float* ref, const float* test, size_t length) { > for (size_t i = 0; i < length; ++i) { >- EXPECT_FLOAT_EQ(ref[i], test[i]); >+ EXPECT_NEAR(ref[i], test[i], 0.01f); > } > } > > TEST(AudioUtilTest, FloatToS16) { >- const size_t kSize = 9; >- const float kInput[kSize] = {0.f, >- 0.4f / 32767.f, >- 0.6f / 32767.f, >- -0.4f / 32768.f, >- -0.6f / 32768.f, >- 1.f, >- -1.f, >- 1.1f, >- -1.1f}; >- const int16_t kReference[kSize] = {0, 0, 1, 0, -1, >- 32767, -32768, 32767, -32768}; >+ static constexpr float kInput[] = {0.f, >+ 0.4f / 32767.f, >+ 0.6f / 32767.f, >+ -0.4f / 32768.f, >+ -0.6f / 32768.f, >+ 1.f, >+ -1.f, >+ 1.1f, >+ -1.1f}; >+ static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, >+ 32767, -32768, 32767, -32768}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); > int16_t output[kSize]; > FloatToS16(kInput, kSize, output); > ExpectArraysEq(kReference, output, kSize); > } > > TEST(AudioUtilTest, S16ToFloat) { >- const size_t kSize = 7; >- const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768}; >- const float kReference[kSize] = { >+ static constexpr int16_t kInput[] = {0, 1, -1, 16384, -16384, 32767, -32768}; >+ static constexpr float kReference[] = { > 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); > float output[kSize]; > S16ToFloat(kInput, kSize, output); > ExpectArraysEq(kReference, output, kSize); > } > > TEST(AudioUtilTest, FloatS16ToS16) { >- const size_t kSize = 7; >- const float kInput[kSize] = {0.f, 0.4f, 0.5f, -0.4f, >- -0.5f, 32768.f, -32769.f}; >- const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768}; >+ static constexpr float kInput[] = {0.f, 0.4f, 0.5f, -0.4f, >+ -0.5f, 32768.f, -32769.f}; >+ static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, 32767, -32768}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); > int16_t output[kSize]; > FloatS16ToS16(kInput, kSize, output); > ExpectArraysEq(kReference, output, kSize); > } > > TEST(AudioUtilTest, FloatToFloatS16) { >- const size_t kSize = 9; >- const float kInput[kSize] = {0.f, >- 0.4f / 32767.f, >- 0.6f / 32767.f, >- -0.4f / 32768.f, >- -0.6f / 32768.f, >- 1.f, >- -1.f, >- 1.1f, >- -1.1f}; >- const float kReference[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f, >- 32767.f, -32768.f, 36043.7f, -36044.8f}; >+ static constexpr float kInput[] = {0.f, >+ 0.4f / 32767.f, >+ 0.6f / 32767.f, >+ -0.4f / 32768.f, >+ -0.6f / 32768.f, >+ 1.f, >+ -1.f, >+ 1.1f, >+ -1.1f}; >+ static constexpr float kReference[] = { >+ 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); > float output[kSize]; > FloatToFloatS16(kInput, kSize, output); > ExpectArraysEq(kReference, output, kSize); > } > > TEST(AudioUtilTest, FloatS16ToFloat) { >- const size_t kSize = 9; >- const float kInput[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f, >- 32767.f, -32768.f, 36043.7f, -36044.8f}; >- const float kReference[kSize] = {0.f, >- 0.4f / 32767.f, >- 0.6f / 32767.f, >- -0.4f / 32768.f, >- -0.6f / 32768.f, >- 1.f, >- -1.f, >- 1.1f, >- -1.1f}; >+ static constexpr float kInput[] = { >+ 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32767.f, -32768.f, 36043.7f, -36044.8f}; >+ static constexpr float kReference[] = {0.f, >+ 0.4f / 32767.f, >+ 0.6f / 32767.f, >+ -0.4f / 32768.f, >+ -0.6f / 32768.f, >+ 1.f, >+ -1.f, >+ 1.1f, >+ -1.1f}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); > float output[kSize]; > FloatS16ToFloat(kInput, kSize, output); > ExpectArraysEq(kReference, output, kSize); > } > >+TEST(AudioUtilTest, DbfsToFloatS16) { >+ static constexpr float kInput[] = {-90.f, -70.f, -30.f, -20.f, -10.f, >+ -5.f, -1.f, 0.f, 1.f}; >+ static constexpr float kReference[] = { >+ 1.036215186f, 10.36215115f, 1036.215088f, 3276.800049f, 10362.15137f, >+ 18426.80078f, 29204.51172f, 32768.f, 36766.30078f}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); >+ float output[kSize]; >+ for (size_t i = 0; i < kSize; ++i) { >+ output[i] = DbfsToFloatS16(kInput[i]); >+ } >+ ExpectArraysEq(kReference, output, kSize); >+} >+ >+TEST(AudioUtilTest, FloatS16ToDbfs) { >+ static constexpr float kInput[] = {1.036215143f, 10.36215143f, 1036.215143f, >+ 3276.8f, 10362.151436f, 18426.800543f, >+ 29204.51074f, 32768.0f, 36766.30071f}; >+ >+ static constexpr float kReference[] = { >+ -90.f, -70.f, -30.f, -20.f, -10.f, -5.f, -1.f, 0.f, 0.9999923706f}; >+ static constexpr size_t kSize = arraysize(kInput); >+ static_assert(arraysize(kReference) == kSize, ""); >+ >+ float output[kSize]; >+ for (size_t i = 0; i < kSize; ++i) { >+ output[i] = FloatS16ToDbfs(kInput[i]); >+ } >+ ExpectArraysEq(kReference, output, kSize); >+} >+ > TEST(AudioUtilTest, InterleavingStereo) { > const int16_t kInterleaved[] = {2, 3, 4, 9, 8, 27, 16, 81}; > const size_t kSamplesPerChannel = 4; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker.cc >index 7d09d21ea84..3dc8ed8040f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker.cc >@@ -41,8 +41,7 @@ void CopyFrames(const float* const* src, > float* const* dst, > size_t dst_start_index) { > for (size_t i = 0; i < num_channels; ++i) { >- memcpy(&dst[i][dst_start_index], >- &src[i][src_start_index], >+ memcpy(&dst[i][dst_start_index], &src[i][src_start_index], > num_frames * sizeof(dst[i][dst_start_index])); > } > } >@@ -55,8 +54,7 @@ void MoveFrames(const float* const* src, > float* const* dst, > size_t dst_start_index) { > for (size_t i = 0; i < num_channels; ++i) { >- memmove(&dst[i][dst_start_index], >- &src[i][src_start_index], >+ memmove(&dst[i][dst_start_index], &src[i][src_start_index], > num_frames * sizeof(dst[i][dst_start_index])); > } > } >@@ -87,9 +85,9 @@ void ApplyWindow(const float* window, > size_t gcd(size_t a, size_t b) { > size_t tmp; > while (b) { >- tmp = a; >- a = b; >- b = tmp % b; >+ tmp = a; >+ a = b; >+ b = tmp % b; > } > return a; > } >@@ -184,51 +182,30 @@ void Blocker::ProcessChunk(const float* const* input, > block_size_); > input_buffer_.MoveReadPositionBackward(block_size_ - shift_amount_); > >- ApplyWindow(window_.get(), >- block_size_, >- num_input_channels_, >+ ApplyWindow(window_.get(), block_size_, num_input_channels_, > input_block_.channels()); >- callback_->ProcessBlock(input_block_.channels(), >- block_size_, >- num_input_channels_, >- num_output_channels_, >+ callback_->ProcessBlock(input_block_.channels(), block_size_, >+ num_input_channels_, num_output_channels_, > output_block_.channels()); >- ApplyWindow(window_.get(), >- block_size_, >- num_output_channels_, >+ ApplyWindow(window_.get(), block_size_, num_output_channels_, > output_block_.channels()); > >- AddFrames(output_buffer_.channels(), >- first_frame_in_block, >- output_block_.channels(), >- 0, >- block_size_, >- num_output_channels_, >- output_buffer_.channels(), >- first_frame_in_block); >+ AddFrames(output_buffer_.channels(), first_frame_in_block, >+ output_block_.channels(), 0, block_size_, num_output_channels_, >+ output_buffer_.channels(), first_frame_in_block); > > first_frame_in_block += shift_amount_; > } > > // Copy output buffer to output >- CopyFrames(output_buffer_.channels(), >- 0, >- chunk_size_, >- num_output_channels_, >- output, >- 0); >+ CopyFrames(output_buffer_.channels(), 0, chunk_size_, num_output_channels_, >+ output, 0); > > // Copy output buffer [chunk_size_, chunk_size_ + initial_delay] > // to output buffer [0, initial_delay], zero the rest. >- MoveFrames(output_buffer_.channels(), >- chunk_size, >- initial_delay_, >- num_output_channels_, >- output_buffer_.channels(), >- 0); >- ZeroOut(output_buffer_.channels(), >- initial_delay_, >- chunk_size_, >+ MoveFrames(output_buffer_.channels(), chunk_size, initial_delay_, >+ num_output_channels_, output_buffer_.channels(), 0); >+ ZeroOut(output_buffer_.channels(), initial_delay_, chunk_size_, > num_output_channels_); > > // Calculate new starting frames. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker_unittest.cc >index 296efab15b8..85a24f68478 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/blocker_unittest.cc >@@ -71,11 +71,8 @@ class BlockerTest : public ::testing::Test { > size_t end = chunk_size - 1; > while (end < num_frames) { > CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); >- blocker->ProcessChunk(input_chunk, >- chunk_size, >- num_input_channels, >- num_output_channels, >- output_chunk); >+ blocker->ProcessChunk(input_chunk, chunk_size, num_input_channels, >+ num_output_channels, output_chunk); > CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk); > > start += chunk_size; >@@ -116,8 +113,7 @@ class BlockerTest : public ::testing::Test { > size_t num_frames, > const float* const* src) { > for (size_t i = 0; i < num_channels; ++i) { >- memcpy(&dst[i][start_index_dst], >- &src[i][start_index_src], >+ memcpy(&dst[i][start_index_dst], &src[i][start_index_src], > num_frames * sizeof(float)); > } > } >@@ -152,27 +148,15 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { > ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); > > PlusThreeBlockerCallback callback; >- Blocker blocker(kChunkSize, >- kBlockSize, >- kNumInputChannels, >- kNumOutputChannels, >- kWindow, >- kShiftAmount, >- &callback); >- >- RunTest(&blocker, >- kChunkSize, >- kNumFrames, >- input_cb.channels(), >- input_chunk_cb.channels(), >- actual_output_cb.channels(), >- output_chunk_cb.channels(), >- kNumInputChannels, >- kNumOutputChannels); >+ Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, >+ kWindow, kShiftAmount, &callback); >+ >+ RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), >+ input_chunk_cb.channels(), actual_output_cb.channels(), >+ output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); > > ValidateSignalEquality(expected_output_cb.channels(), >- actual_output_cb.channels(), >- kNumOutputChannels, >+ actual_output_cb.channels(), kNumOutputChannels, > kNumFrames); > } > >@@ -205,27 +189,15 @@ TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { > ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); > > PlusThreeBlockerCallback callback; >- Blocker blocker(kChunkSize, >- kBlockSize, >- kNumInputChannels, >- kNumOutputChannels, >- kWindow, >- kShiftAmount, >- &callback); >- >- RunTest(&blocker, >- kChunkSize, >- kNumFrames, >- input_cb.channels(), >- input_chunk_cb.channels(), >- actual_output_cb.channels(), >- output_chunk_cb.channels(), >- kNumInputChannels, >- kNumOutputChannels); >+ Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, >+ kWindow, kShiftAmount, &callback); >+ >+ RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), >+ input_chunk_cb.channels(), actual_output_cb.channels(), >+ output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); > > ValidateSignalEquality(expected_output_cb.channels(), >- actual_output_cb.channels(), >- kNumOutputChannels, >+ actual_output_cb.channels(), kNumOutputChannels, > kNumFrames); > } > >@@ -258,27 +230,15 @@ TEST_F(BlockerTest, TestBlockerNoOverlap) { > ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); > > PlusThreeBlockerCallback callback; >- Blocker blocker(kChunkSize, >- kBlockSize, >- kNumInputChannels, >- kNumOutputChannels, >- kWindow, >- kShiftAmount, >- &callback); >- >- RunTest(&blocker, >- kChunkSize, >- kNumFrames, >- input_cb.channels(), >- input_chunk_cb.channels(), >- actual_output_cb.channels(), >- output_chunk_cb.channels(), >- kNumInputChannels, >- kNumOutputChannels); >+ Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, >+ kWindow, kShiftAmount, &callback); >+ >+ RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), >+ input_chunk_cb.channels(), actual_output_cb.channels(), >+ output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); > > ValidateSignalEquality(expected_output_cb.channels(), >- actual_output_cb.channels(), >- kNumOutputChannels, >+ actual_output_cb.channels(), kNumOutputChannels, > kNumFrames); > } > >@@ -286,14 +246,14 @@ TEST_F(BlockerTest, InitialDelaysAreMinimum) { > const size_t kNumInputChannels = 3; > const size_t kNumOutputChannels = 2; > const size_t kNumFrames = 1280; >- const size_t kChunkSize[] = >- {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160}; >- const size_t kBlockSize[] = >- {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256}; >- const size_t kShiftAmount[] = >- {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256}; >- const size_t kInitialDelay[] = >- {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224}; >+ const size_t kChunkSize[] = {80, 80, 80, 80, 80, 80, >+ 160, 160, 160, 160, 160, 160}; >+ const size_t kBlockSize[] = {64, 64, 64, 128, 128, 128, >+ 128, 128, 128, 256, 256, 256}; >+ const size_t kShiftAmount[] = {16, 32, 64, 32, 64, 128, >+ 32, 64, 128, 64, 128, 256}; >+ const size_t kInitialDelay[] = {48, 48, 48, 112, 112, 112, >+ 96, 96, 96, 224, 224, 224}; > > float input[kNumInputChannels][kNumFrames]; > for (size_t i = 0; i < kNumInputChannels; ++i) { >@@ -317,27 +277,15 @@ TEST_F(BlockerTest, InitialDelaysAreMinimum) { > ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels); > ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels); > >- Blocker blocker(kChunkSize[i], >- kBlockSize[i], >- kNumInputChannels, >- kNumOutputChannels, >- window.get(), >- kShiftAmount[i], >+ Blocker blocker(kChunkSize[i], kBlockSize[i], kNumInputChannels, >+ kNumOutputChannels, window.get(), kShiftAmount[i], > &callback); > >- RunTest(&blocker, >- kChunkSize[i], >- kNumFrames, >- input_cb.channels(), >- input_chunk_cb.channels(), >- output_cb.channels(), >- output_chunk_cb.channels(), >- kNumInputChannels, >- kNumOutputChannels); >- >- ValidateInitialDelay(output_cb.channels(), >- kNumOutputChannels, >- kNumFrames, >+ RunTest(&blocker, kChunkSize[i], kNumFrames, input_cb.channels(), >+ input_chunk_cb.channels(), output_cb.channels(), >+ output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); >+ >+ ValidateInitialDelay(output_cb.channels(), kNumOutputChannels, kNumFrames, > kInitialDelay[i]); > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.cc >index df45f6d0f6b..38d231e09d0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.cc >@@ -68,9 +68,7 @@ void IFChannelBuffer::RefreshI() const { > ibuf_.set_num_channels(fbuf_.num_channels()); > const float* const* float_channels = fbuf_.channels(); > for (size_t i = 0; i < fbuf_.num_channels(); ++i) { >- FloatS16ToS16(float_channels[i], >- ibuf_.num_frames(), >- int_channels[i]); >+ FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]); > } > ivalid_ = true; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.h >index 024868c46cd..3f9ba9c0e16 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/channel_buffer.h >@@ -40,9 +40,7 @@ namespace webrtc { > template <typename T> > class ChannelBuffer { > public: >- ChannelBuffer(size_t num_frames, >- size_t num_channels, >- size_t num_bands = 1) >+ ChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1) > : data_(new T[num_frames * num_channels]()), > channels_(new T*[num_channels * num_bands]), > bands_(new T*[num_channels * num_bands]), >@@ -119,7 +117,7 @@ class ChannelBuffer { > size_t num_frames_per_band() const { return num_frames_per_band_; } > size_t num_channels() const { return num_channels_; } > size_t num_bands() const { return num_bands_; } >- size_t size() const {return num_frames_ * num_allocated_channels_; } >+ size_t size() const { return num_frames_ * num_allocated_channels_; } > > void set_num_channels(size_t num_channels) { > RTC_DCHECK_LE(num_channels, num_allocated_channels_); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.cc >index 6fe247011bf..3418434672a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.cc >@@ -20,8 +20,7 @@ > > namespace webrtc { > >-FIRFilterC::~FIRFilterC() { >-} >+FIRFilterC::~FIRFilterC() {} > > FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length) > : coefficients_length_(coefficients_length), >@@ -52,11 +51,10 @@ void FIRFilterC::Filter(const float* in, size_t length, float* out) { > > // Update current state. > if (length >= state_length_) { >- memcpy( >- state_.get(), &in[length - state_length_], state_length_ * sizeof(*in)); >+ memcpy(state_.get(), &in[length - state_length_], >+ state_length_ * sizeof(*in)); > } else { >- memmove(state_.get(), >- &state_[length], >+ memmove(state_.get(), &state_[length], > (state_length_ - length) * sizeof(state_[0])); > memcpy(&state_[state_length_ - length], in, length * sizeof(*in)); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.h >index ffce838a67a..d263e1ba606 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_c.h >@@ -20,8 +20,7 @@ namespace webrtc { > > class FIRFilterC : public FIRFilter { > public: >- FIRFilterC(const float* coefficients, >- size_t coefficients_length); >+ FIRFilterC(const float* coefficients, size_t coefficients_length); > ~FIRFilterC() override; > > void Filter(const float* in, size_t length, float* out) override; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.cc >index c15c2e0c26c..3243b27ef9a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.cc >@@ -12,6 +12,7 @@ > > #include "common_audio/fir_filter_c.h" > #include "rtc_base/checks.h" >+#include "rtc_base/system/arch.h" > #include "system_wrappers/include/cpu_features_wrapper.h" > > #if defined(WEBRTC_HAS_NEON) >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.h >index 2e7ca9b89c9..a952541035e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_factory.h >@@ -1,4 +1,4 @@ >- /* >+/* > * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. > * > * Use of this source code is governed by a BSD-style license >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.cc >index d9f91b76002..f668841be63 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.cc >@@ -14,12 +14,11 @@ > #include <string.h> > > #include "rtc_base/checks.h" >-#include "system_wrappers/include/aligned_malloc.h" >+#include "rtc_base/memory/aligned_malloc.h" > > namespace webrtc { > >-FIRFilterNEON::~FIRFilterNEON() { >-} >+FIRFilterNEON::~FIRFilterNEON() {} > > FIRFilterNEON::FIRFilterNEON(const float* coefficients, > size_t coefficients_length, >@@ -40,8 +39,7 @@ FIRFilterNEON::FIRFilterNEON(const float* coefficients, > for (size_t i = 0; i < coefficients_length; ++i) { > coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; > } >- memset(state_.get(), >- 0.f, >+ memset(state_.get(), 0.f, > (max_input_length + state_length_) * sizeof(state_[0])); > } > >@@ -60,8 +58,8 @@ void FIRFilterNEON::Filter(const float* in, size_t length, float* out) { > float32x4_t m_in; > > for (size_t j = 0; j < coefficients_length_; j += 4) { >- m_in = vld1q_f32(in_ptr + j); >- m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j)); >+ m_in = vld1q_f32(in_ptr + j); >+ m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j)); > } > > float32x2_t m_half = vadd_f32(vget_high_f32(m_sum), vget_low_f32(m_sum)); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.h >index 5696df8f0e0..1ffefd80dc5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_neon.h >@@ -14,7 +14,7 @@ > #include <memory> > > #include "common_audio/fir_filter.h" >-#include "system_wrappers/include/aligned_malloc.h" >+#include "rtc_base/memory/aligned_malloc.h" > > namespace webrtc { > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.cc >index 3302d564917..ee75fb38ad4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.cc >@@ -15,12 +15,11 @@ > #include <xmmintrin.h> > > #include "rtc_base/checks.h" >-#include "system_wrappers/include/aligned_malloc.h" >+#include "rtc_base/memory/aligned_malloc.h" > > namespace webrtc { > >-FIRFilterSSE2::~FIRFilterSSE2() { >-} >+FIRFilterSSE2::~FIRFilterSSE2() {} > > FIRFilterSSE2::FIRFilterSSE2(const float* coefficients, > size_t coefficients_length, >@@ -41,8 +40,7 @@ FIRFilterSSE2::FIRFilterSSE2(const float* coefficients, > for (size_t i = 0; i < coefficients_length; ++i) { > coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; > } >- memset(state_.get(), >- 0, >+ memset(state_.get(), 0, > (max_input_length + state_length_) * sizeof(state_[0])); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.h >index 6506024aff5..7707f933d9e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_sse.h >@@ -14,7 +14,7 @@ > #include <memory> > > #include "common_audio/fir_filter.h" >-#include "system_wrappers/include/aligned_malloc.h" >+#include "rtc_base/memory/aligned_malloc.h" > > namespace webrtc { > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_unittest.cc >index 46966217d77..07abf2094fe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fir_filter_unittest.cc >@@ -21,20 +21,18 @@ namespace webrtc { > namespace { > > static const float kCoefficients[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f}; >-static const size_t kCoefficientsLength = sizeof(kCoefficients) / >- sizeof(kCoefficients[0]); >+static const size_t kCoefficientsLength = >+ sizeof(kCoefficients) / sizeof(kCoefficients[0]); > >-static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, >- 8.f, 9.f, 10.f}; >-static const size_t kInputLength = sizeof(kInput) / >- sizeof(kInput[0]); >+static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, >+ 6.f, 7.f, 8.f, 9.f, 10.f}; >+static const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]); > > void VerifyOutput(const float* expected_output, > const float* output, > size_t length) { >- EXPECT_EQ(0, memcmp(expected_output, >- output, >- length * sizeof(expected_output[0]))); >+ EXPECT_EQ( >+ 0, memcmp(expected_output, output, length * sizeof(expected_output[0]))); > } > > } // namespace >@@ -97,8 +95,8 @@ TEST(FIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) { > > EXPECT_FLOAT_EQ(0.2f, output[0]); > EXPECT_FLOAT_EQ(0.7f, output[1]); >- filter.reset(CreateFirFilter( >- kCoefficients, kCoefficientsLength, kCoefficientsLength)); >+ filter.reset( >+ CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength)); > filter->Filter(kInput, kCoefficientsLength, output); > > EXPECT_FLOAT_EQ(0.2f, output[0]); >@@ -149,19 +147,17 @@ TEST(FIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) { > filter->Filter(&kInput[i], 1, &output_sample_based[i]); > } > >- EXPECT_EQ(0, memcmp(output_sample_based, >- output_block_based, >- kInputLength)); >+ EXPECT_EQ(0, memcmp(output_sample_based, output_block_based, kInputLength)); > } > > TEST(FIRFilterTest, SimplestHighPassFilter) { > const float kCoefficients[] = {1.f, -1.f}; >- const size_t kCoefficientsLength = sizeof(kCoefficients) / >- sizeof(kCoefficients[0]); >+ const size_t kCoefficientsLength = >+ sizeof(kCoefficients) / sizeof(kCoefficients[0]); > > float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; >- const size_t kConstantInputLength = sizeof(kConstantInput) / >- sizeof(kConstantInput[0]); >+ const size_t kConstantInputLength = >+ sizeof(kConstantInput) / sizeof(kConstantInput[0]); > > float output[kConstantInputLength]; > std::unique_ptr<FIRFilter> filter(CreateFirFilter( >@@ -175,12 +171,12 @@ TEST(FIRFilterTest, SimplestHighPassFilter) { > > TEST(FIRFilterTest, SimplestLowPassFilter) { > const float kCoefficients[] = {1.f, 1.f}; >- const size_t kCoefficientsLength = sizeof(kCoefficients) / >- sizeof(kCoefficients[0]); >+ const size_t kCoefficientsLength = >+ sizeof(kCoefficients) / sizeof(kCoefficients[0]); > > float kHighFrequencyInput[] = {-1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f}; >- const size_t kHighFrequencyInputLength = sizeof(kHighFrequencyInput) / >- sizeof(kHighFrequencyInput[0]); >+ const size_t kHighFrequencyInputLength = >+ sizeof(kHighFrequencyInput) / sizeof(kHighFrequencyInput[0]); > > float output[kHighFrequencyInputLength]; > std::unique_ptr<FIRFilter> filter(CreateFirFilter( >@@ -195,16 +191,16 @@ TEST(FIRFilterTest, SimplestLowPassFilter) { > TEST(FIRFilterTest, SameOutputWhenSwapedCoefficientsAndInput) { > float output[kCoefficientsLength]; > float output_swaped[kCoefficientsLength]; >- std::unique_ptr<FIRFilter> filter(CreateFirFilter( >- kCoefficients, kCoefficientsLength, kCoefficientsLength)); >+ std::unique_ptr<FIRFilter> filter( >+ CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength)); > // Use kCoefficientsLength for in_length to get same-length outputs. > filter->Filter(kInput, kCoefficientsLength, output); > >- filter.reset(CreateFirFilter( >- kInput, kCoefficientsLength, kCoefficientsLength)); >+ filter.reset( >+ CreateFirFilter(kInput, kCoefficientsLength, kCoefficientsLength)); > filter->Filter(kCoefficients, kCoefficientsLength, output_swaped); > >- for (size_t i = 0 ; i < kCoefficientsLength; ++i) { >+ for (size_t i = 0; i < kCoefficientsLength; ++i) { > EXPECT_FLOAT_EQ(output[i], output_swaped[i]); > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/include/audio_util.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/include/audio_util.h >index b9e1b26b0db..de242a49be8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/include/audio_util.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/include/audio_util.h >@@ -12,11 +12,11 @@ > #define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ > > #include <algorithm> >-#include <limits> >+#include <cmath> > #include <cstring> >+#include <limits> > > #include "rtc_base/checks.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -26,6 +26,10 @@ typedef std::numeric_limits<int16_t> limits_int16; > // S16: int16_t [-32768, 32767] > // Float: float [-1.0, 1.0] > // FloatS16: float [-32768.0, 32767.0] >+// Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0] >+// The ratio conversion functions use this naming convention: >+// Ratio: float (0, +inf) >+// Db: float (-inf, +inf) > static inline int16_t FloatToS16(float v) { > if (v > 0) > return v >= 1 ? limits_int16::max() >@@ -65,6 +69,27 @@ void FloatS16ToS16(const float* src, size_t size, int16_t* dest); > void FloatToFloatS16(const float* src, size_t size, float* dest); > void FloatS16ToFloat(const float* src, size_t size, float* dest); > >+inline float DbToRatio(float v) { >+ return std::pow(10.0f, v / 20.0f); >+} >+ >+inline float DbfsToFloatS16(float v) { >+ static constexpr float kMaximumAbsFloatS16 = -limits_int16::min(); >+ return DbToRatio(v) * kMaximumAbsFloatS16; >+} >+ >+inline float FloatS16ToDbfs(float v) { >+ RTC_DCHECK_GE(v, 0); >+ >+ // kMinDbfs is equal to -20.0 * log10(-limits_int16::min()) >+ static constexpr float kMinDbfs = -90.30899869919436f; >+ if (v <= 1.0f) { >+ return kMinDbfs; >+ } >+ // Equal to 20 * log10(v / (-limits_int16::min())) >+ return 20.0f * std::log10(v) + kMinDbfs; >+} >+ > // Copy audio from |src| channels to |dest| channels unless |src| and |dest| > // point to the same address. |src| and |dest| must have the same number of > // channels, and there must be sufficient space allocated in |dest|. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.cc >index 517709f4622..72c2ad79f6f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.cc >@@ -29,20 +29,17 @@ void LappedTransform::BlockThunk::ProcessBlock(const float* const* input, > RTC_CHECK_EQ(parent_->block_length_, num_frames); > > for (size_t i = 0; i < num_input_channels; ++i) { >- memcpy(parent_->real_buf_.Row(i), input[i], >- num_frames * sizeof(*input[0])); >+ memcpy(parent_->real_buf_.Row(i), input[i], num_frames * sizeof(*input[0])); > parent_->fft_->Forward(parent_->real_buf_.Row(i), > parent_->cplx_pre_.Row(i)); > } > >- size_t block_length = RealFourier::ComplexLength( >- RealFourier::FftOrder(num_frames)); >+ size_t block_length = >+ RealFourier::ComplexLength(RealFourier::FftOrder(num_frames)); > RTC_CHECK_EQ(parent_->cplx_length_, block_length); >- parent_->block_processor_->ProcessAudioBlock(parent_->cplx_pre_.Array(), >- num_input_channels, >- parent_->cplx_length_, >- num_output_channels, >- parent_->cplx_post_.Array()); >+ parent_->block_processor_->ProcessAudioBlock( >+ parent_->cplx_pre_.Array(), num_input_channels, parent_->cplx_length_, >+ num_output_channels, parent_->cplx_post_.Array()); > > for (size_t i = 0; i < num_output_channels; ++i) { > parent_->fft_->Inverse(parent_->cplx_post_.Row(i), >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.h >index fe3a8cd8c88..1ab2a9fee75 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform.h >@@ -16,7 +16,7 @@ > > #include "common_audio/blocker.h" > #include "common_audio/real_fourier.h" >-#include "system_wrappers/include/aligned_array.h" >+#include "rtc_base/memory/aligned_array.h" > > namespace webrtc { > >@@ -35,7 +35,8 @@ class LappedTransform { > virtual ~Callback() {} > > virtual void ProcessAudioBlock(const std::complex<float>* const* in_block, >- size_t num_in_channels, size_t frames, >+ size_t num_in_channels, >+ size_t frames, > size_t num_out_channels, > std::complex<float>* const* out_block) = 0; > }; >@@ -128,4 +129,3 @@ class LappedTransform { > } // namespace webrtc > > #endif // COMMON_AUDIO_LAPPED_TRANSFORM_H_ >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform_unittest.cc >index d6a312db517..687df8986a1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/lapped_transform_unittest.cc >@@ -24,11 +24,11 @@ class NoopCallback : public webrtc::LappedTransform::Callback { > public: > NoopCallback() : block_num_(0) {} > >- virtual void ProcessAudioBlock(const complex<float>* const* in_block, >- size_t in_channels, >- size_t frames, >- size_t out_channels, >- complex<float>* const* out_block) { >+ void ProcessAudioBlock(const complex<float>* const* in_block, >+ size_t in_channels, >+ size_t frames, >+ size_t out_channels, >+ complex<float>* const* out_block) override { > RTC_CHECK_EQ(in_channels, out_channels); > for (size_t i = 0; i < out_channels; ++i) { > memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames); >@@ -36,9 +36,7 @@ class NoopCallback : public webrtc::LappedTransform::Callback { > ++block_num_; > } > >- size_t block_num() { >- return block_num_; >- } >+ size_t block_num() { return block_num_; } > > private: > size_t block_num_; >@@ -48,11 +46,11 @@ class FftCheckerCallback : public webrtc::LappedTransform::Callback { > public: > FftCheckerCallback() : block_num_(0) {} > >- virtual void ProcessAudioBlock(const complex<float>* const* in_block, >- size_t in_channels, >- size_t frames, >- size_t out_channels, >- complex<float>* const* out_block) { >+ void ProcessAudioBlock(const complex<float>* const* in_block, >+ size_t in_channels, >+ size_t frames, >+ size_t out_channels, >+ complex<float>* const* out_block) override { > RTC_CHECK_EQ(in_channels, out_channels); > > size_t full_length = (frames - 1) * 2; >@@ -69,9 +67,7 @@ class FftCheckerCallback : public webrtc::LappedTransform::Callback { > } > } > >- size_t block_num() { >- return block_num_; >- } >+ size_t block_num() { return block_num_; } > > private: > size_t block_num_; >@@ -150,8 +146,7 @@ TEST(LappedTransformTest, IdentityProcessor) { > trans.ProcessChunk(&in_chunk, &out_chunk); > > for (size_t i = 0; i < kChunkLength; ++i) { >- ASSERT_NEAR(out_chunk[i], >- (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f, >+ ASSERT_NEAR(out_chunk[i], (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f, > 1e-5f); > } > >@@ -167,8 +162,8 @@ TEST(LappedTransformTest, Callbacks) { > float window[kBlockLength]; > std::fill(window, &window[kBlockLength], 1.0f); > >- LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, >- kBlockLength, &call); >+ LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kBlockLength, >+ &call); > float in_buffer[kChunkLength]; > float* in_chunk = in_buffer; > float out_buffer[kChunkLength]; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/mocks/mock_smoothing_filter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/mocks/mock_smoothing_filter.h >index dec6ea5f470..712049fa6a3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/mocks/mock_smoothing_filter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/mocks/mock_smoothing_filter.h >@@ -19,7 +19,7 @@ namespace webrtc { > class MockSmoothingFilter : public SmoothingFilter { > public: > MOCK_METHOD1(AddSample, void(float)); >- MOCK_METHOD0(GetAverage, rtc::Optional<float>()); >+ MOCK_METHOD0(GetAverage, absl::optional<float>()); > MOCK_METHOD1(SetTimeConstantMs, bool(int)); > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.cc >index f759778a35a..7365844e8d0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.cc >@@ -11,7 +11,6 @@ > #include "common_audio/real_fourier.h" > > #include "common_audio/real_fourier_ooura.h" >-#include "common_audio/real_fourier_openmax.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" > #include "rtc_base/checks.h" > >@@ -22,11 +21,7 @@ using std::complex; > const size_t RealFourier::kFftBufferAlignment = 32; > > std::unique_ptr<RealFourier> RealFourier::Create(int fft_order) { >-#if defined(RTC_USE_OPENMAX_DL) >- return std::unique_ptr<RealFourier>(new RealFourierOpenmax(fft_order)); >-#else > return std::unique_ptr<RealFourier>(new RealFourierOoura(fft_order)); >-#endif > } > > int RealFourier::FftOrder(size_t length) { >@@ -36,7 +31,7 @@ int RealFourier::FftOrder(size_t length) { > > size_t RealFourier::FftLength(int order) { > RTC_CHECK_GE(order, 0); >- return static_cast<size_t>(1 << order); >+ return size_t{1} << order; > } > > size_t RealFourier::ComplexLength(int order) { >@@ -54,4 +49,3 @@ RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) { > } > > } // namespace webrtc >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.h >index 4c69c3c7685..a3e4dd16a82 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier.h >@@ -14,7 +14,7 @@ > #include <complex> > #include <memory> > >-#include "system_wrappers/include/aligned_malloc.h" >+#include "rtc_base/memory/aligned_malloc.h" > > // Uniform interface class for the real DFT and its inverse, for power-of-2 > // input lengths. Also contains helper functions for buffer allocation, taking >@@ -72,4 +72,3 @@ class RealFourier { > } // namespace webrtc > > #endif // COMMON_AUDIO_REAL_FOURIER_H_ >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.cc >index 5d75717bc75..89694c16678 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.cc >@@ -10,10 +10,10 @@ > > #include "common_audio/real_fourier_ooura.h" > >-#include <cmath> > #include <algorithm> >+#include <cmath> > >-#include "common_audio/fft4g.h" >+#include "common_audio/third_party/fft4g/fft4g.h" > #include "rtc_base/checks.h" > > namespace webrtc { >@@ -28,8 +28,8 @@ void Conjugate(complex<float>* array, size_t complex_length) { > } > > size_t ComputeWorkIpSize(size_t fft_length) { >- return static_cast<size_t>(2 + std::ceil(std::sqrt( >- static_cast<float>(fft_length)))); >+ return static_cast<size_t>( >+ 2 + std::ceil(std::sqrt(static_cast<float>(fft_length)))); > } > > } // namespace >@@ -45,11 +45,13 @@ RealFourierOoura::RealFourierOoura(int fft_order) > RTC_CHECK_GE(fft_order, 1); > } > >+RealFourierOoura::~RealFourierOoura() = default; >+ > void RealFourierOoura::Forward(const float* src, complex<float>* dest) const { > { > // This cast is well-defined since C++11. See "Non-static data members" at: > // http://en.cppreference.com/w/cpp/numeric/complex >- auto dest_float = reinterpret_cast<float*>(dest); >+ auto* dest_float = reinterpret_cast<float*>(dest); > std::copy(src, src + length_, dest_float); > WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get()); > } >@@ -63,7 +65,7 @@ void RealFourierOoura::Forward(const float* src, complex<float>* dest) const { > > void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const { > { >- auto dest_complex = reinterpret_cast<complex<float>*>(dest); >+ auto* dest_complex = reinterpret_cast<complex<float>*>(dest); > // The real output array is shorter than the input complex array by one > // complex element. > const size_t dest_complex_length = complex_length_ - 1; >@@ -71,8 +73,8 @@ void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const { > // Restore Ooura's conjugate definition. > Conjugate(dest_complex, dest_complex_length); > // Restore real[n/2] to imag[0]. >- dest_complex[0] = complex<float>(dest_complex[0].real(), >- src[complex_length_ - 1].real()); >+ dest_complex[0] = >+ complex<float>(dest_complex[0].real(), src[complex_length_ - 1].real()); > } > > WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get()); >@@ -82,4 +84,8 @@ void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const { > std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; }); > } > >+int RealFourierOoura::order() const { >+ return order_; >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.h >index f885a34f58c..bb8eef96dff 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_ooura.h >@@ -21,13 +21,12 @@ namespace webrtc { > class RealFourierOoura : public RealFourier { > public: > explicit RealFourierOoura(int fft_order); >+ ~RealFourierOoura() override; > > void Forward(const float* src, std::complex<float>* dest) const override; > void Inverse(const std::complex<float>* src, float* dest) const override; > >- int order() const override { >- return order_; >- } >+ int order() const override; > > private: > const int order_; >@@ -42,4 +41,3 @@ class RealFourierOoura : public RealFourier { > } // namespace webrtc > > #endif // COMMON_AUDIO_REAL_FOURIER_OOURA_H_ >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.cc >deleted file mode 100644 >index 6c5c9cee928..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.cc >+++ /dev/null >@@ -1,69 +0,0 @@ >-/* >- * Copyright (c) 2015 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_audio/real_fourier_openmax.h" >- >-#include <cstdlib> >- >-#include "dl/sp/api/omxSP.h" >-#include "rtc_base/checks.h" >- >-namespace webrtc { >- >-using std::complex; >- >-namespace { >- >-// Creates and initializes the Openmax state. Transfers ownership to caller. >-OMXFFTSpec_R_F32* CreateOpenmaxState(int order) { >- RTC_CHECK_GE(order, 1); >- // The omx implementation uses this macro to check order validity. >- RTC_CHECK_LE(order, TWIDDLE_TABLE_ORDER); >- >- OMX_INT buffer_size; >- OMXResult r = omxSP_FFTGetBufSize_R_F32(order, &buffer_size); >- RTC_CHECK_EQ(r, OMX_Sts_NoErr); >- >- OMXFFTSpec_R_F32* omx_spec = malloc(buffer_size); >- RTC_DCHECK(omx_spec); >- >- r = omxSP_FFTInit_R_F32(omx_spec, order); >- RTC_CHECK_EQ(r, OMX_Sts_NoErr); >- return omx_spec; >-} >- >-} // namespace >- >-RealFourierOpenmax::RealFourierOpenmax(int fft_order) >- : order_(fft_order), >- omx_spec_(CreateOpenmaxState(order_)) { >-} >- >-RealFourierOpenmax::~RealFourierOpenmax() { >- free(omx_spec_); >-} >- >-void RealFourierOpenmax::Forward(const float* src, complex<float>* dest) const { >- // This cast is well-defined since C++11. See "Non-static data members" at: >- // http://en.cppreference.com/w/cpp/numeric/complex >- OMXResult r = >- omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_); >- RTC_CHECK_EQ(r, OMX_Sts_NoErr); >-} >- >-void RealFourierOpenmax::Inverse(const complex<float>* src, float* dest) const { >- OMXResult r = >- omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest, >- omx_spec_); >- RTC_CHECK_EQ(r, OMX_Sts_NoErr); >-} >- >-} // namespace webrtc >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.h >deleted file mode 100644 >index 7b4299aa3c9..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_openmax.h >+++ /dev/null >@@ -1,44 +0,0 @@ >-/* >- * Copyright (c) 2015 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. >- */ >- >-#ifndef COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ >-#define COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ >- >-#include <complex> >- >-#include "common_audio/real_fourier.h" >- >-namespace webrtc { >- >-class RealFourierOpenmax : public RealFourier { >- public: >- explicit RealFourierOpenmax(int fft_order); >- ~RealFourierOpenmax() override; >- >- void Forward(const float* src, std::complex<float>* dest) const override; >- void Inverse(const std::complex<float>* src, float* dest) const override; >- >- int order() const override { >- return order_; >- } >- >- private: >- // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the >- // dependency on openmax. >- typedef void OMXFFTSpec_R_F32_; >- const int order_; >- >- OMXFFTSpec_R_F32_* const omx_spec_; >-}; >- >-} // namespace webrtc >- >-#endif // COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_ >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_unittest.cc >index 97849b965b1..132488747ad 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/real_fourier_unittest.cc >@@ -13,7 +13,6 @@ > #include <stdlib.h> > > #include "common_audio/real_fourier_ooura.h" >-#include "common_audio/real_fourier_openmax.h" > #include "test/gtest.h" > > namespace webrtc { >@@ -61,19 +60,14 @@ class RealFourierTest : public ::testing::Test { > real_buffer_(RealFourier::AllocRealBuffer(4)), > cplx_buffer_(RealFourier::AllocCplxBuffer(3)) {} > >- ~RealFourierTest() { >- } >+ ~RealFourierTest() {} > > T rf_; > const RealFourier::fft_real_scoper real_buffer_; > const RealFourier::fft_cplx_scoper cplx_buffer_; > }; > >-using FftTypes = ::testing::Types< >-#if defined(RTC_USE_OPENMAX_DL) >- RealFourierOpenmax, >-#endif >- RealFourierOoura>; >+using FftTypes = ::testing::Types<RealFourierOoura>; > TYPED_TEST_CASE(RealFourierTest, FftTypes); > > TYPED_TEST(RealFourierTest, SimpleForwardTransform) { >@@ -106,4 +100,3 @@ TYPED_TEST(RealFourierTest, SimpleBackwardTransform) { > } > > } // namespace webrtc >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/push_resampler.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/push_resampler.h >index 046415b87e8..082cdc62840 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/push_resampler.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/push_resampler.h >@@ -13,8 +13,6 @@ > > #include <memory> > >-#include "typedefs.h" // NOLINT(build/include) >- > namespace webrtc { > > class PushSincResampler; >@@ -29,7 +27,8 @@ class PushResampler { > > // Must be called whenever the parameters change. Free to be called at any > // time as it is a no-op if parameters have not changed since the last call. >- int InitializeIfNeeded(int src_sample_rate_hz, int dst_sample_rate_hz, >+ int InitializeIfNeeded(int src_sample_rate_hz, >+ int dst_sample_rate_hz, > size_t num_channels); > > // Returns the total number of samples provided in destination (e.g. 32 kHz, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/resampler.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/resampler.h >index fec2c1a7bf2..04c487b331e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/resampler.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/include/resampler.h >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* > * A wrapper for resampling a numerous amount of sampling combinations. > */ >@@ -17,8 +16,7 @@ > #define COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ > > #include <stddef.h> >- >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > namespace webrtc { > >@@ -36,8 +34,11 @@ class Resampler { > int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels); > > // Resample samplesIn to samplesOut. >- int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut, >- size_t maxLen, size_t& outLen); // NOLINT: to avoid changing APIs >+ int Push(const int16_t* samplesIn, >+ size_t lengthIn, >+ int16_t* samplesOut, >+ size_t maxLen, >+ size_t& outLen); // NOLINT: to avoid changing APIs > > private: > enum ResamplerMode { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_resampler.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_resampler.cc >index 3930624b2ad..cc24c4b3f65 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_resampler.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_resampler.cc >@@ -25,7 +25,8 @@ namespace { > // caused the compiler to generate code that threw off the linker. > // TODO(tommi): Re-enable when we've figured out what the problem is. > // http://crbug.com/615050 >-void CheckValidInitParams(int src_sample_rate_hz, int dst_sample_rate_hz, >+void CheckValidInitParams(int src_sample_rate_hz, >+ int dst_sample_rate_hz, > size_t num_channels) { > // The below checks are temporarily disabled on WEBRTC_WIN due to problems > // with clang debug builds. >@@ -57,14 +58,10 @@ void CheckExpectedBufferSizes(size_t src_length, > > template <typename T> > PushResampler<T>::PushResampler() >- : src_sample_rate_hz_(0), >- dst_sample_rate_hz_(0), >- num_channels_(0) { >-} >+ : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {} > > template <typename T> >-PushResampler<T>::~PushResampler() { >-} >+PushResampler<T>::~PushResampler() {} > > template <typename T> > int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz, >@@ -92,22 +89,24 @@ int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz, > static_cast<size_t>(src_sample_rate_hz / 100); > const size_t dst_size_10ms_mono = > static_cast<size_t>(dst_sample_rate_hz / 100); >- sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono, >- dst_size_10ms_mono)); >+ sinc_resampler_.reset( >+ new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono)); > if (num_channels_ == 2) { > src_left_.reset(new T[src_size_10ms_mono]); > src_right_.reset(new T[src_size_10ms_mono]); > dst_left_.reset(new T[dst_size_10ms_mono]); > dst_right_.reset(new T[dst_size_10ms_mono]); >- sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono, >- dst_size_10ms_mono)); >+ sinc_resampler_right_.reset( >+ new PushSincResampler(src_size_10ms_mono, dst_size_10ms_mono)); > } > > return 0; > } > > template <typename T> >-int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst, >+int PushResampler<T>::Resample(const T* src, >+ size_t src_length, >+ T* dst, > size_t dst_capacity) { > CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_, > src_sample_rate_hz_, dst_sample_rate_hz_); >@@ -124,9 +123,8 @@ int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst, > T* deinterleaved[] = {src_left_.get(), src_right_.get()}; > Deinterleave(src, src_length_mono, num_channels_, deinterleaved); > >- size_t dst_length_mono = >- sinc_resampler_->Resample(src_left_.get(), src_length_mono, >- dst_left_.get(), dst_capacity_mono); >+ size_t dst_length_mono = sinc_resampler_->Resample( >+ src_left_.get(), src_length_mono, dst_left_.get(), dst_capacity_mono); > sinc_resampler_right_->Resample(src_right_.get(), src_length_mono, > dst_right_.get(), dst_capacity_mono); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.cc >index 14ab330cdfd..3bfead26e75 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.cc >@@ -28,8 +28,7 @@ PushSincResampler::PushSincResampler(size_t source_frames, > first_pass_(true), > source_available_(0) {} > >-PushSincResampler::~PushSincResampler() { >-} >+PushSincResampler::~PushSincResampler() {} > > size_t PushSincResampler::Resample(const int16_t* source, > size_t source_length, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.h >index bdc03a2c00f..1ffe73f79ba 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler.h >@@ -15,7 +15,6 @@ > > #include "common_audio/resampler/sinc_resampler.h" > #include "rtc_base/constructormagic.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -36,8 +35,10 @@ class PushSincResampler : public SincResamplerCallback { > // at least as large as |destination_frames|. Returns the number of samples > // provided in destination (for convenience, since this will always be equal > // to |destination_frames|). >- size_t Resample(const int16_t* source, size_t source_frames, >- int16_t* destination, size_t destination_capacity); >+ size_t Resample(const int16_t* source, >+ size_t source_frames, >+ int16_t* destination, >+ size_t destination_capacity); > size_t Resample(const float* source, > size_t source_frames, > float* destination, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc >index 3be7c0a3651..2f53a745ae2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc >@@ -19,7 +19,6 @@ > #include "rtc_base/timeutils.h" > #include "test/gmock.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > namespace { >@@ -36,14 +35,13 @@ T DBFS(T x) { > } // namespace > > class PushSincResamplerTest : public ::testing::TestWithParam< >- ::testing::tuple<int, int, double, double>> { >+ ::testing::tuple<int, int, double, double>> { > public: > PushSincResamplerTest() > : input_rate_(::testing::get<0>(GetParam())), > output_rate_(::testing::get<1>(GetParam())), > rms_error_(::testing::get<2>(GetParam())), >- low_freq_error_(::testing::get<3>(GetParam())) { >- } >+ low_freq_error_(::testing::get<3>(GetParam())) {} > > ~PushSincResamplerTest() override {} > >@@ -59,7 +57,7 @@ class PushSincResamplerTest : public ::testing::TestWithParam< > > class ZeroSource : public SincResamplerCallback { > public: >- void Run(size_t frames, float* destination) { >+ void Run(size_t frames, float* destination) override { > std::memset(destination, 0, sizeof(float) * frames); > } > }; >@@ -82,8 +80,8 @@ void PushSincResamplerTest::ResampleBenchmarkTest(bool int_format) { > source_int[i] = static_cast<int16_t>(floor(32767 * source[i] + 0.5)); > } > >- printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n", >- kResampleIterations, input_rate_, output_rate_); >+ printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n", kResampleIterations, >+ input_rate_, output_rate_); > const double io_ratio = input_rate_ / static_cast<double>(output_rate_); > SincResampler sinc_resampler(io_ratio, SincResampler::kDefaultRequestSize, > &resampler_source); >@@ -101,25 +99,23 @@ void PushSincResamplerTest::ResampleBenchmarkTest(bool int_format) { > if (int_format) { > for (int i = 0; i < kResampleIterations; ++i) { > EXPECT_EQ(output_samples, >- resampler.Resample(source_int.get(), >- input_samples, >- destination_int.get(), >- output_samples)); >+ resampler.Resample(source_int.get(), input_samples, >+ destination_int.get(), output_samples)); > } > } else { > for (int i = 0; i < kResampleIterations; ++i) { >- EXPECT_EQ(output_samples, >- resampler.Resample(source.get(), >- input_samples, >- resampled_destination.get(), >- output_samples)); >+ EXPECT_EQ(output_samples, resampler.Resample(source.get(), input_samples, >+ resampled_destination.get(), >+ output_samples)); > } > } > double total_time_us = > (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; >- printf("PushSincResampler took %.2f us per frame; which is a %.1f%% overhead " >- "on SincResampler.\n\n", total_time_us / kResampleIterations, >- (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100); >+ printf( >+ "PushSincResampler took %.2f us per frame; which is a %.1f%% overhead " >+ "on SincResampler.\n\n", >+ total_time_us / kResampleIterations, >+ (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100); > } > > // Disabled because it takes too long to run routinely. Use for performance >@@ -149,8 +145,8 @@ void PushSincResamplerTest::ResampleTest(bool int_format) { > const double input_nyquist_freq = 0.5 * input_rate_; > > // Source for data to be resampled. >- SinusoidalLinearChirpSource resampler_source( >- input_rate_, input_samples, input_nyquist_freq, 0); >+ SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples, >+ input_nyquist_freq, 0); > > PushSincResampler resampler(input_block_size, output_block_size); > >@@ -168,8 +164,8 @@ void PushSincResamplerTest::ResampleTest(bool int_format) { > // deal with it in the test by delaying the "pure" source to match. It must be > // checked before the first call to Resample(), because ChunkSize() will > // change afterwards. >- const size_t output_delay_samples = output_block_size - >- resampler.get_resampler_for_testing()->ChunkSize(); >+ const size_t output_delay_samples = >+ output_block_size - resampler.get_resampler_for_testing()->ChunkSize(); > > // Generate resampled signal. > // With the PushSincResampler, we produce the signal block-by-10ms-block >@@ -178,21 +174,18 @@ void PushSincResamplerTest::ResampleTest(bool int_format) { > if (int_format) { > for (size_t i = 0; i < kNumBlocks; ++i) { > FloatToS16(&source[i * input_block_size], input_block_size, >- source_int.get()); >+ source_int.get()); > EXPECT_EQ(output_block_size, >- resampler.Resample(source_int.get(), >- input_block_size, >- destination_int.get(), >- output_block_size)); >+ resampler.Resample(source_int.get(), input_block_size, >+ destination_int.get(), output_block_size)); > S16ToFloat(destination_int.get(), output_block_size, >- &resampled_destination[i * output_block_size]); >+ &resampled_destination[i * output_block_size]); > } > } else { > for (size_t i = 0; i < kNumBlocks; ++i) { > EXPECT_EQ( > output_block_size, >- resampler.Resample(&source[i * input_block_size], >- input_block_size, >+ resampler.Resample(&source[i * input_block_size], input_block_size, > &resampled_destination[i * output_block_size], > output_block_size)); > } >@@ -252,9 +245,13 @@ void PushSincResamplerTest::ResampleTest(bool int_format) { > EXPECT_LE(high_freq_max_error, kHighFrequencyMaxError); > } > >-TEST_P(PushSincResamplerTest, ResampleInt) { ResampleTest(true); } >+TEST_P(PushSincResamplerTest, ResampleInt) { >+ ResampleTest(true); >+} > >-TEST_P(PushSincResamplerTest, ResampleFloat) { ResampleTest(false); } >+TEST_P(PushSincResamplerTest, ResampleFloat) { >+ ResampleTest(false); >+} > > // Thresholds chosen arbitrarily based on what each resampling reported during > // testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler.cc >index ea85d827e0d..aa3a4bac2aa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler.cc >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* > * A wrapper for resampling a numerous amount of sampling combinations. > */ >@@ -37,8 +36,7 @@ Resampler::Resampler() > my_mode_(kResamplerMode1To1), > num_channels_(0), > slave_left_(nullptr), >- slave_right_(nullptr) { >-} >+ slave_right_(nullptr) {} > > Resampler::Resampler(int inFreq, int outFreq, size_t num_channels) > : Resampler() { >@@ -73,9 +71,9 @@ int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels) { > int tmpInFreq_kHz = inFreq / 1000; > int tmpOutFreq_kHz = outFreq / 1000; > >- if ((tmpInFreq_kHz != my_in_frequency_khz_) >- || (tmpOutFreq_kHz != my_out_frequency_khz_) >- || (num_channels != num_channels_)) { >+ if ((tmpInFreq_kHz != my_in_frequency_khz_) || >+ (tmpOutFreq_kHz != my_out_frequency_khz_) || >+ (num_channels != num_channels_)) { > return Reset(inFreq, outFreq, num_channels); > } else { > return 0; >@@ -191,7 +189,7 @@ int Resampler::Reset(int inFreq, int outFreq, size_t num_channels) { > // 2:6 > state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); > WebRtcSpl_ResetResample16khzTo48khz( >- static_cast<WebRtcSpl_State16khzTo48khz*>(state1_)); >+ static_cast<WebRtcSpl_State16khzTo48khz*>(state1_)); > // 6:3 > state2_ = malloc(8 * sizeof(int32_t)); > memset(state2_, 0, 8 * sizeof(int32_t)); >@@ -395,8 +393,11 @@ int Resampler::ComputeResamplerMode(int in_freq_hz, > } > > // Synchronous resampling, all output samples are written to samplesOut >-int Resampler::Push(const int16_t * samplesIn, size_t lengthIn, >- int16_t* samplesOut, size_t maxLen, size_t& outLen) { >+int Resampler::Push(const int16_t* samplesIn, >+ size_t lengthIn, >+ int16_t* samplesOut, >+ size_t maxLen, >+ size_t& outLen) { > if (num_channels_ == 2) { > // Split up the signal and call the slave object for each channel > int16_t* left = >@@ -575,7 +576,7 @@ int Resampler::Push(const int16_t * samplesIn, size_t lengthIn, > if ((lengthIn % 160) != 0) { > return -1; > } >- tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 3)); >+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 3)); > tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t))); > for (size_t i = 0; i < lengthIn; i += 160) { > WebRtcSpl_Resample16khzTo48khz( >@@ -827,7 +828,7 @@ int Resampler::Push(const int16_t * samplesIn, size_t lengthIn, > return -1; > } > // 3:6 >- tmp = static_cast<int16_t*> (malloc(sizeof(int16_t) * lengthIn * 2)); >+ tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 2)); > WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, > static_cast<int32_t*>(state1_)); > lengthIn *= 2; >@@ -858,8 +859,8 @@ int Resampler::Push(const int16_t * samplesIn, size_t lengthIn, > return -1; > } > tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t))); >- tmp = static_cast<int16_t*>( >- malloc((lengthIn * 4) / 11 * sizeof(int16_t))); >+ tmp = >+ static_cast<int16_t*>(malloc((lengthIn * 4) / 11 * sizeof(int16_t))); > > for (size_t i = 0; i < lengthIn; i += 220) { > WebRtcSpl_Resample22khzTo8khz( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler_unittest.cc >index 03007196374..fd636e29980 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/resampler_unittest.cc >@@ -23,17 +23,10 @@ const size_t kNumChannelsSize = sizeof(kNumChannels) / sizeof(*kNumChannels); > > // Rates we must support. > const int kMaxRate = 96000; >-const int kRates[] = { >- 8000, >- 16000, >- 32000, >- 44000, >- 48000, >- kMaxRate >-}; >+const int kRates[] = {8000, 16000, 32000, 44000, 48000, kMaxRate}; > const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); > const int kMaxChannels = 2; >-const size_t kDataSize = static_cast<size_t> (kMaxChannels * kMaxRate / 100); >+const size_t kDataSize = static_cast<size_t>(kMaxChannels * kMaxRate / 100); > > // TODO(andrew): should we be supporting these combinations? > bool ValidRates(int in_rate, int out_rate) { >@@ -49,8 +42,8 @@ bool ValidRates(int in_rate, int out_rate) { > class ResamplerTest : public testing::Test { > protected: > ResamplerTest(); >- virtual void SetUp(); >- virtual void TearDown(); >+ void SetUp() override; >+ void TearDown() override; > > void ResetIfNeededAndPush(int in_rate, int out_rate, int num_channels); > >@@ -99,7 +92,7 @@ TEST_F(ResamplerTest, Reset) { > for (size_t k = 0; k < kNumChannelsSize; ++k) { > std::ostringstream ss; > ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j] >- << ", channels: " << kNumChannels[k]; >+ << ", channels: " << kNumChannels[k]; > SCOPED_TRACE(ss.str()); > if (ValidRates(kRates[i], kRates[j])) > EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); >@@ -124,8 +117,8 @@ TEST_F(ResamplerTest, Mono) { > size_t in_length = static_cast<size_t>(kRates[i] / 100); > size_t out_length = 0; > EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); >- EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize, >- out_length)); >+ EXPECT_EQ( >+ 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); > EXPECT_EQ(static_cast<size_t>(kRates[j] / 100), out_length); > } else { > EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); >@@ -145,14 +138,12 @@ TEST_F(ResamplerTest, Stereo) { > if (ValidRates(kRates[i], kRates[j])) { > size_t in_length = static_cast<size_t>(kChannels * kRates[i] / 100); > size_t out_length = 0; >- EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], >- kChannels)); >- EXPECT_EQ(0, rs_.Push(data_in_, in_length, data_out_, kDataSize, >- out_length)); >+ EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); >+ EXPECT_EQ( >+ 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); > EXPECT_EQ(static_cast<size_t>(kChannels * kRates[j] / 100), out_length); > } else { >- EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], >- kChannels)); >+ EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); > } > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.cc >index c8577550c95..5aa2061ab75 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.cc >@@ -93,8 +93,8 @@ > #include <limits> > > #include "rtc_base/checks.h" >+#include "rtc_base/system/arch.h" > #include "system_wrappers/include/cpu_features_wrapper.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -160,12 +160,12 @@ SincResampler::SincResampler(double io_sample_rate_ratio, > AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), > input_buffer_(static_cast<float*>( > AlignedMalloc(sizeof(float) * input_buffer_size_, 16))), >-#if defined(WEBRTC_CPU_DETECTION) >+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__) > convolve_proc_(nullptr), > #endif > r1_(input_buffer_.get()), > r2_(input_buffer_.get() + kKernelSize / 2) { >-#if defined(WEBRTC_CPU_DETECTION) >+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__) > InitializeCPUSpecificFeatures(); > RTC_DCHECK(convolve_proc_); > #endif >@@ -217,23 +217,23 @@ void SincResampler::InitializeKernel() { > > for (size_t i = 0; i < kKernelSize; ++i) { > const size_t idx = i + offset_idx * kKernelSize; >- const float pre_sinc = static_cast<float>(M_PI * >- (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) - >- subsample_offset)); >+ const float pre_sinc = static_cast<float>( >+ M_PI * (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) - >+ subsample_offset)); > kernel_pre_sinc_storage_[idx] = pre_sinc; > > // Compute Blackman window, matching the offset of the sinc(). > const float x = (i - subsample_offset) / kKernelSize; > const float window = static_cast<float>(kA0 - kA1 * cos(2.0 * M_PI * x) + >- kA2 * cos(4.0 * M_PI * x)); >+ kA2 * cos(4.0 * M_PI * x)); > kernel_window_storage_[idx] = window; > > // Compute the sinc with offset, then window the sinc() function and store > // at the correct offset. >- kernel_storage_[idx] = static_cast<float>(window * >- ((pre_sinc == 0) ? >- sinc_scale_factor : >- (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); >+ kernel_storage_[idx] = static_cast<float>( >+ window * ((pre_sinc == 0) >+ ? sinc_scale_factor >+ : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); > } > } > } >@@ -255,10 +255,10 @@ void SincResampler::SetRatio(double io_sample_rate_ratio) { > const float window = kernel_window_storage_[idx]; > const float pre_sinc = kernel_pre_sinc_storage_[idx]; > >- kernel_storage_[idx] = static_cast<float>(window * >- ((pre_sinc == 0) ? >- sinc_scale_factor : >- (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); >+ kernel_storage_[idx] = static_cast<float>( >+ window * ((pre_sinc == 0) >+ ? sinc_scale_factor >+ : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); > } > } > } >@@ -312,8 +312,8 @@ void SincResampler::Resample(size_t frames, float* destination) { > // Figure out how much to weight each kernel's "convolution". > const double kernel_interpolation_factor = > virtual_offset_idx - offset_idx; >- *destination++ = CONVOLVE_FUNC( >- input_ptr, k1, k2, kernel_interpolation_factor); >+ *destination++ = >+ CONVOLVE_FUNC(input_ptr, k1, k2, kernel_interpolation_factor); > > // Advance the virtual index. > virtual_source_idx_ += current_io_ratio; >@@ -352,7 +352,8 @@ void SincResampler::Flush() { > UpdateRegions(false); > } > >-float SincResampler::Convolve_C(const float* input_ptr, const float* k1, >+float SincResampler::Convolve_C(const float* input_ptr, >+ const float* k1, > const float* k2, > double kernel_interpolation_factor) { > float sum1 = 0; >@@ -368,7 +369,7 @@ float SincResampler::Convolve_C(const float* input_ptr, const float* k1, > > // Linearly interpolate the two "convolutions". > return static_cast<float>((1.0 - kernel_interpolation_factor) * sum1 + >- kernel_interpolation_factor * sum2); >+ kernel_interpolation_factor * sum2); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.h >index d0112240554..8a833ce88c9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler.h >@@ -18,8 +18,8 @@ > > #include "rtc_base/constructormagic.h" > #include "rtc_base/gtest_prod_util.h" >-#include "system_wrappers/include/aligned_malloc.h" >-#include "typedefs.h" // NOLINT(build/include) >+#include "rtc_base/memory/aligned_malloc.h" >+#include "rtc_base/system/arch.h" > > namespace webrtc { > >@@ -101,14 +101,18 @@ class SincResampler { > // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are > // linearly interpolated using |kernel_interpolation_factor|. On x86 and ARM > // the underlying implementation is chosen at run time. >- static float Convolve_C(const float* input_ptr, const float* k1, >- const float* k2, double kernel_interpolation_factor); >+ static float Convolve_C(const float* input_ptr, >+ const float* k1, >+ const float* k2, >+ double kernel_interpolation_factor); > #if defined(WEBRTC_ARCH_X86_FAMILY) >- static float Convolve_SSE(const float* input_ptr, const float* k1, >+ static float Convolve_SSE(const float* input_ptr, >+ const float* k1, > const float* k2, > double kernel_interpolation_factor); > #elif defined(WEBRTC_HAS_NEON) >- static float Convolve_NEON(const float* input_ptr, const float* k1, >+ static float Convolve_NEON(const float* input_ptr, >+ const float* k1, > const float* k2, > double kernel_interpolation_factor); > #endif >@@ -145,12 +149,14 @@ class SincResampler { > // Data from the source is copied into this buffer for each processing pass. > std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_; > >- // Stores the runtime selection of which Convolve function to use. >- // TODO(ajm): Move to using a global static which must only be initialized >- // once by the user. We're not doing this initially, because we don't have >- // e.g. a LazyInstance helper in webrtc. >-#if defined(WEBRTC_CPU_DETECTION) >- typedef float (*ConvolveProc)(const float*, const float*, const float*, >+// Stores the runtime selection of which Convolve function to use. >+// TODO(ajm): Move to using a global static which must only be initialized >+// once by the user. We're not doing this initially, because we don't have >+// e.g. a LazyInstance helper in webrtc. >+#if defined(WEBRTC_ARCH_X86_FAMILY) && !defined(__SSE2__) >+ typedef float (*ConvolveProc)(const float*, >+ const float*, >+ const float*, > double); > ConvolveProc convolve_proc_; > #endif >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_neon.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_neon.cc >index 9d77f0d12c8..3649324d126 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_neon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_neon.cc >@@ -17,7 +17,8 @@ > > namespace webrtc { > >-float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, >+float SincResampler::Convolve_NEON(const float* input_ptr, >+ const float* k1, > const float* k2, > double kernel_interpolation_factor) { > float32x4_t m_input; >@@ -25,7 +26,7 @@ float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, > float32x4_t m_sums2 = vmovq_n_f32(0); > > const float* upper = input_ptr + kKernelSize; >- for (; input_ptr < upper; ) { >+ for (; input_ptr < upper;) { > m_input = vld1q_f32(input_ptr); > input_ptr += 4; > m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1)); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_sse.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_sse.cc >index 711110858f6..3906a797528 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_sse.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_sse.cc >@@ -17,7 +17,8 @@ > > namespace webrtc { > >-float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, >+float SincResampler::Convolve_SSE(const float* input_ptr, >+ const float* k1, > const float* k2, > double kernel_interpolation_factor) { > __m128 m_input; >@@ -41,17 +42,18 @@ float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, > } > > // Linearly interpolate the two "convolutions". >- m_sums1 = _mm_mul_ps(m_sums1, _mm_set_ps1( >- static_cast<float>(1.0 - kernel_interpolation_factor))); >- m_sums2 = _mm_mul_ps(m_sums2, _mm_set_ps1( >- static_cast<float>(kernel_interpolation_factor))); >+ m_sums1 = _mm_mul_ps( >+ m_sums1, >+ _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor))); >+ m_sums2 = _mm_mul_ps( >+ m_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor))); > m_sums1 = _mm_add_ps(m_sums1, m_sums2); > > // Sum components together. > float result; > m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); >- _mm_store_ss(&result, _mm_add_ss(m_sums2, _mm_shuffle_ps( >- m_sums2, m_sums2, 1))); >+ _mm_store_ss(&result, >+ _mm_add_ss(m_sums2, _mm_shuffle_ps(m_sums2, m_sums2, 1))); > > return result; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_unittest.cc >index 87e991d3b6a..eb5424d54e2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinc_resampler_unittest.cc >@@ -23,6 +23,7 @@ > #include "common_audio/resampler/sinc_resampler.h" > #include "common_audio/resampler/sinusoidal_linear_chirp_source.h" > #include "rtc_base/stringize_macros.h" >+#include "rtc_base/system/arch.h" > #include "rtc_base/timeutils.h" > #include "system_wrappers/include/cpu_features_wrapper.h" > #include "test/gmock.h" >@@ -67,14 +68,14 @@ TEST(SincResamplerTest, ChunkedResample) { > std::unique_ptr<float[]> resampled_destination(new float[max_chunk_size]); > > // Verify requesting ChunkSize() frames causes a single callback. >- EXPECT_CALL(mock_source, Run(_, _)) >- .Times(1).WillOnce(ClearBuffer()); >+ EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer()); > resampler.Resample(resampler.ChunkSize(), resampled_destination.get()); > > // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks. > testing::Mock::VerifyAndClear(&mock_source); > EXPECT_CALL(mock_source, Run(_, _)) >- .Times(kChunks).WillRepeatedly(ClearBuffer()); >+ .Times(kChunks) >+ .WillRepeatedly(ClearBuffer()); > resampler.Resample(max_chunk_size, resampled_destination.get()); > } > >@@ -87,16 +88,14 @@ TEST(SincResamplerTest, Flush) { > new float[resampler.ChunkSize()]); > > // Fill the resampler with junk data. >- EXPECT_CALL(mock_source, Run(_, _)) >- .Times(1).WillOnce(FillBuffer()); >+ EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(FillBuffer()); > resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); > ASSERT_NE(resampled_destination[0], 0); > > // Flush and request more data, which should all be zeros now. > resampler.Flush(); > testing::Mock::VerifyAndClear(&mock_source); >- EXPECT_CALL(mock_source, Run(_, _)) >- .Times(1).WillOnce(ClearBuffer()); >+ EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer()); > resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); > for (size_t i = 0; i < resampler.ChunkSize() / 2; ++i) > ASSERT_FLOAT_EQ(resampled_destination[i], 0); >@@ -116,7 +115,6 @@ TEST(SincResamplerTest, DISABLED_SetRatioBench) { > printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000); > } > >- > // Define platform independent function name for Convolve* tests. > #if defined(WEBRTC_ARCH_X86_FAMILY) > #define CONVOLVE_FUNC Convolve_SSE >@@ -232,8 +230,7 @@ TEST(SincResamplerTest, ConvolveBenchmark) { > #undef CONVOLVE_FUNC > > typedef std::tuple<int, int, double, double> SincResamplerTestData; >-class SincResamplerTest >- : public testing::TestWithParam<SincResamplerTestData> { >+class SincResamplerTest : public testing::TestWithParam<SincResamplerTestData> { > public: > SincResamplerTest() > : input_rate_(std::get<0>(GetParam())), >@@ -263,8 +260,8 @@ TEST_P(SincResamplerTest, Resample) { > const double input_nyquist_freq = 0.5 * input_rate_; > > // Source for data to be resampled. >- SinusoidalLinearChirpSource resampler_source( >- input_rate_, input_samples, input_nyquist_freq, 0); >+ SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples, >+ input_nyquist_freq, 0); > > const double io_ratio = input_rate_ / static_cast<double>(output_rate_); > SincResampler resampler(io_ratio, SincResampler::kDefaultRequestSize, >@@ -291,8 +288,8 @@ TEST_P(SincResamplerTest, Resample) { > resampler.Resample(output_samples, resampled_destination.get()); > > // Generate pure signal. >- SinusoidalLinearChirpSource pure_source( >- output_rate_, output_samples, input_nyquist_freq, 0); >+ SinusoidalLinearChirpSource pure_source(output_rate_, output_samples, >+ input_nyquist_freq, 0); > pure_source.Run(output_samples, pure_destination.get()); > > // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which >@@ -324,8 +321,8 @@ TEST_P(SincResamplerTest, Resample) { > > double rms_error = sqrt(sum_of_squares / output_samples); > >- // Convert each error to dbFS. >- #define DBFS(x) 20 * log10(x) >+// Convert each error to dbFS. >+#define DBFS(x) 20 * log10(x) > rms_error = DBFS(rms_error); > low_freq_max_error = DBFS(low_freq_max_error); > high_freq_max_error = DBFS(high_freq_max_error); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc >index 134044e7786..2afdd1be476 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc >@@ -43,8 +43,7 @@ void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) { > } else { > // Sinusoidal linear chirp. > double t = (current_index_ - delay_samples_) / sample_rate_; >- destination[i] = >- sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t)); >+ destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t)); > } > } > } >@@ -52,7 +51,7 @@ void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) { > > double SinusoidalLinearChirpSource::Frequency(size_t position) { > return kMinFrequency + (position - delay_samples_) * >- (max_frequency_ - kMinFrequency) / total_samples_; >+ (max_frequency_ - kMinFrequency) / total_samples_; > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h >index 7fcbaa08214..71dcff5eb96 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h >@@ -26,19 +26,19 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback { > public: > // |delay_samples| can be used to insert a fractional sample delay into the > // source. It will produce zeros until non-negative time is reached. >- SinusoidalLinearChirpSource(int sample_rate, size_t samples, >- double max_frequency, double delay_samples); >+ SinusoidalLinearChirpSource(int sample_rate, >+ size_t samples, >+ double max_frequency, >+ double delay_samples); > >- virtual ~SinusoidalLinearChirpSource() {} >+ ~SinusoidalLinearChirpSource() override {} > > void Run(size_t frames, float* destination) override; > > double Frequency(size_t position); > > private: >- enum { >- kMinFrequency = 5 >- }; >+ enum { kMinFrequency = 5 }; > > int sample_rate_; > size_t total_samples_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer.h >index aa2ac27375b..0bbe879980d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer.h >@@ -53,7 +53,8 @@ size_t WebRtc_ReadBuffer(RingBuffer* handle, > size_t element_count); > > // Writes |data| to buffer and returns the number of elements written. >-size_t WebRtc_WriteBuffer(RingBuffer* handle, const void* data, >+size_t WebRtc_WriteBuffer(RingBuffer* handle, >+ const void* data, > size_t element_count); > > // Moves the buffer read position and returns the number of elements moved. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer_unittest.cc >index 4bb1497b17b..130e1246733 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/ring_buffer_unittest.cc >@@ -21,9 +21,7 @@ > namespace webrtc { > > struct FreeBufferDeleter { >- inline void operator()(void* ptr) const { >- WebRtc_FreeBuffer(ptr); >- } >+ inline void operator()(void* ptr) const { WebRtc_FreeBuffer(ptr); } > }; > typedef std::unique_ptr<RingBuffer, FreeBufferDeleter> scoped_ring_buffer; > >@@ -31,7 +29,8 @@ static void AssertElementEq(int expected, int actual) { > ASSERT_EQ(expected, actual); > } > >-static int SetIncrementingData(int* data, int num_elements, >+static int SetIncrementingData(int* data, >+ int num_elements, > int starting_value) { > for (int i = 0; i < num_elements; i++) { > data[i] = starting_value++; >@@ -39,7 +38,8 @@ static int SetIncrementingData(int* data, int num_elements, > return starting_value; > } > >-static int CheckIncrementingData(int* data, int num_elements, >+static int CheckIncrementingData(int* data, >+ int num_elements, > int starting_value) { > for (int i = 0; i < num_elements; i++) { > AssertElementEq(starting_value++, data[i]); >@@ -70,35 +70,33 @@ static void RandomStressTest(int** data_ptr) { > int read_element = 0; > for (int j = 0; j < kNumOps; j++) { > const bool write = rand() % 2 == 0 ? true : false; // NOLINT >- const int num_elements = rand() % buffer_size; // NOLINT >+ const int num_elements = rand() % buffer_size; // NOLINT > if (write) { > const int buffer_available = buffer_size - buffer_consumed; > ASSERT_EQ(static_cast<size_t>(buffer_available), > WebRtc_available_write(buffer.get())); > const int expected_elements = std::min(num_elements, buffer_available); > write_element = SetIncrementingData(write_data.get(), expected_elements, >- write_element); >- ASSERT_EQ(static_cast<size_t>(expected_elements), >- WebRtc_WriteBuffer(buffer.get(), write_data.get(), >- num_elements)); >- buffer_consumed = std::min(buffer_consumed + expected_elements, >- buffer_size); >+ write_element); >+ ASSERT_EQ( >+ static_cast<size_t>(expected_elements), >+ WebRtc_WriteBuffer(buffer.get(), write_data.get(), num_elements)); >+ buffer_consumed = >+ std::min(buffer_consumed + expected_elements, buffer_size); > } else { >- const int expected_elements = std::min(num_elements, >- buffer_consumed); >+ const int expected_elements = std::min(num_elements, buffer_consumed); > ASSERT_EQ(static_cast<size_t>(buffer_consumed), > WebRtc_available_read(buffer.get())); >- ASSERT_EQ(static_cast<size_t>(expected_elements), >- WebRtc_ReadBuffer(buffer.get(), >- reinterpret_cast<void**>(data_ptr), >- read_data.get(), >- num_elements)); >+ ASSERT_EQ( >+ static_cast<size_t>(expected_elements), >+ WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(data_ptr), >+ read_data.get(), num_elements)); > int* check_ptr = read_data.get(); > if (data_ptr) { > check_ptr = *data_ptr; > } >- read_element = CheckIncrementingData(check_ptr, expected_elements, >- read_element); >+ read_element = >+ CheckIncrementingData(check_ptr, expected_elements, read_element); > buffer_consumed = std::max(buffer_consumed - expected_elements, 0); > } > } >@@ -127,8 +125,9 @@ TEST(RingBufferTest, PassingNulltoReadBufferForcesMemcpy) { > SetIncrementingData(write_data, kDataSize, 0); > EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize)); > SetIncrementingData(read_data, kDataSize, kDataSize); >- EXPECT_EQ(kDataSize, WebRtc_ReadBuffer(buffer.get(), >- reinterpret_cast<void**>(&data_ptr), read_data, kDataSize)); >+ EXPECT_EQ(kDataSize, >+ WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(&data_ptr), >+ read_data, kDataSize)); > // Copying was not necessary, so |read_data| has not been updated. > CheckIncrementingData(data_ptr, kDataSize, 0); > CheckIncrementingData(read_data, kDataSize, kDataSize); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S >index c70349aaffa..be8e181aa7b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S >@@ -12,7 +12,7 @@ > @ for ARMv5 platforms. > @ Reference C code is in file complex_bit_reverse.c. Bit-exact. > >-#include "system_wrappers/include/asm_defines.h" >+#include "rtc_base/system/asm_defines.h" > > GLOBAL_FUNCTION WebRtcSpl_ComplexBitReverse > .align 2 >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft.c >index 36689b3c462..ddc9a97b599 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft.c >@@ -17,6 +17,7 @@ > > #include "common_audio/signal_processing/complex_fft_tables.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" >+#include "rtc_base/system/arch.h" > > #define CFFTSFT 14 > #define CFFTRND 1 >@@ -166,7 +167,7 @@ int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) > /* The 1024-value is a constant given from the size of kSinTable1024[], > * and should not be changed depending on the input parameter 'stages' > */ >- n = 1 << stages; >+ n = ((size_t)1) << stages; > if (n > 1024) > return -1; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft_tables.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft_tables.h >index 6c3fcfdbe05..90fac072d27 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft_tables.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/complex_fft_tables.h >@@ -8,141 +8,125 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ > #define COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ > >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > static const int16_t kSinTable1024[] = { >- 0, 201, 402, 603, 804, 1005, 1206, 1406, >- 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011, >- 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, >- 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195, >- 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, >- 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319, >- 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, >- 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353, >- 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, >- 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, >- 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, >- 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036, >- 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, >- 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631, >- 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, >- 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027, >- 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, >- 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, >- 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, >- 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132, >- 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, >- 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802, >- 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, >- 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195, >- 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, >- 30851, 30918, 30984, 31049, 31113, 31175, 31236, 31297, >- 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, >- 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, >- 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, >- 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588, >- 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, >- 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766, >- 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736, >- 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628, >- 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, >- 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, >- 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, >- 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413, >- 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, >- 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349, >- 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, >- 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992, >- 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, >- 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355, >- 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, >- 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, >- 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, >- 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311, >- 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, >- 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942, >- 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, >- 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371, >- 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, >- 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, >- 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, >- 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724, >- 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, >- 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703, >- 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, >- 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589, >- 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, >- 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411, >- 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, >- 1607, 1406, 1206, 1005, 804, 603, 402, 201, >- 0, -201, -402, -603, -804, -1005, -1206, -1406, >- -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011, >- -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, >- -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195, >- -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, >- -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319, >- -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, >- -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, >- -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, >- -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268, >- -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, >- -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036, >- -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, >- -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631, >- -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, >- -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027, >- -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, >- -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, >- -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, >- -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132, >- -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, >- -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802, >- -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, >- -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195, >- -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, >- -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, >- -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, >- -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097, >- -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, >- -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588, >- -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, >- -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766, >- -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736, >- -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628, >- -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, >- -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, >- -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, >- -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413, >- -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, >- -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349, >- -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, >- -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992, >- -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, >- -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, >- -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, >- -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456, >- -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, >- -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311, >- -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, >- -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942, >- -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, >- -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371, >- -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, >- -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, >- -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, >- -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724, >- -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, >- -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703, >- -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, >- -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589, >- -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, >- -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, >- -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, >- -1607, -1406, -1206, -1005, -804, -603, -402, -201 >-}; >+ 0, 201, 402, 603, 804, 1005, 1206, 1406, 1607, >+ 1808, 2009, 2209, 2410, 2610, 2811, 3011, 3211, 3411, >+ 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205, >+ 5403, 5601, 5799, 5997, 6195, 6392, 6589, 6786, 6982, >+ 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739, >+ 8932, 9126, 9319, 9511, 9703, 9895, 10087, 10278, 10469, >+ 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166, >+ 12353, 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, >+ 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, 15446, >+ 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017, >+ 17189, 17360, 17530, 17699, 17868, 18036, 18204, 18371, 18537, >+ 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000, >+ 20159, 20317, 20474, 20631, 20787, 20942, 21096, 21249, 21402, >+ 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739, >+ 22883, 23027, 23169, 23311, 23452, 23592, 23731, 23869, 24006, >+ 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, >+ 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318, >+ 26437, 26556, 26673, 26789, 26905, 27019, 27132, 27244, 27355, >+ 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309, >+ 28410, 28510, 28608, 28706, 28802, 28897, 28992, 29085, 29177, >+ 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955, >+ 30036, 30116, 30195, 30272, 30349, 30424, 30498, 30571, 30643, >+ 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236, >+ 31297, 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, >+ 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, 32137, >+ 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441, >+ 32468, 32495, 32520, 32544, 32567, 32588, 32609, 32628, 32646, >+ 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751, >+ 32757, 32761, 32764, 32766, 32767, 32766, 32764, 32761, 32757, >+ 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662, >+ 32646, 32628, 32609, 32588, 32567, 32544, 32520, 32495, 32468, >+ 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, >+ 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785, >+ 31735, 31684, 31633, 31580, 31525, 31470, 31413, 31356, 31297, >+ 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713, >+ 30643, 30571, 30498, 30424, 30349, 30272, 30195, 30116, 30036, >+ 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268, >+ 29177, 29085, 28992, 28897, 28802, 28706, 28608, 28510, 28410, >+ 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, >+ 27355, 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, >+ 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, 25329, >+ 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143, >+ 24006, 23869, 23731, 23592, 23452, 23311, 23169, 23027, 22883, >+ 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554, >+ 21402, 21249, 21096, 20942, 20787, 20631, 20474, 20317, 20159, >+ 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702, >+ 18537, 18371, 18204, 18036, 17868, 17699, 17530, 17360, 17189, >+ 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, >+ 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009, >+ 13827, 13645, 13462, 13278, 13094, 12909, 12724, 12539, 12353, >+ 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659, >+ 10469, 10278, 10087, 9895, 9703, 9511, 9319, 9126, 8932, >+ 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179, >+ 6982, 6786, 6589, 6392, 6195, 5997, 5799, 5601, 5403, >+ 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611, >+ 3411, 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, >+ 1607, 1406, 1206, 1005, 804, 603, 402, 201, 0, >+ -201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808, >+ -2009, -2209, -2410, -2610, -2811, -3011, -3211, -3411, -3611, >+ -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403, >+ -5601, -5799, -5997, -6195, -6392, -6589, -6786, -6982, -7179, >+ -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932, >+ -9126, -9319, -9511, -9703, -9895, -10087, -10278, -10469, -10659, >+ -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, >+ -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009, >+ -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623, >+ -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189, >+ -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702, >+ -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159, >+ -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554, >+ -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883, >+ -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, >+ -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329, >+ -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437, >+ -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466, >+ -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410, >+ -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268, >+ -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036, >+ -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713, >+ -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, >+ -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785, >+ -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176, >+ -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468, >+ -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662, >+ -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757, >+ -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751, >+ -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646, >+ -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, >+ -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137, >+ -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735, >+ -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236, >+ -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643, >+ -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955, >+ -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177, >+ -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309, >+ -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, >+ -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318, >+ -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201, >+ -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006, >+ -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739, >+ -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402, >+ -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000, >+ -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537, >+ -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, >+ -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446, >+ -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827, >+ -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166, >+ -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469, >+ -10278, -10087, -9895, -9703, -9511, -9319, -9126, -8932, -8739, >+ -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982, >+ -6786, -6589, -6392, -6195, -5997, -5799, -5601, -5403, -5205, >+ -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, >+ -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607, >+ -1406, -1206, -1005, -804, -603, -402, -201}; > > #endif // COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/cross_correlation_neon.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/cross_correlation_neon.c >index fdd03f1976d..f2afbdf9f53 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/cross_correlation_neon.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/cross_correlation_neon.c >@@ -9,6 +9,7 @@ > */ > > #include "common_audio/signal_processing/include/signal_processing_library.h" >+#include "rtc_base/system/arch.h" > > #include <arm_neon.h> > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/dot_product_with_scale.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/dot_product_with_scale.h >index ff3c525066a..bb892d40cb3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/dot_product_with_scale.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/dot_product_with_scale.h >@@ -11,10 +11,9 @@ > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ > #define COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ > >+#include <stdint.h> > #include <string.h> > >-#include "typedefs.h" // NOLINT(build/include) >- > #ifdef __cplusplus > extern "C" { > #endif >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/downsample_fast.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/downsample_fast.c >index 9a2ea053da2..80fdc58a499 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/downsample_fast.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/downsample_fast.c >@@ -42,8 +42,13 @@ int WebRtcSpl_DownsampleFastC(const int16_t* data_in, > out_s32 = 2048; // Round value, 0.5 in Q12. > > for (j = 0; j < coefficients_length; j++) { >- rtc_MsanCheckInitialized(&data_in[i - j], sizeof(data_in[0]), 1); >- out_s32 += coefficients[j] * data_in[i - j]; // Q12. >+ // Negative overflow is permitted here, because this is >+ // auto-regressive filters, and the state for each batch run is >+ // stored in the "negative" positions of the output vector. >+ rtc_MsanCheckInitialized(&data_in[(ptrdiff_t) i - (ptrdiff_t) j], >+ sizeof(data_in[0]), 1); >+ // out_s32 is in Q12 domain. >+ out_s32 += coefficients[j] * data_in[(ptrdiff_t) i - (ptrdiff_t) j]; > } > > out_s32 >>= 12; // Q0. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar.c >index 49d5d61960f..2471cd11178 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar.c >@@ -17,6 +17,8 @@ > > #include "common_audio/signal_processing/include/signal_processing_library.h" > >+#include "rtc_base/checks.h" >+ > size_t WebRtcSpl_FilterAR(const int16_t* a, > size_t a_length, > const int16_t* x, >@@ -40,8 +42,10 @@ size_t WebRtcSpl_FilterAR(const int16_t* a, > { > // Calculate filtered[i] and filtered_low[i] > const int16_t* a_ptr = &a[1]; >- int16_t* filtered_ptr = &filtered[i - 1]; >- int16_t* filtered_low_ptr = &filtered_low[i - 1]; >+ // The index can become negative, but the arrays will never be indexed >+ // with it when negative. Nevertheless, the index cannot be a size_t >+ // because of this. >+ int filtered_ix = (int)i - 1; > int16_t* state_ptr = &state[state_length - 1]; > int16_t* state_low_ptr = &state_low[state_length - 1]; > >@@ -51,8 +55,10 @@ size_t WebRtcSpl_FilterAR(const int16_t* a, > stop = (i < a_length) ? i + 1 : a_length; > for (j = 1; j < stop; j++) > { >- o -= *a_ptr * *filtered_ptr--; >- oLOW -= *a_ptr++ * *filtered_low_ptr--; >+ RTC_DCHECK_GE(filtered_ix, 0); >+ o -= *a_ptr * filtered[filtered_ix]; >+ oLOW -= *a_ptr++ * filtered_low[filtered_ix]; >+ --filtered_ix; > } > for (j = i + 1; j < a_length; j++) > { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c >index df9e51889ab..8b8bdb1af5e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c >@@ -8,6 +8,8 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include "stddef.h" >+ > #include "rtc_base/checks.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" > >@@ -29,7 +31,10 @@ void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, > int64_t sum = 0; > > for (j = coefficients_length - 1; j > 0; j--) { >- sum += coefficients[j] * data_out[i - j]; >+ // Negative overflow is permitted here, because this is >+ // auto-regressive filters, and the state for each batch run is >+ // stored in the "negative" positions of the output vector. >+ sum += coefficients[j] * data_out[(ptrdiff_t) i - (ptrdiff_t) j]; > } > > output = coefficients[0] * data_in[i]; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S >index c6397c2055c..60319d29ffd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S >@@ -35,7 +35,7 @@ > @ r11: Scratch > @ r12: &coefficients[j] > >-#include "system_wrappers/include/asm_defines.h" >+#include "rtc_base/system/asm_defines.h" > > GLOBAL_FUNCTION WebRtcSpl_FilterARFastQ12 > .align 2 >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c >index 9596ef19222..329d47e14f9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c >@@ -37,7 +37,10 @@ void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr, > > for (j = 0; j < B_length; j++) > { >- o += B[j] * in_ptr[i - j]; >+ // Negative overflow is permitted here, because this is >+ // auto-regressive filters, and the state for each batch run is >+ // stored in the "negative" positions of the output vector. >+ o += B[j] * in_ptr[(ptrdiff_t) i - (ptrdiff_t) j]; > } > > // If output is higher than 32768, saturate it. Same with negative side >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/real_fft.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/real_fft.h >index 7d21072bc71..84450667d1a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/real_fft.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/real_fft.h >@@ -11,12 +11,11 @@ > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ > #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ > >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > // For ComplexFFT(), the maximum fft order is 10; >-// for OpenMax FFT in ARM, it is 12; > // WebRTC APM uses orders of only 7 and 8. >-enum {kMaxFFTOrder = 10}; >+enum { kMaxFFTOrder = 10 }; > > struct RealFFT; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/signal_processing_library.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/signal_processing_library.h >index 27fea6f8377..33469d429b2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/signal_processing_library.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/signal_processing_library.h >@@ -8,11 +8,10 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* >- * This header file includes all of the fix point signal processing library (SPL) function >- * descriptions and declarations. >- * For specific function calls, see bottom of file. >+ * This header file includes all of the fix point signal processing library >+ * (SPL) function descriptions and declarations. For specific function calls, >+ * see bottom of file. > */ > > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ >@@ -20,66 +19,60 @@ > > #include <string.h> > #include "common_audio/signal_processing/dot_product_with_scale.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Macros specific for the fixed point implementation >-#define WEBRTC_SPL_WORD16_MAX 32767 >-#define WEBRTC_SPL_WORD16_MIN -32768 >-#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff >-#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000 >-#define WEBRTC_SPL_MAX_LPC_ORDER 14 >-#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value >-#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value >+#define WEBRTC_SPL_WORD16_MAX 32767 >+#define WEBRTC_SPL_WORD16_MIN -32768 >+#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff >+#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000 >+#define WEBRTC_SPL_MAX_LPC_ORDER 14 >+#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value >+#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value > // TODO(kma/bjorn): For the next two macros, investigate how to correct the code > // for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN. >-#define WEBRTC_SPL_ABS_W16(a) \ >- (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a)) >-#define WEBRTC_SPL_ABS_W32(a) \ >- (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a)) >- >-#define WEBRTC_SPL_MUL(a, b) \ >- ((int32_t) ((int32_t)(a) * (int32_t)(b))) >-#define WEBRTC_SPL_UMUL(a, b) \ >- ((uint32_t) ((uint32_t)(a) * (uint32_t)(b))) >-#define WEBRTC_SPL_UMUL_32_16(a, b) \ >- ((uint32_t) ((uint32_t)(a) * (uint16_t)(b))) >-#define WEBRTC_SPL_MUL_16_U16(a, b) \ >- ((int32_t)(int16_t)(a) * (uint16_t)(b)) >+#define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a)) >+#define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a)) >+ >+#define WEBRTC_SPL_MUL(a, b) ((int32_t)((int32_t)(a) * (int32_t)(b))) >+#define WEBRTC_SPL_UMUL(a, b) ((uint32_t)((uint32_t)(a) * (uint32_t)(b))) >+#define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b))) >+#define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b)) > >+// clang-format off >+// clang-format would choose some identation >+// leading to presubmit error (cpplint.py) > #ifndef WEBRTC_ARCH_ARM_V7 > // For ARMv7 platforms, these are inline functions in spl_inl_armv7.h > #ifndef MIPS32_LE > // For MIPS platforms, these are inline functions in spl_inl_mips.h >-#define WEBRTC_SPL_MUL_16_16(a, b) \ >- ((int32_t) (((int16_t)(a)) * ((int16_t)(b)))) >+#define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b)))) > #define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \ >- (WEBRTC_SPL_MUL_16_16(a, b >> 16) \ >- + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15)) >+ (WEBRTC_SPL_MUL_16_16(a, b >> 16) + \ >+ ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15)) > #endif > #endif > > #define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \ >- (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \ >- (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10)) >+ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \ >+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10)) > #define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \ >- (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \ >- (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13)) >+ (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \ >+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13)) > #define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \ >- ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \ >- (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14)) >+ ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \ >+ (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14)) >+// clang-format on > >-#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) \ >- (WEBRTC_SPL_MUL_16_16(a, b) >> (c)) >+#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) (WEBRTC_SPL_MUL_16_16(a, b) >> (c)) > > #define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \ >- ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t) \ >- (((int32_t)1) << ((c) - 1)))) >> (c)) >+ ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c)) > > // C + the 32 most significant bits of A * B > #define WEBRTC_SPL_SCALEDIFF32(A, B, C) \ >- (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16)) >+ (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16)) > >-#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) >+#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) > > // Shifting with negative numbers allowed > // Positive means left shift >@@ -87,12 +80,11 @@ > > // Shifting with negative numbers not allowed > // We cannot do casting here due to signed/unsigned problem >-#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) >+#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) > >-#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c)) >+#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c)) > >-#define WEBRTC_SPL_RAND(a) \ >- ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff)) >+#define WEBRTC_SPL_RAND(a) ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff)) > > #ifdef __cplusplus > extern "C" { >@@ -104,6 +96,9 @@ extern "C" { > // inline functions: > #include "common_audio/signal_processing/include/spl_inl.h" > >+// third party math functions >+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" >+ > // Initialize SPL. Currently it contains only function pointer initialization. > // If the underlying platform is known to be ARM-Neon (WEBRTC_HAS_NEON defined), > // the pointers will be assigned to code optimized for Neon; otherwise, generic >@@ -131,13 +126,10 @@ void WebRtcSpl_CopyFromEndW16(const int16_t* in_vector, > size_t in_vector_length, > size_t samples, > int16_t* out_vector); >-void WebRtcSpl_ZerosArrayW16(int16_t* vector, >- size_t vector_length); >-void WebRtcSpl_ZerosArrayW32(int32_t* vector, >- size_t vector_length); >+void WebRtcSpl_ZerosArrayW16(int16_t* vector, size_t vector_length); >+void WebRtcSpl_ZerosArrayW32(int32_t* vector, size_t vector_length); > // End: Copy and set operations. > >- > // Minimum and maximum operation functions and their pointers. > // Implementation in min_max_operations.c. > >@@ -297,7 +289,6 @@ size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length); > > // End: Minimum and maximum operations. > >- > // Vector scaling operations. Implementation in vector_scaling_operations.c. > // Description at bottom of file. > void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector, >@@ -323,9 +314,11 @@ void WebRtcSpl_ScaleVectorWithSat(const int16_t* in_vector, > size_t vector_length, > int16_t right_shifts); > void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1, >- int16_t gain1, int right_shifts1, >+ int16_t gain1, >+ int right_shifts1, > const int16_t* in_vector2, >- int16_t gain2, int right_shifts2, >+ int16_t gain2, >+ int right_shifts2, > int16_t* out_vector, > size_t vector_length); > >@@ -583,7 +576,6 @@ int16_t WebRtcSpl_RandUArray(int16_t* vector, > > // Math functions > int32_t WebRtcSpl_Sqrt(int32_t value); >-int32_t WebRtcSpl_SqrtFloor(int32_t value); > > // Divisions. Implementations collected in division_operations.c and > // descriptions at bottom of this file. >@@ -777,7 +769,8 @@ typedef struct { > int32_t S_16_8[8]; > } WebRtcSpl_State22khzTo8khz; > >-void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State22khzTo8khz* state, > int32_t* tmpmem); > >@@ -790,7 +783,8 @@ typedef struct { > int32_t S_11_22[8]; > } WebRtcSpl_State8khzTo22khz; > >-void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State8khzTo22khz* state, > int32_t* tmpmem); > >@@ -830,7 +824,8 @@ typedef struct { > int32_t S_32_16[8]; > } WebRtcSpl_State48khzTo16khz; > >-void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State48khzTo16khz* state, > int32_t* tmpmem); > >@@ -842,7 +837,8 @@ typedef struct { > int32_t S_24_48[8]; > } WebRtcSpl_State16khzTo48khz; > >-void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State16khzTo48khz* state, > int32_t* tmpmem); > >@@ -855,7 +851,8 @@ typedef struct { > int32_t S_16_8[8]; > } WebRtcSpl_State48khzTo8khz; > >-void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State48khzTo8khz* state, > int32_t* tmpmem); > >@@ -868,7 +865,8 @@ typedef struct { > int32_t S_24_48[8]; > } WebRtcSpl_State8khzTo48khz; > >-void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out, >+void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, >+ int16_t* out, > WebRtcSpl_State8khzTo48khz* state, > int32_t* tmpmem); > >@@ -881,11 +879,15 @@ void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state); > * > ******************************************************************/ > >-void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, >- int16_t* out, int32_t* filtState); >+void WebRtcSpl_DownsampleBy2(const int16_t* in, >+ size_t len, >+ int16_t* out, >+ int32_t* filtState); > >-void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len, >- int16_t* out, int32_t* filtState); >+void WebRtcSpl_UpsampleBy2(const int16_t* in, >+ size_t len, >+ int16_t* out, >+ int32_t* filtState); > > /************************************************************ > * END OF RESAMPLING FUNCTIONS >@@ -1334,23 +1336,6 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band, > // Return value : Result of the sqrt calculation > // > >-// >-// WebRtcSpl_SqrtFloor(...) >-// >-// Returns the square root of the input value |value|. The precision of this >-// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. >-// If |value| is a negative number then 0 is returned. >-// >-// Algorithm: >-// >-// An iterative 4 cylce/bit routine >-// >-// Input: >-// - value : Value to calculate sqrt of >-// >-// Return value : Result of the sqrt calculation >-// >- > // > // WebRtcSpl_DivU32U16(...) > // >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl.h >index ba3a11376b9..656a3125bbe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl.h >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > // This header file includes the inline functions in > // the fix point signal processing library. > >@@ -73,7 +72,7 @@ static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) { > > #if !defined(MIPS_DSP_R1_LE) > static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { >- int16_t out16 = (int16_t) value32; >+ int16_t out16 = (int16_t)value32; > > if (value32 > 32767) > out16 = 32767; >@@ -112,11 +111,11 @@ static __inline int32_t WebRtcSpl_SubSatW32(int32_t a, int32_t b) { > } > > static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { >- return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b); >+ return WebRtcSpl_SatW32ToW16((int32_t)a + (int32_t)b); > } > > static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { >- return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2); >+ return WebRtcSpl_SatW32ToW16((int32_t)var1 - (int32_t)var2); > } > #endif // #if !defined(MIPS_DSP_R1_LE) > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h >index 97179f92f2a..930e91e2b35 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* This header file includes the inline functions for ARM processors in > * the fix point signal processing library. > */ >@@ -26,35 +25,37 @@ > */ > static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { > int32_t tmp = 0; >- __asm __volatile ("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a)); >+ __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a)); > return tmp; > } > > static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) { > int32_t tmp = 0; >- __asm __volatile ("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b)); >+ __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b)); > return tmp; > } > > // TODO(kma): add unit test. > static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { > int32_t tmp = 0; >- __asm __volatile ("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c)); >+ __asm __volatile("smlabb %0, %1, %2, %3" >+ : "=r"(tmp) >+ : "r"(a), "r"(b), "r"(c)); > return tmp; > } > > static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { > int32_t s_sum = 0; > >- __asm __volatile ("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b)); >+ __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b)); > >- return (int16_t) s_sum; >+ return (int16_t)s_sum; > } > > static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { > int32_t l_sum = 0; > >- __asm __volatile ("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2)); >+ __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2)); > > return l_sum; > } >@@ -62,7 +63,7 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { > static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { > int32_t l_sub = 0; > >- __asm __volatile ("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2)); >+ __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2)); > > return l_sub; > } >@@ -70,7 +71,7 @@ static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { > static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { > int32_t s_sub = 0; > >- __asm __volatile ("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2)); >+ __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2)); > > return (int16_t)s_sub; > } >@@ -78,7 +79,7 @@ static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { > static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { > int32_t tmp = 0; > >- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(n)); >+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n)); > > return (int16_t)(32 - tmp); > } >@@ -92,7 +93,7 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) { > a ^= 0xFFFFFFFF; > } > >- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a)); >+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); > > return (int16_t)(tmp - 1); > } >@@ -100,9 +101,10 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) { > static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { > int tmp = 0; > >- if (a == 0) return 0; >+ if (a == 0) >+ return 0; > >- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a)); >+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); > > return (int16_t)tmp; > } >@@ -117,7 +119,7 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) { > a_32 ^= 0xFFFFFFFF; > } > >- __asm __volatile ("clz %0, %1":"=r"(tmp):"r"(a_32)); >+ __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32)); > > return (int16_t)(tmp - 17); > } >@@ -126,7 +128,7 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) { > static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { > int32_t out = 0; > >- __asm __volatile ("ssat %0, #16, %1" : "=r"(out) : "r"(value32)); >+ __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32)); > > return (int16_t)out; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_mips.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_mips.h >index 5819d0f86bd..1db95e8254d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_mips.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/include/spl_inl_mips.h >@@ -8,69 +8,65 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > // This header file includes the inline functions in > // the fix point signal processing library. > > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ > #define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ > >-static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, >- int32_t b) { >+static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) { > int32_t value32 = 0; > int32_t a1 = 0, b1 = 0; > > __asm __volatile( > #if defined(MIPS32_R2_LE) >- "seh %[a1], %[a] \n\t" >- "seh %[b1], %[b] \n\t" >+ "seh %[a1], %[a] \n\t" >+ "seh %[b1], %[b] \n\t" > #else >- "sll %[a1], %[a], 16 \n\t" >- "sll %[b1], %[b], 16 \n\t" >- "sra %[a1], %[a1], 16 \n\t" >- "sra %[b1], %[b1], 16 \n\t" >+ "sll %[a1], %[a], 16 \n\t" >+ "sll %[b1], %[b], 16 \n\t" >+ "sra %[a1], %[a1], 16 \n\t" >+ "sra %[b1], %[b1], 16 \n\t" > #endif >- "mul %[value32], %[a1], %[b1] \n\t" >- : [value32] "=r" (value32), [a1] "=&r" (a1), [b1] "=&r" (b1) >- : [a] "r" (a), [b] "r" (b) >- : "hi", "lo"); >+ "mul %[value32], %[a1], %[b1] \n\t" >+ : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1) >+ : [a] "r"(a), [b] "r"(b) >+ : "hi", "lo"); > return value32; > } > >-static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, >- int32_t b) { >+static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { > int32_t value32 = 0, b1 = 0, b2 = 0; > int32_t a1 = 0; > > __asm __volatile( > #if defined(MIPS32_R2_LE) >- "seh %[a1], %[a] \n\t" >+ "seh %[a1], %[a] \n\t" > #else >- "sll %[a1], %[a], 16 \n\t" >- "sra %[a1], %[a1], 16 \n\t" >+ "sll %[a1], %[a], 16 \n\t" >+ "sra %[a1], %[a1], 16 \n\t" > #endif >- "andi %[b2], %[b], 0xFFFF \n\t" >- "sra %[b1], %[b], 16 \n\t" >- "sra %[b2], %[b2], 1 \n\t" >- "mul %[value32], %[a1], %[b1] \n\t" >- "mul %[b2], %[a1], %[b2] \n\t" >- "addiu %[b2], %[b2], 0x4000 \n\t" >- "sra %[b2], %[b2], 15 \n\t" >- "addu %[value32], %[value32], %[b2] \n\t" >- : [value32] "=&r" (value32), [b1] "=&r" (b1), [b2] "=&r" (b2), >- [a1] "=&r" (a1) >- : [a] "r" (a), [b] "r" (b) >- : "hi", "lo"); >+ "andi %[b2], %[b], 0xFFFF \n\t" >+ "sra %[b1], %[b], 16 \n\t" >+ "sra %[b2], %[b2], 1 \n\t" >+ "mul %[value32], %[a1], %[b1] \n\t" >+ "mul %[b2], %[a1], %[b2] \n\t" >+ "addiu %[b2], %[b2], 0x4000 \n\t" >+ "sra %[b2], %[b2], 15 \n\t" >+ "addu %[value32], %[value32], %[b2] \n\t" >+ : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1) >+ : [a] "r"(a), [b] "r"(b) >+ : "hi", "lo"); > return value32; > } > > #if defined(MIPS_DSP_R1_LE) > static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { > __asm __volatile( >- "shll_s.w %[value32], %[value32], 16 \n\t" >- "sra %[value32], %[value32], 16 \n\t" >- : [value32] "+r" (value32) >- :); >+ "shll_s.w %[value32], %[value32], 16 \n\t" >+ "sra %[value32], %[value32], 16 \n\t" >+ : [value32] "+r"(value32) >+ :); > int16_t out16 = (int16_t)value32; > return out16; > } >@@ -78,10 +74,9 @@ static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { > static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { > int32_t value32 = 0; > >- __asm __volatile( >- "addq_s.ph %[value32], %[a], %[b] \n\t" >- : [value32] "=r" (value32) >- : [a] "r" (a), [b] "r" (b) ); >+ __asm __volatile("addq_s.ph %[value32], %[a], %[b] \n\t" >+ : [value32] "=r"(value32) >+ : [a] "r"(a), [b] "r"(b)); > return (int16_t)value32; > } > >@@ -89,9 +84,9 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { > int32_t l_sum; > > __asm __volatile( >- "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t" >- : [l_sum] "=r" (l_sum) >- : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2) ); >+ "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t" >+ : [l_sum] "=r"(l_sum) >+ : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); > > return l_sum; > } >@@ -99,10 +94,9 @@ static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { > static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { > int32_t value32; > >- __asm __volatile( >- "subq_s.ph %[value32], %[var1], %[var2] \n\t" >- : [value32] "=r" (value32) >- : [var1] "r" (var1), [var2] "r" (var2) ); >+ __asm __volatile("subq_s.ph %[value32], %[var1], %[var2] \n\t" >+ : [value32] "=r"(value32) >+ : [var1] "r"(var1), [var2] "r"(var2)); > > return (int16_t)value32; > } >@@ -111,9 +105,9 @@ static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { > int32_t l_diff; > > __asm __volatile( >- "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t" >- : [l_diff] "=r" (l_diff) >- : [l_var1] "r" (l_var1), [l_var2] "r" (l_var2) ); >+ "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t" >+ : [l_diff] "=r"(l_diff) >+ : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); > > return l_diff; > } >@@ -124,10 +118,10 @@ static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { > int i32 = 32; > > __asm __volatile( >- "clz %[bits], %[n] \n\t" >- "subu %[bits], %[i32], %[bits] \n\t" >- : [bits] "=&r" (bits) >- : [n] "r" (n), [i32] "r" (i32) ); >+ "clz %[bits], %[n] \n\t" >+ "subu %[bits], %[i32], %[bits] \n\t" >+ : [bits] "=&r"(bits) >+ : [n] "r"(n), [i32] "r"(i32)); > > return (int16_t)bits; > } >@@ -136,20 +130,20 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) { > int zeros = 0; > > __asm __volatile( >- ".set push \n\t" >- ".set noreorder \n\t" >- "bnez %[a], 1f \n\t" >- " sra %[zeros], %[a], 31 \n\t" >- "b 2f \n\t" >- " move %[zeros], $zero \n\t" >- "1: \n\t" >- "xor %[zeros], %[a], %[zeros] \n\t" >- "clz %[zeros], %[zeros] \n\t" >- "addiu %[zeros], %[zeros], -1 \n\t" >- "2: \n\t" >- ".set pop \n\t" >- : [zeros]"=&r"(zeros) >- : [a] "r" (a) ); >+ ".set push \n\t" >+ ".set noreorder \n\t" >+ "bnez %[a], 1f \n\t" >+ " sra %[zeros], %[a], 31 \n\t" >+ "b 2f \n\t" >+ " move %[zeros], $zero \n\t" >+ "1: \n\t" >+ "xor %[zeros], %[a], %[zeros] \n\t" >+ "clz %[zeros], %[zeros] \n\t" >+ "addiu %[zeros], %[zeros], -1 \n\t" >+ "2: \n\t" >+ ".set pop \n\t" >+ : [zeros] "=&r"(zeros) >+ : [a] "r"(a)); > > return (int16_t)zeros; > } >@@ -157,10 +151,9 @@ static __inline int16_t WebRtcSpl_NormW32(int32_t a) { > static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { > int zeros = 0; > >- __asm __volatile( >- "clz %[zeros], %[a] \n\t" >- : [zeros] "=r" (zeros) >- : [a] "r" (a) ); >+ __asm __volatile("clz %[zeros], %[a] \n\t" >+ : [zeros] "=r"(zeros) >+ : [a] "r"(a)); > > return (int16_t)(zeros & 0x1f); > } >@@ -170,43 +163,41 @@ static __inline int16_t WebRtcSpl_NormW16(int16_t a) { > int a0 = a << 16; > > __asm __volatile( >- ".set push \n\t" >- ".set noreorder \n\t" >- "bnez %[a0], 1f \n\t" >- " sra %[zeros], %[a0], 31 \n\t" >- "b 2f \n\t" >- " move %[zeros], $zero \n\t" >- "1: \n\t" >- "xor %[zeros], %[a0], %[zeros] \n\t" >- "clz %[zeros], %[zeros] \n\t" >- "addiu %[zeros], %[zeros], -1 \n\t" >- "2: \n\t" >- ".set pop \n\t" >- : [zeros]"=&r"(zeros) >- : [a0] "r" (a0) ); >+ ".set push \n\t" >+ ".set noreorder \n\t" >+ "bnez %[a0], 1f \n\t" >+ " sra %[zeros], %[a0], 31 \n\t" >+ "b 2f \n\t" >+ " move %[zeros], $zero \n\t" >+ "1: \n\t" >+ "xor %[zeros], %[a0], %[zeros] \n\t" >+ "clz %[zeros], %[zeros] \n\t" >+ "addiu %[zeros], %[zeros], -1 \n\t" >+ "2: \n\t" >+ ".set pop \n\t" >+ : [zeros] "=&r"(zeros) >+ : [a0] "r"(a0)); > > return (int16_t)zeros; > } > >-static __inline int32_t WebRtc_MulAccumW16(int16_t a, >- int16_t b, >- int32_t c) { >+static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { > int32_t res = 0, c1 = 0; > __asm __volatile( > #if defined(MIPS32_R2_LE) >- "seh %[a], %[a] \n\t" >- "seh %[b], %[b] \n\t" >+ "seh %[a], %[a] \n\t" >+ "seh %[b], %[b] \n\t" > #else >- "sll %[a], %[a], 16 \n\t" >- "sll %[b], %[b], 16 \n\t" >- "sra %[a], %[a], 16 \n\t" >- "sra %[b], %[b], 16 \n\t" >+ "sll %[a], %[a], 16 \n\t" >+ "sll %[b], %[b], 16 \n\t" >+ "sra %[a], %[a], 16 \n\t" >+ "sra %[b], %[b], 16 \n\t" > #endif >- "mul %[res], %[a], %[b] \n\t" >- "addu %[c1], %[c], %[res] \n\t" >- : [c1] "=r" (c1), [res] "=&r" (res) >- : [a] "r" (a), [b] "r" (b), [c] "r" (c) >- : "hi", "lo"); >+ "mul %[res], %[a], %[b] \n\t" >+ "addu %[c1], %[c], %[res] \n\t" >+ : [c1] "=r"(c1), [res] "=&r"(res) >+ : [a] "r"(a), [b] "r"(b), [c] "r"(c) >+ : "hi", "lo"); > return (c1); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/real_fft_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/real_fft_unittest.cc >index 4f5b5c72b2c..3b4312381ae 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/real_fft_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/real_fft_unittest.cc >@@ -11,7 +11,6 @@ > #include "common_audio/signal_processing/include/real_fft.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > namespace { >@@ -27,17 +26,14 @@ const int kFreqDataLength = (1 << kOrder) + 2; > const int kComplexFftDataLength = 2 << kOrder; > // Reference data for time signal. > const int16_t kRefData[kTimeDataLength] = { >- 11739, 6848, -8688, 31980, -30295, 25242, 27085, 19410, >- -26299, 15607, -10791, 11778, -23819, 14498, -25772, 10076, >- 1173, 6848, -8688, 31980, -30295, 2522, 27085, 19410, >- -2629, 5607, -3, 1178, -23819, 1498, -25772, 10076 >-}; >+ 11739, 6848, -8688, 31980, -30295, 25242, 27085, 19410, >+ -26299, 15607, -10791, 11778, -23819, 14498, -25772, 10076, >+ 1173, 6848, -8688, 31980, -30295, 2522, 27085, 19410, >+ -2629, 5607, -3, 1178, -23819, 1498, -25772, 10076}; > > class RealFFTTest : public ::testing::Test { > protected: >- RealFFTTest() { >- WebRtcSpl_Init(); >- } >+ RealFFTTest() { WebRtcSpl_Init(); } > }; > > TEST_F(RealFFTTest, CreateFailsOnBadInput) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/resample_by_2_internal.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/resample_by_2_internal.h >index b0d19691c41..145395a4cbd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/resample_by_2_internal.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/resample_by_2_internal.h >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* > * This header file contains some internal resampling functions. > * >@@ -17,31 +16,45 @@ > #ifndef COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ > #define COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ > >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > /******************************************************************* > * resample_by_2_fast.c > * Functions for internal use in the other resample functions > ******************************************************************/ >-void WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out, >- int32_t *state); >- >-void WebRtcSpl_DownBy2ShortToInt(const int16_t *in, int32_t len, >- int32_t *out, int32_t *state); >- >-void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len, >- int32_t *out, int32_t *state); >- >-void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out, >- int32_t *state); >+void WebRtcSpl_DownBy2IntToShort(int32_t* in, >+ int32_t len, >+ int16_t* out, >+ int32_t* state); >+ >+void WebRtcSpl_DownBy2ShortToInt(const int16_t* in, >+ int32_t len, >+ int32_t* out, >+ int32_t* state); >+ >+void WebRtcSpl_UpBy2ShortToInt(const int16_t* in, >+ int32_t len, >+ int32_t* out, >+ int32_t* state); >+ >+void WebRtcSpl_UpBy2IntToInt(const int32_t* in, >+ int32_t len, >+ int32_t* out, >+ int32_t* state); > >-void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len, >- int16_t *out, int32_t *state); >+void WebRtcSpl_UpBy2IntToShort(const int32_t* in, >+ int32_t len, >+ int16_t* out, >+ int32_t* state); > >-void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, >- int32_t* out, int32_t* state); >+void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, >+ int32_t len, >+ int32_t* out, >+ int32_t* state); > >-void WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out, >+void WebRtcSpl_LPBy2IntToInt(const int32_t* in, >+ int32_t len, >+ int32_t* out, > int32_t* state); > > #endif // COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/signal_processing_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/signal_processing_unittest.cc >index b9efe01fe7e..8e65ebd2bca 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/signal_processing_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/signal_processing_unittest.cc >@@ -15,111 +15,113 @@ > #include "test/gtest.h" > > static const size_t kVector16Size = 9; >-static const int16_t vector16[kVector16Size] = {1, -15511, 4323, 1963, >- WEBRTC_SPL_WORD16_MAX, 0, WEBRTC_SPL_WORD16_MIN + 5, -3333, 345}; >+static const int16_t vector16[kVector16Size] = {1, >+ -15511, >+ 4323, >+ 1963, >+ WEBRTC_SPL_WORD16_MAX, >+ 0, >+ WEBRTC_SPL_WORD16_MIN + 5, >+ -3333, >+ 345}; > > class SplTest : public testing::Test { > protected: >- SplTest() { >- WebRtcSpl_Init(); >- } >- virtual ~SplTest() { >- } >+ SplTest() { WebRtcSpl_Init(); } >+ ~SplTest() override {} > }; > > TEST_F(SplTest, MacroTest) { >- // Macros with inputs. >- int A = 10; >- int B = 21; >- int a = -3; >- int b = WEBRTC_SPL_WORD32_MAX; >- >- EXPECT_EQ(10, WEBRTC_SPL_MIN(A, B)); >- EXPECT_EQ(21, WEBRTC_SPL_MAX(A, B)); >- >- EXPECT_EQ(3, WEBRTC_SPL_ABS_W16(a)); >- EXPECT_EQ(3, WEBRTC_SPL_ABS_W32(a)); >- >- EXPECT_EQ(-63, WEBRTC_SPL_MUL(a, B)); >- EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b)); >- b = WEBRTC_SPL_WORD16_MAX >> 1; >- EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b)); >- EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b)); >- >- a = b; >- b = -3; >- >- EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT16(a, b)); >- EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT15(a, b)); >- EXPECT_EQ(-3, WEBRTC_SPL_MUL_16_32_RSFT14(a, b)); >- EXPECT_EQ(-24, WEBRTC_SPL_MUL_16_32_RSFT11(a, b)); >- >- EXPECT_EQ(-12288, WEBRTC_SPL_MUL_16_16_RSFT(a, b, 2)); >- EXPECT_EQ(-12287, WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, 2)); >- >- EXPECT_EQ(21, WEBRTC_SPL_SAT(a, A, B)); >- EXPECT_EQ(21, WEBRTC_SPL_SAT(a, B, A)); >- >- // Shifting with negative numbers allowed >- int shift_amount = 1; // Workaround compiler warning using variable here. >- // Positive means left shift >- EXPECT_EQ(32766, WEBRTC_SPL_SHIFT_W32(a, shift_amount)); >- >- // Shifting with negative numbers not allowed >- // We cannot do casting here due to signed/unsigned problem >- EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1)); >- >- EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1)); >- >- EXPECT_EQ(1470, WEBRTC_SPL_RAND(A)); >- >- EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_16(a, b)); >- EXPECT_EQ(1073676289, WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX, >- WEBRTC_SPL_WORD16_MAX)); >- EXPECT_EQ(1073709055, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MAX, >- WEBRTC_SPL_WORD32_MAX)); >- EXPECT_EQ(1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >- WEBRTC_SPL_WORD32_MIN)); >+ // Macros with inputs. >+ int A = 10; >+ int B = 21; >+ int a = -3; >+ int b = WEBRTC_SPL_WORD32_MAX; >+ >+ EXPECT_EQ(10, WEBRTC_SPL_MIN(A, B)); >+ EXPECT_EQ(21, WEBRTC_SPL_MAX(A, B)); >+ >+ EXPECT_EQ(3, WEBRTC_SPL_ABS_W16(a)); >+ EXPECT_EQ(3, WEBRTC_SPL_ABS_W32(a)); >+ >+ EXPECT_EQ(-63, WEBRTC_SPL_MUL(a, B)); >+ EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b)); >+ b = WEBRTC_SPL_WORD16_MAX >> 1; >+ EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b)); >+ EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b)); >+ >+ a = b; >+ b = -3; >+ >+ EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT16(a, b)); >+ EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT15(a, b)); >+ EXPECT_EQ(-3, WEBRTC_SPL_MUL_16_32_RSFT14(a, b)); >+ EXPECT_EQ(-24, WEBRTC_SPL_MUL_16_32_RSFT11(a, b)); >+ >+ EXPECT_EQ(-12288, WEBRTC_SPL_MUL_16_16_RSFT(a, b, 2)); >+ EXPECT_EQ(-12287, WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, 2)); >+ >+ EXPECT_EQ(21, WEBRTC_SPL_SAT(a, A, B)); >+ EXPECT_EQ(21, WEBRTC_SPL_SAT(a, B, A)); >+ >+ // Shifting with negative numbers allowed >+ int shift_amount = 1; // Workaround compiler warning using variable here. >+ // Positive means left shift >+ EXPECT_EQ(32766, WEBRTC_SPL_SHIFT_W32(a, shift_amount)); >+ >+ // Shifting with negative numbers not allowed >+ // We cannot do casting here due to signed/unsigned problem >+ EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1)); >+ >+ EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1)); >+ >+ EXPECT_EQ(1470, WEBRTC_SPL_RAND(A)); >+ >+ EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_16(a, b)); >+ EXPECT_EQ(1073676289, >+ WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MAX)); >+ EXPECT_EQ(1073709055, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MAX, >+ WEBRTC_SPL_WORD32_MAX)); >+ EXPECT_EQ(1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >+ WEBRTC_SPL_WORD32_MIN)); > #ifdef WEBRTC_ARCH_ARM_V7 >- EXPECT_EQ(-1073741824, >- WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >- WEBRTC_SPL_WORD32_MAX)); >+ EXPECT_EQ(-1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >+ WEBRTC_SPL_WORD32_MAX)); > #else >- EXPECT_EQ(-1073741823, >- WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >- WEBRTC_SPL_WORD32_MAX)); >+ EXPECT_EQ(-1073741823, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, >+ WEBRTC_SPL_WORD32_MAX)); > #endif > } > > TEST_F(SplTest, InlineTest) { >- int16_t a16 = 121; >- int16_t b16 = -17; >- int32_t a32 = 111121; >- int32_t b32 = -1711; >- >- EXPECT_EQ(17, WebRtcSpl_GetSizeInBits(a32)); >- >- EXPECT_EQ(0, WebRtcSpl_NormW32(0)); >- EXPECT_EQ(31, WebRtcSpl_NormW32(-1)); >- EXPECT_EQ(0, WebRtcSpl_NormW32(WEBRTC_SPL_WORD32_MIN)); >- EXPECT_EQ(14, WebRtcSpl_NormW32(a32)); >- >- EXPECT_EQ(0, WebRtcSpl_NormW16(0)); >- EXPECT_EQ(15, WebRtcSpl_NormW16(-1)); >- EXPECT_EQ(0, WebRtcSpl_NormW16(WEBRTC_SPL_WORD16_MIN)); >- EXPECT_EQ(4, WebRtcSpl_NormW16(b32)); >- for (int ii = 0; ii < 15; ++ii) { >- int16_t value = 1 << ii; >- EXPECT_EQ(14 - ii, WebRtcSpl_NormW16(value)); >- EXPECT_EQ(15 - ii, WebRtcSpl_NormW16(-value)); >- } >+ int16_t a16 = 121; >+ int16_t b16 = -17; >+ int32_t a32 = 111121; >+ int32_t b32 = -1711; >+ >+ EXPECT_EQ(17, WebRtcSpl_GetSizeInBits(a32)); >+ >+ EXPECT_EQ(0, WebRtcSpl_NormW32(0)); >+ EXPECT_EQ(31, WebRtcSpl_NormW32(-1)); >+ EXPECT_EQ(0, WebRtcSpl_NormW32(WEBRTC_SPL_WORD32_MIN)); >+ EXPECT_EQ(14, WebRtcSpl_NormW32(a32)); >+ >+ EXPECT_EQ(0, WebRtcSpl_NormW16(0)); >+ EXPECT_EQ(15, WebRtcSpl_NormW16(-1)); >+ EXPECT_EQ(0, WebRtcSpl_NormW16(WEBRTC_SPL_WORD16_MIN)); >+ EXPECT_EQ(4, WebRtcSpl_NormW16(b32)); >+ for (int ii = 0; ii < 15; ++ii) { >+ int16_t value = 1 << ii; >+ EXPECT_EQ(14 - ii, WebRtcSpl_NormW16(value)); >+ EXPECT_EQ(15 - ii, WebRtcSpl_NormW16(-value)); >+ } > >- EXPECT_EQ(0, WebRtcSpl_NormU32(0u)); >- EXPECT_EQ(0, WebRtcSpl_NormU32(0xffffffff)); >- EXPECT_EQ(15, WebRtcSpl_NormU32(static_cast<uint32_t>(a32))); >+ EXPECT_EQ(0, WebRtcSpl_NormU32(0u)); >+ EXPECT_EQ(0, WebRtcSpl_NormU32(0xffffffff)); >+ EXPECT_EQ(15, WebRtcSpl_NormU32(static_cast<uint32_t>(a32))); > >- EXPECT_EQ(104, WebRtcSpl_AddSatW16(a16, b16)); >- EXPECT_EQ(138, WebRtcSpl_SubSatW16(a16, b16)); >+ EXPECT_EQ(104, WebRtcSpl_AddSatW16(a16, b16)); >+ EXPECT_EQ(138, WebRtcSpl_SubSatW16(a16, b16)); > } > > TEST_F(SplTest, AddSubSatW32) { >@@ -168,84 +170,83 @@ TEST_F(SplTest, CountLeadingZeros64) { > } > > TEST_F(SplTest, MathOperationsTest) { >- int A = 1134567892; >- int32_t num = 117; >- int32_t den = -5; >- uint16_t denU = 5; >- EXPECT_EQ(33700, WebRtcSpl_Sqrt(A)); >- EXPECT_EQ(33683, WebRtcSpl_SqrtFloor(A)); >- >- >- EXPECT_EQ(-91772805, WebRtcSpl_DivResultInQ31(den, num)); >- EXPECT_EQ(-23, WebRtcSpl_DivW32W16ResW16(num, (int16_t)den)); >- EXPECT_EQ(-23, WebRtcSpl_DivW32W16(num, (int16_t)den)); >- EXPECT_EQ(23u, WebRtcSpl_DivU32U16(num, denU)); >- EXPECT_EQ(0, WebRtcSpl_DivW32HiLow(128, 0, 256)); >+ int A = 1134567892; >+ int32_t num = 117; >+ int32_t den = -5; >+ uint16_t denU = 5; >+ EXPECT_EQ(33700, WebRtcSpl_Sqrt(A)); >+ EXPECT_EQ(33683, WebRtcSpl_SqrtFloor(A)); >+ >+ EXPECT_EQ(-91772805, WebRtcSpl_DivResultInQ31(den, num)); >+ EXPECT_EQ(-23, WebRtcSpl_DivW32W16ResW16(num, (int16_t)den)); >+ EXPECT_EQ(-23, WebRtcSpl_DivW32W16(num, (int16_t)den)); >+ EXPECT_EQ(23u, WebRtcSpl_DivU32U16(num, denU)); >+ EXPECT_EQ(0, WebRtcSpl_DivW32HiLow(128, 0, 256)); > } > > TEST_F(SplTest, BasicArrayOperationsTest) { >- const size_t kVectorSize = 4; >- int B[] = {4, 12, 133, 1100}; >- int16_t b16[kVectorSize]; >- int32_t b32[kVectorSize]; >+ const size_t kVectorSize = 4; >+ int B[] = {4, 12, 133, 1100}; >+ int16_t b16[kVectorSize]; >+ int32_t b32[kVectorSize]; > >- int16_t bTmp16[kVectorSize]; >- int32_t bTmp32[kVectorSize]; >+ int16_t bTmp16[kVectorSize]; >+ int32_t bTmp32[kVectorSize]; > >- WebRtcSpl_MemSetW16(b16, 3, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(3, b16[kk]); >- } >- WebRtcSpl_ZerosArrayW16(b16, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(0, b16[kk]); >- } >- WebRtcSpl_MemSetW32(b32, 3, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(3, b32[kk]); >- } >- WebRtcSpl_ZerosArrayW32(b32, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(0, b32[kk]); >- } >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- bTmp16[kk] = (int16_t)kk; >- bTmp32[kk] = (int32_t)kk; >- } >- WEBRTC_SPL_MEMCPY_W16(b16, bTmp16, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(b16[kk], bTmp16[kk]); >- } >-// WEBRTC_SPL_MEMCPY_W32(b32, bTmp32, kVectorSize); >-// for (int kk = 0; kk < kVectorSize; ++kk) { >-// EXPECT_EQ(b32[kk], bTmp32[kk]); >-// } >- WebRtcSpl_CopyFromEndW16(b16, kVectorSize, 2, bTmp16); >- for (size_t kk = 0; kk < 2; ++kk) { >- EXPECT_EQ(static_cast<int16_t>(kk+2), bTmp16[kk]); >- } >+ WebRtcSpl_MemSetW16(b16, 3, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(3, b16[kk]); >+ } >+ WebRtcSpl_ZerosArrayW16(b16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(0, b16[kk]); >+ } >+ WebRtcSpl_MemSetW32(b32, 3, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(3, b32[kk]); >+ } >+ WebRtcSpl_ZerosArrayW32(b32, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(0, b32[kk]); >+ } >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ bTmp16[kk] = (int16_t)kk; >+ bTmp32[kk] = (int32_t)kk; >+ } >+ WEBRTC_SPL_MEMCPY_W16(b16, bTmp16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(b16[kk], bTmp16[kk]); >+ } >+ // WEBRTC_SPL_MEMCPY_W32(b32, bTmp32, kVectorSize); >+ // for (int kk = 0; kk < kVectorSize; ++kk) { >+ // EXPECT_EQ(b32[kk], bTmp32[kk]); >+ // } >+ WebRtcSpl_CopyFromEndW16(b16, kVectorSize, 2, bTmp16); >+ for (size_t kk = 0; kk < 2; ++kk) { >+ EXPECT_EQ(static_cast<int16_t>(kk + 2), bTmp16[kk]); >+ } > >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- b32[kk] = B[kk]; >- b16[kk] = (int16_t)B[kk]; >- } >- WebRtcSpl_VectorBitShiftW32ToW16(bTmp16, kVectorSize, b32, 1); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((B[kk]>>1), bTmp16[kk]); >- } >- WebRtcSpl_VectorBitShiftW16(bTmp16, kVectorSize, b16, 1); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((B[kk]>>1), bTmp16[kk]); >- } >- WebRtcSpl_VectorBitShiftW32(bTmp32, kVectorSize, b32, 1); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((B[kk]>>1), bTmp32[kk]); >- } >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ b32[kk] = B[kk]; >+ b16[kk] = (int16_t)B[kk]; >+ } >+ WebRtcSpl_VectorBitShiftW32ToW16(bTmp16, kVectorSize, b32, 1); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((B[kk] >> 1), bTmp16[kk]); >+ } >+ WebRtcSpl_VectorBitShiftW16(bTmp16, kVectorSize, b16, 1); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((B[kk] >> 1), bTmp16[kk]); >+ } >+ WebRtcSpl_VectorBitShiftW32(bTmp32, kVectorSize, b32, 1); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((B[kk] >> 1), bTmp32[kk]); >+ } > >- WebRtcSpl_MemCpyReversedOrder(&bTmp16[3], b16, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(b16[3-kk], bTmp16[kk]); >- } >+ WebRtcSpl_MemCpyReversedOrder(&bTmp16[3], b16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(b16[3 - kk], bTmp16[kk]); >+ } > } > > TEST_F(SplTest, MinMaxOperationsTest) { >@@ -253,12 +254,40 @@ TEST_F(SplTest, MinMaxOperationsTest) { > > // Vectors to test the cases where minimum values have to be caught > // outside of the unrolled loops in ARM-Neon. >- int16_t vector16[kVectorSize] = {-1, 7485, 0, 3333, >- -18283, 0, 12334, -29871, 988, -3333, >- 345, -456, 222, 999, 888, 8774, WEBRTC_SPL_WORD16_MIN}; >- int32_t vector32[kVectorSize] = {-1, 0, 283211, 3333, >- 8712345, 0, -3333, 89345, -374585456, 222, 999, 122345334, >- -12389756, -987329871, 888, -2, WEBRTC_SPL_WORD32_MIN}; >+ int16_t vector16[kVectorSize] = {-1, >+ 7485, >+ 0, >+ 3333, >+ -18283, >+ 0, >+ 12334, >+ -29871, >+ 988, >+ -3333, >+ 345, >+ -456, >+ 222, >+ 999, >+ 888, >+ 8774, >+ WEBRTC_SPL_WORD16_MIN}; >+ int32_t vector32[kVectorSize] = {-1, >+ 0, >+ 283211, >+ 3333, >+ 8712345, >+ 0, >+ -3333, >+ 89345, >+ -374585456, >+ 222, >+ 999, >+ 122345334, >+ -12389756, >+ -987329871, >+ 888, >+ -2, >+ WEBRTC_SPL_WORD32_MIN}; > > EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, > WebRtcSpl_MinValueW16(vector16, kVectorSize)); >@@ -312,76 +341,75 @@ TEST_F(SplTest, MinMaxOperationsTest) { > } > > TEST_F(SplTest, VectorOperationsTest) { >- const size_t kVectorSize = 4; >- int B[] = {4, 12, 133, 1100}; >- int16_t a16[kVectorSize]; >- int16_t b16[kVectorSize]; >- int16_t bTmp16[kVectorSize]; >- >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- a16[kk] = B[kk]; >- b16[kk] = B[kk]; >- } >+ const size_t kVectorSize = 4; >+ int B[] = {4, 12, 133, 1100}; >+ int16_t a16[kVectorSize]; >+ int16_t b16[kVectorSize]; >+ int16_t bTmp16[kVectorSize]; >+ >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ a16[kk] = B[kk]; >+ b16[kk] = B[kk]; >+ } > >- WebRtcSpl_AffineTransformVector(bTmp16, b16, 3, 7, 2, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((B[kk]*3+7)>>2, bTmp16[kk]); >- } >- WebRtcSpl_ScaleAndAddVectorsWithRound(b16, 3, b16, 2, 2, bTmp16, >- kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((B[kk]*3+B[kk]*2+2)>>2, bTmp16[kk]); >- } >+ WebRtcSpl_AffineTransformVector(bTmp16, b16, 3, 7, 2, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((B[kk] * 3 + 7) >> 2, bTmp16[kk]); >+ } >+ WebRtcSpl_ScaleAndAddVectorsWithRound(b16, 3, b16, 2, 2, bTmp16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((B[kk] * 3 + B[kk] * 2 + 2) >> 2, bTmp16[kk]); >+ } > >- WebRtcSpl_AddAffineVectorToVector(bTmp16, b16, 3, 7, 2, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(((B[kk]*3+B[kk]*2+2)>>2)+((b16[kk]*3+7)>>2), bTmp16[kk]); >- } >+ WebRtcSpl_AddAffineVectorToVector(bTmp16, b16, 3, 7, 2, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(((B[kk] * 3 + B[kk] * 2 + 2) >> 2) + ((b16[kk] * 3 + 7) >> 2), >+ bTmp16[kk]); >+ } > >- WebRtcSpl_ScaleVector(b16, bTmp16, 13, kVectorSize, 2); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((b16[kk]*13)>>2, bTmp16[kk]); >- } >- WebRtcSpl_ScaleVectorWithSat(b16, bTmp16, 13, kVectorSize, 2); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((b16[kk]*13)>>2, bTmp16[kk]); >- } >- WebRtcSpl_ScaleAndAddVectors(a16, 13, 2, b16, 7, 2, bTmp16, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(((a16[kk]*13)>>2)+((b16[kk]*7)>>2), bTmp16[kk]); >- } >+ WebRtcSpl_ScaleVector(b16, bTmp16, 13, kVectorSize, 2); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]); >+ } >+ WebRtcSpl_ScaleVectorWithSat(b16, bTmp16, 13, kVectorSize, 2); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]); >+ } >+ WebRtcSpl_ScaleAndAddVectors(a16, 13, 2, b16, 7, 2, bTmp16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(((a16[kk] * 13) >> 2) + ((b16[kk] * 7) >> 2), bTmp16[kk]); >+ } > >- WebRtcSpl_AddVectorsAndShift(bTmp16, a16, b16, kVectorSize, 2); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(B[kk] >> 1, bTmp16[kk]); >- } >- WebRtcSpl_ReverseOrderMultArrayElements(bTmp16, a16, &b16[3], >- kVectorSize, 2); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((a16[kk]*b16[3-kk])>>2, bTmp16[kk]); >- } >- WebRtcSpl_ElementwiseVectorMult(bTmp16, a16, b16, kVectorSize, 6); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ((a16[kk]*b16[kk])>>6, bTmp16[kk]); >- } >+ WebRtcSpl_AddVectorsAndShift(bTmp16, a16, b16, kVectorSize, 2); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(B[kk] >> 1, bTmp16[kk]); >+ } >+ WebRtcSpl_ReverseOrderMultArrayElements(bTmp16, a16, &b16[3], kVectorSize, 2); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((a16[kk] * b16[3 - kk]) >> 2, bTmp16[kk]); >+ } >+ WebRtcSpl_ElementwiseVectorMult(bTmp16, a16, b16, kVectorSize, 6); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ((a16[kk] * b16[kk]) >> 6, bTmp16[kk]); >+ } > >- WebRtcSpl_SqrtOfOneMinusXSquared(b16, kVectorSize, bTmp16); >- for (size_t kk = 0; kk < kVectorSize - 1; ++kk) { >- EXPECT_EQ(32767, bTmp16[kk]); >- } >- EXPECT_EQ(32749, bTmp16[kVectorSize - 1]); >+ WebRtcSpl_SqrtOfOneMinusXSquared(b16, kVectorSize, bTmp16); >+ for (size_t kk = 0; kk < kVectorSize - 1; ++kk) { >+ EXPECT_EQ(32767, bTmp16[kk]); >+ } >+ EXPECT_EQ(32749, bTmp16[kVectorSize - 1]); > >- EXPECT_EQ(0, WebRtcSpl_GetScalingSquare(b16, kVectorSize, 1)); >+ EXPECT_EQ(0, WebRtcSpl_GetScalingSquare(b16, kVectorSize, 1)); > } > > TEST_F(SplTest, EstimatorsTest) { > const size_t kOrder = 2; >- const int32_t unstable_filter[] = { 4, 12, 133, 1100 }; >- const int32_t stable_filter[] = { 1100, 133, 12, 4 }; >- int16_t lpc[kOrder + 2] = { 0 }; >- int16_t refl[kOrder + 2] = { 0 }; >- int16_t lpc_result[] = { 4096, -497, 15, 0 }; >- int16_t refl_result[] = { -3962, 123, 0, 0 }; >+ const int32_t unstable_filter[] = {4, 12, 133, 1100}; >+ const int32_t stable_filter[] = {1100, 133, 12, 4}; >+ int16_t lpc[kOrder + 2] = {0}; >+ int16_t refl[kOrder + 2] = {0}; >+ int16_t lpc_result[] = {4096, -497, 15, 0}; >+ int16_t refl_result[] = {-3962, 123, 0, 0}; > > EXPECT_EQ(0, WebRtcSpl_LevinsonDurbin(unstable_filter, lpc, refl, kOrder)); > EXPECT_EQ(1, WebRtcSpl_LevinsonDurbin(stable_filter, lpc, refl, kOrder)); >@@ -392,69 +420,61 @@ TEST_F(SplTest, EstimatorsTest) { > } > > TEST_F(SplTest, FilterTest) { >- const size_t kVectorSize = 4; >- const size_t kFilterOrder = 3; >- int16_t A[] = {1, 2, 33, 100}; >- int16_t A5[] = {1, 2, 33, 100, -5}; >- int16_t B[] = {4, 12, 133, 110}; >- int16_t data_in[kVectorSize]; >- int16_t data_out[kVectorSize]; >- int16_t bTmp16Low[kVectorSize]; >- int16_t bState[kVectorSize]; >- int16_t bStateLow[kVectorSize]; >- >- WebRtcSpl_ZerosArrayW16(bState, kVectorSize); >- WebRtcSpl_ZerosArrayW16(bStateLow, kVectorSize); >- >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- data_in[kk] = A[kk]; >- data_out[kk] = 0; >- } >+ const size_t kVectorSize = 4; >+ const size_t kFilterOrder = 3; >+ int16_t A[] = {1, 2, 33, 100}; >+ int16_t A5[] = {1, 2, 33, 100, -5}; >+ int16_t B[] = {4, 12, 133, 110}; >+ int16_t data_in[kVectorSize]; >+ int16_t data_out[kVectorSize]; >+ int16_t bTmp16Low[kVectorSize]; >+ int16_t bState[kVectorSize]; >+ int16_t bStateLow[kVectorSize]; >+ >+ WebRtcSpl_ZerosArrayW16(bState, kVectorSize); >+ WebRtcSpl_ZerosArrayW16(bStateLow, kVectorSize); >+ >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ data_in[kk] = A[kk]; >+ data_out[kk] = 0; >+ } > >- // MA filters. >- // Note that the input data has |kFilterOrder| states before the actual >- // data (one sample). >- WebRtcSpl_FilterMAFastQ12(&data_in[kFilterOrder], data_out, B, >- kFilterOrder + 1, 1); >- EXPECT_EQ(0, data_out[0]); >- // AR filters. >- // Note that the output data has |kFilterOrder| states before the actual >- // data (one sample). >- WebRtcSpl_FilterARFastQ12(data_in, &data_out[kFilterOrder], A, >- kFilterOrder + 1, 1); >- EXPECT_EQ(0, data_out[kFilterOrder]); >- >- EXPECT_EQ(kVectorSize, WebRtcSpl_FilterAR(A5, >- 5, >- data_in, >- kVectorSize, >- bState, >- kVectorSize, >- bStateLow, >- kVectorSize, >- data_out, >- bTmp16Low, >- kVectorSize)); >+ // MA filters. >+ // Note that the input data has |kFilterOrder| states before the actual >+ // data (one sample). >+ WebRtcSpl_FilterMAFastQ12(&data_in[kFilterOrder], data_out, B, >+ kFilterOrder + 1, 1); >+ EXPECT_EQ(0, data_out[0]); >+ // AR filters. >+ // Note that the output data has |kFilterOrder| states before the actual >+ // data (one sample). >+ WebRtcSpl_FilterARFastQ12(data_in, &data_out[kFilterOrder], A, >+ kFilterOrder + 1, 1); >+ EXPECT_EQ(0, data_out[kFilterOrder]); >+ >+ EXPECT_EQ(kVectorSize, WebRtcSpl_FilterAR(A5, 5, data_in, kVectorSize, bState, >+ kVectorSize, bStateLow, kVectorSize, >+ data_out, bTmp16Low, kVectorSize)); > } > > TEST_F(SplTest, RandTest) { >- const int kVectorSize = 4; >- int16_t BU[] = {3653, 12446, 8525, 30691}; >- int16_t b16[kVectorSize]; >- uint32_t bSeed = 100000; >- >- EXPECT_EQ(7086, WebRtcSpl_RandU(&bSeed)); >- EXPECT_EQ(31565, WebRtcSpl_RandU(&bSeed)); >- EXPECT_EQ(-9786, WebRtcSpl_RandN(&bSeed)); >- EXPECT_EQ(kVectorSize, WebRtcSpl_RandUArray(b16, kVectorSize, &bSeed)); >- for (int kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(BU[kk], b16[kk]); >- } >+ const int kVectorSize = 4; >+ int16_t BU[] = {3653, 12446, 8525, 30691}; >+ int16_t b16[kVectorSize]; >+ uint32_t bSeed = 100000; >+ >+ EXPECT_EQ(7086, WebRtcSpl_RandU(&bSeed)); >+ EXPECT_EQ(31565, WebRtcSpl_RandU(&bSeed)); >+ EXPECT_EQ(-9786, WebRtcSpl_RandN(&bSeed)); >+ EXPECT_EQ(kVectorSize, WebRtcSpl_RandUArray(b16, kVectorSize, &bSeed)); >+ for (int kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(BU[kk], b16[kk]); >+ } > } > > TEST_F(SplTest, DotProductWithScaleTest) { >- EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16, >- vector16, kVector16Size, 2)); >+ EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16, vector16, >+ kVector16Size, 2)); > } > > TEST_F(SplTest, CrossCorrelationTest) { >@@ -464,8 +484,9 @@ TEST_F(SplTest, CrossCorrelationTest) { > const int kStep = 1; > const size_t kSeqDimension = 6; > >- const int16_t kVector16[kVector16Size] = {1, 4323, 1963, >- WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MIN + 5, -3333, -876, 8483, 142}; >+ const int16_t kVector16[kVector16Size] = { >+ 1, 4323, 1963, WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MIN + 5, -3333, >+ -876, 8483, 142}; > int32_t vector32[kCrossCorrelationDimension] = {0}; > > WebRtcSpl_CrossCorrelation(vector32, vector16, kVector16, kSeqDimension, >@@ -473,12 +494,12 @@ TEST_F(SplTest, CrossCorrelationTest) { > > // WebRtcSpl_CrossCorrelationC() and WebRtcSpl_CrossCorrelationNeon() > // are not bit-exact. >- const int32_t kExpected[kCrossCorrelationDimension] = >- {-266947903, -15579555, -171282001}; >+ const int32_t kExpected[kCrossCorrelationDimension] = {-266947903, -15579555, >+ -171282001}; > const int32_t* expected = kExpected; > #if !defined(MIPS32_LE) >- const int32_t kExpectedNeon[kCrossCorrelationDimension] = >- {-266947901, -15579553, -171281999}; >+ const int32_t kExpectedNeon[kCrossCorrelationDimension] = { >+ -266947901, -15579553, -171281999}; > if (WebRtcSpl_CrossCorrelation != WebRtcSpl_CrossCorrelationC) { > expected = kExpectedNeon; > } >@@ -491,8 +512,9 @@ TEST_F(SplTest, CrossCorrelationTest) { > TEST_F(SplTest, AutoCorrelationTest) { > int scale = 0; > int32_t vector32[kVector16Size]; >- const int32_t expected[kVector16Size] = {302681398, 14223410, -121705063, >- -85221647, -17104971, 61806945, 6644603, -669329, 43}; >+ const int32_t expected[kVector16Size] = {302681398, 14223410, -121705063, >+ -85221647, -17104971, 61806945, >+ 6644603, -669329, 43}; > > EXPECT_EQ(kVector16Size, > WebRtcSpl_AutoCorrelation(vector16, kVector16Size, >@@ -504,63 +526,60 @@ TEST_F(SplTest, AutoCorrelationTest) { > } > > TEST_F(SplTest, SignalProcessingTest) { >- const size_t kVectorSize = 4; >- int A[] = {1, 2, 33, 100}; >- const int16_t kHanning[4] = { 2399, 8192, 13985, 16384 }; >- int16_t b16[kVectorSize]; >+ const size_t kVectorSize = 4; >+ int A[] = {1, 2, 33, 100}; >+ const int16_t kHanning[4] = {2399, 8192, 13985, 16384}; >+ int16_t b16[kVectorSize]; > >- int16_t bTmp16[kVectorSize]; >+ int16_t bTmp16[kVectorSize]; > >- int bScale = 0; >+ int bScale = 0; > >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- b16[kk] = A[kk]; >- } >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ b16[kk] = A[kk]; >+ } > >- // TODO(bjornv): Activate the Reflection Coefficient tests when refactoring. >-// WebRtcSpl_ReflCoefToLpc(b16, kVectorSize, bTmp16); >-//// for (int kk = 0; kk < kVectorSize; ++kk) { >-//// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); >-//// } >-// WebRtcSpl_LpcToReflCoef(bTmp16, kVectorSize, b16); >-//// for (int kk = 0; kk < kVectorSize; ++kk) { >-//// EXPECT_EQ(a16[kk], b16[kk]); >-//// } >-// WebRtcSpl_AutoCorrToReflCoef(b32, kVectorSize, bTmp16); >-//// for (int kk = 0; kk < kVectorSize; ++kk) { >-//// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); >-//// } >- >- WebRtcSpl_GetHanningWindow(bTmp16, kVectorSize); >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- EXPECT_EQ(kHanning[kk], bTmp16[kk]); >- } >+ // TODO(bjornv): Activate the Reflection Coefficient tests when refactoring. >+ // WebRtcSpl_ReflCoefToLpc(b16, kVectorSize, bTmp16); >+ //// for (int kk = 0; kk < kVectorSize; ++kk) { >+ //// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); >+ //// } >+ // WebRtcSpl_LpcToReflCoef(bTmp16, kVectorSize, b16); >+ //// for (int kk = 0; kk < kVectorSize; ++kk) { >+ //// EXPECT_EQ(a16[kk], b16[kk]); >+ //// } >+ // WebRtcSpl_AutoCorrToReflCoef(b32, kVectorSize, bTmp16); >+ //// for (int kk = 0; kk < kVectorSize; ++kk) { >+ //// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); >+ //// } >+ >+ WebRtcSpl_GetHanningWindow(bTmp16, kVectorSize); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ EXPECT_EQ(kHanning[kk], bTmp16[kk]); >+ } > >- for (size_t kk = 0; kk < kVectorSize; ++kk) { >- b16[kk] = A[kk]; >- } >- EXPECT_EQ(11094 , WebRtcSpl_Energy(b16, kVectorSize, &bScale)); >- EXPECT_EQ(0, bScale); >+ for (size_t kk = 0; kk < kVectorSize; ++kk) { >+ b16[kk] = A[kk]; >+ } >+ EXPECT_EQ(11094, WebRtcSpl_Energy(b16, kVectorSize, &bScale)); >+ EXPECT_EQ(0, bScale); > } > > TEST_F(SplTest, FFTTest) { >- int16_t B[] = {1, 2, 33, 100, >- 2, 3, 34, 101, >- 3, 4, 35, 102, >- 4, 5, 36, 103}; >- >- EXPECT_EQ(0, WebRtcSpl_ComplexFFT(B, 3, 1)); >-// for (int kk = 0; kk < 16; ++kk) { >-// EXPECT_EQ(A[kk], B[kk]); >-// } >- EXPECT_EQ(0, WebRtcSpl_ComplexIFFT(B, 3, 1)); >-// for (int kk = 0; kk < 16; ++kk) { >-// EXPECT_EQ(A[kk], B[kk]); >-// } >- WebRtcSpl_ComplexBitReverse(B, 3); >- for (int kk = 0; kk < 16; ++kk) { >-// EXPECT_EQ(A[kk], B[kk]); >- } >+ int16_t B[] = {1, 2, 33, 100, 2, 3, 34, 101, 3, 4, 35, 102, 4, 5, 36, 103}; >+ >+ EXPECT_EQ(0, WebRtcSpl_ComplexFFT(B, 3, 1)); >+ // for (int kk = 0; kk < 16; ++kk) { >+ // EXPECT_EQ(A[kk], B[kk]); >+ // } >+ EXPECT_EQ(0, WebRtcSpl_ComplexIFFT(B, 3, 1)); >+ // for (int kk = 0; kk < 16; ++kk) { >+ // EXPECT_EQ(A[kk], B[kk]); >+ // } >+ WebRtcSpl_ComplexBitReverse(B, 3); >+ for (int kk = 0; kk < 16; ++kk) { >+ // EXPECT_EQ(A[kk], B[kk]); >+ } > } > > TEST_F(SplTest, Resample48WithSaturationTest) { >@@ -570,14 +589,13 @@ TEST_F(SplTest, Resample48WithSaturationTest) { > > // Saturated input vector of 48 samples. > const int32_t kVectorSaturated[3 * kBlockSize + 7] = { >- -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >- -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >- -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >- 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >- 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >- 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >- 32767, 32767, 32767, 32767, 32767, 32767, 32767 >- }; >+ -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >+ -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >+ -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, >+ 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >+ 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >+ 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, >+ 32767, 32767, 32767, 32767, 32767, 32767, 32767}; > > // All values in |out_vector| should be |kRefValue32kHz|. > const int32_t kRefValue32kHz1 = -1077493760; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_init.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_init.c >index 0f41bc13211..80e91973477 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_init.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_init.c >@@ -30,7 +30,7 @@ ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound; > > #if (!defined(WEBRTC_HAS_NEON)) && !defined(MIPS32_LE) > /* Initialize function pointers to the generic C version. */ >-static void InitPointersToC() { >+static void InitPointersToC(void) { > WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C; > WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C; > WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C; >@@ -46,7 +46,7 @@ static void InitPointersToC() { > > #if defined(WEBRTC_HAS_NEON) > /* Initialize function pointers to the Neon version. */ >-static void InitPointersToNeon() { >+static void InitPointersToNeon(void) { > WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon; > WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon; > WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon; >@@ -62,7 +62,7 @@ static void InitPointersToNeon() { > > #if defined(MIPS32_LE) > /* Initialize function pointers to the MIPS version. */ >-static void InitPointersToMIPS() { >+static void InitPointersToMIPS(void) { > WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips; > WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips; > WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips; >@@ -128,6 +128,6 @@ static void once(void (*func)(void)) { > */ > #endif /* WEBRTC_POSIX */ > >-void WebRtcSpl_Init() { >+void WebRtcSpl_Init(void) { > once(InitFunctionPointers); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.cc >index ecfb5c252b0..d426bda2501 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.cc >@@ -52,10 +52,10 @@ void SmoothingFilterImpl::AddSample(float sample) { > last_sample_ = sample; > } > >-rtc::Optional<float> SmoothingFilterImpl::GetAverage() { >+absl::optional<float> SmoothingFilterImpl::GetAverage() { > if (!init_end_time_ms_) { > // |init_end_time_ms_| undefined since we have not received any sample. >- return rtc::nullopt; >+ return absl::nullopt; > } > ExtrapolateLastSample(rtc::TimeMillis()); > return state_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.h >index b8ab4e5919c..cff746953aa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter.h >@@ -11,7 +11,7 @@ > #ifndef COMMON_AUDIO_SMOOTHING_FILTER_H_ > #define COMMON_AUDIO_SMOOTHING_FILTER_H_ > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "rtc_base/constructormagic.h" > #include "system_wrappers/include/clock.h" > >@@ -21,7 +21,7 @@ class SmoothingFilter { > public: > virtual ~SmoothingFilter() = default; > virtual void AddSample(float sample) = 0; >- virtual rtc::Optional<float> GetAverage() = 0; >+ virtual absl::optional<float> GetAverage() = 0; > virtual bool SetTimeConstantMs(int time_constant_ms) = 0; > }; > >@@ -44,7 +44,7 @@ class SmoothingFilterImpl final : public SmoothingFilter { > ~SmoothingFilterImpl() override; > > void AddSample(float sample) override; >- rtc::Optional<float> GetAverage() override; >+ absl::optional<float> GetAverage() override; > bool SetTimeConstantMs(int time_constant_ms) override; > > // Methods used for unittests. >@@ -58,7 +58,7 @@ class SmoothingFilterImpl final : public SmoothingFilter { > const float init_factor_; > const float init_const_; > >- rtc::Optional<int64_t> init_end_time_ms_; >+ absl::optional<int64_t> init_end_time_ms_; > float last_sample_; > float alpha_; > float state_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter_unittest.cc >index d173c9ab850..abe4272a825 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/smoothing_filter_unittest.cc >@@ -25,7 +25,7 @@ constexpr int64_t kClockInitialTime = 123456; > struct SmoothingFilterStates { > explicit SmoothingFilterStates(int init_time_ms) > : smoothing_filter(init_time_ms) { >- fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(kClockInitialTime)); >+ fake_clock.AdvanceTime(TimeDelta::ms(kClockInitialTime)); > } > rtc::ScopedFakeClock fake_clock; > SmoothingFilterImpl smoothing_filter; >@@ -41,8 +41,7 @@ void CheckOutput(SmoothingFilterStates* states, > int advance_time_ms, > float expected_ouput) { > states->smoothing_filter.AddSample(sample); >- states->fake_clock.AdvanceTime( >- rtc::TimeDelta::FromMilliseconds(advance_time_ms)); >+ states->fake_clock.AdvanceTime(TimeDelta::ms(advance_time_ms)); > auto output = states->smoothing_filter.GetAverage(); > EXPECT_TRUE(output); > EXPECT_NEAR(expected_ouput, *output, kMaxAbsError); >@@ -141,14 +140,13 @@ TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) { > states.smoothing_filter.AddSample(0.0); > > // During initialization, |SetTimeConstantMs| does not take effect. >- states.fake_clock.AdvanceTime( >- rtc::TimeDelta::FromMilliseconds(kInitTimeMs - 1)); >+ states.fake_clock.AdvanceTime(TimeDelta::ms(kInitTimeMs - 1)); > states.smoothing_filter.AddSample(0.0); > > EXPECT_FALSE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2)); > EXPECT_NE(exp(-1.0f / (kInitTimeMs * 2)), states.smoothing_filter.alpha()); > >- states.fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1)); >+ states.fake_clock.AdvanceTime(TimeDelta::ms(1)); > states.smoothing_filter.AddSample(0.0); > // When initialization finishes, the time constant should be come > // |kInitTimeConstantMs|. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter.cc >index ed2d79bbe16..0fc032722e8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter.cc >@@ -34,8 +34,8 @@ void SparseFIRFilter::Filter(const float* in, size_t length, float* out) { > for (size_t i = 0; i < length; ++i) { > out[i] = 0.f; > size_t j; >- for (j = 0; i >= j * sparsity_ + offset_ && >- j < nonzero_coeffs_.size(); ++j) { >+ for (j = 0; i >= j * sparsity_ + offset_ && j < nonzero_coeffs_.size(); >+ ++j) { > out[i] += in[i - j * sparsity_ - offset_] * nonzero_coeffs_[j]; > } > for (; j < nonzero_coeffs_.size(); ++j) { >@@ -47,12 +47,10 @@ void SparseFIRFilter::Filter(const float* in, size_t length, float* out) { > // Update current state. > if (state_.size() > 0u) { > if (length >= state_.size()) { >- std::memcpy(&state_[0], >- &in[length - state_.size()], >+ std::memcpy(&state_[0], &in[length - state_.size()], > state_.size() * sizeof(*in)); > } else { >- std::memmove(&state_[0], >- &state_[length], >+ std::memmove(&state_[0], &state_[length], > (state_.size() - length) * sizeof(state_[0])); > std::memcpy(&state_[state_.size() - length], in, length * sizeof(*in)); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter_unittest.cc >index 434daaa6d96..b6cd6f9d9b6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/sparse_fir_filter_unittest.cc >@@ -21,8 +21,8 @@ namespace webrtc { > namespace { > > static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f}; >-static const float kInput[] = >- {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f}; >+static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, >+ 6.f, 7.f, 8.f, 9.f, 10.f}; > > template <size_t N> > void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) { >@@ -50,13 +50,9 @@ TEST(SparseFIRFilterTest, SameOutputForScalarCoefficientAndDifferentSparsity) { > const size_t kOffset = 0; > float low_sparsity_output[arraysize(kInput)]; > float high_sparsity_output[arraysize(kInput)]; >- SparseFIRFilter low_sparsity_filter(&kCoeff, >- kNumCoeff, >- kLowSparsity, >+ SparseFIRFilter low_sparsity_filter(&kCoeff, kNumCoeff, kLowSparsity, > kOffset); >- SparseFIRFilter high_sparsity_filter(&kCoeff, >- kNumCoeff, >- kHighSparsity, >+ SparseFIRFilter high_sparsity_filter(&kCoeff, kNumCoeff, kHighSparsity, > kOffset); > low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output); > high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output); >@@ -146,15 +142,10 @@ TEST(SparseFIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) { > const size_t kSparsity = 3; > const size_t kOffset = 1; > float output_block_based[arraysize(kInput)]; >- SparseFIRFilter filter_block(kCoeffs, >- arraysize(kCoeffs), >- kSparsity, >- kOffset); >+ SparseFIRFilter filter_block(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); > filter_block.Filter(kInput, arraysize(kInput), output_block_based); > float output_sample_based[arraysize(kInput)]; >- SparseFIRFilter filter_sample(kCoeffs, >- arraysize(kCoeffs), >- kSparsity, >+ SparseFIRFilter filter_sample(kCoeffs, arraysize(kCoeffs), kSparsity, > kOffset); > for (size_t i = 0; i < arraysize(kInput); ++i) > filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]); >@@ -165,8 +156,8 @@ TEST(SparseFIRFilterTest, SimpleHighPassFilter) { > const size_t kSparsity = 2; > const size_t kOffset = 2; > const float kHPCoeffs[] = {1.f, -1.f}; >- const float kConstantInput[] = >- {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; >+ const float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, >+ 1.f, 1.f, 1.f, 1.f, 1.f}; > float output[arraysize(kConstantInput)]; > SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset); > filter.Filter(kConstantInput, arraysize(kConstantInput), output); >@@ -182,8 +173,8 @@ TEST(SparseFIRFilterTest, SimpleLowPassFilter) { > const size_t kSparsity = 2; > const size_t kOffset = 2; > const float kLPCoeffs[] = {1.f, 1.f}; >- const float kHighFrequencyInput[] = >- {1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f}; >+ const float kHighFrequencyInput[] = {1.f, 1.f, -1.f, -1.f, 1.f, >+ 1.f, -1.f, -1.f, 1.f, 1.f}; > float output[arraysize(kHighFrequencyInput)]; > SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset); > filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output); >@@ -203,9 +194,7 @@ TEST(SparseFIRFilterTest, SameOutputWhenSwappedCoefficientsAndInput) { > SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset); > // Use arraysize(kCoeffs) for in_length to get same-length outputs. > filter.Filter(kInput, arraysize(kCoeffs), output); >- SparseFIRFilter filter_swapped(kInput, >- arraysize(kCoeffs), >- kSparsity, >+ SparseFIRFilter filter_swapped(kInput, arraysize(kCoeffs), kSparsity, > kOffset); > filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped); > VerifyOutput(output, output_swapped); >@@ -218,9 +207,7 @@ TEST(SparseFIRFilterTest, SameOutputAsFIRFilterWhenSparsityOneAndOffsetZero) { > float sparse_output[arraysize(kInput)]; > std::unique_ptr<FIRFilter> filter( > CreateFirFilter(kCoeffs, arraysize(kCoeffs), arraysize(kInput))); >- SparseFIRFilter sparse_filter(kCoeffs, >- arraysize(kCoeffs), >- kSparsity, >+ SparseFIRFilter sparse_filter(kCoeffs, arraysize(kCoeffs), kSparsity, > kOffset); > filter->Filter(kInput, arraysize(kInput), output); > sparse_filter.Filter(kInput, arraysize(kInput), sparse_output); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/BUILD.gn >new file mode 100644 >index 00000000000..ae0d5f6c00c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/BUILD.gn >@@ -0,0 +1,16 @@ >+# Copyright (c) 2018 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. >+ >+import("../../../webrtc.gni") >+ >+rtc_source_set("fft4g") { >+ sources = [ >+ "fft4g.c", >+ "fft4g.h", >+ ] >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/LICENSE b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/LICENSE >new file mode 100644 >index 00000000000..3bf870aa3cc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/LICENSE >@@ -0,0 +1,8 @@ >+/* >+ * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html >+ * Copyright Takuya OOURA, 1996-2001 >+ * >+ * You may use, copy, modify and distribute this code for any purpose (include >+ * commercial use) and without fee. Please refer to this package when you modify >+ * this code. >+ */ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/README.chromium b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/README.chromium >new file mode 100644 >index 00000000000..9df2ddb5e28 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/README.chromium >@@ -0,0 +1,13 @@ >+Name: General Purpose FFT (Fast Fourier/Cosine/Sine Transform) Package >+Short Name: fft4g >+URL: http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html >+Version: 0 >+Date: 2018-06-19 >+License: Custome license >+License File: LICENSE >+Security Critical: yes >+ >+Description: >+This is a package to calculate Discrete Fourier/Cosine/Sine Transforms of >+1-dimensional sequences of length 2^N. This package contains C and Fortran >+FFT codes. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fft4g.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/fft4g.c >similarity index 100% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fft4g.c >rename to Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/fft4g.c >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fft4g.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/fft4g.h >similarity index 52% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fft4g.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/fft4g.h >index 1f0e29dd5c8..f1f31a182d9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/fft4g.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/fft4g/fft4g.h >@@ -1,25 +1,25 @@ > /* >- * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. >+ * Copyright (c) 2018 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 >+ * 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. > */ > >-#ifndef COMMON_AUDIO_FFT4G_H_ >-#define COMMON_AUDIO_FFT4G_H_ >+#ifndef COMMON_AUDIO_THIRD_PARTY_FFT4G_FFT4G_H_ >+#define COMMON_AUDIO_THIRD_PARTY_FFT4G_FFT4G_H_ > > #if defined(__cplusplus) > extern "C" { > #endif > > // Refer to fft4g.c for documentation. >-void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w); >+void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w); > > #if defined(__cplusplus) > } > #endif > >-#endif // COMMON_AUDIO_FFT4G_H_ >+#endif /* COMMON_AUDIO_THIRD_PARTY_FFT4G_FFT4G_H_ */ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn >new file mode 100644 >index 00000000000..194899ebda3 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn >@@ -0,0 +1,26 @@ >+# Copyright (c) 2018 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. >+ >+import("../../../webrtc.gni") >+ >+rtc_source_set("spl_sqrt_floor") { >+ visibility = [ "../..:common_audio_c" ] >+ sources = [ >+ "spl_sqrt_floor.h", >+ ] >+ deps = [] >+ if (current_cpu == "arm") { >+ sources += [ "spl_sqrt_floor_arm.S" ] >+ >+ deps += [ "../../../rtc_base/system:asm_defines" ] >+ } else if (current_cpu == "mipsel") { >+ sources += [ "spl_sqrt_floor_mips.c" ] >+ } else { >+ sources += [ "spl_sqrt_floor.c" ] >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE >new file mode 100644 >index 00000000000..fdf17a2041e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/LICENSE >@@ -0,0 +1,27 @@ >+/* >+ * Written by Wilco Dijkstra, 1996. The following email exchange establishes the >+ * license. >+ * >+ * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> >+ * Date: Fri, Jun 24, 2011 at 3:20 AM >+ * Subject: Re: sqrt routine >+ * To: Kevin Ma <kma@google.com> >+ * Hi Kevin, >+ * Thanks for asking. Those routines are public domain (originally posted to >+ * comp.sys.arm a long time ago), so you can use them freely for any purpose. >+ * Cheers, >+ * Wilco >+ * >+ * ----- Original Message ----- >+ * From: "Kevin Ma" <kma@google.com> >+ * To: <Wilco.Dijkstra@ntlworld.com> >+ * Sent: Thursday, June 23, 2011 11:44 PM >+ * Subject: Fwd: sqrt routine >+ * Hi Wilco, >+ * I saw your sqrt routine from several web sites, including >+ * http://www.finesse.demon.co.uk/steven/sqrt.html. >+ * Just wonder if there's any copyright information with your Successive >+ * approximation routines, or if I can freely use it for any purpose. >+ * Thanks. >+ * Kevin >+ */ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/README.chromium b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/README.chromium >new file mode 100644 >index 00000000000..b226490e85f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/README.chromium >@@ -0,0 +1,12 @@ >+Name: sql sqrt floor >+Short Name: sql_sqrt_floor >+URL: http://www.pertinentdetail.org/sqrt >+Version: 0 >+Date: 2018-03-22 >+License: Custom license >+License File: LICENSE >+Security Critical: yes >+ >+Description: >+Sqrt routine, originally was posted to the USENET group comp.sys.arm on >+20 Jun 1996. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c >similarity index 96% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor.c >rename to Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c >index 714138696bc..b478a41b969 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c >@@ -28,7 +28,7 @@ > > // Minor modifications in code style for WebRTC, 2012. > >-#include "common_audio/signal_processing/include/signal_processing_library.h" >+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" > > /* > * Algorithm: >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h >new file mode 100644 >index 00000000000..eaa58e30a4b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h >@@ -0,0 +1,29 @@ >+/* >+ * Copyright (c) 2018 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 <stdint.h> >+ >+// >+// WebRtcSpl_SqrtFloor(...) >+// >+// Returns the square root of the input value |value|. The precision of this >+// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. >+// If |value| is a negative number then 0 is returned. >+// >+// Algorithm: >+// >+// An iterative 4 cylce/bit routine >+// >+// Input: >+// - value : Value to calculate sqrt of >+// >+// Return value : Result of the sqrt calculation >+// >+int32_t WebRtcSpl_SqrtFloor(int32_t value); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S >similarity index 98% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S >rename to Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S >index 29e6d4d4552..228e68e6ca6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S >@@ -32,7 +32,7 @@ > @ Output: r0 = INT (SQRT (r0)), precision is 16 bits > @ Registers touched: r1, r2 > >-#include "system_wrappers/include/asm_defines.h" >+#include "rtc_base/system/asm_defines.h" > > GLOBAL_FUNCTION WebRtcSpl_SqrtFloor > .align 2 >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c >similarity index 99% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c >rename to Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c >index 7128fbd381a..04033c14dee 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c >@@ -29,7 +29,7 @@ > // Minor modifications in code style for WebRTC, 2012. > // Code optimizations for MIPS, 2013. > >-#include "common_audio/signal_processing/include/signal_processing_library.h" >+#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" > > /* > * Algorithm: >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/vad.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/vad.h >index bd10756c99d..b15275b1668 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/vad.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/vad.h >@@ -15,7 +15,6 @@ > > #include "common_audio/vad/include/webrtc_vad.h" > #include "rtc_base/checks.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/webrtc_vad.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/webrtc_vad.h >index 353dbf0861d..f5bbadf5b78 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/webrtc_vad.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/include/webrtc_vad.h >@@ -8,17 +8,16 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* >- * This header file includes the VAD API calls. Specific function calls are given below. >+ * This header file includes the VAD API calls. Specific function calls are >+ * given below. > */ > > #ifndef COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT > #define COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ > > #include <stddef.h> >- >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > typedef struct WebRtcVadInst VadInst; > >@@ -67,7 +66,9 @@ int WebRtcVad_set_mode(VadInst* handle, int mode); > // returns : 1 - (Active Voice), > // 0 - (Non-active Voice), > // -1 - (Error) >-int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame, >+int WebRtcVad_Process(VadInst* handle, >+ int fs, >+ const int16_t* audio_frame, > size_t frame_length); > > // Checks for valid combinations of |rate| and |frame_length|. We support 10, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.c >index 7316b45ce8b..55927cea40f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.c >@@ -15,7 +15,6 @@ > #include "common_audio/vad/vad_filterbank.h" > #include "common_audio/vad/vad_gmm.h" > #include "common_audio/vad/vad_sp.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Spectrum Weighting > static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.h >index 6541819f53e..e79696cef0b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core.h >@@ -8,7 +8,6 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > /* > * This header file includes the descriptions of the core VAD calls. > */ >@@ -17,39 +16,38 @@ > #define COMMON_AUDIO_VAD_VAD_CORE_H_ > > #include "common_audio/signal_processing/include/signal_processing_library.h" >-#include "typedefs.h" // NOLINT(build/include) > >-enum { kNumChannels = 6 }; // Number of frequency bands (named channels). >+enum { kNumChannels = 6 }; // Number of frequency bands (named channels). > enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM. > enum { kTableSize = kNumChannels * kNumGaussians }; > enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal. > > typedef struct VadInstT_ { >- int vad; >- int32_t downsampling_filter_states[4]; >- WebRtcSpl_State48khzTo8khz state_48_to_8; >- int16_t noise_means[kTableSize]; >- int16_t speech_means[kTableSize]; >- int16_t noise_stds[kTableSize]; >- int16_t speech_stds[kTableSize]; >- // TODO(bjornv): Change to |frame_count|. >- int32_t frame_counter; >- int16_t over_hang; // Over Hang >- int16_t num_of_speech; >- // TODO(bjornv): Change to |age_vector|. >- int16_t index_vector[16 * kNumChannels]; >- int16_t low_value_vector[16 * kNumChannels]; >- // TODO(bjornv): Change to |median|. >- int16_t mean_value[kNumChannels]; >- int16_t upper_state[5]; >- int16_t lower_state[5]; >- int16_t hp_filter_state[4]; >- int16_t over_hang_max_1[3]; >- int16_t over_hang_max_2[3]; >- int16_t individual[3]; >- int16_t total[3]; >+ int vad; >+ int32_t downsampling_filter_states[4]; >+ WebRtcSpl_State48khzTo8khz state_48_to_8; >+ int16_t noise_means[kTableSize]; >+ int16_t speech_means[kTableSize]; >+ int16_t noise_stds[kTableSize]; >+ int16_t speech_stds[kTableSize]; >+ // TODO(bjornv): Change to |frame_count|. >+ int32_t frame_counter; >+ int16_t over_hang; // Over Hang >+ int16_t num_of_speech; >+ // TODO(bjornv): Change to |age_vector|. >+ int16_t index_vector[16 * kNumChannels]; >+ int16_t low_value_vector[16 * kNumChannels]; >+ // TODO(bjornv): Change to |median|. >+ int16_t mean_value[kNumChannels]; >+ int16_t upper_state[5]; >+ int16_t lower_state[5]; >+ int16_t hp_filter_state[4]; >+ int16_t over_hang_max_1[3]; >+ int16_t over_hang_max_2[3]; >+ int16_t individual[3]; >+ int16_t total[3]; > >- int init_flag; >+ int init_flag; > } VadInstT; > > // Initializes the core VAD component. The default aggressiveness mode is >@@ -100,13 +98,17 @@ int WebRtcVad_set_mode_core(VadInstT* self, int mode); > * 0 - No active speech > * 1-6 - Active speech > */ >-int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame, >+int WebRtcVad_CalcVad48khz(VadInstT* inst, >+ const int16_t* speech_frame, > size_t frame_length); >-int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame, >+int WebRtcVad_CalcVad32khz(VadInstT* inst, >+ const int16_t* speech_frame, > size_t frame_length); >-int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame, >+int WebRtcVad_CalcVad16khz(VadInstT* inst, >+ const int16_t* speech_frame, > size_t frame_length); >-int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame, >+int WebRtcVad_CalcVad8khz(VadInstT* inst, >+ const int16_t* speech_frame, > size_t frame_length); > > #endif // COMMON_AUDIO_VAD_VAD_CORE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core_unittest.cc >index 0587878105a..3131a86ae32 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_core_unittest.cc >@@ -12,7 +12,6 @@ > > #include "common_audio/vad/vad_unittest.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > extern "C" { > #include "common_audio/vad/vad_core.h" >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.c >index 82cff25c36e..1513153c48b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.c >@@ -12,7 +12,6 @@ > > #include "rtc_base/checks.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Constants used in LogOfEnergy(). > static const int16_t kLogConst = 24660; // 160*log10(2) in Q9. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.h >index 620f96a6991..53bbbe10fdc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank.h >@@ -16,7 +16,6 @@ > #define COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ > > #include "common_audio/vad/vad_core.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Takes |data_length| samples of |data_in| and calculates the logarithm of the > // energy of each of the |kNumChannels| = 6 frequency bands used by the VAD: >@@ -38,7 +37,9 @@ > // - features [o] : 10 * log10(energy in each frequency band), Q4. > // - returns : Total energy of the signal (NOTE! This value is not > // exact. It is only used in a comparison.) >-int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, >- size_t data_length, int16_t* features); >+int16_t WebRtcVad_CalculateFeatures(VadInstT* self, >+ const int16_t* data_in, >+ size_t data_length, >+ int16_t* features); > > #endif // COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank_unittest.cc >index 55b12793dad..51d8d0fefdf 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_filterbank_unittest.cc >@@ -12,7 +12,6 @@ > > #include "common_audio/vad/vad_unittest.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > extern "C" { > #include "common_audio/vad/vad_core.h" >@@ -26,14 +25,12 @@ const int kNumValidFrameLengths = 3; > > TEST_F(VadTest, vad_filterbank) { > VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); >- static const int16_t kReference[kNumValidFrameLengths] = { 48, 11, 11 }; >+ static const int16_t kReference[kNumValidFrameLengths] = {48, 11, 11}; > static const int16_t kFeatures[kNumValidFrameLengths * kNumChannels] = { >- 1213, 759, 587, 462, 434, 272, >- 1479, 1385, 1291, 1200, 1103, 1099, >- 1732, 1692, 1681, 1629, 1436, 1436 >- }; >- static const int16_t kOffsetVector[kNumChannels] = { >- 368, 368, 272, 176, 176, 176 }; >+ 1213, 759, 587, 462, 434, 272, 1479, 1385, 1291, >+ 1200, 1103, 1099, 1732, 1692, 1681, 1629, 1436, 1436}; >+ static const int16_t kOffsetVector[kNumChannels] = {368, 368, 272, >+ 176, 176, 176}; > int16_t features[kNumChannels]; > > // Construct a speech signal that will trigger the VAD in all modes. It is >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.c >index b746fd53642..ddc87b6edd3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.c >@@ -11,7 +11,6 @@ > #include "common_audio/vad/vad_gmm.h" > > #include "common_audio/signal_processing/include/signal_processing_library.h" >-#include "typedefs.h" // NOLINT(build/include) > > static const int32_t kCompVar = 22005; > static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.h >index 79f15c89574..6b2d11ba336 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm.h >@@ -13,7 +13,7 @@ > #ifndef COMMON_AUDIO_VAD_VAD_GMM_H_ > #define COMMON_AUDIO_VAD_VAD_GMM_H_ > >-#include "typedefs.h" // NOLINT(build/include) >+#include <stdint.h> > > // Calculates the probability for |input|, given that |input| comes from a > // normal distribution with mean and standard deviation (|mean|, |std|). >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm_unittest.cc >index e77603d6ec0..be61f7f9715 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_gmm_unittest.cc >@@ -10,7 +10,6 @@ > > #include "common_audio/vad/vad_unittest.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > extern "C" { > #include "common_audio/vad/vad_gmm.h" >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.c >index 915fb375206..d367c8b0af1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.c >@@ -13,7 +13,6 @@ > #include "rtc_base/checks.h" > #include "common_audio/signal_processing/include/signal_processing_library.h" > #include "common_audio/vad/vad_core.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Allpass filter coefficients, upper and lower, in Q13. > // Upper: 0.64, Lower: 0.17. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.h >index 21fed11b1af..ff367603c58 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp.h >@@ -8,14 +8,12 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >- > // This file includes specific signal processing tools used in vad_core.c. > > #ifndef COMMON_AUDIO_VAD_VAD_SP_H_ > #define COMMON_AUDIO_VAD_VAD_SP_H_ > > #include "common_audio/vad/vad_core.h" >-#include "typedefs.h" // NOLINT(build/include) > > // Downsamples the signal by a factor 2, eg. 32->16 or 16->8. > // >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp_unittest.cc >index 7eb6794d217..cdde56d1ca2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_sp_unittest.cc >@@ -12,7 +12,6 @@ > > #include "common_audio/vad/vad_unittest.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > extern "C" { > #include "common_audio/vad/vad_core.h" >@@ -25,19 +24,17 @@ namespace test { > TEST_F(VadTest, vad_sp) { > VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); > const size_t kMaxFrameLenSp = 960; // Maximum frame length in this unittest. >- int16_t zeros[kMaxFrameLenSp] = { 0 }; >- int32_t state[2] = { 0 }; >+ int16_t zeros[kMaxFrameLenSp] = {0}; >+ int32_t state[2] = {0}; > int16_t data_in[kMaxFrameLenSp]; > int16_t data_out[kMaxFrameLenSp]; > > // We expect the first value to be 1600 as long as |frame_counter| is zero, > // which is true for the first iteration. > static const int16_t kReferenceMin[32] = { >- 1600, 720, 509, 512, 532, 552, 570, 588, >- 606, 624, 642, 659, 675, 691, 707, 723, >- 1600, 544, 502, 522, 542, 561, 579, 597, >- 615, 633, 651, 667, 683, 699, 715, 731 >- }; >+ 1600, 720, 509, 512, 532, 552, 570, 588, 606, 624, 642, >+ 659, 675, 691, 707, 723, 1600, 544, 502, 522, 542, 561, >+ 579, 597, 615, 633, 651, 667, 683, 699, 715, 731}; > > // Construct a speech signal that will trigger the VAD in all modes. It is > // known that (i * i) will wrap around, but that doesn't matter in this case. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.cc >index f79678b8a00..c54014efce8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.cc >@@ -17,7 +17,6 @@ > #include "rtc_base/arraysize.h" > #include "rtc_base/checks.h" > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > VadTest::VadTest() {} > >@@ -60,7 +59,7 @@ TEST_F(VadTest, ApiTest) { > // combinations. > > VadInst* handle = WebRtcVad_Create(); >- int16_t zeros[kMaxFrameLength] = { 0 }; >+ int16_t zeros[kMaxFrameLength] = {0}; > > // Construct a speech signal that will trigger the VAD in all modes. It is > // known that (i * i) will wrap around, but that doesn't matter in this case. >@@ -87,12 +86,10 @@ TEST_F(VadTest, ApiTest) { > > // WebRtcVad_set_mode() invalid modes tests. Tries smallest supported value > // minus one and largest supported value plus one. >- EXPECT_EQ(-1, WebRtcVad_set_mode(handle, >- WebRtcSpl_MinValueW32(kModes, >- kModesSize) - 1)); >- EXPECT_EQ(-1, WebRtcVad_set_mode(handle, >- WebRtcSpl_MaxValueW32(kModes, >- kModesSize) + 1)); >+ EXPECT_EQ(-1, WebRtcVad_set_mode( >+ handle, WebRtcSpl_MinValueW32(kModes, kModesSize) - 1)); >+ EXPECT_EQ(-1, WebRtcVad_set_mode( >+ handle, WebRtcSpl_MaxValueW32(kModes, kModesSize) + 1)); > > // WebRtcVad_Process() tests > // nullptr as speech pointer >@@ -109,14 +106,10 @@ TEST_F(VadTest, ApiTest) { > for (size_t i = 0; i < kRatesSize; i++) { > for (size_t j = 0; j < kFrameLengthsSize; j++) { > if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) { >- EXPECT_EQ(1, WebRtcVad_Process(handle, >- kRates[i], >- speech, >+ EXPECT_EQ(1, WebRtcVad_Process(handle, kRates[i], speech, > kFrameLengths[j])); > } else { >- EXPECT_EQ(-1, WebRtcVad_Process(handle, >- kRates[i], >- speech, >+ EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[i], speech, > kFrameLengths[j])); > } > } >@@ -130,22 +123,20 @@ TEST_F(VadTest, ValidRatesFrameLengths) { > // This test verifies valid and invalid rate/frame_length combinations. We > // loop through some sampling rates and frame lengths from negative values to > // values larger than possible. >- const int kRates[] = { >- -8000, -4000, 0, 4000, 8000, 8001, 15999, 16000, 32000, 48000, 48001, 96000 >- }; >+ const int kRates[] = {-8000, -4000, 0, 4000, 8000, 8001, >+ 15999, 16000, 32000, 48000, 48001, 96000}; > >- const size_t kFrameLengths[] = { >- 0, 80, 81, 159, 160, 240, 320, 480, 640, 960, 1440, 2000 >- }; >+ const size_t kFrameLengths[] = {0, 80, 81, 159, 160, 240, >+ 320, 480, 640, 960, 1440, 2000}; > > for (size_t i = 0; i < arraysize(kRates); i++) { > for (size_t j = 0; j < arraysize(kFrameLengths); j++) { > if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) { >- EXPECT_EQ(0, WebRtcVad_ValidRateAndFrameLength(kRates[i], >- kFrameLengths[j])); >+ EXPECT_EQ( >+ 0, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j])); > } else { >- EXPECT_EQ(-1, WebRtcVad_ValidRateAndFrameLength(kRates[i], >- kFrameLengths[j])); >+ EXPECT_EQ( >+ -1, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j])); > } > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.h >index f982f52eb5a..ee642063af5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/vad_unittest.h >@@ -14,23 +14,22 @@ > #include <stddef.h> // size_t > > #include "test/gtest.h" >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > namespace test { > > // Modes we support >-const int kModes[] = { 0, 1, 2, 3 }; >+const int kModes[] = {0, 1, 2, 3}; > const size_t kModesSize = sizeof(kModes) / sizeof(*kModes); > > // Rates we support. >-const int kRates[] = { 8000, 12000, 16000, 24000, 32000, 48000 }; >+const int kRates[] = {8000, 12000, 16000, 24000, 32000, 48000}; > const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); > > // Frame lengths we support. > const size_t kMaxFrameLength = 1440; >-const size_t kFrameLengths[] = { 80, 120, 160, 240, 320, 480, 640, 960, >- kMaxFrameLength }; >+const size_t kFrameLengths[] = { >+ 80, 120, 160, 240, 320, 480, 640, 960, kMaxFrameLength}; > const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths); > > } // namespace test >@@ -39,8 +38,8 @@ const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths); > class VadTest : public ::testing::Test { > protected: > VadTest(); >- virtual void SetUp(); >- virtual void TearDown(); >+ void SetUp() override; >+ void TearDown() override; > > // Returns true if the rate and frame length combination is valid. > bool ValidRatesAndFrameLengths(int rate, size_t frame_length); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/webrtc_vad.c b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/webrtc_vad.c >index 7fc4d65ed27..d8457eeebe8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/webrtc_vad.c >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/vad/webrtc_vad.c >@@ -15,7 +15,6 @@ > > #include "common_audio/signal_processing/include/signal_processing_library.h" > #include "common_audio/vad/vad_core.h" >-#include "typedefs.h" // NOLINT(build/include) > > static const int kInitCheck = 42; > static const int kValidRates[] = { 8000, 16000, 32000, 48000 }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.cc >index 37f249e7fa8..0209f52d2c7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.cc >@@ -13,12 +13,13 @@ > #include <algorithm> > #include <cstdio> > #include <limits> >-#include <sstream> > > #include "common_audio/include/audio_util.h" > #include "common_audio/wav_header.h" > #include "rtc_base/checks.h" >+#include "rtc_base/logging.h" > #include "rtc_base/numerics/safe_conversions.h" >+#include "rtc_base/system/arch.h" > > namespace webrtc { > >@@ -30,7 +31,7 @@ static const size_t kBytesPerSample = 2; > class ReadableWavFile : public ReadableWav { > public: > explicit ReadableWavFile(FILE* file) : file_(file) {} >- virtual size_t Read(void* buf, size_t num_bytes) { >+ size_t Read(void* buf, size_t num_bytes) override { > return fread(buf, 1, num_bytes, file_); > } > >@@ -38,17 +39,22 @@ class ReadableWavFile : public ReadableWav { > FILE* file_; > }; > >-std::string WavFile::FormatAsString() const { >- std::ostringstream s; >- s << "Sample rate: " << sample_rate() << " Hz, Channels: " << num_channels() >- << ", Duration: " >- << (1.f * num_samples()) / (num_channels() * sample_rate()) << " s"; >- return s.str(); >-} >- > WavReader::WavReader(const std::string& filename) >- : file_handle_(fopen(filename.c_str(), "rb")) { >- RTC_CHECK(file_handle_) << "Could not open wav file for reading."; >+ : WavReader(rtc::OpenPlatformFileReadOnly(filename)) {} >+ >+WavReader::WavReader(rtc::PlatformFile file) { >+ RTC_CHECK_NE(file, rtc::kInvalidPlatformFileValue) >+ << "Invalid file. Could not create file handle for wav file."; >+ file_handle_ = rtc::FdopenPlatformFile(file, "rb"); >+ if (!file_handle_) { >+ RTC_LOG(LS_ERROR) << "Could not open wav file for reading: " << errno; >+ // Even though we failed to open a FILE*, the file is still open >+ // and needs to be closed. >+ if (!rtc::ClosePlatformFile(file)) { >+ RTC_LOG(LS_ERROR) << "Can't close file."; >+ } >+ RTC_FATAL() << "Could not open wav file for reading."; >+ } > > ReadableWavFile readable(file_handle_); > WavFormat format; >@@ -110,13 +116,31 @@ void WavReader::Close() { > file_handle_ = nullptr; > } > >-WavWriter::WavWriter(const std::string& filename, int sample_rate, >+WavWriter::WavWriter(const std::string& filename, >+ int sample_rate, > size_t num_channels) >- : sample_rate_(sample_rate), >- num_channels_(num_channels), >- num_samples_(0), >- file_handle_(fopen(filename.c_str(), "wb")) { >- RTC_CHECK(file_handle_) << "Could not open wav file for writing."; >+ // Unlike plain fopen, CreatePlatformFile takes care of filename utf8 -> >+ // wchar conversion on windows. >+ : WavWriter(rtc::CreatePlatformFile(filename), sample_rate, num_channels) {} >+ >+WavWriter::WavWriter(rtc::PlatformFile file, >+ int sample_rate, >+ size_t num_channels) >+ : sample_rate_(sample_rate), num_channels_(num_channels), num_samples_(0) { >+ // Handle errors from the CreatePlatformFile call in above constructor. >+ RTC_CHECK_NE(file, rtc::kInvalidPlatformFileValue) >+ << "Invalid file. Could not create wav file."; >+ file_handle_ = rtc::FdopenPlatformFile(file, "wb"); >+ if (!file_handle_) { >+ RTC_LOG(LS_ERROR) << "Could not open wav file for writing."; >+ // Even though we failed to open a FILE*, the file is still open >+ // and needs to be closed. >+ if (!rtc::ClosePlatformFile(file)) { >+ RTC_LOG(LS_ERROR) << "Can't close file."; >+ } >+ RTC_FATAL() << "Could not open wav file for writing."; >+ } >+ > RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, kWavFormat, > kBytesPerSample, num_samples_)); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.h >index f7afe9239c6..cbce59d364a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file.h >@@ -18,6 +18,7 @@ > #include <string> > > #include "rtc_base/constructormagic.h" >+#include "rtc_base/platform_file.h" > > namespace webrtc { > >@@ -29,9 +30,6 @@ class WavFile { > virtual int sample_rate() const = 0; > virtual size_t num_channels() const = 0; > virtual size_t num_samples() const = 0; >- >- // Returns a human-readable string containing the audio format. >- std::string FormatAsString() const; > }; > > // Simple C++ class for writing 16-bit PCM WAV files. All error handling is >@@ -41,6 +39,9 @@ class WavWriter final : public WavFile { > // Open a new WAV file for writing. > WavWriter(const std::string& filename, int sample_rate, size_t num_channels); > >+ // Open a new WAV file for writing. >+ WavWriter(rtc::PlatformFile file, int sample_rate, size_t num_channels); >+ > // Close the WAV file, after writing its header. > ~WavWriter() override; > >@@ -59,7 +60,7 @@ class WavWriter final : public WavFile { > const int sample_rate_; > const size_t num_channels_; > size_t num_samples_; // Total number of samples written to file. >- FILE* file_handle_; // Output file, owned by this class >+ FILE* file_handle_; // Output file, owned by this class > > RTC_DISALLOW_COPY_AND_ASSIGN(WavWriter); > }; >@@ -70,6 +71,9 @@ class WavReader final : public WavFile { > // Opens an existing WAV file for reading. > explicit WavReader(const std::string& filename); > >+ // Opens an existing WAV file for reading. >+ explicit WavReader(rtc::PlatformFile file); >+ > // Close the WAV file. > ~WavReader() override; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file_unittest.cc >index 7113b47c75c..d40229a1ebd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_file_unittest.cc >@@ -19,12 +19,22 @@ > #include "test/gtest.h" > #include "test/testsupport/fileutils.h" > >+// WavWriterTest.CPPFileDescriptor and WavWriterTest.CPP flaky on Mac. >+// See webrtc:9247. >+#if defined(WEBRTC_MAC) >+#define MAYBE_CPP DISABLED_CPP >+#define MAYBE_CPPFileDescriptor DISABLED_CPPFileDescriptor >+#else >+#define MAYBE_CPP CPP >+#define MAYBE_CPPFileDescriptor CPPFileDescriptor >+#endif >+ > namespace webrtc { > > static const float kSamples[] = {0.0, 10.0, 4e4, -1e9}; > > // Write a tiny WAV file with the C++ interface and verify the result. >-TEST(WavWriterTest, CPP) { >+TEST(WavWriterTest, MAYBE_CPP) { > const std::string outfile = test::OutputPath() + "wavtest1.wav"; > static const size_t kNumSamples = 3; > { >@@ -46,6 +56,8 @@ TEST(WavWriterTest, CPP) { > fclose(f); > } > static const uint8_t kExpectedContents[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 42, 0, 0, 0, // size of whole file - 8: 6 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -63,6 +75,7 @@ TEST(WavWriterTest, CPP) { > 10, 0, // second sample: 10.0 > 0xff, 0x7f, // third sample: 4e4 (saturated) > kMetadata[0], kMetadata[1], >+ // clang-format on > }; > static const size_t kContentSize = > kWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata); >@@ -102,6 +115,8 @@ TEST(WavWriterTest, C) { > EXPECT_EQ(kNumSamples, rtc_WavNumSamples(w)); > rtc_WavClose(w); > static const uint8_t kExpectedContents[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 44, 0, 0, 0, // size of whole file - 8: 8 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -119,6 +134,7 @@ TEST(WavWriterTest, C) { > 10, 0, // second sample: 10.0 > 0xff, 0x7f, // third sample: 4e4 (saturated) > 0, 0x80, // fourth sample: -1e9 (saturated) >+ // clang-format on > }; > static const size_t kContentSize = > kWavHeaderSize + kNumSamples * sizeof(int16_t); >@@ -174,4 +190,73 @@ TEST(WavWriterTest, LargeFile) { > } > } > >+// Write a tiny WAV file with the the std::FILE interface and verify the >+// result. >+TEST(WavWriterTest, MAYBE_CPPFileDescriptor) { >+ const std::string outfile = test::OutputPath() + "wavtest1.wav"; >+ static constexpr size_t kNumSamples = 3; >+ { >+ WavWriter w(rtc::CreatePlatformFile(outfile), 14099, 1); >+ EXPECT_EQ(14099, w.sample_rate()); >+ EXPECT_EQ(1u, w.num_channels()); >+ EXPECT_EQ(0u, w.num_samples()); >+ w.WriteSamples(kSamples, kNumSamples); >+ EXPECT_EQ(kNumSamples, w.num_samples()); >+ } >+ // Write some extra "metadata" to the file that should be silently ignored >+ // by WavReader. We don't use WavWriter directly for this because it doesn't >+ // support metadata. >+ static constexpr uint8_t kMetadata[] = {101, 202}; >+ { >+ FILE* f = fopen(outfile.c_str(), "ab"); >+ ASSERT_TRUE(f); >+ ASSERT_EQ(1u, fwrite(kMetadata, sizeof(kMetadata), 1, f)); >+ fclose(f); >+ } >+ static const uint8_t kExpectedContents[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. >+ 'R', 'I', 'F', 'F', >+ 42, 0, 0, 0, // size of whole file - 8: 6 + 44 - 8 >+ 'W', 'A', 'V', 'E', >+ 'f', 'm', 't', ' ', >+ 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 >+ 1, 0, // format: PCM (1) >+ 1, 0, // channels: 1 >+ 0x13, 0x37, 0, 0, // sample rate: 14099 >+ 0x26, 0x6e, 0, 0, // byte rate: 2 * 14099 >+ 2, 0, // block align: NumChannels * BytesPerSample >+ 16, 0, // bits per sample: 2 * 8 >+ 'd', 'a', 't', 'a', >+ 6, 0, 0, 0, // size of payload: 6 >+ 0, 0, // first sample: 0.0 >+ 10, 0, // second sample: 10.0 >+ 0xff, 0x7f, // third sample: 4e4 (saturated) >+ kMetadata[0], kMetadata[1], >+ // clang-format on >+ }; >+ static constexpr size_t kContentSize = >+ kWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata); >+ static_assert(sizeof(kExpectedContents) == kContentSize, ""); >+ EXPECT_EQ(kContentSize, test::GetFileSize(outfile)); >+ FILE* f = fopen(outfile.c_str(), "rb"); >+ ASSERT_TRUE(f); >+ uint8_t contents[kContentSize]; >+ ASSERT_EQ(1u, fread(contents, kContentSize, 1, f)); >+ EXPECT_EQ(0, fclose(f)); >+ EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize)); >+ >+ { >+ WavReader r(rtc::OpenPlatformFileReadOnly(outfile)); >+ EXPECT_EQ(14099, r.sample_rate()); >+ EXPECT_EQ(1u, r.num_channels()); >+ EXPECT_EQ(kNumSamples, r.num_samples()); >+ static constexpr float kTruncatedSamples[] = {0.0, 10.0, 32767.0}; >+ float samples[kNumSamples]; >+ EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples)); >+ EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples))); >+ EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples)); >+ } >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.cc >index a57e917249c..8fc5fef5085 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.cc >@@ -21,6 +21,7 @@ > > #include "common_audio/include/audio_util.h" > #include "rtc_base/checks.h" >+#include "rtc_base/system/arch.h" > > namespace webrtc { > namespace { >@@ -112,17 +113,23 @@ bool CheckWavParameters(size_t num_channels, > } > > #ifdef WEBRTC_ARCH_LITTLE_ENDIAN >-static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; } >-static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; } >+static inline void WriteLE16(uint16_t* f, uint16_t x) { >+ *f = x; >+} >+static inline void WriteLE32(uint32_t* f, uint32_t x) { >+ *f = x; >+} > static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) { >- *f = static_cast<uint32_t>(a) >- | static_cast<uint32_t>(b) << 8 >- | static_cast<uint32_t>(c) << 16 >- | static_cast<uint32_t>(d) << 24; >+ *f = static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 | >+ static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24; > } > >-static inline uint16_t ReadLE16(uint16_t x) { return x; } >-static inline uint32_t ReadLE32(uint32_t x) { return x; } >+static inline uint16_t ReadLE16(uint16_t x) { >+ return x; >+} >+static inline uint32_t ReadLE32(uint32_t x) { >+ return x; >+} > static inline std::string ReadFourCC(uint32_t x) { > return std::string(reinterpret_cast<char*>(&x), 4); > } >@@ -131,11 +138,12 @@ static inline std::string ReadFourCC(uint32_t x) { > #endif > > static inline uint32_t RiffChunkSize(size_t bytes_in_payload) { >- return static_cast<uint32_t>( >- bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader)); >+ return static_cast<uint32_t>(bytes_in_payload + kWavHeaderSize - >+ sizeof(ChunkHeader)); > } > >-static inline uint32_t ByteRate(size_t num_channels, int sample_rate, >+static inline uint32_t ByteRate(size_t num_channels, >+ int sample_rate, > size_t bytes_per_sample) { > return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample); > } >@@ -166,8 +174,8 @@ void WriteWavHeader(uint8_t* buf, > WriteLE16(&header.fmt.AudioFormat, format); > WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels)); > WriteLE32(&header.fmt.SampleRate, sample_rate); >- WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate, >- bytes_per_sample)); >+ WriteLE32(&header.fmt.ByteRate, >+ ByteRate(num_channels, sample_rate, bytes_per_sample)); > WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample)); > WriteLE16(&header.fmt.BitsPerSample, > static_cast<uint16_t>(8 * bytes_per_sample)); >@@ -239,5 +247,4 @@ bool ReadWavHeader(ReadableWav* readable, > *bytes_per_sample, *num_samples); > } > >- > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.h >index 2295fbe6adc..872d3abce5c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header.h >@@ -26,8 +26,8 @@ class ReadableWav { > }; > > enum WavFormat { >- kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample >- kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law >+ kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample >+ kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law > kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header_unittest.cc >index c6f605f7298..b7169b53c8f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/wav_header_unittest.cc >@@ -8,6 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include <string.h> > #include <limits> > > #include "common_audio/wav_header.h" >@@ -31,13 +32,13 @@ class ReadableWavBuffer : public ReadableWav { > buf_exhausted_(false), > check_read_size_(check_read_size) {} > >- virtual ~ReadableWavBuffer() { >+ ~ReadableWavBuffer() override { > // Verify the entire buffer has been read. > if (check_read_size_) > EXPECT_EQ(size_, pos_); > } > >- virtual size_t Read(void* buf, size_t num_bytes) { >+ size_t Read(void* buf, size_t num_bytes) override { > // Verify we don't try to read outside of a properly sized header. > if (size_ >= kWavHeaderSize) > EXPECT_GE(size_, pos_ + num_bytes); >@@ -83,8 +84,8 @@ TEST(WavHeaderTest, CheckWavParameters) { > > // Too large values. > EXPECT_FALSE(CheckWavParameters(1 << 20, 1 << 20, kWavFormatPcm, 1, 0)); >- EXPECT_FALSE(CheckWavParameters( >- 1, 8000, kWavFormatPcm, 1, std::numeric_limits<uint32_t>::max())); >+ EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 1, >+ std::numeric_limits<uint32_t>::max())); > > // Not the same number of samples for each channel. > EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5)); >@@ -103,6 +104,8 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > // *BAD*. > { > static const uint8_t kBadRiffID[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'i', 'f', 'f', // *BAD* > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -116,14 +119,16 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 8, 0, // bits per sample: 1 * 8 > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID)); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kBadBitsPerSample[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -137,14 +142,16 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 1, 0, // bits per sample: *BAD* > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample)); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kBadByteRate[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -158,14 +165,16 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 8, 0, // bits per sample: 1 * 8 > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate)); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kBadFmtHeaderSize[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -180,14 +189,16 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 0, // extra (though invalid) header byte > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kNonZeroExtensionField[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -202,15 +213,17 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 1, 0, // non-zero extension field *BAD* > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField), > false); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kMissingDataChunk[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >@@ -222,23 +235,25 @@ TEST(WavHeaderTest, ReadWavHeaderWithErrors) { > 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 > 17, 0, // block align: NumChannels * BytesPerSample > 8, 0, // bits per sample: 1 * 8 >+ // clang-format on > }; > ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk)); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > { > static const uint8_t kMissingFmtAndDataChunks[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 > 'W', 'A', 'V', 'E', >+ // clang-format on > }; > ReadableWavBuffer r(kMissingFmtAndDataChunks, > sizeof(kMissingFmtAndDataChunks)); >- EXPECT_FALSE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > } > } > >@@ -249,6 +264,8 @@ TEST(WavHeaderTest, WriteAndReadWavHeader) { > memset(buf, 0xa4, sizeof(buf)); > WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689); > static const uint8_t kExpectedBuf[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header > 'R', 'I', 'F', 'F', > 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 >@@ -264,6 +281,7 @@ TEST(WavHeaderTest, WriteAndReadWavHeader) { > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 > 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header >+ // clang-format on > }; > static_assert(sizeof(kExpectedBuf) == kSize, "buffer size"); > EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize)); >@@ -274,9 +292,8 @@ TEST(WavHeaderTest, WriteAndReadWavHeader) { > size_t bytes_per_sample = 0; > size_t num_samples = 0; > ReadableWavBuffer r(buf + 4, sizeof(buf) - 8); >- EXPECT_TRUE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > EXPECT_EQ(17u, num_channels); > EXPECT_EQ(12345, sample_rate); > EXPECT_EQ(kWavFormatALaw, format); >@@ -287,6 +304,8 @@ TEST(WavHeaderTest, WriteAndReadWavHeader) { > // Try reading an atypical but valid WAV header and make sure it's parsed OK. > TEST(WavHeaderTest, ReadAtypicalWavHeader) { > static const uint8_t kBuf[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 'R', 'I', 'F', 'F', > 0x3d, 0xd1, 0x5b, 0x07, // size of whole file - 8 + an extra 128 bytes of > // "metadata": 123457689 + 44 - 8 + 128. (atypical) >@@ -302,6 +321,7 @@ TEST(WavHeaderTest, ReadAtypicalWavHeader) { > 0, 0, // zero extension size field (atypical) > 'd', 'a', 't', 'a', > 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 >+ // clang-format on > }; > > size_t num_channels = 0; >@@ -310,9 +330,8 @@ TEST(WavHeaderTest, ReadAtypicalWavHeader) { > size_t bytes_per_sample = 0; > size_t num_samples = 0; > ReadableWavBuffer r(kBuf, sizeof(kBuf)); >- EXPECT_TRUE( >- ReadWavHeader(&r, &num_channels, &sample_rate, &format, >- &bytes_per_sample, &num_samples)); >+ EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, >+ &bytes_per_sample, &num_samples)); > EXPECT_EQ(17u, num_channels); > EXPECT_EQ(12345, sample_rate); > EXPECT_EQ(kWavFormatALaw, format); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.cc >index 823d2b7387e..da5603d9e7a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.cc >@@ -25,12 +25,11 @@ namespace { > complex<float> I0(complex<float> x) { > complex<float> y = x / 3.75f; > y *= y; >- return 1.0f + y * ( >- 3.5156229f + y * ( >- 3.0899424f + y * ( >- 1.2067492f + y * ( >- 0.2659732f + y * ( >- 0.360768e-1f + y * 0.45813e-2f))))); >+ return 1.0f + y * (3.5156229f + >+ y * (3.0899424f + >+ y * (1.2067492f + >+ y * (0.2659732f + >+ y * (0.360768e-1f + y * 0.45813e-2f))))); > } > > } // namespace >@@ -41,12 +40,13 @@ void WindowGenerator::Hanning(int length, float* window) { > RTC_CHECK_GT(length, 1); > RTC_CHECK(window != nullptr); > for (int i = 0; i < length; ++i) { >- window[i] = 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i / >- (length - 1))); >+ window[i] = >+ 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i / (length - 1))); > } > } > >-void WindowGenerator::KaiserBesselDerived(float alpha, size_t length, >+void WindowGenerator::KaiserBesselDerived(float alpha, >+ size_t length, > float* window) { > RTC_CHECK_GT(length, 1U); > RTC_CHECK(window != nullptr); >@@ -69,4 +69,3 @@ void WindowGenerator::KaiserBesselDerived(float alpha, size_t length, > } > > } // namespace webrtc >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.h >index 5fc738eaf07..ad3b4456b9e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator.h >@@ -30,4 +30,3 @@ class WindowGenerator { > } // namespace webrtc > > #endif // COMMON_AUDIO_WINDOW_GENERATOR_H_ >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator_unittest.cc >index b2089d471aa..cf339327c6a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_audio/window_generator_unittest.cc >@@ -89,4 +89,3 @@ TEST(WindowGeneratorTest, Hanning) { > } > > } // namespace webrtc >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.cc >deleted file mode 100644 >index 07f77b77778..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.cc >+++ /dev/null >@@ -1,234 +0,0 @@ >-/* >- * 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 { >- >-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 const char* kPayloadNameStereo = "Stereo"; >- >-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; >- // Other codecs default to generic. >- case kVideoCodecStereo: >- case kVideoCodecFlexfec: >- case kVideoCodecGeneric: >- case kVideoCodecUnknown: >- return kPayloadNameGeneric; >- } >- 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; >- if (CodecNamesEq(name.c_str(), kPayloadNameStereo)) >- return kVideoCodecStereo; >- return kVideoCodecGeneric; >-} >- >-const uint32_t BitrateAllocation::kMaxBitrateBps = >- std::numeric_limits<uint32_t>::max(); >- >-BitrateAllocation::BitrateAllocation() : sum_(0), bitrates_{}, has_bitrate_{} {} >- >-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; >- has_bitrate_[spatial_index][temporal_index] = true; >- sum_ = static_cast<uint32_t>(new_bitrate_sum_bps); >- return true; >-} >- >-bool BitrateAllocation::HasBitrate(size_t spatial_index, >- size_t temporal_index) const { >- RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >- RTC_CHECK_LT(temporal_index, kMaxTemporalStreams); >- return has_bitrate_[spatial_index][temporal_index]; >-} >- >-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]; >-} >- >-// Whether the specific spatial layers has the bitrate set in any of its >-// temporal layers. >-bool BitrateAllocation::IsSpatialLayerUsed(size_t spatial_index) const { >- RTC_CHECK_LT(spatial_index, kMaxSpatialLayers); >- for (int i = 0; i < kMaxTemporalStreams; ++i) { >- if (has_bitrate_[spatial_index][i]) >- return true; >- } >- return false; >-} >- >-// 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 >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.h >index 9f1ad8f9f79..c9eeee434e6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_types.h >@@ -13,15 +13,14 @@ > > #include <stddef.h> > #include <string.h> >-#include <ostream> > #include <string> > #include <vector> > > #include "api/array_view.h" >-#include "api/optional.h" >+// TODO(sprang): Remove this include when all usage includes it directly. >+#include "api/video/video_bitrate_allocation.h" > #include "rtc_base/checks.h" > #include "rtc_base/deprecation.h" >-#include "typedefs.h" // NOLINT(build/include) > > #if defined(_MSC_VER) > // Disable "new behavior: elements of array will be default initialized" >@@ -29,18 +28,6 @@ > #pragma warning(disable : 4351) > #endif > >-#if defined(WEBRTC_EXPORT) >-#define WEBRTC_DLLEXPORT _declspec(dllexport) >-#elif defined(WEBRTC_DLL) >-#define WEBRTC_DLLEXPORT _declspec(dllimport) >-#else >-#define WEBRTC_DLLEXPORT >-#endif >- >-#ifndef NULL >-#define NULL 0 >-#endif >- > #define RTP_PAYLOAD_NAME_SIZE 32u > > #if defined(WEBRTC_WIN) || defined(WIN32) >@@ -55,34 +42,6 @@ > > namespace webrtc { > >-class RewindableStream { >- public: >- virtual ~RewindableStream() {} >- virtual int Rewind() = 0; >-}; >- >-class InStream : public RewindableStream { >- public: >- // Reads |len| bytes from file to |buf|. Returns the number of bytes read >- // or -1 on error. >- virtual int Read(void* buf, size_t len) = 0; >-}; >- >-class OutStream : public RewindableStream { >- public: >- // Writes |len| bytes from |buf| to file. The actual writing may happen >- // some time later. Call Flush() to force a write. >- virtual bool Write(const void* buf, size_t len) = 0; >-}; >- >-// For the deprecated MediaFile module. >-enum FileFormats { >- kFileFormatWavFile = 1, >- kFileFormatPcm16kHzFile = 7, >- kFileFormatPcm8kHzFile = 8, >- kFileFormatPcm32kHzFile = 9, >-}; >- > enum FrameType { > kEmptyFrame = 0, > kAudioFrameSpeech = 1, >@@ -100,14 +59,8 @@ struct RtcpStatistics { > jitter(0) {} > > uint8_t fraction_lost; >- union { >- int32_t packets_lost; // Defined as a 24 bit signed integer in RTCP >- RTC_DEPRECATED uint32_t cumulative_lost; >- }; >- union { >- uint32_t extended_highest_sequence_number; >- RTC_DEPRECATED uint32_t extended_max_sequence_number; >- }; >+ int32_t packets_lost; // Defined as a 24 bit signed integer in RTCP >+ uint32_t extended_highest_sequence_number; > uint32_t jitter; > }; > >@@ -186,14 +139,6 @@ class RtcpPacketTypeCounterObserver { > const RtcpPacketTypeCounter& packet_counter) = 0; > }; > >-// Rate statistics for a stream. >-struct BitrateStatistics { >- BitrateStatistics() : bitrate_bps(0), packet_rate(0) {} >- >- uint32_t bitrate_bps; // Bitrate in bits per second. >- uint32_t packet_rate; // Packet rate in packets per second. >-}; >- > // Callback, used to notify an observer whenever new rates have been estimated. > class BitrateStatisticsObserver { > public: >@@ -268,35 +213,11 @@ struct CodecInst { > } > > bool operator!=(const CodecInst& other) const { return !(*this == other); } >- >- friend std::ostream& operator<<(std::ostream& os, const CodecInst& ci) { >- os << "{pltype: " << ci.pltype; >- os << ", plname: " << ci.plname; >- os << ", plfreq: " << ci.plfreq; >- os << ", pacsize: " << ci.pacsize; >- os << ", channels: " << ci.channels; >- os << ", rate: " << ci.rate << "}"; >- return os; >- } > }; > > // RTP > enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 > >-enum PayloadFrequencies { >- kFreq8000Hz = 8000, >- kFreq16000Hz = 16000, >- kFreq32000Hz = 32000 >-}; >- >-// Degree of bandwidth reduction. >-enum VadModes { >- kVadConventional = 0, // lowest reduction >- kVadAggressiveLow, >- kVadAggressiveMid, >- kVadAggressiveHigh // highest reduction >-}; >- > // NETEQ statistics. > struct NetworkStatistics { > // current jitter buffer size in ms >@@ -367,7 +288,7 @@ struct AudioDecodingCallStats { > int decoded_normal; // Number of calls where audio RTP packet decoded. > int decoded_plc; // Number of calls resulted in PLC. > int decoded_cng; // Number of calls where comfort noise generated due to DTX. >- int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG. >+ int decoded_plc_cng; // Number of calls resulted where PLC faded to CNG. > int decoded_muted_output; // Number of calls returning a muted state output. > }; > >@@ -396,60 +317,6 @@ enum class VideoType { > kBGRA, > }; > >-// Video codec >-enum { kPayloadNameSize = 32 }; >-enum { kMaxSimulcastStreams = 4 }; >-enum { kMaxSpatialLayers = 5 }; >-enum { kMaxTemporalStreams = 4 }; >- >-enum VideoCodecComplexity { >- kComplexityNormal = 0, >- kComplexityHigh = 1, >- kComplexityHigher = 2, >- kComplexityMax = 3 >-}; >- >-enum VP8ResilienceMode { >- kResilienceOff, // The stream produced by the encoder requires a >- // recovery frame (typically a key frame) to be >- // decodable after a packet loss. >- kResilientStream, // A stream produced by the encoder is resilient to >- // packet losses, but packets within a frame subsequent >- // to a loss can't be decoded. >- kResilientFrames // Same as kResilientStream but with added resilience >- // within a frame. >-}; >- >-class TemporalLayersFactory; >-// VP8 specific >-struct VideoCodecVP8 { >- // TODO(nisse): Unused, delete? >- bool pictureLossIndicationOn; >- VideoCodecComplexity complexity; >- VP8ResilienceMode resilience; >- unsigned char numberOfTemporalLayers; >- bool denoisingOn; >- bool errorConcealmentOn; >- bool automaticResizeOn; >- bool frameDroppingOn; >- int keyFrameInterval; >- TemporalLayersFactory* tl_factory; >-}; >- >-// VP9 specific. >-struct VideoCodecVP9 { >- VideoCodecComplexity complexity; >- bool resilienceOn; >- unsigned char numberOfTemporalLayers; >- bool denoisingOn; >- bool frameDroppingOn; >- int keyFrameInterval; >- bool adaptiveQpMode; >- bool automaticResizeOn; >- unsigned char numberOfSpatialLayers; >- bool flexibleMode; >-}; >- > // TODO(magjed): Move this and other H264 related classes out to their own file. > namespace H264 { > >@@ -463,45 +330,35 @@ enum Profile { > > } // namespace H264 > >-// H264 specific. >-struct VideoCodecH264 { >- bool frameDroppingOn; >- int keyFrameInterval; >- // These are NULL/0 if not externally negotiated. >- const uint8_t* spsData; >- size_t spsLen; >- const uint8_t* ppsData; >- size_t ppsLen; >- H264::Profile profile; >-}; >- > // Video codec types > enum VideoCodecType { >+ // There are various memset(..., 0, ...) calls in the code that rely on >+ // kVideoCodecGeneric being zero. >+ kVideoCodecGeneric = 0, > kVideoCodecVP8, > kVideoCodecVP9, > kVideoCodecH264, > kVideoCodecI420, >- kVideoCodecRED, >- kVideoCodecULPFEC, >- kVideoCodecFlexfec, >- kVideoCodecGeneric, >- kVideoCodecStereo, >- kVideoCodecUnknown >+ kVideoCodecMultiplex, >+ // DEPRECATED. Do not use. >+ kVideoCodecUnknown, >+ >+ // TODO(nisse): Deprecated aliases, for code expecting RtpVideoCodecTypes. >+ kRtpVideoNone = kVideoCodecGeneric, >+ kRtpVideoGeneric = kVideoCodecGeneric, >+ kRtpVideoVp8 = kVideoCodecVP8, >+ kRtpVideoVp9 = kVideoCodecVP9, >+ kRtpVideoH264 = kVideoCodecH264, > }; > > // Translates from name of codec to codec type and vice versa. > const char* CodecTypeToPayloadString(VideoCodecType type); > VideoCodecType PayloadStringToCodecType(const std::string& name); > >-union VideoCodecUnion { >- VideoCodecVP8 VP8; >- VideoCodecVP9 VP9; >- VideoCodecH264 H264; >-}; >+struct SpatialLayer { >+ bool operator==(const SpatialLayer& other) const; >+ bool operator!=(const SpatialLayer& other) const { return !(*this == other); } > >-// Simulcast is when the same stream is encoded multiple times with different >-// settings such as resolution. >-struct SimulcastStream { > unsigned short width; > unsigned short height; > unsigned char numberOfTemporalLayers; >@@ -509,117 +366,15 @@ struct SimulcastStream { > unsigned int targetBitrate; // kilobits/sec. > unsigned int minBitrate; // kilobits/sec. > unsigned int qpMax; // minimum quality >+ bool active; // encoded and sent. > }; > >-struct SpatialLayer { >- int scaling_factor_num; >- int scaling_factor_den; >- int target_bitrate_bps; >- // TODO(ivica): Add max_quantizer and min_quantizer? >-}; >- >-enum VideoCodecMode { kRealtimeVideo, kScreensharing }; >- >-// Common video codec properties >-class VideoCodec { >- public: >- VideoCodec(); >- >- // Public variables. TODO(hta): Make them private with accessors. >- VideoCodecType codecType; >- char plName[kPayloadNameSize]; >- unsigned char plType; >- >- unsigned short width; >- unsigned short height; >- >- unsigned int startBitrate; // kilobits/sec. >- unsigned int maxBitrate; // kilobits/sec. >- unsigned int minBitrate; // kilobits/sec. >- unsigned int targetBitrate; // kilobits/sec. >- >- uint32_t maxFramerate; >- >- unsigned int qpMax; >- unsigned char numberOfSimulcastStreams; >- SimulcastStream simulcastStream[kMaxSimulcastStreams]; >- SpatialLayer spatialLayers[kMaxSpatialLayers]; >- >- VideoCodecMode mode; >- bool expect_encode_from_texture; >- >- // Timing frames configuration. There is delay of delay_ms between two >- // consequent timing frames, excluding outliers. Frame is always made a >- // timing frame if it's at least outlier_ratio in percent of "ideal" average >- // frame given bitrate and framerate, i.e. if it's bigger than >- // |outlier_ratio / 100.0 * bitrate_bps / fps| in bits. This way, timing >- // frames will not be sent too often usually. Yet large frames will always >- // have timing information for debug purposes because they are more likely to >- // cause extra delays. >- struct TimingFrameTriggerThresholds { >- int64_t delay_ms; >- uint16_t outlier_ratio_percent; >- } timing_frame_thresholds; >- >- bool operator==(const VideoCodec& other) const = delete; >- bool operator!=(const VideoCodec& other) const = delete; >- >- // Accessors for codec specific information. >- // There is a const version of each that returns a reference, >- // and a non-const version that returns a pointer, in order >- // to allow modification of the parameters. >- VideoCodecVP8* VP8(); >- const VideoCodecVP8& VP8() const; >- VideoCodecVP9* VP9(); >- const VideoCodecVP9& VP9() const; >- VideoCodecH264* H264(); >- const VideoCodecH264& H264() const; >- >- private: >- // TODO(hta): Consider replacing the union with a pointer type. >- // This will allow removing the VideoCodec* types from this file. >- VideoCodecUnion codec_specific_; >-}; >- >-class BitrateAllocation { >- public: >- static const uint32_t kMaxBitrateBps; >- BitrateAllocation(); >- >- bool SetBitrate(size_t spatial_index, >- size_t temporal_index, >- uint32_t bitrate_bps); >- >- bool HasBitrate(size_t spatial_index, size_t temporal_index) const; >- >- uint32_t GetBitrate(size_t spatial_index, size_t temporal_index) const; >- >- // Whether the specific spatial layers has the bitrate set in any of its >- // temporal layers. >- bool IsSpatialLayerUsed(size_t spatial_index) const; >- >- // Get the sum of all the temporal layer for a specific spatial layer. >- uint32_t GetSpatialLayerSum(size_t spatial_index) const; >- >- uint32_t get_sum_bps() const { return sum_; } // Sum of all bitrates. >- uint32_t get_sum_kbps() const { return (sum_ + 500) / 1000; } >- >- inline bool operator==(const BitrateAllocation& other) const { >- return memcmp(bitrates_, other.bitrates_, sizeof(bitrates_)) == 0; >- } >- inline bool operator!=(const BitrateAllocation& other) const { >- return !(*this == other); >- } >- >- // Expensive, please use only in tests. >- std::string ToString() const; >- std::ostream& operator<<(std::ostream& os) const; >+// Simulcast is when the same stream is encoded multiple times with different >+// settings such as resolution. >+typedef SpatialLayer SimulcastStream; > >- private: >- uint32_t sum_; >- uint32_t bitrates_[kMaxSpatialLayers][kMaxTemporalStreams]; >- bool has_bitrate_[kMaxSpatialLayers][kMaxTemporalStreams]; >-}; >+// TODO(sprang): Remove this when downstream projects have been updated. >+using BitrateAllocation = VideoBitrateAllocation; > > // Bandwidth over-use detector options. These are used to drive > // experimentation with bandwidth estimation parameters. >@@ -649,6 +404,9 @@ struct OverUseDetectorOptions { > double initial_var_noise; > }; > >+// TODO(nisse): This struct is phased out, delete as soon as down stream code is >+// updated. >+ > // This structure will have the information about when packet is actually > // received by socket. > struct PacketTime { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/BUILD.gn >index 1c298fdba09..5bc4eb4ad38 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/BUILD.gn >@@ -8,10 +8,6 @@ > > import("../webrtc.gni") > >-config("common_video_config") { >- include_dirs = [ "include" ] >-} >- > rtc_static_library("common_video") { > visibility = [ "*" ] > >@@ -45,28 +41,19 @@ rtc_static_library("common_video") { > "video_render_frames.h", > ] > >- include_dirs = [ "../modules/interface" ] >- >- public_configs = [ ":common_video_config" ] >- >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > deps = [ > "..:webrtc_common", >- "../:typedefs", >- "../api:libjingle_peerconnection_api", >- "../api:optional", >- "../api:video_frame_api", >- "../api:video_frame_api_i420", >+ "../api/video:video_bitrate_allocation", >+ "../api/video:video_bitrate_allocator", >+ "../api/video:video_frame", >+ "../api/video:video_frame_i420", > "../media:rtc_h264_profile_id", > "../modules:module_api", > "../rtc_base:checks", > "../rtc_base:rtc_base", > "../rtc_base:rtc_task_queue", >- "../system_wrappers", >+ "../rtc_base:safe_minmax", >+ "//third_party/abseil-cpp/absl/types:optional", > "//third_party/libyuv", > ] > } >@@ -95,29 +82,22 @@ if (rtc_include_tests) { > "h264/sps_parser_unittest.cc", > "h264/sps_vui_rewriter_unittest.cc", > "i420_buffer_pool_unittest.cc", >- "i420_video_frame_unittest.cc", > "libyuv/libyuv_unittest.cc", >+ "video_frame_unittest.cc", > ] > >- # TODO(jschuh): Bug 1348: fix this warning. >- configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] >- >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >- > deps = [ > ":common_video", >- "../api:video_frame_api", >- "../api:video_frame_api_i420", >+ "../api/video:video_frame", >+ "../api/video:video_frame_i010", >+ "../api/video:video_frame_i420", > "../modules/video_capture:video_capture", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >- "../system_wrappers:system_wrappers", >+ "../rtc_base:rtc_base_tests_utils", >+ "../test:fileutils", > "../test:test_main", > "../test:video_test_common", >- "//testing/gmock", > "//testing/gtest", > "//third_party/libyuv", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster.cc >index 0d3458c6c84..163c4b19814 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster.cc >@@ -15,7 +15,7 @@ > > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" >-#include "system_wrappers/include/clock.h" >+#include "rtc_base/timeutils.h" > > namespace webrtc { > >@@ -30,11 +30,9 @@ const float BitrateAdjuster::kBitrateTolerancePct = .1f; > > const float BitrateAdjuster::kBytesPerMsToBitsPerSecond = 8 * 1000; > >-BitrateAdjuster::BitrateAdjuster(Clock* clock, >- float min_adjusted_bitrate_pct, >+BitrateAdjuster::BitrateAdjuster(float min_adjusted_bitrate_pct, > float max_adjusted_bitrate_pct) >- : clock_(clock), >- min_adjusted_bitrate_pct_(min_adjusted_bitrate_pct), >+ : min_adjusted_bitrate_pct_(min_adjusted_bitrate_pct), > max_adjusted_bitrate_pct_(max_adjusted_bitrate_pct), > bitrate_tracker_(1.5 * kBitrateUpdateIntervalMs, > kBytesPerMsToBitsPerSecond) { >@@ -70,14 +68,14 @@ uint32_t BitrateAdjuster::GetAdjustedBitrateBps() const { > return adjusted_bitrate_bps_; > } > >-rtc::Optional<uint32_t> BitrateAdjuster::GetEstimatedBitrateBps() { >+absl::optional<uint32_t> BitrateAdjuster::GetEstimatedBitrateBps() { > rtc::CritScope cs(&crit_); >- return bitrate_tracker_.Rate(clock_->TimeInMilliseconds()); >+ return bitrate_tracker_.Rate(rtc::TimeMillis()); > } > > void BitrateAdjuster::Update(size_t frame_size) { > rtc::CritScope cs(&crit_); >- uint32_t current_time_ms = clock_->TimeInMilliseconds(); >+ uint32_t current_time_ms = rtc::TimeMillis(); > bitrate_tracker_.Update(frame_size, current_time_ms); > UpdateBitrate(current_time_ms); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster_unittest.cc >index b75f184cf2d..6e8d3fb856d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/bitrate_adjuster_unittest.cc >@@ -9,7 +9,7 @@ > */ > > #include "common_video/include/bitrate_adjuster.h" >-#include "system_wrappers/include/clock.h" >+#include "rtc_base/fakeclock.h" > #include "test/gtest.h" > > namespace webrtc { >@@ -17,8 +17,7 @@ namespace webrtc { > class BitrateAdjusterTest : public ::testing::Test { > public: > BitrateAdjusterTest() >- : clock_(0), >- adjuster_(&clock_, kMinAdjustedBitratePct, kMaxAdjustedBitratePct) {} >+ : adjuster_(kMinAdjustedBitratePct, kMaxAdjustedBitratePct) {} > > // Simulate an output bitrate for one update cycle of BitrateAdjuster. > void SimulateBitrateBps(uint32_t bitrate_bps) { >@@ -33,7 +32,7 @@ class BitrateAdjusterTest : public ::testing::Test { > const size_t frame_size_bytes = > (bitrate_bps * frame_interval_ms) / (8 * 1000); > for (size_t i = 0; i < update_frame_interval; ++i) { >- clock_.AdvanceTimeMilliseconds(frame_interval_ms); >+ clock_.AdvanceTime(webrtc::TimeDelta::ms(frame_interval_ms)); > adjuster_.Update(frame_size_bytes); > } > } >@@ -63,7 +62,7 @@ class BitrateAdjusterTest : public ::testing::Test { > protected: > static const float kMinAdjustedBitratePct; > static const float kMaxAdjustedBitratePct; >- SimulatedClock clock_; >+ rtc::ScopedFakeClock clock_; > BitrateAdjuster adjuster_; > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.cc >index 439beecec29..d8f8a62378c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.cc >@@ -22,7 +22,7 @@ namespace { > const int kMaxAbsQpDeltaValue = 51; > const int kMinQpValue = 0; > const int kMaxQpValue = 51; >-} >+} // namespace > > namespace webrtc { > >@@ -44,7 +44,7 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu( > if (!sps_ || !pps_) > return kInvalidStream; > >- last_slice_qp_delta_ = rtc::nullopt; >+ last_slice_qp_delta_ = absl::nullopt; > const std::vector<uint8_t> slice_rbsp = > H264::ParseRbsp(source, source_length); > if (slice_rbsp.size() < H264::kNaluTypeSize) >@@ -247,8 +247,8 @@ H264BitstreamParser::Result H264BitstreamParser::ParseNonParameterSetNalu( > } > } > } >- if (pps_->entropy_coding_mode_flag && >- slice_type != H264::SliceType::kI && slice_type != H264::SliceType::kSi) { >+ if (pps_->entropy_coding_mode_flag && slice_type != H264::SliceType::kI && >+ slice_type != H264::SliceType::kSi) { > // cabac_init_idc: ue(v) > RETURN_INV_ON_FAIL(slice_reader.ReadExponentialGolomb(&golomb_tmp)); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.h >index 4ef6b40b440..b3fac7bb215 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser.h >@@ -13,7 +13,7 @@ > #include <stddef.h> > #include <stdint.h> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "common_video/h264/pps_parser.h" > #include "common_video/h264/sps_parser.h" > >@@ -53,11 +53,11 @@ class H264BitstreamParser { > uint8_t nalu_type); > > // SPS/PPS state, updated when parsing new SPS/PPS, used to parse slices. >- rtc::Optional<SpsParser::SpsState> sps_; >- rtc::Optional<PpsParser::PpsState> pps_; >+ absl::optional<SpsParser::SpsState> sps_; >+ absl::optional<PpsParser::PpsState> pps_; > > // Last parsed slice QP. >- rtc::Optional<int32_t> last_slice_qp_delta_; >+ absl::optional<int32_t> last_slice_qp_delta_; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser_unittest.cc >index 3bfbdb27042..1509d677535 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/h264_bitstream_parser_unittest.cc >@@ -28,9 +28,9 @@ uint8_t kH264BitstreamChunk[] = { > }; > > uint8_t kH264BitstreamChunkCabac[] = { >- 0x00, 0x00, 0x00, 0x01, 0x27, 0x64, 0x00, 0x0d, 0xac, 0x52, 0x30, 0x50, >- 0x7e, 0xc0, 0x5a, 0x81, 0x01, 0x01, 0x18, 0x56, 0xbd, 0xef, 0x80, 0x80, >- 0x00, 0x00, 0x00, 0x01, 0x28, 0xfe, 0x09, 0x8b, >+ 0x00, 0x00, 0x00, 0x01, 0x27, 0x64, 0x00, 0x0d, 0xac, 0x52, 0x30, >+ 0x50, 0x7e, 0xc0, 0x5a, 0x81, 0x01, 0x01, 0x18, 0x56, 0xbd, 0xef, >+ 0x80, 0x80, 0x00, 0x00, 0x00, 0x01, 0x28, 0xfe, 0x09, 0x8b, > }; > > // Contains enough of the image slice to contain slice QP. >@@ -40,8 +40,8 @@ uint8_t kH264BitstreamNextImageSliceChunk[] = { > > // Contains enough of the image slice to contain slice QP. > uint8_t kH264BitstreamNextImageSliceChunkCabac[] = { >- 0x00, 0x00, 0x00, 0x01, 0x21, 0xe1, 0x05, 0x11, 0x3f, 0x9a, 0xae, 0x46, >- 0x70, 0xbf, 0xc1, 0x4a, 0x16, 0x8f, 0x51, 0xf4, 0xca, 0xfb, 0xa3, 0x65, >+ 0x00, 0x00, 0x00, 0x01, 0x21, 0xe1, 0x05, 0x11, 0x3f, 0x9a, 0xae, 0x46, >+ 0x70, 0xbf, 0xc1, 0x4a, 0x16, 0x8f, 0x51, 0xf4, 0xca, 0xfb, 0xa3, 0x65, > }; > > TEST(H264BitstreamParserTest, ReportsNoQpWithoutParsedSlices) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.cc >index 407b15c7227..5bc29f35925 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.cc >@@ -19,13 +19,13 @@ > > #define RETURN_EMPTY_ON_FAIL(x) \ > if (!(x)) { \ >- return rtc::nullopt; \ >+ return absl::nullopt; \ > } > > namespace { > const int kMaxPicInitQpDeltaValue = 25; > const int kMinPicInitQpDeltaValue = -26; >-} >+} // namespace > > namespace webrtc { > >@@ -33,8 +33,8 @@ namespace webrtc { > // You can find it on this page: > // http://www.itu.int/rec/T-REC-H.264 > >-rtc::Optional<PpsParser::PpsState> PpsParser::ParsePps(const uint8_t* data, >- size_t length) { >+absl::optional<PpsParser::PpsState> PpsParser::ParsePps(const uint8_t* data, >+ size_t length) { > // First, parse out rbsp, which is basically the source buffer minus emulation > // bytes (the last byte of a 0x00 0x00 0x03 sequence). RBSP is defined in > // section 7.3.1 of the H.264 standard. >@@ -57,26 +57,26 @@ bool PpsParser::ParsePpsIds(const uint8_t* data, > return ParsePpsIdsInternal(&bit_buffer, pps_id, sps_id); > } > >-rtc::Optional<uint32_t> PpsParser::ParsePpsIdFromSlice(const uint8_t* data, >- size_t length) { >+absl::optional<uint32_t> PpsParser::ParsePpsIdFromSlice(const uint8_t* data, >+ size_t length) { > std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length); > rtc::BitBuffer slice_reader(unpacked_buffer.data(), unpacked_buffer.size()); > > uint32_t golomb_tmp; > // first_mb_in_slice: ue(v) > if (!slice_reader.ReadExponentialGolomb(&golomb_tmp)) >- return rtc::nullopt; >+ return absl::nullopt; > // slice_type: ue(v) > if (!slice_reader.ReadExponentialGolomb(&golomb_tmp)) >- return rtc::nullopt; >+ return absl::nullopt; > // pic_parameter_set_id: ue(v) > uint32_t slice_pps_id; > if (!slice_reader.ReadExponentialGolomb(&slice_pps_id)) >- return rtc::nullopt; >+ return absl::nullopt; > return slice_pps_id; > } > >-rtc::Optional<PpsParser::PpsState> PpsParser::ParseInternal( >+absl::optional<PpsParser::PpsState> PpsParser::ParseInternal( > rtc::BitBuffer* bit_buffer) { > PpsState pps; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.h >index 571af9773a0..d6c31b06887 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser.h >@@ -11,7 +11,7 @@ > #ifndef COMMON_VIDEO_H264_PPS_PARSER_H_ > #define COMMON_VIDEO_H264_PPS_PARSER_H_ > >-#include "api/optional.h" >+#include "absl/types/optional.h" > > namespace rtc { > class BitBuffer; >@@ -38,20 +38,20 @@ class PpsParser { > }; > > // Unpack RBSP and parse PPS state from the supplied buffer. >- static rtc::Optional<PpsState> ParsePps(const uint8_t* data, size_t length); >+ static absl::optional<PpsState> ParsePps(const uint8_t* data, size_t length); > > static bool ParsePpsIds(const uint8_t* data, > size_t length, > uint32_t* pps_id, > uint32_t* sps_id); > >- static rtc::Optional<uint32_t> ParsePpsIdFromSlice(const uint8_t* data, >- size_t length); >+ static absl::optional<uint32_t> ParsePpsIdFromSlice(const uint8_t* data, >+ size_t length); > > protected: > // Parse the PPS state, for a bit buffer where RBSP decoding has already been > // performed. >- static rtc::Optional<PpsState> ParseInternal(rtc::BitBuffer* bit_buffer); >+ static absl::optional<PpsState> ParseInternal(rtc::BitBuffer* bit_buffer); > static bool ParsePpsIdsInternal(rtc::BitBuffer* bit_buffer, > uint32_t* pps_id, > uint32_t* sps_id); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser_unittest.cc >index 14a425f6c4e..bfafecfc654 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/pps_parser_unittest.cc >@@ -140,7 +140,7 @@ void WritePps(const PpsParser::PpsState& pps, > class PpsParserTest : public ::testing::Test { > public: > PpsParserTest() {} >- virtual ~PpsParserTest() {} >+ ~PpsParserTest() override {} > > void RunTest() { > VerifyParsing(generated_pps_, 0, 1, 0); >@@ -192,7 +192,7 @@ class PpsParserTest : public ::testing::Test { > > PpsParser::PpsState generated_pps_; > rtc::Buffer buffer_; >- rtc::Optional<PpsParser::PpsState> parsed_pps_; >+ absl::optional<PpsParser::PpsState> parsed_pps_; > }; > > TEST_F(PpsParserTest, ZeroPps) { >@@ -215,7 +215,7 @@ TEST_F(PpsParserTest, MaxPps) { > } > > TEST_F(PpsParserTest, PpsIdFromSlice) { >- rtc::Optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice( >+ absl::optional<uint32_t> pps_id = PpsParser::ParsePpsIdFromSlice( > kH264BitstreamChunk, sizeof(kH264BitstreamChunk)); > ASSERT_TRUE(pps_id); > EXPECT_EQ(2u, *pps_id); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/profile_level_id_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/profile_level_id_unittest.cc >index d7b7cfb3518..66ad300131e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/profile_level_id_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/profile_level_id_unittest.cc >@@ -125,7 +125,7 @@ TEST(H264ProfileLevelId, TestToStringInvalid) { > } > > TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) { >- const rtc::Optional<ProfileLevelId> profile_level_id = >+ const absl::optional<ProfileLevelId> profile_level_id = > ParseSdpProfileLevelId(CodecParameterMap()); > EXPECT_TRUE(profile_level_id); > EXPECT_EQ(kProfileConstrainedBaseline, profile_level_id->profile); >@@ -135,7 +135,7 @@ TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdEmpty) { > TEST(H264ProfileLevelId, TestParseSdpProfileLevelIdConstrainedHigh) { > CodecParameterMap params; > params["profile-level-id"] = "640c2a"; >- const rtc::Optional<ProfileLevelId> profile_level_id = >+ const absl::optional<ProfileLevelId> profile_level_id = > ParseSdpProfileLevelId(params); > EXPECT_TRUE(profile_level_id); > EXPECT_EQ(kProfileConstrainedHigh, profile_level_id->profile); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.cc >index 2ee7391f8c4..ce12834fe1e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.cc >@@ -18,7 +18,7 @@ > #include "rtc_base/logging.h" > > namespace { >-typedef rtc::Optional<webrtc::SpsParser::SpsState> OptionalSps; >+typedef absl::optional<webrtc::SpsParser::SpsState> OptionalSps; > > #define RETURN_EMPTY_ON_FAIL(x) \ > if (!(x)) { \ >@@ -31,19 +31,23 @@ constexpr int kScaldingDeltaMax = 127; > > namespace webrtc { > >+SpsParser::SpsState::SpsState() = default; >+SpsParser::SpsState::SpsState(const SpsState&) = default; >+SpsParser::SpsState::~SpsState() = default; >+ > // General note: this is based off the 02/2014 version of the H.264 standard. > // You can find it on this page: > // http://www.itu.int/rec/T-REC-H.264 > > // Unpack RBSP and parse SPS state from the supplied buffer. >-rtc::Optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data, >- size_t length) { >+absl::optional<SpsParser::SpsState> SpsParser::ParseSps(const uint8_t* data, >+ size_t length) { > std::vector<uint8_t> unpacked_buffer = H264::ParseRbsp(data, length); > rtc::BitBuffer bit_buffer(unpacked_buffer.data(), unpacked_buffer.size()); > return ParseSpsUpToVui(&bit_buffer); > } > >-rtc::Optional<SpsParser::SpsState> SpsParser::ParseSpsUpToVui( >+absl::optional<SpsParser::SpsState> SpsParser::ParseSpsUpToVui( > rtc::BitBuffer* buffer) { > // Now, we need to use a bit buffer to parse through the actual AVC SPS > // format. See Section 7.3.2.1.1 ("Sequence parameter set data syntax") of the >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.h >index 0ccc481356d..386d4689369 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser.h >@@ -11,7 +11,7 @@ > #ifndef COMMON_VIDEO_H264_SPS_PARSER_H_ > #define COMMON_VIDEO_H264_SPS_PARSER_H_ > >-#include "api/optional.h" >+#include "absl/types/optional.h" > > namespace rtc { > class BitBuffer; >@@ -25,7 +25,9 @@ class SpsParser { > // The parsed state of the SPS. Only some select values are stored. > // Add more as they are actually needed. > struct SpsState { >- SpsState() = default; >+ SpsState(); >+ SpsState(const SpsState&); >+ ~SpsState(); > > uint32_t width = 0; > uint32_t height = 0; >@@ -41,12 +43,12 @@ class SpsParser { > }; > > // Unpack RBSP and parse SPS state from the supplied buffer. >- static rtc::Optional<SpsState> ParseSps(const uint8_t* data, size_t length); >+ static absl::optional<SpsState> ParseSps(const uint8_t* data, size_t length); > > protected: > // Parse the SPS state, up till the VUI part, for a bit buffer where RBSP > // decoding has already been performed. >- static rtc::Optional<SpsState> ParseSpsUpToVui(rtc::BitBuffer* buffer); >+ static absl::optional<SpsState> ParseSpsUpToVui(rtc::BitBuffer* buffer); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser_unittest.cc >index 6856c1bbf2a..e88d0c31191 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_parser_unittest.cc >@@ -110,9 +110,9 @@ void GenerateFakeSps(uint16_t width, > class H264SpsParserTest : public ::testing::Test { > public: > H264SpsParserTest() {} >- virtual ~H264SpsParserTest() {} >+ ~H264SpsParserTest() override {} > >- rtc::Optional<SpsParser::SpsState> sps_; >+ absl::optional<SpsParser::SpsState> sps_; > }; > > TEST_F(H264SpsParserTest, TestSampleSPSHdLandscape) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.cc >index c346865090e..749b62e6d21 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.cc >@@ -72,13 +72,13 @@ bool CopyRemainingBits(rtc::BitBuffer* source, > SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps( > const uint8_t* buffer, > size_t length, >- rtc::Optional<SpsParser::SpsState>* sps, >+ absl::optional<SpsParser::SpsState>* sps, > rtc::Buffer* destination) { > // Create temporary RBSP decoded buffer of the payload (exlcuding the > // leading nalu type header byte (the SpsParser uses only the payload). > std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer, length); > rtc::BitBuffer source_buffer(rbsp_buffer.data(), rbsp_buffer.size()); >- rtc::Optional<SpsParser::SpsState> sps_state = >+ absl::optional<SpsParser::SpsState> sps_state = > SpsParser::ParseSpsUpToVui(&source_buffer); > if (!sps_state) > return ParseResult::kFailure; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.h >index f639c0d8931..233051d2d61 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter.h >@@ -12,7 +12,7 @@ > #ifndef COMMON_VIDEO_H264_SPS_VUI_REWRITER_H_ > #define COMMON_VIDEO_H264_SPS_VUI_REWRITER_H_ > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "common_video/h264/sps_parser.h" > #include "rtc_base/buffer.h" > >@@ -43,10 +43,11 @@ class SpsVuiRewriter : private SpsParser { > // SPS state. This function assumes that any previous headers > // (NALU start, type, Stap-A, etc) have already been parsed and that RBSP > // decoding has been performed. >- static ParseResult ParseAndRewriteSps(const uint8_t* buffer, >- size_t length, >- rtc::Optional<SpsParser::SpsState>* sps, >- rtc::Buffer* destination); >+ static ParseResult ParseAndRewriteSps( >+ const uint8_t* buffer, >+ size_t length, >+ absl::optional<SpsParser::SpsState>* sps, >+ rtc::Buffer* destination); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter_unittest.cc >index 0de5d3372dc..9464de80771 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/h264/sps_vui_rewriter_unittest.cc >@@ -159,7 +159,7 @@ void TestSps(SpsMode mode, SpsVuiRewriter::ParseResult expected_parse_result) { > index.payload_start_offset += H264::kNaluTypeSize; > index.payload_size -= H264::kNaluTypeSize; > >- rtc::Optional<SpsParser::SpsState> sps; >+ absl::optional<SpsParser::SpsState> sps; > rtc::Buffer out_buffer; > SpsVuiRewriter::ParseResult result = > SpsVuiRewriter::ParseAndRewriteSps(&buffer[index.payload_start_offset], >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_buffer_pool.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_buffer_pool.cc >index 48d6512971d..c403eeb4fcb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_buffer_pool.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_buffer_pool.cc >@@ -14,10 +14,14 @@ > > namespace webrtc { > >+I420BufferPool::I420BufferPool() : I420BufferPool(false) {} >+I420BufferPool::I420BufferPool(bool zero_initialize) >+ : I420BufferPool(zero_initialize, std::numeric_limits<size_t>::max()) {} > I420BufferPool::I420BufferPool(bool zero_initialize, > size_t max_number_of_buffers) > : zero_initialize_(zero_initialize), > max_number_of_buffers_(max_number_of_buffers) {} >+I420BufferPool::~I420BufferPool() = default; > > void I420BufferPool::Release() { > buffers_.clear(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_video_frame_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_video_frame_unittest.cc >deleted file mode 100644 >index 7004d9dab14..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/i420_video_frame_unittest.cc >+++ /dev/null >@@ -1,298 +0,0 @@ >-/* >- * 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 <math.h> >-#include <string.h> >- >-#include "api/video/i420_buffer.h" >-#include "api/video/video_frame.h" >-#include "rtc_base/bind.h" >-#include "rtc_base/timeutils.h" >-#include "test/fake_texture_frame.h" >-#include "test/frame_utils.h" >-#include "test/gtest.h" >- >-namespace webrtc { >- >-namespace { >- >-rtc::scoped_refptr<I420Buffer> CreateGradient(int width, int height) { >- rtc::scoped_refptr<I420Buffer> buffer( >- I420Buffer::Create(width, height)); >- // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h >- for (int x = 0; x < width; x++) { >- for (int y = 0; y < height; y++) { >- buffer->MutableDataY()[x + y * width] = >- 128 * (x * height + y * width) / (width * height); >- } >- } >- int chroma_width = buffer->ChromaWidth(); >- int chroma_height = buffer->ChromaHeight(); >- for (int x = 0; x < chroma_width; x++) { >- for (int y = 0; y < chroma_height; y++) { >- buffer->MutableDataU()[x + y * chroma_width] = >- 255 * x / (chroma_width - 1); >- buffer->MutableDataV()[x + y * chroma_width] = >- 255 * y / (chroma_height - 1); >- } >- } >- return buffer; >-} >- >-// The offsets and sizes describe the rectangle extracted from the >-// original (gradient) frame, in relative coordinates where the >-// original frame correspond to the unit square, 0.0 <= x, y < 1.0. >-void CheckCrop(const webrtc::I420BufferInterface& frame, >- double offset_x, >- double offset_y, >- double rel_width, >- double rel_height) { >- int width = frame.width(); >- int height = frame.height(); >- // Check that pixel values in the corners match the gradient used >- // for initialization. >- for (int i = 0; i < 2; i++) { >- for (int j = 0; j < 2; j++) { >- // Pixel coordinates of the corner. >- int x = i * (width - 1); >- int y = j * (height - 1); >- // Relative coordinates, range 0.0 - 1.0 correspond to the >- // size of the uncropped input frame. >- double orig_x = offset_x + i * rel_width; >- double orig_y = offset_y + j * rel_height; >- >- EXPECT_NEAR(frame.DataY()[x + y * frame.StrideY()] / 256.0, >- (orig_x + orig_y) / 2, 0.02); >- EXPECT_NEAR(frame.DataU()[x / 2 + (y / 2) * frame.StrideU()] / 256.0, >- orig_x, 0.02); >- EXPECT_NEAR(frame.DataV()[x / 2 + (y / 2) * frame.StrideV()] / 256.0, >- orig_y, 0.02); >- } >- } >-} >- >-void CheckRotate(int width, >- int height, >- webrtc::VideoRotation rotation, >- const webrtc::I420BufferInterface& rotated) { >- int rotated_width = width; >- int rotated_height = height; >- >- if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { >- std::swap(rotated_width, rotated_height); >- } >- EXPECT_EQ(rotated_width, rotated.width()); >- EXPECT_EQ(rotated_height, rotated.height()); >- >- // Clock-wise order (with 0,0 at top-left) >- const struct { int x; int y; } corners[] = { >- { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } >- }; >- // Corresponding corner colors of the frame produced by CreateGradient. >- const struct { int y; int u; int v; } colors[] = { >- {0, 0, 0}, { 127, 255, 0}, { 255, 255, 255 }, {127, 0, 255} >- }; >- int corner_offset = static_cast<int>(rotation) / 90; >- >- for (int i = 0; i < 4; i++) { >- int j = (i + corner_offset) % 4; >- int x = corners[j].x * (rotated_width - 1); >- int y = corners[j].y * (rotated_height - 1); >- EXPECT_EQ(colors[i].y, rotated.DataY()[x + y * rotated.StrideY()]); >- EXPECT_EQ(colors[i].u, >- rotated.DataU()[(x / 2) + (y / 2) * rotated.StrideU()]); >- EXPECT_EQ(colors[i].v, >- rotated.DataV()[(x / 2) + (y / 2) * rotated.StrideV()]); >- } >-} >- >-} // namespace >- >-TEST(TestVideoFrame, WidthHeightValues) { >- VideoFrame frame(I420Buffer::Create(10, 10, 10, 14, 90), >- webrtc::kVideoRotation_0, >- 789 * rtc::kNumMicrosecsPerMillisec); >- const int valid_value = 10; >- EXPECT_EQ(valid_value, frame.width()); >- EXPECT_EQ(valid_value, frame.height()); >- frame.set_timestamp(123u); >- EXPECT_EQ(123u, frame.timestamp()); >- frame.set_ntp_time_ms(456); >- EXPECT_EQ(456, frame.ntp_time_ms()); >- EXPECT_EQ(789, frame.render_time_ms()); >-} >- >-TEST(TestVideoFrame, ShallowCopy) { >- uint32_t timestamp = 1; >- int64_t ntp_time_ms = 2; >- int64_t timestamp_us = 3; >- int stride_y = 15; >- int stride_u = 10; >- int stride_v = 10; >- int width = 15; >- int height = 15; >- >- const int kSizeY = 400; >- const int kSizeU = 100; >- const int kSizeV = 100; >- const VideoRotation kRotation = kVideoRotation_270; >- uint8_t buffer_y[kSizeY]; >- uint8_t buffer_u[kSizeU]; >- uint8_t buffer_v[kSizeV]; >- memset(buffer_y, 16, kSizeY); >- memset(buffer_u, 8, kSizeU); >- memset(buffer_v, 4, kSizeV); >- >- VideoFrame frame1( >- I420Buffer::Copy(width, height, >- buffer_y, stride_y, >- buffer_u, stride_u, >- buffer_v, stride_v), >- kRotation, 0); >- frame1.set_timestamp(timestamp); >- frame1.set_ntp_time_ms(ntp_time_ms); >- frame1.set_timestamp_us(timestamp_us); >- VideoFrame frame2(frame1); >- >- EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer()); >- rtc::scoped_refptr<I420BufferInterface> yuv1 = >- frame1.video_frame_buffer()->GetI420(); >- rtc::scoped_refptr<I420BufferInterface> yuv2 = >- frame2.video_frame_buffer()->GetI420(); >- EXPECT_EQ(yuv1->DataY(), yuv2->DataY()); >- EXPECT_EQ(yuv1->DataU(), yuv2->DataU()); >- EXPECT_EQ(yuv1->DataV(), yuv2->DataV()); >- >- EXPECT_EQ(frame2.timestamp(), frame1.timestamp()); >- EXPECT_EQ(frame2.ntp_time_ms(), frame1.ntp_time_ms()); >- EXPECT_EQ(frame2.timestamp_us(), frame1.timestamp_us()); >- EXPECT_EQ(frame2.rotation(), frame1.rotation()); >- >- frame2.set_timestamp(timestamp + 1); >- frame2.set_ntp_time_ms(ntp_time_ms + 1); >- frame2.set_timestamp_us(timestamp_us + 1); >- frame2.set_rotation(kVideoRotation_90); >- >- EXPECT_NE(frame2.timestamp(), frame1.timestamp()); >- EXPECT_NE(frame2.ntp_time_ms(), frame1.ntp_time_ms()); >- EXPECT_NE(frame2.timestamp_us(), frame1.timestamp_us()); >- EXPECT_NE(frame2.rotation(), frame1.rotation()); >-} >- >-TEST(TestVideoFrame, TextureInitialValues) { >- VideoFrame frame = test::FakeNativeBuffer::CreateFrame( >- 640, 480, 100, 10, webrtc::kVideoRotation_0); >- EXPECT_EQ(640, frame.width()); >- EXPECT_EQ(480, frame.height()); >- EXPECT_EQ(100u, frame.timestamp()); >- EXPECT_EQ(10, frame.render_time_ms()); >- ASSERT_TRUE(frame.video_frame_buffer() != nullptr); >- EXPECT_TRUE(frame.video_frame_buffer()->type() == >- VideoFrameBuffer::Type::kNative); >- >- frame.set_timestamp(200); >- EXPECT_EQ(200u, frame.timestamp()); >- frame.set_timestamp_us(20); >- EXPECT_EQ(20, frame.timestamp_us()); >-} >- >-TEST(TestI420FrameBuffer, Copy) { >- rtc::scoped_refptr<I420Buffer> buf1( >- I420Buffer::Create(20, 10)); >- memset(buf1->MutableDataY(), 1, 200); >- memset(buf1->MutableDataU(), 2, 50); >- memset(buf1->MutableDataV(), 3, 50); >- rtc::scoped_refptr<I420Buffer> buf2 = I420Buffer::Copy(*buf1); >- EXPECT_TRUE(test::FrameBufsEqual(buf1, buf2)); >-} >- >-TEST(TestI420FrameBuffer, Scale) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(200, 100); >- >- // Pure scaling, no cropping. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(150, 75)); >- >- scaled_buffer->ScaleFrom(*buf); >- CheckCrop(*scaled_buffer, 0.0, 0.0, 1.0, 1.0); >-} >- >-TEST(TestI420FrameBuffer, CropXCenter) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(200, 100); >- >- // Pure center cropping, no scaling. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(100, 100)); >- >- scaled_buffer->CropAndScaleFrom(*buf, 50, 0, 100, 100); >- CheckCrop(*scaled_buffer, 0.25, 0.0, 0.5, 1.0); >-} >- >-TEST(TestI420FrameBuffer, CropXNotCenter) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(200, 100); >- >- // Non-center cropping, no scaling. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(100, 100)); >- >- scaled_buffer->CropAndScaleFrom(*buf, 25, 0, 100, 100); >- CheckCrop(*scaled_buffer, 0.125, 0.0, 0.5, 1.0); >-} >- >-TEST(TestI420FrameBuffer, CropYCenter) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(100, 200); >- >- // Pure center cropping, no scaling. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(100, 100)); >- >- scaled_buffer->CropAndScaleFrom(*buf, 0, 50, 100, 100); >- CheckCrop(*scaled_buffer, 0.0, 0.25, 1.0, 0.5); >-} >- >-TEST(TestI420FrameBuffer, CropYNotCenter) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(100, 200); >- >- // Non-center cropping, no scaling. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(100, 100)); >- >- scaled_buffer->CropAndScaleFrom(*buf, 0, 25, 100, 100); >- CheckCrop(*scaled_buffer, 0.0, 0.125, 1.0, 0.5); >-} >- >-TEST(TestI420FrameBuffer, CropAndScale16x9) { >- rtc::scoped_refptr<I420Buffer> buf = CreateGradient(640, 480); >- >- // Center crop to 640 x 360 (16/9 aspect), then scale down by 2. >- rtc::scoped_refptr<I420Buffer> scaled_buffer( >- I420Buffer::Create(320, 180)); >- >- scaled_buffer->CropAndScaleFrom(*buf); >- CheckCrop(*scaled_buffer, 0.0, 0.125, 1.0, 0.75); >-} >- >-class TestI420BufferRotate >- : public ::testing::TestWithParam<webrtc::VideoRotation> {}; >- >-TEST_P(TestI420BufferRotate, Rotates) { >- rtc::scoped_refptr<I420BufferInterface> buffer = CreateGradient(640, 480); >- rtc::scoped_refptr<I420BufferInterface> rotated_buffer = >- I420Buffer::Rotate(*buffer, GetParam()); >- CheckRotate(640, 480, GetParam(), *rotated_buffer); >-} >- >-INSTANTIATE_TEST_CASE_P(Rotate, TestI420BufferRotate, >- ::testing::Values(kVideoRotation_0, >- kVideoRotation_90, >- kVideoRotation_180, >- kVideoRotation_270)); >- >-} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/bitrate_adjuster.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/bitrate_adjuster.h >index fd83555469c..ee312e4f9a4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/bitrate_adjuster.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/bitrate_adjuster.h >@@ -18,8 +18,6 @@ > > namespace webrtc { > >-class Clock; >- > // Certain hardware encoders tend to consistently overshoot the bitrate that > // they are configured to encode at. This class estimates an adjusted bitrate > // that when set on the encoder will produce the desired bitrate. >@@ -28,8 +26,7 @@ class BitrateAdjuster { > // min_adjusted_bitrate_pct and max_adjusted_bitrate_pct are the lower and > // upper bound outputted adjusted bitrates as a percentage of the target > // bitrate. >- BitrateAdjuster(Clock* clock, >- float min_adjusted_bitrate_pct, >+ BitrateAdjuster(float min_adjusted_bitrate_pct, > float max_adjusted_bitrate_pct); > virtual ~BitrateAdjuster() {} > >@@ -47,7 +44,7 @@ class BitrateAdjuster { > uint32_t GetAdjustedBitrateBps() const; > > // Returns what we think the current bitrate is. >- rtc::Optional<uint32_t> GetEstimatedBitrateBps(); >+ absl::optional<uint32_t> GetEstimatedBitrateBps(); > > // This should be called after each frame is encoded. The timestamp at which > // it is called is used to estimate the output bitrate of the encoder. >@@ -68,7 +65,6 @@ class BitrateAdjuster { > RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_); > > rtc::CriticalSection crit_; >- Clock* const clock_; > const float min_adjusted_bitrate_pct_; > const float max_adjusted_bitrate_pct_; > // The bitrate we want. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/i420_buffer_pool.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/i420_buffer_pool.h >index 863eb101804..79f7eec23af 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/i420_buffer_pool.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/i420_buffer_pool.h >@@ -11,8 +11,8 @@ > #ifndef COMMON_VIDEO_INCLUDE_I420_BUFFER_POOL_H_ > #define COMMON_VIDEO_INCLUDE_I420_BUFFER_POOL_H_ > >-#include <list> > #include <limits> >+#include <list> > > #include "api/video/i420_buffer.h" > #include "rtc_base/race_checker.h" >@@ -29,11 +29,10 @@ namespace webrtc { > // are created. This is to prevent memory leaks where frames are not returned. > class I420BufferPool { > public: >- I420BufferPool() >- : I420BufferPool(false) {} >- explicit I420BufferPool(bool zero_initialize) >- : I420BufferPool(zero_initialize, std::numeric_limits<size_t>::max()) {} >+ I420BufferPool(); >+ explicit I420BufferPool(bool zero_initialize); > I420BufferPool(bool zero_initialze, size_t max_number_of_buffers); >+ ~I420BufferPool(); > > // Returns a buffer from the pool. If no suitable buffer exist in the pool > // and there are less than |max_number_of_buffers| pending, a buffer is >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/incoming_video_stream.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/incoming_video_stream.h >index 405416c2d81..8063061d313 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/incoming_video_stream.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/incoming_video_stream.h >@@ -11,7 +11,7 @@ > #ifndef COMMON_VIDEO_INCLUDE_INCOMING_VIDEO_STREAM_H_ > #define COMMON_VIDEO_INCLUDE_INCOMING_VIDEO_STREAM_H_ > >-#include "api/videosinkinterface.h" >+#include "api/video/video_sink_interface.h" > #include "common_video/video_render_frames.h" > #include "rtc_base/race_checker.h" > #include "rtc_base/task_queue.h" >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_bitrate_allocator.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_bitrate_allocator.h >index 597b6259a4a..77a0fef1dd0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_bitrate_allocator.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_bitrate_allocator.h >@@ -11,29 +11,6 @@ > #ifndef COMMON_VIDEO_INCLUDE_VIDEO_BITRATE_ALLOCATOR_H_ > #define COMMON_VIDEO_INCLUDE_VIDEO_BITRATE_ALLOCATOR_H_ > >-#include "common_types.h" // NOLINT(build/include) >- >-namespace webrtc { >- >-class VideoBitrateAllocator { >- public: >- VideoBitrateAllocator() {} >- virtual ~VideoBitrateAllocator() {} >- >- virtual BitrateAllocation GetAllocation(uint32_t total_bitrate, >- uint32_t framerate) = 0; >- virtual uint32_t GetPreferredBitrateBps(uint32_t framerate) = 0; >-}; >- >-class VideoBitrateAllocationObserver { >- public: >- VideoBitrateAllocationObserver() {} >- virtual ~VideoBitrateAllocationObserver() {} >- >- virtual void OnBitrateAllocationUpdated( >- const BitrateAllocation& allocation) = 0; >-}; >- >-} // namespace webrtc >+#include "api/video/video_bitrate_allocator.h" > > #endif // COMMON_VIDEO_INCLUDE_VIDEO_BITRATE_ALLOCATOR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame.h >index 572a4e47033..ccb709f7bc5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame.h >@@ -16,9 +16,11 @@ > // to refactor and clean up related interfaces, at which point it > // should be moved to somewhere under api/. > >-#include "api/rtp_headers.h" >+#include "absl/types/optional.h" >+#include "api/video/video_content_type.h" >+#include "api/video/video_rotation.h" >+#include "api/video/video_timing.h" > #include "common_types.h" // NOLINT(build/include) >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >@@ -32,10 +34,22 @@ class EncodedImage { > static size_t GetBufferPaddingBytes(VideoCodecType codec_type); > > EncodedImage(); >+ EncodedImage(const EncodedImage&); > EncodedImage(uint8_t* buffer, size_t length, size_t size); > > void SetEncodeTime(int64_t encode_start_ms, int64_t encode_finish_ms); > >+ absl::optional<int> SpatialIndex() const { >+ if (spatial_index_ < 0) >+ return absl::nullopt; >+ return spatial_index_; >+ } >+ void SetSpatialIndex(absl::optional<int> spatial_index) { >+ RTC_DCHECK_GE(spatial_index.value_or(0), 0); >+ RTC_DCHECK_LT(spatial_index.value_or(0), kMaxSpatialLayers); >+ spatial_index_ = spatial_index.value_or(-1); >+ } >+ > uint32_t _encodedWidth = 0; > uint32_t _encodedHeight = 0; > uint32_t _timeStamp = 0; >@@ -57,7 +71,7 @@ class EncodedImage { > PlayoutDelay playout_delay_ = {-1, -1}; > > struct Timing { >- uint8_t flags = TimingFrameFlags::kInvalid; >+ uint8_t flags = VideoSendTiming::kInvalid; > int64_t encode_start_ms = 0; > int64_t encode_finish_ms = 0; > int64_t packetization_finish_ms = 0; >@@ -67,6 +81,11 @@ class EncodedImage { > int64_t receive_start_ms = 0; > int64_t receive_finish_ms = 0; > } timing_; >+ >+ private: >+ // -1 means not set. Use a plain int rather than optional, to keep this class >+ // copyable with memcpy. >+ int spatial_index_ = -1; > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame_buffer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame_buffer.h >index 312979b05d8..11bb8125316 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame_buffer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/include/video_frame_buffer.h >@@ -103,6 +103,17 @@ rtc::scoped_refptr<PlanarYuvBuffer> WrapYuvBuffer( > int v_stride, > const rtc::Callback0<void>& no_longer_used); > >+rtc::scoped_refptr<I010BufferInterface> WrapI010Buffer( >+ int width, >+ int height, >+ const uint16_t* y_plane, >+ int y_stride, >+ const uint16_t* u_plane, >+ int u_stride, >+ const uint16_t* v_plane, >+ int v_stride, >+ const rtc::Callback0<void>& no_longer_used); >+ > } // namespace webrtc > > #endif // COMMON_VIDEO_INCLUDE_VIDEO_FRAME_BUFFER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/incoming_video_stream.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/incoming_video_stream.cc >index 8e715407ea6..efca5145566 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/incoming_video_stream.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/incoming_video_stream.cc >@@ -15,7 +15,6 @@ > #include "common_video/video_render_frames.h" > #include "rtc_base/timeutils.h" > #include "rtc_base/trace_event.h" >-#include "system_wrappers/include/event_wrapper.h" > > namespace webrtc { > namespace { >@@ -70,7 +69,7 @@ void IncomingVideoStream::OnFrame(const VideoFrame& video_frame) { > void IncomingVideoStream::Dequeue() { > TRACE_EVENT0("webrtc", "IncomingVideoStream::Dequeue"); > RTC_DCHECK(incoming_render_queue_.IsCurrent()); >- rtc::Optional<VideoFrame> frame_to_render = render_buffers_.FrameToRender(); >+ absl::optional<VideoFrame> frame_to_render = render_buffers_.FrameToRender(); > if (frame_to_render) > callback_->OnFrame(*frame_to_render); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/include/webrtc_libyuv.h >index 5b2a3af8359..4cbfec20187 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/include/webrtc_libyuv.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/include/webrtc_libyuv.h >@@ -20,11 +20,9 @@ > > #include "api/video/video_frame.h" > #include "common_types.h" // NOLINT(build/include) // VideoTypes. >-#include "typedefs.h" // NOLINT(build/include) > > namespace webrtc { > >- > // This is the max PSNR value our algorithms can return. > const double kPerfectPSNR = 48.0f; > >@@ -93,12 +91,18 @@ double I420SSIM(const I420BufferInterface& ref_buffer, > // |tmp_buffer| should be: > // (src_width/2) * (src_height/2) * 2 + (dst_width/2) * (dst_height/2) * 2 > void NV12Scale(uint8_t* tmp_buffer, >- const uint8_t* src_y, int src_stride_y, >- const uint8_t* src_uv, int src_stride_uv, >- int src_width, int src_height, >- uint8_t* dst_y, int dst_stride_y, >- uint8_t* dst_uv, int dst_stride_uv, >- int dst_width, int dst_height); >+ const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ int src_width, >+ int src_height, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_uv, >+ int dst_stride_uv, >+ int dst_width, >+ int dst_height); > > // Helper class for directly converting and scaling NV12 to I420. The Y-plane > // will be scaled directly to the I420 destination, which makes this faster >@@ -107,13 +111,21 @@ class NV12ToI420Scaler { > public: > NV12ToI420Scaler(); > ~NV12ToI420Scaler(); >- void NV12ToI420Scale(const uint8_t* src_y, int src_stride_y, >- const uint8_t* src_uv, int src_stride_uv, >- int src_width, int src_height, >- uint8_t* dst_y, int dst_stride_y, >- uint8_t* dst_u, int dst_stride_u, >- uint8_t* dst_v, int dst_stride_v, >- int dst_width, int dst_height); >+ void NV12ToI420Scale(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ int src_width, >+ int src_height, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, >+ int dst_width, >+ int dst_height); >+ > private: > std::vector<uint8_t> tmp_uv_planes_; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/libyuv_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/libyuv_unittest.cc >index ba65544bf01..79e7cb61b98 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/libyuv_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/libyuv_unittest.cc >@@ -35,8 +35,8 @@ void Calc16ByteAlignedStride(int width, int* stride_y, int* stride_uv) { > class TestLibYuv : public ::testing::Test { > protected: > TestLibYuv(); >- virtual void SetUp(); >- virtual void TearDown(); >+ void SetUp() override; >+ void TearDown() override; > > FILE* source_file_; > std::unique_ptr<VideoFrame> orig_frame_; >@@ -57,11 +57,11 @@ TestLibYuv::TestLibYuv() > frame_length_(CalcBufferSize(VideoType::kI420, 352, 288)) {} > > void TestLibYuv::SetUp() { >- const std::string input_file_name = webrtc::test::ResourcePath("foreman_cif", >- "yuv"); >- source_file_ = fopen(input_file_name.c_str(), "rb"); >- ASSERT_TRUE(source_file_ != NULL) << "Cannot read file: "<< >- input_file_name << "\n"; >+ const std::string input_file_name = >+ webrtc::test::ResourcePath("foreman_cif", "yuv"); >+ source_file_ = fopen(input_file_name.c_str(), "rb"); >+ ASSERT_TRUE(source_file_ != NULL) >+ << "Cannot read file: " << input_file_name << "\n"; > > rtc::scoped_refptr<I420BufferInterface> buffer( > test::ReadI420Buffer(width_, height_, source_file_)); >@@ -83,9 +83,9 @@ TEST_F(TestLibYuv, ConvertSanityTest) { > TEST_F(TestLibYuv, ConvertTest) { > // Reading YUV frame - testing on the first frame of the foreman sequence > int j = 0; >- std::string output_file_name = webrtc::test::OutputPath() + >- "LibYuvTest_conversion.yuv"; >- FILE* output_file = fopen(output_file_name.c_str(), "wb"); >+ std::string output_file_name = >+ webrtc::test::OutputPath() + "LibYuvTest_conversion.yuv"; >+ FILE* output_file = fopen(output_file_name.c_str(), "wb"); > ASSERT_TRUE(output_file != NULL); > > double psnr = 0.0; >@@ -249,9 +249,9 @@ TEST_F(TestLibYuv, ConvertTest) { > > TEST_F(TestLibYuv, ConvertAlignedFrame) { > // Reading YUV frame - testing on the first frame of the foreman sequence >- std::string output_file_name = webrtc::test::OutputPath() + >- "LibYuvTest_conversion.yuv"; >- FILE* output_file = fopen(output_file_name.c_str(), "wb"); >+ std::string output_file_name = >+ webrtc::test::OutputPath() + "LibYuvTest_conversion.yuv"; >+ FILE* output_file = fopen(output_file_name.c_str(), "wb"); > ASSERT_TRUE(output_file != NULL); > > double psnr = 0.0; >@@ -290,33 +290,24 @@ static uint8_t Average(int a, int b, int c, int d) { > } > > TEST_F(TestLibYuv, NV12Scale2x2to2x2) { >- const std::vector<uint8_t> src_y = {0, 1, >- 2, 3}; >+ const std::vector<uint8_t> src_y = {0, 1, 2, 3}; > const std::vector<uint8_t> src_uv = {0, 1}; > std::vector<uint8_t> dst_y(4); > std::vector<uint8_t> dst_uv(2); > > uint8_t* tmp_buffer = nullptr; > >- NV12Scale(tmp_buffer, >- src_y.data(), 2, >- src_uv.data(), 2, >- 2, 2, >- dst_y.data(), 2, >- dst_uv.data(), 2, >- 2, 2); >+ NV12Scale(tmp_buffer, src_y.data(), 2, src_uv.data(), 2, 2, 2, dst_y.data(), >+ 2, dst_uv.data(), 2, 2, 2); > > EXPECT_THAT(dst_y, ::testing::ContainerEq(src_y)); > EXPECT_THAT(dst_uv, ::testing::ContainerEq(src_uv)); > } > > TEST_F(TestLibYuv, NV12Scale4x4to2x2) { >- const uint8_t src_y[] = { 0, 1, 2, 3, >- 4, 5, 6, 7, >- 8, 9, 10, 11, >- 12, 13, 14, 15}; >- const uint8_t src_uv[] = {0, 1, 2, 3, >- 4, 5, 6, 7}; >+ const uint8_t src_y[] = {0, 1, 2, 3, 4, 5, 6, 7, >+ 8, 9, 10, 11, 12, 13, 14, 15}; >+ const uint8_t src_uv[] = {0, 1, 2, 3, 4, 5, 6, 7}; > std::vector<uint8_t> dst_y(4); > std::vector<uint8_t> dst_uv(2); > >@@ -329,13 +320,8 @@ TEST_F(TestLibYuv, NV12Scale4x4to2x2) { > dst_chroma_width * dst_chroma_height * 2); > tmp_buffer.shrink_to_fit(); > >- NV12Scale(tmp_buffer.data(), >- src_y, 4, >- src_uv, 4, >- 4, 4, >- dst_y.data(), 2, >- dst_uv.data(), 2, >- 2, 2); >+ NV12Scale(tmp_buffer.data(), src_y, 4, src_uv, 4, 4, 4, dst_y.data(), 2, >+ dst_uv.data(), 2, 2, 2); > > EXPECT_THAT(dst_y, ::testing::ElementsAre( > Average(0, 1, 4, 5), Average(2, 3, 6, 7), >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/webrtc_libyuv.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/webrtc_libyuv.cc >index 676dad3d0c3..6bdfabd5e9c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/webrtc_libyuv.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/libyuv/webrtc_libyuv.cc >@@ -13,6 +13,8 @@ > #include <string.h> > > #include "api/video/i420_buffer.h" >+#include "common_video/include/video_frame_buffer.h" >+#include "rtc_base/bind.h" > #include "rtc_base/checks.h" > #include "third_party/libyuv/include/libyuv.h" > >@@ -73,18 +75,15 @@ int PrintVideoFrame(const I420BufferInterface& frame, FILE* file) { > int chroma_width = frame.ChromaWidth(); > int chroma_height = frame.ChromaHeight(); > >- if (PrintPlane(frame.DataY(), width, height, >- frame.StrideY(), file) < 0) { >+ if (PrintPlane(frame.DataY(), width, height, frame.StrideY(), file) < 0) { > return -1; > } >- if (PrintPlane(frame.DataU(), >- chroma_width, chroma_height, >- frame.StrideU(), file) < 0) { >+ if (PrintPlane(frame.DataU(), chroma_width, chroma_height, frame.StrideU(), >+ file) < 0) { > return -1; > } >- if (PrintPlane(frame.DataV(), >- chroma_width, chroma_height, >- frame.StrideV(), file) < 0) { >+ if (PrintPlane(frame.DataV(), chroma_width, chroma_height, frame.StrideV(), >+ file) < 0) { > return -1; > } > return 0; >@@ -104,23 +103,18 @@ int ExtractBuffer(const rtc::scoped_refptr<I420BufferInterface>& input_frame, > int height = input_frame->height(); > size_t length = CalcBufferSize(VideoType::kI420, width, height); > if (size < length) { >- return -1; >+ return -1; > } > > int chroma_width = input_frame->ChromaWidth(); > int chroma_height = input_frame->ChromaHeight(); > >- libyuv::I420Copy(input_frame->DataY(), >- input_frame->StrideY(), >- input_frame->DataU(), >- input_frame->StrideU(), >- input_frame->DataV(), >- input_frame->StrideV(), >- buffer, width, >- buffer + width*height, chroma_width, >- buffer + width*height + chroma_width*chroma_height, >- chroma_width, >- width, height); >+ libyuv::I420Copy(input_frame->DataY(), input_frame->StrideY(), >+ input_frame->DataU(), input_frame->StrideU(), >+ input_frame->DataV(), input_frame->StrideV(), buffer, width, >+ buffer + width * height, chroma_width, >+ buffer + width * height + chroma_width * chroma_height, >+ chroma_width, width, height); > > return static_cast<int>(length); > } >@@ -132,24 +126,25 @@ int ExtractBuffer(const VideoFrame& input_frame, size_t size, uint8_t* buffer) { > > int ConvertNV12ToRGB565(const uint8_t* src_frame, > uint8_t* dst_frame, >- int width, int height) { >+ int width, >+ int height) { > int abs_height = (height < 0) ? -height : height; > const uint8_t* yplane = src_frame; > const uint8_t* uvInterlaced = src_frame + (width * abs_height); > >- return libyuv::NV12ToRGB565(yplane, width, >- uvInterlaced, (width + 1) >> 1, >- dst_frame, width, >- width, height); >+ return libyuv::NV12ToRGB565(yplane, width, uvInterlaced, (width + 1) >> 1, >+ dst_frame, width, width, height); > } > >-int ConvertRGB24ToARGB(const uint8_t* src_frame, uint8_t* dst_frame, >- int width, int height, int dst_stride) { >+int ConvertRGB24ToARGB(const uint8_t* src_frame, >+ uint8_t* dst_frame, >+ int width, >+ int height, >+ int dst_stride) { > if (dst_stride == 0) > dst_stride = width; >- return libyuv::RGB24ToARGB(src_frame, width, >- dst_frame, dst_stride, >- width, height); >+ return libyuv::RGB24ToARGB(src_frame, width, dst_frame, dst_stride, width, >+ height); > } > > int ConvertVideoType(VideoType video_type) { >@@ -203,6 +198,78 @@ int ConvertFromI420(const VideoFrame& src_frame, > ConvertVideoType(dst_video_type)); > } > >+// Helper functions for keeping references alive. >+void KeepBufferRefs(rtc::scoped_refptr<webrtc::VideoFrameBuffer>, >+ rtc::scoped_refptr<webrtc::VideoFrameBuffer>) {} >+ >+rtc::scoped_refptr<I420ABufferInterface> ScaleI420ABuffer( >+ const I420ABufferInterface& buffer, >+ int target_width, >+ int target_height) { >+ rtc::scoped_refptr<I420Buffer> yuv_buffer = >+ I420Buffer::Create(target_width, target_height); >+ yuv_buffer->ScaleFrom(buffer); >+ rtc::scoped_refptr<I420Buffer> axx_buffer = >+ I420Buffer::Create(target_width, target_height); >+ libyuv::ScalePlane(buffer.DataA(), buffer.StrideA(), buffer.width(), >+ buffer.height(), axx_buffer->MutableDataY(), >+ axx_buffer->StrideY(), target_width, target_height, >+ libyuv::kFilterBox); >+ rtc::scoped_refptr<I420ABufferInterface> merged_buffer = WrapI420ABuffer( >+ yuv_buffer->width(), yuv_buffer->height(), yuv_buffer->DataY(), >+ yuv_buffer->StrideY(), yuv_buffer->DataU(), yuv_buffer->StrideU(), >+ yuv_buffer->DataV(), yuv_buffer->StrideV(), axx_buffer->DataY(), >+ axx_buffer->StrideY(), >+ rtc::Bind(&KeepBufferRefs, yuv_buffer, axx_buffer)); >+ return merged_buffer; >+} >+ >+// Compute PSNR for an I420A frame (all planes). Can upscale test frame. >+double I420APSNR(const I420ABufferInterface& ref_buffer, >+ const I420ABufferInterface& test_buffer) { >+ RTC_DCHECK_GE(ref_buffer.width(), test_buffer.width()); >+ RTC_DCHECK_GE(ref_buffer.height(), test_buffer.height()); >+ if ((ref_buffer.width() != test_buffer.width()) || >+ (ref_buffer.height() != test_buffer.height())) { >+ rtc::scoped_refptr<I420ABufferInterface> scaled_buffer = >+ ScaleI420ABuffer(test_buffer, ref_buffer.width(), ref_buffer.height()); >+ return I420APSNR(ref_buffer, *scaled_buffer); >+ } >+ const int width = test_buffer.width(); >+ const int height = test_buffer.height(); >+ const uint64_t sse_y = libyuv::ComputeSumSquareErrorPlane( >+ ref_buffer.DataY(), ref_buffer.StrideY(), test_buffer.DataY(), >+ test_buffer.StrideY(), width, height); >+ const int width_uv = (width + 1) >> 1; >+ const int height_uv = (height + 1) >> 1; >+ const uint64_t sse_u = libyuv::ComputeSumSquareErrorPlane( >+ ref_buffer.DataU(), ref_buffer.StrideU(), test_buffer.DataU(), >+ test_buffer.StrideU(), width_uv, height_uv); >+ const uint64_t sse_v = libyuv::ComputeSumSquareErrorPlane( >+ ref_buffer.DataV(), ref_buffer.StrideV(), test_buffer.DataV(), >+ test_buffer.StrideV(), width_uv, height_uv); >+ const uint64_t sse_a = libyuv::ComputeSumSquareErrorPlane( >+ ref_buffer.DataA(), ref_buffer.StrideA(), test_buffer.DataA(), >+ test_buffer.StrideA(), width, height); >+ const uint64_t samples = 2 * (uint64_t)width * (uint64_t)height + >+ 2 * ((uint64_t)width_uv * (uint64_t)height_uv); >+ const uint64_t sse = sse_y + sse_u + sse_v + sse_a; >+ const double psnr = libyuv::SumSquareErrorToPsnr(sse, samples); >+ return (psnr > kPerfectPSNR) ? kPerfectPSNR : psnr; >+} >+ >+// Compute PSNR for an I420A frame (all planes) >+double I420APSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { >+ if (!ref_frame || !test_frame) >+ return -1; >+ RTC_DCHECK(ref_frame->video_frame_buffer()->type() == >+ VideoFrameBuffer::Type::kI420A); >+ RTC_DCHECK(test_frame->video_frame_buffer()->type() == >+ VideoFrameBuffer::Type::kI420A); >+ return I420APSNR(*ref_frame->video_frame_buffer()->GetI420A(), >+ *test_frame->video_frame_buffer()->GetI420A()); >+} >+ > // Compute PSNR for an I420 frame (all planes). Can upscale test frame. > double I420PSNR(const I420BufferInterface& ref_buffer, > const I420BufferInterface& test_buffer) { >@@ -234,6 +301,41 @@ double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame) { > *test_frame->video_frame_buffer()->ToI420()); > } > >+// Compute SSIM for an I420A frame (all planes). Can upscale test frame. >+double I420ASSIM(const I420ABufferInterface& ref_buffer, >+ const I420ABufferInterface& test_buffer) { >+ RTC_DCHECK_GE(ref_buffer.width(), test_buffer.width()); >+ RTC_DCHECK_GE(ref_buffer.height(), test_buffer.height()); >+ if ((ref_buffer.width() != test_buffer.width()) || >+ (ref_buffer.height() != test_buffer.height())) { >+ rtc::scoped_refptr<I420ABufferInterface> scaled_buffer = >+ ScaleI420ABuffer(test_buffer, ref_buffer.width(), ref_buffer.height()); >+ return I420ASSIM(ref_buffer, *scaled_buffer); >+ } >+ const double yuv_ssim = libyuv::I420Ssim( >+ ref_buffer.DataY(), ref_buffer.StrideY(), ref_buffer.DataU(), >+ ref_buffer.StrideU(), ref_buffer.DataV(), ref_buffer.StrideV(), >+ test_buffer.DataY(), test_buffer.StrideY(), test_buffer.DataU(), >+ test_buffer.StrideU(), test_buffer.DataV(), test_buffer.StrideV(), >+ test_buffer.width(), test_buffer.height()); >+ const double a_ssim = libyuv::CalcFrameSsim( >+ ref_buffer.DataA(), ref_buffer.StrideA(), test_buffer.DataA(), >+ test_buffer.StrideA(), test_buffer.width(), test_buffer.height()); >+ return (yuv_ssim + (a_ssim * 0.8)) / 1.8; >+} >+ >+// Compute SSIM for an I420A frame (all planes) >+double I420ASSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { >+ if (!ref_frame || !test_frame) >+ return -1; >+ RTC_DCHECK(ref_frame->video_frame_buffer()->type() == >+ VideoFrameBuffer::Type::kI420A); >+ RTC_DCHECK(test_frame->video_frame_buffer()->type() == >+ VideoFrameBuffer::Type::kI420A); >+ return I420ASSIM(*ref_frame->video_frame_buffer()->GetI420A(), >+ *test_frame->video_frame_buffer()->GetI420A()); >+} >+ > // Compute SSIM for an I420 frame (all planes). Can upscale test_buffer. > double I420SSIM(const I420BufferInterface& ref_buffer, > const I420BufferInterface& test_buffer) { >@@ -253,6 +355,7 @@ double I420SSIM(const I420BufferInterface& ref_buffer, > test_buffer.StrideU(), test_buffer.DataV(), test_buffer.StrideV(), > test_buffer.width(), test_buffer.height()); > } >+ > double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { > if (!ref_frame || !test_frame) > return -1; >@@ -261,12 +364,18 @@ double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { > } > > void NV12Scale(uint8_t* tmp_buffer, >- const uint8_t* src_y, int src_stride_y, >- const uint8_t* src_uv, int src_stride_uv, >- int src_width, int src_height, >- uint8_t* dst_y, int dst_stride_y, >- uint8_t* dst_uv, int dst_stride_uv, >- int dst_width, int dst_height) { >+ const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ int src_width, >+ int src_height, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_uv, >+ int dst_stride_uv, >+ int dst_width, >+ int dst_height) { > const int src_chroma_width = (src_width + 1) / 2; > const int src_chroma_height = (src_height + 1) / 2; > >@@ -290,51 +399,44 @@ void NV12Scale(uint8_t* tmp_buffer, > uint8_t* const dst_v = dst_u + dst_chroma_width * dst_chroma_height; > > // Split source UV plane into separate U and V plane using the temporary data. >- libyuv::SplitUVPlane(src_uv, src_stride_uv, >- src_u, src_chroma_width, >- src_v, src_chroma_width, >- src_chroma_width, src_chroma_height); >+ libyuv::SplitUVPlane(src_uv, src_stride_uv, src_u, src_chroma_width, src_v, >+ src_chroma_width, src_chroma_width, src_chroma_height); > > // Scale the planes. >- libyuv::I420Scale(src_y, src_stride_y, >- src_u, src_chroma_width, >- src_v, src_chroma_width, >- src_width, src_height, >- dst_y, dst_stride_y, >- dst_u, dst_chroma_width, >- dst_v, dst_chroma_width, >- dst_width, dst_height, >- libyuv::kFilterBox); >+ libyuv::I420Scale( >+ src_y, src_stride_y, src_u, src_chroma_width, src_v, src_chroma_width, >+ src_width, src_height, dst_y, dst_stride_y, dst_u, dst_chroma_width, >+ dst_v, dst_chroma_width, dst_width, dst_height, libyuv::kFilterBox); > > // Merge the UV planes into the destination. >- libyuv::MergeUVPlane(dst_u, dst_chroma_width, >- dst_v, dst_chroma_width, >- dst_uv, dst_stride_uv, >- dst_chroma_width, dst_chroma_height); >+ libyuv::MergeUVPlane(dst_u, dst_chroma_width, dst_v, dst_chroma_width, dst_uv, >+ dst_stride_uv, dst_chroma_width, dst_chroma_height); > } > > NV12ToI420Scaler::NV12ToI420Scaler() = default; > NV12ToI420Scaler::~NV12ToI420Scaler() = default; > >-void NV12ToI420Scaler::NV12ToI420Scale( >- const uint8_t* src_y, int src_stride_y, >- const uint8_t* src_uv, int src_stride_uv, >- int src_width, int src_height, >- uint8_t* dst_y, int dst_stride_y, >- uint8_t* dst_u, int dst_stride_u, >- uint8_t* dst_v, int dst_stride_v, >- int dst_width, int dst_height) { >+void NV12ToI420Scaler::NV12ToI420Scale(const uint8_t* src_y, >+ int src_stride_y, >+ const uint8_t* src_uv, >+ int src_stride_uv, >+ int src_width, >+ int src_height, >+ uint8_t* dst_y, >+ int dst_stride_y, >+ uint8_t* dst_u, >+ int dst_stride_u, >+ uint8_t* dst_v, >+ int dst_stride_v, >+ int dst_width, >+ int dst_height) { > if (src_width == dst_width && src_height == dst_height) { > // No scaling. > tmp_uv_planes_.clear(); > tmp_uv_planes_.shrink_to_fit(); >- libyuv::NV12ToI420( >- src_y, src_stride_y, >- src_uv, src_stride_uv, >- dst_y, dst_stride_y, >- dst_u, dst_stride_u, >- dst_v, dst_stride_v, >- src_width, src_height); >+ libyuv::NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y, >+ dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, >+ src_width, src_height); > return; > } > >@@ -348,21 +450,14 @@ void NV12ToI420Scaler::NV12ToI420Scale( > // Split source UV plane into separate U and V plane using the temporary data. > uint8_t* const src_u = tmp_uv_planes_.data(); > uint8_t* const src_v = tmp_uv_planes_.data() + src_uv_width * src_uv_height; >- libyuv::SplitUVPlane(src_uv, src_stride_uv, >- src_u, src_uv_width, >- src_v, src_uv_width, >- src_uv_width, src_uv_height); >+ libyuv::SplitUVPlane(src_uv, src_stride_uv, src_u, src_uv_width, src_v, >+ src_uv_width, src_uv_width, src_uv_height); > > // Scale the planes into the destination. >- libyuv::I420Scale(src_y, src_stride_y, >- src_u, src_uv_width, >- src_v, src_uv_width, >- src_width, src_height, >- dst_y, dst_stride_y, >- dst_u, dst_stride_u, >- dst_v, dst_stride_v, >- dst_width, dst_height, >- libyuv::kFilterBox); >+ libyuv::I420Scale(src_y, src_stride_y, src_u, src_uv_width, src_v, >+ src_uv_width, src_width, src_height, dst_y, dst_stride_y, >+ dst_u, dst_stride_u, dst_v, dst_stride_v, dst_width, >+ dst_height, libyuv::kFilterBox); > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame.cc >index 58342a91831..f4618146711 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame.cc >@@ -25,28 +25,19 @@ const size_t EncodedImage::kBufferPaddingBytesH264 = 8; > > size_t EncodedImage::GetBufferPaddingBytes(VideoCodecType codec_type) { > switch (codec_type) { >- case kVideoCodecVP8: >- case kVideoCodecVP9: >- return 0; > case kVideoCodecH264: > return kBufferPaddingBytesH264; >- case kVideoCodecI420: >- case kVideoCodecRED: >- case kVideoCodecULPFEC: >- case kVideoCodecFlexfec: >- case kVideoCodecGeneric: >- case kVideoCodecStereo: >- case kVideoCodecUnknown: >+ default: > return 0; > } >- RTC_NOTREACHED(); >- return 0; > } > > EncodedImage::EncodedImage() : EncodedImage(nullptr, 0, 0) {} > >+EncodedImage::EncodedImage(const EncodedImage&) = default; >+ > EncodedImage::EncodedImage(uint8_t* buffer, size_t length, size_t size) >- : _buffer(buffer), _length(length), _size(size) {} >+ : _buffer(buffer), _length(length), _size(size) {} > > void EncodedImage::SetEncodeTime(int64_t encode_start_ms, > int64_t encode_finish_ms) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_buffer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_buffer.cc >index eebae2ad94b..be0b4927bbe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_buffer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_buffer.cc >@@ -130,6 +130,77 @@ rtc::scoped_refptr<I420BufferInterface> I444BufferBase::ToI420() { > return i420_buffer; > } > >+// Template to implement a wrapped buffer for a PlanarYuv16BBuffer. >+template <typename Base> >+class WrappedYuv16BBuffer : public Base { >+ public: >+ WrappedYuv16BBuffer(int width, >+ int height, >+ const uint16_t* y_plane, >+ int y_stride, >+ const uint16_t* u_plane, >+ int u_stride, >+ const uint16_t* v_plane, >+ int v_stride, >+ const rtc::Callback0<void>& no_longer_used) >+ : width_(width), >+ height_(height), >+ y_plane_(y_plane), >+ u_plane_(u_plane), >+ v_plane_(v_plane), >+ y_stride_(y_stride), >+ u_stride_(u_stride), >+ v_stride_(v_stride), >+ no_longer_used_cb_(no_longer_used) {} >+ >+ ~WrappedYuv16BBuffer() override { no_longer_used_cb_(); } >+ >+ int width() const override { return width_; } >+ >+ int height() const override { return height_; } >+ >+ const uint16_t* DataY() const override { return y_plane_; } >+ >+ const uint16_t* DataU() const override { return u_plane_; } >+ >+ const uint16_t* DataV() const override { return v_plane_; } >+ >+ int StrideY() const override { return y_stride_; } >+ >+ int StrideU() const override { return u_stride_; } >+ >+ int StrideV() const override { return v_stride_; } >+ >+ private: >+ friend class rtc::RefCountedObject<WrappedYuv16BBuffer>; >+ >+ const int width_; >+ const int height_; >+ const uint16_t* const y_plane_; >+ const uint16_t* const u_plane_; >+ const uint16_t* const v_plane_; >+ const int y_stride_; >+ const int u_stride_; >+ const int v_stride_; >+ rtc::Callback0<void> no_longer_used_cb_; >+}; >+ >+class I010BufferBase : public I010BufferInterface { >+ public: >+ rtc::scoped_refptr<I420BufferInterface> ToI420() final; >+}; >+ >+rtc::scoped_refptr<I420BufferInterface> I010BufferBase::ToI420() { >+ rtc::scoped_refptr<I420Buffer> i420_buffer = >+ I420Buffer::Create(width(), height()); >+ libyuv::I010ToI420(DataY(), StrideY(), DataU(), StrideU(), DataV(), StrideV(), >+ i420_buffer->MutableDataY(), i420_buffer->StrideY(), >+ i420_buffer->MutableDataU(), i420_buffer->StrideU(), >+ i420_buffer->MutableDataV(), i420_buffer->StrideV(), >+ width(), height()); >+ return i420_buffer; >+} >+ > } // namespace > > WrappedI420Buffer::WrappedI420Buffer(int width, >@@ -149,8 +220,7 @@ WrappedI420Buffer::WrappedI420Buffer(int width, > y_stride_(y_stride), > u_stride_(u_stride), > v_stride_(v_stride), >- no_longer_used_cb_(no_longer_used) { >-} >+ no_longer_used_cb_(no_longer_used) {} > > WrappedI420Buffer::~WrappedI420Buffer() { > no_longer_used_cb_(); >@@ -258,4 +328,20 @@ rtc::scoped_refptr<PlanarYuvBuffer> WrapYuvBuffer( > } > } > >+rtc::scoped_refptr<I010BufferInterface> WrapI010Buffer( >+ int width, >+ int height, >+ const uint16_t* y_plane, >+ int y_stride, >+ const uint16_t* u_plane, >+ int u_stride, >+ const uint16_t* v_plane, >+ int v_stride, >+ const rtc::Callback0<void>& no_longer_used) { >+ return rtc::scoped_refptr<I010BufferInterface>( >+ new rtc::RefCountedObject<WrappedYuv16BBuffer<I010BufferBase>>( >+ width, height, y_plane, y_stride, u_plane, u_stride, v_plane, >+ v_stride, no_longer_used)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_unittest.cc >new file mode 100644 >index 00000000000..a4b110b6b93 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_frame_unittest.cc >@@ -0,0 +1,435 @@ >+/* >+ * Copyright (c) 2018 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 <math.h> >+#include <string.h> >+ >+#include "api/video/i010_buffer.h" >+#include "api/video/i420_buffer.h" >+#include "api/video/video_frame.h" >+#include "rtc_base/bind.h" >+#include "rtc_base/timeutils.h" >+#include "test/fake_texture_frame.h" >+#include "test/frame_utils.h" >+#include "test/gtest.h" >+ >+namespace webrtc { >+ >+namespace { >+ >+// Helper class to delegate calls to appropriate container. >+class PlanarYuvBufferFactory { >+ public: >+ static rtc::scoped_refptr<PlanarYuvBuffer> Create(VideoFrameBuffer::Type type, >+ int width, >+ int height) { >+ switch (type) { >+ case VideoFrameBuffer::Type::kI420: >+ return I420Buffer::Create(width, height); >+ case VideoFrameBuffer::Type::kI010: >+ return I010Buffer::Create(width, height); >+ default: >+ RTC_NOTREACHED(); >+ } >+ return nullptr; >+ } >+ >+ static rtc::scoped_refptr<PlanarYuvBuffer> Copy(const VideoFrameBuffer& src) { >+ switch (src.type()) { >+ case VideoFrameBuffer::Type::kI420: >+ return I420Buffer::Copy(src); >+ case VideoFrameBuffer::Type::kI010: >+ return I010Buffer::Copy(*src.GetI010()); >+ default: >+ RTC_NOTREACHED(); >+ } >+ return nullptr; >+ } >+ >+ static rtc::scoped_refptr<PlanarYuvBuffer> Rotate(const VideoFrameBuffer& src, >+ VideoRotation rotation) { >+ switch (src.type()) { >+ case VideoFrameBuffer::Type::kI420: >+ return I420Buffer::Rotate(src, rotation); >+ case VideoFrameBuffer::Type::kI010: >+ return I010Buffer::Rotate(*src.GetI010(), rotation); >+ default: >+ RTC_NOTREACHED(); >+ } >+ return nullptr; >+ } >+ >+ static rtc::scoped_refptr<PlanarYuvBuffer> CropAndScaleFrom( >+ const VideoFrameBuffer& src, >+ int offset_x, >+ int offset_y, >+ int crop_width, >+ int crop_height) { >+ switch (src.type()) { >+ case VideoFrameBuffer::Type::kI420: { >+ rtc::scoped_refptr<I420Buffer> buffer = >+ I420Buffer::Create(crop_width, crop_height); >+ buffer->CropAndScaleFrom(*src.GetI420(), offset_x, offset_y, crop_width, >+ crop_height); >+ return buffer; >+ } >+ case VideoFrameBuffer::Type::kI010: { >+ rtc::scoped_refptr<I010Buffer> buffer = >+ I010Buffer::Create(crop_width, crop_height); >+ buffer->CropAndScaleFrom(*src.GetI010(), offset_x, offset_y, crop_width, >+ crop_height); >+ return buffer; >+ } >+ default: >+ RTC_NOTREACHED(); >+ } >+ return nullptr; >+ } >+ >+ static rtc::scoped_refptr<PlanarYuvBuffer> CropAndScaleFrom( >+ const VideoFrameBuffer& src, >+ int crop_width, >+ int crop_height) { >+ const int out_width = >+ std::min(src.width(), crop_width * src.height() / crop_height); >+ const int out_height = >+ std::min(src.height(), crop_height * src.width() / crop_width); >+ return CropAndScaleFrom(src, (src.width() - out_width) / 2, >+ (src.height() - out_height) / 2, out_width, >+ out_height); >+ } >+ >+ static rtc::scoped_refptr<PlanarYuvBuffer> >+ ScaleFrom(const VideoFrameBuffer& src, int crop_width, int crop_height) { >+ switch (src.type()) { >+ case VideoFrameBuffer::Type::kI420: { >+ rtc::scoped_refptr<I420Buffer> buffer = >+ I420Buffer::Create(crop_width, crop_height); >+ buffer->ScaleFrom(*src.GetI420()); >+ return buffer; >+ } >+ case VideoFrameBuffer::Type::kI010: { >+ rtc::scoped_refptr<I010Buffer> buffer = >+ I010Buffer::Create(crop_width, crop_height); >+ buffer->ScaleFrom(*src.GetI010()); >+ return buffer; >+ } >+ default: >+ RTC_NOTREACHED(); >+ } >+ return nullptr; >+ } >+}; >+ >+rtc::scoped_refptr<PlanarYuvBuffer> CreateGradient(VideoFrameBuffer::Type type, >+ int width, >+ int height) { >+ rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(width, height)); >+ // Initialize with gradient, Y = 128(x/w + y/h), U = 256 x/w, V = 256 y/h >+ for (int x = 0; x < width; x++) { >+ for (int y = 0; y < height; y++) { >+ buffer->MutableDataY()[x + y * width] = >+ 128 * (x * height + y * width) / (width * height); >+ } >+ } >+ int chroma_width = buffer->ChromaWidth(); >+ int chroma_height = buffer->ChromaHeight(); >+ for (int x = 0; x < chroma_width; x++) { >+ for (int y = 0; y < chroma_height; y++) { >+ buffer->MutableDataU()[x + y * chroma_width] = >+ 255 * x / (chroma_width - 1); >+ buffer->MutableDataV()[x + y * chroma_width] = >+ 255 * y / (chroma_height - 1); >+ } >+ } >+ if (type == VideoFrameBuffer::Type::kI420) >+ return buffer; >+ >+ RTC_DCHECK(type == VideoFrameBuffer::Type::kI010); >+ return I010Buffer::Copy(*buffer); >+} >+ >+// The offsets and sizes describe the rectangle extracted from the >+// original (gradient) frame, in relative coordinates where the >+// original frame correspond to the unit square, 0.0 <= x, y < 1.0. >+void CheckCrop(const webrtc::I420BufferInterface& frame, >+ double offset_x, >+ double offset_y, >+ double rel_width, >+ double rel_height) { >+ int width = frame.width(); >+ int height = frame.height(); >+ // Check that pixel values in the corners match the gradient used >+ // for initialization. >+ for (int i = 0; i < 2; i++) { >+ for (int j = 0; j < 2; j++) { >+ // Pixel coordinates of the corner. >+ int x = i * (width - 1); >+ int y = j * (height - 1); >+ // Relative coordinates, range 0.0 - 1.0 correspond to the >+ // size of the uncropped input frame. >+ double orig_x = offset_x + i * rel_width; >+ double orig_y = offset_y + j * rel_height; >+ >+ EXPECT_NEAR(frame.DataY()[x + y * frame.StrideY()] / 256.0, >+ (orig_x + orig_y) / 2, 0.02); >+ EXPECT_NEAR(frame.DataU()[x / 2 + (y / 2) * frame.StrideU()] / 256.0, >+ orig_x, 0.02); >+ EXPECT_NEAR(frame.DataV()[x / 2 + (y / 2) * frame.StrideV()] / 256.0, >+ orig_y, 0.02); >+ } >+ } >+} >+ >+void CheckRotate(int width, >+ int height, >+ webrtc::VideoRotation rotation, >+ const webrtc::I420BufferInterface& rotated) { >+ int rotated_width = width; >+ int rotated_height = height; >+ >+ if (rotation == kVideoRotation_90 || rotation == kVideoRotation_270) { >+ std::swap(rotated_width, rotated_height); >+ } >+ EXPECT_EQ(rotated_width, rotated.width()); >+ EXPECT_EQ(rotated_height, rotated.height()); >+ >+ // Clock-wise order (with 0,0 at top-left) >+ const struct { >+ int x; >+ int y; >+ } corners[] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}}; >+ // Corresponding corner colors of the frame produced by CreateGradient. >+ const struct { >+ int y; >+ int u; >+ int v; >+ } colors[] = {{0, 0, 0}, {127, 255, 0}, {255, 255, 255}, {127, 0, 255}}; >+ int corner_offset = static_cast<int>(rotation) / 90; >+ >+ for (int i = 0; i < 4; i++) { >+ int j = (i + corner_offset) % 4; >+ int x = corners[j].x * (rotated_width - 1); >+ int y = corners[j].y * (rotated_height - 1); >+ EXPECT_EQ(colors[i].y, rotated.DataY()[x + y * rotated.StrideY()]); >+ EXPECT_EQ(colors[i].u, >+ rotated.DataU()[(x / 2) + (y / 2) * rotated.StrideU()]); >+ EXPECT_EQ(colors[i].v, >+ rotated.DataV()[(x / 2) + (y / 2) * rotated.StrideV()]); >+ } >+} >+ >+} // namespace >+ >+TEST(TestVideoFrame, WidthHeightValues) { >+ VideoFrame frame(I420Buffer::Create(10, 10, 10, 14, 90), >+ webrtc::kVideoRotation_0, >+ 789 * rtc::kNumMicrosecsPerMillisec); >+ const int valid_value = 10; >+ EXPECT_EQ(valid_value, frame.width()); >+ EXPECT_EQ(valid_value, frame.height()); >+ frame.set_timestamp(123u); >+ EXPECT_EQ(123u, frame.timestamp()); >+ frame.set_ntp_time_ms(456); >+ EXPECT_EQ(456, frame.ntp_time_ms()); >+ EXPECT_EQ(789, frame.render_time_ms()); >+} >+ >+TEST(TestVideoFrame, ShallowCopy) { >+ uint32_t timestamp = 1; >+ int64_t ntp_time_ms = 2; >+ int64_t timestamp_us = 3; >+ int stride_y = 15; >+ int stride_u = 10; >+ int stride_v = 10; >+ int width = 15; >+ int height = 15; >+ >+ const int kSizeY = 400; >+ const int kSizeU = 100; >+ const int kSizeV = 100; >+ const VideoRotation kRotation = kVideoRotation_270; >+ uint8_t buffer_y[kSizeY]; >+ uint8_t buffer_u[kSizeU]; >+ uint8_t buffer_v[kSizeV]; >+ memset(buffer_y, 16, kSizeY); >+ memset(buffer_u, 8, kSizeU); >+ memset(buffer_v, 4, kSizeV); >+ >+ VideoFrame frame1(I420Buffer::Copy(width, height, buffer_y, stride_y, >+ buffer_u, stride_u, buffer_v, stride_v), >+ kRotation, 0); >+ frame1.set_timestamp(timestamp); >+ frame1.set_ntp_time_ms(ntp_time_ms); >+ frame1.set_timestamp_us(timestamp_us); >+ VideoFrame frame2(frame1); >+ >+ EXPECT_EQ(frame1.video_frame_buffer(), frame2.video_frame_buffer()); >+ rtc::scoped_refptr<I420BufferInterface> yuv1 = >+ frame1.video_frame_buffer()->GetI420(); >+ rtc::scoped_refptr<I420BufferInterface> yuv2 = >+ frame2.video_frame_buffer()->GetI420(); >+ EXPECT_EQ(yuv1->DataY(), yuv2->DataY()); >+ EXPECT_EQ(yuv1->DataU(), yuv2->DataU()); >+ EXPECT_EQ(yuv1->DataV(), yuv2->DataV()); >+ >+ EXPECT_EQ(frame2.timestamp(), frame1.timestamp()); >+ EXPECT_EQ(frame2.ntp_time_ms(), frame1.ntp_time_ms()); >+ EXPECT_EQ(frame2.timestamp_us(), frame1.timestamp_us()); >+ EXPECT_EQ(frame2.rotation(), frame1.rotation()); >+ >+ frame2.set_timestamp(timestamp + 1); >+ frame2.set_ntp_time_ms(ntp_time_ms + 1); >+ frame2.set_timestamp_us(timestamp_us + 1); >+ frame2.set_rotation(kVideoRotation_90); >+ >+ EXPECT_NE(frame2.timestamp(), frame1.timestamp()); >+ EXPECT_NE(frame2.ntp_time_ms(), frame1.ntp_time_ms()); >+ EXPECT_NE(frame2.timestamp_us(), frame1.timestamp_us()); >+ EXPECT_NE(frame2.rotation(), frame1.rotation()); >+} >+ >+TEST(TestVideoFrame, TextureInitialValues) { >+ VideoFrame frame = test::FakeNativeBuffer::CreateFrame( >+ 640, 480, 100, 10, webrtc::kVideoRotation_0); >+ EXPECT_EQ(640, frame.width()); >+ EXPECT_EQ(480, frame.height()); >+ EXPECT_EQ(100u, frame.timestamp()); >+ EXPECT_EQ(10, frame.render_time_ms()); >+ ASSERT_TRUE(frame.video_frame_buffer() != nullptr); >+ EXPECT_TRUE(frame.video_frame_buffer()->type() == >+ VideoFrameBuffer::Type::kNative); >+ >+ frame.set_timestamp(200); >+ EXPECT_EQ(200u, frame.timestamp()); >+ frame.set_timestamp_us(20); >+ EXPECT_EQ(20, frame.timestamp_us()); >+} >+ >+class TestPlanarYuvBuffer >+ : public ::testing::TestWithParam<VideoFrameBuffer::Type> {}; >+ >+rtc::scoped_refptr<I420Buffer> CreateAndFillBuffer() { >+ auto buf = I420Buffer::Create(20, 10); >+ memset(buf->MutableDataY(), 1, 200); >+ memset(buf->MutableDataU(), 2, 50); >+ memset(buf->MutableDataV(), 3, 50); >+ return buf; >+} >+ >+TEST_P(TestPlanarYuvBuffer, Copy) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf1; >+ switch (GetParam()) { >+ case VideoFrameBuffer::Type::kI420: { >+ buf1 = CreateAndFillBuffer(); >+ break; >+ } >+ case VideoFrameBuffer::Type::kI010: { >+ buf1 = I010Buffer::Copy(*CreateAndFillBuffer()); >+ break; >+ } >+ default: >+ RTC_NOTREACHED(); >+ } >+ >+ rtc::scoped_refptr<PlanarYuvBuffer> buf2 = >+ PlanarYuvBufferFactory::Copy(*buf1); >+ EXPECT_TRUE(test::FrameBufsEqual(buf1->ToI420(), buf2->ToI420())); >+} >+ >+TEST_P(TestPlanarYuvBuffer, Scale) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 200, 100); >+ >+ // Pure scaling, no cropping. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::ScaleFrom(*buf, 150, 75); >+ CheckCrop(*scaled_buffer->ToI420(), 0.0, 0.0, 1.0, 1.0); >+} >+ >+TEST_P(TestPlanarYuvBuffer, CropXCenter) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 200, 100); >+ >+ // Pure center cropping, no scaling. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::CropAndScaleFrom(*buf, 50, 0, 100, 100); >+ CheckCrop(*scaled_buffer->ToI420(), 0.25, 0.0, 0.5, 1.0); >+} >+ >+TEST_P(TestPlanarYuvBuffer, CropXNotCenter) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 200, 100); >+ >+ // Non-center cropping, no scaling. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::CropAndScaleFrom(*buf, 25, 0, 100, 100); >+ CheckCrop(*scaled_buffer->ToI420(), 0.125, 0.0, 0.5, 1.0); >+} >+ >+TEST_P(TestPlanarYuvBuffer, CropYCenter) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 100, 200); >+ >+ // Pure center cropping, no scaling. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::CropAndScaleFrom(*buf, 0, 50, 100, 100); >+ CheckCrop(*scaled_buffer->ToI420(), 0.0, 0.25, 1.0, 0.5); >+} >+ >+TEST_P(TestPlanarYuvBuffer, CropYNotCenter) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 100, 200); >+ >+ // Pure center cropping, no scaling. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::CropAndScaleFrom(*buf, 0, 25, 100, 100); >+ CheckCrop(*scaled_buffer->ToI420(), 0.0, 0.125, 1.0, 0.5); >+} >+ >+TEST_P(TestPlanarYuvBuffer, CropAndScale16x9) { >+ rtc::scoped_refptr<PlanarYuvBuffer> buf = >+ CreateGradient(GetParam(), 640, 480); >+ >+ // Pure center cropping, no scaling. >+ rtc::scoped_refptr<PlanarYuvBuffer> scaled_buffer = >+ PlanarYuvBufferFactory::CropAndScaleFrom(*buf, 320, 180); >+ CheckCrop(*scaled_buffer->ToI420(), 0.0, 0.125, 1.0, 0.75); >+} >+ >+INSTANTIATE_TEST_CASE_P(, >+ TestPlanarYuvBuffer, >+ ::testing::Values(VideoFrameBuffer::Type::kI420, >+ VideoFrameBuffer::Type::kI010)); >+ >+class TestPlanarYuvBufferRotate >+ : public ::testing::TestWithParam< >+ std::tuple<webrtc::VideoRotation, VideoFrameBuffer::Type>> {}; >+ >+TEST_P(TestPlanarYuvBufferRotate, Rotates) { >+ const webrtc::VideoRotation rotation = std::get<0>(GetParam()); >+ const VideoFrameBuffer::Type type = std::get<1>(GetParam()); >+ rtc::scoped_refptr<PlanarYuvBuffer> buffer = CreateGradient(type, 640, 480); >+ rtc::scoped_refptr<PlanarYuvBuffer> rotated_buffer = >+ PlanarYuvBufferFactory::Rotate(*buffer, rotation); >+ CheckRotate(640, 480, rotation, *rotated_buffer->ToI420()); >+} >+ >+INSTANTIATE_TEST_CASE_P( >+ Rotate, >+ TestPlanarYuvBufferRotate, >+ ::testing::Combine(::testing::Values(kVideoRotation_0, >+ kVideoRotation_90, >+ kVideoRotation_180, >+ kVideoRotation_270), >+ ::testing::Values(VideoFrameBuffer::Type::kI420, >+ VideoFrameBuffer::Type::kI010))); >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.cc >index 5c732df2cf8..02a105ac07a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.cc >@@ -38,6 +38,8 @@ uint32_t EnsureValidRenderDelay(uint32_t render_delay) { > VideoRenderFrames::VideoRenderFrames(uint32_t render_delay_ms) > : render_delay_ms_(EnsureValidRenderDelay(render_delay_ms)) {} > >+VideoRenderFrames::~VideoRenderFrames() = default; >+ > int32_t VideoRenderFrames::AddFrame(VideoFrame&& new_frame) { > const int64_t time_now = rtc::TimeMillis(); > >@@ -73,8 +75,8 @@ int32_t VideoRenderFrames::AddFrame(VideoFrame&& new_frame) { > return static_cast<int32_t>(incoming_frames_.size()); > } > >-rtc::Optional<VideoFrame> VideoRenderFrames::FrameToRender() { >- rtc::Optional<VideoFrame> render_frame; >+absl::optional<VideoFrame> VideoRenderFrames::FrameToRender() { >+ absl::optional<VideoFrame> render_frame; > // Get the newest frame that can be released for rendering. > while (!incoming_frames_.empty() && TimeToNextFrameRelease() <= 0) { > render_frame = std::move(incoming_frames_.front()); >@@ -88,8 +90,7 @@ uint32_t VideoRenderFrames::TimeToNextFrameRelease() { > return kEventMaxWaitTimeMs; > } > const int64_t time_to_release = incoming_frames_.front().render_time_ms() - >- render_delay_ms_ - >- rtc::TimeMillis(); >+ render_delay_ms_ - rtc::TimeMillis(); > return time_to_release < 0 ? 0u : static_cast<uint32_t>(time_to_release); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.h b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.h >index af254f2c63b..0b47e0a0586 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/common_video/video_render_frames.h >@@ -15,7 +15,7 @@ > > #include <list> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "api/video/video_frame.h" > > namespace webrtc { >@@ -25,12 +25,13 @@ class VideoRenderFrames { > public: > explicit VideoRenderFrames(uint32_t render_delay_ms); > VideoRenderFrames(const VideoRenderFrames&) = delete; >+ ~VideoRenderFrames(); > > // Add a frame to the render queue > int32_t AddFrame(VideoFrame&& new_frame); > > // Get a frame for rendering, or false if it's not time to render. >- rtc::Optional<VideoFrame> FrameToRender(); >+ absl::optional<VideoFrame> FrameToRender(); > > // Returns the number of ms to next frame to render > uint32_t TimeToNextFrameRelease(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/OWNERS >new file mode 100644 >index 00000000000..59d718ff995 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/OWNERS >@@ -0,0 +1,3 @@ >+peah@webrtc.org >+henrik.lundin@webrtc.org >+ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_fixed.pb b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_fixed.pb >new file mode 100644 >index 00000000000..2f45fd367eb >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_fixed.pb differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_float.pb b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_float.pb >new file mode 100644 >index 00000000000..1bf18c2a2a6 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/audio_processing/android/output_data_float.pb differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/common_video/jpeg/webrtc_logo.jpg b/Source/ThirdParty/libwebrtc/Source/webrtc/data/common_video/jpeg/webrtc_logo.jpg >new file mode 100644 >index 00000000000..ddb6192bc7b >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/common_video/jpeg/webrtc_logo.jpg differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Iframe.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Iframe.bin >new file mode 100644 >index 00000000000..00e3f8058ee >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Iframe.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Pframe.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Pframe.bin >new file mode 100644 >index 00000000000..57f94c3a525 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263Foreman_CIF_Pframe.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_IFRAME.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_IFRAME.bin >new file mode 100644 >index 00000000000..00e3f8058ee >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_IFRAME.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_PFRAME.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_PFRAME.bin >new file mode 100644 >index 00000000000..248f3a19834 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_CIF_PFRAME.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_QCIF_IFRAME.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_QCIF_IFRAME.bin >new file mode 100644 >index 00000000000..0fa144c9c17 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/H263_QCIF_IFRAME.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR0.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR0.bin >new file mode 100644 >index 00000000000..19df13c4d74 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR0.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR1.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR1.bin >new file mode 100644 >index 00000000000..b7b7c941ed6 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR1.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR2.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR2.bin >new file mode 100644 >index 00000000000..257835c616d >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR2.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR3.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR3.bin >new file mode 100644 >index 00000000000..4a8e375ee3f >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR3.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4.bin >new file mode 100644 >index 00000000000..28cd99ce9f1 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_1.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_1.bin >new file mode 100644 >index 00000000000..5080b88ab9f >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_1.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_2.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_2.bin >new file mode 100644 >index 00000000000..2c2f288fcb1 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR4_2.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR5.bin b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR5.bin >new file mode 100644 >index 00000000000..da7235a56eb >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/rtp_rtcp/RTCPPacketTMMBR5.bin differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16.wav >new file mode 100644 >index 00000000000..ebe91c44377 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16big_endian.pcm b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16big_endian.pcm >new file mode 100644 >index 00000000000..563e4e9932a >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16big_endian.pcm differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16noise.pcm b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16noise.pcm >new file mode 100644 >index 00000000000..a7be53779c2 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long16noise.pcm differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8.pcm b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8.pcm >new file mode 100644 >index 00000000000..85d17e5dd91 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8.pcm differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8mulaw.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8mulaw.wav >new file mode 100644 >index 00000000000..2d3d8b3ff44 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_long8mulaw.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_short16.pcm b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_short16.pcm >new file mode 100644 >index 00000000000..15a0f1811c7 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_short16.pcm differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny11.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny11.wav >new file mode 100644 >index 00000000000..6db80d536ee >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny11.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny16.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny16.wav >new file mode 100644 >index 00000000000..baab0acce59 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny16.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny22.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny22.wav >new file mode 100644 >index 00000000000..b4218679735 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny22.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny32.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny32.wav >new file mode 100644 >index 00000000000..773ac23eb2e >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny32.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny44.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny44.wav >new file mode 100644 >index 00000000000..c9faa45f504 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny44.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny8.wav b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny8.wav >new file mode 100644 >index 00000000000..d71c65e89e4 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/audio_tiny8.wav differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb.rtp >new file mode 100644 >index 00000000000..02abbc24f7f >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb_jitter.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb_jitter.rtp >new file mode 100644 >index 00000000000..4ed110b5fa8 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/HRTF_pcm16wb_jitter.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/README.txt b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/README.txt >new file mode 100644 >index 00000000000..976ac56c88b >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/README.txt >@@ -0,0 +1,4 @@ >+Use RTP Play tool with command 'rtpplay.exe -v -T -f <path>\<file.rtp> 127.0.0.1/1236' >+Example: rtpplay.exe -v -T -f hrtf_g722_1C_48.rtp 127.0.0.1/1236. >+This sends the stereo rtp file to port 1236. >+You can hear the voice getting panned from left, right and center. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48.rtp >new file mode 100644 >index 00000000000..b96d59b89fc >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48_jitterT2.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48_jitterT2.rtp >new file mode 100644 >index 00000000000..527a50a5c73 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/hrtf_g722_1C_48_jitterT2.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/rtpplay.exe b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/rtpplay.exe >new file mode 100755 >index 00000000000..6f938c8fb22 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/rtpplay.exe differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729.rtp >new file mode 100644 >index 00000000000..3c36e30786e >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729_jitter.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729_jitter.rtp >new file mode 100644 >index 00000000000..913226cc919 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_g729_jitter.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb.rtp >new file mode 100644 >index 00000000000..729b565178b >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb_jitter.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb_jitter.rtp >new file mode 100644 >index 00000000000..efa2800c132 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcm16wb_jitter.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu.rtp >new file mode 100644 >index 00000000000..bb2d93c1c47 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_jitter.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_jitter.rtp >new file mode 100644 >index 00000000000..fb7937863d0 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_jitter.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad.rtp >new file mode 100644 >index 00000000000..eebcf349854 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad_jitter.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad_jitter.rtp >new file mode 100644 >index 00000000000..5c368b4bcf9 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/stereo_pcmu_vad_jitter.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/toggling_stereo_g729_pt18_pt125.rtp b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/toggling_stereo_g729_pt18_pt125.rtp >new file mode 100644 >index 00000000000..1f713f6e813 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/data/voice_engine/stereo_rtp_files/toggling_stereo_g729_pt18_pt125.rtp differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/BUILD.gn >index eef20d4bb89..5a19a372ec0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/BUILD.gn >@@ -7,6 +7,7 @@ > # be found in the AUTHORS file in the root of the source tree. > > import("../webrtc.gni") >+ > if (is_android) { > import("//build/config/android/config.gni") > import("//build/config/android/rules.gni") >@@ -19,26 +20,33 @@ if (is_android) { > group("examples") { > # This target shall build all targets in examples. > testonly = true >- public_deps = [] >+ deps = [] > > if (is_android) { >- public_deps += [ >+ deps += [ > ":AppRTCMobile", >- ":AppRTCMobileTest", >- ":AppRTCMobileTestStubbedVideoIO", >+ ":AppRTCMobile_stubbed_video_io_test_apk", >+ ":AppRTCMobile_test_apk", >+ ":libwebrtc_unity", > ] >+ >+ # TODO(sakal): We include some code from the tests. Remove this dependency >+ # and remove this if-clause. >+ if (rtc_include_tests) { >+ deps += [ "androidnativeapi:androidnativeapi" ] >+ } > } > > if (!build_with_chromium) { >- public_deps += [ ":stun_prober" ] >+ deps += [ ":stun_prober" ] > } > > if (is_ios || (is_mac && target_cpu != "x86")) { >- public_deps += [ ":AppRTCMobile" ] >+ deps += [ ":AppRTCMobile" ] > } > > if (is_linux || is_win) { >- public_deps += [ >+ deps += [ > ":peerconnection_client", > ":peerconnection_server", > ":relayserver", >@@ -46,6 +54,10 @@ group("examples") { > ":turnserver", > ] > } >+ >+ if (is_android || is_win) { >+ deps += [ ":webrtc_unity_plugin" ] >+ } > } > > if (is_android) { >@@ -58,7 +70,6 @@ if (is_android) { > ":AppRTCMobile_javalib", > ":AppRTCMobile_resources", > "../rtc_base:base_java", >- "//base:base_java", > ] > > shared_libraries = [ "../sdk/android:libjingle_peerconnection_so" ] >@@ -66,7 +77,7 @@ if (is_android) { > > rtc_android_library("AppRTCMobile_javalib") { > testonly = true >- android_manifest = "androidapp/AndroidManifest.xml" >+ android_manifest_for_lint = "androidapp/AndroidManifest.xml" > > java_files = [ > "androidapp/src/org/appspot/apprtc/AppRTCAudioManager.java", >@@ -82,6 +93,8 @@ if (is_android) { > "androidapp/src/org/appspot/apprtc/HudFragment.java", > "androidapp/src/org/appspot/apprtc/PeerConnectionClient.java", > "androidapp/src/org/appspot/apprtc/RoomParametersFetcher.java", >+ "androidapp/src/org/appspot/apprtc/RtcEventLog.java", >+ "androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java", > "androidapp/src/org/appspot/apprtc/SettingsActivity.java", > "androidapp/src/org/appspot/apprtc/SettingsFragment.java", > "androidapp/src/org/appspot/apprtc/TCPChannelClient.java", >@@ -96,9 +109,23 @@ if (is_android) { > ":AppRTCMobile_resources", > "../modules/audio_device:audio_device_java", > "../rtc_base:base_java", >+ "../sdk/android:audio_api_java", >+ "../sdk/android:base_java", >+ "../sdk/android:camera_java", >+ "../sdk/android:default_video_codec_factory_java", >+ "../sdk/android:filevideo_java", >+ "../sdk/android:hwcodecs_java", >+ "../sdk/android:java_audio_device_module_java", > "../sdk/android:libjingle_peerconnection_java", > "../sdk/android:libjingle_peerconnection_metrics_default_java", >+ "../sdk/android:peerconnection_java", >+ "../sdk/android:screencapturer_java", >+ "../sdk/android:surfaceviewrenderer_java", >+ "../sdk/android:swcodecs_java", >+ "../sdk/android:video_api_java", >+ "../sdk/android:video_java", > "androidapp/third_party/autobanh:autobanh_java", >+ "//third_party/jsr-305:jsr_305_javalib", > ] > } > >@@ -108,23 +135,26 @@ if (is_android) { > custom_package = "org.appspot.apprtc" > } > >- rtc_instrumentation_test_apk("AppRTCMobileTest") { >+ rtc_instrumentation_test_apk("AppRTCMobile_test_apk") { > apk_name = "AppRTCMobileTest" > android_manifest = "androidtests/AndroidManifest.xml" > >- java_files = [ "androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java" ] >+ java_files = [ >+ "androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java", >+ ] > > apk_under_test = ":AppRTCMobile" > > deps = [ > ":AppRTCMobile_javalib", > "../sdk/android:libjingle_peerconnection_java", >+ "../sdk/android:video_java", > "//third_party/android_support_test_runner:runner_java", > "//third_party/junit", > ] > } > >- rtc_instrumentation_test_apk("AppRTCMobileTestStubbedVideoIO") { >+ rtc_instrumentation_test_apk("AppRTCMobile_stubbed_video_io_test_apk") { > apk_name = "AppRTCMobileTestStubbedVideoIO" > android_manifest = "androidtests/AndroidManifest.xml" > >@@ -143,7 +173,19 @@ if (is_android) { > ] > > data = [ >+ "../build/android/adb_reverse_forwarder.py", >+ "../examples/androidtests/video_quality_loopback_test.py", > "../resources/reference_video_640x360_30fps.y4m", >+ "../rtc_tools/barcode_tools/barcode_decoder.py", >+ "../rtc_tools/barcode_tools/helper_functions.py", >+ "../rtc_tools/compare_videos.py", >+ "../rtc_tools/testing/prebuilt_apprtc.zip", >+ "../rtc_tools/testing/golang/linux/go.tar.gz", >+ "../rtc_tools/testing/build_apprtc.py", >+ "../rtc_tools/testing/utils.py", >+ "../tools_webrtc/video_quality_toolchain/linux/ffmpeg", >+ "../tools_webrtc/video_quality_toolchain/linux/frame_analyzer", >+ "../tools_webrtc/video_quality_toolchain/linux/zxing", > ] > } > } >@@ -162,28 +204,27 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > public_configs = [ ":apprtc_common_config" ] > > if (is_ios) { >+ # iOS must use WebRTC.framework which is dynamically linked. >+ # 'gn check' is disabled in order to avoid confusion and >+ # errors caused by multiple implementations. >+ check_includes = false > deps = [ >- ":AppRTCMobile_ios_frameworks", >+ "../sdk:framework_objc", >+ "../system_wrappers:field_trial_default", >+ "../system_wrappers:runtime_enabled_features_default", > ] > } else { > deps = [ > "../sdk:common_objc", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", > ] > } > } > > config("apprtc_signaling_config") { > include_dirs = [ "objc/AppRTCMobile" ] >- >- # GN orders flags on a target before flags from configs. The default config >- # adds these flags so to cancel them out they need to come from a config and >- # cannot be on the target directly. >- cflags = [ >- "-Wno-sign-compare", >- "-Wno-unused-variable", >- ] > } > > rtc_static_library("apprtc_signaling") { >@@ -198,6 +239,8 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > "objc/AppRTCMobile/ARDBitrateTracker.m", > "objc/AppRTCMobile/ARDCaptureController.h", > "objc/AppRTCMobile/ARDCaptureController.m", >+ "objc/AppRTCMobile/ARDExternalSampleCapturer.h", >+ "objc/AppRTCMobile/ARDExternalSampleCapturer.m", > "objc/AppRTCMobile/ARDJoinResponse+Internal.h", > "objc/AppRTCMobile/ARDJoinResponse.h", > "objc/AppRTCMobile/ARDJoinResponse.m", >@@ -235,10 +278,23 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > ":socketrocket", > ] > if (is_ios) { >- deps += [ ":AppRTCMobile_ios_frameworks" ] >+ # iOS must use WebRTC.framework which is dynamically linked. >+ # 'gn check' is disabled in order to avoid confusion and >+ # errors caused by multiple implementations. >+ check_includes = false >+ deps += [ >+ ":AppRTCMobile_ios_frameworks", >+ "../sdk:framework_objc", >+ ] > } else { >- public_deps = [ >- "../sdk:peerconnection_objc", >+ deps += [ >+ "../sdk:common_objc", >+ "../sdk:mediaconstraints_objc", >+ "../sdk:peerconnectionfactory_base_objc", >+ "../sdk:videocapture_objc", >+ "../sdk:videocodec_objc", >+ "../sdk:videoframebuffer_objc", >+ "../sdk:videosource_objc", > ] > } > libs = [ "QuartzCore.framework" ] >@@ -246,8 +302,13 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > > if (is_ios) { > rtc_static_library("AppRTCMobile_lib") { >+ # iOS must use WebRTC.framework which is dynamically linked. >+ # 'gn check' is disabled in order to avoid confusion and >+ # errors caused by multiple implementations. >+ check_includes = false > testonly = true > sources = [ >+ "objc/AppRTCMobile/ios/ARDAppDelegate.h", > "objc/AppRTCMobile/ios/ARDAppDelegate.m", > "objc/AppRTCMobile/ios/ARDFileCaptureController.h", > "objc/AppRTCMobile/ios/ARDFileCaptureController.m", >@@ -273,6 +334,7 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > ":AppRTCMobile_ios_frameworks", > ":apprtc_common", > ":apprtc_signaling", >+ "../sdk:framework_objc", > ] > } > >@@ -291,15 +353,96 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > ":AppRTCMobile_ios_bundle_data", > ":AppRTCMobile_ios_frameworks", > ":AppRTCMobile_lib", >+ "../sdk:framework_objc", > ] > >+ if (rtc_apprtcmobile_broadcast_extension) { >+ deps += [ >+ ":AppRTCMobileBroadcastSetupUI_extension_bundle", >+ ":AppRTCMobileBroadcastUpload_extension_bundle", >+ ] >+ } >+ > if (target_cpu == "x86") { > deps += [ "//testing/iossim:iossim" ] > } > } > >+ if (rtc_apprtcmobile_broadcast_extension) { >+ bundle_data("AppRTCMobileBroadcastUpload_extension_bundle") { >+ testonly = true >+ public_deps = [ >+ ":AppRTCMobileBroadcastUpload", >+ ] >+ sources = [ >+ "$root_out_dir/AppRTCMobileBroadcastUpload.appex", >+ ] >+ outputs = [ >+ "{{bundle_plugins_dir}}/{{source_file_part}}", >+ ] >+ } >+ >+ bundle_data("AppRTCMobileBroadcastSetupUI_extension_bundle") { >+ testonly = true >+ public_deps = [ >+ ":AppRTCMobileBroadcastSetupUI", >+ ] >+ sources = [ >+ "$root_out_dir/AppRTCMobileBroadcastSetupUI.appex", >+ ] >+ outputs = [ >+ "{{bundle_plugins_dir}}/{{source_file_part}}", >+ ] >+ } >+ >+ rtc_static_library("AppRTCMobileBroadcastUpload_lib") { >+ check_includes = false >+ testonly = true >+ sources = [ >+ "objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.h", >+ "objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m", >+ ] >+ >+ deps = [ >+ ":AppRTCMobile_ios_frameworks", >+ ":apprtc_signaling", >+ "../sdk:framework_objc", >+ ] >+ >+ libs = [ "ReplayKit.framework" ] >+ } >+ >+ ios_appex_bundle("AppRTCMobileBroadcastUpload") { >+ testonly = true >+ configs += [ "..:common_config" ] >+ public_configs = [ "..:common_inherited_config" ] >+ >+ info_plist = "objc/AppRTCMobile/ios/broadcast_extension/BroadcastUploadInfo.plist" >+ >+ deps = [ >+ ":AppRTCMobileBroadcastUpload_lib", >+ "../sdk:framework_objc", >+ ] >+ } >+ >+ ios_appex_bundle("AppRTCMobileBroadcastSetupUI") { >+ sources = [ >+ "objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.h", >+ "objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.m", >+ ] >+ >+ info_plist = "objc/AppRTCMobile/ios/broadcast_extension/BroadcastSetupUIInfo.plist" >+ >+ libs = [ "ReplayKit.framework" ] >+ >+ deps = [ >+ ":AppRTCMobile_ios_bundle_data", >+ ] >+ } >+ } >+ > bundle_data("AppRTCMobile_ios_frameworks") { >- public_deps = [ >+ deps = [ > "../sdk:framework_objc+link", > ] > sources = [ >@@ -338,6 +481,67 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > "{{bundle_resources_dir}}/{{source_file_part}}", > ] > } >+ >+ rtc_static_library("ObjCNativeAPIDemo_lib") { >+ testonly = true >+ sources = [ >+ "objcnativeapi/objc/NADAppDelegate.h", >+ "objcnativeapi/objc/NADAppDelegate.m", >+ "objcnativeapi/objc/NADViewController.h", >+ "objcnativeapi/objc/NADViewController.mm", >+ "objcnativeapi/objc/objccallclient.h", >+ "objcnativeapi/objc/objccallclient.mm", >+ ] >+ >+ if (!build_with_chromium && is_clang) { >+ # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >+ suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ } >+ >+ deps = [ >+ "../api:libjingle_peerconnection_api", >+ "../api/audio_codecs:builtin_audio_decoder_factory", >+ "../api/audio_codecs:builtin_audio_encoder_factory", >+ "../logging:rtc_event_log_impl_base", >+ "../media:rtc_audio_video", >+ "../modules/audio_processing:audio_processing", >+ "../pc:libjingle_peerconnection", >+ "../rtc_base:rtc_base", >+ "../sdk:default_codec_factory_objc", >+ "../sdk:framework_objc", >+ "../sdk:native_api", >+ "../sdk:ui_objc", >+ "../sdk:videotoolbox_objc", >+ "../system_wrappers:field_trial_default", >+ "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+ >+ if (current_cpu == "arm64") { >+ deps += [ "../sdk:metal_objc" ] >+ } >+ } >+ >+ ios_app_bundle("ObjCNativeAPIDemo") { >+ testonly = true >+ sources = [ >+ "objcnativeapi/objc/main.m", >+ ] >+ >+ info_plist = "objcnativeapi/Info.plist" >+ >+ configs += [ "..:common_config" ] >+ public_configs = [ "..:common_inherited_config" ] >+ >+ deps = [ >+ ":ObjCNativeAPIDemo_lib", >+ ] >+ >+ if (target_cpu == "x86") { >+ deps += [ "//testing/iossim:iossim" ] >+ } >+ } > } > > if (is_mac) { >@@ -353,7 +557,14 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > deps = [ > ":apprtc_common", > ":apprtc_signaling", >+ "../sdk:default_codec_factory_objc", >+ "../sdk:metal_objc", >+ "../sdk:peerconnectionfactory_base_objc", > "../sdk:ui_objc", >+ "../sdk:videocapture_objc", >+ "../sdk:videocodec_objc", >+ "../sdk:videocodec_objc", >+ "../sdk:videotoolbox_objc", > ] > } > >@@ -417,6 +628,10 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > # TODO(kthelgason): compile xctests on mac when chromium supports it. > if (is_ios) { > rtc_source_set("apprtcmobile_test_sources") { >+ # iOS must use WebRTC.framework which is dynamically linked. >+ # 'gn check' is disabled in order to avoid confusion and >+ # errors caused by multiple implementations. >+ check_includes = false > testonly = true > include_dirs = [ > "objc/AppRTCMobile", >@@ -429,11 +644,11 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > "objc/AppRTCMobile/tests/ARDSettingsModel_xctest.mm", > ] > deps = [ >- "../rtc_base:rtc_base", >- ] >- public_deps = [ > ":AppRTCMobile_ios_frameworks", > ":AppRTCMobile_lib", >+ ":apprtc_signaling", >+ "../rtc_base:rtc_base", >+ "../sdk:framework_objc", > "//build/config/ios:xctest", > "//third_party/ocmock", > ] >@@ -445,7 +660,9 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > "objc/AppRTCMobile/ios/main.m", > ] > deps = [ >+ ":AppRTCMobile_lib", > ":apprtcmobile_test_sources", >+ "../sdk:framework_objc", > ] > ldflags = [ "-all_load" ] > } >@@ -454,35 +671,6 @@ if (is_ios || (is_mac && target_cpu != "x86")) { > } > > if (is_linux || is_win) { >- config("peerconnection_client_warnings_config") { >- cflags = [] >- if (is_win && is_clang) { >- cflags += [ >- # Disable warnings failing when compiling with Clang on Windows. >- # https://bugs.chromium.org/p/webrtc/issues/detail?id=5366 >- "-Wno-format", >- >- # See https://bugs.chromium.org/p/webrtc/issues/detail?id=6271 >- # for -Wno-reorder and -Wno-sign-compare >- "-Wno-reorder", >- "-Wno-sign-compare", >- ] >- } >- if (is_linux && target_cpu == "x86") { >- cflags += [ >- # Needed to compile on Linux 32-bit. >- "-Wno-sentinel", >- ] >- } >- >- if (is_clang) { >- # TODO(ehmaldonado): Make peerconnection_client compile with the standard >- # set of warnings. >- # See https://bugs.chromium.org/p/webrtc/issues/detail?id=6306 >- cflags += [ "-Wno-inconsistent-missing-override" ] >- } >- } >- > rtc_executable("peerconnection_client") { > testonly = true > sources = [ >@@ -499,7 +687,11 @@ if (is_linux || is_win) { > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > deps = [ >- "../api:video_frame_api_i420", >+ "../api:libjingle_peerconnection_api", >+ "../api/video:video_frame_i420", >+ "../rtc_base:checks", >+ "../rtc_base:stringutils", >+ "../rtc_base/third_party/sigslot", > ] > if (is_win) { > sources += [ >@@ -508,7 +700,6 @@ if (is_linux || is_win) { > "peerconnection/client/main_wnd.cc", > "peerconnection/client/main_wnd.h", > ] >- cflags = [ "/wd4245" ] > configs += [ "//build/config/win:windowed" ] > deps += [ "../media:rtc_media_base" ] > } >@@ -527,14 +718,18 @@ if (is_linux || is_win) { > ] > deps += [ "//build/config/linux/gtk" ] > } >- configs += [ ":peerconnection_client_warnings_config" ] > > deps += [ >+ "../api:libjingle_peerconnection_api", > "../api:libjingle_peerconnection_test_api", >- "../api:video_frame_api", > "../api/audio_codecs:builtin_audio_decoder_factory", > "../api/audio_codecs:builtin_audio_encoder_factory", >- "../media:rtc_media", >+ "../api/video:video_frame", >+ "../api/video_codecs:builtin_video_decoder_factory", >+ "../api/video_codecs:builtin_video_encoder_factory", >+ "../media:rtc_audio_video", >+ "../modules/audio_device:audio_device", >+ "../modules/audio_processing:audio_processing", > "../modules/video_capture:video_capture_module", > "../pc:libjingle_peerconnection", > "../rtc_base:rtc_base", >@@ -542,6 +737,7 @@ if (is_linux || is_win) { > "../rtc_base:rtc_json", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", > "//third_party/libyuv", > ] > } >@@ -560,6 +756,7 @@ if (is_linux || is_win) { > deps = [ > "..:webrtc_common", > "../rtc_base:rtc_base_approved", >+ "../rtc_base:stringutils", > "../rtc_tools:command_line_parser", > ] > if (!build_with_chromium && is_clang) { >@@ -579,6 +776,7 @@ if (is_linux || is_win) { > "../rtc_base:rtc_base_approved", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -597,6 +795,7 @@ if (is_linux || is_win) { > "../rtc_base:rtc_base_approved", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -615,6 +814,7 @@ if (is_linux || is_win) { > "../rtc_base:rtc_base_approved", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >@@ -641,6 +841,7 @@ if (is_win || is_android) { > "unityplugin/classreferenceholder.h", > "unityplugin/jni_onload.cc", > ] >+ suppressed_configs += [ "//build/config/android:hide_all_but_jni_onload" ] > } > > if (!build_with_chromium && is_clang) { >@@ -648,25 +849,33 @@ if (is_win || is_android) { > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > if (is_win) { >- cflags = [ "/wd4245" ] >- configs += [ >- "//build/config/win:windowed", >- ":peerconnection_client_warnings_config", >- ] >+ configs += [ "//build/config/win:windowed" ] > } > deps = [ >+ "../api:libjingle_peerconnection_api", > "../api:libjingle_peerconnection_test_api", >- "../api:video_frame_api", >+ "../api/audio_codecs:builtin_audio_decoder_factory", >+ "../api/audio_codecs:builtin_audio_encoder_factory", >+ "../api/video:video_frame", >+ "../media:rtc_audio_video", >+ "../media:rtc_internal_video_codecs", > "../media:rtc_media", > "../media:rtc_media_base", >+ "../modules/audio_device:audio_device", >+ "../modules/audio_processing:audio_processing", > "../modules/video_capture:video_capture_module", > "../pc:libjingle_peerconnection", > "../rtc_base:rtc_base", > "../system_wrappers:field_trial_default", > "../system_wrappers:metrics_default", >+ "../system_wrappers:runtime_enabled_features_default", >+ "//third_party/abseil-cpp/absl/memory", > ] > if (is_android) { >- deps += [ "../sdk/android:libjingle_peerconnection_jni" ] >+ deps += [ >+ "../modules/utility:utility", >+ "../sdk/android:libjingle_peerconnection_jni", >+ ] > } > } > } >@@ -683,8 +892,9 @@ if (is_android) { > dist_jar("libwebrtc_unity") { > _target_dir_name = get_label_info(":$target_name", "dir") > output = "${root_out_dir}/lib.java${_target_dir_name}/${target_name}.jar" >- direct_deps_only = true >+ direct_deps_only = false > use_interface_jars = false >+ use_unprocessed_jars = false > requires_android = true > deps = [ > ":webrtc_unity_java", >@@ -713,8 +923,10 @@ if (!build_with_chromium) { > deps = [ > "../p2p:libstunprober", > "../p2p:rtc_p2p", >+ "../rtc_base:checks", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >+ "../rtc_base:stringutils", > "../system_wrappers:field_trial_default", > ] > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/DEPS >index 4ade6af1054..15702200975 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/DEPS >@@ -1,9 +1,13 @@ > include_rules = [ > "+WebRTC", > "+api", >+ "+common_video", > "+media", > "+modules/audio_device", > "+modules/video_capture", >+ "+modules/audio_processing", > "+p2p", > "+pc", >+ "+sdk/objc/Framework/Native/api", >+ "+third_party/libyuv", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.gitignore.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.gitignore.rej >deleted file mode 100644 >index bb40f75ab3e..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.gitignore.rej >+++ /dev/null >@@ -1,18 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.gitignore b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.gitignore (rejected hunks) >-@@ -0,0 +1,16 @@ >-+# Default ignores by Android Studio >-+*.iml >-+.gradle >-+# We want to specify our own SDK. >-+# /local.properties >-+/.idea/workspace.xml >-+/.idea/libraries >-+.DS_Store >-+/build >-+/captures >-+.externalNativeBuild >-+ >-+# Additional ignores >-+/gradlew >-+/gradlew.bat >-+/gradle >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/encodings.xml.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/encodings.xml.rej >deleted file mode 100644 >index d1a368af363..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/encodings.xml.rej >+++ /dev/null >@@ -1,9 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/encodings.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/encodings.xml (rejected hunks) >-@@ -0,0 +1,6 @@ >-+<?xml version="1.0" encoding="UTF-8"?> >-+<project version="4"> >-+ <component name="Encoding"> >-+ <file url="PROJECT" charset="UTF-8" /> >-+ </component> >-+</project> >-\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/gradle.xml.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/gradle.xml.rej >deleted file mode 100644 >index c8ae0e7b7b2..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/gradle.xml.rej >+++ /dev/null >@@ -1,21 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/gradle.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/gradle.xml (rejected hunks) >-@@ -0,0 +1,18 @@ >-+<?xml version="1.0" encoding="UTF-8"?> >-+<project version="4"> >-+ <component name="GradleSettings"> >-+ <option name="linkedExternalProjectsSettings"> >-+ <GradleProjectSettings> >-+ <option name="distributionType" value="DEFAULT_WRAPPED" /> >-+ <option name="externalProjectPath" value="$PROJECT_DIR$" /> >-+ <option name="modules"> >-+ <set> >-+ <option value="$PROJECT_DIR$" /> >-+ <option value="$PROJECT_DIR$/app" /> >-+ </set> >-+ </option> >-+ <option name="resolveModulePerSourceSet" value="false" /> >-+ </GradleProjectSettings> >-+ </option> >-+ </component> >-+</project> >-\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/misc.xml.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/misc.xml.rej >deleted file mode 100644 >index 78ad0ae47ac..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/misc.xml.rej >+++ /dev/null >@@ -1,36 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/misc.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/misc.xml (rejected hunks) >-@@ -0,0 +1,33 @@ >-+<?xml version="1.0" encoding="UTF-8"?> >-+<project version="4"> >-+ <component name="NullableNotNullManager"> >-+ <option name="myDefaultNullable" value="android.support.annotation.Nullable" /> >-+ <option name="myDefaultNotNull" value="android.support.annotation.NonNull" /> >-+ <option name="myNullables"> >-+ <value> >-+ <list size="4"> >-+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" /> >-+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" /> >-+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" /> >-+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" /> >-+ </list> >-+ </value> >-+ </option> >-+ <option name="myNotNulls"> >-+ <value> >-+ <list size="4"> >-+ <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" /> >-+ <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" /> >-+ <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" /> >-+ <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" /> >-+ </list> >-+ </value> >-+ </option> >-+ </component> >-+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK"> >-+ <output url="file://$PROJECT_DIR$/build/classes" /> >-+ </component> >-+ <component name="ProjectType"> >-+ <option name="id" value="Android" /> >-+ </component> >-+</project> >-\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/modules.xml.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/modules.xml.rej >deleted file mode 100644 >index 3ca43f07ea7..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/modules.xml.rej >+++ /dev/null >@@ -1,12 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/modules.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/modules.xml (rejected hunks) >-@@ -0,0 +1,9 @@ >-+<?xml version="1.0" encoding="UTF-8"?> >-+<project version="4"> >-+ <component name="ProjectModuleManager"> >-+ <modules> >-+ <module fileurl="file://$PROJECT_DIR$/aarproject.iml" filepath="$PROJECT_DIR$/aarproject.iml" /> >-+ <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> >-+ </modules> >-+ </component> >-+</project> >-\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/runConfigurations.xml.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/runConfigurations.xml.rej >deleted file mode 100644 >index 29c687fe1b6..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/runConfigurations.xml.rej >+++ /dev/null >@@ -1,15 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/runConfigurations.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/.idea/runConfigurations.xml (rejected hunks) >-@@ -0,0 +1,12 @@ >-+<?xml version="1.0" encoding="UTF-8"?> >-+<project version="4"> >-+ <component name="RunConfigurationProducerService"> >-+ <option name="ignoredProducers"> >-+ <set> >-+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> >-+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> >-+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> >-+ </set> >-+ </option> >-+ </component> >-+</project> >-\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/.gitignore.rej b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/.gitignore.rej >deleted file mode 100644 >index 9071603f0da..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/.gitignore.rej >+++ /dev/null >@@ -1,3 +0,0 @@ >-diff a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/.gitignore b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/.gitignore (rejected hunks) >-@@ -0,0 +1 @@ >-+/build >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/build.gradle b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/build.gradle >index 1dd15112d6a..ca9793fc3a0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/build.gradle >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/aarproject/app/build.gradle >@@ -1,8 +1,8 @@ > apply plugin: 'com.android.application' > > android { >- compileSdkVersion 26 >- buildToolsVersion "26.0.0" >+ compileSdkVersion 27 >+ buildToolsVersion "27.0.1" > defaultConfig { > applicationId "org.appspot.apprtc" > minSdkVersion 16 >@@ -46,6 +46,7 @@ dependencies { > implementation fileTree(dir: 'libs', include: ['*.jar']) > implementation fileTree(dir: '../../androidapp/third_party/autobanh/lib', include: ['autobanh.jar']) > implementation 'com.android.support:appcompat-v7:26.1.0' >+ implementation 'com.google.code.findbugs:jsr305:3.0.2' > implementation 'org.webrtc:google-webrtc:1.0.+' > testImplementation 'junit:junit:4.12' > androidTestImplementation 'com.android.support.test:runner:1.0.1' >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/values/strings.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/values/strings.xml >index 231475f587f..9006dc1cc7b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/values/strings.xml >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/values/strings.xml >@@ -125,6 +125,11 @@ > <string name="pref_aecdump_dlg">Enable diagnostic audio recordings.</string> > <string name="pref_aecdump_default">false</string> > >+ <string name="pref_enable_save_input_audio_to_file_key">enable_key</string> >+ <string name="pref_enable_save_input_audio_to_file_title">Save input audio to file.</string> >+ <string name="pref_enable_save_input_audio_to_file_dlg">Save input audio to file.</string> >+ <string name="pref_enable_save_input_audio_to_file_default">false</string> >+ > <string name="pref_opensles_key">opensles_preference</string> > <string name="pref_opensles_title">Use OpenSL ES for audio playback.</string> > <string name="pref_opensles_dlg">Use OpenSL ES for audio playback.</string> >@@ -148,10 +153,6 @@ > <string name="pref_disable_built_in_ns_default">false</string> > <string name="pref_built_in_ns_not_available">Hardware NS is not available</string> > >- <string name="pref_enable_level_control_key">enable_level_control_preference</string> >- <string name="pref_enable_level_control_title">Enable level control.</string> >- <string name="pref_enable_level_control_default">false</string> >- > <string name="pref_disable_webrtc_agc_and_hpf_key">disable_webrtc_agc_and_hpf_preference</string> > <string name="pref_disable_webrtc_agc_and_hpf_title">Disable WebRTC AGC and HPF.</string> > <string name="pref_disable_webrtc_agc_default">false</string> >@@ -213,4 +214,12 @@ > <string name="pref_tracing_title">Debug performance tracing.</string> > <string name="pref_tracing_dlg">Debug performance tracing.</string> > <string name="pref_tracing_default" translatable="false">false</string> >+ >+ <string name="pref_enable_rtceventlog_key">enable_rtceventlog_key</string> >+ <string name="pref_enable_rtceventlog_title">Enable RtcEventLog.</string> >+ <string name="pref_enable_rtceventlog_default">false</string> >+ >+ <string name="pref_use_legacy_audio_device_key">use_legacy_audio_device_key</string> >+ <string name="pref_use_legacy_audio_device_title">Use legacy audio device.</string> >+ <string name="pref_use_legacy_audio_device_default">false</string> > </resources> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/xml/preferences.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/xml/preferences.xml >index c9fe750d9e2..ffe2daa8f57 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/xml/preferences.xml >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/res/xml/preferences.xml >@@ -123,6 +123,12 @@ > android:dialogTitle="@string/pref_aecdump_dlg" > android:defaultValue="@string/pref_aecdump_default" /> > >+ <CheckBoxPreference >+ android:key="@string/pref_enable_save_input_audio_to_file_key" >+ android:title="@string/pref_enable_save_input_audio_to_file_title" >+ android:dialogTitle="@string/pref_enable_save_input_audio_to_file_dlg" >+ android:defaultValue="@string/pref_enable_save_input_audio_to_file_default" /> >+ > <CheckBoxPreference > android:key="@string/pref_opensles_key" > android:title="@string/pref_opensles_title" >@@ -147,11 +153,6 @@ > android:dialogTitle="@string/pref_disable_built_in_ns_dlg" > android:defaultValue="@string/pref_disable_built_in_ns_default" /> > >- <CheckBoxPreference >- android:key="@string/pref_enable_level_control_key" >- android:title="@string/pref_enable_level_control_title" >- android:defaultValue="@string/pref_enable_level_control_default" /> >- > <CheckBoxPreference > android:key="@string/pref_disable_webrtc_agc_and_hpf_key" > android:title="@string/pref_disable_webrtc_agc_and_hpf_title" >@@ -164,6 +165,11 @@ > android:dialogTitle="@string/pref_speakerphone_dlg" > android:entries="@array/speakerphone" > android:entryValues="@array/speakerphoneValues" /> >+ >+ <CheckBoxPreference >+ android:key="@string/pref_use_legacy_audio_device_key" >+ android:title="@string/pref_use_legacy_audio_device_title" >+ android:defaultValue="@string/pref_use_legacy_audio_device_default" /> > </PreferenceCategory> > > <PreferenceCategory >@@ -229,13 +235,18 @@ > android:key="@string/pref_displayhud_key" > android:title="@string/pref_displayhud_title" > android:dialogTitle="@string/pref_displayhud_dlg" >- android:defaultValue="@string/pref_displayhud_default" /> >+ android:defaultValue="@string/pref_displayhud_default" /> > > <CheckBoxPreference > android:key="@string/pref_tracing_key" > android:title="@string/pref_tracing_title" > android:dialogTitle="@string/pref_tracing_dlg" >- android:defaultValue="@string/pref_tracing_default" /> >+ android:defaultValue="@string/pref_tracing_default" /> >+ >+ <CheckBoxPreference >+ android:key="@string/pref_enable_rtceventlog_key" >+ android:title="@string/pref_enable_rtceventlog_title" >+ android:defaultValue="@string/pref_enable_rtceventlog_default"/> > </PreferenceCategory> > > </PreferenceScreen> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCAudioManager.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCAudioManager.java >index 5418ca0c311..aff198e88cd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCAudioManager.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCAudioManager.java >@@ -24,6 +24,7 @@ import android.util.Log; > import java.util.Collections; > import java.util.HashSet; > import java.util.Set; >+import javax.annotation.Nullable; > import org.appspot.apprtc.util.AppRTCUtils; > import org.webrtc.ThreadUtils; > >@@ -57,8 +58,10 @@ public class AppRTCAudioManager { > } > > private final Context apprtcContext; >+ @Nullable > private AudioManager audioManager; > >+ @Nullable > private AudioManagerEvents audioManagerEvents; > private AudioManagerState amState; > private int savedAudioMode = AudioManager.MODE_INVALID; >@@ -90,6 +93,7 @@ public class AppRTCAudioManager { > // relative to the view screen of a device and can therefore be used to > // assist device switching (close to ear <=> use headset earpiece if > // available, far from ear <=> use speaker phone). >+ @Nullable > private AppRTCProximitySensor proximitySensor = null; > > // Handles all tasks related to Bluetooth headset devices. >@@ -103,6 +107,7 @@ public class AppRTCAudioManager { > private BroadcastReceiver wiredHeadsetReceiver; > > // Callback method for changes in audio focus. >+ @Nullable > private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener; > > /** >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCBluetoothManager.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCBluetoothManager.java >index 00e6b04e418..6720e927c1c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCBluetoothManager.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCBluetoothManager.java >@@ -24,6 +24,7 @@ import android.media.AudioManager; > import android.os.Handler; > import android.os.Looper; > import android.os.Process; >+import javax.annotation.Nullable; > import android.util.Log; > import java.util.List; > import java.util.Set; >@@ -64,14 +65,18 @@ public class AppRTCBluetoothManager { > > private final Context apprtcContext; > private final AppRTCAudioManager apprtcAudioManager; >+ @Nullable > private final AudioManager audioManager; > private final Handler handler; > > int scoConnectionAttempts; > private State bluetoothState; > private final BluetoothProfile.ServiceListener bluetoothServiceListener; >+ @Nullable > private BluetoothAdapter bluetoothAdapter; >+ @Nullable > private BluetoothHeadset bluetoothHeadset; >+ @Nullable > private BluetoothDevice bluetoothDevice; > private final BroadcastReceiver bluetoothHeadsetReceiver; > >@@ -390,6 +395,7 @@ public class AppRTCBluetoothManager { > /** > * Stubs for test mocks. > */ >+ @Nullable > protected AudioManager getAudioManager(Context context) { > return (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCProximitySensor.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCProximitySensor.java >index b63e8b867f5..ac03a8025ef 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCProximitySensor.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/AppRTCProximitySensor.java >@@ -16,6 +16,7 @@ import android.hardware.SensorEvent; > import android.hardware.SensorEventListener; > import android.hardware.SensorManager; > import android.os.Build; >+import javax.annotation.Nullable; > import android.util.Log; > import org.appspot.apprtc.util.AppRTCUtils; > import org.webrtc.ThreadUtils; >@@ -39,6 +40,7 @@ public class AppRTCProximitySensor implements SensorEventListener { > > private final Runnable onSensorStateListener; > private final SensorManager sensorManager; >+ @Nullable > private Sensor proximitySensor = null; > private boolean lastStateReportIsNear = false; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java >index dabff97de5b..b66b91c39c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CallActivity.java >@@ -36,6 +36,7 @@ import java.lang.RuntimeException; > import java.util.ArrayList; > import java.util.List; > import java.util.Set; >+import javax.annotation.Nullable; > import org.appspot.apprtc.AppRTCAudioManager.AudioDevice; > import org.appspot.apprtc.AppRTCAudioManager.AudioManagerEvents; > import org.appspot.apprtc.AppRTCClient.RoomConnectionParameters; >@@ -45,6 +46,7 @@ import org.appspot.apprtc.PeerConnectionClient.PeerConnectionParameters; > import org.webrtc.Camera1Enumerator; > import org.webrtc.Camera2Enumerator; > import org.webrtc.CameraEnumerator; >+import org.webrtc.EglBase; > import org.webrtc.FileVideoCapturer; > import org.webrtc.IceCandidate; > import org.webrtc.Logging; >@@ -57,7 +59,6 @@ import org.webrtc.SurfaceViewRenderer; > import org.webrtc.VideoCapturer; > import org.webrtc.VideoFileRenderer; > import org.webrtc.VideoFrame; >-import org.webrtc.VideoRenderer; > import org.webrtc.VideoSink; > > /** >@@ -90,11 +91,12 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > public static final String EXTRA_NOAUDIOPROCESSING_ENABLED = > "org.appspot.apprtc.NOAUDIOPROCESSING"; > public static final String EXTRA_AECDUMP_ENABLED = "org.appspot.apprtc.AECDUMP"; >+ public static final String EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED = >+ "org.appspot.apprtc.SAVE_INPUT_AUDIO_TO_FILE"; > public static final String EXTRA_OPENSLES_ENABLED = "org.appspot.apprtc.OPENSLES"; > public static final String EXTRA_DISABLE_BUILT_IN_AEC = "org.appspot.apprtc.DISABLE_BUILT_IN_AEC"; > public static final String EXTRA_DISABLE_BUILT_IN_AGC = "org.appspot.apprtc.DISABLE_BUILT_IN_AGC"; > public static final String EXTRA_DISABLE_BUILT_IN_NS = "org.appspot.apprtc.DISABLE_BUILT_IN_NS"; >- public static final String EXTRA_ENABLE_LEVEL_CONTROL = "org.appspot.apprtc.ENABLE_LEVEL_CONTROL"; > public static final String EXTRA_DISABLE_WEBRTC_AGC_AND_HPF = > "org.appspot.apprtc.DISABLE_WEBRTC_GAIN_CONTROL"; > public static final String EXTRA_DISPLAY_HUD = "org.appspot.apprtc.DISPLAY_HUD"; >@@ -117,6 +119,9 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > public static final String EXTRA_PROTOCOL = "org.appspot.apprtc.PROTOCOL"; > public static final String EXTRA_NEGOTIATED = "org.appspot.apprtc.NEGOTIATED"; > public static final String EXTRA_ID = "org.appspot.apprtc.ID"; >+ public static final String EXTRA_ENABLE_RTCEVENTLOG = "org.appspot.apprtc.ENABLE_RTCEVENTLOG"; >+ public static final String EXTRA_USE_LEGACY_AUDIO_DEVICE = >+ "org.appspot.apprtc.USE_LEGACY_AUDIO_DEVICE"; > > private static final int CAPTURE_PERMISSION_REQUEST_CODE = 1; > >@@ -127,25 +132,6 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > // Peer connection statistics callback period in ms. > private static final int STAT_CALLBACK_PERIOD = 1000; > >- private static class ProxyRenderer implements VideoRenderer.Callbacks { >- private VideoRenderer.Callbacks target; >- >- @Override >- synchronized public void renderFrame(VideoRenderer.I420Frame frame) { >- if (target == null) { >- Logging.d(TAG, "Dropping frame in proxy because target is null."); >- VideoRenderer.renderFrameDone(frame); >- return; >- } >- >- target.renderFrame(frame); >- } >- >- synchronized public void setTarget(VideoRenderer.Callbacks target) { >- this.target = target; >- } >- } >- > private static class ProxyVideoSink implements VideoSink { > private VideoSink target; > >@@ -164,20 +150,28 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > } > } > >- private final ProxyRenderer remoteProxyRenderer = new ProxyRenderer(); >+ private final ProxyVideoSink remoteProxyRenderer = new ProxyVideoSink(); > private final ProxyVideoSink localProxyVideoSink = new ProxyVideoSink(); >+ @Nullable > private PeerConnectionClient peerConnectionClient = null; >+ @Nullable > private AppRTCClient appRtcClient; >+ @Nullable > private SignalingParameters signalingParameters; >+ @Nullable > private AppRTCAudioManager audioManager = null; >+ @Nullable > private SurfaceViewRenderer pipRenderer; >+ @Nullable > private SurfaceViewRenderer fullscreenRenderer; >+ @Nullable > private VideoFileRenderer videoFileRenderer; >- private final List<VideoRenderer.Callbacks> remoteRenderers = new ArrayList<>(); >+ private final List<VideoSink> remoteSinks = new ArrayList<>(); > private Toast logToast; > private boolean commandLineRun; > private boolean activityRunning; > private RoomConnectionParameters roomConnectionParameters; >+ @Nullable > private PeerConnectionParameters peerConnectionParameters; > private boolean iceConnected; > private boolean isError; >@@ -196,6 +190,9 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > private CpuMonitor cpuMonitor; > > @Override >+ // TODO(bugs.webrtc.org/8580): LayoutParams.FLAG_TURN_SCREEN_ON and >+ // LayoutParams.FLAG_SHOW_WHEN_LOCKED are deprecated. >+ @SuppressWarnings("deprecation") > public void onCreate(Bundle savedInstanceState) { > super.onCreate(savedInstanceState); > Thread.setDefaultUncaughtExceptionHandler(new UnhandledExceptionHandler(this)); >@@ -234,15 +231,13 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > }); > > fullscreenRenderer.setOnClickListener(listener); >- remoteRenderers.add(remoteProxyRenderer); >+ remoteSinks.add(remoteProxyRenderer); > > final Intent intent = getIntent(); >- >- // Create peer connection client. >- peerConnectionClient = new PeerConnectionClient(); >+ final EglBase eglBase = EglBase.create(); > > // Create video renderers. >- pipRenderer.init(peerConnectionClient.getRenderContext(), null); >+ pipRenderer.init(eglBase.getEglBaseContext(), null); > pipRenderer.setScalingType(ScalingType.SCALE_ASPECT_FIT); > String saveRemoteVideoToFile = intent.getStringExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE); > >@@ -251,20 +246,20 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > int videoOutWidth = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_WIDTH, 0); > int videoOutHeight = intent.getIntExtra(EXTRA_SAVE_REMOTE_VIDEO_TO_FILE_HEIGHT, 0); > try { >- videoFileRenderer = new VideoFileRenderer(saveRemoteVideoToFile, videoOutWidth, >- videoOutHeight, peerConnectionClient.getRenderContext()); >- remoteRenderers.add(videoFileRenderer); >+ videoFileRenderer = new VideoFileRenderer( >+ saveRemoteVideoToFile, videoOutWidth, videoOutHeight, eglBase.getEglBaseContext()); >+ remoteSinks.add(videoFileRenderer); > } catch (IOException e) { > throw new RuntimeException( > "Failed to open video file for output: " + saveRemoteVideoToFile, e); > } > } >- fullscreenRenderer.init(peerConnectionClient.getRenderContext(), null); >+ fullscreenRenderer.init(eglBase.getEglBaseContext(), null); > fullscreenRenderer.setScalingType(ScalingType.SCALE_ASPECT_FILL); > > pipRenderer.setZOrderMediaOverlay(true); > pipRenderer.setEnableHardwareScaler(true /* enabled */); >- fullscreenRenderer.setEnableHardwareScaler(true /* enabled */); >+ fullscreenRenderer.setEnableHardwareScaler(false /* enabled */); > // Start with local feed in fullscreen and swap it to the pip when the call is connected. > setSwappedFeeds(true /* isSwappedFeeds */); > >@@ -327,12 +322,14 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > intent.getIntExtra(EXTRA_AUDIO_BITRATE, 0), intent.getStringExtra(EXTRA_AUDIOCODEC), > intent.getBooleanExtra(EXTRA_NOAUDIOPROCESSING_ENABLED, false), > intent.getBooleanExtra(EXTRA_AECDUMP_ENABLED, false), >+ intent.getBooleanExtra(EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED, false), > intent.getBooleanExtra(EXTRA_OPENSLES_ENABLED, false), > intent.getBooleanExtra(EXTRA_DISABLE_BUILT_IN_AEC, false), > intent.getBooleanExtra(EXTRA_DISABLE_BUILT_IN_AGC, false), > intent.getBooleanExtra(EXTRA_DISABLE_BUILT_IN_NS, false), >- intent.getBooleanExtra(EXTRA_ENABLE_LEVEL_CONTROL, false), >- intent.getBooleanExtra(EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, false), dataChannelParameters); >+ intent.getBooleanExtra(EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, false), >+ intent.getBooleanExtra(EXTRA_ENABLE_RTCEVENTLOG, false), >+ intent.getBooleanExtra(EXTRA_USE_LEGACY_AUDIO_DEVICE, false), dataChannelParameters); > commandLineRun = intent.getBooleanExtra(EXTRA_CMDLINE, false); > int runTimeMs = intent.getIntExtra(EXTRA_RUNTIME, 0); > >@@ -352,7 +349,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > new RoomConnectionParameters(roomUri.toString(), roomId, loopback, urlParameters); > > // Create CPU monitor >- if (cpuMonitor.isSupported()) { >+ if (CpuMonitor.isSupported()) { > cpuMonitor = new CpuMonitor(this); > hudFragment.setCpuMonitor(cpuMonitor); > } >@@ -376,13 +373,14 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > }, runTimeMs); > } > >+ // Create peer connection client. >+ peerConnectionClient = new PeerConnectionClient( >+ getApplicationContext(), eglBase, peerConnectionParameters, CallActivity.this); >+ PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); > if (loopback) { >- PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); > options.networkIgnoreMask = 0; >- peerConnectionClient.setPeerConnectionFactoryOptions(options); > } >- peerConnectionClient.createPeerConnectionFactory( >- getApplicationContext(), peerConnectionParameters, CallActivity.this); >+ peerConnectionClient.createPeerConnectionFactory(options); > > if (screencaptureEnabled) { > startScreenCapture(); >@@ -435,7 +433,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > return getIntent().getBooleanExtra(EXTRA_CAPTURETOTEXTURE_ENABLED, false); > } > >- private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { >+ private @Nullable VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { > final String[] deviceNames = enumerator.getDeviceNames(); > > // First, try to find front facing camera >@@ -468,7 +466,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > } > > @TargetApi(21) >- private VideoCapturer createScreenCapturer() { >+ private @Nullable VideoCapturer createScreenCapturer() { > if (mediaProjectionPermissionResultCode != Activity.RESULT_OK) { > reportError("User didn't give permission to capture the screen."); > return null; >@@ -705,7 +703,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > }); > } > >- private VideoCapturer createVideoCapturer() { >+ private @Nullable VideoCapturer createVideoCapturer() { > final VideoCapturer videoCapturer; > String videoFileAsCamera = getIntent().getStringExtra(EXTRA_VIDEO_FILE_AS_CAMERA); > if (videoFileAsCamera != null) { >@@ -758,7 +756,7 @@ public class CallActivity extends Activity implements AppRTCClient.SignalingEven > videoCapturer = createVideoCapturer(); > } > peerConnectionClient.createPeerConnection( >- localProxyVideoSink, remoteRenderers, videoCapturer, signalingParameters); >+ localProxyVideoSink, remoteSinks, videoCapturer, signalingParameters); > > if (signalingParameters.initiator) { > logAndToast("Creating OFFER..."); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/ConnectActivity.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/ConnectActivity.java >index d6f2ec3e99b..54cd0d7400d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/ConnectActivity.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/ConnectActivity.java >@@ -235,7 +235,7 @@ public class ConnectActivity extends Activity { > */ > private boolean sharedPrefGetBoolean( > int attributeId, String intentName, int defaultId, boolean useFromIntent) { >- boolean defaultValue = Boolean.valueOf(getString(defaultId)); >+ boolean defaultValue = Boolean.parseBoolean(getString(defaultId)); > if (useFromIntent) { > return getIntent().getBooleanExtra(intentName, defaultValue); > } else { >@@ -266,6 +266,7 @@ public class ConnectActivity extends Activity { > } > } > >+ @SuppressWarnings("StringSplitter") > private void connectToRoom(String roomId, boolean commandLineRun, boolean loopback, > boolean useValuesFromIntent, int runTimeMs) { > ConnectActivity.commandLineRun = commandLineRun; >@@ -314,10 +315,14 @@ public class ConnectActivity extends Activity { > CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, R.string.pref_noaudioprocessing_default, > useValuesFromIntent); > >- // Check Disable Audio Processing flag. > boolean aecDump = sharedPrefGetBoolean(R.string.pref_aecdump_key, > CallActivity.EXTRA_AECDUMP_ENABLED, R.string.pref_aecdump_default, useValuesFromIntent); > >+ boolean saveInputAudioToFile = >+ sharedPrefGetBoolean(R.string.pref_enable_save_input_audio_to_file_key, >+ CallActivity.EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED, >+ R.string.pref_enable_save_input_audio_to_file_default, useValuesFromIntent); >+ > // Check OpenSL ES enabled flag. > boolean useOpenSLES = sharedPrefGetBoolean(R.string.pref_opensles_key, > CallActivity.EXTRA_OPENSLES_ENABLED, R.string.pref_opensles_default, useValuesFromIntent); >@@ -337,11 +342,6 @@ public class ConnectActivity extends Activity { > CallActivity.EXTRA_DISABLE_BUILT_IN_NS, R.string.pref_disable_built_in_ns_default, > useValuesFromIntent); > >- // Check Enable level control. >- boolean enableLevelControl = sharedPrefGetBoolean(R.string.pref_enable_level_control_key, >- CallActivity.EXTRA_ENABLE_LEVEL_CONTROL, R.string.pref_enable_level_control_key, >- useValuesFromIntent); >- > // Check Disable gain control > boolean disableWebRtcAGCAndHPF = sharedPrefGetBoolean( > R.string.pref_disable_webrtc_agc_and_hpf_key, CallActivity.EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, >@@ -429,6 +429,15 @@ public class ConnectActivity extends Activity { > boolean tracing = sharedPrefGetBoolean(R.string.pref_tracing_key, CallActivity.EXTRA_TRACING, > R.string.pref_tracing_default, useValuesFromIntent); > >+ // Check Enable RtcEventLog. >+ boolean rtcEventLogEnabled = sharedPrefGetBoolean(R.string.pref_enable_rtceventlog_key, >+ CallActivity.EXTRA_ENABLE_RTCEVENTLOG, R.string.pref_enable_rtceventlog_default, >+ useValuesFromIntent); >+ >+ boolean useLegacyAudioDevice = sharedPrefGetBoolean(R.string.pref_use_legacy_audio_device_key, >+ CallActivity.EXTRA_USE_LEGACY_AUDIO_DEVICE, R.string.pref_use_legacy_audio_device_default, >+ useValuesFromIntent); >+ > // Get datachannel options > boolean dataChannelEnabled = sharedPrefGetBoolean(R.string.pref_enable_datachannel_key, > CallActivity.EXTRA_DATA_CHANNEL_ENABLED, R.string.pref_enable_datachannel_default, >@@ -470,18 +479,20 @@ public class ConnectActivity extends Activity { > intent.putExtra(CallActivity.EXTRA_FLEXFEC_ENABLED, flexfecEnabled); > intent.putExtra(CallActivity.EXTRA_NOAUDIOPROCESSING_ENABLED, noAudioProcessing); > intent.putExtra(CallActivity.EXTRA_AECDUMP_ENABLED, aecDump); >+ intent.putExtra(CallActivity.EXTRA_SAVE_INPUT_AUDIO_TO_FILE_ENABLED, saveInputAudioToFile); > intent.putExtra(CallActivity.EXTRA_OPENSLES_ENABLED, useOpenSLES); > intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_AEC, disableBuiltInAEC); > intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_AGC, disableBuiltInAGC); > intent.putExtra(CallActivity.EXTRA_DISABLE_BUILT_IN_NS, disableBuiltInNS); >- intent.putExtra(CallActivity.EXTRA_ENABLE_LEVEL_CONTROL, enableLevelControl); > intent.putExtra(CallActivity.EXTRA_DISABLE_WEBRTC_AGC_AND_HPF, disableWebRtcAGCAndHPF); > intent.putExtra(CallActivity.EXTRA_AUDIO_BITRATE, audioStartBitrate); > intent.putExtra(CallActivity.EXTRA_AUDIOCODEC, audioCodec); > intent.putExtra(CallActivity.EXTRA_DISPLAY_HUD, displayHud); > intent.putExtra(CallActivity.EXTRA_TRACING, tracing); >+ intent.putExtra(CallActivity.EXTRA_ENABLE_RTCEVENTLOG, rtcEventLogEnabled); > intent.putExtra(CallActivity.EXTRA_CMDLINE, commandLineRun); > intent.putExtra(CallActivity.EXTRA_RUNTIME, runTimeMs); >+ intent.putExtra(CallActivity.EXTRA_USE_LEGACY_AUDIO_DEVICE, useLegacyAudioDevice); > > intent.putExtra(CallActivity.EXTRA_DATA_CHANNEL_ENABLED, dataChannelEnabled); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CpuMonitor.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CpuMonitor.java >index 4a7ab9ecae6..8e2881c2d7d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CpuMonitor.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/CpuMonitor.java >@@ -31,6 +31,7 @@ import java.util.concurrent.Executors; > import java.util.concurrent.Future; > import java.util.concurrent.ScheduledExecutorService; > import java.util.concurrent.TimeUnit; >+import javax.annotation.Nullable; > > /** > * Simple CPU monitor. The caller creates a CpuMonitor object which can then >@@ -91,6 +92,7 @@ class CpuMonitor { > // CPU frequency in percentage from maximum. > private final MovingAverage frequencyScale; > >+ @Nullable > private ScheduledExecutorService executor; > private long lastStatLogTimeMs; > private long[] cpuFreqMax; >@@ -101,6 +103,7 @@ class CpuMonitor { > private String[] maxPath; > private String[] curPath; > private double[] curFreqScales; >+ @Nullable > private ProcStat lastProcStat; > > private static class ProcStat { >@@ -484,7 +487,8 @@ class CpuMonitor { > * Read the current utilization of all CPUs using the cumulative first line > * of /proc/stat. > */ >- private ProcStat readProcStat() { >+ @SuppressWarnings("StringSplitter") >+ private @Nullable ProcStat readProcStat() { > long userTime = 0; > long systemTime = 0; > long idleTime = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/DirectRTCClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/DirectRTCClient.java >index ae3a5228d63..9762e79aa03 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/DirectRTCClient.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/DirectRTCClient.java >@@ -10,6 +10,7 @@ > > package org.appspot.apprtc; > >+import javax.annotation.Nullable; > import android.util.Log; > > import org.json.JSONArray; >@@ -53,6 +54,7 @@ public class DirectRTCClient implements AppRTCClient, TCPChannelClient.TCPChanne > > private final ExecutorService executor; > private final SignalingEvents events; >+ @Nullable > private TCPChannelClient tcpClient; > private RoomConnectionParameters connectionParameters; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java >index fb11e4ae0bb..ae1f77b05ab 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java >@@ -13,23 +13,30 @@ package org.appspot.apprtc; > import android.content.Context; > import android.os.Environment; > import android.os.ParcelFileDescriptor; >+import android.preference.PreferenceManager; > import android.util.Log; > import java.io.File; > import java.io.IOException; > import java.nio.ByteBuffer; > import java.nio.charset.Charset; >+import java.text.DateFormat; >+import java.text.SimpleDateFormat; > import java.util.ArrayList; > import java.util.Arrays; > import java.util.Collections; >+import java.util.Date; > import java.util.Iterator; > import java.util.List; >+import java.util.Locale; > import java.util.Timer; > import java.util.TimerTask; > import java.util.concurrent.ExecutorService; > import java.util.concurrent.Executors; > import java.util.regex.Matcher; > import java.util.regex.Pattern; >+import javax.annotation.Nullable; > import org.appspot.apprtc.AppRTCClient.SignalingParameters; >+import org.appspot.apprtc.RecordedAudioToFileController; > import org.webrtc.AudioSource; > import org.webrtc.AudioTrack; > import org.webrtc.CameraVideoCapturer; >@@ -41,25 +48,33 @@ import org.webrtc.IceCandidate; > import org.webrtc.Logging; > import org.webrtc.MediaConstraints; > import org.webrtc.MediaStream; >+import org.webrtc.MediaStreamTrack; >+import org.webrtc.MediaStreamTrack.MediaType; > import org.webrtc.PeerConnection; > import org.webrtc.PeerConnection.IceConnectionState; > import org.webrtc.PeerConnectionFactory; > import org.webrtc.RtpParameters; > import org.webrtc.RtpReceiver; > import org.webrtc.RtpSender; >+import org.webrtc.RtpTransceiver; > import org.webrtc.SdpObserver; > import org.webrtc.SessionDescription; > import org.webrtc.SoftwareVideoDecoderFactory; > import org.webrtc.SoftwareVideoEncoderFactory; > import org.webrtc.StatsObserver; > import org.webrtc.StatsReport; >+import org.webrtc.SurfaceTextureHelper; > import org.webrtc.VideoCapturer; > import org.webrtc.VideoDecoderFactory; > import org.webrtc.VideoEncoderFactory; >-import org.webrtc.VideoRenderer; > import org.webrtc.VideoSink; > import org.webrtc.VideoSource; > import org.webrtc.VideoTrack; >+import org.webrtc.audio.AudioDeviceModule; >+import org.webrtc.audio.JavaAudioDeviceModule; >+import org.webrtc.audio.JavaAudioDeviceModule.AudioRecordErrorCallback; >+import org.webrtc.audio.JavaAudioDeviceModule.AudioTrackErrorCallback; >+import org.webrtc.audio.LegacyAudioDeviceModule; > import org.webrtc.voiceengine.WebRtcAudioManager; > import org.webrtc.voiceengine.WebRtcAudioRecord; > import org.webrtc.voiceengine.WebRtcAudioRecord.AudioRecordStartErrorCode; >@@ -91,23 +106,18 @@ public class PeerConnectionClient { > private static final String VIDEO_FLEXFEC_FIELDTRIAL = > "WebRTC-FlexFEC-03-Advertised/Enabled/WebRTC-FlexFEC-03/Enabled/"; > private static final String VIDEO_VP8_INTEL_HW_ENCODER_FIELDTRIAL = "WebRTC-IntelVP8/Enabled/"; >- private static final String VIDEO_H264_HIGH_PROFILE_FIELDTRIAL = >- "WebRTC-H264HighProfile/Enabled/"; > private static final String DISABLE_WEBRTC_AGC_FIELDTRIAL = > "WebRTC-Audio-MinimizeResamplingOnMobile/Enabled/"; >- private static final String VIDEO_FRAME_EMIT_FIELDTRIAL = >- PeerConnectionFactory.VIDEO_FRAME_EMIT_TRIAL + "/" + PeerConnectionFactory.TRIAL_ENABLED >- + "/"; > private static final String AUDIO_CODEC_PARAM_BITRATE = "maxaveragebitrate"; > private static final String AUDIO_ECHO_CANCELLATION_CONSTRAINT = "googEchoCancellation"; > private static final String AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT = "googAutoGainControl"; > private static final String AUDIO_HIGH_PASS_FILTER_CONSTRAINT = "googHighpassFilter"; > private static final String AUDIO_NOISE_SUPPRESSION_CONSTRAINT = "googNoiseSuppression"; >- private static final String AUDIO_LEVEL_CONTROL_CONSTRAINT = "levelControl"; > private static final String DTLS_SRTP_KEY_AGREEMENT_CONSTRAINT = "DtlsSrtpKeyAgreement"; > private static final int HD_VIDEO_WIDTH = 1280; > private static final int HD_VIDEO_HEIGHT = 720; > private static final int BPS_IN_KBPS = 1000; >+ private static final String RTCEVENTLOG_OUTPUT_DIR_NAME = "rtc_event_log"; > > // Executor thread is started once in private ctor and is used for all > // peer connection API calls to ensure new peer connection factory is >@@ -116,48 +126,64 @@ public class PeerConnectionClient { > > private final PCObserver pcObserver = new PCObserver(); > private final SDPObserver sdpObserver = new SDPObserver(); >- >+ private final Timer statsTimer = new Timer(); > private final EglBase rootEglBase; >+ private final Context appContext; >+ private final PeerConnectionParameters peerConnectionParameters; >+ private final PeerConnectionEvents events; >+ >+ @Nullable > private PeerConnectionFactory factory; >+ @Nullable > private PeerConnection peerConnection; >- PeerConnectionFactory.Options options = null; >+ @Nullable > private AudioSource audioSource; >- private VideoSource videoSource; >- private boolean videoCallEnabled; >+ @Nullable private SurfaceTextureHelper surfaceTextureHelper; >+ @Nullable private VideoSource videoSource; > private boolean preferIsac; >- private String preferredVideoCodec; > private boolean videoCapturerStopped; > private boolean isError; >- private Timer statsTimer; >+ @Nullable > private VideoSink localRender; >- private List<VideoRenderer.Callbacks> remoteRenders; >+ @Nullable private List<VideoSink> remoteSinks; > private SignalingParameters signalingParameters; >- private MediaConstraints pcConstraints; > private int videoWidth; > private int videoHeight; > private int videoFps; > private MediaConstraints audioConstraints; > private MediaConstraints sdpMediaConstraints; >- private PeerConnectionParameters peerConnectionParameters; > // Queued remote ICE candidates are consumed only after both local and > // remote descriptions are set. Similarly local ICE candidates are sent to > // remote peer after both local and remote description are set. >+ @Nullable > private List<IceCandidate> queuedRemoteCandidates; >- private PeerConnectionEvents events; > private boolean isInitiator; >+ @Nullable > private SessionDescription localSdp; // either offer or answer SDP >- private MediaStream mediaStream; >+ @Nullable > private VideoCapturer videoCapturer; > // enableVideo is set to true if video should be rendered and sent. >- private boolean renderVideo; >+ private boolean renderVideo = true; >+ @Nullable > private VideoTrack localVideoTrack; >+ @Nullable > private VideoTrack remoteVideoTrack; >+ @Nullable > private RtpSender localVideoSender; > // enableAudio is set to true if audio should be sent. >- private boolean enableAudio; >+ private boolean enableAudio = true; >+ @Nullable > private AudioTrack localAudioTrack; >+ @Nullable > private DataChannel dataChannel; >- private boolean dataChannelEnabled; >+ private final boolean dataChannelEnabled; >+ // Enable RtcEventLog. >+ @Nullable >+ private RtcEventLog rtcEventLog; >+ // Implements the WebRtcAudioRecordSamplesReadyCallback interface and writes >+ // recorded audio samples to an output file. >+ @Nullable >+ private RecordedAudioToFileController saveRecordedAudioToFile = null; > > /** > * Peer connection parameters. >@@ -199,33 +225,23 @@ public class PeerConnectionClient { > public final String audioCodec; > public final boolean noAudioProcessing; > public final boolean aecDump; >+ public final boolean saveInputAudioToFile; > public final boolean useOpenSLES; > public final boolean disableBuiltInAEC; > public final boolean disableBuiltInAGC; > public final boolean disableBuiltInNS; >- public final boolean enableLevelControl; > public final boolean disableWebRtcAGCAndHPF; >+ public final boolean enableRtcEventLog; >+ public final boolean useLegacyAudioDevice; > private final DataChannelParameters dataChannelParameters; > > public PeerConnectionParameters(boolean videoCallEnabled, boolean loopback, boolean tracing, > int videoWidth, int videoHeight, int videoFps, int videoMaxBitrate, String videoCodec, > boolean videoCodecHwAcceleration, boolean videoFlexfecEnabled, int audioStartBitrate, >- String audioCodec, boolean noAudioProcessing, boolean aecDump, boolean useOpenSLES, >- boolean disableBuiltInAEC, boolean disableBuiltInAGC, boolean disableBuiltInNS, >- boolean enableLevelControl, boolean disableWebRtcAGCAndHPF) { >- this(videoCallEnabled, loopback, tracing, videoWidth, videoHeight, videoFps, videoMaxBitrate, >- videoCodec, videoCodecHwAcceleration, videoFlexfecEnabled, audioStartBitrate, audioCodec, >- noAudioProcessing, aecDump, useOpenSLES, disableBuiltInAEC, disableBuiltInAGC, >- disableBuiltInNS, enableLevelControl, disableWebRtcAGCAndHPF, null); >- } >- >- public PeerConnectionParameters(boolean videoCallEnabled, boolean loopback, boolean tracing, >- int videoWidth, int videoHeight, int videoFps, int videoMaxBitrate, String videoCodec, >- boolean videoCodecHwAcceleration, boolean videoFlexfecEnabled, int audioStartBitrate, >- String audioCodec, boolean noAudioProcessing, boolean aecDump, boolean useOpenSLES, >- boolean disableBuiltInAEC, boolean disableBuiltInAGC, boolean disableBuiltInNS, >- boolean enableLevelControl, boolean disableWebRtcAGCAndHPF, >- DataChannelParameters dataChannelParameters) { >+ String audioCodec, boolean noAudioProcessing, boolean aecDump, boolean saveInputAudioToFile, >+ boolean useOpenSLES, boolean disableBuiltInAEC, boolean disableBuiltInAGC, >+ boolean disableBuiltInNS, boolean disableWebRtcAGCAndHPF, boolean enableRtcEventLog, >+ boolean useLegacyAudioDevice, DataChannelParameters dataChannelParameters) { > this.videoCallEnabled = videoCallEnabled; > this.loopback = loopback; > this.tracing = tracing; >@@ -240,12 +256,14 @@ public class PeerConnectionClient { > this.audioCodec = audioCodec; > this.noAudioProcessing = noAudioProcessing; > this.aecDump = aecDump; >+ this.saveInputAudioToFile = saveInputAudioToFile; > this.useOpenSLES = useOpenSLES; > this.disableBuiltInAEC = disableBuiltInAEC; > this.disableBuiltInAGC = disableBuiltInAGC; > this.disableBuiltInNS = disableBuiltInNS; >- this.enableLevelControl = enableLevelControl; > this.disableWebRtcAGCAndHPF = disableWebRtcAGCAndHPF; >+ this.enableRtcEventLog = enableRtcEventLog; >+ this.useLegacyAudioDevice = useLegacyAudioDevice; > this.dataChannelParameters = dataChannelParameters; > } > } >@@ -297,141 +315,83 @@ public class PeerConnectionClient { > void onPeerConnectionError(final String description); > } > >- public PeerConnectionClient() { >- rootEglBase = EglBase.create(); >- } >- >- public void setPeerConnectionFactoryOptions(PeerConnectionFactory.Options options) { >- this.options = options; >- } >- >- public void createPeerConnectionFactory(final Context context, >- final PeerConnectionParameters peerConnectionParameters, final PeerConnectionEvents events) { >- this.peerConnectionParameters = peerConnectionParameters; >+ /** >+ * Create a PeerConnectionClient with the specified parameters. PeerConnectionClient takes >+ * ownership of |eglBase|. >+ */ >+ public PeerConnectionClient(Context appContext, EglBase eglBase, >+ PeerConnectionParameters peerConnectionParameters, PeerConnectionEvents events) { >+ this.rootEglBase = eglBase; >+ this.appContext = appContext; > this.events = events; >- videoCallEnabled = peerConnectionParameters.videoCallEnabled; >- dataChannelEnabled = peerConnectionParameters.dataChannelParameters != null; >- // Reset variables to initial states. >- factory = null; >- peerConnection = null; >- preferIsac = false; >- videoCapturerStopped = false; >- isError = false; >- queuedRemoteCandidates = null; >- localSdp = null; // either offer or answer SDP >- mediaStream = null; >- videoCapturer = null; >- renderVideo = true; >- localVideoTrack = null; >- remoteVideoTrack = null; >- localVideoSender = null; >- enableAudio = true; >- localAudioTrack = null; >- statsTimer = new Timer(); >- >- executor.execute(new Runnable() { >- @Override >- public void run() { >- createPeerConnectionFactoryInternal(context); >- } >+ this.peerConnectionParameters = peerConnectionParameters; >+ this.dataChannelEnabled = peerConnectionParameters.dataChannelParameters != null; >+ >+ Log.d(TAG, "Preferred video codec: " + getSdpVideoCodecName(peerConnectionParameters)); >+ >+ final String fieldTrials = getFieldTrials(peerConnectionParameters); >+ executor.execute(() -> { >+ Log.d(TAG, "Initialize WebRTC. Field trials: " + fieldTrials); >+ PeerConnectionFactory.initialize( >+ PeerConnectionFactory.InitializationOptions.builder(appContext) >+ .setFieldTrials(fieldTrials) >+ .setEnableInternalTracer(true) >+ .createInitializationOptions()); > }); > } > >- public void createPeerConnection(final VideoSink localRender, >- final VideoRenderer.Callbacks remoteRender, final VideoCapturer videoCapturer, >- final SignalingParameters signalingParameters) { >+ /** >+ * This function should only be called once. >+ */ >+ public void createPeerConnectionFactory(PeerConnectionFactory.Options options) { >+ if (factory != null) { >+ throw new IllegalStateException("PeerConnectionFactory has already been constructed"); >+ } >+ executor.execute(() -> createPeerConnectionFactoryInternal(options)); >+ } >+ >+ public void createPeerConnection(final VideoSink localRender, final VideoSink remoteSink, >+ final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) { >+ if (peerConnectionParameters.videoCallEnabled && videoCapturer == null) { >+ Log.w(TAG, "Video call enabled but no video capturer provided."); >+ } > createPeerConnection( >- localRender, Collections.singletonList(remoteRender), videoCapturer, signalingParameters); >+ localRender, Collections.singletonList(remoteSink), videoCapturer, signalingParameters); > } > >- public void createPeerConnection(final VideoSink localRender, >- final List<VideoRenderer.Callbacks> remoteRenders, final VideoCapturer videoCapturer, >- final SignalingParameters signalingParameters) { >+ public void createPeerConnection(final VideoSink localRender, final List<VideoSink> remoteSinks, >+ final VideoCapturer videoCapturer, final SignalingParameters signalingParameters) { > if (peerConnectionParameters == null) { > Log.e(TAG, "Creating peer connection without initializing factory."); > return; > } > this.localRender = localRender; >- this.remoteRenders = remoteRenders; >+ this.remoteSinks = remoteSinks; > this.videoCapturer = videoCapturer; > this.signalingParameters = signalingParameters; >- executor.execute(new Runnable() { >- @Override >- public void run() { >- try { >- createMediaConstraintsInternal(); >- createPeerConnectionInternal(); >- } catch (Exception e) { >- reportError("Failed to create peer connection: " + e.getMessage()); >- throw e; >- } >+ executor.execute(() -> { >+ try { >+ createMediaConstraintsInternal(); >+ createPeerConnectionInternal(); >+ maybeCreateAndStartRtcEventLog(); >+ } catch (Exception e) { >+ reportError("Failed to create peer connection: " + e.getMessage()); >+ throw e; > } > }); > } > > public void close() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- closeInternal(); >- } >- }); >+ executor.execute(this ::closeInternal); > } > >- public boolean isVideoCallEnabled() { >- return videoCallEnabled; >+ private boolean isVideoCallEnabled() { >+ return peerConnectionParameters.videoCallEnabled && videoCapturer != null; > } > >- private void createPeerConnectionFactoryInternal(Context context) { >+ private void createPeerConnectionFactoryInternal(PeerConnectionFactory.Options options) { > isError = false; > >- // Initialize field trials. >- String fieldTrials = ""; >- if (peerConnectionParameters.videoFlexfecEnabled) { >- fieldTrials += VIDEO_FLEXFEC_FIELDTRIAL; >- Log.d(TAG, "Enable FlexFEC field trial."); >- } >- fieldTrials += VIDEO_VP8_INTEL_HW_ENCODER_FIELDTRIAL; >- if (peerConnectionParameters.disableWebRtcAGCAndHPF) { >- fieldTrials += DISABLE_WEBRTC_AGC_FIELDTRIAL; >- Log.d(TAG, "Disable WebRTC AGC field trial."); >- } >- fieldTrials += VIDEO_FRAME_EMIT_FIELDTRIAL; >- >- // Check preferred video codec. >- preferredVideoCodec = VIDEO_CODEC_VP8; >- if (videoCallEnabled && peerConnectionParameters.videoCodec != null) { >- switch (peerConnectionParameters.videoCodec) { >- case VIDEO_CODEC_VP8: >- preferredVideoCodec = VIDEO_CODEC_VP8; >- break; >- case VIDEO_CODEC_VP9: >- preferredVideoCodec = VIDEO_CODEC_VP9; >- break; >- case VIDEO_CODEC_H264_BASELINE: >- preferredVideoCodec = VIDEO_CODEC_H264; >- break; >- case VIDEO_CODEC_H264_HIGH: >- // TODO(magjed): Strip High from SDP when selecting Baseline instead of using field trial. >- fieldTrials += VIDEO_H264_HIGH_PROFILE_FIELDTRIAL; >- preferredVideoCodec = VIDEO_CODEC_H264; >- break; >- default: >- preferredVideoCodec = VIDEO_CODEC_VP8; >- } >- } >- Log.d(TAG, "Preferred video codec: " + preferredVideoCodec); >- >- // Initialize WebRTC >- Log.d(TAG, >- "Initialize WebRTC. Field trials: " + fieldTrials + " Enable video HW acceleration: " >- + peerConnectionParameters.videoCodecHwAcceleration); >- PeerConnectionFactory.initialize( >- PeerConnectionFactory.InitializationOptions.builder(context) >- .setFieldTrials(fieldTrials) >- .setEnableVideoHwAcceleration(peerConnectionParameters.videoCodecHwAcceleration) >- .setEnableInternalTracer(true) >- .createInitializationOptions()); > if (peerConnectionParameters.tracing) { > PeerConnectionFactory.startInternalTracingCapture( > Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator >@@ -442,6 +402,55 @@ public class PeerConnectionClient { > preferIsac = peerConnectionParameters.audioCodec != null > && peerConnectionParameters.audioCodec.equals(AUDIO_CODEC_ISAC); > >+ // It is possible to save a copy in raw PCM format on a file by checking >+ // the "Save input audio to file" checkbox in the Settings UI. A callback >+ // interface is set when this flag is enabled. As a result, a copy of recorded >+ // audio samples are provided to this client directly from the native audio >+ // layer in Java. >+ if (peerConnectionParameters.saveInputAudioToFile) { >+ if (!peerConnectionParameters.useOpenSLES) { >+ Log.d(TAG, "Enable recording of microphone input audio to file"); >+ saveRecordedAudioToFile = new RecordedAudioToFileController(executor); >+ } else { >+ // TODO(henrika): ensure that the UI reflects that if OpenSL ES is selected, >+ // then the "Save inut audio to file" option shall be grayed out. >+ Log.e(TAG, "Recording of input audio is not supported for OpenSL ES"); >+ } >+ } >+ >+ final AudioDeviceModule adm = peerConnectionParameters.useLegacyAudioDevice >+ ? createLegacyAudioDevice() >+ : createJavaAudioDevice(); >+ >+ // Create peer connection factory. >+ if (options != null) { >+ Log.d(TAG, "Factory networkIgnoreMask option: " + options.networkIgnoreMask); >+ } >+ final boolean enableH264HighProfile = >+ VIDEO_CODEC_H264_HIGH.equals(peerConnectionParameters.videoCodec); >+ final VideoEncoderFactory encoderFactory; >+ final VideoDecoderFactory decoderFactory; >+ >+ if (peerConnectionParameters.videoCodecHwAcceleration) { >+ encoderFactory = new DefaultVideoEncoderFactory( >+ rootEglBase.getEglBaseContext(), true /* enableIntelVp8Encoder */, enableH264HighProfile); >+ decoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext()); >+ } else { >+ encoderFactory = new SoftwareVideoEncoderFactory(); >+ decoderFactory = new SoftwareVideoDecoderFactory(); >+ } >+ >+ factory = PeerConnectionFactory.builder() >+ .setOptions(options) >+ .setAudioDeviceModule(adm) >+ .setVideoEncoderFactory(encoderFactory) >+ .setVideoDecoderFactory(decoderFactory) >+ .createPeerConnectionFactory(); >+ Log.d(TAG, "Peer connection factory created."); >+ adm.release(); >+ } >+ >+ AudioDeviceModule createLegacyAudioDevice() { > // Enable/disable OpenSL ES playback. > if (!peerConnectionParameters.useOpenSLES) { > Log.d(TAG, "Disable OpenSL ES audio even if device supports it"); >@@ -459,14 +468,6 @@ public class PeerConnectionClient { > WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(false); > } > >- if (peerConnectionParameters.disableBuiltInAGC) { >- Log.d(TAG, "Disable built-in AGC even if device supports it"); >- WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(true); >- } else { >- Log.d(TAG, "Enable built-in AGC if device supports it"); >- WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(false); >- } >- > if (peerConnectionParameters.disableBuiltInNS) { > Log.d(TAG, "Disable built-in NS even if device supports it"); > WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(true); >@@ -475,6 +476,8 @@ public class PeerConnectionClient { > WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(false); > } > >+ WebRtcAudioRecord.setOnAudioSamplesReady(saveRecordedAudioToFile); >+ > // Set audio record error callbacks. > WebRtcAudioRecord.setErrorCallback(new WebRtcAudioRecordErrorCallback() { > @Override >@@ -518,47 +521,71 @@ public class PeerConnectionClient { > } > }); > >- // Create peer connection factory. >- if (options != null) { >- Log.d(TAG, "Factory networkIgnoreMask option: " + options.networkIgnoreMask); >- } >- final boolean enableH264HighProfile = >- VIDEO_CODEC_H264_HIGH.equals(peerConnectionParameters.videoCodec); >- final VideoEncoderFactory encoderFactory; >- final VideoDecoderFactory decoderFactory; >+ return new LegacyAudioDeviceModule(); >+ } > >- if (peerConnectionParameters.videoCodecHwAcceleration) { >- encoderFactory = new DefaultVideoEncoderFactory( >- rootEglBase.getEglBaseContext(), true /* enableIntelVp8Encoder */, enableH264HighProfile); >- decoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext()); >- } else { >- encoderFactory = new SoftwareVideoEncoderFactory(); >- decoderFactory = new SoftwareVideoDecoderFactory(); >+ AudioDeviceModule createJavaAudioDevice() { >+ // Enable/disable OpenSL ES playback. >+ if (!peerConnectionParameters.useOpenSLES) { >+ Log.w(TAG, "External OpenSLES ADM not implemented yet."); >+ // TODO(magjed): Add support for external OpenSLES ADM. > } > >- factory = new PeerConnectionFactory(options, encoderFactory, decoderFactory); >- Log.d(TAG, "Peer connection factory created."); >+ // Set audio record error callbacks. >+ AudioRecordErrorCallback audioRecordErrorCallback = new AudioRecordErrorCallback() { >+ @Override >+ public void onWebRtcAudioRecordInitError(String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioRecordInitError: " + errorMessage); >+ reportError(errorMessage); >+ } >+ >+ @Override >+ public void onWebRtcAudioRecordStartError( >+ JavaAudioDeviceModule.AudioRecordStartErrorCode errorCode, String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioRecordStartError: " + errorCode + ". " + errorMessage); >+ reportError(errorMessage); >+ } >+ >+ @Override >+ public void onWebRtcAudioRecordError(String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioRecordError: " + errorMessage); >+ reportError(errorMessage); >+ } >+ }; >+ >+ AudioTrackErrorCallback audioTrackErrorCallback = new AudioTrackErrorCallback() { >+ @Override >+ public void onWebRtcAudioTrackInitError(String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioTrackInitError: " + errorMessage); >+ reportError(errorMessage); >+ } >+ >+ @Override >+ public void onWebRtcAudioTrackStartError( >+ JavaAudioDeviceModule.AudioTrackStartErrorCode errorCode, String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioTrackStartError: " + errorCode + ". " + errorMessage); >+ reportError(errorMessage); >+ } >+ >+ @Override >+ public void onWebRtcAudioTrackError(String errorMessage) { >+ Log.e(TAG, "onWebRtcAudioTrackError: " + errorMessage); >+ reportError(errorMessage); >+ } >+ }; >+ >+ return JavaAudioDeviceModule.builder(appContext) >+ .setSamplesReadyCallback(saveRecordedAudioToFile) >+ .setUseHardwareAcousticEchoCanceler(!peerConnectionParameters.disableBuiltInAEC) >+ .setUseHardwareNoiseSuppressor(!peerConnectionParameters.disableBuiltInNS) >+ .setAudioRecordErrorCallback(audioRecordErrorCallback) >+ .setAudioTrackErrorCallback(audioTrackErrorCallback) >+ .createAudioDeviceModule(); > } > > private void createMediaConstraintsInternal() { >- // Create peer connection constraints. >- pcConstraints = new MediaConstraints(); >- // Enable DTLS for normal calls and disable for loopback calls. >- if (peerConnectionParameters.loopback) { >- pcConstraints.optional.add( >- new MediaConstraints.KeyValuePair(DTLS_SRTP_KEY_AGREEMENT_CONSTRAINT, "false")); >- } else { >- pcConstraints.optional.add( >- new MediaConstraints.KeyValuePair(DTLS_SRTP_KEY_AGREEMENT_CONSTRAINT, "true")); >- } >- >- // Check if there is a camera on device and disable video call if not. >- if (videoCapturer == null) { >- Log.w(TAG, "No camera on device. Switch to audio only call."); >- videoCallEnabled = false; >- } > // Create video constraints if video call is enabled. >- if (videoCallEnabled) { >+ if (isVideoCallEnabled()) { > videoWidth = peerConnectionParameters.videoWidth; > videoHeight = peerConnectionParameters.videoHeight; > videoFps = peerConnectionParameters.videoFps; >@@ -590,22 +617,12 @@ public class PeerConnectionClient { > audioConstraints.mandatory.add( > new MediaConstraints.KeyValuePair(AUDIO_NOISE_SUPPRESSION_CONSTRAINT, "false")); > } >- if (peerConnectionParameters.enableLevelControl) { >- Log.d(TAG, "Enabling level control."); >- audioConstraints.mandatory.add( >- new MediaConstraints.KeyValuePair(AUDIO_LEVEL_CONTROL_CONSTRAINT, "true")); >- } > // Create SDP constraints. > sdpMediaConstraints = new MediaConstraints(); > sdpMediaConstraints.mandatory.add( > new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")); >- if (videoCallEnabled || peerConnectionParameters.loopback) { >- sdpMediaConstraints.mandatory.add( >- new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true")); >- } else { >- sdpMediaConstraints.mandatory.add( >- new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "false")); >- } >+ sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair( >+ "OfferToReceiveVideo", Boolean.toString(isVideoCallEnabled()))); > } > > private void createPeerConnectionInternal() { >@@ -615,14 +632,8 @@ public class PeerConnectionClient { > } > Log.d(TAG, "Create peer connection."); > >- Log.d(TAG, "PCConstraints: " + pcConstraints.toString()); > queuedRemoteCandidates = new ArrayList<>(); > >- if (videoCallEnabled) { >- factory.setVideoHwAccelerationOptions( >- rootEglBase.getEglBaseContext(), rootEglBase.getEglBaseContext()); >- } >- > PeerConnection.RTCConfiguration rtcConfig = > new PeerConnection.RTCConfiguration(signalingParameters.iceServers); > // TCP candidates are only useful when connecting to a server that supports >@@ -633,8 +644,11 @@ public class PeerConnectionClient { > rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY; > // Use ECDSA encryption. > rtcConfig.keyType = PeerConnection.KeyType.ECDSA; >+ // Enable DTLS for normal calls and disable for loopback calls. >+ rtcConfig.enableDtlsSrtp = !peerConnectionParameters.loopback; >+ rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN; > >- peerConnection = factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver); >+ peerConnection = factory.createPeerConnection(rtcConfig, pcObserver); > > if (dataChannelEnabled) { > DataChannel.Init init = new DataChannel.Init(); >@@ -652,14 +666,19 @@ public class PeerConnectionClient { > // NOTE: this _must_ happen while |factory| is alive! > Logging.enableLogToDebugOutput(Logging.Severity.LS_INFO); > >- mediaStream = factory.createLocalMediaStream("ARDAMS"); >- if (videoCallEnabled) { >- mediaStream.addTrack(createVideoTrack(videoCapturer)); >+ List<String> mediaStreamLabels = Collections.singletonList("ARDAMS"); >+ if (isVideoCallEnabled()) { >+ peerConnection.addTrack(createVideoTrack(videoCapturer), mediaStreamLabels); >+ // We can add the renderers right away because we don't need to wait for an >+ // answer to get the remote track. >+ remoteVideoTrack = getRemoteVideoTrack(); >+ remoteVideoTrack.setEnabled(renderVideo); >+ for (VideoSink remoteSink : remoteSinks) { >+ remoteVideoTrack.addSink(remoteSink); >+ } > } >- >- mediaStream.addTrack(createAudioTrack()); >- peerConnection.addStream(mediaStream); >- if (videoCallEnabled) { >+ peerConnection.addTrack(createAudioTrack(), mediaStreamLabels); >+ if (isVideoCallEnabled()) { > findVideoSender(); > } > >@@ -670,15 +689,40 @@ public class PeerConnectionClient { > + File.separator + "Download/audio.aecdump"), > ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE > | ParcelFileDescriptor.MODE_TRUNCATE); >- factory.startAecDump(aecDumpFileDescriptor.getFd(), -1); >+ factory.startAecDump(aecDumpFileDescriptor.detachFd(), -1); > } catch (IOException e) { > Log.e(TAG, "Can not open aecdump file", e); > } > } > >+ if (saveRecordedAudioToFile != null) { >+ if (saveRecordedAudioToFile.start()) { >+ Log.d(TAG, "Recording input audio to file is activated"); >+ } >+ } > Log.d(TAG, "Peer connection created."); > } > >+ private File createRtcEventLogOutputFile() { >+ DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_hhmm_ss", Locale.getDefault()); >+ Date date = new Date(); >+ final String outputFileName = "event_log_" + dateFormat.format(date) + ".log"; >+ return new File( >+ appContext.getDir(RTCEVENTLOG_OUTPUT_DIR_NAME, Context.MODE_PRIVATE), outputFileName); >+ } >+ >+ private void maybeCreateAndStartRtcEventLog() { >+ if (appContext == null || peerConnection == null) { >+ return; >+ } >+ if (!peerConnectionParameters.enableRtcEventLog) { >+ Log.d(TAG, "RtcEventLog is disabled."); >+ return; >+ } >+ rtcEventLog = new RtcEventLog(peerConnection); >+ rtcEventLog.start(createRtcEventLogOutputFile()); >+ } >+ > private void closeInternal() { > if (factory != null && peerConnectionParameters.aecDump) { > factory.stopAecDump(); >@@ -689,6 +733,11 @@ public class PeerConnectionClient { > dataChannel.dispose(); > dataChannel = null; > } >+ if (rtcEventLog != null) { >+ // RtcEventLog should stop before the peer connection is disposed. >+ rtcEventLog.stop(); >+ rtcEventLog = null; >+ } > if (peerConnection != null) { > peerConnection.dispose(); > peerConnection = null; >@@ -714,28 +763,31 @@ public class PeerConnectionClient { > videoSource.dispose(); > videoSource = null; > } >+ if (surfaceTextureHelper != null) { >+ surfaceTextureHelper.dispose(); >+ surfaceTextureHelper = null; >+ } >+ if (saveRecordedAudioToFile != null) { >+ Log.d(TAG, "Closing audio file for recorded input audio."); >+ saveRecordedAudioToFile.stop(); >+ saveRecordedAudioToFile = null; >+ } > localRender = null; >- remoteRenders = null; >+ remoteSinks = null; > Log.d(TAG, "Closing peer connection factory."); > if (factory != null) { > factory.dispose(); > factory = null; > } >- options = null; > rootEglBase.release(); > Log.d(TAG, "Closing peer connection done."); > events.onPeerConnectionClosed(); > PeerConnectionFactory.stopInternalTracingCapture(); > PeerConnectionFactory.shutdownInternalTracer(); >- events = null; > } > > public boolean isHDVideo() { >- return videoCallEnabled && videoWidth * videoHeight >= 1280 * 720; >- } >- >- public EglBase.Context getRenderContext() { >- return rootEglBase.getEglBaseContext(); >+ return isVideoCallEnabled() && videoWidth * videoHeight >= 1280 * 720; > } > > @SuppressWarnings("deprecation") // TODO(sakal): getStats is deprecated. >@@ -760,12 +812,7 @@ public class PeerConnectionClient { > statsTimer.schedule(new TimerTask() { > @Override > public void run() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- getStats(); >- } >- }); >+ executor.execute(() -> getStats()); > } > }, 0, periodMs); > } catch (Exception e) { >@@ -777,186 +824,155 @@ public class PeerConnectionClient { > } > > public void setAudioEnabled(final boolean enable) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- enableAudio = enable; >- if (localAudioTrack != null) { >- localAudioTrack.setEnabled(enableAudio); >- } >+ executor.execute(() -> { >+ enableAudio = enable; >+ if (localAudioTrack != null) { >+ localAudioTrack.setEnabled(enableAudio); > } > }); > } > > public void setVideoEnabled(final boolean enable) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- renderVideo = enable; >- if (localVideoTrack != null) { >- localVideoTrack.setEnabled(renderVideo); >- } >- if (remoteVideoTrack != null) { >- remoteVideoTrack.setEnabled(renderVideo); >- } >+ executor.execute(() -> { >+ renderVideo = enable; >+ if (localVideoTrack != null) { >+ localVideoTrack.setEnabled(renderVideo); >+ } >+ if (remoteVideoTrack != null) { >+ remoteVideoTrack.setEnabled(renderVideo); > } > }); > } > > public void createOffer() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection != null && !isError) { >- Log.d(TAG, "PC Create OFFER"); >- isInitiator = true; >- peerConnection.createOffer(sdpObserver, sdpMediaConstraints); >- } >+ executor.execute(() -> { >+ if (peerConnection != null && !isError) { >+ Log.d(TAG, "PC Create OFFER"); >+ isInitiator = true; >+ peerConnection.createOffer(sdpObserver, sdpMediaConstraints); > } > }); > } > > public void createAnswer() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection != null && !isError) { >- Log.d(TAG, "PC create ANSWER"); >- isInitiator = false; >- peerConnection.createAnswer(sdpObserver, sdpMediaConstraints); >- } >+ executor.execute(() -> { >+ if (peerConnection != null && !isError) { >+ Log.d(TAG, "PC create ANSWER"); >+ isInitiator = false; >+ peerConnection.createAnswer(sdpObserver, sdpMediaConstraints); > } > }); > } > > public void addRemoteIceCandidate(final IceCandidate candidate) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection != null && !isError) { >- if (queuedRemoteCandidates != null) { >- queuedRemoteCandidates.add(candidate); >- } else { >- peerConnection.addIceCandidate(candidate); >- } >+ executor.execute(() -> { >+ if (peerConnection != null && !isError) { >+ if (queuedRemoteCandidates != null) { >+ queuedRemoteCandidates.add(candidate); >+ } else { >+ peerConnection.addIceCandidate(candidate); > } > } > }); > } > > public void removeRemoteIceCandidates(final IceCandidate[] candidates) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection == null || isError) { >- return; >- } >- // Drain the queued remote candidates if there is any so that >- // they are processed in the proper order. >- drainCandidates(); >- peerConnection.removeIceCandidates(candidates); >+ executor.execute(() -> { >+ if (peerConnection == null || isError) { >+ return; > } >+ // Drain the queued remote candidates if there is any so that >+ // they are processed in the proper order. >+ drainCandidates(); >+ peerConnection.removeIceCandidates(candidates); > }); > } > > public void setRemoteDescription(final SessionDescription sdp) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection == null || isError) { >- return; >- } >- String sdpDescription = sdp.description; >- if (preferIsac) { >- sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true); >- } >- if (videoCallEnabled) { >- sdpDescription = preferCodec(sdpDescription, preferredVideoCodec, false); >- } >- if (peerConnectionParameters.audioStartBitrate > 0) { >- sdpDescription = setStartBitrate( >- AUDIO_CODEC_OPUS, false, sdpDescription, peerConnectionParameters.audioStartBitrate); >- } >- Log.d(TAG, "Set remote SDP."); >- SessionDescription sdpRemote = new SessionDescription(sdp.type, sdpDescription); >- peerConnection.setRemoteDescription(sdpObserver, sdpRemote); >+ executor.execute(() -> { >+ if (peerConnection == null || isError) { >+ return; >+ } >+ String sdpDescription = sdp.description; >+ if (preferIsac) { >+ sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true); >+ } >+ if (isVideoCallEnabled()) { >+ sdpDescription = >+ preferCodec(sdpDescription, getSdpVideoCodecName(peerConnectionParameters), false); > } >+ if (peerConnectionParameters.audioStartBitrate > 0) { >+ sdpDescription = setStartBitrate( >+ AUDIO_CODEC_OPUS, false, sdpDescription, peerConnectionParameters.audioStartBitrate); >+ } >+ Log.d(TAG, "Set remote SDP."); >+ SessionDescription sdpRemote = new SessionDescription(sdp.type, sdpDescription); >+ peerConnection.setRemoteDescription(sdpObserver, sdpRemote); > }); > } > > public void stopVideoSource() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (videoCapturer != null && !videoCapturerStopped) { >- Log.d(TAG, "Stop video source."); >- try { >- videoCapturer.stopCapture(); >- } catch (InterruptedException e) { >- } >- videoCapturerStopped = true; >+ executor.execute(() -> { >+ if (videoCapturer != null && !videoCapturerStopped) { >+ Log.d(TAG, "Stop video source."); >+ try { >+ videoCapturer.stopCapture(); >+ } catch (InterruptedException e) { > } >+ videoCapturerStopped = true; > } > }); > } > > public void startVideoSource() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (videoCapturer != null && videoCapturerStopped) { >- Log.d(TAG, "Restart video source."); >- videoCapturer.startCapture(videoWidth, videoHeight, videoFps); >- videoCapturerStopped = false; >- } >+ executor.execute(() -> { >+ if (videoCapturer != null && videoCapturerStopped) { >+ Log.d(TAG, "Restart video source."); >+ videoCapturer.startCapture(videoWidth, videoHeight, videoFps); >+ videoCapturerStopped = false; > } > }); > } > >- public void setVideoMaxBitrate(final Integer maxBitrateKbps) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection == null || localVideoSender == null || isError) { >- return; >- } >- Log.d(TAG, "Requested max video bitrate: " + maxBitrateKbps); >- if (localVideoSender == null) { >- Log.w(TAG, "Sender is not ready."); >- return; >- } >+ public void setVideoMaxBitrate(@Nullable final Integer maxBitrateKbps) { >+ executor.execute(() -> { >+ if (peerConnection == null || localVideoSender == null || isError) { >+ return; >+ } >+ Log.d(TAG, "Requested max video bitrate: " + maxBitrateKbps); >+ if (localVideoSender == null) { >+ Log.w(TAG, "Sender is not ready."); >+ return; >+ } > >- RtpParameters parameters = localVideoSender.getParameters(); >- if (parameters.encodings.size() == 0) { >- Log.w(TAG, "RtpParameters are not ready."); >- return; >- } >+ RtpParameters parameters = localVideoSender.getParameters(); >+ if (parameters.encodings.size() == 0) { >+ Log.w(TAG, "RtpParameters are not ready."); >+ return; >+ } > >- for (RtpParameters.Encoding encoding : parameters.encodings) { >- // Null value means no limit. >- encoding.maxBitrateBps = maxBitrateKbps == null ? null : maxBitrateKbps * BPS_IN_KBPS; >- } >- if (!localVideoSender.setParameters(parameters)) { >- Log.e(TAG, "RtpSender.setParameters failed."); >- } >- Log.d(TAG, "Configured max video bitrate to: " + maxBitrateKbps); >+ for (RtpParameters.Encoding encoding : parameters.encodings) { >+ // Null value means no limit. >+ encoding.maxBitrateBps = maxBitrateKbps == null ? null : maxBitrateKbps * BPS_IN_KBPS; > } >+ if (!localVideoSender.setParameters(parameters)) { >+ Log.e(TAG, "RtpSender.setParameters failed."); >+ } >+ Log.d(TAG, "Configured max video bitrate to: " + maxBitrateKbps); > }); > } > > private void reportError(final String errorMessage) { > Log.e(TAG, "Peerconnection error: " + errorMessage); >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (!isError) { >- events.onPeerConnectionError(errorMessage); >- isError = true; >- } >+ executor.execute(() -> { >+ if (!isError) { >+ events.onPeerConnectionError(errorMessage); >+ isError = true; > } > }); > } > >+ @Nullable > private AudioTrack createAudioTrack() { > audioSource = factory.createAudioSource(audioConstraints); > localAudioTrack = factory.createAudioTrack(AUDIO_TRACK_ID, audioSource); >@@ -964,8 +980,12 @@ public class PeerConnectionClient { > return localAudioTrack; > } > >+ @Nullable > private VideoTrack createVideoTrack(VideoCapturer capturer) { >- videoSource = factory.createVideoSource(capturer); >+ surfaceTextureHelper = >+ SurfaceTextureHelper.create("CaptureThread", rootEglBase.getEglBaseContext()); >+ videoSource = factory.createVideoSource(capturer.isScreencast()); >+ capturer.initialize(surfaceTextureHelper, appContext, videoSource.getCapturerObserver()); > capturer.startCapture(videoWidth, videoHeight, videoFps); > > localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource); >@@ -986,6 +1006,46 @@ public class PeerConnectionClient { > } > } > >+ // Returns the remote VideoTrack, assuming there is only one. >+ private @Nullable VideoTrack getRemoteVideoTrack() { >+ for (RtpTransceiver transceiver : peerConnection.getTransceivers()) { >+ MediaStreamTrack track = transceiver.getReceiver().track(); >+ if (track instanceof VideoTrack) { >+ return (VideoTrack) track; >+ } >+ } >+ return null; >+ } >+ >+ private static String getSdpVideoCodecName(PeerConnectionParameters parameters) { >+ switch (parameters.videoCodec) { >+ case VIDEO_CODEC_VP8: >+ return VIDEO_CODEC_VP8; >+ case VIDEO_CODEC_VP9: >+ return VIDEO_CODEC_VP9; >+ case VIDEO_CODEC_H264_HIGH: >+ case VIDEO_CODEC_H264_BASELINE: >+ return VIDEO_CODEC_H264; >+ default: >+ return VIDEO_CODEC_VP8; >+ } >+ } >+ >+ private static String getFieldTrials(PeerConnectionParameters peerConnectionParameters) { >+ String fieldTrials = ""; >+ if (peerConnectionParameters.videoFlexfecEnabled) { >+ fieldTrials += VIDEO_FLEXFEC_FIELDTRIAL; >+ Log.d(TAG, "Enable FlexFEC field trial."); >+ } >+ fieldTrials += VIDEO_VP8_INTEL_HW_ENCODER_FIELDTRIAL; >+ if (peerConnectionParameters.disableWebRtcAGCAndHPF) { >+ fieldTrials += DISABLE_WEBRTC_AGC_FIELDTRIAL; >+ Log.d(TAG, "Disable WebRTC AGC field trial."); >+ } >+ return fieldTrials; >+ } >+ >+ @SuppressWarnings("StringSplitter") > private static String setStartBitrate( > String codec, boolean isVideoCodec, String sdpDescription, int bitrateKbps) { > String[] lines = sdpDescription.split("\r\n"); >@@ -1076,7 +1136,8 @@ public class PeerConnectionClient { > return buffer.toString(); > } > >- private static String movePayloadTypesToFront(List<String> preferredPayloadTypes, String mLine) { >+ private static @Nullable String movePayloadTypesToFront( >+ List<String> preferredPayloadTypes, String mLine) { > // The format of the media description line should be: m=<media> <port> <proto> <fmt> ... > final List<String> origLineParts = Arrays.asList(mLine.split(" ")); > if (origLineParts.size() <= 3) { >@@ -1140,8 +1201,9 @@ public class PeerConnectionClient { > > private void switchCameraInternal() { > if (videoCapturer instanceof CameraVideoCapturer) { >- if (!videoCallEnabled || isError) { >- Log.e(TAG, "Failed to switch camera. Video: " + videoCallEnabled + ". Error : " + isError); >+ if (!isVideoCallEnabled() || isError) { >+ Log.e(TAG, >+ "Failed to switch camera. Video: " + isVideoCallEnabled() + ". Error : " + isError); > return; // No video is sent or only one camera is available or error happened. > } > Log.d(TAG, "Switch camera"); >@@ -1153,27 +1215,18 @@ public class PeerConnectionClient { > } > > public void switchCamera() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- switchCameraInternal(); >- } >- }); >+ executor.execute(this ::switchCameraInternal); > } > > public void changeCaptureFormat(final int width, final int height, final int framerate) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- changeCaptureFormatInternal(width, height, framerate); >- } >- }); >+ executor.execute(() -> changeCaptureFormatInternal(width, height, framerate)); > } > > private void changeCaptureFormatInternal(int width, int height, int framerate) { >- if (!videoCallEnabled || isError || videoCapturer == null) { >+ if (!isVideoCallEnabled() || isError || videoCapturer == null) { > Log.e(TAG, >- "Failed to change capture format. Video: " + videoCallEnabled + ". Error : " + isError); >+ "Failed to change capture format. Video: " + isVideoCallEnabled() >+ + ". Error : " + isError); > return; > } > Log.d(TAG, "changeCaptureFormat: " + width + "x" + height + "@" + framerate); >@@ -1184,22 +1237,12 @@ public class PeerConnectionClient { > private class PCObserver implements PeerConnection.Observer { > @Override > public void onIceCandidate(final IceCandidate candidate) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- events.onIceCandidate(candidate); >- } >- }); >+ executor.execute(() -> events.onIceCandidate(candidate)); > } > > @Override > public void onIceCandidatesRemoved(final IceCandidate[] candidates) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- events.onIceCandidatesRemoved(candidates); >- } >- }); >+ executor.execute(() -> events.onIceCandidatesRemoved(candidates)); > } > > @Override >@@ -1209,17 +1252,14 @@ public class PeerConnectionClient { > > @Override > public void onIceConnectionChange(final PeerConnection.IceConnectionState newState) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- Log.d(TAG, "IceConnectionState: " + newState); >- if (newState == IceConnectionState.CONNECTED) { >- events.onIceConnected(); >- } else if (newState == IceConnectionState.DISCONNECTED) { >- events.onIceDisconnected(); >- } else if (newState == IceConnectionState.FAILED) { >- reportError("ICE connection failed."); >- } >+ executor.execute(() -> { >+ Log.d(TAG, "IceConnectionState: " + newState); >+ if (newState == IceConnectionState.CONNECTED) { >+ events.onIceConnected(); >+ } else if (newState == IceConnectionState.DISCONNECTED) { >+ events.onIceDisconnected(); >+ } else if (newState == IceConnectionState.FAILED) { >+ reportError("ICE connection failed."); > } > }); > } >@@ -1235,37 +1275,10 @@ public class PeerConnectionClient { > } > > @Override >- public void onAddStream(final MediaStream stream) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection == null || isError) { >- return; >- } >- if (stream.audioTracks.size() > 1 || stream.videoTracks.size() > 1) { >- reportError("Weird-looking stream: " + stream); >- return; >- } >- if (stream.videoTracks.size() == 1) { >- remoteVideoTrack = stream.videoTracks.get(0); >- remoteVideoTrack.setEnabled(renderVideo); >- for (VideoRenderer.Callbacks remoteRender : remoteRenders) { >- remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender)); >- } >- } >- } >- }); >- } >+ public void onAddStream(final MediaStream stream) {} > > @Override >- public void onRemoveStream(final MediaStream stream) { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- remoteVideoTrack = null; >- } >- }); >- } >+ public void onRemoveStream(final MediaStream stream) {} > > @Override > public void onDataChannel(final DataChannel dc) { >@@ -1323,57 +1336,52 @@ public class PeerConnectionClient { > if (preferIsac) { > sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true); > } >- if (videoCallEnabled) { >- sdpDescription = preferCodec(sdpDescription, preferredVideoCodec, false); >+ if (isVideoCallEnabled()) { >+ sdpDescription = >+ preferCodec(sdpDescription, getSdpVideoCodecName(peerConnectionParameters), false); > } > final SessionDescription sdp = new SessionDescription(origSdp.type, sdpDescription); > localSdp = sdp; >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection != null && !isError) { >- Log.d(TAG, "Set local SDP from " + sdp.type); >- peerConnection.setLocalDescription(sdpObserver, sdp); >- } >+ executor.execute(() -> { >+ if (peerConnection != null && !isError) { >+ Log.d(TAG, "Set local SDP from " + sdp.type); >+ peerConnection.setLocalDescription(sdpObserver, sdp); > } > }); > } > > @Override > public void onSetSuccess() { >- executor.execute(new Runnable() { >- @Override >- public void run() { >- if (peerConnection == null || isError) { >- return; >+ executor.execute(() -> { >+ if (peerConnection == null || isError) { >+ return; >+ } >+ if (isInitiator) { >+ // For offering peer connection we first create offer and set >+ // local SDP, then after receiving answer set remote SDP. >+ if (peerConnection.getRemoteDescription() == null) { >+ // We've just set our local SDP so time to send it. >+ Log.d(TAG, "Local SDP set succesfully"); >+ events.onLocalDescription(localSdp); >+ } else { >+ // We've just set remote description, so drain remote >+ // and send local ICE candidates. >+ Log.d(TAG, "Remote SDP set succesfully"); >+ drainCandidates(); > } >- if (isInitiator) { >- // For offering peer connection we first create offer and set >- // local SDP, then after receiving answer set remote SDP. >- if (peerConnection.getRemoteDescription() == null) { >- // We've just set our local SDP so time to send it. >- Log.d(TAG, "Local SDP set succesfully"); >- events.onLocalDescription(localSdp); >- } else { >- // We've just set remote description, so drain remote >- // and send local ICE candidates. >- Log.d(TAG, "Remote SDP set succesfully"); >- drainCandidates(); >- } >+ } else { >+ // For answering peer connection we set remote SDP and then >+ // create answer and set local SDP. >+ if (peerConnection.getLocalDescription() != null) { >+ // We've just set our local SDP so time to send it, drain >+ // remote and send local ICE candidates. >+ Log.d(TAG, "Local SDP set succesfully"); >+ events.onLocalDescription(localSdp); >+ drainCandidates(); > } else { >- // For answering peer connection we set remote SDP and then >- // create answer and set local SDP. >- if (peerConnection.getLocalDescription() != null) { >- // We've just set our local SDP so time to send it, drain >- // remote and send local ICE candidates. >- Log.d(TAG, "Local SDP set succesfully"); >- events.onLocalDescription(localSdp); >- drainCandidates(); >- } else { >- // We've just set remote SDP - do nothing for now - >- // answer will be created soon. >- Log.d(TAG, "Remote SDP set succesfully"); >- } >+ // We've just set remote SDP - do nothing for now - >+ // answer will be created soon. >+ Log.d(TAG, "Remote SDP set succesfully"); > } > } > }); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java >new file mode 100644 >index 00000000000..ede98194330 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RecordedAudioToFileController.java >@@ -0,0 +1,154 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+package org.appspot.apprtc; >+ >+import android.media.AudioFormat; >+import android.os.Environment; >+import javax.annotation.Nullable; >+import android.util.Log; >+import java.io.File; >+import java.io.FileOutputStream; >+import java.io.FileNotFoundException; >+import java.io.IOException; >+import java.io.OutputStream; >+import java.util.concurrent.ExecutorService; >+import org.webrtc.audio.JavaAudioDeviceModule; >+import org.webrtc.audio.JavaAudioDeviceModule.SamplesReadyCallback; >+import org.webrtc.voiceengine.WebRtcAudioRecord; >+import org.webrtc.voiceengine.WebRtcAudioRecord.WebRtcAudioRecordSamplesReadyCallback; >+ >+/** >+ * Implements the AudioRecordSamplesReadyCallback interface and writes >+ * recorded raw audio samples to an output file. >+ */ >+public class RecordedAudioToFileController >+ implements SamplesReadyCallback, WebRtcAudioRecordSamplesReadyCallback { >+ private static final String TAG = "RecordedAudioToFile"; >+ private static final long MAX_FILE_SIZE_IN_BYTES = 58348800L; >+ >+ private final Object lock = new Object(); >+ private final ExecutorService executor; >+ @Nullable >+ private OutputStream rawAudioFileOutputStream = null; >+ private boolean isRunning; >+ private long fileSizeInBytes = 0; >+ >+ public RecordedAudioToFileController(ExecutorService executor) { >+ Log.d(TAG, "ctor"); >+ this.executor = executor; >+ } >+ >+ /** >+ * Should be called on the same executor thread as the one provided at >+ * construction. >+ */ >+ public boolean start() { >+ Log.d(TAG, "start"); >+ if (!isExternalStorageWritable()) { >+ Log.e(TAG, "Writing to external media is not possible"); >+ return false; >+ } >+ synchronized (lock) { >+ isRunning = true; >+ } >+ return true; >+ } >+ >+ /** >+ * Should be called on the same executor thread as the one provided at >+ * construction. >+ */ >+ public void stop() { >+ Log.d(TAG, "stop"); >+ synchronized (lock) { >+ isRunning = false; >+ if (rawAudioFileOutputStream != null) { >+ try { >+ rawAudioFileOutputStream.close(); >+ } catch (IOException e) { >+ Log.e(TAG, "Failed to close file with saved input audio: " + e); >+ } >+ rawAudioFileOutputStream = null; >+ } >+ fileSizeInBytes = 0; >+ } >+ } >+ >+ // Checks if external storage is available for read and write. >+ private boolean isExternalStorageWritable() { >+ String state = Environment.getExternalStorageState(); >+ if (Environment.MEDIA_MOUNTED.equals(state)) { >+ return true; >+ } >+ return false; >+ } >+ >+ // Utilizes audio parameters to create a file name which contains sufficient >+ // information so that the file can be played using an external file player. >+ // Example: /sdcard/recorded_audio_16bits_48000Hz_mono.pcm. >+ private void openRawAudioOutputFile(int sampleRate, int channelCount) { >+ final String fileName = Environment.getExternalStorageDirectory().getPath() + File.separator >+ + "recorded_audio_16bits_" + String.valueOf(sampleRate) + "Hz" >+ + ((channelCount == 1) ? "_mono" : "_stereo") + ".pcm"; >+ final File outputFile = new File(fileName); >+ try { >+ rawAudioFileOutputStream = new FileOutputStream(outputFile); >+ } catch (FileNotFoundException e) { >+ Log.e(TAG, "Failed to open audio output file: " + e.getMessage()); >+ } >+ Log.d(TAG, "Opened file for recording: " + fileName); >+ } >+ >+ // Called when new audio samples are ready. >+ @Override >+ public void onWebRtcAudioRecordSamplesReady(WebRtcAudioRecord.AudioSamples samples) { >+ onWebRtcAudioRecordSamplesReady(new JavaAudioDeviceModule.AudioSamples(samples.getAudioFormat(), >+ samples.getChannelCount(), samples.getSampleRate(), samples.getData())); >+ } >+ >+ // Called when new audio samples are ready. >+ @Override >+ public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples samples) { >+ // The native audio layer on Android should use 16-bit PCM format. >+ if (samples.getAudioFormat() != AudioFormat.ENCODING_PCM_16BIT) { >+ Log.e(TAG, "Invalid audio format"); >+ return; >+ } >+ synchronized (lock) { >+ // Abort early if stop() has been called. >+ if (!isRunning) { >+ return; >+ } >+ // Open a new file for the first callback only since it allows us to add audio parameters to >+ // the file name. >+ if (rawAudioFileOutputStream == null) { >+ openRawAudioOutputFile(samples.getSampleRate(), samples.getChannelCount()); >+ fileSizeInBytes = 0; >+ } >+ } >+ // Append the recorded 16-bit audio samples to the open output file. >+ executor.execute(() -> { >+ if (rawAudioFileOutputStream != null) { >+ try { >+ // Set a limit on max file size. 58348800 bytes corresponds to >+ // approximately 10 minutes of recording in mono at 48kHz. >+ if (fileSizeInBytes < MAX_FILE_SIZE_IN_BYTES) { >+ // Writes samples.getData().length bytes to output stream. >+ rawAudioFileOutputStream.write(samples.getData()); >+ fileSizeInBytes += samples.getData().length; >+ } >+ } catch (IOException e) { >+ Log.e(TAG, "Failed to write audio to file: " + e.getMessage()); >+ } >+ } >+ }); >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RtcEventLog.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RtcEventLog.java >new file mode 100644 >index 00000000000..bbbd06b1eec >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/RtcEventLog.java >@@ -0,0 +1,74 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+package org.appspot.apprtc; >+ >+import android.content.Context; >+import android.os.ParcelFileDescriptor; >+import android.util.Log; >+import java.io.File; >+import java.io.IOException; >+import org.webrtc.PeerConnection; >+ >+public class RtcEventLog { >+ private static final String TAG = "RtcEventLog"; >+ private static final int OUTPUT_FILE_MAX_BYTES = 10_000_000; >+ private final PeerConnection peerConnection; >+ private RtcEventLogState state = RtcEventLogState.INACTIVE; >+ >+ enum RtcEventLogState { >+ INACTIVE, >+ STARTED, >+ STOPPED, >+ } >+ >+ public RtcEventLog(PeerConnection peerConnection) { >+ if (peerConnection == null) { >+ throw new NullPointerException("The peer connection is null."); >+ } >+ this.peerConnection = peerConnection; >+ } >+ >+ public void start(final File outputFile) { >+ if (state == RtcEventLogState.STARTED) { >+ Log.e(TAG, "RtcEventLog has already started."); >+ return; >+ } >+ final ParcelFileDescriptor fileDescriptor; >+ try { >+ fileDescriptor = ParcelFileDescriptor.open(outputFile, >+ ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE >+ | ParcelFileDescriptor.MODE_TRUNCATE); >+ } catch (IOException e) { >+ Log.e(TAG, "Failed to create a new file", e); >+ return; >+ } >+ >+ // Passes ownership of the file to WebRTC. >+ boolean success = >+ peerConnection.startRtcEventLog(fileDescriptor.detachFd(), OUTPUT_FILE_MAX_BYTES); >+ if (!success) { >+ Log.e(TAG, "Failed to start RTC event log."); >+ return; >+ } >+ state = RtcEventLogState.STARTED; >+ Log.d(TAG, "RtcEventLog started."); >+ } >+ >+ public void stop() { >+ if (state != RtcEventLogState.STARTED) { >+ Log.e(TAG, "RtcEventLog was not started."); >+ return; >+ } >+ peerConnection.stopRtcEventLog(); >+ state = RtcEventLogState.STOPPED; >+ Log.d(TAG, "RtcEventLog stopped."); >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/SettingsActivity.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/SettingsActivity.java >index 43b8a0a662e..8a556c335f6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/SettingsActivity.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/SettingsActivity.java >@@ -17,7 +17,7 @@ import android.os.Bundle; > import android.preference.ListPreference; > import android.preference.Preference; > import org.webrtc.Camera2Enumerator; >-import org.webrtc.voiceengine.WebRtcAudioUtils; >+import org.webrtc.audio.JavaAudioDeviceModule; > > /** > * Settings activity for AppRTC. >@@ -42,17 +42,18 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > private String keyPrefAudioCodec; > private String keyprefNoAudioProcessing; > private String keyprefAecDump; >+ private String keyprefEnableSaveInputAudioToFile; > private String keyprefOpenSLES; > private String keyprefDisableBuiltInAEC; > private String keyprefDisableBuiltInAGC; > private String keyprefDisableBuiltInNS; >- private String keyprefEnableLevelControl; > private String keyprefDisableWebRtcAGCAndHPF; > private String keyprefSpeakerphone; > > private String keyPrefRoomServerUrl; > private String keyPrefDisplayHud; > private String keyPrefTracing; >+ private String keyprefEnabledRtcEventLog; > > private String keyprefEnableDataChannel; > private String keyprefOrdered; >@@ -61,6 +62,7 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > private String keyprefDataProtocol; > private String keyprefNegotiated; > private String keyprefDataId; >+ private String keyprefUseLegacyAudioDevice; > > @Override > protected void onCreate(Bundle savedInstanceState) { >@@ -83,11 +85,12 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > keyPrefAudioCodec = getString(R.string.pref_audiocodec_key); > keyprefNoAudioProcessing = getString(R.string.pref_noaudioprocessing_key); > keyprefAecDump = getString(R.string.pref_aecdump_key); >+ keyprefEnableSaveInputAudioToFile = >+ getString(R.string.pref_enable_save_input_audio_to_file_key); > keyprefOpenSLES = getString(R.string.pref_opensles_key); > keyprefDisableBuiltInAEC = getString(R.string.pref_disable_built_in_aec_key); > keyprefDisableBuiltInAGC = getString(R.string.pref_disable_built_in_agc_key); > keyprefDisableBuiltInNS = getString(R.string.pref_disable_built_in_ns_key); >- keyprefEnableLevelControl = getString(R.string.pref_enable_level_control_key); > keyprefDisableWebRtcAGCAndHPF = getString(R.string.pref_disable_webrtc_agc_and_hpf_key); > keyprefSpeakerphone = getString(R.string.pref_speakerphone_key); > >@@ -102,6 +105,8 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > keyPrefRoomServerUrl = getString(R.string.pref_room_server_url_key); > keyPrefDisplayHud = getString(R.string.pref_displayhud_key); > keyPrefTracing = getString(R.string.pref_tracing_key); >+ keyprefEnabledRtcEventLog = getString(R.string.pref_enable_rtceventlog_key); >+ keyprefUseLegacyAudioDevice = getString(R.string.pref_use_legacy_audio_device_key); > > // Display the fragment as the main content. > settingsFragment = new SettingsFragment(); >@@ -138,11 +143,11 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > updateSummary(sharedPreferences, keyPrefAudioCodec); > updateSummaryB(sharedPreferences, keyprefNoAudioProcessing); > updateSummaryB(sharedPreferences, keyprefAecDump); >+ updateSummaryB(sharedPreferences, keyprefEnableSaveInputAudioToFile); > updateSummaryB(sharedPreferences, keyprefOpenSLES); > updateSummaryB(sharedPreferences, keyprefDisableBuiltInAEC); > updateSummaryB(sharedPreferences, keyprefDisableBuiltInAGC); > updateSummaryB(sharedPreferences, keyprefDisableBuiltInNS); >- updateSummaryB(sharedPreferences, keyprefEnableLevelControl); > updateSummaryB(sharedPreferences, keyprefDisableWebRtcAGCAndHPF); > updateSummaryList(sharedPreferences, keyprefSpeakerphone); > >@@ -158,6 +163,8 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > updateSummary(sharedPreferences, keyPrefRoomServerUrl); > updateSummaryB(sharedPreferences, keyPrefDisplayHud); > updateSummaryB(sharedPreferences, keyPrefTracing); >+ updateSummaryB(sharedPreferences, keyprefEnabledRtcEventLog); >+ updateSummaryB(sharedPreferences, keyprefUseLegacyAudioDevice); > > if (!Camera2Enumerator.isSupported(this)) { > Preference camera2Preference = settingsFragment.findPreference(keyprefCamera2); >@@ -166,10 +173,7 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > camera2Preference.setEnabled(false); > } > >- // Disable forcing WebRTC based AEC so it won't affect our value. >- // Otherwise, if it was enabled, isAcousticEchoCancelerSupported would always return false. >- WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(false); >- if (!WebRtcAudioUtils.isAcousticEchoCancelerSupported()) { >+ if (!JavaAudioDeviceModule.isBuiltInAcousticEchoCancelerSupported()) { > Preference disableBuiltInAECPreference = > settingsFragment.findPreference(keyprefDisableBuiltInAEC); > >@@ -177,17 +181,13 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > disableBuiltInAECPreference.setEnabled(false); > } > >- WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(false); >- if (!WebRtcAudioUtils.isAutomaticGainControlSupported()) { >- Preference disableBuiltInAGCPreference = >- settingsFragment.findPreference(keyprefDisableBuiltInAGC); >+ Preference disableBuiltInAGCPreference = >+ settingsFragment.findPreference(keyprefDisableBuiltInAGC); > >- disableBuiltInAGCPreference.setSummary(getString(R.string.pref_built_in_agc_not_available)); >- disableBuiltInAGCPreference.setEnabled(false); >- } >+ disableBuiltInAGCPreference.setSummary(getString(R.string.pref_built_in_agc_not_available)); >+ disableBuiltInAGCPreference.setEnabled(false); > >- WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(false); >- if (!WebRtcAudioUtils.isNoiseSuppressorSupported()) { >+ if (!JavaAudioDeviceModule.isBuiltInNoiseSuppressorSupported()) { > Preference disableBuiltInNSPreference = > settingsFragment.findPreference(keyprefDisableBuiltInNS); > >@@ -232,16 +232,18 @@ public class SettingsActivity extends Activity implements OnSharedPreferenceChan > || key.equals(keyprefFlexfec) > || key.equals(keyprefNoAudioProcessing) > || key.equals(keyprefAecDump) >+ || key.equals(keyprefEnableSaveInputAudioToFile) > || key.equals(keyprefOpenSLES) > || key.equals(keyprefDisableBuiltInAEC) > || key.equals(keyprefDisableBuiltInAGC) > || key.equals(keyprefDisableBuiltInNS) >- || key.equals(keyprefEnableLevelControl) > || key.equals(keyprefDisableWebRtcAGCAndHPF) > || key.equals(keyPrefDisplayHud) > || key.equals(keyprefEnableDataChannel) > || key.equals(keyprefOrdered) >- || key.equals(keyprefNegotiated)) { >+ || key.equals(keyprefNegotiated) >+ || key.equals(keyprefEnabledRtcEventLog) >+ || key.equals(keyprefUseLegacyAudioDevice)) { > updateSummaryB(sharedPreferences, key); > } else if (key.equals(keyprefSpeakerphone)) { > updateSummaryList(sharedPreferences, key); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/TCPChannelClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/TCPChannelClient.java >index 39f41f86174..e9fd7be4059 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/TCPChannelClient.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/TCPChannelClient.java >@@ -10,6 +10,7 @@ > > package org.appspot.apprtc; > >+import javax.annotation.Nullable; > import android.util.Log; > import java.io.BufferedReader; > import java.io.IOException; >@@ -123,7 +124,9 @@ public class TCPChannelClient { > private abstract class TCPSocket extends Thread { > // Lock for editing out and rawSocket > protected final Object rawSocketLock; >+ @Nullable > private PrintWriter out; >+ @Nullable > private Socket rawSocket; > > /** >@@ -131,6 +134,7 @@ public class TCPChannelClient { > * > * @return Socket connection, null if connection failed. > */ >+ @Nullable > public abstract Socket connect(); > > /** Returns true if sockets is a server rawSocket. */ >@@ -263,6 +267,7 @@ public class TCPChannelClient { > > private class TCPSocketServer extends TCPSocket { > // Server socket is also guarded by rawSocketLock. >+ @Nullable > private ServerSocket serverSocket; > > final private InetAddress address; >@@ -274,6 +279,7 @@ public class TCPChannelClient { > } > > /** Opens a listening socket and waits for a connection. */ >+ @Nullable > @Override > public Socket connect() { > Log.d(TAG, "Listening on [" + address.getHostAddress() + "]:" + Integer.toString(port)); >@@ -335,6 +341,7 @@ public class TCPChannelClient { > } > > /** Connects to the peer. */ >+ @Nullable > @Override > public Socket connect() { > Log.d(TAG, "Connecting to [" + address.getHostAddress() + "]:" + Integer.toString(port)); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketChannelClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketChannelClient.java >index d3e5c8751b0..07b78472f41 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketChannelClient.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketChannelClient.java >@@ -11,6 +11,7 @@ > package org.appspot.apprtc; > > import android.os.Handler; >+import javax.annotation.Nullable; > import android.util.Log; > import de.tavendo.autobahn.WebSocket.WebSocketConnectionObserver; > import de.tavendo.autobahn.WebSocketConnection; >@@ -39,7 +40,9 @@ public class WebSocketChannelClient { > private WebSocketConnection ws; > private String wsServerUrl; > private String postServerUrl; >+ @Nullable > private String roomID; >+ @Nullable > private String clientID; > private WebSocketConnectionState state; > // Do not remove this member variable. If this is removed, the observer gets garbage collected and >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketRTCClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketRTCClient.java >index 32150519346..dbe34bed1b1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketRTCClient.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/src/org/appspot/apprtc/WebSocketRTCClient.java >@@ -10,6 +10,7 @@ > > package org.appspot.apprtc; > >+import javax.annotation.Nullable; > import org.appspot.apprtc.RoomParametersFetcher.RoomParametersFetcherEvents; > import org.appspot.apprtc.WebSocketChannelClient.WebSocketChannelEvents; > import org.appspot.apprtc.WebSocketChannelClient.WebSocketConnectionState; >@@ -380,7 +381,7 @@ public class WebSocketRTCClient implements AppRTCClient, WebSocketChannelEvents > > // Send SDP or ICE candidate to a room server. > private void sendPostMessage( >- final MessageType messageType, final String url, final String message) { >+ final MessageType messageType, final String url, @Nullable final String message) { > String logInfo = url; > if (message != null) { > logInfo += ". Message: " + message; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/third_party/autobanh/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/third_party/autobanh/BUILD.gn >index d5f6b0f2d6a..b671239bae7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/third_party/autobanh/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidapp/third_party/autobanh/BUILD.gn >@@ -6,8 +6,10 @@ > # in the file PATENTS. All contributing project authors may > # be found in the AUTHORS file in the root of the source tree. > >-import("//build/config/android/rules.gni") >+if (is_android) { >+ import("//build/config/android/rules.gni") > >-android_java_prebuilt("autobanh_java") { >- jar_path = "lib/autobanh.jar" >+ android_java_prebuilt("autobanh_java") { >+ jar_path = "lib/autobanh.jar" >+ } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/BluetoothManagerTest.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/BluetoothManagerTest.java >index 0724ec17c0c..b97f1f0bf6f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/BluetoothManagerTest.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/BluetoothManagerTest.java >@@ -11,11 +11,8 @@ > package org.appspot.apprtc; > > import static org.junit.Assert.assertEquals; >-import static org.junit.Assert.assertFalse; > import static org.junit.Assert.assertNotNull; > import static org.junit.Assert.assertNull; >-import static org.junit.Assert.assertTrue; >-import static org.mockito.Mockito.doCallRealMethod; > import static org.mockito.Mockito.mock; > import static org.mockito.Mockito.never; > import static org.mockito.Mockito.times; >@@ -39,8 +36,8 @@ import org.chromium.testing.local.LocalRobolectricTestRunner; > import org.junit.Before; > import org.junit.Test; > import org.junit.runner.RunWith; >+import org.robolectric.RuntimeEnvironment; > import org.robolectric.annotation.Config; >-import org.robolectric.shadows.ShadowApplication; > import org.robolectric.shadows.ShadowLog; > > /** >@@ -68,7 +65,7 @@ public class BluetoothManagerTest { > @Before > public void setUp() { > ShadowLog.stream = System.out; >- context = ShadowApplication.getInstance().getApplicationContext(); >+ context = RuntimeEnvironment.application; > mockedAppRtcAudioManager = mock(AppRTCAudioManager.class); > mockedAudioManager = mock(AudioManager.class); > mockedBluetoothHeadset = mock(BluetoothHeadset.class); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/TCPChannelClientTest.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/TCPChannelClientTest.java >index 0f4916aa48c..8c5f38ccb31 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/TCPChannelClientTest.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidjunit/src/org/appspot/apprtc/TCPChannelClientTest.java >@@ -35,10 +35,10 @@ import java.util.concurrent.TimeUnit; > public class TCPChannelClientTest { > private static final int PORT = 8888; > /** >- * How long we wait before trying to connect to the server. Chosen quite arbitrarily and >- * could be made smaller if need be. >+ * How long we wait before trying to connect to the server. Note: was >+ * previously only 10, which was too short (tests were flaky). > */ >- private static final int SERVER_WAIT = 10; >+ private static final int SERVER_WAIT = 100; > private static final int CONNECT_TIMEOUT = 100; > private static final int SEND_TIMEOUT = 100; > private static final int DISCONNECT_TIMEOUT = 100; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/AndroidManifest.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/AndroidManifest.xml >new file mode 100644 >index 00000000000..f10f55a1b68 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/AndroidManifest.xml >@@ -0,0 +1,23 @@ >+<?xml version="1.0" encoding="utf-8"?> >+<manifest xmlns:android="http://schemas.android.com/apk/res/android" >+ package="org.webrtc.examples.androidnativeapi"> >+ >+ <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="27" /> >+ >+ <uses-permission android:name="android.permission.INTERNET" /> >+ <uses-permission android:name="android.permission.CAMERA" /> >+ >+ <application >+ android:allowBackup="true" >+ android:label="@string/app_name" >+ android:supportsRtl="true"> >+ <activity android:name=".MainActivity"> >+ <intent-filter> >+ <action android:name="android.intent.action.MAIN" /> >+ >+ <category android:name="android.intent.category.LAUNCHER" /> >+ </intent-filter> >+ </activity> >+ </application> >+ >+</manifest> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/BUILD.gn >new file mode 100644 >index 00000000000..f96fab2e8e4 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/BUILD.gn >@@ -0,0 +1,75 @@ >+import("//webrtc.gni") >+ >+if (is_android) { >+ rtc_android_apk("androidnativeapi") { >+ testonly = true >+ apk_name = "androidnativeapi" >+ android_manifest = "AndroidManifest.xml" >+ >+ java_files = [ >+ "java/org/webrtc/examples/androidnativeapi/MainActivity.java", >+ "java/org/webrtc/examples/androidnativeapi/CallClient.java", >+ ] >+ >+ deps = [ >+ ":resources", >+ "//modules/audio_device:audio_device_java", >+ "//sdk/android:camera_java", >+ "//sdk/android:surfaceviewrenderer_java", >+ "//sdk/android:video_api_java", >+ "//sdk/android:video_java", >+ ] >+ >+ shared_libraries = [ ":examples_androidnativeapi_jni" ] >+ } >+ >+ generate_jni("generated_jni") { >+ testonly = true >+ sources = [ >+ "java/org/webrtc/examples/androidnativeapi/CallClient.java", >+ ] >+ jni_package = "" >+ namespace = "webrtc_examples" >+ jni_generator_include = "//sdk/android/src/jni/jni_generator_helper.h" >+ } >+ >+ rtc_shared_library("examples_androidnativeapi_jni") { >+ testonly = true >+ sources = [ >+ "jni/androidcallclient.cc", >+ "jni/androidcallclient.h", >+ "jni/onload.cc", >+ ] >+ >+ suppressed_configs += [ "//build/config/android:hide_all_but_jni_onload" ] >+ configs += [ "//build/config/android:hide_all_but_jni" ] >+ >+ deps = [ >+ ":generated_jni", >+ "//api:libjingle_peerconnection_api", >+ "//api/audio_codecs:builtin_audio_decoder_factory", >+ "//api/audio_codecs:builtin_audio_encoder_factory", >+ "//logging:rtc_event_log_impl_base", >+ "//media:rtc_audio_video", >+ "//media:rtc_internal_video_codecs", >+ "//modules/audio_processing", >+ "//modules/utility:utility", >+ "//pc:libjingle_peerconnection", >+ "//rtc_base:rtc_base", >+ "//rtc_base:rtc_base_approved", >+ "//sdk/android:native_api_base", >+ "//sdk/android:native_api_jni", >+ "//sdk/android:native_api_video", >+ "//system_wrappers:field_trial_default", >+ "//system_wrappers:metrics_default", >+ "//system_wrappers:runtime_enabled_features_default", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+ } >+ >+ android_resources("resources") { >+ testonly = true >+ resource_dirs = [ "res" ] >+ custom_package = "org.webrtc.examples.androidnativeapi" >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/DEPS >new file mode 100644 >index 00000000000..2d4c0d8bfbd >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/DEPS >@@ -0,0 +1,4 @@ >+include_rules = [ >+ "+modules/utility/include", >+ "+sdk/android/native_api", >+] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/OWNERS >new file mode 100644 >index 00000000000..3c4e54174e6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/OWNERS >@@ -0,0 +1 @@ >+sakal@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java >new file mode 100644 >index 00000000000..7369a1286d0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/CallClient.java >@@ -0,0 +1,72 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+package org.webrtc.examples.androidnativeapi; >+ >+import android.content.Context; >+import android.os.Handler; >+import android.os.HandlerThread; >+import org.webrtc.CapturerObserver; >+import org.webrtc.SurfaceTextureHelper; >+import org.webrtc.VideoCapturer; >+import org.webrtc.VideoSink; >+ >+public class CallClient { >+ private static final String TAG = "CallClient"; >+ private static final int CAPTURE_WIDTH = 640; >+ private static final int CAPTURE_HEIGHT = 480; >+ private static final int CAPTURE_FPS = 30; >+ >+ private final Context applicationContext; >+ private final HandlerThread thread; >+ private final Handler handler; >+ >+ private long nativeClient; >+ private SurfaceTextureHelper surfaceTextureHelper; >+ private VideoCapturer videoCapturer; >+ >+ public CallClient(Context applicationContext) { >+ this.applicationContext = applicationContext; >+ thread = new HandlerThread(TAG + "Thread"); >+ thread.start(); >+ handler = new Handler(thread.getLooper()); >+ handler.post(() -> { nativeClient = nativeCreateClient(); }); >+ } >+ >+ public void call(VideoSink localSink, VideoSink remoteSink, VideoCapturer videoCapturer, >+ SurfaceTextureHelper videoCapturerSurfaceTextureHelper) { >+ handler.post(() -> { >+ nativeCall(nativeClient, localSink, remoteSink); >+ videoCapturer.initialize(videoCapturerSurfaceTextureHelper, applicationContext, >+ nativeGetJavaVideoCapturerObserver(nativeClient)); >+ videoCapturer.startCapture(CAPTURE_WIDTH, CAPTURE_HEIGHT, CAPTURE_FPS); >+ }); >+ } >+ >+ public void hangup() { >+ handler.post(() -> { nativeHangup(nativeClient); }); >+ } >+ >+ public void close() { >+ handler.post(() -> { >+ nativeDelete(nativeClient); >+ nativeClient = 0; >+ }); >+ thread.quitSafely(); >+ } >+ >+ private static native long nativeCreateClient(); >+ private static native void nativeCall( >+ long nativeAndroidCallClient, VideoSink localSink, VideoSink remoteSink); >+ private static native void nativeHangup(long nativeAndroidCallClient); >+ private static native void nativeDelete(long nativeAndroidCallClient); >+ private static native CapturerObserver nativeGetJavaVideoCapturerObserver( >+ long nativeAndroidCallClient); >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java >new file mode 100644 >index 00000000000..801e238782d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/java/org/webrtc/examples/androidnativeapi/MainActivity.java >@@ -0,0 +1,120 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+package org.webrtc.examples.androidnativeapi; >+ >+import android.app.Activity; >+import android.content.Context; >+import android.os.Bundle; >+import android.widget.Button; >+import javax.annotation.Nullable; >+import org.webrtc.Camera1Enumerator; >+import org.webrtc.Camera2Enumerator; >+import org.webrtc.CameraEnumerator; >+import org.webrtc.ContextUtils; >+import org.webrtc.EglBase; >+import org.webrtc.GlRectDrawer; >+import org.webrtc.SurfaceTextureHelper; >+import org.webrtc.SurfaceViewRenderer; >+import org.webrtc.VideoCapturer; >+ >+public class MainActivity extends Activity { >+ private @Nullable CallClient callClient; >+ private @Nullable EglBase eglBase; >+ private @Nullable SurfaceViewRenderer localRenderer; >+ private @Nullable SurfaceViewRenderer remoteRenderer; >+ private @Nullable SurfaceTextureHelper videoCapturerSurfaceTextureHelper; >+ private @Nullable VideoCapturer videoCapturer; >+ >+ @Override >+ protected void onCreate(Bundle savedInstance) { >+ ContextUtils.initialize(getApplicationContext()); >+ >+ super.onCreate(savedInstance); >+ setContentView(R.layout.activity_main); >+ >+ System.loadLibrary("examples_androidnativeapi_jni"); >+ callClient = new CallClient(getApplicationContext()); >+ >+ Button callButton = (Button) findViewById(R.id.call_button); >+ callButton.setOnClickListener((view) -> { >+ if (videoCapturer == null) { >+ videoCapturer = createVideoCapturer(getApplicationContext()); >+ } >+ callClient.call( >+ localRenderer, remoteRenderer, videoCapturer, videoCapturerSurfaceTextureHelper); >+ }); >+ >+ Button hangupButton = (Button) findViewById(R.id.hangup_button); >+ hangupButton.setOnClickListener((view) -> { hangup(); }); >+ } >+ >+ @Override >+ protected void onStart() { >+ super.onStart(); >+ >+ eglBase = EglBase.create(null /* sharedContext */, EglBase.CONFIG_PLAIN); >+ localRenderer = (SurfaceViewRenderer) findViewById(R.id.local_renderer); >+ remoteRenderer = (SurfaceViewRenderer) findViewById(R.id.remote_renderer); >+ >+ localRenderer.init(eglBase.getEglBaseContext(), null /* rendererEvents */, EglBase.CONFIG_PLAIN, >+ new GlRectDrawer()); >+ remoteRenderer.init(eglBase.getEglBaseContext(), null /* rendererEvents */, >+ EglBase.CONFIG_PLAIN, new GlRectDrawer()); >+ >+ videoCapturerSurfaceTextureHelper = >+ SurfaceTextureHelper.create("VideoCapturerThread", eglBase.getEglBaseContext()); >+ } >+ >+ @Override >+ protected void onStop() { >+ hangup(); >+ >+ localRenderer.release(); >+ remoteRenderer.release(); >+ videoCapturerSurfaceTextureHelper.dispose(); >+ eglBase.release(); >+ >+ localRenderer = null; >+ remoteRenderer = null; >+ videoCapturerSurfaceTextureHelper = null; >+ eglBase = null; >+ >+ super.onStop(); >+ } >+ >+ @Override >+ protected void onDestroy() { >+ callClient.close(); >+ callClient = null; >+ >+ super.onDestroy(); >+ } >+ >+ private void hangup() { >+ if (videoCapturer != null) { >+ try { >+ videoCapturer.stopCapture(); >+ } catch (InterruptedException e) { >+ throw new RuntimeException(e); >+ } >+ videoCapturer.dispose(); >+ videoCapturer = null; >+ } >+ callClient.hangup(); >+ } >+ >+ private static VideoCapturer createVideoCapturer(Context context) { >+ CameraEnumerator enumerator = Camera2Enumerator.isSupported(context) >+ ? new Camera2Enumerator(context) >+ : new Camera1Enumerator(); >+ return enumerator.createCapturer(enumerator.getDeviceNames()[0], null /* eventsHandler */); >+ } >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.cc >new file mode 100644 >index 00000000000..005f369a6d1 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.cc >@@ -0,0 +1,290 @@ >+/* >+ * Copyright 2018 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 "examples/androidnativeapi/jni/androidcallclient.h" >+ >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "api/audio_codecs/builtin_audio_decoder_factory.h" >+#include "api/audio_codecs/builtin_audio_encoder_factory.h" >+#include "api/peerconnectioninterface.h" >+#include "examples/androidnativeapi/generated_jni/jni/CallClient_jni.h" >+#include "media/engine/internaldecoderfactory.h" >+#include "media/engine/internalencoderfactory.h" >+#include "media/engine/webrtcmediaengine.h" >+#include "modules/audio_processing/include/audio_processing.h" >+#include "sdk/android/native_api/jni/java_types.h" >+#include "sdk/android/native_api/video/wrapper.h" >+ >+namespace webrtc_examples { >+ >+class AndroidCallClient::PCObserver : public webrtc::PeerConnectionObserver { >+ public: >+ explicit PCObserver(AndroidCallClient* client); >+ >+ void OnSignalingChange( >+ webrtc::PeerConnectionInterface::SignalingState new_state) override; >+ void OnDataChannel( >+ rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override; >+ void OnRenegotiationNeeded() override; >+ void OnIceConnectionChange( >+ webrtc::PeerConnectionInterface::IceConnectionState new_state) override; >+ void OnIceGatheringChange( >+ webrtc::PeerConnectionInterface::IceGatheringState new_state) override; >+ void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override; >+ >+ private: >+ const AndroidCallClient* client_; >+}; >+ >+namespace { >+ >+class CreateOfferObserver : public webrtc::CreateSessionDescriptionObserver { >+ public: >+ explicit CreateOfferObserver( >+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc); >+ >+ void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; >+ void OnFailure(webrtc::RTCError error) override; >+ >+ private: >+ const rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_; >+}; >+ >+class SetRemoteSessionDescriptionObserver >+ : public webrtc::SetRemoteDescriptionObserverInterface { >+ public: >+ void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override; >+}; >+ >+class SetLocalSessionDescriptionObserver >+ : public webrtc::SetSessionDescriptionObserver { >+ public: >+ void OnSuccess() override; >+ void OnFailure(webrtc::RTCError error) override; >+}; >+ >+} // namespace >+ >+AndroidCallClient::AndroidCallClient() >+ : call_started_(false), pc_observer_(absl::make_unique<PCObserver>(this)) { >+ thread_checker_.DetachFromThread(); >+ CreatePeerConnectionFactory(); >+} >+ >+AndroidCallClient::~AndroidCallClient() = default; >+ >+void AndroidCallClient::Call(JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls, >+ const webrtc::JavaRef<jobject>& local_sink, >+ const webrtc::JavaRef<jobject>& remote_sink) { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ rtc::CritScope lock(&pc_mutex_); >+ if (call_started_) { >+ RTC_LOG(LS_WARNING) << "Call already started."; >+ return; >+ } >+ call_started_ = true; >+ >+ local_sink_ = webrtc::JavaToNativeVideoSink(env, local_sink.obj()); >+ remote_sink_ = webrtc::JavaToNativeVideoSink(env, remote_sink.obj()); >+ >+ video_source_ = webrtc::CreateJavaVideoSource(env, signaling_thread_.get(), >+ false /* is_screencast */); >+ >+ CreatePeerConnection(); >+ Connect(); >+} >+ >+void AndroidCallClient::Hangup(JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls) { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ call_started_ = false; >+ >+ { >+ rtc::CritScope lock(&pc_mutex_); >+ if (pc_ != nullptr) { >+ pc_->Close(); >+ pc_ = nullptr; >+ } >+ } >+ >+ local_sink_ = nullptr; >+ remote_sink_ = nullptr; >+ video_source_ = nullptr; >+} >+ >+void AndroidCallClient::Delete(JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls) { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ delete this; >+} >+ >+webrtc::ScopedJavaLocalRef<jobject> >+AndroidCallClient::GetJavaVideoCapturerObserver( >+ JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls) { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ return video_source_->GetJavaVideoCapturerObserver(env); >+} >+ >+void AndroidCallClient::CreatePeerConnectionFactory() { >+ network_thread_ = rtc::Thread::CreateWithSocketServer(); >+ network_thread_->SetName("network_thread", nullptr); >+ RTC_CHECK(network_thread_->Start()) << "Failed to start thread"; >+ >+ worker_thread_ = rtc::Thread::Create(); >+ worker_thread_->SetName("worker_thread", nullptr); >+ RTC_CHECK(worker_thread_->Start()) << "Failed to start thread"; >+ >+ signaling_thread_ = rtc::Thread::Create(); >+ signaling_thread_->SetName("signaling_thread", nullptr); >+ RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread"; >+ >+ std::unique_ptr<cricket::MediaEngineInterface> media_engine = >+ cricket::WebRtcMediaEngineFactory::Create( >+ nullptr /* adm */, webrtc::CreateBuiltinAudioEncoderFactory(), >+ webrtc::CreateBuiltinAudioDecoderFactory(), >+ absl::make_unique<webrtc::InternalEncoderFactory>(), >+ absl::make_unique<webrtc::InternalDecoderFactory>(), >+ nullptr /* audio_mixer */, webrtc::AudioProcessingBuilder().Create()); >+ RTC_LOG(LS_INFO) << "Media engine created: " << media_engine.get(); >+ >+ pcf_ = CreateModularPeerConnectionFactory( >+ network_thread_.get(), worker_thread_.get(), signaling_thread_.get(), >+ std::move(media_engine), webrtc::CreateCallFactory(), >+ webrtc::CreateRtcEventLogFactory()); >+ RTC_LOG(LS_INFO) << "PeerConnectionFactory created: " << pcf_; >+} >+ >+void AndroidCallClient::CreatePeerConnection() { >+ rtc::CritScope lock(&pc_mutex_); >+ webrtc::PeerConnectionInterface::RTCConfiguration config; >+ config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; >+ // DTLS SRTP has to be disabled for loopback to work. >+ config.enable_dtls_srtp = false; >+ pc_ = pcf_->CreatePeerConnection(config, nullptr /* port_allocator */, >+ nullptr /* cert_generator */, >+ pc_observer_.get()); >+ RTC_LOG(LS_INFO) << "PeerConnection created: " << pc_; >+ >+ rtc::scoped_refptr<webrtc::VideoTrackInterface> local_video_track = >+ pcf_->CreateVideoTrack("video", video_source_); >+ local_video_track->AddOrUpdateSink(local_sink_.get(), rtc::VideoSinkWants()); >+ pc_->AddTransceiver(local_video_track); >+ RTC_LOG(LS_INFO) << "Local video sink set up: " << local_video_track; >+ >+ for (const rtc::scoped_refptr<webrtc::RtpTransceiverInterface>& tranceiver : >+ pc_->GetTransceivers()) { >+ rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = >+ tranceiver->receiver()->track(); >+ if (track && >+ track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { >+ static_cast<webrtc::VideoTrackInterface*>(track.get()) >+ ->AddOrUpdateSink(remote_sink_.get(), rtc::VideoSinkWants()); >+ RTC_LOG(LS_INFO) << "Remote video sink set up: " << track; >+ break; >+ } >+ } >+} >+ >+void AndroidCallClient::Connect() { >+ rtc::CritScope lock(&pc_mutex_); >+ pc_->CreateOffer(new rtc::RefCountedObject<CreateOfferObserver>(pc_), >+ webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); >+} >+ >+AndroidCallClient::PCObserver::PCObserver(AndroidCallClient* client) >+ : client_(client) {} >+ >+void AndroidCallClient::PCObserver::OnSignalingChange( >+ webrtc::PeerConnectionInterface::SignalingState new_state) { >+ RTC_LOG(LS_INFO) << "OnSignalingChange: " << new_state; >+} >+ >+void AndroidCallClient::PCObserver::OnDataChannel( >+ rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { >+ RTC_LOG(LS_INFO) << "OnDataChannel"; >+} >+ >+void AndroidCallClient::PCObserver::OnRenegotiationNeeded() { >+ RTC_LOG(LS_INFO) << "OnRenegotiationNeeded"; >+} >+ >+void AndroidCallClient::PCObserver::OnIceConnectionChange( >+ webrtc::PeerConnectionInterface::IceConnectionState new_state) { >+ RTC_LOG(LS_INFO) << "OnIceConnectionChange: " << new_state; >+} >+ >+void AndroidCallClient::PCObserver::OnIceGatheringChange( >+ webrtc::PeerConnectionInterface::IceGatheringState new_state) { >+ RTC_LOG(LS_INFO) << "OnIceGatheringChange: " << new_state; >+} >+ >+void AndroidCallClient::PCObserver::OnIceCandidate( >+ const webrtc::IceCandidateInterface* candidate) { >+ RTC_LOG(LS_INFO) << "OnIceCandidate: " << candidate->server_url(); >+ rtc::CritScope lock(&client_->pc_mutex_); >+ RTC_DCHECK(client_->pc_ != nullptr); >+ client_->pc_->AddIceCandidate(candidate); >+} >+ >+CreateOfferObserver::CreateOfferObserver( >+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc) >+ : pc_(pc) {} >+ >+void CreateOfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) { >+ std::string sdp; >+ desc->ToString(&sdp); >+ RTC_LOG(LS_INFO) << "Created offer: " << sdp; >+ >+ // Ownership of desc was transferred to us, now we transfer it forward. >+ pc_->SetLocalDescription( >+ new rtc::RefCountedObject<SetLocalSessionDescriptionObserver>(), desc); >+ >+ // Generate a fake answer. >+ std::unique_ptr<webrtc::SessionDescriptionInterface> answer( >+ webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp)); >+ pc_->SetRemoteDescription( >+ std::move(answer), >+ new rtc::RefCountedObject<SetRemoteSessionDescriptionObserver>()); >+} >+ >+void CreateOfferObserver::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Failed to create offer: " << ToString(error.type()) >+ << ": " << error.message(); >+} >+ >+void SetRemoteSessionDescriptionObserver::OnSetRemoteDescriptionComplete( >+ webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Set remote description: " << error.message(); >+} >+ >+void SetLocalSessionDescriptionObserver::OnSuccess() { >+ RTC_LOG(LS_INFO) << "Set local description success!"; >+} >+ >+void SetLocalSessionDescriptionObserver::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Set local description failure: " >+ << ToString(error.type()) << ": " << error.message(); >+} >+ >+static jlong JNI_CallClient_CreateClient( >+ JNIEnv* env, >+ const webrtc::JavaParamRef<jclass>& cls) { >+ return webrtc::NativeToJavaPointer(new webrtc_examples::AndroidCallClient()); >+} >+ >+} // namespace webrtc_examples >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.h >new file mode 100644 >index 00000000000..d456e9c10a9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/androidcallclient.h >@@ -0,0 +1,79 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#ifndef EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROIDCALLCLIENT_H_ >+#define EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROIDCALLCLIENT_H_ >+ >+#include <jni.h> >+ >+#include <memory> >+#include <string> >+ >+#include "api/peerconnectioninterface.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/scoped_ref_ptr.h" >+#include "rtc_base/thread_checker.h" >+#include "sdk/android/native_api/jni/scoped_java_ref.h" >+#include "sdk/android/native_api/video/videosource.h" >+ >+namespace webrtc_examples { >+ >+class AndroidCallClient { >+ public: >+ AndroidCallClient(); >+ ~AndroidCallClient(); >+ >+ void Call(JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls, >+ const webrtc::JavaRef<jobject>& local_sink, >+ const webrtc::JavaRef<jobject>& remote_sink); >+ void Hangup(JNIEnv* env, const webrtc::JavaRef<jobject>& cls); >+ // A helper method for Java code to delete this object. Calls delete this. >+ void Delete(JNIEnv* env, const webrtc::JavaRef<jobject>& cls); >+ >+ webrtc::ScopedJavaLocalRef<jobject> GetJavaVideoCapturerObserver( >+ JNIEnv* env, >+ const webrtc::JavaRef<jobject>& cls); >+ >+ private: >+ class PCObserver; >+ >+ void CreatePeerConnectionFactory() RTC_RUN_ON(thread_checker_); >+ void CreatePeerConnection() RTC_RUN_ON(thread_checker_); >+ void Connect() RTC_RUN_ON(thread_checker_); >+ >+ rtc::ThreadChecker thread_checker_; >+ >+ bool call_started_ RTC_GUARDED_BY(thread_checker_); >+ >+ const std::unique_ptr<PCObserver> pc_observer_; >+ >+ rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pcf_ >+ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> network_thread_ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> worker_thread_ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> signaling_thread_ >+ RTC_GUARDED_BY(thread_checker_); >+ >+ std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> local_sink_ >+ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> remote_sink_ >+ RTC_GUARDED_BY(thread_checker_); >+ rtc::scoped_refptr<webrtc::JavaVideoTrackSourceInterface> video_source_ >+ RTC_GUARDED_BY(thread_checker_); >+ >+ rtc::CriticalSection pc_mutex_; >+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_ >+ RTC_GUARDED_BY(pc_mutex_); >+}; >+ >+} // namespace webrtc_examples >+ >+#endif // EXAMPLES_ANDROIDNATIVEAPI_JNI_ANDROIDCALLCLIENT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/onload.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/onload.cc >new file mode 100644 >index 00000000000..4b4b5d960a2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/jni/onload.cc >@@ -0,0 +1,30 @@ >+/* >+ * Copyright 2018 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 <jni.h> >+ >+#include "modules/utility/include/jvm_android.h" >+#include "rtc_base/ssladapter.h" >+#include "sdk/android/native_api/base/init.h" >+ >+namespace webrtc_examples { >+ >+extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM* jvm, void* reserved) { >+ webrtc::InitAndroid(jvm); >+ webrtc::JVM::Initialize(jvm); >+ RTC_CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()"; >+ return JNI_VERSION_1_6; >+} >+ >+extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM* jvm, void* reserved) { >+ RTC_CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()"; >+} >+ >+} // namespace webrtc_examples >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/layout/activity_main.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/layout/activity_main.xml >new file mode 100644 >index 00000000000..ac8037320f6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/layout/activity_main.xml >@@ -0,0 +1,52 @@ >+<?xml version="1.0" encoding="utf-8"?> >+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" >+ xmlns:app="http://schemas.android.com/apk/res-auto" >+ xmlns:tools="http://schemas.android.com/tools" >+ android:orientation="vertical" >+ android:layout_width="match_parent" >+ android:layout_height="match_parent" >+ android:padding="8dp" >+ tools:context="org.webrtc.examples.androidnativeapi.MainActivity"> >+ >+ <org.webrtc.SurfaceViewRenderer >+ android:id="@+id/local_renderer" >+ android:layout_width="match_parent" >+ android:layout_height="0dp" >+ android:layout_weight="1" >+ android:layout_margin="8dp"/> >+ >+ <org.webrtc.SurfaceViewRenderer >+ android:id="@+id/remote_renderer" >+ android:layout_width="match_parent" >+ android:layout_height="0dp" >+ android:layout_weight="1" >+ android:layout_margin="8dp"/> >+ >+ >+ <LinearLayout >+ android:orientation="horizontal" >+ android:layout_width="match_parent" >+ android:layout_height="48dp" >+ style="?android:attr/buttonBarStyle"> >+ >+ <Button >+ android:id="@+id/call_button" >+ android:text="@string/call_button" >+ style="?android:attr/buttonBarButtonStyle" >+ android:layout_width="0dp" >+ android:layout_height="48dp" >+ android:layout_weight="1" >+ android:layout_margin="8dp"/> >+ >+ <Button >+ android:id="@+id/hangup_button" >+ android:text="@string/hangup_button" >+ style="?android:attr/buttonBarButtonStyle" >+ android:layout_width="0dp" >+ android:layout_height="48dp" >+ android:layout_weight="1" >+ android:layout_margin="8dp"/> >+ >+ </LinearLayout> >+ >+</LinearLayout> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/values/strings.xml b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/values/strings.xml >new file mode 100644 >index 00000000000..a00920c92b6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidnativeapi/res/values/strings.xml >@@ -0,0 +1,5 @@ >+<resources> >+ <string name="app_name">androidnativeapi</string> >+ <string name="call_button">Call</string> >+ <string name="hangup_button">Hangup</string> >+</resources> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/README b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/README >index 49ae6c81d69..0701b0e8966 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/README >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/README >@@ -4,11 +4,11 @@ Example of building & using the app: > > - Build Android AppRTCMobile and AppRTCMobile unit test: > cd <path/to/webrtc>/src >-ninja -C out/Debug AppRTCMobileTest >+ninja -C out/Debug AppRTCMobile_test_apk > > - Install AppRTCMobile and AppRTCMobileTest: > adb install -r out/Debug/apks/AppRTCMobile.apk > adb install -r out/Debug/apks/AppRTCMobileTest.apk > > - Run unit tests: >-adb shell am instrument -w org.appspot.apprtc.test/android.test.InstrumentationTestRunner >\ No newline at end of file >+adb shell am instrument -w org.appspot.apprtc.test/android.test.InstrumentationTestRunner >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java >index 56eb3f72843..ec06bb9dde5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/src/org/appspot/apprtc/test/PeerConnectionClientTest.java >@@ -35,15 +35,14 @@ import org.junit.runner.RunWith; > import org.webrtc.Camera1Enumerator; > import org.webrtc.Camera2Enumerator; > import org.webrtc.CameraEnumerator; >+import org.webrtc.EglBase; > import org.webrtc.IceCandidate; >-import org.webrtc.MediaCodecVideoEncoder; > import org.webrtc.PeerConnection; > import org.webrtc.PeerConnectionFactory; > import org.webrtc.SessionDescription; > import org.webrtc.StatsReport; > import org.webrtc.VideoCapturer; > import org.webrtc.VideoFrame; >-import org.webrtc.VideoRenderer; > import org.webrtc.VideoSink; > > @RunWith(AndroidJUnit4.class) >@@ -85,53 +84,6 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > private final Object iceConnectedEvent = new Object(); > private final Object closeEvent = new Object(); > >- // Mock renderer implementation. >- private static class MockRenderer implements VideoRenderer.Callbacks { >- // These are protected by 'this' since we gets called from worker threads. >- private String rendererName; >- private boolean renderFrameCalled = false; >- >- // Thread-safe in itself. >- private CountDownLatch doneRendering; >- >- public MockRenderer(int expectedFrames, String rendererName) { >- this.rendererName = rendererName; >- reset(expectedFrames); >- } >- >- // Resets render to wait for new amount of video frames. >- // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. >- @SuppressWarnings("NoSynchronizedMethodCheck") >- public synchronized void reset(int expectedFrames) { >- renderFrameCalled = false; >- doneRendering = new CountDownLatch(expectedFrames); >- } >- >- @Override >- // TODO(bugs.webrtc.org/8491): Remove NoSynchronizedMethodCheck suppression. >- @SuppressWarnings("NoSynchronizedMethodCheck") >- public synchronized void renderFrame(VideoRenderer.I420Frame frame) { >- if (!renderFrameCalled) { >- if (rendererName != null) { >- Log.d(TAG, rendererName + " render frame: " + frame.rotatedWidth() + " x " >- + frame.rotatedHeight()); >- } else { >- Log.d(TAG, "Render frame: " + frame.rotatedWidth() + " x " + frame.rotatedHeight()); >- } >- } >- renderFrameCalled = true; >- VideoRenderer.renderFrameDone(frame); >- doneRendering.countDown(); >- } >- >- // This method shouldn't hold any locks or touch member variables since it >- // blocks. >- public boolean waitForFramesRendered(int timeoutMs) throws InterruptedException { >- doneRendering.await(timeoutMs, TimeUnit.MILLISECONDS); >- return (doneRendering.getCount() <= 0); >- } >- } >- > // Mock VideoSink implementation. > private static class MockSink implements VideoSink { > // These are protected by 'this' since we gets called from worker threads. >@@ -306,22 +258,22 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > } > } > >- PeerConnectionClient createPeerConnectionClient(MockSink localRenderer, >- MockRenderer remoteRenderer, PeerConnectionParameters peerConnectionParameters, >- VideoCapturer videoCapturer) { >+ PeerConnectionClient createPeerConnectionClient(MockSink localRenderer, MockSink remoteRenderer, >+ PeerConnectionParameters peerConnectionParameters, VideoCapturer videoCapturer) { > List<PeerConnection.IceServer> iceServers = new ArrayList<>(); > SignalingParameters signalingParameters = > new SignalingParameters(iceServers, true, // iceServers, initiator. > null, null, null, // clientId, wssUrl, wssPostUrl. > null, null); // offerSdp, iceCandidates. > >- PeerConnectionClient client = new PeerConnectionClient(); >+ final EglBase eglBase = EglBase.create(); >+ PeerConnectionClient client = >+ new PeerConnectionClient(InstrumentationRegistry.getTargetContext(), eglBase, >+ peerConnectionParameters, this /* PeerConnectionEvents */); > PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); > options.networkIgnoreMask = 0; > options.disableNetworkMonitor = true; >- client.setPeerConnectionFactoryOptions(options); >- client.createPeerConnectionFactory( >- InstrumentationRegistry.getTargetContext(), peerConnectionParameters, this); >+ client.createPeerConnectionFactory(options); > client.createPeerConnection(localRenderer, remoteRenderer, videoCapturer, signalingParameters); > client.createOffer(); > return client; >@@ -344,8 +296,10 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > "OPUS", /* audioCodec */ > false, /* noAudioProcessing */ > false, /* aecDump */ >+ false, /* saveInputAudioToFile */ > false /* useOpenSLES */, false /* disableBuiltInAEC */, false /* disableBuiltInAGC */, >- false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */); >+ false /* disableBuiltInNS */, false /* disableWebRtcAGC */, false /* enableRtcEventLog */, >+ false /* useLegacyAudioDevice */, null /* dataChannelParameters */); > } > > private VideoCapturer createCameraCapturer(boolean captureToTexture) { >@@ -379,8 +333,10 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > "OPUS", /* audioCodec */ > false, /* noAudioProcessing */ > false, /* aecDump */ >+ false, /* saveInputAudioToFile */ > false /* useOpenSLES */, false /* disableBuiltInAEC */, false /* disableBuiltInAGC */, >- false /* disableBuiltInNS */, false /* enableLevelControl */, false /* disableWebRtcAGC */); >+ false /* disableBuiltInNS */, false /* disableWebRtcAGC */, false /* enableRtcEventLog */, >+ false /* useLegacyAudioDevice */, null /* dataChannelParameters */); > } > > @Before >@@ -398,7 +354,8 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > public void testSetLocalOfferMakesVideoFlowLocally() throws InterruptedException { > Log.d(TAG, "testSetLocalOfferMakesVideoFlowLocally"); > MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); >- pcClient = createPeerConnectionClient(localRenderer, new MockRenderer(0, null), >+ pcClient = createPeerConnectionClient(localRenderer, >+ new MockSink(/* expectedFrames= */ 0, /* rendererName= */ null), > createParametersForVideoCall(VIDEO_CODEC_VP8), > createCameraCapturer(false /* captureToTexture */)); > >@@ -420,11 +377,11 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > boolean decodeToTexture) throws InterruptedException { > loopback = true; > MockSink localRenderer = null; >- MockRenderer remoteRenderer = null; >+ MockSink remoteRenderer = null; > if (parameters.videoCallEnabled) { > Log.d(TAG, "testLoopback for video " + parameters.videoCodec); > localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); >- remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); >+ remoteRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); > } else { > Log.d(TAG, "testLoopback for audio."); > } >@@ -523,12 +480,6 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > Log.i(TAG, "Encode to textures is not supported. Requires SDK version 19"); > return; > } >- // TODO(perkj): If we can always capture to textures, there is no need to check if the >- // hardware encoder supports to encode from a texture. >- if (!MediaCodecVideoEncoder.isVp8HwSupportedUsingTextures()) { >- Log.i(TAG, "VP8 encode to textures is not supported."); >- return; >- } > doLoopbackTest(createParametersForVideoCall(VIDEO_CODEC_VP8), > createCameraCapturer(true /* captureToTexture */), true /* decodeToTexture */); > } >@@ -540,12 +491,6 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > Log.i(TAG, "Encode to textures is not supported. Requires KITKAT"); > return; > } >- // TODO(perkj): If we can always capture to textures, there is no need to check if the >- // hardware encoder supports to encode from a texture. >- if (!MediaCodecVideoEncoder.isH264HwSupportedUsingTextures()) { >- Log.i(TAG, "H264 encode to textures is not supported."); >- return; >- } > doLoopbackTest(createParametersForVideoCall(VIDEO_CODEC_H264), > createCameraCapturer(true /* captureToTexture */), true /* decodeToTexture */); > } >@@ -559,7 +504,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > loopback = true; > > MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); >- MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); >+ MockSink remoteRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); > > pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, > createParametersForVideoCall(VIDEO_CODEC_VP8), >@@ -607,7 +552,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > loopback = true; > > MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); >- MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); >+ MockSink remoteRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); > > pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, > createParametersForVideoCall(VIDEO_CODEC_VP8), >@@ -656,7 +601,7 @@ public class PeerConnectionClientTest implements PeerConnectionEvents { > loopback = true; > > MockSink localRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, LOCAL_RENDERER_NAME); >- MockRenderer remoteRenderer = new MockRenderer(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); >+ MockSink remoteRenderer = new MockSink(EXPECTED_VIDEO_FRAMES, REMOTE_RENDERER_NAME); > > pcClient = createPeerConnectionClient(localRenderer, remoteRenderer, > createParametersForVideoCall(VIDEO_CODEC_VP8), >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/video_quality_loopback_test.py b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/video_quality_loopback_test.py >index 6991a0a57b6..225f885273c 100755 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/video_quality_loopback_test.py >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/androidtests/video_quality_loopback_test.py >@@ -22,7 +22,6 @@ import argparse > import json > import logging > import os >-import shutil > import subprocess > import sys > import tempfile >@@ -31,11 +30,15 @@ import time > > SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) > SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir)) >+RTC_TOOLS_DIR = os.path.join(SRC_DIR, 'rtc_tools', 'testing') >+TOOLCHAIN_DIR = os.path.join(SRC_DIR, 'tools_webrtc', 'video_quality_toolchain', >+ 'linux') > BAD_DEVICES_JSON = os.path.join(SRC_DIR, > os.environ.get('CHROMIUM_OUT_DIR', 'out'), > 'bad_devices.json') >-sys.path.append(os.path.join(SRC_DIR, 'build')) >-import find_depot_tools >+ >+sys.path.append(RTC_TOOLS_DIR) >+import utils > > > class Error(Exception): >@@ -46,19 +49,19 @@ class VideoQualityTestError(Error): > pass > > >-def _RunCommand(argv, cwd=SRC_DIR, **kwargs): >+def _RunCommand(argv, **kwargs): > logging.info('Running %r', argv) >- subprocess.check_call(argv, cwd=cwd, **kwargs) >+ subprocess.check_call(argv, **kwargs) > > >-def _RunCommandWithOutput(argv, cwd=SRC_DIR, **kwargs): >+def _RunCommandWithOutput(argv, **kwargs): > logging.info('Running %r', argv) >- return subprocess.check_output(argv, cwd=cwd, **kwargs) >+ return subprocess.check_output(argv, **kwargs) > > >-def _RunBackgroundCommand(argv, cwd=SRC_DIR): >+def _RunBackgroundCommand(argv): > logging.info('Running %r', argv) >- process = subprocess.Popen(argv, cwd=cwd) >+ process = subprocess.Popen(argv) > time.sleep(0.5) > status = process.poll() > if status: # is not None or 0 >@@ -66,6 +69,14 @@ def _RunBackgroundCommand(argv, cwd=SRC_DIR): > return process > > >+def CreateEmptyDir(suggested_dir): >+ if not suggested_dir: >+ return tempfile.mkdtemp() >+ utils.RemoveDirectory(suggested_dir) >+ os.makedirs(suggested_dir) >+ return suggested_dir >+ >+ > def _ParseArgs(): > parser = argparse.ArgumentParser(description='Start loopback video analysis.') > parser.add_argument('build_dir_android', >@@ -75,50 +86,27 @@ def _ParseArgs(): > parser.add_argument('--temp_dir', > help='A temporary directory to put the output.') > parser.add_argument('--adb-path', help='Path to adb binary.', default='adb') >+ parser.add_argument('--num-retries', default='0', >+ help='Number of times to retry the test on Android.') >+ parser.add_argument('--isolated-script-test-perf-output', >+ help='Where to store perf results in chartjson format.', default=None) > >- args = parser.parse_args() >- return args >- >- >-def main(): >- logging.basicConfig(level=logging.INFO) >- >- args = _ParseArgs() >- >- build_dir_android = args.build_dir_android >- build_dir_x86 = args.build_dir_x86 >- temp_dir = args.temp_dir >- adb_path = args.adb_path >- if not temp_dir: >- temp_dir = tempfile.mkdtemp() >- else: >- if not os.path.exists(temp_dir): >- os.makedirs(temp_dir) >- >- if not build_dir_x86: >- build_dir_x86 = os.path.join(temp_dir, 'LocalBuild') >+ args, unknown_args = parser.parse_known_args() > >- def DepotToolPath(*args): >- return os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, *args) >+ # Ignore Chromium-specific flags >+ parser = argparse.ArgumentParser() >+ parser.add_argument('--isolated-script-test-output', >+ type=str, default=None) >+ parser.add_argument('--test-launcher-summary-output', >+ type=str, default=None) > >- _RunCommand([sys.executable, DepotToolPath('gn.py'), 'gen', build_dir_x86]) >- _RunCommand([DepotToolPath('ninja'), '-C', build_dir_x86, >- 'frame_analyzer']) >+ parser.parse_args(unknown_args) > >- tools_dir = os.path.join(SRC_DIR, 'tools_webrtc') >- toolchain_dir = os.path.join(tools_dir, 'video_quality_toolchain') >- >- # Download ffmpeg and zxing. >- download_tools_script = os.path.join(tools_dir, 'download_tools.py') >- _RunCommand([sys.executable, download_tools_script, toolchain_dir]) >- >- testing_tools_dir = os.path.join(SRC_DIR, 'rtc_tools', 'testing') >+ return args > >- # Download, extract and build AppRTC. >- setup_apprtc_script = os.path.join(testing_tools_dir, 'setup_apprtc.py') >- _RunCommand([sys.executable, setup_apprtc_script, temp_dir]) > >- # Select an Android device in case multiple are connected >+def SelectAndroidDevice(adb_path): >+ # Select an Android device in case multiple are connected. > try: > with open(BAD_DEVICES_JSON) as bad_devices_file: > bad_devices = json.load(bad_devices_file) >@@ -131,91 +119,124 @@ def main(): > if line.endswith('\tdevice'): > android_device = line.split('\t')[0] > if android_device not in bad_devices: >- break >- else: >- raise VideoQualityTestError('Cannot find any connected Android device.') >+ return android_device >+ raise VideoQualityTestError('Cannot find any connected Android device.') >+ >+ >+def SetUpTools(android_device, temp_dir, processes): >+ # Extract AppRTC. >+ apprtc_archive = os.path.join(RTC_TOOLS_DIR, 'prebuilt_apprtc.zip') >+ golang_archive = os.path.join(RTC_TOOLS_DIR, 'golang', 'linux', 'go.tar.gz') >+ >+ utils.UnpackArchiveTo(apprtc_archive, temp_dir) >+ utils.UnpackArchiveTo(golang_archive, temp_dir) >+ >+ # Build AppRTC. >+ build_apprtc_script = os.path.join(RTC_TOOLS_DIR, 'build_apprtc.py') >+ apprtc_dir = os.path.join(temp_dir, 'apprtc') >+ go_dir = os.path.join(temp_dir, 'go') >+ collider_dir = os.path.join(temp_dir, 'collider') >+ >+ _RunCommand([sys.executable, build_apprtc_script, apprtc_dir, go_dir, >+ collider_dir]) >+ >+ # Start AppRTC Server. >+ dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk', >+ 'bin', 'dev_appserver.py') >+ appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine') >+ processes.append(_RunBackgroundCommand([ >+ sys.executable, dev_appserver, appengine_dir, '--port=9999', >+ '--admin_port=9998', '--skip_sdk_update_check', '--clear_datastore=yes'])) >+ >+ # Start Collider. >+ collider_path = os.path.join(temp_dir, 'collider', 'collidermain') >+ processes.append(_RunBackgroundCommand([ >+ collider_path, '-tls=false', '-port=8089', >+ '-room-server=http://localhost:9999'])) >+ >+ # Start adb reverse forwarder. >+ reverseforwarder_path = os.path.join( >+ SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py') >+ processes.append(_RunBackgroundCommand([ >+ reverseforwarder_path, '--device', android_device, '9999', '9999', '8089', >+ '8089'])) >+ >+ >+def RunTest(android_device, adb_path, build_dir, temp_dir, num_retries, >+ chartjson_result_file): >+ ffmpeg_path = os.path.join(TOOLCHAIN_DIR, 'ffmpeg') >+ def ConvertVideo(input_video, output_video): >+ _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video]) >+ >+ # Start loopback call and record video. >+ test_script = os.path.join( >+ build_dir, 'bin', 'run_AppRTCMobile_stubbed_video_io_test_apk') >+ _RunCommand([test_script, '--device', android_device, >+ '--num-retries', num_retries]) >+ >+ # Pull the recorded video. >+ test_video = os.path.join(temp_dir, 'test_video.y4m') >+ _RunCommand([adb_path, '-s', android_device, >+ 'pull', '/sdcard/output.y4m', test_video]) >+ >+ # Convert the recorded and reference videos to YUV. >+ reference_video = os.path.join(SRC_DIR, >+ 'resources', 'reference_video_640x360_30fps.y4m') >+ >+ test_video_yuv = os.path.join(temp_dir, 'test_video.yuv') >+ reference_video_yuv = os.path.join( >+ temp_dir, 'reference_video_640x360_30fps.yuv') >+ >+ ConvertVideo(test_video, test_video_yuv) >+ ConvertVideo(reference_video, reference_video_yuv) >+ >+ # Run comparison script. >+ compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py') >+ frame_analyzer = os.path.join(TOOLCHAIN_DIR, 'frame_analyzer') >+ zxing_path = os.path.join(TOOLCHAIN_DIR, 'zxing') >+ stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt') >+ stats_file_test = os.path.join(temp_dir, 'stats_test.txt') >+ >+ args = [ >+ '--ref_video', reference_video_yuv, >+ '--test_video', test_video_yuv, >+ '--yuv_frame_width', '640', >+ '--yuv_frame_height', '360', >+ '--stats_file_ref', stats_file_ref, >+ '--stats_file_test', stats_file_test, >+ '--frame_analyzer', frame_analyzer, >+ '--ffmpeg_path', ffmpeg_path, >+ '--zxing_path', zxing_path, >+ ] >+ if chartjson_result_file: >+ args.extend(['--chartjson_result_file', chartjson_result_file]) >+ >+ _RunCommand([sys.executable, compare_script] + args) >+ >+ >+def main(): >+ logging.basicConfig(level=logging.INFO) >+ >+ args = _ParseArgs() >+ >+ temp_dir = args.temp_dir >+ build_dir = args.build_dir_android >+ adb_path = args.adb_path > > processes = [] >+ temp_dir = CreateEmptyDir(temp_dir) > try: >- # Start AppRTC Server >- dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk', >- 'bin', 'dev_appserver.py') >- appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine') >- processes.append(_RunBackgroundCommand([ >- 'python', dev_appserver, appengine_dir, >- '--port=9999', '--admin_port=9998', >- '--skip_sdk_update_check', '--clear_datastore=yes'])) >- >- # Start Collider >- collider_path = os.path.join(temp_dir, 'collider', 'collidermain') >- processes.append(_RunBackgroundCommand([ >- collider_path, '-tls=false', '-port=8089', >- '-room-server=http://localhost:9999'])) >- >- # Start adb reverse forwarder >- reverseforwarder_path = os.path.join( >- SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py') >- processes.append(_RunBackgroundCommand([ >- reverseforwarder_path, '--device', android_device, >- '9999', '9999', '8089', '8089'])) >- >- # Run the Espresso code. >- test_script = os.path.join(build_dir_android, >- 'bin', 'run_AppRTCMobileTestStubbedVideoIO') >- _RunCommand([test_script, '--device', android_device]) >- >- # Pull the output video. >- test_video = os.path.join(temp_dir, 'test_video.y4m') >- _RunCommand([adb_path, '-s', android_device, >- 'pull', '/sdcard/output.y4m', test_video]) >- >- test_video_yuv = os.path.join(temp_dir, 'test_video.yuv') >- >- ffmpeg_path = os.path.join(toolchain_dir, 'linux', 'ffmpeg') >- >- def ConvertVideo(input_video, output_video): >- _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video]) >- >- ConvertVideo(test_video, test_video_yuv) >- >- reference_video = os.path.join(SRC_DIR, >- 'resources', 'reference_video_640x360_30fps.y4m') >- >- reference_video_yuv = os.path.join(temp_dir, >- 'reference_video_640x360_30fps.yuv') >- >- ConvertVideo(reference_video, reference_video_yuv) >- >- # Run compare script. >- compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py') >- zxing_path = os.path.join(toolchain_dir, 'linux', 'zxing') >- >- # The frame_analyzer binary should be built for local computer and not for >- # Android >- frame_analyzer = os.path.join(build_dir_x86, 'frame_analyzer') >- >- frame_width = 640 >- frame_height = 360 >- >- stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt') >- stats_file_test = os.path.join(temp_dir, 'stats_test.txt') >- >- _RunCommand([ >- sys.executable, compare_script, '--ref_video', reference_video_yuv, >- '--test_video', test_video_yuv, '--yuv_frame_width', str(frame_width), >- '--yuv_frame_height', str(frame_height), >- '--stats_file_ref', stats_file_ref, >- '--stats_file_test', stats_file_test, >- '--frame_analyzer', frame_analyzer, >- '--ffmpeg_path', ffmpeg_path, '--zxing_path', zxing_path]) >- >+ android_device = SelectAndroidDevice(adb_path) >+ SetUpTools(android_device, temp_dir, processes) >+ RunTest(android_device, adb_path, build_dir, temp_dir, args.num_retries, >+ args.isolated_script_test_perf_output) > finally: > for process in processes: > if process: > process.terminate() > process.wait() > >- shutil.rmtree(temp_dir) >+ utils.RemoveDirectory(temp_dir) > > > if __name__ == '__main__': >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h >index 3cf40400f59..8e96b169090 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient+Internal.h >@@ -18,8 +18,7 @@ > > @class RTCPeerConnectionFactory; > >-@interface ARDAppClient () <ARDSignalingChannelDelegate, >- RTCPeerConnectionDelegate> >+@interface ARDAppClient () <ARDSignalingChannelDelegate, RTCPeerConnectionDelegate> > > // All properties should only be mutated from the main queue. > @property(nonatomic, strong) id<ARDRoomServerClient> roomServerClient; >@@ -43,8 +42,7 @@ > @property(nonatomic, strong) NSURL *webSocketRestURL; > @property(nonatomic, readonly) BOOL isLoopback; > >-@property(nonatomic, strong) >- RTCMediaConstraints *defaultPeerConnectionConstraints; >+@property(nonatomic, strong) RTCMediaConstraints *defaultPeerConnectionConstraints; > > - (instancetype)initWithRoomServerClient:(id<ARDRoomServerClient>)rsClient > signalingChannel:(id<ARDSignalingChannel>)channel >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h >index 5054c28676f..07cd53d1675 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.h >@@ -23,6 +23,7 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) { > > @class ARDAppClient; > @class ARDSettingsModel; >+@class ARDExternalSampleCapturer; > @class RTCMediaConstraints; > @class RTCCameraVideoCapturer; > @class RTCFileVideoCapturer; >@@ -31,30 +32,28 @@ typedef NS_ENUM(NSInteger, ARDAppClientState) { > // main queue. > @protocol ARDAppClientDelegate <NSObject> > >-- (void)appClient:(ARDAppClient *)client >- didChangeState:(ARDAppClientState)state; >+- (void)appClient:(ARDAppClient *)client didChangeState:(ARDAppClientState)state; > >-- (void)appClient:(ARDAppClient *)client >- didChangeConnectionState:(RTCIceConnectionState)state; >+- (void)appClient:(ARDAppClient *)client didChangeConnectionState:(RTCIceConnectionState)state; > > - (void)appClient:(ARDAppClient *)client > didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer; > >-- (void)appClient:(ARDAppClient *)client >- didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack; >+- (void)appClient:(ARDAppClient *)client didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack; > > - (void)appClient:(ARDAppClient *)client > didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack; > >-- (void)appClient:(ARDAppClient *)client >- didError:(NSError *)error; >+- (void)appClient:(ARDAppClient *)client didError:(NSError *)error; > >-- (void)appClient:(ARDAppClient *)client >- didGetStats:(NSArray *)stats; >+- (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats; > > @optional > - (void)appClient:(ARDAppClient *)client >-didCreateLocalFileCapturer:(RTCFileVideoCapturer *)fileCapturer; >+ didCreateLocalFileCapturer:(RTCFileVideoCapturer *)fileCapturer; >+ >+- (void)appClient:(ARDAppClient *)client >+ didCreateLocalExternalSampleCapturer:(ARDExternalSampleCapturer *)externalSampleCapturer; > > @end > >@@ -67,6 +66,8 @@ didCreateLocalFileCapturer:(RTCFileVideoCapturer *)fileCapturer; > @property(nonatomic, assign) BOOL shouldGetStats; > @property(nonatomic, readonly) ARDAppClientState state; > @property(nonatomic, weak) id<ARDAppClientDelegate> delegate; >+@property(nonatomic, assign, getter=isBroadcast) BOOL broadcast; >+ > // Convenience constructor since all expected use cases will need a delegate > // in order to receive remote tracks. > - (instancetype)initWithDelegate:(id<ARDAppClientDelegate>)delegate; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m >index 10be40a89ea..465ce8c9b80 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppClient.m >@@ -10,7 +10,6 @@ > > #import "ARDAppClient+Internal.h" > >-#import "WebRTC/RTCAVFoundationVideoSource.h" > #import "WebRTC/RTCAudioTrack.h" > #import "WebRTC/RTCCameraVideoCapturer.h" > #import "WebRTC/RTCConfiguration.h" >@@ -22,11 +21,14 @@ > #import "WebRTC/RTCMediaStream.h" > #import "WebRTC/RTCPeerConnectionFactory.h" > #import "WebRTC/RTCRtpSender.h" >+#import "WebRTC/RTCRtpTransceiver.h" > #import "WebRTC/RTCTracing.h" > #import "WebRTC/RTCVideoCodecFactory.h" >+#import "WebRTC/RTCVideoSource.h" > #import "WebRTC/RTCVideoTrack.h" > > #import "ARDAppEngineClient.h" >+#import "ARDExternalSampleCapturer.h" > #import "ARDJoinResponse.h" > #import "ARDMessageResponse.h" > #import "ARDSettingsModel.h" >@@ -52,10 +54,12 @@ > static NSString * const kARDVideoTrackKind = @"video"; > > // TODO(tkchin): Add these as UI options. >+#if defined(WEBRTC_IOS) > static BOOL const kARDAppClientEnableTracing = NO; > static BOOL const kARDAppClientEnableRtcEventLog = YES; > static int64_t const kARDAppClientAecDumpMaxSizeInBytes = 5e6; // 5 MB. > static int64_t const kARDAppClientRtcEventLogMaxSizeInBytes = 5e6; // 5 MB. >+#endif > static int const kKbpsMultiplier = 1000; > > // We need a proxy to NSTimer because it causes a strong retain cycle. When >@@ -127,6 +131,7 @@ @implementation ARDAppClient { > @synthesize defaultPeerConnectionConstraints = > _defaultPeerConnectionConstraints; > @synthesize isLoopback = _isLoopback; >+@synthesize broadcast = _broadcast; > > - (instancetype)init { > return [self initWithDelegate:nil]; >@@ -236,8 +241,7 @@ - (void)connectToRoomWithId:(NSString *)roomId > [_turnClient requestServersWithCompletionHandler:^(NSArray *turnServers, > NSError *error) { > if (error) { >- RTCLogError("Error retrieving TURN servers: %@", >- error.localizedDescription); >+ RTCLogError(@"Error retrieving TURN servers: %@", error.localizedDescription); > } > ARDAppClient *strongSelf = weakSelf; > [strongSelf.iceServers addObjectsFromArray:turnServers]; >@@ -371,15 +375,15 @@ - (void)peerConnection:(RTCPeerConnection *)peerConnection > > - (void)peerConnection:(RTCPeerConnection *)peerConnection > didAddStream:(RTCMediaStream *)stream { >- dispatch_async(dispatch_get_main_queue(), ^{ >- RTCLog(@"Received %lu video tracks and %lu audio tracks", >- (unsigned long)stream.videoTracks.count, >- (unsigned long)stream.audioTracks.count); >- if (stream.videoTracks.count) { >- RTCVideoTrack *videoTrack = stream.videoTracks[0]; >- [_delegate appClient:self didReceiveRemoteVideoTrack:videoTrack]; >- } >- }); >+ RTCLog(@"Stream with %lu video tracks and %lu audio tracks was added.", >+ (unsigned long)stream.videoTracks.count, >+ (unsigned long)stream.audioTracks.count); >+} >+ >+- (void)peerConnection:(RTCPeerConnection *)peerConnection >+ didStartReceivingOnTransceiver:(RTCRtpTransceiver *)transceiver { >+ RTCMediaStreamTrack *track = transceiver.receiver.track; >+ RTCLog(@"Now receiving %@ on track %@.", track.kind, track.trackId); > } > > - (void)peerConnection:(RTCPeerConnection *)peerConnection >@@ -529,7 +533,14 @@ - (void)startSignalingIfReady { > // Create peer connection. > RTCMediaConstraints *constraints = [self defaultPeerConnectionConstraints]; > RTCConfiguration *config = [[RTCConfiguration alloc] init]; >+ RTCCertificate *pcert = [RTCCertificate generateCertificateWithParams:@{ >+ @"expires" : @100000, >+ @"name" : @"RSASSA-PKCS1-v1_5" >+ }]; > config.iceServers = _iceServers; >+ config.sdpSemantics = RTCSdpSemanticsUnifiedPlan; >+ config.certificate = pcert; >+ > _peerConnection = [_factory peerConnectionWithConfiguration:config > constraints:constraints > delegate:self]; >@@ -676,18 +687,31 @@ - (void)setMaxBitrate:(NSNumber *)maxBitrate forVideoSender:(RTCRtpSender *)send > [sender setParameters:parametersToModify]; > } > >+- (RTCRtpTransceiver *)videoTransceiver { >+ for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) { >+ if (transceiver.mediaType == RTCRtpMediaTypeVideo) { >+ return transceiver; >+ } >+ } >+ return nil; >+} >+ > - (void)createMediaSenders { > RTCMediaConstraints *constraints = [self defaultMediaAudioConstraints]; > RTCAudioSource *source = [_factory audioSourceWithConstraints:constraints]; > RTCAudioTrack *track = [_factory audioTrackWithSource:source > trackId:kARDAudioTrackId]; >- RTCMediaStream *stream = [_factory mediaStreamWithStreamId:kARDMediaStreamId]; >- [stream addAudioTrack:track]; >+ [_peerConnection addTrack:track streamIds:@[ kARDMediaStreamId ]]; > _localVideoTrack = [self createLocalVideoTrack]; > if (_localVideoTrack) { >- [stream addVideoTrack:_localVideoTrack]; >+ [_peerConnection addTrack:_localVideoTrack streamIds:@[ kARDMediaStreamId ]]; >+ [_delegate appClient:self didReceiveLocalVideoTrack:_localVideoTrack]; >+ // We can set up rendering for the remote track right away since the transceiver already has an >+ // RTCRtpReceiver with a track. The track will automatically get unmuted and produce frames >+ // once RTP is received. >+ RTCVideoTrack *track = (RTCVideoTrack *)([self videoTransceiver].receiver.track); >+ [_delegate appClient:self didReceiveRemoteVideoTrack:track]; > } >- [_peerConnection addStream:stream]; > } > > - (RTCVideoTrack *)createLocalVideoTrack { >@@ -698,9 +722,14 @@ - (RTCVideoTrack *)createLocalVideoTrack { > RTCVideoSource *source = [_factory videoSource]; > > #if !TARGET_IPHONE_SIMULATOR >- RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source]; >- [_delegate appClient:self didCreateLocalCapturer:capturer]; >- >+ if (self.isBroadcast) { >+ ARDExternalSampleCapturer *capturer = >+ [[ARDExternalSampleCapturer alloc] initWithDelegate:source]; >+ [_delegate appClient:self didCreateLocalExternalSampleCapturer:capturer]; >+ } else { >+ RTCCameraVideoCapturer *capturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:source]; >+ [_delegate appClient:self didCreateLocalCapturer:capturer]; >+ } > #else > #if defined(__IPHONE_11_0) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0) > if (@available(iOS 10, *)) { >@@ -740,10 +769,7 @@ - (void)registerWithColliderIfReady { > #pragma mark - Defaults > > - (RTCMediaConstraints *)defaultMediaAudioConstraints { >- NSString *valueLevelControl = [_settings currentUseLevelControllerSettingFromStore] ? >- kRTCMediaConstraintsValueTrue : >- kRTCMediaConstraintsValueFalse; >- NSDictionary *mandatoryConstraints = @{ kRTCMediaConstraintsLevelControl : valueLevelControl }; >+ NSDictionary *mandatoryConstraints = @{}; > RTCMediaConstraints *constraints = > [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatoryConstraints > optionalConstraints:nil]; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.h >index 7514f3645c4..db4e2efd7f8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.h >@@ -10,5 +10,5 @@ > > #import "ARDRoomServerClient.h" > >-@interface ARDAppEngineClient : NSObject <ARDRoomServerClient> >+@interface ARDAppEngineClient : NSObject<ARDRoomServerClient> > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.m >index ad7a6c2bf2b..0c22ea4b0f3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDAppEngineClient.m >@@ -55,10 +55,8 @@ - (void)joinRoomWithRoomId:(NSString *)roomId > RTCLog(@"Joining room:%@ on room server.", roomId); > NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL]; > request.HTTPMethod = @"POST"; >- __weak ARDAppEngineClient *weakSelf = self; > [NSURLConnection sendAsyncRequest:request > completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { >- ARDAppEngineClient *strongSelf = weakSelf; > if (error) { > if (completionHandler) { > completionHandler(nil, error); >@@ -97,12 +95,10 @@ - (void)sendMessage:(ARDSignalingMessage *)message > NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; > request.HTTPMethod = @"POST"; > request.HTTPBody = data; >- __weak ARDAppEngineClient *weakSelf = self; > [NSURLConnection sendAsyncRequest:request > completionHandler:^(NSURLResponse *response, > NSData *data, > NSError *error) { >- ARDAppEngineClient *strongSelf = weakSelf; > if (error) { > if (completionHandler) { > completionHandler(nil, error); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m >index 6830e88c23e..068e18ec929 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDCaptureController.m >@@ -13,6 +13,8 @@ > #import "ARDSettingsModel.h" > #import "WebRTC/RTCLogging.h" > >+const Float64 kFramerateLimit = 30.0; >+ > @implementation ARDCaptureController { > RTCCameraVideoCapturer *_capturer; > ARDSettingsModel *_settings; >@@ -21,7 +23,7 @@ @implementation ARDCaptureController { > > - (instancetype)initWithCapturer:(RTCCameraVideoCapturer *)capturer > settings:(ARDSettingsModel *)settings { >- if ([super init]) { >+ if (self = [super init]) { > _capturer = capturer; > _settings = settings; > _usingFrontCamera = YES; >@@ -93,11 +95,11 @@ - (AVCaptureDeviceFormat *)selectFormatForDevice:(AVCaptureDevice *)device { > } > > - (NSInteger)selectFpsForFormat:(AVCaptureDeviceFormat *)format { >- Float64 maxFramerate = 0; >+ Float64 maxSupportedFramerate = 0; > for (AVFrameRateRange *fpsRange in format.videoSupportedFrameRateRanges) { >- maxFramerate = fmax(maxFramerate, fpsRange.maxFrameRate); >+ maxSupportedFramerate = fmax(maxSupportedFramerate, fpsRange.maxFrameRate); > } >- return maxFramerate; >+ return fmin(maxSupportedFramerate, kFramerateLimit); > } > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.h >new file mode 100644 >index 00000000000..98a60fc7eda >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.h >@@ -0,0 +1,18 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import <WebRTC/RTCVideoCapturer.h> >+ >+@protocol ARDExternalSampleDelegate <NSObject> >+- (void)didCaptureSampleBuffer:(CMSampleBufferRef)sampleBuffer; >+@end >+ >+@interface ARDExternalSampleCapturer : RTCVideoCapturer <ARDExternalSampleDelegate> >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.m >new file mode 100644 >index 00000000000..d377033bde2 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDExternalSampleCapturer.m >@@ -0,0 +1,43 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import "ARDExternalSampleCapturer.h" >+ >+#import "WebRTC/RTCVideoFrameBuffer.h" >+ >+@implementation ARDExternalSampleCapturer >+ >+- (instancetype)initWithDelegate:(__weak id<RTCVideoCapturerDelegate>)delegate { >+ return [super initWithDelegate:delegate]; >+} >+ >+#pragma mark - ARDExternalSampleDelegate >+ >+- (void)didCaptureSampleBuffer:(CMSampleBufferRef)sampleBuffer { >+ if (CMSampleBufferGetNumSamples(sampleBuffer) != 1 || !CMSampleBufferIsValid(sampleBuffer) || >+ !CMSampleBufferDataIsReady(sampleBuffer)) { >+ return; >+ } >+ >+ CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); >+ if (pixelBuffer == nil) { >+ return; >+ } >+ >+ RTCCVPixelBuffer *rtcPixelBuffer = [[RTCCVPixelBuffer alloc] initWithPixelBuffer:pixelBuffer]; >+ int64_t timeStampNs = >+ CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)) * NSEC_PER_SEC; >+ RTCVideoFrame *videoFrame = [[RTCVideoFrame alloc] initWithBuffer:rtcPixelBuffer >+ rotation:RTCVideoRotation_0 >+ timeStampNs:timeStampNs]; >+ [self.delegate capturer:self didCaptureVideoFrame:videoFrame]; >+} >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDJoinResponse+Internal.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDJoinResponse+Internal.h >index b3202999d08..0edf7083c0c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDJoinResponse+Internal.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDJoinResponse+Internal.h >@@ -14,10 +14,10 @@ > > @property(nonatomic, assign) ARDJoinResultType result; > @property(nonatomic, assign) BOOL isInitiator; >-@property(nonatomic, strong) NSString *roomId; >-@property(nonatomic, strong) NSString *clientId; >-@property(nonatomic, strong) NSArray *messages; >-@property(nonatomic, strong) NSURL *webSocketURL; >-@property(nonatomic, strong) NSURL *webSocketRestURL; >+@property(nonatomic, strong) NSString* roomId; >+@property(nonatomic, strong) NSString* clientId; >+@property(nonatomic, strong) NSArray* messages; >+@property(nonatomic, strong) NSURL* webSocketURL; >+@property(nonatomic, strong) NSURL* webSocketRestURL; > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDRoomServerClient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDRoomServerClient.h >index 70694a8c9f1..3a5818d6d6f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDRoomServerClient.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDRoomServerClient.h >@@ -18,14 +18,12 @@ > > - (void)joinRoomWithRoomId:(NSString *)roomId > isLoopback:(BOOL)isLoopback >- completionHandler:(void (^)(ARDJoinResponse *response, >- NSError *error))completionHandler; >+ completionHandler:(void (^)(ARDJoinResponse *response, NSError *error))completionHandler; > > - (void)sendMessage:(ARDSignalingMessage *)message > forRoomId:(NSString *)roomId > clientId:(NSString *)clientId >- completionHandler:(void (^)(ARDMessageResponse *response, >- NSError *error))completionHandler; >+ completionHandler:(void (^)(ARDMessageResponse *response, NSError *error))completionHandler; > > - (void)leaveRoomWithRoomId:(NSString *)roomId > clientId:(NSString *)clientId >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h >index 625b533a0e3..597ab38fbf5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.h >@@ -106,19 +106,6 @@ NS_ASSUME_NONNULL_BEGIN > */ > - (void)storeCreateAecDumpSetting:(BOOL)createAecDump; > >-/** >- * Returns current setting whether to use level controller from store if present or default (NO) >- * otherwise. >- */ >-- (BOOL)currentUseLevelControllerSettingFromStore; >- >-/** >- * Stores the provided use level controller setting into the store. >- * >- * @param setting the boolean value to be stored. >- */ >-- (void)storeUseLevelControllerSetting:(BOOL)useLevelController; >- > /** > * Returns current setting whether to use manual audio config from store if present or default (YES) > * otherwise. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m >index a4eea731d45..34a47a49894 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsModel.m >@@ -39,7 +39,11 @@ @implementation ARDSettingsModel > NSArray<NSArray<NSNumber *> *> *sortedResolutions = > [[resolutions allObjects] sortedArrayUsingComparator:^NSComparisonResult( > NSArray<NSNumber *> *obj1, NSArray<NSNumber *> *obj2) { >- return obj1.firstObject > obj2.firstObject; >+ NSComparisonResult cmp = [obj1.firstObject compare:obj2.firstObject]; >+ if (cmp != NSOrderedSame) { >+ return cmp; >+ } >+ return [obj1.lastObject compare:obj2.lastObject]; > }]; > > NSMutableArray<NSString *> *resolutionStrings = [[NSMutableArray<NSString *> alloc] init]; >@@ -109,14 +113,6 @@ - (void)storeCreateAecDumpSetting:(BOOL)createAecDump { > [[self settingsStore] setCreateAecDump:createAecDump]; > } > >-- (BOOL)currentUseLevelControllerSettingFromStore { >- return [[self settingsStore] useLevelController]; >-} >- >-- (void)storeUseLevelControllerSetting:(BOOL)useLevelController { >- [[self settingsStore] setUseLevelController:useLevelController]; >-} >- > - (BOOL)currentUseManualAudioConfigSettingFromStore { > return [[self settingsStore] useManualAudioConfig]; > } >@@ -168,15 +164,12 @@ - (int)videoResolutionComponentAtIndex:(int)index inString:(NSString *)resolutio > } > > - (void)registerStoreDefaults { >- NSString *defaultVideoResolutionSetting = [self defaultVideoResolutionSetting]; >- > NSData *codecData = [NSKeyedArchiver archivedDataWithRootObject:[self defaultVideoCodecSetting]]; > [ARDSettingsStore setDefaultsForVideoResolution:[self defaultVideoResolutionSetting] > videoCodec:codecData > bitrate:nil > audioOnly:NO > createAecDump:NO >- useLevelController:NO > useManualAudioConfig:YES]; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h >index b68adb737af..bb051dbb26d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.h >@@ -28,7 +28,6 @@ NS_ASSUME_NONNULL_BEGIN > bitrate:(nullable NSNumber *)bitrate > audioOnly:(BOOL)audioOnly > createAecDump:(BOOL)createAecDump >- useLevelController:(BOOL)useLevelController > useManualAudioConfig:(BOOL)useManualAudioConfig; > > @property(nonatomic) NSString *videoResolution; >@@ -47,7 +46,6 @@ NS_ASSUME_NONNULL_BEGIN > > @property(nonatomic) BOOL audioOnly; > @property(nonatomic) BOOL createAecDump; >-@property(nonatomic) BOOL useLevelController; > @property(nonatomic) BOOL useManualAudioConfig; > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m >index 86bdaaf54c7..a3713e2f0e6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSettingsStore.m >@@ -15,7 +15,6 @@ > static NSString *const kBitrateKey = @"rtc_max_bitrate_key"; > static NSString *const kAudioOnlyKey = @"rtc_audio_only_key"; > static NSString *const kCreateAecDumpKey = @"rtc_create_aec_dump_key"; >-static NSString *const kUseLevelControllerKey = @"rtc_use_level_controller_key"; > static NSString *const kUseManualAudioConfigKey = @"rtc_use_manual_audio_config_key"; > > NS_ASSUME_NONNULL_BEGIN >@@ -32,12 +31,10 @@ + (void)setDefaultsForVideoResolution:(NSString *)videoResolution > bitrate:(nullable NSNumber *)bitrate > audioOnly:(BOOL)audioOnly > createAecDump:(BOOL)createAecDump >- useLevelController:(BOOL)useLevelController > useManualAudioConfig:(BOOL)useManualAudioConfig { > NSMutableDictionary<NSString *, id> *defaultsDictionary = [@{ > kAudioOnlyKey : @(audioOnly), > kCreateAecDumpKey : @(createAecDump), >- kUseLevelControllerKey : @(useLevelController), > kUseManualAudioConfigKey : @(useManualAudioConfig) > } mutableCopy]; > >@@ -105,15 +102,6 @@ - (void)setCreateAecDump:(BOOL)createAecDump { > [self.storage synchronize]; > } > >-- (BOOL)useLevelController { >- return [self.storage boolForKey:kUseLevelControllerKey]; >-} >- >-- (void)setUseLevelController:(BOOL)useLevelController { >- [self.storage setBool:useLevelController forKey:kUseLevelControllerKey]; >- [self.storage synchronize]; >-} >- > - (BOOL)useManualAudioConfig { > return [self.storage boolForKey:kUseManualAudioConfigKey]; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingChannel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingChannel.h >index 70ba2ff4c95..396b117b179 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingChannel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingChannel.h >@@ -26,11 +26,9 @@ typedef NS_ENUM(NSInteger, ARDSignalingChannelState) { > @protocol ARDSignalingChannel; > @protocol ARDSignalingChannelDelegate <NSObject> > >-- (void)channel:(id<ARDSignalingChannel>)channel >- didChangeState:(ARDSignalingChannelState)state; >+- (void)channel:(id<ARDSignalingChannel>)channel didChangeState:(ARDSignalingChannelState)state; > >-- (void)channel:(id<ARDSignalingChannel>)channel >- didReceiveMessage:(ARDSignalingMessage *)message; >+- (void)channel:(id<ARDSignalingChannel>)channel didReceiveMessage:(ARDSignalingMessage *)message; > > @end > >@@ -42,11 +40,9 @@ typedef NS_ENUM(NSInteger, ARDSignalingChannelState) { > @property(nonatomic, weak) id<ARDSignalingChannelDelegate> delegate; > > // Registers the channel for the given room and client id. >-- (void)registerForRoomId:(NSString *)roomId >- clientId:(NSString *)clientId; >+- (void)registerForRoomId:(NSString *)roomId clientId:(NSString *)clientId; > > // Sends signaling message over the channel. > - (void)sendMessage:(ARDSignalingMessage *)message; > > @end >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingMessage.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingMessage.h >index e60517282b9..93ff4862cf2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingMessage.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDSignalingMessage.h >@@ -42,8 +42,7 @@ typedef enum { > > @property(nonatomic, readonly) NSArray<RTCIceCandidate *> *candidates; > >-- (instancetype)initWithRemovedCandidates: >- (NSArray<RTCIceCandidate *> *)candidates; >+- (instancetype)initWithRemovedCandidates:(NSArray<RTCIceCandidate *> *)candidates; > > @end > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDTURNClient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDTURNClient.h >index 75ccffcb8ca..0cefaf6c199 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDTURNClient.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDTURNClient.h >@@ -15,8 +15,7 @@ > @protocol ARDTURNClient <NSObject> > > // Returns TURN server urls if successful. >-- (void)requestServersWithCompletionHandler: >- (void (^)(NSArray *turnServers, >- NSError *error))completionHandler; >+- (void)requestServersWithCompletionHandler:(void (^)(NSArray *turnServers, >+ NSError *error))completionHandler; > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDWebSocketChannel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDWebSocketChannel.h >index ffb0b724afa..81888e6e839 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDWebSocketChannel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ARDWebSocketChannel.h >@@ -21,8 +21,7 @@ > > // Registers with the WebSocket server for the given room and client id once > // the web socket connection is open. >-- (void)registerForRoomId:(NSString *)roomId >- clientId:(NSString *)clientId; >+- (void)registerForRoomId:(NSString *)roomId clientId:(NSString *)clientId; > > // Sends message over the WebSocket connection if registered, otherwise POSTs to > // the web socket server instead. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCIceCandidate+JSON.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCIceCandidate+JSON.h >index d2e5e33b5bb..18265558618 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCIceCandidate+JSON.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCIceCandidate+JSON.h >@@ -13,8 +13,7 @@ > @interface RTCIceCandidate (JSON) > > + (RTCIceCandidate *)candidateFromJSONDictionary:(NSDictionary *)dictionary; >-+ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary: >- (NSDictionary *)dictionary; >++ (NSArray<RTCIceCandidate *> *)candidatesFromJSONDictionary:(NSDictionary *)dictionary; > + (NSData *)JSONDataForIceCandidates:(NSArray<RTCIceCandidate *> *)candidates > withType:(NSString *)typeValue; > - (NSData *)JSONData; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCMediaConstraints+JSON.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCMediaConstraints+JSON.h >index 74f89a953fb..42d7ab0f019 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCMediaConstraints+JSON.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCMediaConstraints+JSON.h >@@ -12,8 +12,6 @@ > > @interface RTCMediaConstraints (JSON) > >-+ (RTCMediaConstraints *)constraintsFromJSONDictionary: >- (NSDictionary *)dictionary; >++ (RTCMediaConstraints *)constraintsFromJSONDictionary:(NSDictionary *)dictionary; > > @end >- >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCSessionDescription+JSON.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCSessionDescription+JSON.h >index cccff9ad74c..f5671213a89 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCSessionDescription+JSON.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/RTCSessionDescription+JSON.h >@@ -12,8 +12,7 @@ > > @interface RTCSessionDescription (JSON) > >-+ (RTCSessionDescription *)descriptionFromJSONDictionary: >- (NSDictionary *)dictionary; >++ (RTCSessionDescription *)descriptionFromJSONDictionary:(NSDictionary *)dictionary; > - (NSData *)JSONData; > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/common/ARDUtilities.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/common/ARDUtilities.h >index 8a5c1262ab9..5f0d7dbef71 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/common/ARDUtilities.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/common/ARDUtilities.h >@@ -22,17 +22,14 @@ > > // Issues an asynchronous request that calls back on main queue. > + (void)sendAsyncRequest:(NSURLRequest *)request >- completionHandler:(void (^)(NSURLResponse *response, >- NSData *data, >- NSError *error))completionHandler; >+ completionHandler: >+ (void (^)(NSURLResponse *response, NSData *data, NSError *error))completionHandler; > > // Posts data to the specified URL. > + (void)sendAsyncPostToURL:(NSURL *)url > withData:(NSData *)data >- completionHandler:(void (^)(BOOL succeeded, >- NSData *data))completionHandler; >+ completionHandler:(void (^)(BOOL succeeded, NSData *data))completionHandler; > > @end > >-NSInteger ARDGetCpuUsagePercentage(); >- >+NSInteger ARDGetCpuUsagePercentage(void); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.h >index 7eafff8ebcd..623e8590960 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.h >@@ -13,5 +13,5 @@ > // The main application class of the AppRTCMobile iOS app demonstrating > // interoperability between the Objective C implementation of PeerConnection > // and the appr.tc demo webapp. >-@interface ARDAppDelegate : NSObject <UIApplicationDelegate> >+@interface ARDAppDelegate : NSObject<UIApplicationDelegate> > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m >index 07c83a0826f..4f444e428d1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDAppDelegate.m >@@ -25,9 +25,7 @@ @implementation ARDAppDelegate { > > - (BOOL)application:(UIApplication *)application > didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { >- NSDictionary *fieldTrials = @{ >- kRTCFieldTrialH264HighProfileKey: kRTCFieldTrialEnabledValue, >- }; >+ NSDictionary *fieldTrials = @{}; > RTCInitFieldTrialDictionary(fieldTrials); > RTCInitializeSSL(); > RTCSetupInternalTracer(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m >index fcce3c30159..c3bd24a7a06 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDMainView.m >@@ -29,7 +29,7 @@ - (instancetype)initWithFrame:(CGRect)frame { > if (self = [super initWithFrame:frame]) { > _roomText = [[UITextField alloc] initWithFrame:CGRectZero]; > _roomText.borderStyle = UITextBorderStyleNone; >- _roomText.font = [UIFont fontWithName:@"Roboto" size:12]; >+ _roomText.font = [UIFont systemFontOfSize:12]; > _roomText.placeholder = @"Room name"; > _roomText.autocorrectionType = UITextAutocorrectionTypeNo; > _roomText.autocapitalizationType = UITextAutocapitalizationTypeNone; >@@ -73,10 +73,8 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField { > > @implementation ARDMainView { > ARDRoomTextField *_roomText; >- UILabel *_callOptionsLabel; >- UISwitch *_loopbackSwitch; >- UILabel *_loopbackLabel; >- UIButton *_startCallButton; >+ UIButton *_startRegularCallButton; >+ UIButton *_startLoopbackCallButton; > UIButton *_audioLoopButton; > } > >@@ -88,40 +86,38 @@ - (instancetype)initWithFrame:(CGRect)frame { > _roomText = [[ARDRoomTextField alloc] initWithFrame:CGRectZero]; > [self addSubview:_roomText]; > >- UIFont *controlFont = [UIFont fontWithName:@"Roboto" size:20]; >- UIColor *controlFontColor = [UIColor colorWithWhite:0 alpha:.6]; >- >- _callOptionsLabel = [[UILabel alloc] initWithFrame:CGRectZero]; >- _callOptionsLabel.text = @"Call Options"; >- _callOptionsLabel.font = controlFont; >- _callOptionsLabel.textColor = controlFontColor; >- [_callOptionsLabel sizeToFit]; >- [self addSubview:_callOptionsLabel]; >- >- _loopbackSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; >- [_loopbackSwitch sizeToFit]; >- [self addSubview:_loopbackSwitch]; >- >- _loopbackLabel = [[UILabel alloc] initWithFrame:CGRectZero]; >- _loopbackLabel.text = @"Loopback mode"; >- _loopbackLabel.font = controlFont; >- _loopbackLabel.textColor = controlFontColor; >- [_loopbackLabel sizeToFit]; >- [self addSubview:_loopbackLabel]; >- >- _startCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; >- [_startCallButton setTitle:@"Start call" >- forState:UIControlStateNormal]; >- _startCallButton.titleLabel.font = controlFont; >- [_startCallButton sizeToFit]; >- [_startCallButton addTarget:self >- action:@selector(onStartCall:) >- forControlEvents:UIControlEventTouchUpInside]; >- [self addSubview:_startCallButton]; >+ UIFont *controlFont = [UIFont boldSystemFontOfSize:18.0]; >+ UIColor *controlFontColor = [UIColor whiteColor]; >+ >+ _startRegularCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ _startRegularCallButton.titleLabel.font = controlFont; >+ [_startRegularCallButton setTitleColor:controlFontColor forState:UIControlStateNormal]; >+ _startRegularCallButton.backgroundColor >+ = [UIColor colorWithRed:66.0/255.0 green:200.0/255.0 blue:90.0/255.0 alpha:1.0]; >+ [_startRegularCallButton setTitle:@"Call room" forState:UIControlStateNormal]; >+ [_startRegularCallButton addTarget:self >+ action:@selector(onStartRegularCall:) >+ forControlEvents:UIControlEventTouchUpInside]; >+ [self addSubview:_startRegularCallButton]; >+ >+ _startLoopbackCallButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ _startLoopbackCallButton.titleLabel.font = controlFont; >+ [_startLoopbackCallButton setTitleColor:controlFontColor forState:UIControlStateNormal]; >+ _startLoopbackCallButton.backgroundColor = >+ [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0]; >+ [_startLoopbackCallButton setTitle:@"Loopback call" forState:UIControlStateNormal]; >+ [_startLoopbackCallButton addTarget:self >+ action:@selector(onStartLoopbackCall:) >+ forControlEvents:UIControlEventTouchUpInside]; >+ [self addSubview:_startLoopbackCallButton]; >+ > > // Used to test what happens to sounds when calls are in progress. > _audioLoopButton = [UIButton buttonWithType:UIButtonTypeSystem]; > _audioLoopButton.titleLabel.font = controlFont; >+ [_audioLoopButton setTitleColor:controlFontColor forState:UIControlStateNormal]; >+ _audioLoopButton.backgroundColor = >+ [UIColor colorWithRed:1.0 green:149.0/255.0 blue:0.0 alpha:1.0]; > [self updateAudioLoopButton]; > [_audioLoopButton addTarget:self > action:@selector(onToggleAudioLoop:) >@@ -146,51 +142,42 @@ - (void)layoutSubviews { > CGFloat roomTextWidth = bounds.size.width - 2 * kRoomTextFieldMargin; > CGFloat roomTextHeight = [_roomText sizeThatFits:bounds.size].height; > _roomText.frame = >- CGRectMake(kRoomTextFieldMargin, kRoomTextFieldMargin, roomTextWidth, roomTextHeight); >- >- CGFloat callOptionsLabelTop = >- CGRectGetMaxY(_roomText.frame) + kCallControlMargin * 4; >- _callOptionsLabel.frame = CGRectMake(kCallControlMargin, >- callOptionsLabelTop, >- _callOptionsLabel.frame.size.width, >- _callOptionsLabel.frame.size.height); >- >- CGFloat loopbackModeTop = CGRectGetMaxY(_callOptionsLabel.frame) + kCallControlMargin * 2; >- CGRect loopbackModeRect = CGRectMake(kCallControlMargin * 3, >- loopbackModeTop, >- _loopbackSwitch.frame.size.width, >- _loopbackSwitch.frame.size.height); >- _loopbackSwitch.frame = loopbackModeRect; >- CGFloat loopbackModeLabelCenterX = CGRectGetMaxX(loopbackModeRect) + >- kCallControlMargin + _loopbackLabel.frame.size.width / 2; >- _loopbackLabel.center = CGPointMake(loopbackModeLabelCenterX, >- CGRectGetMidY(loopbackModeRect)); >- >- CGFloat audioLoopTop = CGRectGetMaxY(loopbackModeRect) + kCallControlMargin * 3; >- _audioLoopButton.frame = CGRectMake(kCallControlMargin, >- audioLoopTop, >- _audioLoopButton.frame.size.width, >- _audioLoopButton.frame.size.height); >- >- CGFloat startCallTop = >- CGRectGetMaxY(_audioLoopButton.frame) + kCallControlMargin * 3; >- _startCallButton.frame = CGRectMake(kCallControlMargin, >- startCallTop, >- _startCallButton.frame.size.width, >- _startCallButton.frame.size.height); >+ CGRectMake(kRoomTextFieldMargin, kRoomTextFieldMargin, roomTextWidth, >+ roomTextHeight); >+ >+ CGFloat buttonHeight = >+ (CGRectGetMaxY(self.bounds) - CGRectGetMaxY(_roomText.frame) - kCallControlMargin * 4) / 3; >+ >+ CGFloat regularCallFrameTop = CGRectGetMaxY(_roomText.frame) + kCallControlMargin; >+ CGRect regularCallFrame = CGRectMake(kCallControlMargin, >+ regularCallFrameTop, >+ bounds.size.width - 2*kCallControlMargin, >+ buttonHeight); >+ >+ CGFloat loopbackCallFrameTop = CGRectGetMaxY(regularCallFrame) + kCallControlMargin; >+ CGRect loopbackCallFrame = CGRectMake(kCallControlMargin, >+ loopbackCallFrameTop, >+ bounds.size.width - 2*kCallControlMargin, >+ buttonHeight); >+ >+ CGFloat audioLoopTop = CGRectGetMaxY(loopbackCallFrame) + kCallControlMargin; >+ CGRect audioLoopFrame = CGRectMake(kCallControlMargin, >+ audioLoopTop, >+ bounds.size.width - 2*kCallControlMargin, >+ buttonHeight); >+ >+ _startRegularCallButton.frame = regularCallFrame; >+ _startLoopbackCallButton.frame = loopbackCallFrame; >+ _audioLoopButton.frame = audioLoopFrame; > } > > #pragma mark - Private > > - (void)updateAudioLoopButton { > if (_isAudioLoopPlaying) { >- [_audioLoopButton setTitle:@"Stop sound" >- forState:UIControlStateNormal]; >- [_audioLoopButton sizeToFit]; >+ [_audioLoopButton setTitle:@"Stop sound" forState:UIControlStateNormal]; > } else { >- [_audioLoopButton setTitle:@"Play sound" >- forState:UIControlStateNormal]; >- [_audioLoopButton sizeToFit]; >+ [_audioLoopButton setTitle:@"Play sound" forState:UIControlStateNormal]; > } > } > >@@ -198,8 +185,12 @@ - (void)onToggleAudioLoop:(id)sender { > [_delegate mainViewDidToggleAudioLoop:self]; > } > >-- (void)onStartCall:(id)sender { >- [_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:_loopbackSwitch.isOn]; >+- (void)onStartRegularCall:(id)sender { >+ [_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:NO]; >+} >+ >+- (void)onStartLoopbackCall:(id)sender { >+ [_delegate mainView:self didInputRoom:_roomText.roomText isLoopback:YES]; > } > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m >index 27aa757ff74..f2fea15c094 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDSettingsViewController.m >@@ -24,7 +24,6 @@ typedef NS_ENUM(int, ARDSettingsSections) { > typedef NS_ENUM(int, ARDAudioSettingsOptions) { > ARDAudioSettingsAudioOnly = 0, > ARDAudioSettingsCreateAecDump, >- ARDAudioSettingsUseLevelController, > ARDAudioSettingsUseManualAudioConfig, > }; > >@@ -92,7 +91,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { > - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { > switch (section) { > case ARDSettingsSectionAudioSettings: >- return 4; >+ return 3; > case ARDSettingsSectionVideoResolution: > return self.videoResolutionArray.count; > case ARDSettingsSectionVideoCodec: >@@ -319,8 +318,6 @@ - (NSString *)labelForAudioSettingAtIndexPathRow:(NSInteger)setting { > return @"Audio only"; > case ARDAudioSettingsCreateAecDump: > return @"Create AecDump"; >- case ARDAudioSettingsUseLevelController: >- return @"Use level controller"; > case ARDAudioSettingsUseManualAudioConfig: > return @"Use manual audio config"; > default: >@@ -334,8 +331,6 @@ - (BOOL)valueForAudioSettingAtIndexPathRow:(NSInteger)setting { > return [_settingsModel currentAudioOnlySettingFromStore]; > case ARDAudioSettingsCreateAecDump: > return [_settingsModel currentCreateAecDumpSettingFromStore]; >- case ARDAudioSettingsUseLevelController: >- return [_settingsModel currentUseLevelControllerSettingFromStore]; > case ARDAudioSettingsUseManualAudioConfig: > return [_settingsModel currentUseManualAudioConfigSettingFromStore]; > default: >@@ -353,10 +348,6 @@ - (void)audioSettingSwitchChanged:(UISwitch *)sender { > [_settingsModel storeCreateAecDumpSetting:sender.isOn]; > break; > } >- case ARDAudioSettingsUseLevelController: { >- [_settingsModel storeUseLevelControllerSetting:sender.isOn]; >- break; >- } > case ARDAudioSettingsUseManualAudioConfig: { > [_settingsModel storeUseManualAudioConfigSetting:sender.isOn]; > break; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m >index bf349ceea96..dbd78ea279f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/ARDVideoCallViewController.m >@@ -18,7 +18,6 @@ > #import "ARDFileCaptureController.h" > #import "ARDSettingsModel.h" > #import "ARDVideoCallView.h" >-#import "WebRTC/RTCAVFoundationVideoSource.h" > #import "WebRTC/RTCDispatcher.h" > #import "WebRTC/RTCLogging.h" > #import "WebRTC/RTCMediaConstraints.h" >@@ -125,7 +124,11 @@ - (void)appClient:(ARDAppClient *)client > - (void)appClient:(ARDAppClient *)client > didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { > self.remoteVideoTrack = remoteVideoTrack; >- _videoCallView.statusLabel.hidden = YES; >+ __weak ARDVideoCallViewController *weakSelf = self; >+ dispatch_async(dispatch_get_main_queue(), ^{ >+ ARDVideoCallViewController *strongSelf = weakSelf; >+ strongSelf.videoCallView.statusLabel.hidden = YES; >+ }); > } > > - (void)appClient:(ARDAppClient *)client >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.h >new file mode 100644 >index 00000000000..2218261991f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.h >@@ -0,0 +1,25 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import <ReplayKit/ReplayKit.h> >+ >+#import "WebRTC/RTCLogging.h" >+ >+#import "ARDAppClient.h" >+ >+@protocol ARDExternalSampleDelegate; >+ >+API_AVAILABLE(ios(10.0)) >+@interface ARDBroadcastSampleHandler >+ : RPBroadcastSampleHandler<ARDAppClientDelegate> >+ >+@property(nonatomic, strong) id<ARDExternalSampleDelegate> capturer; >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m >new file mode 100644 >index 00000000000..d54bec7583a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSampleHandler.m >@@ -0,0 +1,130 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import "ARDBroadcastSampleHandler.h" >+ >+#import <os/log.h> >+ >+#import "ARDExternalSampleCapturer.h" >+#import "ARDSettingsModel.h" >+ >+#import "WebRTC/RTCCallbackLogger.h" >+#import "WebRTC/RTCLogging.h" >+ >+@implementation ARDBroadcastSampleHandler { >+ ARDAppClient *_client; >+ RTCCallbackLogger *_callbackLogger; >+} >+ >+@synthesize capturer = _capturer; >+ >+- (instancetype)init { >+ if (self = [super init]) { >+ _callbackLogger = [[RTCCallbackLogger alloc] init]; >+ os_log_t rtc_os_log = os_log_create("com.google.AppRTCMobile", "RTCLog"); >+ [_callbackLogger start:^(NSString *logMessage) { >+ os_log(rtc_os_log, "%{public}s", [logMessage cStringUsingEncoding:NSUTF8StringEncoding]); >+ }]; >+ } >+ return self; >+} >+ >+- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *, NSObject *> *)setupInfo { >+ // User has requested to start the broadcast. Setup info from the UI extension can be supplied but >+ // optional. >+ ARDSettingsModel *settingsModel = [[ARDSettingsModel alloc] init]; >+ >+ _client = [[ARDAppClient alloc] initWithDelegate:self]; >+ _client.broadcast = YES; >+ >+ NSString *roomName = nil; >+ if (setupInfo[@"roomName"]) { >+ roomName = (NSString *)setupInfo[@"roomName"]; >+ } else { >+ u_int32_t randomRoomSuffix = arc4random_uniform(1000); >+ roomName = [NSString stringWithFormat:@"broadcast_%d", randomRoomSuffix]; >+ } >+ [_client connectToRoomWithId:roomName settings:settingsModel isLoopback:NO]; >+ RTCLog(@"Broadcast started."); >+} >+ >+- (void)broadcastPaused { >+ // User has requested to pause the broadcast. Samples will stop being delivered. >+} >+ >+- (void)broadcastResumed { >+ // User has requested to resume the broadcast. Samples delivery will resume. >+} >+ >+- (void)broadcastFinished { >+ // User has requested to finish the broadcast. >+ [_client disconnect]; >+} >+ >+- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer >+ withType:(RPSampleBufferType)sampleBufferType { >+ switch (sampleBufferType) { >+ case RPSampleBufferTypeVideo: >+ [self.capturer didCaptureSampleBuffer:sampleBuffer]; >+ break; >+ case RPSampleBufferTypeAudioApp: >+ break; >+ case RPSampleBufferTypeAudioMic: >+ break; >+ default: >+ break; >+ } >+} >+ >+#pragma mark - ARDAppClientDelegate >+ >+- (void)appClient:(ARDAppClient *)client didChangeState:(ARDAppClientState)state { >+ switch (state) { >+ case kARDAppClientStateConnected: >+ RTCLog(@"Client connected."); >+ break; >+ case kARDAppClientStateConnecting: >+ RTCLog("Client connecting."); >+ break; >+ case kARDAppClientStateDisconnected: >+ RTCLog(@"Client disconnected."); >+ break; >+ } >+} >+ >+- (void)appClient:(ARDAppClient *)client didChangeConnectionState:(RTCIceConnectionState)state { >+ RTCLog(@"ICE state changed: %ld", (long)state); >+} >+ >+- (void)appClient:(ARDAppClient *)client >+ didCreateLocalCapturer:(RTCCameraVideoCapturer *)localCapturer { >+} >+ >+- (void)appClient:(ARDAppClient *)client >+ didCreateLocalExternalSampleCapturer:(ARDExternalSampleCapturer *)externalSampleCapturer { >+ self.capturer = externalSampleCapturer; >+} >+ >+- (void)appClient:(ARDAppClient *)client >+ didReceiveLocalVideoTrack:(RTCVideoTrack *)localVideoTrack { >+} >+ >+- (void)appClient:(ARDAppClient *)client >+ didReceiveRemoteVideoTrack:(RTCVideoTrack *)remoteVideoTrack { >+} >+ >+- (void)appClient:(ARDAppClient *)client didGetStats:(NSArray *)stats { >+} >+ >+- (void)appClient:(ARDAppClient *)client didError:(NSError *)error { >+ RTCLog(@"Error: %@", error); >+} >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.h >new file mode 100644 >index 00000000000..e95c5cc226d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.h >@@ -0,0 +1,18 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import <ReplayKit/ReplayKit.h> >+#import <UIKit/UIKit.h> >+ >+API_AVAILABLE(ios(11.0)) >+@interface ARDBroadcastSetupViewController >+ : UIViewController<UITextFieldDelegate> >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.m >new file mode 100644 >index 00000000000..55438f17d87 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/ARDBroadcastSetupViewController.m >@@ -0,0 +1,107 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import "ARDBroadcastSetupViewController.h" >+ >+@implementation ARDBroadcastSetupViewController { >+ UITextField *_roomNameField; >+} >+ >+- (void)loadView { >+ UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; >+ view.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.7]; >+ >+ UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Icon-180"]]; >+ imageView.translatesAutoresizingMaskIntoConstraints = NO; >+ [view addSubview:imageView]; >+ >+ _roomNameField = [[UITextField alloc] initWithFrame:CGRectZero]; >+ _roomNameField.borderStyle = UITextBorderStyleRoundedRect; >+ _roomNameField.font = [UIFont systemFontOfSize:14.0]; >+ _roomNameField.translatesAutoresizingMaskIntoConstraints = NO; >+ _roomNameField.placeholder = @"Room name"; >+ _roomNameField.returnKeyType = UIReturnKeyDone; >+ _roomNameField.delegate = self; >+ [view addSubview:_roomNameField]; >+ >+ UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ doneButton.translatesAutoresizingMaskIntoConstraints = NO; >+ doneButton.titleLabel.font = [UIFont systemFontOfSize:20.0]; >+ [doneButton setTitle:@"Done" forState:UIControlStateNormal]; >+ [doneButton addTarget:self >+ action:@selector(userDidFinishSetup) >+ forControlEvents:UIControlEventTouchUpInside]; >+ [view addSubview:doneButton]; >+ >+ UIButton *cancelButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ cancelButton.translatesAutoresizingMaskIntoConstraints = NO; >+ cancelButton.titleLabel.font = [UIFont systemFontOfSize:20.0]; >+ [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal]; >+ [cancelButton addTarget:self >+ action:@selector(userDidCancelSetup) >+ forControlEvents:UIControlEventTouchUpInside]; >+ [view addSubview:cancelButton]; >+ >+ UILayoutGuide *margin = view.layoutMarginsGuide; >+ [imageView.widthAnchor constraintEqualToConstant:60.0].active = YES; >+ [imageView.heightAnchor constraintEqualToConstant:60.0].active = YES; >+ [imageView.topAnchor constraintEqualToAnchor:margin.topAnchor constant:20].active = YES; >+ [imageView.centerXAnchor constraintEqualToAnchor:view.centerXAnchor].active = YES; >+ >+ [_roomNameField.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor].active = YES; >+ [_roomNameField.topAnchor constraintEqualToAnchor:imageView.bottomAnchor constant:20].active = >+ YES; >+ [_roomNameField.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor].active = YES; >+ >+ [doneButton.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor].active = YES; >+ [doneButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:-20].active = YES; >+ >+ [cancelButton.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor].active = YES; >+ [cancelButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:-20].active = YES; >+ >+ UITapGestureRecognizer *tgr = >+ [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)]; >+ [view addGestureRecognizer:tgr]; >+ >+ self.view = view; >+} >+ >+- (IBAction)didTap:(id)sender { >+ [self.view endEditing:YES]; >+} >+ >+- (void)userDidFinishSetup { >+ // URL of the resource where broadcast can be viewed that will be returned to the application >+ NSURL *broadcastURL = [NSURL >+ URLWithString:[NSString stringWithFormat:@"https://appr.tc/r/%@", _roomNameField.text]]; >+ >+ // Dictionary with setup information that will be provided to broadcast extension when broadcast >+ // is started >+ NSDictionary *setupInfo = @{@"roomName" : _roomNameField.text}; >+ >+ // Tell ReplayKit that the extension is finished setting up and can begin broadcasting >+ [self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo]; >+} >+ >+- (void)userDidCancelSetup { >+ // Tell ReplayKit that the extension was cancelled by the user >+ [self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"com.google.AppRTCMobile" >+ code:-1 >+ userInfo:nil]]; >+} >+ >+#pragma mark - UITextFieldDelegate >+ >+- (BOOL)textFieldShouldReturn:(UITextField *)textField { >+ [self userDidFinishSetup]; >+ return YES; >+} >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastSetupUIInfo.plist b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastSetupUIInfo.plist >new file mode 100644 >index 00000000000..a123c111e55 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastSetupUIInfo.plist >@@ -0,0 +1,39 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>en</string> >+ <key>CFBundleDisplayName</key> >+ <string>AppRTCMobile</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIdentifier</key> >+ <string>com.google.AppRTCMobile.BroadcastSetupUI</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>XPC!</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+ <key>NSExtension</key> >+ <dict> >+ <key>NSExtensionAttributes</key> >+ <dict> >+ <key>NSExtensionActivationRule</key> >+ <dict> >+ <key>NSExtensionActivationSupportsReplayKitStreaming</key> >+ <true/> >+ </dict> >+ </dict> >+ <key>NSExtensionPointIdentifier</key> >+ <string>com.apple.broadcast-services-setupui</string> >+ <key>NSExtensionPrincipalClass</key> >+ <string>ARDBroadcastSetupViewController</string> >+ </dict> >+</dict> >+</plist> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastUploadInfo.plist b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastUploadInfo.plist >new file mode 100644 >index 00000000000..2bab60ea8fb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/broadcast_extension/BroadcastUploadInfo.plist >@@ -0,0 +1,33 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>en</string> >+ <key>CFBundleDisplayName</key> >+ <string>AppRTCMobile</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIdentifier</key> >+ <string>com.google.AppRTCMobile.BroadcastUpload</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>$(PRODUCT_NAME)</string> >+ <key>CFBundlePackageType</key> >+ <string>XPC!</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+ <key>NSExtension</key> >+ <dict> >+ <key>NSExtensionPointIdentifier</key> >+ <string>com.apple.broadcast-services-upload</string> >+ <key>NSExtensionPrincipalClass</key> >+ <string>ARDBroadcastSampleHandler</string> >+ <key>RPBroadcastProcessMode</key> >+ <string>RPBroadcastProcessModeSampleBuffer</string> >+ </dict> >+</dict> >+</plist> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/resources/foreman.mp4 b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/resources/foreman.mp4 >new file mode 100644 >index 00000000000..ccffbf47225 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/AppRTCMobile/ios/resources/foreman.mp4 differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-120.png b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-120.png >new file mode 100644 >index 00000000000..938fef477b0 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-120.png differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-180.png b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-180.png >new file mode 100644 >index 00000000000..a5b76096800 >Binary files /dev/null and b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objc/Icon-180.png differ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/Info.plist b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/Info.plist >new file mode 100644 >index 00000000000..cbc9e5f9f3c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/Info.plist >@@ -0,0 +1,45 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> >+<plist version="1.0"> >+<dict> >+ <key>CFBundleDevelopmentRegion</key> >+ <string>en</string> >+ <key>CFBundleExecutable</key> >+ <string>$(EXECUTABLE_NAME)</string> >+ <key>CFBundleIdentifier</key> >+ <string>com.google.ObjCNativeAPIDemo</string> >+ <key>CFBundleInfoDictionaryVersion</key> >+ <string>6.0</string> >+ <key>CFBundleName</key> >+ <string>ObjCNativeAPIDemo</string> >+ <key>CFBundlePackageType</key> >+ <string>APPL</string> >+ <key>CFBundleShortVersionString</key> >+ <string>1.0</string> >+ <key>CFBundleVersion</key> >+ <string>1</string> >+ <key>LSRequiresIPhoneOS</key> >+ <true/> >+ <key>UIRequiredDeviceCapabilities</key> >+ <array> >+ <string>armv7</string> >+ </array> >+ <key>UISupportedInterfaceOrientations</key> >+ <array> >+ <string>UIInterfaceOrientationPortrait</string> >+ <string>UIInterfaceOrientationLandscapeLeft</string> >+ <string>UIInterfaceOrientationLandscapeRight</string> >+ </array> >+ <key>UISupportedInterfaceOrientations~ipad</key> >+ <array> >+ <string>UIInterfaceOrientationPortrait</string> >+ <string>UIInterfaceOrientationPortraitUpsideDown</string> >+ <string>UIInterfaceOrientationLandscapeLeft</string> >+ <string>UIInterfaceOrientationLandscapeRight</string> >+ </array> >+ <key>NSCameraUsageDescription</key> >+ <string>Camera access needed for video calling</string> >+ <key>NSMicrophoneUsageDescription</key> >+ <string>Microphone access needed for video calling</string> >+</dict> >+</plist> >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/AppDelegate.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.h >similarity index 68% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/AppDelegate.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.h >index de2cc0465db..d4211208427 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/AppDelegate.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.h >@@ -1,5 +1,5 @@ > /* >- * Copyright 2016 The WebRTC project authors. All Rights Reserved. >+ * Copyright 2018 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 >@@ -10,8 +10,8 @@ > > #import <UIKit/UIKit.h> > >-@interface AppDelegate : UIResponder <UIApplicationDelegate> >+@interface NADAppDelegate : UIResponder<UIApplicationDelegate> > >-@property (strong, nonatomic) UIWindow *window; >+@property(strong, nonatomic) UIWindow* window; > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.m >new file mode 100644 >index 00000000000..254dd3be76f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADAppDelegate.m >@@ -0,0 +1,63 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import "NADAppDelegate.h" >+ >+#import "NADViewController.h" >+ >+@interface NADAppDelegate () >+@end >+ >+@implementation NADAppDelegate >+ >+@synthesize window = _window; >+ >+- (BOOL)application:(UIApplication *)application >+ didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { >+ _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; >+ [_window makeKeyAndVisible]; >+ >+ NADViewController *viewController = [[NADViewController alloc] init]; >+ _window.rootViewController = viewController; >+ >+ return YES; >+} >+ >+- (void)applicationWillResignActive:(UIApplication *)application { >+ // Sent when the application is about to move from active to inactive state. This can occur for >+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or >+ // when the user quits the application and it begins the transition to the background state. Use >+ // this method to pause ongoing tasks, disable timers, and invalidate graphics rendering >+ // callbacks. Games should use this method to pause the game. >+} >+ >+- (void)applicationDidEnterBackground:(UIApplication *)application { >+ // Use this method to release shared resources, save user data, invalidate timers, and store >+ // enough application state information to restore your application to its current state in case >+ // it is terminated later. If your application supports background execution, this method is >+ // called instead of applicationWillTerminate: when the user quits. >+} >+ >+- (void)applicationWillEnterForeground:(UIApplication *)application { >+ // Called as part of the transition from the background to the active state; here you can undo >+ // many of the changes made on entering the background. >+} >+ >+- (void)applicationDidBecomeActive:(UIApplication *)application { >+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If >+ // the application was previously in the background, optionally refresh the user interface. >+} >+ >+- (void)applicationWillTerminate:(UIApplication *)application { >+ // Called when the application is about to terminate. Save data if appropriate. See also >+ // applicationDidEnterBackground:. >+} >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/ViewController.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.h >similarity index 77% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/ViewController.h >rename to Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.h >index bdf8f31856d..c43bebb52d4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/ViewController.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.h >@@ -1,5 +1,5 @@ > /* >- * Copyright 2016 The WebRTC project authors. All Rights Reserved. >+ * Copyright 2018 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 >@@ -10,6 +10,6 @@ > > #import <UIKit/UIKit.h> > >-@interface ViewController : UIViewController >+@interface NADViewController : UIViewController > > @end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.mm b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.mm >new file mode 100644 >index 00000000000..0d5ac9a3b91 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/NADViewController.mm >@@ -0,0 +1,157 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#import "NADViewController.h" >+ >+#import <WebRTC/RTCCameraPreviewView.h> >+#import <WebRTC/RTCCameraVideoCapturer.h> >+#import <WebRTC/RTCEAGLVideoView.h> >+#import <WebRTC/RTCMTLVideoView.h> >+#import <WebRTC/RTCVideoRenderer.h> >+#include <memory> >+ >+#include "objccallclient.h" >+ >+@interface NADViewController () >+ >+@property(nonatomic) RTCCameraVideoCapturer *capturer; >+@property(nonatomic) RTCCameraPreviewView *localVideoView; >+@property(nonatomic) __kindof UIView<RTCVideoRenderer> *remoteVideoView; >+@property(nonatomic) UIButton *callButton; >+@property(nonatomic) UIButton *hangUpButton; >+ >+@end >+ >+@implementation NADViewController { >+ std::unique_ptr<webrtc_examples::ObjCCallClient> _call_client; >+ >+ UIView *_view; >+} >+ >+@synthesize capturer = _capturer; >+@synthesize localVideoView = _localVideoView; >+@synthesize remoteVideoView = _remoteVideoView; >+@synthesize callButton = _callButton; >+@synthesize hangUpButton = _hangUpButton; >+ >+#pragma mark - View controller lifecycle >+ >+- (void)loadView { >+ _view = [[UIView alloc] initWithFrame:CGRectZero]; >+ >+#if defined(RTC_SUPPORTS_METAL) >+ _remoteVideoView = [[RTCMTLVideoView alloc] initWithFrame:CGRectZero]; >+#else >+ _remoteVideoView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero]; >+#endif >+ _remoteVideoView.translatesAutoresizingMaskIntoConstraints = NO; >+ [_view addSubview:_remoteVideoView]; >+ >+ _localVideoView = [[RTCCameraPreviewView alloc] initWithFrame:CGRectZero]; >+ _localVideoView.translatesAutoresizingMaskIntoConstraints = NO; >+ [_view addSubview:_localVideoView]; >+ >+ _callButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ _callButton.translatesAutoresizingMaskIntoConstraints = NO; >+ [_callButton setTitle:@"Call" forState:UIControlStateNormal]; >+ [_callButton addTarget:self action:@selector(call:) forControlEvents:UIControlEventTouchUpInside]; >+ [_view addSubview:_callButton]; >+ >+ _hangUpButton = [UIButton buttonWithType:UIButtonTypeSystem]; >+ _hangUpButton.translatesAutoresizingMaskIntoConstraints = NO; >+ [_hangUpButton setTitle:@"Hang up" forState:UIControlStateNormal]; >+ [_hangUpButton addTarget:self >+ action:@selector(hangUp:) >+ forControlEvents:UIControlEventTouchUpInside]; >+ [_view addSubview:_hangUpButton]; >+ >+ UILayoutGuide *margin = _view.layoutMarginsGuide; >+ [_remoteVideoView.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor].active = YES; >+ [_remoteVideoView.topAnchor constraintEqualToAnchor:margin.topAnchor].active = YES; >+ [_remoteVideoView.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor].active = YES; >+ [_remoteVideoView.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor].active = YES; >+ >+ [_localVideoView.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor constant:8.0].active = >+ YES; >+ [_localVideoView.topAnchor constraintEqualToAnchor:margin.topAnchor constant:8.0].active = YES; >+ [_localVideoView.widthAnchor constraintEqualToConstant:60].active = YES; >+ [_localVideoView.heightAnchor constraintEqualToConstant:60].active = YES; >+ >+ [_callButton.leadingAnchor constraintEqualToAnchor:margin.leadingAnchor constant:8.0].active = >+ YES; >+ [_callButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:8.0].active = YES; >+ [_callButton.widthAnchor constraintEqualToConstant:100].active = YES; >+ [_callButton.heightAnchor constraintEqualToConstant:40].active = YES; >+ >+ [_hangUpButton.trailingAnchor constraintEqualToAnchor:margin.trailingAnchor constant:8.0].active = >+ YES; >+ [_hangUpButton.bottomAnchor constraintEqualToAnchor:margin.bottomAnchor constant:8.0].active = >+ YES; >+ [_hangUpButton.widthAnchor constraintEqualToConstant:100].active = YES; >+ [_hangUpButton.heightAnchor constraintEqualToConstant:40].active = YES; >+ >+ self.view = _view; >+} >+ >+- (void)viewDidLoad { >+ [super viewDidLoad]; >+ >+ self.capturer = [[RTCCameraVideoCapturer alloc] init]; >+ self.localVideoView.captureSession = self.capturer.captureSession; >+ >+ _call_client.reset(new webrtc_examples::ObjCCallClient()); >+ >+ // Start capturer. >+ AVCaptureDevice *selectedDevice = nil; >+ NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices]; >+ for (AVCaptureDevice *device in captureDevices) { >+ if (device.position == AVCaptureDevicePositionFront) { >+ selectedDevice = device; >+ break; >+ } >+ } >+ >+ AVCaptureDeviceFormat *selectedFormat = nil; >+ int targetWidth = 640; >+ int targetHeight = 480; >+ int currentDiff = INT_MAX; >+ NSArray<AVCaptureDeviceFormat *> *formats = >+ [RTCCameraVideoCapturer supportedFormatsForDevice:selectedDevice]; >+ for (AVCaptureDeviceFormat *format in formats) { >+ CMVideoDimensions dimension = CMVideoFormatDescriptionGetDimensions(format.formatDescription); >+ FourCharCode pixelFormat = CMFormatDescriptionGetMediaSubType(format.formatDescription); >+ int diff = abs(targetWidth - dimension.width) + abs(targetHeight - dimension.height); >+ if (diff < currentDiff) { >+ selectedFormat = format; >+ currentDiff = diff; >+ } else if (diff == currentDiff && pixelFormat == [_capturer preferredOutputPixelFormat]) { >+ selectedFormat = format; >+ } >+ } >+ >+ [self.capturer startCaptureWithDevice:selectedDevice format:selectedFormat fps:30]; >+} >+ >+- (void)didReceiveMemoryWarning { >+ [super didReceiveMemoryWarning]; >+ // Dispose of any resources that can be recreated. >+} >+ >+#pragma mark - Actions >+ >+- (IBAction)call:(id)sender { >+ _call_client->Call(self.capturer, self.remoteVideoView); >+} >+ >+- (IBAction)hangUp:(id)sender { >+ _call_client->Hangup(); >+} >+ >+@end >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/main.m b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/main.m >similarity index 62% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/main.m >rename to Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/main.m >index 4169aa9fabd..2c3b5fbbfb1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/tools_webrtc/ios/SDK/PodTest/PodTest/main.m >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/main.m >@@ -1,5 +1,5 @@ > /* >- * Copyright 2016 The WebRTC project authors. All Rights Reserved. >+ * Copyright 2018 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 >@@ -9,13 +9,10 @@ > */ > > #import <UIKit/UIKit.h> >-#import "AppDelegate.h" >+#import "NADAppDelegate.h" > > int main(int argc, char* argv[]) { > @autoreleasepool { >- return UIApplicationMain(argc, >- argv, >- nil, >- NSStringFromClass([AppDelegate class])); >+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([NADAppDelegate class])); > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.h >new file mode 100644 >index 00000000000..e48aae47e1e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.h >@@ -0,0 +1,84 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#ifndef EXAMPLES_OBJCNATIVEAPI_OBJCCALLCLIENT_H_ >+#define EXAMPLES_OBJCNATIVEAPI_OBJCCALLCLIENT_H_ >+ >+#include <memory> >+#include <string> >+ >+#include "api/peerconnectioninterface.h" >+#include "rtc_base/criticalsection.h" >+#include "rtc_base/scoped_ref_ptr.h" >+#include "rtc_base/thread_checker.h" >+ >+@class RTCVideoCapturer; >+@protocol RTCVideoRenderer; >+ >+namespace webrtc_examples { >+ >+class ObjCCallClient { >+ public: >+ ObjCCallClient(); >+ >+ void Call(RTCVideoCapturer* capturer, id<RTCVideoRenderer> remote_renderer); >+ void Hangup(); >+ >+ private: >+ class PCObserver : public webrtc::PeerConnectionObserver { >+ public: >+ explicit PCObserver(ObjCCallClient* client); >+ >+ void OnSignalingChange( >+ webrtc::PeerConnectionInterface::SignalingState new_state) override; >+ void OnDataChannel( >+ rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override; >+ void OnRenegotiationNeeded() override; >+ void OnIceConnectionChange( >+ webrtc::PeerConnectionInterface::IceConnectionState new_state) override; >+ void OnIceGatheringChange( >+ webrtc::PeerConnectionInterface::IceGatheringState new_state) override; >+ void OnIceCandidate( >+ const webrtc::IceCandidateInterface* candidate) override; >+ >+ private: >+ const ObjCCallClient* client_; >+ }; >+ >+ void CreatePeerConnectionFactory() RTC_RUN_ON(thread_checker_); >+ void CreatePeerConnection() RTC_RUN_ON(thread_checker_); >+ void Connect() RTC_RUN_ON(thread_checker_); >+ >+ rtc::ThreadChecker thread_checker_; >+ >+ bool call_started_ RTC_GUARDED_BY(thread_checker_); >+ >+ const std::unique_ptr<PCObserver> pc_observer_; >+ >+ rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pcf_ >+ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> network_thread_ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> worker_thread_ RTC_GUARDED_BY(thread_checker_); >+ std::unique_ptr<rtc::Thread> signaling_thread_ >+ RTC_GUARDED_BY(thread_checker_); >+ >+ std::unique_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> remote_sink_ >+ RTC_GUARDED_BY(thread_checker_); >+ rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> video_source_ >+ RTC_GUARDED_BY(thread_checker_); >+ >+ rtc::CriticalSection pc_mutex_; >+ rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_ >+ RTC_GUARDED_BY(pc_mutex_); >+}; >+ >+} // namespace webrtc_examples >+ >+#endif // EXAMPLES_OBJCNATIVEAPI_OBJCCALLCLIENT_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.mm b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.mm >new file mode 100644 >index 00000000000..0e3b8e05db0 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/objcnativeapi/objc/objccallclient.mm >@@ -0,0 +1,237 @@ >+/* >+ * Copyright 2018 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 "examples/objcnativeapi/objc/objccallclient.h" >+ >+#include <utility> >+ >+#import <WebRTC/RTCCameraPreviewView.h> >+#import <WebRTC/RTCVideoCodecFactory.h> >+#import <WebRTC/RTCVideoRenderer.h> >+ >+#include "absl/memory/memory.h" >+#include "api/audio_codecs/builtin_audio_decoder_factory.h" >+#include "api/audio_codecs/builtin_audio_encoder_factory.h" >+#include "api/peerconnectioninterface.h" >+#include "media/engine/webrtcmediaengine.h" >+#include "modules/audio_processing/include/audio_processing.h" >+#include "sdk/objc/Framework/Native/api/video_capturer.h" >+#include "sdk/objc/Framework/Native/api/video_decoder_factory.h" >+#include "sdk/objc/Framework/Native/api/video_encoder_factory.h" >+#include "sdk/objc/Framework/Native/api/video_renderer.h" >+ >+namespace webrtc_examples { >+ >+namespace { >+ >+class CreateOfferObserver : public webrtc::CreateSessionDescriptionObserver { >+ public: >+ explicit CreateOfferObserver(rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc); >+ >+ void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; >+ void OnFailure(webrtc::RTCError error) override; >+ >+ private: >+ const rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc_; >+}; >+ >+class SetRemoteSessionDescriptionObserver : public webrtc::SetRemoteDescriptionObserverInterface { >+ public: >+ void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override; >+}; >+ >+class SetLocalSessionDescriptionObserver : public webrtc::SetSessionDescriptionObserver { >+ public: >+ void OnSuccess() override; >+ void OnFailure(webrtc::RTCError error) override; >+}; >+ >+} // namespace >+ >+ObjCCallClient::ObjCCallClient() >+ : call_started_(false), pc_observer_(absl::make_unique<PCObserver>(this)) { >+ thread_checker_.DetachFromThread(); >+ CreatePeerConnectionFactory(); >+} >+ >+void ObjCCallClient::Call(RTCVideoCapturer* capturer, id<RTCVideoRenderer> remote_renderer) { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ rtc::CritScope lock(&pc_mutex_); >+ if (call_started_) { >+ RTC_LOG(LS_WARNING) << "Call already started."; >+ return; >+ } >+ call_started_ = true; >+ >+ remote_sink_ = webrtc::ObjCToNativeVideoRenderer(remote_renderer); >+ >+ video_source_ = >+ webrtc::ObjCToNativeVideoCapturer(capturer, signaling_thread_.get(), worker_thread_.get()); >+ >+ CreatePeerConnection(); >+ Connect(); >+} >+ >+void ObjCCallClient::Hangup() { >+ RTC_DCHECK_RUN_ON(&thread_checker_); >+ >+ call_started_ = false; >+ >+ { >+ rtc::CritScope lock(&pc_mutex_); >+ if (pc_ != nullptr) { >+ pc_->Close(); >+ pc_ = nullptr; >+ } >+ } >+ >+ remote_sink_ = nullptr; >+ video_source_ = nullptr; >+} >+ >+void ObjCCallClient::CreatePeerConnectionFactory() { >+ network_thread_ = rtc::Thread::CreateWithSocketServer(); >+ network_thread_->SetName("network_thread", nullptr); >+ RTC_CHECK(network_thread_->Start()) << "Failed to start thread"; >+ >+ worker_thread_ = rtc::Thread::Create(); >+ worker_thread_->SetName("worker_thread", nullptr); >+ RTC_CHECK(worker_thread_->Start()) << "Failed to start thread"; >+ >+ signaling_thread_ = rtc::Thread::Create(); >+ signaling_thread_->SetName("signaling_thread", nullptr); >+ RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread"; >+ >+ std::unique_ptr<webrtc::VideoDecoderFactory> videoDecoderFactory = >+ webrtc::ObjCToNativeVideoDecoderFactory([[RTCDefaultVideoDecoderFactory alloc] init]); >+ std::unique_ptr<webrtc::VideoEncoderFactory> videoEncoderFactory = >+ webrtc::ObjCToNativeVideoEncoderFactory([[RTCDefaultVideoEncoderFactory alloc] init]); >+ >+ std::unique_ptr<cricket::MediaEngineInterface> media_engine = >+ cricket::WebRtcMediaEngineFactory::Create(nullptr /* adm */, >+ webrtc::CreateBuiltinAudioEncoderFactory(), >+ webrtc::CreateBuiltinAudioDecoderFactory(), >+ std::move(videoEncoderFactory), >+ std::move(videoDecoderFactory), >+ nullptr /* audio_mixer */, >+ webrtc::AudioProcessingBuilder().Create()); >+ RTC_LOG(LS_INFO) << "Media engine created: " << media_engine.get(); >+ >+ pcf_ = webrtc::CreateModularPeerConnectionFactory(network_thread_.get(), >+ worker_thread_.get(), >+ signaling_thread_.get(), >+ std::move(media_engine), >+ webrtc::CreateCallFactory(), >+ webrtc::CreateRtcEventLogFactory()); >+ RTC_LOG(LS_INFO) << "PeerConnectionFactory created: " << pcf_; >+} >+ >+void ObjCCallClient::CreatePeerConnection() { >+ rtc::CritScope lock(&pc_mutex_); >+ webrtc::PeerConnectionInterface::RTCConfiguration config; >+ config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; >+ // DTLS SRTP has to be disabled for loopback to work. >+ config.enable_dtls_srtp = false; >+ pc_ = pcf_->CreatePeerConnection( >+ config, nullptr /* port_allocator */, nullptr /* cert_generator */, pc_observer_.get()); >+ RTC_LOG(LS_INFO) << "PeerConnection created: " << pc_; >+ >+ rtc::scoped_refptr<webrtc::VideoTrackInterface> local_video_track = >+ pcf_->CreateVideoTrack("video", video_source_); >+ pc_->AddTransceiver(local_video_track); >+ RTC_LOG(LS_INFO) << "Local video sink set up: " << local_video_track; >+ >+ for (const rtc::scoped_refptr<webrtc::RtpTransceiverInterface>& tranceiver : >+ pc_->GetTransceivers()) { >+ rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track = tranceiver->receiver()->track(); >+ if (track && track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { >+ static_cast<webrtc::VideoTrackInterface*>(track.get()) >+ ->AddOrUpdateSink(remote_sink_.get(), rtc::VideoSinkWants()); >+ RTC_LOG(LS_INFO) << "Remote video sink set up: " << track; >+ break; >+ } >+ } >+} >+ >+void ObjCCallClient::Connect() { >+ rtc::CritScope lock(&pc_mutex_); >+ pc_->CreateOffer(new rtc::RefCountedObject<CreateOfferObserver>(pc_), >+ webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); >+} >+ >+ObjCCallClient::PCObserver::PCObserver(ObjCCallClient* client) : client_(client) {} >+ >+void ObjCCallClient::PCObserver::OnSignalingChange( >+ webrtc::PeerConnectionInterface::SignalingState new_state) { >+ RTC_LOG(LS_INFO) << "OnSignalingChange: " << new_state; >+} >+ >+void ObjCCallClient::PCObserver::OnDataChannel( >+ rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { >+ RTC_LOG(LS_INFO) << "OnDataChannel"; >+} >+ >+void ObjCCallClient::PCObserver::OnRenegotiationNeeded() { >+ RTC_LOG(LS_INFO) << "OnRenegotiationNeeded"; >+} >+ >+void ObjCCallClient::PCObserver::OnIceConnectionChange( >+ webrtc::PeerConnectionInterface::IceConnectionState new_state) { >+ RTC_LOG(LS_INFO) << "OnIceConnectionChange: " << new_state; >+} >+ >+void ObjCCallClient::PCObserver::OnIceGatheringChange( >+ webrtc::PeerConnectionInterface::IceGatheringState new_state) { >+ RTC_LOG(LS_INFO) << "OnIceGatheringChange: " << new_state; >+} >+ >+void ObjCCallClient::PCObserver::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { >+ RTC_LOG(LS_INFO) << "OnIceCandidate: " << candidate->server_url(); >+ rtc::CritScope lock(&client_->pc_mutex_); >+ RTC_DCHECK(client_->pc_ != nullptr); >+ client_->pc_->AddIceCandidate(candidate); >+} >+ >+CreateOfferObserver::CreateOfferObserver(rtc::scoped_refptr<webrtc::PeerConnectionInterface> pc) >+ : pc_(pc) {} >+ >+void CreateOfferObserver::OnSuccess(webrtc::SessionDescriptionInterface* desc) { >+ std::string sdp; >+ desc->ToString(&sdp); >+ RTC_LOG(LS_INFO) << "Created offer: " << sdp; >+ >+ // Ownership of desc was transferred to us, now we transfer it forward. >+ pc_->SetLocalDescription(new rtc::RefCountedObject<SetLocalSessionDescriptionObserver>(), desc); >+ >+ // Generate a fake answer. >+ std::unique_ptr<webrtc::SessionDescriptionInterface> answer( >+ webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp)); >+ pc_->SetRemoteDescription(std::move(answer), >+ new rtc::RefCountedObject<SetRemoteSessionDescriptionObserver>()); >+} >+ >+void CreateOfferObserver::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Failed to create offer: " << error.message(); >+} >+ >+void SetRemoteSessionDescriptionObserver::OnSetRemoteDescriptionComplete(webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Set remote description: " << error.message(); >+} >+ >+void SetLocalSessionDescriptionObserver::OnSuccess() { >+ RTC_LOG(LS_INFO) << "Set local description success!"; >+} >+ >+void SetLocalSessionDescriptionObserver::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LS_INFO) << "Set local description failure: " << error.message(); >+} >+ >+} // namespace webrtc_examples >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.cc >index 7394137c5d8..89c89846928 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.cc >@@ -17,8 +17,12 @@ > #include "api/audio_codecs/builtin_audio_decoder_factory.h" > #include "api/audio_codecs/builtin_audio_encoder_factory.h" > #include "api/test/fakeconstraints.h" >+#include "api/video_codecs/builtin_video_decoder_factory.h" >+#include "api/video_codecs/builtin_video_encoder_factory.h" > #include "examples/peerconnection/client/defaults.h" > #include "media/engine/webrtcvideocapturerfactory.h" >+#include "modules/audio_device/include/audio_device.h" >+#include "modules/audio_processing/include/audio_processing.h" > #include "modules/video_capture/video_capture_factory.h" > #include "rtc_base/checks.h" > #include "rtc_base/json.h" >@@ -33,41 +37,31 @@ const char kCandidateSdpName[] = "candidate"; > const char kSessionDescriptionTypeName[] = "type"; > const char kSessionDescriptionSdpName[] = "sdp"; > >-#define DTLS_ON true >-#define DTLS_OFF false >- > class DummySetSessionDescriptionObserver > : public webrtc::SetSessionDescriptionObserver { > public: > static DummySetSessionDescriptionObserver* Create() { >- return >- new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); >+ return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); > } > virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; } >- virtual void OnFailure(const std::string& error) { >- RTC_LOG(INFO) << __FUNCTION__ << " " << error; >+ virtual void OnFailure(webrtc::RTCError error) { >+ RTC_LOG(INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": " >+ << error.message(); > } >- >- protected: >- DummySetSessionDescriptionObserver() {} >- ~DummySetSessionDescriptionObserver() {} > }; > > Conductor::Conductor(PeerConnectionClient* client, MainWindow* main_wnd) >- : peer_id_(-1), >- loopback_(false), >- client_(client), >- main_wnd_(main_wnd) { >+ : peer_id_(-1), loopback_(false), client_(client), main_wnd_(main_wnd) { > client_->RegisterObserver(this); > main_wnd->RegisterObserver(this); > } > > Conductor::~Conductor() { >- RTC_DCHECK(peer_connection_.get() == NULL); >+ RTC_DCHECK(!peer_connection_); > } > > bool Conductor::connection_active() const { >- return peer_connection_.get() != NULL; >+ return peer_connection_ != nullptr; > } > > void Conductor::Close() { >@@ -76,77 +70,77 @@ void Conductor::Close() { > } > > bool Conductor::InitializePeerConnection() { >- RTC_DCHECK(peer_connection_factory_.get() == NULL); >- RTC_DCHECK(peer_connection_.get() == NULL); >+ RTC_DCHECK(!peer_connection_factory_); >+ RTC_DCHECK(!peer_connection_); > > peer_connection_factory_ = webrtc::CreatePeerConnectionFactory( >+ nullptr /* network_thread */, nullptr /* worker_thread */, >+ nullptr /* signaling_thread */, nullptr /* default_adm */, > webrtc::CreateBuiltinAudioEncoderFactory(), >- webrtc::CreateBuiltinAudioDecoderFactory()); >+ webrtc::CreateBuiltinAudioDecoderFactory(), >+ webrtc::CreateBuiltinVideoEncoderFactory(), >+ webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, >+ nullptr /* audio_processing */); > >- if (!peer_connection_factory_.get()) { >- main_wnd_->MessageBox("Error", >- "Failed to initialize PeerConnectionFactory", true); >+ if (!peer_connection_factory_) { >+ main_wnd_->MessageBox("Error", "Failed to initialize PeerConnectionFactory", >+ true); > DeletePeerConnection(); > return false; > } > >- if (!CreatePeerConnection(DTLS_ON)) { >- main_wnd_->MessageBox("Error", >- "CreatePeerConnection failed", true); >+ if (!CreatePeerConnection(/*dtls=*/true)) { >+ main_wnd_->MessageBox("Error", "CreatePeerConnection failed", true); > DeletePeerConnection(); > } >- AddStreams(); >- return peer_connection_.get() != NULL; >+ >+ AddTracks(); >+ >+ return peer_connection_ != nullptr; > } > > bool Conductor::ReinitializePeerConnectionForLoopback() { > loopback_ = true; >- rtc::scoped_refptr<webrtc::StreamCollectionInterface> streams( >- peer_connection_->local_streams()); >- peer_connection_ = NULL; >- if (CreatePeerConnection(DTLS_OFF)) { >- for (size_t i = 0; i < streams->count(); ++i) >- peer_connection_->AddStream(streams->at(i)); >- peer_connection_->CreateOffer(this, NULL); >+ std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> senders = >+ peer_connection_->GetSenders(); >+ peer_connection_ = nullptr; >+ if (CreatePeerConnection(/*dtls=*/false)) { >+ for (const auto& sender : senders) { >+ peer_connection_->AddTrack(sender->track(), sender->stream_ids()); >+ } >+ peer_connection_->CreateOffer( >+ this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); > } >- return peer_connection_.get() != NULL; >+ return peer_connection_ != nullptr; > } > > bool Conductor::CreatePeerConnection(bool dtls) { >- RTC_DCHECK(peer_connection_factory_.get() != NULL); >- RTC_DCHECK(peer_connection_.get() == NULL); >+ RTC_DCHECK(peer_connection_factory_); >+ RTC_DCHECK(!peer_connection_); > > webrtc::PeerConnectionInterface::RTCConfiguration config; >+ config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; >+ config.enable_dtls_srtp = dtls; > webrtc::PeerConnectionInterface::IceServer server; > server.uri = GetPeerConnectionString(); > config.servers.push_back(server); > >- webrtc::FakeConstraints constraints; >- if (dtls) { >- constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, >- "true"); >- } else { >- constraints.AddOptional(webrtc::MediaConstraintsInterface::kEnableDtlsSrtp, >- "false"); >- } >- > peer_connection_ = peer_connection_factory_->CreatePeerConnection( >- config, &constraints, NULL, NULL, this); >- return peer_connection_.get() != NULL; >+ config, nullptr, nullptr, this); >+ return peer_connection_ != nullptr; > } > > void Conductor::DeletePeerConnection() { >- peer_connection_ = NULL; >- active_streams_.clear(); > main_wnd_->StopLocalRenderer(); > main_wnd_->StopRemoteRenderer(); >- peer_connection_factory_ = NULL; >+ peer_connection_ = nullptr; >+ peer_connection_factory_ = nullptr; > peer_id_ = -1; > loopback_ = false; > } > > void Conductor::EnsureStreamingUI() { >- RTC_DCHECK(peer_connection_.get() != NULL); >+ RTC_DCHECK(peer_connection_); > if (main_wnd_->IsWindow()) { > if (main_wnd_->current_ui() != MainWindow::STREAMING) > main_wnd_->SwitchToStreamingUI(); >@@ -157,17 +151,19 @@ void Conductor::EnsureStreamingUI() { > // PeerConnectionObserver implementation. > // > >-// Called when a remote stream is added >-void Conductor::OnAddStream( >- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { >- RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label(); >- main_wnd_->QueueUIThreadCallback(NEW_STREAM_ADDED, stream.release()); >+void Conductor::OnAddTrack( >+ rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, >+ const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& >+ streams) { >+ RTC_LOG(INFO) << __FUNCTION__ << " " << receiver->id(); >+ main_wnd_->QueueUIThreadCallback(NEW_TRACK_ADDED, >+ receiver->track().release()); > } > >-void Conductor::OnRemoveStream( >- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { >- RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label(); >- main_wnd_->QueueUIThreadCallback(STREAM_REMOVED, stream.release()); >+void Conductor::OnRemoveTrack( >+ rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) { >+ RTC_LOG(INFO) << __FUNCTION__ << " " << receiver->id(); >+ main_wnd_->QueueUIThreadCallback(TRACK_REMOVED, receiver->track().release()); > } > > void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { >@@ -258,12 +254,13 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { > RTC_LOG(WARNING) << "Received unknown message. " << message; > return; > } >- std::string type; >+ std::string type_str; > std::string json_object; > >- rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, &type); >- if (!type.empty()) { >- if (type == "offer-loopback") { >+ rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionTypeName, >+ &type_str); >+ if (!type_str.empty()) { >+ if (type_str == "offer-loopback") { > // This is a loopback call. > // Recreate the peerconnection with DTLS disabled. > if (!ReinitializePeerConnectionForLoopback()) { >@@ -273,7 +270,13 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { > } > return; > } >- >+ absl::optional<webrtc::SdpType> type_maybe = >+ webrtc::SdpTypeFromString(type_str); >+ if (!type_maybe) { >+ RTC_LOG(LS_ERROR) << "Unknown SDP type: " << type_str; >+ return; >+ } >+ webrtc::SdpType type = *type_maybe; > std::string sdp; > if (!rtc::GetStringFromJsonObject(jmessage, kSessionDescriptionSdpName, > &sdp)) { >@@ -281,8 +284,8 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { > return; > } > webrtc::SdpParseError error; >- webrtc::SessionDescriptionInterface* session_description( >- webrtc::CreateSessionDescription(type, sdp, &error)); >+ std::unique_ptr<webrtc::SessionDescriptionInterface> session_description = >+ webrtc::CreateSessionDescription(type, sdp, &error); > if (!session_description) { > RTC_LOG(WARNING) << "Can't parse received session description message. " > << "SdpParseError was: " << error.description; >@@ -290,12 +293,12 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { > } > RTC_LOG(INFO) << " Received session description :" << message; > peer_connection_->SetRemoteDescription( >- DummySetSessionDescriptionObserver::Create(), session_description); >- if (session_description->type() == >- webrtc::SessionDescriptionInterface::kOffer) { >- peer_connection_->CreateAnswer(this, NULL); >+ DummySetSessionDescriptionObserver::Create(), >+ session_description.release()); >+ if (type == webrtc::SdpType::kOffer) { >+ peer_connection_->CreateAnswer( >+ this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); > } >- return; > } else { > std::string sdp_mid; > int sdp_mlineindex = 0; >@@ -321,7 +324,6 @@ void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) { > return; > } > RTC_LOG(INFO) << " Received candidate :" << message; >- return; > } > } > >@@ -331,8 +333,8 @@ void Conductor::OnMessageSent(int err) { > } > > void Conductor::OnServerConnectionFailure() { >- main_wnd_->MessageBox("Error", ("Failed to connect to " + server_).c_str(), >- true); >+ main_wnd_->MessageBox("Error", ("Failed to connect to " + server_).c_str(), >+ true); > } > > // >@@ -356,14 +358,15 @@ void Conductor::ConnectToPeer(int peer_id) { > RTC_DCHECK(peer_id != -1); > > if (peer_connection_.get()) { >- main_wnd_->MessageBox("Error", >- "We only support connecting to one peer at a time", true); >+ main_wnd_->MessageBox( >+ "Error", "We only support connecting to one peer at a time", true); > return; > } > > if (InitializePeerConnection()) { > peer_id_ = peer_id; >- peer_connection_->CreateOffer(this, NULL); >+ peer_connection_->CreateOffer( >+ this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); > } else { > main_wnd_->MessageBox("Error", "Failed to initialize PeerConnection", true); > } >@@ -399,33 +402,39 @@ std::unique_ptr<cricket::VideoCapturer> Conductor::OpenVideoCaptureDevice() { > return capturer; > } > >-void Conductor::AddStreams() { >- if (active_streams_.find(kStreamLabel) != active_streams_.end()) >- return; // Already added. >+void Conductor::AddTracks() { >+ if (!peer_connection_->GetSenders().empty()) { >+ return; // Already added tracks. >+ } > > rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( > peer_connection_factory_->CreateAudioTrack( >- kAudioLabel, peer_connection_factory_->CreateAudioSource(NULL))); >- >- rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track( >- peer_connection_factory_->CreateVideoTrack( >- kVideoLabel, >- peer_connection_factory_->CreateVideoSource(OpenVideoCaptureDevice(), >- NULL))); >- main_wnd_->StartLocalRenderer(video_track); >- >- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = >- peer_connection_factory_->CreateLocalMediaStream(kStreamLabel); >- >- stream->AddTrack(audio_track); >- stream->AddTrack(video_track); >- if (!peer_connection_->AddStream(stream)) { >- RTC_LOG(LS_ERROR) << "Adding stream to PeerConnection failed"; >+ kAudioLabel, peer_connection_factory_->CreateAudioSource( >+ cricket::AudioOptions()))); >+ auto result_or_error = peer_connection_->AddTrack(audio_track, {kStreamId}); >+ if (!result_or_error.ok()) { >+ RTC_LOG(LS_ERROR) << "Failed to add audio track to PeerConnection: " >+ << result_or_error.error().message(); > } >- typedef std::pair<std::string, >- rtc::scoped_refptr<webrtc::MediaStreamInterface> > >- MediaStreamPair; >- active_streams_.insert(MediaStreamPair(stream->label(), stream)); >+ >+ std::unique_ptr<cricket::VideoCapturer> video_device = >+ OpenVideoCaptureDevice(); >+ if (video_device) { >+ rtc::scoped_refptr<webrtc::VideoTrackInterface> video_track_( >+ peer_connection_factory_->CreateVideoTrack( >+ kVideoLabel, peer_connection_factory_->CreateVideoSource( >+ std::move(video_device), nullptr))); >+ main_wnd_->StartLocalRenderer(video_track_); >+ >+ result_or_error = peer_connection_->AddTrack(video_track_, {kStreamId}); >+ if (!result_or_error.ok()) { >+ RTC_LOG(LS_ERROR) << "Failed to add video track to PeerConnection: " >+ << result_or_error.error().message(); >+ } >+ } else { >+ RTC_LOG(LS_ERROR) << "OpenVideoCaptureDevice failed"; >+ } >+ > main_wnd_->SwitchToStreamingUI(); > } > >@@ -446,8 +455,6 @@ void Conductor::UIThreadCallback(int msg_id, void* data) { > RTC_LOG(INFO) << "PEER_CONNECTION_CLOSED"; > DeletePeerConnection(); > >- RTC_DCHECK(active_streams_.empty()); >- > if (main_wnd_->IsWindow()) { > if (client_->is_connected()) { > main_wnd_->SwitchToPeerList(client_->peers()); >@@ -486,26 +493,20 @@ void Conductor::UIThreadCallback(int msg_id, void* data) { > break; > } > >- case NEW_STREAM_ADDED: { >- webrtc::MediaStreamInterface* stream = >- reinterpret_cast<webrtc::MediaStreamInterface*>( >- data); >- webrtc::VideoTrackVector tracks = stream->GetVideoTracks(); >- // Only render the first track. >- if (!tracks.empty()) { >- webrtc::VideoTrackInterface* track = tracks[0]; >- main_wnd_->StartRemoteRenderer(track); >+ case NEW_TRACK_ADDED: { >+ auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data); >+ if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { >+ auto* video_track = static_cast<webrtc::VideoTrackInterface*>(track); >+ main_wnd_->StartRemoteRenderer(video_track); > } >- stream->Release(); >+ track->Release(); > break; > } > >- case STREAM_REMOVED: { >- // Remote peer stopped sending a stream. >- webrtc::MediaStreamInterface* stream = >- reinterpret_cast<webrtc::MediaStreamInterface*>( >- data); >- stream->Release(); >+ case TRACK_REMOVED: { >+ // Remote peer stopped sending a track. >+ auto* track = reinterpret_cast<webrtc::MediaStreamTrackInterface*>(data); >+ track->Release(); > break; > } > >@@ -525,22 +526,24 @@ void Conductor::OnSuccess(webrtc::SessionDescriptionInterface* desc) { > // For loopback test. To save some connecting delay. > if (loopback_) { > // Replace message type from "offer" to "answer" >- webrtc::SessionDescriptionInterface* session_description( >- webrtc::CreateSessionDescription("answer", sdp, nullptr)); >+ std::unique_ptr<webrtc::SessionDescriptionInterface> session_description = >+ webrtc::CreateSessionDescription(webrtc::SdpType::kAnswer, sdp); > peer_connection_->SetRemoteDescription( >- DummySetSessionDescriptionObserver::Create(), session_description); >+ DummySetSessionDescriptionObserver::Create(), >+ session_description.release()); > return; > } > > Json::StyledWriter writer; > Json::Value jmessage; >- jmessage[kSessionDescriptionTypeName] = desc->type(); >+ jmessage[kSessionDescriptionTypeName] = >+ webrtc::SdpTypeToString(desc->GetType()); > jmessage[kSessionDescriptionSdpName] = sdp; > SendMessage(writer.write(jmessage)); > } > >-void Conductor::OnFailure(const std::string& error) { >- RTC_LOG(LERROR) << error; >+void Conductor::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LERROR) << ToString(error.type()) << ": " << error.message(); > } > > void Conductor::SendMessage(const std::string& json_object) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.h >index ebd2b6baed9..a038743915b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/conductor.h >@@ -14,8 +14,8 @@ > #include <deque> > #include <map> > #include <memory> >-#include <set> > #include <string> >+#include <vector> > > #include "api/mediastreaminterface.h" > #include "api/peerconnectioninterface.h" >@@ -30,25 +30,24 @@ namespace cricket { > class VideoRenderer; > } // namespace cricket > >-class Conductor >- : public webrtc::PeerConnectionObserver, >- public webrtc::CreateSessionDescriptionObserver, >- public PeerConnectionClientObserver, >- public MainWndCallback { >+class Conductor : public webrtc::PeerConnectionObserver, >+ public webrtc::CreateSessionDescriptionObserver, >+ public PeerConnectionClientObserver, >+ public MainWndCallback { > public: > enum CallbackID { > MEDIA_CHANNELS_INITIALIZED = 1, > PEER_CONNECTION_CLOSED, > SEND_MESSAGE_TO_PEER, >- NEW_STREAM_ADDED, >- STREAM_REMOVED, >+ NEW_TRACK_ADDED, >+ TRACK_REMOVED, > }; > > Conductor(PeerConnectionClient* client, MainWindow* main_wnd); > > bool connection_active() const; > >- virtual void Close(); >+ void Close() override; > > protected: > ~Conductor(); >@@ -57,7 +56,7 @@ class Conductor > bool CreatePeerConnection(bool dtls); > void DeletePeerConnection(); > void EnsureStreamingUI(); >- void AddStreams(); >+ void AddTracks(); > std::unique_ptr<cricket::VideoCapturer> OpenVideoCaptureDevice(); > > // >@@ -66,10 +65,12 @@ class Conductor > > void OnSignalingChange( > webrtc::PeerConnectionInterface::SignalingState new_state) override{}; >- void OnAddStream( >- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override; >- void OnRemoveStream( >- rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override; >+ void OnAddTrack( >+ rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, >+ const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& >+ streams) override; >+ void OnRemoveTrack( >+ rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override; > void OnDataChannel( > rtc::scoped_refptr<webrtc::DataChannelInterface> channel) override {} > void OnRenegotiationNeeded() override {} >@@ -114,7 +115,7 @@ class Conductor > > // CreateSessionDescriptionObserver implementation. > void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; >- void OnFailure(const std::string& error) override; >+ void OnFailure(webrtc::RTCError error) override; > > protected: > // Send a message to the remote peer. >@@ -128,8 +129,6 @@ class Conductor > PeerConnectionClient* client_; > MainWindow* main_wnd_; > std::deque<std::string*> pending_messages_; >- std::map<std::string, rtc::scoped_refptr<webrtc::MediaStreamInterface> > >- active_streams_; > std::string server_; > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.cc >index 51732ad4848..aeb5cb488d2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.cc >@@ -23,7 +23,7 @@ > > const char kAudioLabel[] = "audio_label"; > const char kVideoLabel[] = "video_label"; >-const char kStreamLabel[] = "stream_label"; >+const char kStreamId[] = "stream_id"; > const uint16_t kDefaultServerPort = 8888; > > std::string GetEnvVarOrDefault(const char* env_var_name, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.h >index c46011e3eab..30936fd9d4a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/defaults.h >@@ -17,7 +17,7 @@ > > extern const char kAudioLabel[]; > extern const char kVideoLabel[]; >-extern const char kStreamLabel[]; >+extern const char kStreamId[]; > extern const uint16_t kDefaultServerPort; > > std::string GetEnvVarOrDefault(const char* env_var_name, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/flagdefs.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/flagdefs.h >index cc66c6f34a6..564e0e95f90 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/flagdefs.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/flagdefs.h >@@ -20,13 +20,19 @@ extern const uint16_t kDefaultServerPort; // From defaults.[h|cc] > // for each platform. > > DEFINE_bool(help, false, "Prints this message"); >-DEFINE_bool(autoconnect, false, "Connect to the server without user " >- "intervention."); >+DEFINE_bool(autoconnect, >+ false, >+ "Connect to the server without user " >+ "intervention."); > DEFINE_string(server, "localhost", "The server to connect to."); >-DEFINE_int(port, kDefaultServerPort, >+DEFINE_int(port, >+ kDefaultServerPort, > "The port on which the server is listening."); >-DEFINE_bool(autocall, false, "Call the first available other client on " >- "the server without user intervention. Note: this flag should only be set " >- "to true on one of the two clients."); >+DEFINE_bool( >+ autocall, >+ false, >+ "Call the first available other client on " >+ "the server without user intervention. Note: this flag should only be set " >+ "to true on one of the two clients."); > > #endif // EXAMPLES_PEERCONNECTION_CLIENT_FLAGDEFS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main.cc >index c074d7c2387..50179c4ba55 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main.cc >@@ -32,21 +32,21 @@ class CustomSocketServer : public rtc::PhysicalSocketServer { > void set_conductor(Conductor* conductor) { conductor_ = conductor; } > > // Override so that we can also pump the GTK message loop. >- virtual bool Wait(int cms, bool process_io) { >+ bool Wait(int cms, bool process_io) override { > // Pump GTK events. > // TODO(henrike): We really should move either the socket server or UI to a > // different thread. Alternatively we could look at merging the two loops > // by implementing a dispatcher for the socket server and/or use > // g_main_context_set_poll_func. >- while (gtk_events_pending()) >- gtk_main_iteration(); >+ while (gtk_events_pending()) >+ gtk_main_iteration(); > > if (!wnd_->IsWindow() && !conductor_->connection_active() && > client_ != NULL && !client_->is_connected()) { > message_queue_->Quit(); > } >- return rtc::PhysicalSocketServer::Wait(0/*cms == -1 ? 1 : cms*/, >- process_io); >+ return rtc::PhysicalSocketServer::Wait(0 /*cms == -1 ? 1 : cms*/, >+ process_io); > } > > protected: >@@ -58,15 +58,15 @@ class CustomSocketServer : public rtc::PhysicalSocketServer { > > int main(int argc, char* argv[]) { > gtk_init(&argc, &argv); >- // g_type_init API is deprecated (and does nothing) since glib 2.35.0, see: >- // https://mail.gnome.org/archives/commits-list/2012-November/msg07809.html >+// g_type_init API is deprecated (and does nothing) since glib 2.35.0, see: >+// https://mail.gnome.org/archives/commits-list/2012-November/msg07809.html > #if !GLIB_CHECK_VERSION(2, 35, 0) >- g_type_init(); >+ g_type_init(); > #endif >- // g_thread_init API is deprecated since glib 2.31.0, see release note: >- // http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html >+// g_thread_init API is deprecated since glib 2.31.0, see release note: >+// http://mail.gnome.org/archives/gnome-announce-list/2011-October/msg00041.html > #if !GLIB_CHECK_VERSION(2, 31, 0) >- g_thread_init(NULL); >+ g_thread_init(NULL); > #endif > > rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.cc >index f7863d9461c..52b0d88523c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.cc >@@ -14,12 +14,12 @@ > #include <gtk/gtk.h> > #include <stddef.h> > >-#include "libyuv/convert_from.h" > #include "api/video/i420_buffer.h" > #include "examples/peerconnection/client/defaults.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" > #include "rtc_base/stringutils.h" >+#include "third_party/libyuv/include/libyuv/convert_from.h" > > using rtc::sprintfn; > >@@ -30,7 +30,8 @@ namespace { > // GtkMainWnd instance. > // > >-gboolean OnDestroyedCallback(GtkWidget* widget, GdkEvent* event, >+gboolean OnDestroyedCallback(GtkWidget* widget, >+ GdkEvent* event, > gpointer data) { > reinterpret_cast<GtkMainWnd*>(data)->OnDestroyed(widget, event); > return FALSE; >@@ -45,14 +46,17 @@ gboolean SimulateButtonClick(gpointer button) { > return false; > } > >-gboolean OnKeyPressCallback(GtkWidget* widget, GdkEventKey* key, >+gboolean OnKeyPressCallback(GtkWidget* widget, >+ GdkEventKey* key, > gpointer data) { > reinterpret_cast<GtkMainWnd*>(data)->OnKeyPress(widget, key); > return false; > } > >-void OnRowActivatedCallback(GtkTreeView* tree_view, GtkTreePath* path, >- GtkTreeViewColumn* column, gpointer data) { >+void OnRowActivatedCallback(GtkTreeView* tree_view, >+ GtkTreePath* path, >+ GtkTreeViewColumn* column, >+ gpointer data) { > reinterpret_cast<GtkMainWnd*>(data)->OnRowActivated(tree_view, path, column); > } > >@@ -90,8 +94,8 @@ void InitializeList(GtkWidget* list) { > > // Adds an entry to a tree view. > void AddToList(GtkWidget* list, const gchar* str, int value) { >- GtkListStore* store = GTK_LIST_STORE( >- gtk_tree_view_get_model(GTK_TREE_VIEW(list))); >+ GtkListStore* store = >+ GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list))); > > GtkTreeIter iter; > gtk_list_store_append(store, &iter); >@@ -131,11 +135,20 @@ gboolean Draw(GtkWidget* widget, cairo_t* cr, gpointer data) { > // GtkMainWnd implementation. > // > >-GtkMainWnd::GtkMainWnd(const char* server, int port, bool autoconnect, >+GtkMainWnd::GtkMainWnd(const char* server, >+ int port, >+ bool autoconnect, > bool autocall) >- : window_(NULL), draw_area_(NULL), vbox_(NULL), server_edit_(NULL), >- port_edit_(NULL), peer_list_(NULL), callback_(NULL), >- server_(server), autoconnect_(autoconnect), autocall_(autocall) { >+ : window_(NULL), >+ draw_area_(NULL), >+ vbox_(NULL), >+ server_edit_(NULL), >+ port_edit_(NULL), >+ peer_list_(NULL), >+ callback_(NULL), >+ server_(server), >+ autoconnect_(autoconnect), >+ autocall_(autocall) { > char buffer[10]; > sprintfn(buffer, sizeof(buffer), "%i", port); > port_ = buffer; >@@ -153,12 +166,13 @@ bool GtkMainWnd::IsWindow() { > return window_ != NULL && GTK_IS_WINDOW(window_); > } > >-void GtkMainWnd::MessageBox(const char* caption, const char* text, >+void GtkMainWnd::MessageBox(const char* caption, >+ const char* text, > bool is_error) { >- GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(window_), >- GTK_DIALOG_DESTROY_WITH_PARENT, >- is_error ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, >- GTK_BUTTONS_CLOSE, "%s", text); >+ GtkWidget* dialog = gtk_message_dialog_new( >+ GTK_WINDOW(window_), GTK_DIALOG_DESTROY_WITH_PARENT, >+ is_error ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s", >+ text); > gtk_window_set_title(GTK_WINDOW(dialog), caption); > gtk_dialog_run(GTK_DIALOG(dialog)); > gtk_widget_destroy(dialog); >@@ -174,7 +188,6 @@ MainWindow::UI GtkMainWnd::current_ui() { > return STREAMING; > } > >- > void GtkMainWnd::StartLocalRenderer(webrtc::VideoTrackInterface* local_video) { > local_renderer_.reset(new VideoRenderer(this, local_video)); > } >@@ -394,7 +407,8 @@ void GtkMainWnd::OnKeyPress(GtkWidget* widget, GdkEventKey* key) { > } > } > >-void GtkMainWnd::OnRowActivated(GtkTreeView* tree_view, GtkTreePath* path, >+void GtkMainWnd::OnRowActivated(GtkTreeView* tree_view, >+ GtkTreePath* path, > GtkTreeViewColumn* column) { > RTC_DCHECK(peer_list_ != NULL); > GtkTreeIter iter; >@@ -402,12 +416,12 @@ void GtkMainWnd::OnRowActivated(GtkTreeView* tree_view, GtkTreePath* path, > GtkTreeSelection* selection = > gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); > if (gtk_tree_selection_get_selected(selection, &model, &iter)) { >- char* text; >- int id = -1; >- gtk_tree_model_get(model, &iter, 0, &text, 1, &id, -1); >- if (id != -1) >- callback_->ConnectToPeer(id); >- g_free(text); >+ char* text; >+ int id = -1; >+ gtk_tree_model_get(model, &iter, 0, &text, 1, &id, -1); >+ if (id != -1) >+ callback_->ConnectToPeer(id); >+ g_free(text); > } > } > >@@ -519,8 +533,7 @@ void GtkMainWnd::VideoRenderer::SetSize(int width, int height) { > gdk_threads_leave(); > } > >-void GtkMainWnd::VideoRenderer::OnFrame( >- const webrtc::VideoFrame& video_frame) { >+void GtkMainWnd::VideoRenderer::OnFrame(const webrtc::VideoFrame& video_frame) { > gdk_threads_enter(); > > rtc::scoped_refptr<webrtc::I420BufferInterface> buffer( >@@ -536,11 +549,10 @@ void GtkMainWnd::VideoRenderer::OnFrame( > // This was supposed to be a call to libyuv::I420ToRGBA but it was resulting > // in a reddish video output (see https://bugs.webrtc.org/6857) because it > // was producing an unexpected byte order (ABGR, byte swapped). >- libyuv::I420ToABGR(buffer->DataY(), buffer->StrideY(), >- buffer->DataU(), buffer->StrideU(), >- buffer->DataV(), buffer->StrideV(), >- image_.get(), width_ * 4, >- buffer->width(), buffer->height()); >+ libyuv::I420ToABGR(buffer->DataY(), buffer->StrideY(), buffer->DataU(), >+ buffer->StrideU(), buffer->DataV(), buffer->StrideV(), >+ image_.get(), width_ * 4, buffer->width(), >+ buffer->height()); > > gdk_threads_leave(); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.h >index fdeee4ba7b3..a2edb747577 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/linux/main_wnd.h >@@ -39,8 +39,7 @@ class GtkMainWnd : public MainWindow { > virtual void SwitchToConnectUI(); > virtual void SwitchToPeerList(const Peers& peers); > virtual void SwitchToStreamingUI(); >- virtual void MessageBox(const char* caption, const char* text, >- bool is_error); >+ virtual void MessageBox(const char* caption, const char* text, bool is_error); > virtual MainWindow::UI current_ui(); > virtual void StartLocalRenderer(webrtc::VideoTrackInterface* local_video); > virtual void StopLocalRenderer(); >@@ -67,7 +66,8 @@ class GtkMainWnd : public MainWindow { > > // Callback when the user double clicks a peer in order to initiate a > // connection. >- void OnRowActivated(GtkTreeView* tree_view, GtkTreePath* path, >+ void OnRowActivated(GtkTreeView* tree_view, >+ GtkTreePath* path, > GtkTreeViewColumn* column); > > void OnRedraw(); >@@ -86,13 +86,9 @@ class GtkMainWnd : public MainWindow { > > const uint8_t* image() const { return image_.get(); } > >- int width() const { >- return width_; >- } >+ int width() const { return width_; } > >- int height() const { >- return height_; >- } >+ int height() const { return height_; } > > protected: > void SetSize(int width, int height); >@@ -104,9 +100,9 @@ class GtkMainWnd : public MainWindow { > }; > > protected: >- GtkWidget* window_; // Our main window. >+ GtkWidget* window_; // Our main window. > GtkWidget* draw_area_; // The drawing surface for rendering video streams. >- GtkWidget* vbox_; // Container for the Connect UI. >+ GtkWidget* vbox_; // Container for the Connect UI. > GtkWidget* server_edit_; > GtkWidget* port_edit_; > GtkWidget* peer_list_; // The list of peers. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main.cc >index bcf86f185ee..ee70da620f2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main.cc >@@ -17,8 +17,10 @@ > #include "rtc_base/win32socketinit.h" > #include "rtc_base/win32socketserver.h" > >-int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance, >- wchar_t* cmd_line, int cmd_show) { >+int PASCAL wWinMain(HINSTANCE instance, >+ HINSTANCE prev_instance, >+ wchar_t* cmd_line, >+ int cmd_show) { > rtc::EnsureWinsockInit(); > rtc::Win32SocketServer w32_ss; > rtc::Win32Thread w32_thread(&w32_ss); >@@ -26,7 +28,7 @@ int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance, > > rtc::WindowsCommandLineArguments win_args; > int argc = win_args.argc(); >- char **argv = win_args.argv(); >+ char** argv = win_args.argv(); > > rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); > if (FLAG_help) { >@@ -50,7 +52,7 @@ int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance, > rtc::InitializeSSL(); > PeerConnectionClient client; > rtc::scoped_refptr<Conductor> conductor( >- new rtc::RefCountedObject<Conductor>(&client, &wnd)); >+ new rtc::RefCountedObject<Conductor>(&client, &wnd)); > > // Main loop. > MSG msg; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.cc >index a33391d5ed1..3ad248843a8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.cc >@@ -12,12 +12,13 @@ > > #include <math.h> > >-#include "libyuv/convert_argb.h" > #include "api/video/i420_buffer.h" > #include "examples/peerconnection/client/defaults.h" > #include "rtc_base/arraysize.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" >+#include "rtc_base/stringutils.h" >+#include "third_party/libyuv/include/libyuv/convert_argb.h" > > ATOM MainWnd::wnd_class_ = 0; > const wchar_t MainWnd::kClassName[] = L"WebRTC_MainWnd"; >@@ -30,8 +31,10 @@ const char kConnecting[] = "Connecting... "; > const char kNoVideoStreams[] = "(no video streams either way)"; > const char kNoIncomingStream[] = "(no incoming video)"; > >-void CalculateWindowSizeForText(HWND wnd, const wchar_t* text, >- size_t* width, size_t* height) { >+void CalculateWindowSizeForText(HWND wnd, >+ const wchar_t* text, >+ size_t* width, >+ size_t* height) { > HDC dc = ::GetDC(wnd); > RECT text_rc = {0}; > ::DrawText(dc, text, -1, &text_rc, DT_CALCRECT | DT_SINGLELINE); >@@ -41,11 +44,9 @@ void CalculateWindowSizeForText(HWND wnd, const wchar_t* text, > ::GetWindowRect(wnd, &window); > > *width = text_rc.right - text_rc.left; >- *width += (window.right - window.left) - >- (client.right - client.left); >+ *width += (window.right - window.left) - (client.right - client.left); > *height = text_rc.bottom - text_rc.top; >- *height += (window.bottom - window.top) - >- (client.bottom - client.top); >+ *height += (window.bottom - window.top) - (client.bottom - client.top); > } > > HFONT GetDefaultFont() { >@@ -61,18 +62,30 @@ std::string GetWindowText(HWND wnd) { > > void AddListBoxItem(HWND listbox, const std::string& str, LPARAM item_data) { > LRESULT index = ::SendMessageA(listbox, LB_ADDSTRING, 0, >- reinterpret_cast<LPARAM>(str.c_str())); >+ reinterpret_cast<LPARAM>(str.c_str())); > ::SendMessageA(listbox, LB_SETITEMDATA, index, item_data); > } > > } // namespace > >-MainWnd::MainWnd(const char* server, int port, bool auto_connect, >+MainWnd::MainWnd(const char* server, >+ int port, >+ bool auto_connect, > bool auto_call) >- : ui_(CONNECT_TO_SERVER), wnd_(NULL), edit1_(NULL), edit2_(NULL), >- label1_(NULL), label2_(NULL), button_(NULL), listbox_(NULL), >- destroyed_(false), callback_(NULL), nested_msg_(NULL), >- server_(server), auto_connect_(auto_connect), auto_call_(auto_call) { >+ : ui_(CONNECT_TO_SERVER), >+ wnd_(NULL), >+ edit1_(NULL), >+ edit2_(NULL), >+ label1_(NULL), >+ label2_(NULL), >+ button_(NULL), >+ listbox_(NULL), >+ destroyed_(false), >+ nested_msg_(NULL), >+ callback_(NULL), >+ server_(server), >+ auto_connect_(auto_connect), >+ auto_call_(auto_call) { > char buffer[10] = {0}; > sprintfn(buffer, sizeof(buffer), "%i", port); > port_ = buffer; >@@ -88,10 +101,11 @@ bool MainWnd::Create() { > return false; > > ui_thread_id_ = ::GetCurrentThreadId(); >- wnd_ = ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC", >- WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, >- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, >- NULL, NULL, GetModuleHandle(NULL), this); >+ wnd_ = >+ ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC", >+ WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN, >+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, >+ CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), this); > > ::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()), > TRUE); >@@ -175,10 +189,10 @@ void MainWnd::SwitchToPeerList(const Peers& peers) { > LRESULT count = ::SendMessage(listbox_, LB_GETCOUNT, 0, 0); > if (count != LB_ERR) { > // Select the last item in the list >- LRESULT selection = ::SendMessage(listbox_, LB_SETCURSEL , count - 1, 0); >+ LRESULT selection = ::SendMessage(listbox_, LB_SETCURSEL, count - 1, 0); > if (selection != LB_ERR) >- ::PostMessage(wnd_, WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(listbox_), >- LBN_DBLCLK), >+ ::PostMessage(wnd_, WM_COMMAND, >+ MAKEWPARAM(GetDlgCtrlID(listbox_), LBN_DBLCLK), > reinterpret_cast<LPARAM>(listbox_)); > } > } >@@ -198,7 +212,6 @@ void MainWnd::MessageBox(const char* caption, const char* text, bool is_error) { > ::MessageBoxA(handle(), text, caption, flags); > } > >- > void MainWnd::StartLocalRenderer(webrtc::VideoTrackInterface* local_video) { > local_renderer_.reset(new VideoRenderer(handle(), 1, 1, local_video)); > } >@@ -217,7 +230,8 @@ void MainWnd::StopRemoteRenderer() { > > void MainWnd::QueueUIThreadCallback(int msg_id, void* data) { > ::PostThreadMessage(ui_thread_id_, UI_THREAD_CALLBACK, >- static_cast<WPARAM>(msg_id), reinterpret_cast<LPARAM>(data)); >+ static_cast<WPARAM>(msg_id), >+ reinterpret_cast<LPARAM>(data)); > } > > void MainWnd::OnPaint() { >@@ -243,8 +257,8 @@ void MainWnd::OnPaint() { > ::SetStretchBltMode(dc_mem, HALFTONE); > > // Set the map mode so that the ratio will be maintained for us. >- HDC all_dc[] = { ps.hdc, dc_mem }; >- for (int i = 0; i < arraysize(all_dc); ++i) { >+ HDC all_dc[] = {ps.hdc, dc_mem}; >+ for (size_t i = 0; i < arraysize(all_dc); ++i) { > SetMapMode(all_dc[i], MM_ISOTROPIC); > SetWindowExtEx(all_dc[i], width, height, NULL); > SetViewportExtEx(all_dc[i], rc.right, rc.bottom, NULL); >@@ -253,35 +267,34 @@ void MainWnd::OnPaint() { > HBITMAP bmp_mem = ::CreateCompatibleBitmap(ps.hdc, rc.right, rc.bottom); > HGDIOBJ bmp_old = ::SelectObject(dc_mem, bmp_mem); > >- POINT logical_area = { rc.right, rc.bottom }; >+ POINT logical_area = {rc.right, rc.bottom}; > DPtoLP(ps.hdc, &logical_area, 1); > > HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); >- RECT logical_rect = {0, 0, logical_area.x, logical_area.y }; >+ RECT logical_rect = {0, 0, logical_area.x, logical_area.y}; > ::FillRect(dc_mem, &logical_rect, brush); > ::DeleteObject(brush); > > int x = (logical_area.x / 2) - (width / 2); > int y = (logical_area.y / 2) - (height / 2); > >- StretchDIBits(dc_mem, x, y, width, height, >- 0, 0, width, height, image, &bmi, DIB_RGB_COLORS, SRCCOPY); >+ StretchDIBits(dc_mem, x, y, width, height, 0, 0, width, height, image, >+ &bmi, DIB_RGB_COLORS, SRCCOPY); > > if ((rc.right - rc.left) > 200 && (rc.bottom - rc.top) > 200) { > const BITMAPINFO& bmi = local_renderer->bmi(); > image = local_renderer->image(); > int thumb_width = bmi.bmiHeader.biWidth / 4; > int thumb_height = abs(bmi.bmiHeader.biHeight) / 4; >- StretchDIBits(dc_mem, >- logical_area.x - thumb_width - 10, >- logical_area.y - thumb_height - 10, >- thumb_width, thumb_height, >- 0, 0, bmi.bmiHeader.biWidth, -bmi.bmiHeader.biHeight, >- image, &bmi, DIB_RGB_COLORS, SRCCOPY); >+ StretchDIBits(dc_mem, logical_area.x - thumb_width - 10, >+ logical_area.y - thumb_height - 10, thumb_width, >+ thumb_height, 0, 0, bmi.bmiHeader.biWidth, >+ -bmi.bmiHeader.biHeight, image, &bmi, DIB_RGB_COLORS, >+ SRCCOPY); > } > >- BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y, >- dc_mem, 0, 0, SRCCOPY); >+ BitBlt(ps.hdc, 0, 0, logical_area.x, logical_area.y, dc_mem, 0, 0, >+ SRCCOPY); > > // Cleanup. > ::SelectObject(dc_mem, bmp_old); >@@ -304,7 +317,7 @@ void MainWnd::OnPaint() { > text += kNoIncomingStream; > } > ::DrawTextA(ps.hdc, text.c_str(), -1, &rc, >- DT_SINGLELINE | DT_CENTER | DT_VCENTER); >+ DT_SINGLELINE | DT_CENTER | DT_VCENTER); > ::SelectObject(ps.hdc, old_font); > } > } else { >@@ -392,8 +405,8 @@ bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) { > > // static > LRESULT CALLBACK MainWnd::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { >- MainWnd* me = reinterpret_cast<MainWnd*>( >- ::GetWindowLongPtr(hwnd, GWLP_USERDATA)); >+ MainWnd* me = >+ reinterpret_cast<MainWnd*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA)); > if (!me && WM_CREATE == msg) { > CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lp); > me = reinterpret_cast<MainWnd*>(cs->lpCreateParams); >@@ -432,7 +445,7 @@ bool MainWnd::RegisterWindowClass() { > if (wnd_class_) > return true; > >- WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; >+ WNDCLASSEX wcex = {sizeof(WNDCLASSEX)}; > wcex.style = CS_DBLCLKS; > wcex.hInstance = GetModuleHandle(NULL); > wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1); >@@ -444,17 +457,18 @@ bool MainWnd::RegisterWindowClass() { > return wnd_class_ != 0; > } > >-void MainWnd::CreateChildWindow(HWND* wnd, MainWnd::ChildWindowID id, >- const wchar_t* class_name, DWORD control_style, >+void MainWnd::CreateChildWindow(HWND* wnd, >+ MainWnd::ChildWindowID id, >+ const wchar_t* class_name, >+ DWORD control_style, > DWORD ex_style) { > if (::IsWindow(*wnd)) > return; > > // Child windows are invisible at first, and shown after being resized. > DWORD style = WS_CHILD | control_style; >- *wnd = ::CreateWindowEx(ex_style, class_name, L"", style, >- 100, 100, 100, 100, wnd_, >- reinterpret_cast<HMENU>(id), >+ *wnd = ::CreateWindowEx(ex_style, class_name, L"", style, 100, 100, 100, 100, >+ wnd_, reinterpret_cast<HMENU>(id), > GetModuleHandle(NULL), NULL); > RTC_DCHECK(::IsWindow(*wnd) != FALSE); > ::SendMessage(*wnd, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()), >@@ -485,11 +499,9 @@ void MainWnd::LayoutConnectUI(bool show) { > size_t width; > size_t height; > } windows[] = { >- { label1_, L"Server" }, >- { edit1_, L"XXXyyyYYYgggXXXyyyYYYggg" }, >- { label2_, L":" }, >- { edit2_, L"XyXyX" }, >- { button_, L"Connect" }, >+ {label1_, L"Server"}, {edit1_, L"XXXyyyYYYgggXXXyyyYYYggg"}, >+ {label2_, L":"}, {edit2_, L"XyXyX"}, >+ {button_, L"Connect"}, > }; > > if (show) { >@@ -510,8 +522,7 @@ void MainWnd::LayoutConnectUI(bool show) { > size_t top = y - (windows[i].height / 2); > ::MoveWindow(windows[i].wnd, static_cast<int>(x), static_cast<int>(top), > static_cast<int>(windows[i].width), >- static_cast<int>(windows[i].height), >- TRUE); >+ static_cast<int>(windows[i].height), TRUE); > x += kSeparator + windows[i].width; > if (windows[i].text[0] != 'X') > ::SetWindowText(windows[i].wnd, windows[i].text); >@@ -565,7 +576,9 @@ void MainWnd::HandleTabbing() { > // > > MainWnd::VideoRenderer::VideoRenderer( >- HWND wnd, int width, int height, >+ HWND wnd, >+ int width, >+ int height, > webrtc::VideoTrackInterface* track_to_render) > : wnd_(wnd), rendered_track_(track_to_render) { > ::InitializeCriticalSection(&buffer_lock_); >@@ -576,8 +589,8 @@ MainWnd::VideoRenderer::VideoRenderer( > bmi_.bmiHeader.biCompression = BI_RGB; > bmi_.bmiHeader.biWidth = width; > bmi_.bmiHeader.biHeight = -height; >- bmi_.bmiHeader.biSizeImage = width * height * >- (bmi_.bmiHeader.biBitCount >> 3); >+ bmi_.bmiHeader.biSizeImage = >+ width * height * (bmi_.bmiHeader.biBitCount >> 3); > rendered_track_->AddOrUpdateSink(this, rtc::VideoSinkWants()); > } > >@@ -595,14 +608,12 @@ void MainWnd::VideoRenderer::SetSize(int width, int height) { > > bmi_.bmiHeader.biWidth = width; > bmi_.bmiHeader.biHeight = -height; >- bmi_.bmiHeader.biSizeImage = width * height * >- (bmi_.bmiHeader.biBitCount >> 3); >+ bmi_.bmiHeader.biSizeImage = >+ width * height * (bmi_.bmiHeader.biBitCount >> 3); > image_.reset(new uint8_t[bmi_.bmiHeader.biSizeImage]); > } > >-void MainWnd::VideoRenderer::OnFrame( >- const webrtc::VideoFrame& video_frame) { >- >+void MainWnd::VideoRenderer::OnFrame(const webrtc::VideoFrame& video_frame) { > { > AutoLock<VideoRenderer> lock(this); > >@@ -615,12 +626,10 @@ void MainWnd::VideoRenderer::OnFrame( > SetSize(buffer->width(), buffer->height()); > > RTC_DCHECK(image_.get() != NULL); >- libyuv::I420ToARGB(buffer->DataY(), buffer->StrideY(), >- buffer->DataU(), buffer->StrideU(), >- buffer->DataV(), buffer->StrideV(), >+ libyuv::I420ToARGB(buffer->DataY(), buffer->StrideY(), buffer->DataU(), >+ buffer->StrideU(), buffer->DataV(), buffer->StrideV(), > image_.get(), >- bmi_.bmiHeader.biWidth * >- bmi_.bmiHeader.biBitCount / 8, >+ bmi_.bmiHeader.biWidth * bmi_.bmiHeader.biBitCount / 8, > buffer->width(), buffer->height()); > } > InvalidateRect(wnd_, NULL, TRUE); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.h >index f3ed2f576cb..57002583ea4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/main_wnd.h >@@ -20,7 +20,9 @@ > #include "examples/peerconnection/client/peer_connection_client.h" > #include "media/base/mediachannel.h" > #include "media/base/videocommon.h" >+#if defined(WEBRTC_WIN) > #include "rtc_base/win32.h" >+#endif // WEBRTC_WIN > > class MainWndCallback { > public: >@@ -30,6 +32,7 @@ class MainWndCallback { > virtual void DisconnectFromCurrentPeer() = 0; > virtual void UIThreadCallback(int msg_id, void* data) = 0; > virtual void Close() = 0; >+ > protected: > virtual ~MainWndCallback() {} > }; >@@ -48,7 +51,8 @@ class MainWindow { > virtual void RegisterObserver(MainWndCallback* callback) = 0; > > virtual bool IsWindow() = 0; >- virtual void MessageBox(const char* caption, const char* text, >+ virtual void MessageBox(const char* caption, >+ const char* text, > bool is_error) = 0; > > virtual UI current_ui() = 0; >@@ -88,8 +92,7 @@ class MainWnd : public MainWindow { > virtual void SwitchToConnectUI(); > virtual void SwitchToPeerList(const Peers& peers); > virtual void SwitchToStreamingUI(); >- virtual void MessageBox(const char* caption, const char* text, >- bool is_error); >+ virtual void MessageBox(const char* caption, const char* text, bool is_error); > virtual UI current_ui() { return ui_; } > > virtual void StartLocalRenderer(webrtc::VideoTrackInterface* local_video); >@@ -103,17 +106,15 @@ class MainWnd : public MainWindow { > > class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> { > public: >- VideoRenderer(HWND wnd, int width, int height, >+ VideoRenderer(HWND wnd, >+ int width, >+ int height, > webrtc::VideoTrackInterface* track_to_render); > virtual ~VideoRenderer(); > >- void Lock() { >- ::EnterCriticalSection(&buffer_lock_); >- } >+ void Lock() { ::EnterCriticalSection(&buffer_lock_); } > >- void Unlock() { >- ::LeaveCriticalSection(&buffer_lock_); >- } >+ void Unlock() { ::LeaveCriticalSection(&buffer_lock_); } > > // VideoSinkInterface implementation > void OnFrame(const webrtc::VideoFrame& frame) override; >@@ -143,6 +144,7 @@ class MainWnd : public MainWindow { > public: > explicit AutoLock(T* obj) : obj_(obj) { obj_->Lock(); } > ~AutoLock() { obj_->Unlock(); } >+ > protected: > T* obj_; > }; >@@ -166,8 +168,11 @@ class MainWnd : public MainWindow { > static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp); > static bool RegisterWindowClass(); > >- void CreateChildWindow(HWND* wnd, ChildWindowID id, const wchar_t* class_name, >- DWORD control_style, DWORD ex_style); >+ void CreateChildWindow(HWND* wnd, >+ ChildWindowID id, >+ const wchar_t* class_name, >+ DWORD control_style, >+ DWORD ex_style); > void CreateChildWindows(); > > void LayoutConnectUI(bool show); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.cc >index 40dfec55fe1..bb79d167911 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.cc >@@ -46,30 +46,23 @@ rtc::AsyncSocket* CreateClientSocket(int family) { > } // namespace > > PeerConnectionClient::PeerConnectionClient() >- : callback_(NULL), >- resolver_(NULL), >- state_(NOT_CONNECTED), >- my_id_(-1) { >-} >+ : callback_(NULL), resolver_(NULL), state_(NOT_CONNECTED), my_id_(-1) {} > >-PeerConnectionClient::~PeerConnectionClient() { >-} >+PeerConnectionClient::~PeerConnectionClient() {} > > void PeerConnectionClient::InitSocketSignals() { > RTC_DCHECK(control_socket_.get() != NULL); > RTC_DCHECK(hanging_get_.get() != NULL); > control_socket_->SignalCloseEvent.connect(this, >- &PeerConnectionClient::OnClose); >- hanging_get_->SignalCloseEvent.connect(this, >- &PeerConnectionClient::OnClose); >+ &PeerConnectionClient::OnClose); >+ hanging_get_->SignalCloseEvent.connect(this, &PeerConnectionClient::OnClose); > control_socket_->SignalConnectEvent.connect(this, >- &PeerConnectionClient::OnConnect); >- hanging_get_->SignalConnectEvent.connect(this, >- &PeerConnectionClient::OnHangingGetConnect); >- control_socket_->SignalReadEvent.connect(this, >- &PeerConnectionClient::OnRead); >- hanging_get_->SignalReadEvent.connect(this, >- &PeerConnectionClient::OnHangingGetRead); >+ &PeerConnectionClient::OnConnect); >+ hanging_get_->SignalConnectEvent.connect( >+ this, &PeerConnectionClient::OnHangingGetConnect); >+ control_socket_->SignalReadEvent.connect(this, &PeerConnectionClient::OnRead); >+ hanging_get_->SignalReadEvent.connect( >+ this, &PeerConnectionClient::OnHangingGetRead); > } > > int PeerConnectionClient::id() const { >@@ -90,7 +83,8 @@ void PeerConnectionClient::RegisterObserver( > callback_ = callback; > } > >-void PeerConnectionClient::Connect(const std::string& server, int port, >+void PeerConnectionClient::Connect(const std::string& server, >+ int port, > const std::string& client_name) { > RTC_DCHECK(!server.empty()); > RTC_DCHECK(!client_name.empty()); >@@ -142,8 +136,8 @@ void PeerConnectionClient::DoConnect() { > hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family())); > InitSocketSignals(); > char buffer[1024]; >- sprintfn(buffer, sizeof(buffer), >- "GET /sign_in?%s HTTP/1.0\r\n\r\n", client_name_.c_str()); >+ sprintfn(buffer, sizeof(buffer), "GET /sign_in?%s HTTP/1.0\r\n\r\n", >+ client_name_.c_str()); > onconnect_data_ = buffer; > > bool ret = ConnectControlSocket(); >@@ -165,11 +159,11 @@ bool PeerConnectionClient::SendToPeer(int peer_id, const std::string& message) { > > char headers[1024]; > sprintfn(headers, sizeof(headers), >- "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n" >- "Content-Length: %i\r\n" >- "Content-Type: text/plain\r\n" >- "\r\n", >- my_id_, peer_id, message.length()); >+ "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n" >+ "Content-Length: %i\r\n" >+ "Content-Type: text/plain\r\n" >+ "\r\n", >+ my_id_, peer_id, message.length()); > onconnect_data_ = headers; > onconnect_data_ += message; > return ConnectControlSocket(); >@@ -197,7 +191,7 @@ bool PeerConnectionClient::SignOut() { > if (my_id_ != -1) { > char buffer[1024]; > sprintfn(buffer, sizeof(buffer), >- "GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n", my_id_); >+ "GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n", my_id_); > onconnect_data_ = buffer; > return ConnectControlSocket(); > } else { >@@ -243,8 +237,8 @@ void PeerConnectionClient::OnConnect(rtc::AsyncSocket* socket) { > > void PeerConnectionClient::OnHangingGetConnect(rtc::AsyncSocket* socket) { > char buffer[1024]; >- sprintfn(buffer, sizeof(buffer), >- "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n", my_id_); >+ sprintfn(buffer, sizeof(buffer), "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n", >+ my_id_); > int len = static_cast<int>(strlen(buffer)); > int sent = socket->Send(buffer, len); > RTC_DCHECK(sent == len); >@@ -273,7 +267,8 @@ bool PeerConnectionClient::GetHeaderValue(const std::string& data, > return false; > } > >-bool PeerConnectionClient::GetHeaderValue(const std::string& data, size_t eoh, >+bool PeerConnectionClient::GetHeaderValue(const std::string& data, >+ size_t eoh, > const char* header_pattern, > std::string* value) { > RTC_DCHECK(value != NULL); >@@ -331,8 +326,8 @@ void PeerConnectionClient::OnRead(rtc::AsyncSocket* socket) { > size_t content_length = 0; > if (ReadIntoBuffer(socket, &control_data_, &content_length)) { > size_t peer_id = 0, eoh = 0; >- bool ok = ParseServerResponse(control_data_, content_length, &peer_id, >- &eoh); >+ bool ok = >+ ParseServerResponse(control_data_, content_length, &peer_id, &eoh); > if (ok) { > if (my_id_ == -1) { > // First response. Let's store our server assigned ID. >@@ -351,7 +346,8 @@ void PeerConnectionClient::OnRead(rtc::AsyncSocket* socket) { > std::string name; > bool connected; > if (ParseEntry(control_data_.substr(pos, eol - pos), &name, &id, >- &connected) && id != my_id_) { >+ &connected) && >+ id != my_id_) { > peers_[id] = name; > callback_->OnPeerConnected(id, name); > } >@@ -383,8 +379,8 @@ void PeerConnectionClient::OnHangingGetRead(rtc::AsyncSocket* socket) { > size_t content_length = 0; > if (ReadIntoBuffer(socket, ¬ification_data_, &content_length)) { > size_t peer_id = 0, eoh = 0; >- bool ok = ParseServerResponse(notification_data_, content_length, >- &peer_id, &eoh); >+ bool ok = >+ ParseServerResponse(notification_data_, content_length, &peer_id, &eoh); > > if (ok) { > // Store the position where the body begins. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.h >index f5f87ec381e..8dd28f79933 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/client/peer_connection_client.h >@@ -18,7 +18,7 @@ > #include "rtc_base/nethelpers.h" > #include "rtc_base/physicalsocketserver.h" > #include "rtc_base/signalthread.h" >-#include "rtc_base/sigslot.h" >+#include "rtc_base/third_party/sigslot/sigslot.h" > > typedef std::map<int, std::string> Peers; > >@@ -56,7 +56,8 @@ class PeerConnectionClient : public sigslot::has_slots<>, > > void RegisterObserver(PeerConnectionClientObserver* callback); > >- void Connect(const std::string& server, int port, >+ void Connect(const std::string& server, >+ int port, > const std::string& client_name); > > bool SendToPeer(int peer_id, const std::string& message); >@@ -78,14 +79,19 @@ class PeerConnectionClient : public sigslot::has_slots<>, > void OnMessageFromPeer(int peer_id, const std::string& message); > > // Quick and dirty support for parsing HTTP header values. >- bool GetHeaderValue(const std::string& data, size_t eoh, >- const char* header_pattern, size_t* value); >+ bool GetHeaderValue(const std::string& data, >+ size_t eoh, >+ const char* header_pattern, >+ size_t* value); > >- bool GetHeaderValue(const std::string& data, size_t eoh, >- const char* header_pattern, std::string* value); >+ bool GetHeaderValue(const std::string& data, >+ size_t eoh, >+ const char* header_pattern, >+ std::string* value); > > // Returns true if the whole response has been read. >- bool ReadIntoBuffer(rtc::AsyncSocket* socket, std::string* data, >+ bool ReadIntoBuffer(rtc::AsyncSocket* socket, >+ std::string* data, > size_t* content_length); > > void OnRead(rtc::AsyncSocket* socket); >@@ -93,13 +99,17 @@ class PeerConnectionClient : public sigslot::has_slots<>, > void OnHangingGetRead(rtc::AsyncSocket* socket); > > // Parses a single line entry in the form "<name>,<id>,<connected>" >- bool ParseEntry(const std::string& entry, std::string* name, int* id, >+ bool ParseEntry(const std::string& entry, >+ std::string* name, >+ int* id, > bool* connected); > > int GetResponseStatus(const std::string& response); > >- bool ParseServerResponse(const std::string& response, size_t content_length, >- size_t* peer_id, size_t* eoh); >+ bool ParseServerResponse(const std::string& response, >+ size_t content_length, >+ size_t* peer_id, >+ size_t* eoh); > > void OnClose(rtc::AsyncSocket* socket, int err); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.cc >index 7a924316aa2..4369117e1f6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.cc >@@ -29,7 +29,7 @@ const char DataSocket::kCrossOriginAllowHeaders[] = > "Access-Control-Allow-Credentials: true\r\n" > "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n" > "Access-Control-Allow-Headers: Content-Type, " >- "Content-Length, Connection, Cache-Control\r\n" >+ "Content-Length, Connection, Cache-Control\r\n" > "Access-Control-Expose-Headers: Content-Length, X-Peer-Id\r\n"; > > #if defined(WIN32) >@@ -116,10 +116,11 @@ bool DataSocket::OnDataAvailable(bool* close_socket) { > > bool DataSocket::Send(const std::string& data) const { > return send(socket_, data.data(), static_cast<int>(data.length()), 0) != >- SOCKET_ERROR; >+ SOCKET_ERROR; > } > >-bool DataSocket::Send(const std::string& status, bool connection_close, >+bool DataSocket::Send(const std::string& status, >+ bool connection_close, > const std::string& content_type, > const std::string& extra_headers, > const std::string& data) const { >@@ -127,8 +128,9 @@ bool DataSocket::Send(const std::string& status, bool connection_close, > assert(!status.empty()); > std::string buffer("HTTP/1.1 " + status + "\r\n"); > >- buffer += "Server: PeerConnectionTestServer/0.1\r\n" >- "Cache-Control: no-cache\r\n"; >+ buffer += >+ "Server: PeerConnectionTestServer/0.1\r\n" >+ "Cache-Control: no-cache\r\n"; > > if (connection_close) > buffer += "Connection: close\r\n"; >@@ -136,8 +138,8 @@ bool DataSocket::Send(const std::string& status, bool connection_close, > if (!content_type.empty()) > buffer += "Content-Type: " + content_type + "\r\n"; > >- buffer += "Content-Length: " + int2str(static_cast<int>(data.size())) + >- "\r\n"; >+ buffer += >+ "Content-Length: " + int2str(static_cast<int>(data.size())) + "\r\n"; > > if (!extra_headers.empty()) { > buffer += extra_headers; >@@ -190,9 +192,7 @@ bool DataSocket::ParseMethodAndPath(const char* begin, size_t len) { > size_t method_name_len; > RequestMethod id; > } supported_methods[] = { >- { "GET", 3, GET }, >- { "POST", 4, POST }, >- { "OPTIONS", 7, OPTIONS }, >+ {"GET", 3, GET}, {"POST", 4, POST}, {"OPTIONS", 7, OPTIONS}, > }; > > const char* path = NULL; >@@ -231,15 +231,15 @@ bool DataSocket::ParseContentLengthAndType(const char* headers, size_t length) { > static const char kContentLength[] = "Content-Length:"; > static const char kContentType[] = "Content-Type:"; > if ((headers + ARRAYSIZE(kContentLength)) < end && >- strncmp(headers, kContentLength, >- ARRAYSIZE(kContentLength) - 1) == 0) { >+ strncmp(headers, kContentLength, ARRAYSIZE(kContentLength) - 1) == >+ 0) { > headers += ARRAYSIZE(kContentLength) - 1; > while (headers[0] == ' ') > ++headers; > content_length_ = atoi(headers); > } else if ((headers + ARRAYSIZE(kContentType)) < end && >- strncmp(headers, kContentType, >- ARRAYSIZE(kContentType) - 1) == 0) { >+ strncmp(headers, kContentType, ARRAYSIZE(kContentType) - 1) == >+ 0) { > headers += ARRAYSIZE(kContentType) - 1; > while (headers[0] == ' ') > ++headers; >@@ -267,13 +267,13 @@ bool ListeningSocket::Listen(unsigned short port) { > assert(valid()); > int enabled = 1; > setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, >- reinterpret_cast<const char*>(&enabled), sizeof(enabled)); >+ reinterpret_cast<const char*>(&enabled), sizeof(enabled)); > struct sockaddr_in addr = {0}; > addr.sin_family = AF_INET; > addr.sin_addr.s_addr = htonl(INADDR_ANY); > addr.sin_port = htons(port); >- if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr), >- sizeof(addr)) == SOCKET_ERROR) { >+ if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) == >+ SOCKET_ERROR) { > printf("bind failed\n"); > return false; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.h >index 6bafa830a9e..4429bc5a00f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/data_socket.h >@@ -27,7 +27,7 @@ typedef int NativeSocket; > #endif > > #ifndef INVALID_SOCKET >-#define INVALID_SOCKET static_cast<NativeSocket>(-1) >+#define INVALID_SOCKET static_cast<NativeSocket>(-1) > #endif > #endif > >@@ -35,8 +35,8 @@ typedef int NativeSocket; > > class SocketBase { > public: >- SocketBase() : socket_(INVALID_SOCKET) { } >- explicit SocketBase(NativeSocket socket) : socket_(socket) { } >+ SocketBase() : socket_(INVALID_SOCKET) {} >+ explicit SocketBase(NativeSocket socket) : socket_(socket) {} > ~SocketBase() { Close(); } > > NativeSocket socket() const { return socket_; } >@@ -60,13 +60,9 @@ class DataSocket : public SocketBase { > }; > > explicit DataSocket(NativeSocket socket) >- : SocketBase(socket), >- method_(INVALID), >- content_length_(0) { >- } >+ : SocketBase(socket), method_(INVALID), content_length_(0) {} > >- ~DataSocket() { >- } >+ ~DataSocket() {} > > static const char kCrossOriginAllowHeaders[]; > >@@ -110,9 +106,11 @@ class DataSocket : public SocketBase { > // header terminates with "\r\n". > // |data| is the body of the message. It's length will be specified via > // a "Content-Length" header. >- bool Send(const std::string& status, bool connection_close, >+ bool Send(const std::string& status, >+ bool connection_close, > const std::string& content_type, >- const std::string& extra_headers, const std::string& data) const; >+ const std::string& extra_headers, >+ const std::string& data) const; > > // Clears all held state and prepares the socket for receiving a new request. > void Clear(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/main.cc >index d26a1da4d7f..eafda606303 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/main.cc >@@ -46,7 +46,7 @@ void HandleBrowserRequest(DataSocket* ds, bool* quit) { > } > } > >-int main(int argc, char** argv) { >+int main(int argc, char* argv[]) { > std::string program_name = argv[0]; > std::string usage = "Example usage: " + program_name + " --port=8888"; > webrtc::test::CommandLineParser parser; >@@ -94,7 +94,7 @@ int main(int argc, char** argv) { > for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) > FD_SET((*i)->socket(), &socket_set); > >- struct timeval timeout = { 10, 0 }; >+ struct timeval timeout = {10, 0}; > if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) { > printf("select failed\n"); > break; >@@ -111,8 +111,7 @@ int main(int argc, char** argv) { > if (s->PathEquals("/sign_in")) { > clients.AddMember(s); > } else { >- printf("No member found for: %s\n", >- s->request_path().c_str()); >+ printf("No member found for: %s\n", s->request_path().c_str()); > s->Send("500 Error", true, "text/plain", "", > "Peer most likely gone."); > } >@@ -127,7 +126,7 @@ int main(int argc, char** argv) { > s->Send("200 OK", true, "text/plain", "", ""); > } else { > printf("Couldn't find target for request: %s\n", >- s->request_path().c_str()); >+ s->request_path().c_str()); > s->Send("500 Error", true, "text/plain", "", > "Peer most likely gone."); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.cc >index 69a0e104f3e..6ef08d7b21d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.cc >@@ -37,7 +37,7 @@ using rtc::sprintfn; > static const char kPeerIdHeader[] = "Pragma: "; > > static const char* kRequestPaths[] = { >- "/wait", "/sign_out", "/message", >+ "/wait", "/sign_out", "/message", > }; > > enum RequestPathIndex { >@@ -55,8 +55,10 @@ const size_t kMaxNameLength = 512; > int ChannelMember::s_member_id_ = 0; > > ChannelMember::ChannelMember(DataSocket* socket) >- : waiting_socket_(NULL), id_(++s_member_id_), >- connected_(true), timestamp_(time(NULL)) { >+ : waiting_socket_(NULL), >+ id_(++s_member_id_), >+ connected_(true), >+ timestamp_(time(NULL)) { > assert(socket); > assert(socket->method() == DataSocket::GET); > assert(socket->PathEquals("/sign_in")); >@@ -69,8 +71,7 @@ ChannelMember::ChannelMember(DataSocket* socket) > std::replace(name_.begin(), name_.end(), ',', '_'); > } > >-ChannelMember::~ChannelMember() { >-} >+ChannelMember::~ChannelMember() {} > > bool ChannelMember::is_wait_request(DataSocket* ds) const { > return ds && ds->PathEquals(kRequestPaths[kWait]); >@@ -87,8 +88,7 @@ std::string ChannelMember::GetPeerIdHeader() const { > > bool ChannelMember::NotifyOfOtherMember(const ChannelMember& other) { > assert(&other != this); >- QueueResponse("200 OK", "text/plain", GetPeerIdHeader(), >- other.GetEntry()); >+ QueueResponse("200 OK", "text/plain", GetPeerIdHeader(), other.GetEntry()); > return true; > } > >@@ -110,11 +110,9 @@ void ChannelMember::ForwardRequestToPeer(DataSocket* ds, ChannelMember* peer) { > std::string extra_headers(GetPeerIdHeader()); > > if (peer == this) { >- ds->Send("200 OK", true, ds->content_type(), extra_headers, >- ds->data()); >+ ds->Send("200 OK", true, ds->content_type(), extra_headers, ds->data()); > } else { >- printf("Client %s sending to %s\n", >- name_.c_str(), peer->name().c_str()); >+ printf("Client %s sending to %s\n", name_.c_str(), peer->name().c_str()); > peer->QueueResponse("200 OK", ds->content_type(), extra_headers, > ds->data()); > ds->Send("200 OK", true, "text/plain", "", ""); >@@ -135,8 +133,8 @@ void ChannelMember::QueueResponse(const std::string& status, > if (waiting_socket_) { > assert(queue_.size() == 0); > assert(waiting_socket_->method() == DataSocket::GET); >- bool ok = waiting_socket_->Send(status, true, content_type, extra_headers, >- data); >+ bool ok = >+ waiting_socket_->Send(status, true, content_type, extra_headers, data); > if (!ok) { > printf("Failed to deliver data to waiting socket\n"); > } >@@ -251,7 +249,7 @@ bool PeerChannel::AddMember(DataSocket* ds) { > members_.push_back(new_guy); > > printf("New member added (total=%s): %s\n", >- size_t2str(members_.size()).c_str(), new_guy->name().c_str()); >+ size_t2str(members_.size()).c_str(), new_guy->name().c_str()); > > // Let the newly connected peer know about other members of the channel. > std::string content_type; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.h >index a9343d9aebb..c3bb1ad10b5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/peer_channel.h >@@ -44,8 +44,10 @@ class ChannelMember { > > void OnClosing(DataSocket* ds); > >- void QueueResponse(const std::string& status, const std::string& content_type, >- const std::string& extra_headers, const std::string& data); >+ void QueueResponse(const std::string& status, >+ const std::string& content_type, >+ const std::string& extra_headers, >+ const std::string& data); > > void SetWaitingSocket(DataSocket* ds); > >@@ -68,12 +70,9 @@ class PeerChannel { > public: > typedef std::vector<ChannelMember*> Members; > >- PeerChannel() { >- } >+ PeerChannel() {} > >- ~PeerChannel() { >- DeleteAll(); >- } >+ ~PeerChannel() { DeleteAll(); } > > const Members& members() const { return members_; } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/utils.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/utils.cc >index 1bcbe6bd916..dcd1ef74db8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/utils.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/peerconnection/server/utils.cc >@@ -17,9 +17,9 @@ > using rtc::ToString; > > std::string int2str(int i) { >- return ToString<int>(i); >+ return ToString(i); > } > > std::string size_t2str(size_t i) { >- return ToString<size_t>(i); >+ return ToString(i); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/relayserver/relayserver_main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/relayserver/relayserver_main.cc >index e3b18f1a92c..b98caba044f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/relayserver/relayserver_main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/relayserver/relayserver_main.cc >@@ -14,7 +14,7 @@ > #include "p2p/base/relayserver.h" > #include "rtc_base/thread.h" > >-int main(int argc, char **argv) { >+int main(int argc, char** argv) { > if (argc != 3) { > std::cerr << "usage: relayserver internal-address external-address" > << std::endl; >@@ -33,21 +33,21 @@ int main(int argc, char **argv) { > return 1; > } > >- rtc::Thread *pthMain = rtc::Thread::Current(); >+ rtc::Thread* pthMain = rtc::Thread::Current(); > > std::unique_ptr<rtc::AsyncUDPSocket> int_socket( > rtc::AsyncUDPSocket::Create(pthMain->socketserver(), int_addr)); > if (!int_socket) { >- std::cerr << "Failed to create a UDP socket bound at" >- << int_addr.ToString() << std::endl; >+ std::cerr << "Failed to create a UDP socket bound at" << int_addr.ToString() >+ << std::endl; > return 1; > } > > std::unique_ptr<rtc::AsyncUDPSocket> ext_socket( > rtc::AsyncUDPSocket::Create(pthMain->socketserver(), ext_addr)); > if (!ext_socket) { >- std::cerr << "Failed to create a UDP socket bound at" >- << ext_addr.ToString() << std::endl; >+ std::cerr << "Failed to create a UDP socket bound at" << ext_addr.ToString() >+ << std::endl; > return 1; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunprober/main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunprober/main.cc >index e0f98773fe4..973db39d778 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunprober/main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunprober/main.cc >@@ -100,7 +100,7 @@ void StopTrial(rtc::Thread* thread, StunProber* prober, int result) { > > } // namespace > >-int main(int argc, char** argv) { >+int main(int argc, char* argv[]) { > rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); > if (FLAG_help) { > rtc::FlagList::Print(nullptr, false); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunserver/stunserver_main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunserver/stunserver_main.cc >index 8129e1226d5..64d8b419a97 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunserver/stunserver_main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/stunserver/stunserver_main.cc >@@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { > return 1; > } > >- rtc::Thread *pthMain = rtc::Thread::Current(); >+ rtc::Thread* pthMain = rtc::Thread::Current(); > > rtc::AsyncUDPSocket* server_socket = > rtc::AsyncUDPSocket::Create(pthMain->socketserver(), server_addr); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/turnserver/turnserver_main.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/turnserver/turnserver_main.cc >index 5433f951c10..edc0b699b4c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/turnserver/turnserver_main.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/turnserver/turnserver_main.cc >@@ -21,10 +21,9 @@ static const char kSoftware[] = "libjingle TurnServer"; > > class TurnFileAuth : public cricket::TurnAuthInterface { > public: >- explicit TurnFileAuth(const std::string& path) : file_(path) { >- file_.Load(); >- } >- virtual bool GetKey(const std::string& username, const std::string& realm, >+ explicit TurnFileAuth(const std::string& path) : file_(path) { file_.Load(); } >+ virtual bool GetKey(const std::string& username, >+ const std::string& realm, > std::string* key) { > // File is stored as lines of <username>=<HA1>. > // Generate HA1 via "echo -n "<username>:<realm>:<password>" | md5sum" >@@ -37,11 +36,12 @@ class TurnFileAuth : public cricket::TurnAuthInterface { > } > return ret; > } >+ > private: > rtc::OptionsFile file_; > }; > >-int main(int argc, char **argv) { >+int main(int argc, char* argv[]) { > if (argc != 5) { > std::cerr << "usage: turnserver int-addr ext-ip realm auth-file" > << std::endl; >@@ -64,8 +64,8 @@ int main(int argc, char **argv) { > rtc::AsyncUDPSocket* int_socket = > rtc::AsyncUDPSocket::Create(main->socketserver(), int_addr); > if (!int_socket) { >- std::cerr << "Failed to create a UDP socket bound at" >- << int_addr.ToString() << std::endl; >+ std::cerr << "Failed to create a UDP socket bound at" << int_addr.ToString() >+ << std::endl; > return 1; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/ANDROID_INSTRUCTION b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/ANDROID_INSTRUCTION >index 7f69faa8349..f0149eb953e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/ANDROID_INSTRUCTION >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/ANDROID_INSTRUCTION >@@ -1,29 +1,25 @@ >-Instruction of Running webrtc_unity_plugin on Android Unity >+Instruction of running webrtc_unity_plugin on Android Unity > > 1. On Linux machine, compile target webrtc_unity_plugin. > Checkout WebRTC codebase: fetch --no-hooks webrtc_android > If you already have a checkout for linux, add target_os=âandroidâ into .gclient file. > Run gclient sync >- Modify files src/build/android/android_only_jni_exports.lst and src/build/android/android_only_explicit_jni_exports.lst to expose all functions. Namely, change "global" section to "*", and remove "local" section. Otherwise, Unity C# code will not be able to access the functions defined in the plugin. If you do this step after you create a build folder, you may have to clean and recreate the build folder. > Run gn args out/Android, and again set target_os=âandroidâ in the args.gn > Run ninja -C out/Android webrtc_unity_plugin > >-2. On Linux machine, compile target libwebrtc_unity under webrtc checkout. This is the java code for webrtc to work on Android. >+2. On Linux machine, build target libwebrtc_unity under webrtc checkout. This is the java code for webrtc to work on Android. > > 3. Copy libwebrtc_unity.jar and libwebrtc_unity_plugin.so into Unity project folder, under Assets/Plugins/Android folder. > >-4. Rename libwebrtc_unity_plugin.so to libjingle_peerconnection_so.so. Again, this is hacky, and the purpose is to let the java code in libwebrtc.jar to find their JNI implementation. And simultaneously, in your C# wrapper script for the native plugin libjingle_peerconnection_so.so, the dll_path should be set to âjingle_peerconnection_soâ. >+4. Rename libwebrtc_unity_plugin.so to libjingle_peerconnection_so.so. This is hacky, and the purpose is to let the java code in libwebrtc_unity.jar to find their JNI implementations. Simultaneously, in your C# wrapper script for the native plugin libjingle_peerconnection_so.so, the dll_path should be set to âjingle_peerconnection_soâ. > > 5. In the Unity Main Sceneâs Start method, write the following code to initialize the Java environment for webrtc (otherwise, webrtc will not be able to access audio device or camera from C++ code): > > #if UNITY_ANDROID >- AndroidJavaClass playerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); >- AndroidJavaObject activity = playerClass.GetStatic<AndroidJavaObject>("currentActivity"); >- AndroidJavaClass webrtcClass = new AndroidJavaClass("org.webrtc.PeerConnectionFactory"); >- if (webrtcClass != null) >- { >- webrtcClass.CallStatic("initializeAndroidGlobals", new object[2] { activity, false }); >- } >+ AndroidJavaClass playerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); >+ AndroidJavaObject activity = playerClass.GetStatic<AndroidJavaObject>("currentActivity"); >+ AndroidJavaClass utilityClass = new AndroidJavaClass("org.webrtc.UnityUtility"); >+ utilityClass.CallStatic("InitializePeerConncectionFactory", new object[1] { activity }); > #endif > > 6. Compile the unity project into an APK, and decompile the apk using apktool that you can download from https://ibotpeaches.github.io/Apktool/ >@@ -32,6 +28,6 @@ Then copy the AndroidManifest.xml in the decompiled folder to the Assets/Plugins > <uses-permission android:name="android.permission.RECORD_AUDIO" /> > <uses-permission android:name="android.permission.CAMERA" /> > >- The purpose of using apktool is to get a well-written android manifest xml file. If you know how to write manifest file from scratch, you can skip using apktool. >+The purpose of using apktool is to get a well-written android manifest xml file. If you know how to write manifest file from scratch, you can skip using apktool. > > 7. Compile the unity project into an APK again and deploy it to an android device. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/DEPS >index 608c6ade4b7..604005ac734 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/DEPS >@@ -1,3 +1,4 @@ > include_rules = [ >+ "+modules/utility", > "+sdk", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/OWNERS >index 61ea9a97f5d..343f8600f10 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/OWNERS >@@ -1 +1,2 @@ > gyzhou@chromium.org >+qiangchen@chromium.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/java/src/org/webrtc/UnityUtility.java b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/java/src/org/webrtc/UnityUtility.java >index b16d20ad403..5118bac5076 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/java/src/org/webrtc/UnityUtility.java >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/java/src/org/webrtc/UnityUtility.java >@@ -12,6 +12,7 @@ package org.webrtc; > > import android.content.Context; > import java.util.List; >+import javax.annotation.Nullable; > > public class UnityUtility { > private static final String VIDEO_CAPTURER_THREAD_NAME = "VideoCapturerThread"; >@@ -26,7 +27,7 @@ public class UnityUtility { > return Camera2Enumerator.isSupported(ContextUtils.getApplicationContext()); > } > >- private static VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { >+ private static @Nullable VideoCapturer createCameraCapturer(CameraEnumerator enumerator) { > final String[] deviceNames = enumerator.getDeviceNames(); > > for (String deviceName : deviceNames) { >@@ -47,11 +48,10 @@ public class UnityUtility { > VideoCapturer capturer = > createCameraCapturer(new Camera2Enumerator(ContextUtils.getApplicationContext())); > >- VideoCapturer.CapturerObserver capturerObserver = >- new AndroidVideoTrackSourceObserver(nativeTrackSource); >+ VideoSource videoSource = new VideoSource(nativeTrackSource); > >- capturer.initialize( >- surfaceTextureHelper, ContextUtils.getApplicationContext(), capturerObserver); >+ capturer.initialize(surfaceTextureHelper, ContextUtils.getApplicationContext(), >+ videoSource.getCapturerObserver()); > > capturer.startCapture(720, 480, 30); > return capturer; >@@ -61,4 +61,9 @@ public class UnityUtility { > camera.stopCapture(); > camera.dispose(); > } >+ >+ public static void InitializePeerConncectionFactory(Context context) throws InterruptedException { >+ PeerConnectionFactory.initialize( >+ PeerConnectionFactory.InitializationOptions.builder(context).createInitializationOptions()); >+ } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.cc >index 9332a83a27b..df03e3767b6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.cc >@@ -12,21 +12,32 @@ > > #include <utility> > >+#include "absl/memory/memory.h" >+#include "api/audio_codecs/builtin_audio_decoder_factory.h" >+#include "api/audio_codecs/builtin_audio_encoder_factory.h" > #include "api/test/fakeconstraints.h" > #include "api/videosourceproxy.h" >+#include "media/engine/internaldecoderfactory.h" >+#include "media/engine/internalencoderfactory.h" >+#include "media/engine/multiplexcodecfactory.h" > #include "media/engine/webrtcvideocapturerfactory.h" >+#include "media/engine/webrtcvideodecoderfactory.h" >+#include "media/engine/webrtcvideoencoderfactory.h" >+#include "modules/audio_device/include/audio_device.h" >+#include "modules/audio_processing/include/audio_processing.h" > #include "modules/video_capture/video_capture_factory.h" > > #if defined(WEBRTC_ANDROID) > #include "examples/unityplugin/classreferenceholder.h" >+#include "modules/utility/include/helpers_android.h" > #include "sdk/android/src/jni/androidvideotracksource.h" > #include "sdk/android/src/jni/jni_helpers.h" > #endif > >-// Names used for media stream labels. >+// Names used for media stream ids. > const char kAudioLabel[] = "audio_label"; > const char kVideoLabel[] = "video_label"; >-const char kStreamLabel[] = "stream_label"; >+const char kStreamId[] = "stream_id"; > > namespace { > static int g_peer_count = 0; >@@ -65,8 +76,9 @@ class DummySetSessionDescriptionObserver > return new rtc::RefCountedObject<DummySetSessionDescriptionObserver>(); > } > virtual void OnSuccess() { RTC_LOG(INFO) << __FUNCTION__; } >- virtual void OnFailure(const std::string& error) { >- RTC_LOG(INFO) << __FUNCTION__ << " " << error; >+ virtual void OnFailure(webrtc::RTCError error) { >+ RTC_LOG(INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": " >+ << error.message(); > } > > protected: >@@ -91,7 +103,15 @@ bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls, > > g_peer_connection_factory = webrtc::CreatePeerConnectionFactory( > g_worker_thread.get(), g_worker_thread.get(), g_signaling_thread.get(), >- nullptr, nullptr, nullptr); >+ nullptr, webrtc::CreateBuiltinAudioEncoderFactory(), >+ webrtc::CreateBuiltinAudioDecoderFactory(), >+ std::unique_ptr<webrtc::VideoEncoderFactory>( >+ new webrtc::MultiplexEncoderFactory( >+ absl::make_unique<webrtc::InternalEncoderFactory>())), >+ std::unique_ptr<webrtc::VideoDecoderFactory>( >+ new webrtc::MultiplexDecoderFactory( >+ absl::make_unique<webrtc::InternalDecoderFactory>())), >+ nullptr, nullptr); > } > if (!g_peer_connection_factory.get()) { > DeletePeerConnection(); >@@ -99,19 +119,19 @@ bool SimplePeerConnection::InitializePeerConnection(const char** turn_urls, > } > > g_peer_count++; >- if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential, >- is_receiver)) { >+ if (!CreatePeerConnection(turn_urls, no_of_urls, username, credential)) { > DeletePeerConnection(); > return false; > } >+ >+ mandatory_receive_ = is_receiver; > return peer_connection_.get() != nullptr; > } > > bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls, > const int no_of_urls, > const char* username, >- const char* credential, >- bool is_receiver) { >+ const char* credential) { > RTC_DCHECK(g_peer_connection_factory.get() != nullptr); > RTC_DCHECK(peer_connection_.get() == nullptr); > >@@ -148,11 +168,6 @@ bool SimplePeerConnection::CreatePeerConnection(const char** turn_urls, > webrtc::FakeConstraints constraints; > constraints.SetAllowDtlsSctpDataChannels(); > >- if (is_receiver) { >- constraints.SetMandatoryReceiveAudio(true); >- constraints.SetMandatoryReceiveVideo(true); >- } >- > peer_connection_ = g_peer_connection_factory->CreatePeerConnection( > config_, &constraints, nullptr, nullptr, this); > >@@ -167,7 +182,7 @@ void SimplePeerConnection::DeletePeerConnection() { > JNIEnv* env = webrtc::jni::GetEnv(); > jclass pc_factory_class = > unity_plugin::FindClass(env, "org/webrtc/UnityUtility"); >- jmethodID stop_camera_method = webrtc::jni::GetStaticMethodID( >+ jmethodID stop_camera_method = webrtc::GetStaticMethodID( > env, pc_factory_class, "StopCamera", "(Lorg/webrtc/VideoCapturer;)V"); > > env->CallStaticVoidMethod(pc_factory_class, stop_camera_method, g_camera); >@@ -192,7 +207,12 @@ bool SimplePeerConnection::CreateOffer() { > if (!peer_connection_.get()) > return false; > >- peer_connection_->CreateOffer(this, nullptr); >+ webrtc::FakeConstraints constraints; >+ if (mandatory_receive_) { >+ constraints.SetMandatoryReceiveAudio(true); >+ constraints.SetMandatoryReceiveVideo(true); >+ } >+ peer_connection_->CreateOffer(this, &constraints); > return true; > } > >@@ -200,7 +220,12 @@ bool SimplePeerConnection::CreateAnswer() { > if (!peer_connection_.get()) > return false; > >- peer_connection_->CreateAnswer(this, nullptr); >+ webrtc::FakeConstraints constraints; >+ if (mandatory_receive_) { >+ constraints.SetMandatoryReceiveAudio(true); >+ constraints.SetMandatoryReceiveVideo(true); >+ } >+ peer_connection_->CreateAnswer(this, &constraints); > return true; > } > >@@ -216,11 +241,12 @@ void SimplePeerConnection::OnSuccess( > OnLocalSdpReady(desc->type().c_str(), sdp.c_str()); > } > >-void SimplePeerConnection::OnFailure(const std::string& error) { >- RTC_LOG(LERROR) << error; >+void SimplePeerConnection::OnFailure(webrtc::RTCError error) { >+ RTC_LOG(LERROR) << ToString(error.type()) << ": " << error.message(); > >+ // TODO(hta): include error.type in the message > if (OnFailureMessage) >- OnFailureMessage(error.c_str()); >+ OnFailureMessage(error.message()); > } > > void SimplePeerConnection::OnIceCandidate( >@@ -354,7 +380,7 @@ void SimplePeerConnection::SetAudioControl() { > > void SimplePeerConnection::OnAddStream( > rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { >- RTC_LOG(INFO) << __FUNCTION__ << " " << stream->label(); >+ RTC_LOG(INFO) << __FUNCTION__ << " " << stream->id(); > remote_stream_ = stream; > if (remote_video_observer_ && !remote_stream_->GetVideoTracks().empty()) { > remote_stream_->GetVideoTracks()[0]->AddOrUpdateSink( >@@ -395,15 +421,16 @@ SimplePeerConnection::OpenVideoCaptureDevice() { > } > > void SimplePeerConnection::AddStreams(bool audio_only) { >- if (active_streams_.find(kStreamLabel) != active_streams_.end()) >+ if (active_streams_.find(kStreamId) != active_streams_.end()) > return; // Already added. > > rtc::scoped_refptr<webrtc::MediaStreamInterface> stream = >- g_peer_connection_factory->CreateLocalMediaStream(kStreamLabel); >+ g_peer_connection_factory->CreateLocalMediaStream(kStreamId); > > rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track( > g_peer_connection_factory->CreateAudioTrack( >- kAudioLabel, g_peer_connection_factory->CreateAudioSource(nullptr))); >+ kAudioLabel, g_peer_connection_factory->CreateAudioSource( >+ cricket::AudioOptions()))); > std::string id = audio_track->id(); > stream->AddTrack(audio_track); > >@@ -412,7 +439,7 @@ void SimplePeerConnection::AddStreams(bool audio_only) { > JNIEnv* env = webrtc::jni::GetEnv(); > jclass pc_factory_class = > unity_plugin::FindClass(env, "org/webrtc/UnityUtility"); >- jmethodID load_texture_helper_method = webrtc::jni::GetStaticMethodID( >+ jmethodID load_texture_helper_method = webrtc::GetStaticMethodID( > env, pc_factory_class, "LoadSurfaceTextureHelper", > "()Lorg/webrtc/SurfaceTextureHelper;"); > jobject texture_helper = env->CallStaticObjectMethod( >@@ -421,15 +448,15 @@ void SimplePeerConnection::AddStreams(bool audio_only) { > RTC_DCHECK(texture_helper != nullptr) > << "Cannot get the Surface Texture Helper."; > >- rtc::scoped_refptr<AndroidVideoTrackSource> source( >- new rtc::RefCountedObject<AndroidVideoTrackSource>( >- g_signaling_thread.get(), env, texture_helper, false)); >+ rtc::scoped_refptr<webrtc::jni::AndroidVideoTrackSource> source( >+ new rtc::RefCountedObject<webrtc::jni::AndroidVideoTrackSource>( >+ g_signaling_thread.get(), env, false)); > rtc::scoped_refptr<webrtc::VideoTrackSourceProxy> proxy_source = > webrtc::VideoTrackSourceProxy::Create(g_signaling_thread.get(), > g_worker_thread.get(), source); > > // link with VideoCapturer (Camera); >- jmethodID link_camera_method = webrtc::jni::GetStaticMethodID( >+ jmethodID link_camera_method = webrtc::GetStaticMethodID( > env, pc_factory_class, "LinkCamera", > "(JLorg/webrtc/SurfaceTextureHelper;)Lorg/webrtc/VideoCapturer;"); > jobject camera_tmp = >@@ -466,7 +493,7 @@ void SimplePeerConnection::AddStreams(bool audio_only) { > typedef std::pair<std::string, > rtc::scoped_refptr<webrtc::MediaStreamInterface>> > MediaStreamPair; >- active_streams_.insert(MediaStreamPair(stream->label(), stream)); >+ active_streams_.insert(MediaStreamPair(stream->id(), stream)); > } > > bool SimplePeerConnection::CreateDataChannel() { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.h >index 0c7a2615d76..5b30778711f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/simple_peer_connection.h >@@ -64,8 +64,7 @@ class SimplePeerConnection : public webrtc::PeerConnectionObserver, > bool CreatePeerConnection(const char** turn_urls, > const int no_of_urls, > const char* username, >- const char* credential, >- bool is_receiver); >+ const char* credential); > void CloseDataChannel(); > std::unique_ptr<cricket::VideoCapturer> OpenVideoCaptureDevice(); > void SetAudioControl(); >@@ -89,7 +88,7 @@ class SimplePeerConnection : public webrtc::PeerConnectionObserver, > > // CreateSessionDescriptionObserver implementation. > void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; >- void OnFailure(const std::string& error) override; >+ void OnFailure(webrtc::RTCError error) override; > > // DataChannelObserver implementation. > void OnStateChange() override; >@@ -127,6 +126,7 @@ class SimplePeerConnection : public webrtc::PeerConnectionObserver, > > bool is_mute_audio_ = false; > bool is_record_audio_ = false; >+ bool mandatory_receive_ = false; > > // disallow copy-and-assign > SimplePeerConnection(const SimplePeerConnection&) = delete; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.cc >index ae98a833f5d..34c28d926a3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.cc >@@ -24,12 +24,13 @@ static std::map<int, rtc::scoped_refptr<SimplePeerConnection>> > int CreatePeerConnection(const char** turn_urls, > const int no_of_urls, > const char* username, >- const char* credential) { >+ const char* credential, >+ bool mandatory_receive_video) { > g_peer_connection_map[g_peer_connection_id] = > new rtc::RefCountedObject<SimplePeerConnection>(); > > if (!g_peer_connection_map[g_peer_connection_id]->InitializePeerConnection( >- turn_urls, no_of_urls, username, credential, false)) >+ turn_urls, no_of_urls, username, credential, mandatory_receive_video)) > return -1; > > return g_peer_connection_id++; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.h >index 814b9675fb2..b32f9e2caf2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/unity_plugin_apis.h >@@ -19,9 +19,11 @@ > typedef void (*I420FRAMEREADY_CALLBACK)(const uint8_t* data_y, > const uint8_t* data_u, > const uint8_t* data_v, >+ const uint8_t* data_a, > int stride_y, > int stride_u, > int stride_v, >+ int stride_a, > uint32_t width, > uint32_t height); > typedef void (*LOCALDATACHANNELREADY_CALLBACK)(); >@@ -47,7 +49,8 @@ extern "C" { > WEBRTC_PLUGIN_API int CreatePeerConnection(const char** turn_urls, > const int no_of_urls, > const char* username, >- const char* credential); >+ const char* credential, >+ bool mandatory_receive_video); > // Close a peerconnection. > WEBRTC_PLUGIN_API bool ClosePeerConnection(int peer_connection_id); > // Add a audio stream. If audio_only is true, the stream only has an audio >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.cc >index 821acd66aaa..a78ef57e417 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.cc >@@ -17,11 +17,28 @@ void VideoObserver::SetVideoCallback(I420FRAMEREADY_CALLBACK callback) { > > void VideoObserver::OnFrame(const webrtc::VideoFrame& frame) { > std::unique_lock<std::mutex> lock(mutex); >- rtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer( >- frame.video_frame_buffer()->ToI420()); >- if (OnI420FrameReady) { >- OnI420FrameReady(buffer->DataY(), buffer->DataU(), buffer->DataV(), >- buffer->StrideY(), buffer->StrideU(), buffer->StrideV(), >+ if (!OnI420FrameReady) >+ return; >+ >+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer( >+ frame.video_frame_buffer()); >+ >+ if (buffer->type() != webrtc::VideoFrameBuffer::Type::kI420A) { >+ rtc::scoped_refptr<webrtc::I420BufferInterface> i420_buffer = >+ buffer->ToI420(); >+ OnI420FrameReady(i420_buffer->DataY(), i420_buffer->DataU(), >+ i420_buffer->DataV(), nullptr, i420_buffer->StrideY(), >+ i420_buffer->StrideU(), i420_buffer->StrideV(), 0, >+ frame.width(), frame.height()); >+ >+ } else { >+ // The buffer has alpha channel. >+ webrtc::I420ABufferInterface* i420a_buffer = buffer->GetI420A(); >+ >+ OnI420FrameReady(i420a_buffer->DataY(), i420a_buffer->DataU(), >+ i420a_buffer->DataV(), i420a_buffer->DataA(), >+ i420a_buffer->StrideY(), i420a_buffer->StrideU(), >+ i420a_buffer->StrideV(), i420a_buffer->StrideA(), > frame.width(), frame.height()); > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.h >index f2b06b3d495..84c03d329a9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/examples/unityplugin/video_observer.h >@@ -14,8 +14,8 @@ > #include <mutex> > > #include "api/mediastreaminterface.h" >+#include "api/video/video_sink_interface.h" > #include "examples/unityplugin/unity_plugin_apis.h" >-#include "media/base/videosinkinterface.h" > > class VideoObserver : public rtc::VideoSinkInterface<webrtc::VideoFrame> { > public: >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/OWNERS >index b159542bc40..67dfd2fc52b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/OWNERS >@@ -1,3 +1,4 @@ > set noparent > sergiyb@chromium.org > phoglund@webrtc.org >+oprypin@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/cq.cfg b/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/cq.cfg >index ef656d3c2f9..d4f8d963e3a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/cq.cfg >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/infra/config/cq.cfg >@@ -2,7 +2,6 @@ > # at http://luci-config.appspot.com/schemas/projects/refs:cq.cfg. > > version: 1 >-cq_name: "webrtc" > cq_status_url: "https://chromium-cq-status.appspot.com" > git_repo_url: "https://webrtc.googlesource.com/src" > commit_burst_delay: 60 >@@ -22,16 +21,17 @@ verifiers { > > try_job { > buckets { >- name: "master.tryserver.webrtc" >+ name: "luci.webrtc.try" > builders { name: "android_dbg" } > builders { name: "android_rel" } > builders { name: "android_arm64_rel" } >- builders { name: "android_compile_mips_dbg" } >+ builders { name: "android_chromium_compile" } >+ builders { name: "android_compile_arm64_rel" } >+ builders { name: "android_compile_rel" } > builders { name: "android_compile_x86_dbg" } > builders { name: "android_compile_x86_rel" } > builders { name: "android_compile_x64_dbg" } > builders { name: "android_more_configs" } >- builders { name: "android_webrtc_compile_rel" } > builders { name: "ios_arm64_dbg" } > builders { name: "ios_arm64_rel" } > builders { name: "ios_dbg" } >@@ -48,12 +48,10 @@ verifiers { > builders { name: "linux_arm64_dbg" } > builders { name: "linux_arm64_rel" } > builders { name: "linux_asan" } >- builders { name: "linux_baremetal" } >- builders { name: "linux_chromium_webrtc_compile_rel_ng" } >+ builders { name: "linux_chromium_compile" } > builders { name: "linux_compile_dbg" } >+ builders { name: "linux_compile_rel" } > builders { name: "linux_libfuzzer_rel" } >- # TODO(bugs.webrtc.org/8356): Investigate fixing and re-enabling. >- #builders { name: "linux_memcheck" } > builders { name: "linux_msan" } > builders { name: "linux_rel" } > builders { name: "linux_tsan2" } >@@ -62,14 +60,12 @@ verifiers { > builders { name: "linux_gcc_rel" } > builders { name: "linux_more_configs" } > builders { name: "mac_asan" } >- builders { name: "mac_baremetal" } >- builders { name: "mac_chromium_webrtc_compile_rel_ng" } >+ builders { name: "mac_chromium_compile" } > builders { name: "mac_compile_dbg" } > builders { name: "mac_rel" } > builders { name: "presubmit" } > builders { name: "win_asan" } >- builders { name: "win_baremetal" } >- builders { name: "win_chromium_webrtc_compile_rel_ng" } >+ builders { name: "win_chromium_compile" } > builders { name: "win_clang_dbg" } > builders { name: "win_clang_rel" } > builders { name: "win_dbg" } >@@ -79,6 +75,15 @@ verifiers { > builders { name: "win_x64_dbg" } > builders { name: "win_x64_rel" } > builders { name: "win_more_configs" } >+ builders { >+ name: "noop" >+ equivalent_to { >+ bucket: "master.internal.tryserver.corp.webrtc" >+ builder: "linux_internal_compile_lite" >+ owner_whitelist_group: "project-webrtc-internal-tryjob-access" >+ percentage: 100 >+ } >+ } > } > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/BUILD.gn >index f1afddccd54..843c38dbd93 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/BUILD.gn >@@ -17,18 +17,62 @@ if (is_android) { > > group("logging") { > deps = [ >- ":rtc_event_log_impl", >+ ":rtc_event_audio", >+ ":rtc_event_bwe", >+ ":rtc_event_log_impl_base", >+ ":rtc_event_log_impl_encoder", >+ ":rtc_event_log_impl_output", >+ ":rtc_event_pacing", >+ ":rtc_event_rtp_rtcp", >+ ":rtc_event_video", > ] >- if (rtc_enable_protobuf) { >- deps += [ ":rtc_event_log_parser" ] >- } > } > > rtc_source_set("rtc_event_log_api") { > sources = [ >+ "rtc_event_log/encoder/rtc_event_log_encoder.h", > "rtc_event_log/events/rtc_event.h", >+ "rtc_event_log/rtc_event_log.cc", >+ "rtc_event_log/rtc_event_log.h", >+ "rtc_event_log/rtc_event_log_factory_interface.h", >+ ] >+ >+ deps = [ >+ "../api:libjingle_logging_api", >+ "../rtc_base:ptr_util", >+ "../rtc_base:rtc_base_approved", >+ "../rtc_base:rtc_task_queue", >+ ] >+} >+ >+rtc_source_set("rtc_stream_config") { >+ sources = [ >+ "rtc_event_log/rtc_stream_config.cc", >+ "rtc_event_log/rtc_stream_config.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "..:webrtc_common", >+ "../api:libjingle_peerconnection_api", >+ ] >+} >+ >+rtc_source_set("rtc_event_pacing") { >+ sources = [ > "rtc_event_log/events/rtc_event_alr_state.cc", > "rtc_event_log/events/rtc_event_alr_state.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("rtc_event_audio") { >+ sources = [ > "rtc_event_log/events/rtc_event_audio_network_adaptation.cc", > "rtc_event_log/events/rtc_event_audio_network_adaptation.h", > "rtc_event_log/events/rtc_event_audio_playout.cc", >@@ -37,6 +81,19 @@ rtc_source_set("rtc_event_log_api") { > "rtc_event_log/events/rtc_event_audio_receive_stream_config.h", > "rtc_event_log/events/rtc_event_audio_send_stream_config.cc", > "rtc_event_log/events/rtc_event_audio_send_stream_config.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ ":rtc_stream_config", >+ "../modules/audio_coding:audio_network_adaptor_config", >+ "../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("rtc_event_bwe") { >+ sources = [ > "rtc_event_log/events/rtc_event_bwe_update_delay_based.cc", > "rtc_event_log/events/rtc_event_bwe_update_delay_based.h", > "rtc_event_log/events/rtc_event_bwe_update_loss_based.cc", >@@ -47,6 +104,18 @@ rtc_source_set("rtc_event_log_api") { > "rtc_event_log/events/rtc_event_probe_result_failure.h", > "rtc_event_log/events/rtc_event_probe_result_success.cc", > "rtc_event_log/events/rtc_event_probe_result_success.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "../modules/remote_bitrate_estimator:remote_bitrate_estimator", >+ "../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("rtc_event_rtp_rtcp") { >+ sources = [ > "rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc", > "rtc_event_log/events/rtc_event_rtcp_packet_incoming.h", > "rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc", >@@ -55,77 +124,124 @@ rtc_source_set("rtc_event_log_api") { > "rtc_event_log/events/rtc_event_rtp_packet_incoming.h", > "rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc", > "rtc_event_log/events/rtc_event_rtp_packet_outgoing.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "../api:array_view", >+ "../modules/rtp_rtcp:rtp_rtcp_format", >+ "../rtc_base:ptr_util", >+ "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_source_set("rtc_event_video") { >+ sources = [ > "rtc_event_log/events/rtc_event_video_receive_stream_config.cc", > "rtc_event_log/events/rtc_event_video_receive_stream_config.h", > "rtc_event_log/events/rtc_event_video_send_stream_config.cc", > "rtc_event_log/events/rtc_event_video_send_stream_config.h", >- "rtc_event_log/output/rtc_event_log_output_file.cc", >- "rtc_event_log/output/rtc_event_log_output_file.h", >- "rtc_event_log/rtc_event_log.h", >- "rtc_event_log/rtc_event_log_factory_interface.h", >- "rtc_event_log/rtc_stream_config.cc", >- "rtc_event_log/rtc_stream_config.h", > ] > > deps = [ >- "..:webrtc_common", >- "../:typedefs", >- "../api:array_view", >- "../api:libjingle_logging_api", >- "../api:libjingle_peerconnection_api", >- "../call:video_stream_api", >- "../modules/audio_coding:audio_network_adaptor_config", >+ ":rtc_event_log_api", >+ ":rtc_stream_config", >+ "../rtc_base:ptr_util", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ >+rtc_static_library("rtc_event_log_impl_encoder") { >+ visibility = [ "*" ] >+ sources = [ >+ "rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc", >+ "rtc_event_log/encoder/rtc_event_log_encoder_legacy.h", >+ ] >+ >+ defines = [] >+ >+ deps = [ >+ ":ice_log", >+ ":rtc_event_audio", >+ ":rtc_event_bwe", >+ ":rtc_event_log_api", >+ ":rtc_event_log_impl_output", >+ ":rtc_event_pacing", >+ ":rtc_event_rtp_rtcp", >+ ":rtc_event_video", >+ ":rtc_stream_config", >+ "../modules/audio_coding:audio_network_adaptor", > "../modules/remote_bitrate_estimator:remote_bitrate_estimator", > "../modules/rtp_rtcp:rtp_rtcp_format", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >- "../system_wrappers", > ] > >- # TODO(eladalon): Remove this. >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >+ if (rtc_enable_protobuf) { >+ defines += [ "ENABLE_RTC_EVENT_LOG" ] >+ deps += [ ":rtc_event_log_proto" ] > } > } > >-rtc_static_library("rtc_event_log_impl") { >+rtc_source_set("rtc_event_log_impl_output") { >+ sources = [ >+ "rtc_event_log/output/rtc_event_log_output_file.cc", >+ "rtc_event_log/output/rtc_event_log_output_file.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "../api:libjingle_logging_api", >+ "../rtc_base:checks", >+ "../rtc_base:rtc_base_approved", >+ ] >+} >+ >+rtc_static_library("rtc_event_log_impl_base") { > visibility = [ "*" ] > sources = [ >- "rtc_event_log/encoder/rtc_event_log_encoder.h", >- "rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc", >- "rtc_event_log/encoder/rtc_event_log_encoder_legacy.h", >- "rtc_event_log/rtc_event_log.cc", > "rtc_event_log/rtc_event_log_factory.cc", > "rtc_event_log/rtc_event_log_factory.h", >+ "rtc_event_log/rtc_event_log_impl.cc", > ] > > defines = [] > > deps = [ >+ ":ice_log", > ":rtc_event_log_api", >- "..:webrtc_common", >- "../modules/audio_coding:audio_network_adaptor", >- "../modules/remote_bitrate_estimator:remote_bitrate_estimator", >- "../modules/rtp_rtcp:rtp_rtcp_format", >+ ":rtc_event_log_impl_encoder", >+ ":rtc_event_log_impl_output", > "../rtc_base:checks", >- "../rtc_base:protobuf_utils", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_task_queue", >+ "../rtc_base:safe_minmax", > "../rtc_base:sequenced_task_checker", >- "../system_wrappers", >+ "//third_party/abseil-cpp/absl/memory", > ] > > if (rtc_enable_protobuf) { > defines += [ "ENABLE_RTC_EVENT_LOG" ] > deps += [ ":rtc_event_log_proto" ] > } >+} > >- # TODO(eladalon): Remove this. >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } >+rtc_source_set("fake_rtc_event_log") { >+ testonly = true >+ sources = [ >+ "rtc_event_log/fake_rtc_event_log.cc", >+ "rtc_event_log/fake_rtc_event_log.h", >+ "rtc_event_log/fake_rtc_event_log_factory.cc", >+ "rtc_event_log/fake_rtc_event_log_factory.h", >+ ] >+ >+ deps = [ >+ ":ice_log", >+ ":rtc_event_log_api", >+ "../rtc_base:checks", >+ "../rtc_base:rtc_base", >+ ] > } > > if (rtc_enable_protobuf) { >@@ -144,16 +260,23 @@ if (rtc_enable_protobuf) { > } > > rtc_static_library("rtc_event_log_parser") { >+ visibility = [ "*" ] > sources = [ > "rtc_event_log/rtc_event_log_parser.cc", > "rtc_event_log/rtc_event_log_parser.h", >+ "rtc_event_log/rtc_event_log_parser_new.cc", >+ "rtc_event_log/rtc_event_log_parser_new.h", > ] > > deps = [ >+ ":ice_log", >+ ":rtc_event_bwe", > ":rtc_event_log2_proto", > ":rtc_event_log_api", > ":rtc_event_log_proto", >+ ":rtc_stream_config", > "..:webrtc_common", >+ "../api:libjingle_peerconnection_api", > "../call:video_stream_api", > "../modules/audio_coding:audio_network_adaptor", > "../modules/remote_bitrate_estimator:remote_bitrate_estimator", >@@ -162,7 +285,7 @@ if (rtc_enable_protobuf) { > "../rtc_base:checks", > "../rtc_base:protobuf_utils", > "../rtc_base:rtc_base_approved", >- "../system_wrappers", >+ "//third_party/abseil-cpp/absl/memory", > ] > > if (!build_with_chromium && is_clang) { >@@ -176,9 +299,6 @@ if (rtc_enable_protobuf) { > testonly = true > assert(rtc_enable_protobuf) > defines = [ "ENABLE_RTC_EVENT_LOG" ] >- if (rtc_use_memcheck) { >- defines += [ "WEBRTC_USE_MEMCHECK" ] >- } > sources = [ > "rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc", > "rtc_event_log/output/rtc_event_log_output_file_unittest.cc", >@@ -187,10 +307,19 @@ if (rtc_enable_protobuf) { > "rtc_event_log/rtc_event_log_unittest_helper.h", > ] > deps = [ >+ ":ice_log", >+ ":rtc_event_audio", >+ ":rtc_event_bwe", > ":rtc_event_log_api", >- ":rtc_event_log_impl", >+ ":rtc_event_log_impl_base", >+ ":rtc_event_log_impl_encoder", >+ ":rtc_event_log_impl_output", > ":rtc_event_log_parser", > ":rtc_event_log_proto", >+ ":rtc_event_pacing", >+ ":rtc_event_rtp_rtcp", >+ ":rtc_event_video", >+ ":rtc_stream_config", > "../api:libjingle_peerconnection_api", > "../call", > "../call:call_interfaces", >@@ -200,16 +329,17 @@ if (rtc_enable_protobuf) { > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_base_tests_utils", >- "../system_wrappers:metrics_default", >+ "../test:fileutils", > "../test:test_support", >- "//testing/gmock", > "//testing/gtest", >+ "//third_party/abseil-cpp/absl/memory", > ] > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > } >+ > rtc_test("rtc_event_log2rtp_dump") { > testonly = true > sources = [ >@@ -217,7 +347,6 @@ if (rtc_enable_protobuf) { > ] > deps = [ > ":rtc_event_log_api", >- ":rtc_event_log_impl", > ":rtc_event_log_parser", > "../modules/rtp_rtcp", > "../modules/rtp_rtcp:rtp_rtcp_format", >@@ -243,7 +372,6 @@ if (rtc_enable_protobuf) { > ] > deps = [ > ":rtc_event_log_api", >- ":rtc_event_log_impl", > ":rtc_event_log_parser", > "../:webrtc_common", > "../call:video_stream_api", >@@ -251,6 +379,7 @@ if (rtc_enable_protobuf) { > "../rtc_base:checks", > "../rtc_base:protobuf_utils", > "../rtc_base:rtc_base_approved", >+ "../rtc_base:stringutils", > > # TODO(kwiberg): Remove this dependency. > "../api/audio_codecs:audio_codecs_api", >@@ -271,28 +400,42 @@ if (rtc_enable_protobuf) { > ] > deps = [ > ":rtc_event_log_api", >- ":rtc_event_log_impl", > ":rtc_event_log_proto", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", > ] >- if (!build_with_chromium && is_clang) { >- # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). >- suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] >- } > } > } > } > >+rtc_source_set("ice_log") { >+ sources = [ >+ "rtc_event_log/events/rtc_event_ice_candidate_pair.cc", >+ "rtc_event_log/events/rtc_event_ice_candidate_pair.h", >+ "rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc", >+ "rtc_event_log/events/rtc_event_ice_candidate_pair_config.h", >+ "rtc_event_log/icelogger.cc", >+ "rtc_event_log/icelogger.h", >+ ] >+ >+ deps = [ >+ ":rtc_event_log_api", >+ "../api:libjingle_logging_api", >+ "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/memory", >+ ] >+} >+ > if (rtc_include_tests) { > rtc_source_set("mocks") { > testonly = true > sources = [ >+ "rtc_event_log/mock/mock_rtc_event_log.cc", > "rtc_event_log/mock/mock_rtc_event_log.h", > ] > deps = [ > ":rtc_event_log_api", >- "../../test:test_support", >+ "../test:test_support", > ] > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/OWNERS >index 492fb7ab32c..96b781d87d9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/OWNERS >@@ -1,3 +1,2 @@ >-skvlad@webrtc.org > stefan@webrtc.org > terelius@webrtc.org >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/DEPS >index ec93428e809..d09e30eace6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/DEPS >@@ -3,5 +3,4 @@ include_rules = [ > "+modules/audio_coding/audio_network_adaptor", > "+modules/remote_bitrate_estimator/include", > "+modules/rtp_rtcp", >- "+system_wrappers", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h >index 8f509ce896e..beb711c9dd8 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder.h >@@ -25,8 +25,6 @@ class RtcEventLogEncoder { > virtual std::string EncodeLogStart(int64_t timestamp_us) = 0; > virtual std::string EncodeLogEnd(int64_t timestamp_us) = 0; > >- virtual std::string Encode(const RtcEvent& event) = 0; >- > virtual std::string EncodeBatch( > std::deque<std::unique_ptr<RtcEvent>>::const_iterator begin, > std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc >index c05f7717c85..7ef8d677c60 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.cc >@@ -17,6 +17,8 @@ > #include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h" > #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" > #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" > #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" > #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" > #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" >@@ -103,8 +105,123 @@ rtclog::VideoReceiveConfig_RtcpMode ConvertRtcpMode(RtcpMode rtcp_mode) { > RTC_NOTREACHED(); > return rtclog::VideoReceiveConfig::RTCP_COMPOUND; > } >-} // namespace > >+rtclog::IceCandidatePairConfig::IceCandidatePairConfigType >+ConvertIceCandidatePairConfigType(IceCandidatePairConfigType type) { >+ switch (type) { >+ case IceCandidatePairConfigType::kAdded: >+ return rtclog::IceCandidatePairConfig::ADDED; >+ case IceCandidatePairConfigType::kUpdated: >+ return rtclog::IceCandidatePairConfig::UPDATED; >+ case IceCandidatePairConfigType::kDestroyed: >+ return rtclog::IceCandidatePairConfig::DESTROYED; >+ case IceCandidatePairConfigType::kSelected: >+ return rtclog::IceCandidatePairConfig::SELECTED; >+ case IceCandidatePairConfigType::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairConfig::ADDED; >+} >+ >+rtclog::IceCandidatePairConfig::IceCandidateType ConvertIceCandidateType( >+ IceCandidateType type) { >+ switch (type) { >+ case IceCandidateType::kUnknown: >+ return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; >+ case IceCandidateType::kLocal: >+ return rtclog::IceCandidatePairConfig::LOCAL; >+ case IceCandidateType::kStun: >+ return rtclog::IceCandidatePairConfig::STUN; >+ case IceCandidateType::kPrflx: >+ return rtclog::IceCandidatePairConfig::PRFLX; >+ case IceCandidateType::kRelay: >+ return rtclog::IceCandidatePairConfig::RELAY; >+ case IceCandidateType::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE; >+} >+ >+rtclog::IceCandidatePairConfig::Protocol ConvertIceCandidatePairProtocol( >+ IceCandidatePairProtocol protocol) { >+ switch (protocol) { >+ case IceCandidatePairProtocol::kUnknown: >+ return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL; >+ case IceCandidatePairProtocol::kUdp: >+ return rtclog::IceCandidatePairConfig::UDP; >+ case IceCandidatePairProtocol::kTcp: >+ return rtclog::IceCandidatePairConfig::TCP; >+ case IceCandidatePairProtocol::kSsltcp: >+ return rtclog::IceCandidatePairConfig::SSLTCP; >+ case IceCandidatePairProtocol::kTls: >+ return rtclog::IceCandidatePairConfig::TLS; >+ case IceCandidatePairProtocol::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL; >+} >+ >+rtclog::IceCandidatePairConfig::AddressFamily >+ConvertIceCandidatePairAddressFamily( >+ IceCandidatePairAddressFamily address_family) { >+ switch (address_family) { >+ case IceCandidatePairAddressFamily::kUnknown: >+ return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; >+ case IceCandidatePairAddressFamily::kIpv4: >+ return rtclog::IceCandidatePairConfig::IPV4; >+ case IceCandidatePairAddressFamily::kIpv6: >+ return rtclog::IceCandidatePairConfig::IPV6; >+ case IceCandidatePairAddressFamily::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY; >+} >+ >+rtclog::IceCandidatePairConfig::NetworkType ConvertIceCandidateNetworkType( >+ IceCandidateNetworkType network_type) { >+ switch (network_type) { >+ case IceCandidateNetworkType::kUnknown: >+ return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; >+ case IceCandidateNetworkType::kEthernet: >+ return rtclog::IceCandidatePairConfig::ETHERNET; >+ case IceCandidateNetworkType::kLoopback: >+ return rtclog::IceCandidatePairConfig::LOOPBACK; >+ case IceCandidateNetworkType::kWifi: >+ return rtclog::IceCandidatePairConfig::WIFI; >+ case IceCandidateNetworkType::kVpn: >+ return rtclog::IceCandidatePairConfig::VPN; >+ case IceCandidateNetworkType::kCellular: >+ return rtclog::IceCandidatePairConfig::CELLULAR; >+ case IceCandidateNetworkType::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE; >+} >+ >+rtclog::IceCandidatePairEvent::IceCandidatePairEventType >+ConvertIceCandidatePairEventType(IceCandidatePairEventType type) { >+ switch (type) { >+ case IceCandidatePairEventType::kCheckSent: >+ return rtclog::IceCandidatePairEvent::CHECK_SENT; >+ case IceCandidatePairEventType::kCheckReceived: >+ return rtclog::IceCandidatePairEvent::CHECK_RECEIVED; >+ case IceCandidatePairEventType::kCheckResponseSent: >+ return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT; >+ case IceCandidatePairEventType::kCheckResponseReceived: >+ return rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED; >+ case IceCandidatePairEventType::kNumValues: >+ RTC_NOTREACHED(); >+ } >+ RTC_NOTREACHED(); >+ return rtclog::IceCandidatePairEvent::CHECK_SENT; >+} >+ >+} // namespace > > std::string RtcEventLogEncoderLegacy::EncodeLogStart(int64_t timestamp_us) { > rtclog::Event rtclog_event; >@@ -127,6 +244,7 @@ std::string RtcEventLogEncoderLegacy::EncodeBatch( > for (auto it = begin; it != end; ++it) { > // TODO(terelius): Can we avoid the slight inefficiency of reallocating the > // string? >+ RTC_CHECK(it->get() != nullptr); > encoded_output += Encode(**it); > } > return encoded_output; >@@ -172,6 +290,17 @@ std::string RtcEventLogEncoderLegacy::Encode(const RtcEvent& event) { > return EncodeBweUpdateLossBased(rtc_event); > } > >+ case RtcEvent::Type::IceCandidatePairConfig: { >+ auto& rtc_event = >+ static_cast<const RtcEventIceCandidatePairConfig&>(event); >+ return EncodeIceCandidatePairConfig(rtc_event); >+ } >+ >+ case RtcEvent::Type::IceCandidatePairEvent: { >+ auto& rtc_event = static_cast<const RtcEventIceCandidatePair&>(event); >+ return EncodeIceCandidatePairEvent(rtc_event); >+ } >+ > case RtcEvent::Type::ProbeClusterCreated: { > auto& rtc_event = static_cast<const RtcEventProbeClusterCreated&>(event); > return EncodeProbeClusterCreated(rtc_event); >@@ -231,7 +360,7 @@ std::string RtcEventLogEncoderLegacy::EncodeAlrState( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::ALR_STATE_EVENT); > >- auto alr_state = rtclog_event.mutable_alr_state(); >+ auto* alr_state = rtclog_event.mutable_alr_state(); > alr_state->set_in_alr(event.in_alr_); > return Serialize(&rtclog_event); > } >@@ -242,7 +371,7 @@ std::string RtcEventLogEncoderLegacy::EncodeAudioNetworkAdaptation( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT); > >- auto audio_network_adaptation = >+ auto* audio_network_adaptation = > rtclog_event.mutable_audio_network_adaptation(); > if (event.config_->bitrate_bps) > audio_network_adaptation->set_bitrate_bps(*event.config_->bitrate_bps); >@@ -269,7 +398,7 @@ std::string RtcEventLogEncoderLegacy::EncodeAudioPlayout( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::AUDIO_PLAYOUT_EVENT); > >- auto playout_event = rtclog_event.mutable_audio_playout_event(); >+ auto* playout_event = rtclog_event.mutable_audio_playout_event(); > playout_event->set_local_ssrc(event.ssrc_); > > return Serialize(&rtclog_event); >@@ -323,7 +452,7 @@ std::string RtcEventLogEncoderLegacy::EncodeBweUpdateDelayBased( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::DELAY_BASED_BWE_UPDATE); > >- auto bwe_event = rtclog_event.mutable_delay_based_bwe_update(); >+ auto* bwe_event = rtclog_event.mutable_delay_based_bwe_update(); > bwe_event->set_bitrate_bps(event.bitrate_bps_); > bwe_event->set_detector_state(ConvertDetectorState(event.detector_state_)); > >@@ -336,7 +465,7 @@ std::string RtcEventLogEncoderLegacy::EncodeBweUpdateLossBased( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::LOSS_BASED_BWE_UPDATE); > >- auto bwe_event = rtclog_event.mutable_loss_based_bwe_update(); >+ auto* bwe_event = rtclog_event.mutable_loss_based_bwe_update(); > bwe_event->set_bitrate_bps(event.bitrate_bps_); > bwe_event->set_fraction_loss(event.fraction_loss_); > bwe_event->set_total_packets(event.total_packets_); >@@ -344,13 +473,56 @@ std::string RtcEventLogEncoderLegacy::EncodeBweUpdateLossBased( > return Serialize(&rtclog_event); > } > >+std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairConfig( >+ const RtcEventIceCandidatePairConfig& event) { >+ rtclog::Event encoded_rtc_event; >+ encoded_rtc_event.set_timestamp_us(event.timestamp_us_); >+ encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG); >+ >+ auto* encoded_ice_event = >+ encoded_rtc_event.mutable_ice_candidate_pair_config(); >+ encoded_ice_event->set_config_type( >+ ConvertIceCandidatePairConfigType(event.type_)); >+ encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id_); >+ const auto& desc = event.candidate_pair_desc_; >+ encoded_ice_event->set_local_candidate_type( >+ ConvertIceCandidateType(desc.local_candidate_type)); >+ encoded_ice_event->set_local_relay_protocol( >+ ConvertIceCandidatePairProtocol(desc.local_relay_protocol)); >+ encoded_ice_event->set_local_network_type( >+ ConvertIceCandidateNetworkType(desc.local_network_type)); >+ encoded_ice_event->set_local_address_family( >+ ConvertIceCandidatePairAddressFamily(desc.local_address_family)); >+ encoded_ice_event->set_remote_candidate_type( >+ ConvertIceCandidateType(desc.remote_candidate_type)); >+ encoded_ice_event->set_remote_address_family( >+ ConvertIceCandidatePairAddressFamily(desc.remote_address_family)); >+ encoded_ice_event->set_candidate_pair_protocol( >+ ConvertIceCandidatePairProtocol(desc.candidate_pair_protocol)); >+ return Serialize(&encoded_rtc_event); >+} >+ >+std::string RtcEventLogEncoderLegacy::EncodeIceCandidatePairEvent( >+ const RtcEventIceCandidatePair& event) { >+ rtclog::Event encoded_rtc_event; >+ encoded_rtc_event.set_timestamp_us(event.timestamp_us_); >+ encoded_rtc_event.set_type(rtclog::Event::ICE_CANDIDATE_PAIR_EVENT); >+ >+ auto* encoded_ice_event = >+ encoded_rtc_event.mutable_ice_candidate_pair_event(); >+ encoded_ice_event->set_event_type( >+ ConvertIceCandidatePairEventType(event.type_)); >+ encoded_ice_event->set_candidate_pair_id(event.candidate_pair_id_); >+ return Serialize(&encoded_rtc_event); >+} >+ > std::string RtcEventLogEncoderLegacy::EncodeProbeClusterCreated( > const RtcEventProbeClusterCreated& event) { > rtclog::Event rtclog_event; > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT); > >- auto probe_cluster = rtclog_event.mutable_probe_cluster(); >+ auto* probe_cluster = rtclog_event.mutable_probe_cluster(); > probe_cluster->set_id(event.id_); > probe_cluster->set_bitrate_bps(event.bitrate_bps_); > probe_cluster->set_min_packets(event.min_probes_); >@@ -365,7 +537,7 @@ std::string RtcEventLogEncoderLegacy::EncodeProbeResultFailure( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT); > >- auto probe_result = rtclog_event.mutable_probe_result(); >+ auto* probe_result = rtclog_event.mutable_probe_result(); > probe_result->set_id(event.id_); > probe_result->set_result(ConvertProbeResultType(event.failure_reason_)); > >@@ -378,7 +550,7 @@ std::string RtcEventLogEncoderLegacy::EncodeProbeResultSuccess( > rtclog_event.set_timestamp_us(event.timestamp_us_); > rtclog_event.set_type(rtclog::Event::BWE_PROBE_RESULT_EVENT); > >- auto probe_result = rtclog_event.mutable_probe_result(); >+ auto* probe_result = rtclog_event.mutable_probe_result(); > probe_result->set_id(event.id_); > probe_result->set_result(rtclog::BweProbeResult::SUCCESS); > probe_result->set_bitrate_bps(event.bitrate_bps_); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h >index a8173135aef..87db039e3af 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h >@@ -32,6 +32,8 @@ class RtcEventAudioReceiveStreamConfig; > class RtcEventAudioSendStreamConfig; > class RtcEventBweUpdateDelayBased; > class RtcEventBweUpdateLossBased; >+class RtcEventIceCandidatePairConfig; >+class RtcEventIceCandidatePair; > class RtcEventLoggingStarted; > class RtcEventLoggingStopped; > class RtcEventProbeClusterCreated; >@@ -50,8 +52,6 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { > public: > ~RtcEventLogEncoderLegacy() override = default; > >- std::string Encode(const RtcEvent& event) override; >- > std::string EncodeLogStart(int64_t timestamp_us) override; > std::string EncodeLogEnd(int64_t timestamp_us) override; > >@@ -60,6 +60,7 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { > std::deque<std::unique_ptr<RtcEvent>>::const_iterator end) override; > > private: >+ std::string Encode(const RtcEvent& event); > // Encoding entry-point for the various RtcEvent subclasses. > std::string EncodeAlrState(const RtcEventAlrState& event); > std::string EncodeAudioNetworkAdaptation( >@@ -72,6 +73,10 @@ class RtcEventLogEncoderLegacy final : public RtcEventLogEncoder { > std::string EncodeBweUpdateDelayBased( > const RtcEventBweUpdateDelayBased& event); > std::string EncodeBweUpdateLossBased(const RtcEventBweUpdateLossBased& event); >+ std::string EncodeIceCandidatePairConfig( >+ const RtcEventIceCandidatePairConfig& event); >+ std::string EncodeIceCandidatePairEvent( >+ const RtcEventIceCandidatePair& event); > std::string EncodeProbeClusterCreated( > const RtcEventProbeClusterCreated& event); > std::string EncodeProbeResultFailure(const RtcEventProbeResultFailure& event); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc >index 00dad29d0f1..990fa6080bb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/encoder/rtc_event_log_encoder_unittest.cc >@@ -8,14 +8,13 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include <cmath> >+#include <deque> > #include <limits> >-#include <memory> > #include <string> >-#include <utility> > >-#include "api/rtpparameters.h" // RtpExtension >+#include "absl/memory/memory.h" > #include "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h" >+#include "logging/rtc_event_log/events/rtc_event_alr_state.h" > #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" > #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" > #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" >@@ -31,51 +30,24 @@ > #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" > #include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h" > #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" >-#include "logging/rtc_event_log/rtc_event_log_parser.h" >+#include "logging/rtc_event_log/rtc_event_log_parser_new.h" >+#include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" > #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" > #include "modules/remote_bitrate_estimator/include/bwe_defines.h" >-#include "modules/rtp_rtcp/source/rtcp_packet/bye.h" // Arbitrary RTCP message. > #include "modules/rtp_rtcp/source/rtp_header_extensions.h" >-#include "modules/rtp_rtcp/source/rtp_packet_received.h" >-#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" >-#include "rtc_base/arraysize.h" >-#include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/random.h" > #include "test/gtest.h" > > namespace webrtc { > >-namespace { >-struct ExtensionInfo { >- RTPExtensionType type; >- const char* uri; >-}; >- >-template <typename Extension> >-constexpr ExtensionInfo CreateExtensionInfo() { >- return {Extension::kId, Extension::kUri}; >-} >- >-constexpr ExtensionInfo kExtensions[] = { >- CreateExtensionInfo<TransmissionOffset>(), >- CreateExtensionInfo<AudioLevel>(), >- CreateExtensionInfo<AbsoluteSendTime>(), >- CreateExtensionInfo<VideoOrientation>(), >- CreateExtensionInfo<TransportSequenceNumber>(), >- CreateExtensionInfo<PlayoutDelayLimits>(), >- CreateExtensionInfo<VideoContentTypeExtension>(), >- CreateExtensionInfo<VideoTimingExtension>(), >- CreateExtensionInfo<RtpStreamId>(), >- CreateExtensionInfo<RepairedRtpStreamId>(), >- CreateExtensionInfo<RtpMid>(), >-}; >-} // namespace > > class RtcEventLogEncoderTest : public testing::TestWithParam<int> { > protected: > RtcEventLogEncoderTest() >- : encoder_(new RtcEventLogEncoderLegacy), prng_(GetParam()) {} >+ : encoder_(new RtcEventLogEncoderLegacy), >+ seed_(GetParam()), >+ prng_(seed_), >+ gen_(seed_ * 880001UL) {} > ~RtcEventLogEncoderTest() override = default; > > // ANA events have some optional fields, so we want to make sure that we get >@@ -84,74 +56,57 @@ class RtcEventLogEncoderTest : public testing::TestWithParam<int> { > void TestRtcEventAudioNetworkAdaptation( > std::unique_ptr<AudioEncoderRuntimeConfig> runtime_config); > >- // These help prevent code duplication between incoming/outgoing variants. >- void TestRtcEventRtcpPacket(PacketDirection direction); >- void TestRtcEventRtpPacket(PacketDirection direction); >- >- int RandomInt() { >- // Don't run this on a SNES. >- static_assert(8 * sizeof(int) >= 32, "Don't run this on a SNES."); >- int32_t rand = prng_.Rand(0, std::numeric_limits<int32_t>::max()); >- return rtc::saturated_cast<int>(rand); >- } >- >- int RandomPositiveInt() { >- int32_t rand = prng_.Rand(1, std::numeric_limits<int32_t>::max()); >- return rtc::saturated_cast<int>(rand); >- } >- >- uint32_t RandomSsrc() { >- return prng_.Rand(std::numeric_limits<uint32_t>::max()); >- } >- >- std::vector<RtpExtension> RandomRtpExtensions() { >- RTC_DCHECK(arraysize(kExtensions) >= 2); >- size_t id_1 = prng_.Rand(0u, arraysize(kExtensions) - 1); >- size_t id_2 = prng_.Rand(0u, arraysize(kExtensions) - 2); >- if (id_2 == id_1) >- id_2 = arraysize(kExtensions) - 1; >- return std::vector<RtpExtension>{ >- RtpExtension(kExtensions[id_1].uri, kExtensions[id_1].type), >- RtpExtension(kExtensions[id_2].uri, kExtensions[id_2].type)}; >- } >- >- int RandomBitrate() { return RandomInt(); } >- >- // TODO(eladalon): Once we have more than once possible encoder, parameterize >+ std::deque<std::unique_ptr<RtcEvent>> history_; >+ // TODO(eladalon): Once we have more than one possible encoder, parameterize > // encoder selection. > std::unique_ptr<RtcEventLogEncoder> encoder_; >- ParsedRtcEventLog parsed_log_; >+ ParsedRtcEventLogNew parsed_log_; >+ const uint64_t seed_; > Random prng_; >+ test::EventGenerator gen_; > }; > >+TEST_P(RtcEventLogEncoderTest, RtcEventAlrState) { >+ std::unique_ptr<RtcEventAlrState> event = gen_.NewAlrState(); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& alr_state_events = parsed_log_.alr_state_events(); >+ >+ ASSERT_EQ(alr_state_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedAlrStateEvent(*event, alr_state_events[0])); >+} >+ > void RtcEventLogEncoderTest::TestRtcEventAudioNetworkAdaptation( > std::unique_ptr<AudioEncoderRuntimeConfig> runtime_config) { >+ // This function is called repeatedly. Clear state between calls. >+ history_.clear(); > auto original_runtime_config = *runtime_config; >- auto event = rtc::MakeUnique<RtcEventAudioNetworkAdaptation>( >+ auto event = absl::make_unique<RtcEventAudioNetworkAdaptation>( > std::move(runtime_config)); > const int64_t timestamp_us = event->timestamp_us_; >+ history_.push_back(std::move(event)); > >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT); >- >- AudioEncoderRuntimeConfig parsed_runtime_config; >- parsed_log_.GetAudioNetworkAdaptation(0, &parsed_runtime_config); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& ana_configs = parsed_log_.audio_network_adaptation_events(); >+ ASSERT_EQ(ana_configs.size(), 1u); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_runtime_config, original_runtime_config); >+ EXPECT_EQ(ana_configs[0].timestamp_us, timestamp_us); >+ EXPECT_EQ(ana_configs[0].config, original_runtime_config); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationBitrate) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >- const int bitrate_bps = RandomBitrate(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); >+ const int bitrate_bps = rtc::checked_cast<int>( >+ prng_.Rand(0, std::numeric_limits<int32_t>::max())); > runtime_config->bitrate_bps = bitrate_bps; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFrameLength) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > const int frame_length_ms = prng_.Rand(1, 1000); > runtime_config->frame_length_ms = frame_length_ms; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); >@@ -160,7 +115,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFrameLength) { > TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationPacketLoss) { > // To simplify the test, we just check powers of two. > const float plr = std::pow(0.5f, prng_.Rand(1, 8)); >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > runtime_config->uplink_packet_loss_fraction = plr; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); > } >@@ -169,7 +124,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationFec) { > // The test might be trivially passing for one of the two boolean values, so > // for safety's sake, we test both. > for (bool fec_enabled : {false, true}) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > runtime_config->enable_fec = fec_enabled; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); > } >@@ -179,7 +134,7 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationDtx) { > // The test might be trivially passing for one of the two boolean values, so > // for safety's sake, we test both. > for (bool dtx_enabled : {false, true}) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > runtime_config->enable_dtx = dtx_enabled; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); > } >@@ -189,20 +144,21 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationChannels) { > // The test might be trivially passing for one of the two possible values, so > // for safety's sake, we test both. > for (size_t channels : {1, 2}) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > runtime_config->num_channels = channels; > TestRtcEventAudioNetworkAdaptation(std::move(runtime_config)); > } > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationAll) { >- const int bitrate_bps = RandomBitrate(); >+ const int bitrate_bps = rtc::checked_cast<int>( >+ prng_.Rand(0, std::numeric_limits<int32_t>::max())); > const int frame_length_ms = prng_.Rand(1, 1000); > const float plr = std::pow(0.5f, prng_.Rand(1, 8)); > for (bool fec_enabled : {false, true}) { > for (bool dtx_enabled : {false, true}) { > for (size_t channels : {1, 2}) { >- auto runtime_config = rtc::MakeUnique<AudioEncoderRuntimeConfig>(); >+ auto runtime_config = absl::make_unique<AudioEncoderRuntimeConfig>(); > runtime_config->bitrate_bps = bitrate_bps; > runtime_config->frame_length_ms = frame_length_ms; > runtime_config->uplink_packet_loss_fraction = plr; >@@ -217,350 +173,268 @@ TEST_P(RtcEventLogEncoderTest, RtcEventAudioNetworkAdaptationAll) { > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioPlayout) { >- const uint32_t ssrc = RandomSsrc(); >- auto event = rtc::MakeUnique<RtcEventAudioPlayout>(ssrc); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT); >- >- uint32_t parsed_ssrc; >- parsed_log_.GetAudioPlayout(0, &parsed_ssrc); >- >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_ssrc, ssrc); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ std::unique_ptr<RtcEventAudioPlayout> event = gen_.NewAudioPlayout(ssrc); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ >+ const auto& playout_events = parsed_log_.audio_playout_events(); >+ ASSERT_EQ(playout_events.size(), 1u); >+ const auto playout_stream = playout_events.find(ssrc); >+ ASSERT_TRUE(playout_stream != playout_events.end()); >+ ASSERT_EQ(playout_stream->second.size(), 1u); >+ LoggedAudioPlayoutEvent playout_event = playout_stream->second[0]; >+ EXPECT_TRUE(test::VerifyLoggedAudioPlayoutEvent(*event, playout_event)); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioReceiveStreamConfig) { >- auto stream_config = rtc::MakeUnique<rtclog::StreamConfig>(); >- stream_config->local_ssrc = RandomSsrc(); >- stream_config->remote_ssrc = RandomSsrc(); >- // TODO(eladalon): Verify that the extensions are used correctly when >- // parsing RTP packets headers. Here and elsewhere. >- std::vector<RtpExtension> extensions = RandomRtpExtensions(); >- for (const auto& extension : extensions) >- stream_config->rtp_extensions.push_back(extension); >- >- auto original_stream_config = *stream_config; >- >- auto event = rtc::MakeUnique<RtcEventAudioReceiveStreamConfig>( >- std::move(stream_config)); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT); >- >- auto parsed_event = parsed_log_.GetAudioReceiveConfig(0); >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_event, original_stream_config); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ std::unique_ptr<RtcEventAudioReceiveStreamConfig> event = >+ gen_.NewAudioReceiveStreamConfig(ssrc, extensions); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& audio_recv_configs = parsed_log_.audio_recv_configs(); >+ >+ ASSERT_EQ(audio_recv_configs.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedAudioRecvConfig(*event, audio_recv_configs[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventAudioSendStreamConfig) { >- auto stream_config = rtc::MakeUnique<rtclog::StreamConfig>(); >- stream_config->local_ssrc = RandomSsrc(); >- std::vector<RtpExtension> extensions = RandomRtpExtensions(); >- for (const auto& extension : extensions) >- stream_config->rtp_extensions.push_back(extension); >- >- auto original_stream_config = *stream_config; >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ std::unique_ptr<RtcEventAudioSendStreamConfig> event = >+ gen_.NewAudioSendStreamConfig(ssrc, extensions); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& audio_send_configs = parsed_log_.audio_send_configs(); >+ >+ ASSERT_EQ(audio_send_configs.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedAudioSendConfig(*event, audio_send_configs[0])); >+} > >- auto event = >- rtc::MakeUnique<RtcEventAudioSendStreamConfig>(std::move(stream_config)); >- const int64_t timestamp_us = event->timestamp_us_; >+TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateDelayBased) { >+ std::unique_ptr<RtcEventBweUpdateDelayBased> event = >+ gen_.NewBweUpdateDelayBased(); >+ history_.push_back(event->Copy()); > >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& bwe_delay_updates = parsed_log_.bwe_delay_updates(); > >- auto parsed_event = parsed_log_.GetAudioSendConfig(0); >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_event, original_stream_config); >+ ASSERT_EQ(bwe_delay_updates.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedBweDelayBasedUpdate(*event, bwe_delay_updates[0])); > } > >-TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateDelayBased) { >- const int32_t bitrate_bps = RandomBitrate(); >- const BandwidthUsage detector_state = static_cast<BandwidthUsage>( >- prng_.Rand(0, static_cast<int32_t>(BandwidthUsage::kLast) - 1)); >- auto event = >- rtc::MakeUnique<RtcEventBweUpdateDelayBased>(bitrate_bps, detector_state); >- const int64_t timestamp_us = event->timestamp_us_; >+TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) { >+ std::unique_ptr<RtcEventBweUpdateLossBased> event = >+ gen_.NewBweUpdateLossBased(); >+ history_.push_back(event->Copy()); > >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& bwe_loss_updates = parsed_log_.bwe_loss_updates(); >+ >+ ASSERT_EQ(bwe_loss_updates.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedBweLossBasedUpdate(*event, bwe_loss_updates[0])); >+} > >- auto parsed_event = parsed_log_.GetDelayBasedBweUpdate(0); >+TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePairConfig) { >+ std::unique_ptr<RtcEventIceCandidatePairConfig> event = >+ gen_.NewIceCandidatePairConfig(); >+ history_.push_back(event->Copy()); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_event.bitrate_bps, bitrate_bps); >- EXPECT_EQ(parsed_event.detector_state, detector_state); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& ice_candidate_pair_configs = >+ parsed_log_.ice_candidate_pair_configs(); >+ >+ ASSERT_EQ(ice_candidate_pair_configs.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedIceCandidatePairConfig( >+ *event, ice_candidate_pair_configs[0])); > } > >-TEST_P(RtcEventLogEncoderTest, RtcEventBweUpdateLossBased) { >- const int32_t bitrate_bps = RandomBitrate(); >- const uint8_t fraction_loss = rtc::dchecked_cast<uint8_t>( >- prng_.Rand(0, std::numeric_limits<uint8_t>::max())); >- const int32_t total_packets = RandomInt(); >+TEST_P(RtcEventLogEncoderTest, RtcEventIceCandidatePair) { >+ std::unique_ptr<RtcEventIceCandidatePair> event = gen_.NewIceCandidatePair(); >+ history_.push_back(event->Copy()); > >- auto event = rtc::MakeUnique<RtcEventBweUpdateLossBased>( >- bitrate_bps, fraction_loss, total_packets); >- const int64_t timestamp_us = event->timestamp_us_; >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& ice_candidate_pair_events = >+ parsed_log_.ice_candidate_pair_events(); > >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE); >- >- int32_t parsed_bitrate_bps; >- uint8_t parsed_fraction_loss; >- int32_t parsed_total_packets; >- parsed_log_.GetLossBasedBweUpdate( >- 0, &parsed_bitrate_bps, &parsed_fraction_loss, &parsed_total_packets); >- >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_bitrate_bps, bitrate_bps); >- EXPECT_EQ(parsed_fraction_loss, fraction_loss); >- EXPECT_EQ(parsed_total_packets, total_packets); >+ ASSERT_EQ(ice_candidate_pair_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedIceCandidatePairEvent( >+ *event, ice_candidate_pair_events[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStarted) { > const int64_t timestamp_us = rtc::TimeMicros(); > > ASSERT_TRUE(parsed_log_.ParseString(encoder_->EncodeLogStart(timestamp_us))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::LOG_START); >+ const auto& start_log_events = parsed_log_.start_log_events(); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >+ ASSERT_EQ(start_log_events.size(), 1u); >+ EXPECT_EQ(start_log_events[0].timestamp_us, timestamp_us); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventLoggingStopped) { > const int64_t timestamp_us = rtc::TimeMicros(); > > ASSERT_TRUE(parsed_log_.ParseString(encoder_->EncodeLogEnd(timestamp_us))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::LOG_END); >+ const auto& stop_log_events = parsed_log_.stop_log_events(); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >+ ASSERT_EQ(stop_log_events.size(), 1u); >+ EXPECT_EQ(stop_log_events[0].timestamp_us, timestamp_us); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventProbeClusterCreated) { >- const int id = RandomPositiveInt(); >- const int bitrate_bps = RandomBitrate(); >- const int min_probes = RandomPositiveInt(); >- const int min_bytes = RandomPositiveInt(); >- >- auto event = rtc::MakeUnique<RtcEventProbeClusterCreated>( >- id, bitrate_bps, min_probes, min_bytes); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT); >- >- auto parsed_event = parsed_log_.GetBweProbeClusterCreated(0); >- >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.id), id); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.bitrate_bps), bitrate_bps); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.min_packets), min_probes); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.min_bytes), min_bytes); >+ std::unique_ptr<RtcEventProbeClusterCreated> event = >+ gen_.NewProbeClusterCreated(); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& bwe_probe_cluster_created_events = >+ parsed_log_.bwe_probe_cluster_created_events(); >+ >+ ASSERT_EQ(bwe_probe_cluster_created_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedBweProbeClusterCreatedEvent( >+ *event, bwe_probe_cluster_created_events[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultFailure) { >- const int id = RandomPositiveInt(); >- const ProbeFailureReason failure_reason = static_cast<ProbeFailureReason>( >- prng_.Rand(0, static_cast<int32_t>(ProbeFailureReason::kLast) - 1)); >- >- auto event = rtc::MakeUnique<RtcEventProbeResultFailure>(id, failure_reason); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT); >+ std::unique_ptr<RtcEventProbeResultFailure> event = >+ gen_.NewProbeResultFailure(); >+ history_.push_back(event->Copy()); > >- auto parsed_event = parsed_log_.GetBweProbeResult(0); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& bwe_probe_failure_events = parsed_log_.bwe_probe_failure_events(); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.id), id); >- ASSERT_FALSE(parsed_event.bitrate_bps); >- ASSERT_TRUE(parsed_event.failure_reason); >- EXPECT_EQ(parsed_event.failure_reason, failure_reason); >+ ASSERT_EQ(bwe_probe_failure_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedBweProbeFailureEvent( >+ *event, bwe_probe_failure_events[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventProbeResultSuccess) { >- const int id = RandomPositiveInt(); >- const int bitrate_bps = RandomBitrate(); >- >- auto event = rtc::MakeUnique<RtcEventProbeResultSuccess>(id, bitrate_bps); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT); >+ std::unique_ptr<RtcEventProbeResultSuccess> event = >+ gen_.NewProbeResultSuccess(); >+ history_.push_back(event->Copy()); > >- auto parsed_event = parsed_log_.GetBweProbeResult(0); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& bwe_probe_success_events = parsed_log_.bwe_probe_success_events(); > >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(rtc::dchecked_cast<int>(parsed_event.id), id); >- ASSERT_TRUE(parsed_event.bitrate_bps); >- EXPECT_EQ(parsed_event.bitrate_bps, bitrate_bps); >- ASSERT_FALSE(parsed_event.failure_reason); >+ ASSERT_EQ(bwe_probe_success_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedBweProbeSuccessEvent( >+ *event, bwe_probe_success_events[0])); > } > >-void RtcEventLogEncoderTest::TestRtcEventRtcpPacket(PacketDirection direction) { >- rtcp::Bye bye_packet; // Arbitrarily chosen RTCP packet type. >- bye_packet.SetReason("a man's reach should exceed his grasp"); >- auto rtcp_packet = bye_packet.Build(); >- >- std::unique_ptr<RtcEvent> event; >- if (direction == PacketDirection::kIncomingPacket) { >- event = rtc::MakeUnique<RtcEventRtcpPacketIncoming>(rtcp_packet); >- } else { >- event = rtc::MakeUnique<RtcEventRtcpPacketOutgoing>(rtcp_packet); >- } >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::RTCP_EVENT); >+TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketIncoming) { >+ std::unique_ptr<RtcEventRtcpPacketIncoming> event = >+ gen_.NewRtcpPacketIncoming(); >+ history_.push_back(event->Copy()); > >- PacketDirection parsed_direction; >- uint8_t parsed_packet[IP_PACKET_SIZE]; // "Parsed" = after event-encoding. >- size_t parsed_packet_length; >- parsed_log_.GetRtcpPacket(0, &parsed_direction, parsed_packet, >- &parsed_packet_length); >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& incoming_rtcp_packets = parsed_log_.incoming_rtcp_packets(); > >- EXPECT_EQ(parsed_direction, direction); >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- ASSERT_EQ(parsed_packet_length, rtcp_packet.size()); >- ASSERT_EQ(memcmp(parsed_packet, rtcp_packet.data(), parsed_packet_length), 0); >-} >- >-TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketIncoming) { >- TestRtcEventRtcpPacket(PacketDirection::kIncomingPacket); >+ ASSERT_EQ(incoming_rtcp_packets.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedRtcpPacketIncoming(*event, incoming_rtcp_packets[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventRtcpPacketOutgoing) { >- TestRtcEventRtcpPacket(PacketDirection::kOutgoingPacket); >-} >+ std::unique_ptr<RtcEventRtcpPacketOutgoing> event = >+ gen_.NewRtcpPacketOutgoing(); >+ history_.push_back(event->Copy()); > >-void RtcEventLogEncoderTest::TestRtcEventRtpPacket(PacketDirection direction) { >- const int probe_cluster_id = RandomPositiveInt(); >- >- std::unique_ptr<RtpPacketReceived> packet_received; >- std::unique_ptr<RtpPacketToSend> packet_to_send; >- RtpPacket* packet; >- if (direction == PacketDirection::kIncomingPacket) { >- packet_received = rtc::MakeUnique<RtpPacketReceived>(); >- packet = packet_received.get(); >- } else { >- packet_to_send = rtc::MakeUnique<RtpPacketToSend>(nullptr); >- packet = packet_to_send.get(); >- } >- packet->SetSsrc(RandomSsrc()); >- packet->SetSequenceNumber(static_cast<uint16_t>(RandomInt())); >- packet->SetPayloadSize(prng_.Rand(0u, 1000u)); >- // TODO(terelius): Add marker bit, capture timestamp, CSRCs, and header >- // extensions. >- >- std::unique_ptr<RtcEvent> event; >- if (direction == PacketDirection::kIncomingPacket) { >- event = rtc::MakeUnique<RtcEventRtpPacketIncoming>(*packet_received); >- } else { >- event = rtc::MakeUnique<RtcEventRtpPacketOutgoing>(*packet_to_send, >- probe_cluster_id); >- } >- const int64_t timestamp_us = event->timestamp_us_; >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& outgoing_rtcp_packets = parsed_log_.outgoing_rtcp_packets(); > >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), ParsedRtcEventLog::RTP_EVENT); >- >- PacketDirection parsed_direction; >- uint8_t parsed_rtp_header[IP_PACKET_SIZE]; >- size_t parsed_header_length; >- size_t parsed_total_length; >- int parsed_probe_cluster_id; >- parsed_log_.GetRtpHeader(0, &parsed_direction, parsed_rtp_header, >- &parsed_header_length, &parsed_total_length, >- &parsed_probe_cluster_id); >- >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_direction, direction); >- if (parsed_direction == PacketDirection::kOutgoingPacket) { >- EXPECT_EQ(parsed_probe_cluster_id, probe_cluster_id); >- } >- EXPECT_EQ(memcmp(parsed_rtp_header, packet->data(), parsed_header_length), 0); >- EXPECT_EQ(parsed_header_length, packet->headers_size()); >- EXPECT_EQ(parsed_total_length, packet->size()); >+ ASSERT_EQ(outgoing_rtcp_packets.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedRtcpPacketOutgoing(*event, outgoing_rtcp_packets[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketIncoming) { >- TestRtcEventRtpPacket(PacketDirection::kIncomingPacket); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extension_map; // TODO(terelius): Test extensions too. >+ std::unique_ptr<RtcEventRtpPacketIncoming> event = >+ gen_.NewRtpPacketIncoming(ssrc, extension_map); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& incoming_rtp_packets_by_ssrc = >+ parsed_log_.incoming_rtp_packets_by_ssrc(); >+ >+ ASSERT_EQ(incoming_rtp_packets_by_ssrc.size(), 1u); >+ const auto& stream = incoming_rtp_packets_by_ssrc[0]; >+ EXPECT_EQ(stream.ssrc, ssrc); >+ ASSERT_EQ(stream.incoming_packets.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedRtpPacketIncoming(*event, stream.incoming_packets[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventRtpPacketOutgoing) { >- TestRtcEventRtpPacket(PacketDirection::kOutgoingPacket); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extension_map; // TODO(terelius): Test extensions too. >+ std::unique_ptr<RtcEventRtpPacketOutgoing> event = >+ gen_.NewRtpPacketOutgoing(ssrc, extension_map); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& outgoing_rtp_packets_by_ssrc = >+ parsed_log_.outgoing_rtp_packets_by_ssrc(); >+ >+ ASSERT_EQ(outgoing_rtp_packets_by_ssrc.size(), 1u); >+ const auto& stream = outgoing_rtp_packets_by_ssrc[0]; >+ EXPECT_EQ(stream.ssrc, ssrc); >+ ASSERT_EQ(stream.outgoing_packets.size(), 1u); >+ EXPECT_TRUE( >+ test::VerifyLoggedRtpPacketOutgoing(*event, stream.outgoing_packets[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventVideoReceiveStreamConfig) { >- auto stream_config = rtc::MakeUnique<rtclog::StreamConfig>(); >- stream_config->local_ssrc = RandomSsrc(); >- stream_config->remote_ssrc = RandomSsrc(); >- stream_config->rtcp_mode = RtcpMode::kCompound; >- stream_config->remb = prng_.Rand<bool>(); >- std::vector<RtpExtension> extensions = RandomRtpExtensions(); >- for (const auto& extension : extensions) >- stream_config->rtp_extensions.push_back(extension); >- stream_config->codecs.emplace_back("CODEC", 122, 7); >- >- auto original_stream_config = *stream_config; >- >- auto event = rtc::MakeUnique<RtcEventVideoReceiveStreamConfig>( >- std::move(stream_config)); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT); >- >- auto parsed_event = parsed_log_.GetVideoReceiveConfig(0); >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_event, original_stream_config); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ std::unique_ptr<RtcEventVideoReceiveStreamConfig> event = >+ gen_.NewVideoReceiveStreamConfig(ssrc, extensions); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& video_recv_configs = parsed_log_.video_recv_configs(); >+ >+ ASSERT_EQ(video_recv_configs.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedVideoRecvConfig(*event, video_recv_configs[0])); > } > > TEST_P(RtcEventLogEncoderTest, RtcEventVideoSendStreamConfig) { >- auto stream_config = rtc::MakeUnique<rtclog::StreamConfig>(); >- stream_config->local_ssrc = RandomSsrc(); >- std::vector<RtpExtension> extensions = RandomRtpExtensions(); >- for (const auto& extension : extensions) >- stream_config->rtp_extensions.push_back(extension); >- stream_config->codecs.emplace_back("CODEC", 120, 3); >- >- auto original_stream_config = *stream_config; >- >- auto event = >- rtc::MakeUnique<RtcEventVideoSendStreamConfig>(std::move(stream_config)); >- const int64_t timestamp_us = event->timestamp_us_; >- >- ASSERT_TRUE(parsed_log_.ParseString(encoder_->Encode(*event))); >- ASSERT_EQ(parsed_log_.GetNumberOfEvents(), 1u); >- ASSERT_EQ(parsed_log_.GetEventType(0), >- ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT); >- >- auto parsed_event = parsed_log_.GetVideoSendConfig(0)[0]; >- EXPECT_EQ(parsed_log_.GetTimestamp(0), timestamp_us); >- EXPECT_EQ(parsed_event, original_stream_config); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ std::unique_ptr<RtcEventVideoSendStreamConfig> event = >+ gen_.NewVideoSendStreamConfig(ssrc, extensions); >+ history_.push_back(event->Copy()); >+ >+ std::string encoded = encoder_->EncodeBatch(history_.begin(), history_.end()); >+ ASSERT_TRUE(parsed_log_.ParseString(encoded)); >+ const auto& video_send_configs = parsed_log_.video_send_configs(); >+ >+ ASSERT_EQ(video_send_configs.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedVideoSendConfig(*event, video_send_configs[0])); > } > > INSTANTIATE_TEST_CASE_P(RandomSeeds, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event.h >index 6410698673d..21d6e48e0f5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event.h >@@ -11,7 +11,7 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_H_ > >-#include <typedefs.h> >+#include <memory> > > #include "rtc_base/timeutils.h" > >@@ -37,6 +37,8 @@ class RtcEvent { > AudioSendStreamConfig, > BweUpdateDelayBased, > BweUpdateLossBased, >+ IceCandidatePairConfig, >+ IceCandidatePairEvent, > ProbeClusterCreated, > ProbeResultFailure, > ProbeResultSuccess, >@@ -55,7 +57,12 @@ class RtcEvent { > > virtual bool IsConfigEvent() const = 0; > >+ virtual std::unique_ptr<RtcEvent> Copy() const = 0; >+ > const int64_t timestamp_us_; >+ >+ protected: >+ explicit RtcEvent(int64_t timestamp_us) : timestamp_us_(timestamp_us) {} > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc >index e329079c613..c1f1b395320 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.cc >@@ -9,11 +9,15 @@ > */ > > #include "logging/rtc_event_log/events/rtc_event_alr_state.h" >+#include "absl/memory/memory.h" > > namespace webrtc { > > RtcEventAlrState::RtcEventAlrState(bool in_alr) : in_alr_(in_alr) {} > >+RtcEventAlrState::RtcEventAlrState(const RtcEventAlrState& other) >+ : RtcEvent(other.timestamp_us_), in_alr_(other.in_alr_) {} >+ > RtcEventAlrState::~RtcEventAlrState() = default; > > RtcEvent::Type RtcEventAlrState::GetType() const { >@@ -24,4 +28,8 @@ bool RtcEventAlrState::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventAlrState::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventAlrState(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.h >index d07f3f2019b..e737c915e1d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_alr_state.h >@@ -11,9 +11,9 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ALR_STATE_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ALR_STATE_H_ > >-#include "logging/rtc_event_log/events/rtc_event.h" >+#include <memory> > >-#include "typedefs.h" // NOLINT(build/include) >+#include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { > >@@ -26,7 +26,12 @@ class RtcEventAlrState final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const bool in_alr_; >+ >+ private: >+ RtcEventAlrState(const RtcEventAlrState& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc >index 5ab7da67965..dcf2d7de592 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.cc >@@ -12,6 +12,7 @@ > > #include <utility> > >+#include "absl/memory/memory.h" > #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" > > namespace webrtc { >@@ -20,6 +21,11 @@ RtcEventAudioNetworkAdaptation::RtcEventAudioNetworkAdaptation( > std::unique_ptr<AudioEncoderRuntimeConfig> config) > : config_(std::move(config)) {} > >+RtcEventAudioNetworkAdaptation::RtcEventAudioNetworkAdaptation( >+ const RtcEventAudioNetworkAdaptation& other) >+ : RtcEvent(other.timestamp_us_), >+ config_(absl::make_unique<AudioEncoderRuntimeConfig>(*other.config_)) {} >+ > RtcEventAudioNetworkAdaptation::~RtcEventAudioNetworkAdaptation() = default; > > RtcEvent::Type RtcEventAudioNetworkAdaptation::GetType() const { >@@ -30,4 +36,8 @@ bool RtcEventAudioNetworkAdaptation::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventAudioNetworkAdaptation::Copy() const { >+ return absl::WrapUnique(new RtcEventAudioNetworkAdaptation(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h >index 9b39d24bfa6..65fbad8621d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h >@@ -29,7 +29,12 @@ class RtcEventAudioNetworkAdaptation final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const std::unique_ptr<const AudioEncoderRuntimeConfig> config_; >+ >+ private: >+ RtcEventAudioNetworkAdaptation(const RtcEventAudioNetworkAdaptation& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc >index 8378993acec..a9643ba868c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.cc >@@ -10,10 +10,15 @@ > > #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventAudioPlayout::RtcEventAudioPlayout(uint32_t ssrc) : ssrc_(ssrc) {} > >+RtcEventAudioPlayout::RtcEventAudioPlayout(const RtcEventAudioPlayout& other) >+ : RtcEvent(other.timestamp_us_), ssrc_(other.ssrc_) {} >+ > RtcEvent::Type RtcEventAudioPlayout::GetType() const { > return RtcEvent::Type::AudioPlayout; > } >@@ -22,4 +27,8 @@ bool RtcEventAudioPlayout::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventAudioPlayout::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventAudioPlayout(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h >index c74148109bd..3080f5b9f0e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_playout.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_PLAYOUT_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_AUDIO_PLAYOUT_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { >@@ -24,7 +26,12 @@ class RtcEventAudioPlayout final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const uint32_t ssrc_; >+ >+ private: >+ RtcEventAudioPlayout(const RtcEventAudioPlayout& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc >index 6bc9dc6b306..fee7c3c766c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.cc >@@ -12,6 +12,7 @@ > > #include <utility> > >+#include "absl/memory/memory.h" > #include "logging/rtc_event_log/rtc_stream_config.h" > > namespace webrtc { >@@ -20,6 +21,11 @@ RtcEventAudioReceiveStreamConfig::RtcEventAudioReceiveStreamConfig( > std::unique_ptr<rtclog::StreamConfig> config) > : config_(std::move(config)) {} > >+RtcEventAudioReceiveStreamConfig::RtcEventAudioReceiveStreamConfig( >+ const RtcEventAudioReceiveStreamConfig& other) >+ : RtcEvent(other.timestamp_us_), >+ config_(absl::make_unique<rtclog::StreamConfig>(*other.config_)) {} >+ > RtcEventAudioReceiveStreamConfig::~RtcEventAudioReceiveStreamConfig() = default; > > RtcEvent::Type RtcEventAudioReceiveStreamConfig::GetType() const { >@@ -30,4 +36,10 @@ bool RtcEventAudioReceiveStreamConfig::IsConfigEvent() const { > return true; > } > >+std::unique_ptr<RtcEvent> RtcEventAudioReceiveStreamConfig::Copy() const { >+ auto config_copy = absl::make_unique<rtclog::StreamConfig>(*config_); >+ return absl::WrapUnique<RtcEvent>( >+ new RtcEventAudioReceiveStreamConfig(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h >index ae79bbf44a4..27576503143 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h >@@ -31,7 +31,13 @@ class RtcEventAudioReceiveStreamConfig final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const std::unique_ptr<const rtclog::StreamConfig> config_; >+ >+ private: >+ RtcEventAudioReceiveStreamConfig( >+ const RtcEventAudioReceiveStreamConfig& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc >index de88bcad5c0..47939c7bdc3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.cc >@@ -12,6 +12,7 @@ > > #include <utility> > >+#include "absl/memory/memory.h" > #include "logging/rtc_event_log/rtc_stream_config.h" > > namespace webrtc { >@@ -20,6 +21,11 @@ RtcEventAudioSendStreamConfig::RtcEventAudioSendStreamConfig( > std::unique_ptr<rtclog::StreamConfig> config) > : config_(std::move(config)) {} > >+RtcEventAudioSendStreamConfig::RtcEventAudioSendStreamConfig( >+ const RtcEventAudioSendStreamConfig& other) >+ : RtcEvent(other.timestamp_us_), >+ config_(absl::make_unique<rtclog::StreamConfig>(*other.config_)) {} >+ > RtcEventAudioSendStreamConfig::~RtcEventAudioSendStreamConfig() = default; > > RtcEvent::Type RtcEventAudioSendStreamConfig::GetType() const { >@@ -30,4 +36,9 @@ bool RtcEventAudioSendStreamConfig::IsConfigEvent() const { > return true; > } > >+std::unique_ptr<RtcEvent> RtcEventAudioSendStreamConfig::Copy() const { >+ auto config_copy = absl::make_unique<rtclog::StreamConfig>(*config_); >+ return absl::WrapUnique<RtcEvent>(new RtcEventAudioSendStreamConfig(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h >index 44611f1e4b6..b248a619150 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h >@@ -31,7 +31,12 @@ class RtcEventAudioSendStreamConfig final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const std::unique_ptr<const rtclog::StreamConfig> config_; >+ >+ private: >+ RtcEventAudioSendStreamConfig(const RtcEventAudioSendStreamConfig& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc >index caf0f77c446..8c179712605 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.cc >@@ -10,6 +10,7 @@ > > #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" > >+#include "absl/memory/memory.h" > #include "modules/remote_bitrate_estimator/include/bwe_defines.h" > > namespace webrtc { >@@ -19,6 +20,12 @@ RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased( > BandwidthUsage detector_state) > : bitrate_bps_(bitrate_bps), detector_state_(detector_state) {} > >+RtcEventBweUpdateDelayBased::RtcEventBweUpdateDelayBased( >+ const RtcEventBweUpdateDelayBased& other) >+ : RtcEvent(other.timestamp_us_), >+ bitrate_bps_(other.bitrate_bps_), >+ detector_state_(other.detector_state_) {} >+ > RtcEventBweUpdateDelayBased::~RtcEventBweUpdateDelayBased() = default; > > RtcEvent::Type RtcEventBweUpdateDelayBased::GetType() const { >@@ -29,4 +36,8 @@ bool RtcEventBweUpdateDelayBased::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventBweUpdateDelayBased::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventBweUpdateDelayBased(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h >index b59b78cdcd9..3f47dc7f970 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_DELAY_BASED_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_DELAY_BASED_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { >@@ -27,8 +29,13 @@ class RtcEventBweUpdateDelayBased final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const int32_t bitrate_bps_; > const BandwidthUsage detector_state_; >+ >+ private: >+ RtcEventBweUpdateDelayBased(const RtcEventBweUpdateDelayBased& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc >index 5d11200e736..b0e72ddb0aa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.cc >@@ -10,6 +10,8 @@ > > #include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased(int32_t bitrate_bps, >@@ -19,6 +21,13 @@ RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased(int32_t bitrate_bps, > fraction_loss_(fraction_loss), > total_packets_(total_packets) {} > >+RtcEventBweUpdateLossBased::RtcEventBweUpdateLossBased( >+ const RtcEventBweUpdateLossBased& other) >+ : RtcEvent(other.timestamp_us_), >+ bitrate_bps_(other.bitrate_bps_), >+ fraction_loss_(other.fraction_loss_), >+ total_packets_(other.total_packets_) {} >+ > RtcEventBweUpdateLossBased::~RtcEventBweUpdateLossBased() = default; > > RtcEvent::Type RtcEventBweUpdateLossBased::GetType() const { >@@ -29,4 +38,8 @@ bool RtcEventBweUpdateLossBased::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventBweUpdateLossBased::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventBweUpdateLossBased(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h >index 474b9de0404..2d4ffda1b1e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_LOSS_BASED_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_BWE_UPDATE_LOSS_BASED_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { >@@ -26,9 +28,14 @@ class RtcEventBweUpdateLossBased final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const int32_t bitrate_bps_; > const uint8_t fraction_loss_; > const int32_t total_packets_; >+ >+ private: >+ RtcEventBweUpdateLossBased(const RtcEventBweUpdateLossBased& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc >new file mode 100644 >index 00000000000..fa32de68d5e >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.cc >@@ -0,0 +1,42 @@ >+/* >+ * Copyright (c) 2017 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 "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+ >+#include "absl/memory/memory.h" >+ >+namespace webrtc { >+ >+RtcEventIceCandidatePair::RtcEventIceCandidatePair( >+ IceCandidatePairEventType type, >+ uint32_t candidate_pair_id) >+ : type_(type), candidate_pair_id_(candidate_pair_id) {} >+ >+RtcEventIceCandidatePair::RtcEventIceCandidatePair( >+ const RtcEventIceCandidatePair& other) >+ : RtcEvent(other.timestamp_us_), >+ type_(other.type_), >+ candidate_pair_id_(other.candidate_pair_id_) {} >+ >+RtcEventIceCandidatePair::~RtcEventIceCandidatePair() = default; >+ >+RtcEvent::Type RtcEventIceCandidatePair::GetType() const { >+ return RtcEvent::Type::IceCandidatePairEvent; >+} >+ >+bool RtcEventIceCandidatePair::IsConfigEvent() const { >+ return false; >+} >+ >+std::unique_ptr<RtcEvent> RtcEventIceCandidatePair::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventIceCandidatePair(*this)); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h >new file mode 100644 >index 00000000000..f49a0d1792c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h >@@ -0,0 +1,50 @@ >+/* >+ * Copyright (c) 2017 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. >+ */ >+ >+#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ >+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ >+ >+#include <memory> >+ >+#include "logging/rtc_event_log/events/rtc_event.h" >+ >+namespace webrtc { >+ >+enum class IceCandidatePairEventType { >+ kCheckSent, >+ kCheckReceived, >+ kCheckResponseSent, >+ kCheckResponseReceived, >+ kNumValues, >+}; >+ >+class RtcEventIceCandidatePair final : public RtcEvent { >+ public: >+ RtcEventIceCandidatePair(IceCandidatePairEventType type, >+ uint32_t candidate_pair_id); >+ >+ ~RtcEventIceCandidatePair() override; >+ >+ Type GetType() const override; >+ >+ bool IsConfigEvent() const override; >+ >+ std::unique_ptr<RtcEvent> Copy() const override; >+ >+ const IceCandidatePairEventType type_; >+ const uint32_t candidate_pair_id_; >+ >+ private: >+ RtcEventIceCandidatePair(const RtcEventIceCandidatePair& other); >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc >new file mode 100644 >index 00000000000..f89de7740c7 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.cc >@@ -0,0 +1,71 @@ >+/* >+ * Copyright (c) 2017 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 "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" >+ >+#include "absl/memory/memory.h" >+ >+namespace webrtc { >+ >+IceCandidatePairDescription::IceCandidatePairDescription() { >+ local_candidate_type = IceCandidateType::kUnknown; >+ local_relay_protocol = IceCandidatePairProtocol::kUnknown; >+ local_network_type = IceCandidateNetworkType::kUnknown; >+ local_address_family = IceCandidatePairAddressFamily::kUnknown; >+ remote_candidate_type = IceCandidateType::kUnknown; >+ remote_address_family = IceCandidatePairAddressFamily::kUnknown; >+ candidate_pair_protocol = IceCandidatePairProtocol::kUnknown; >+} >+ >+IceCandidatePairDescription::IceCandidatePairDescription( >+ const IceCandidatePairDescription& other) { >+ local_candidate_type = other.local_candidate_type; >+ local_relay_protocol = other.local_relay_protocol; >+ local_network_type = other.local_network_type; >+ local_address_family = other.local_address_family; >+ remote_candidate_type = other.remote_candidate_type; >+ remote_address_family = other.remote_address_family; >+ candidate_pair_protocol = other.candidate_pair_protocol; >+} >+ >+IceCandidatePairDescription::~IceCandidatePairDescription() {} >+ >+RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig( >+ IceCandidatePairConfigType type, >+ uint32_t candidate_pair_id, >+ const IceCandidatePairDescription& candidate_pair_desc) >+ : type_(type), >+ candidate_pair_id_(candidate_pair_id), >+ candidate_pair_desc_(candidate_pair_desc) {} >+ >+RtcEventIceCandidatePairConfig::RtcEventIceCandidatePairConfig( >+ const RtcEventIceCandidatePairConfig& other) >+ : RtcEvent(other.timestamp_us_), >+ type_(other.type_), >+ candidate_pair_id_(other.candidate_pair_id_), >+ candidate_pair_desc_(other.candidate_pair_desc_) {} >+ >+RtcEventIceCandidatePairConfig::~RtcEventIceCandidatePairConfig() = default; >+ >+RtcEvent::Type RtcEventIceCandidatePairConfig::GetType() const { >+ return RtcEvent::Type::IceCandidatePairConfig; >+} >+ >+// The ICE candidate pair config event is not equivalent to a RtcEventLog config >+// event. >+bool RtcEventIceCandidatePairConfig::IsConfigEvent() const { >+ return false; >+} >+ >+std::unique_ptr<RtcEvent> RtcEventIceCandidatePairConfig::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventIceCandidatePairConfig(*this)); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h >new file mode 100644 >index 00000000000..1f6eb8ceb0f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h >@@ -0,0 +1,107 @@ >+/* >+ * Copyright (c) 2017 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. >+ */ >+ >+#ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ >+#define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ >+ >+#include <memory> >+ >+#include "logging/rtc_event_log/events/rtc_event.h" >+ >+namespace webrtc { >+ >+enum class IceCandidatePairConfigType { >+ kAdded, >+ kUpdated, >+ kDestroyed, >+ kSelected, >+ kNumValues, >+}; >+ >+// TODO(qingsi): Change the names of candidate types to "host", "srflx", "prflx" >+// and "relay" after the naming is spec-compliant in the signaling part >+enum class IceCandidateType { >+ kUnknown, >+ kLocal, >+ kStun, >+ kPrflx, >+ kRelay, >+ kNumValues, >+}; >+ >+enum class IceCandidatePairProtocol { >+ kUnknown, >+ kUdp, >+ kTcp, >+ kSsltcp, >+ kTls, >+ kNumValues, >+}; >+ >+enum class IceCandidatePairAddressFamily { >+ kUnknown, >+ kIpv4, >+ kIpv6, >+ kNumValues, >+}; >+ >+enum class IceCandidateNetworkType { >+ kUnknown, >+ kEthernet, >+ kLoopback, >+ kWifi, >+ kVpn, >+ kCellular, >+ kNumValues, >+}; >+ >+class IceCandidatePairDescription { >+ public: >+ IceCandidatePairDescription(); >+ explicit IceCandidatePairDescription( >+ const IceCandidatePairDescription& other); >+ >+ ~IceCandidatePairDescription(); >+ >+ IceCandidateType local_candidate_type; >+ IceCandidatePairProtocol local_relay_protocol; >+ IceCandidateNetworkType local_network_type; >+ IceCandidatePairAddressFamily local_address_family; >+ IceCandidateType remote_candidate_type; >+ IceCandidatePairAddressFamily remote_address_family; >+ IceCandidatePairProtocol candidate_pair_protocol; >+}; >+ >+class RtcEventIceCandidatePairConfig final : public RtcEvent { >+ public: >+ RtcEventIceCandidatePairConfig( >+ IceCandidatePairConfigType type, >+ uint32_t candidate_pair_id, >+ const IceCandidatePairDescription& candidate_pair_desc); >+ >+ ~RtcEventIceCandidatePairConfig() override; >+ >+ Type GetType() const override; >+ >+ bool IsConfigEvent() const override; >+ >+ std::unique_ptr<RtcEvent> Copy() const override; >+ >+ const IceCandidatePairConfigType type_; >+ const uint32_t candidate_pair_id_; >+ const IceCandidatePairDescription candidate_pair_desc_; >+ >+ private: >+ RtcEventIceCandidatePairConfig(const RtcEventIceCandidatePairConfig& other); >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_ICE_CANDIDATE_PAIR_CONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc >index d5dad741220..a60765dbd0f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.cc >@@ -10,17 +10,27 @@ > > #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > >-RtcEventProbeClusterCreated::RtcEventProbeClusterCreated(int id, >- int bitrate_bps, >- int min_probes, >- int min_bytes) >+RtcEventProbeClusterCreated::RtcEventProbeClusterCreated(int32_t id, >+ int32_t bitrate_bps, >+ uint32_t min_probes, >+ uint32_t min_bytes) > : id_(id), > bitrate_bps_(bitrate_bps), > min_probes_(min_probes), > min_bytes_(min_bytes) {} > >+RtcEventProbeClusterCreated::RtcEventProbeClusterCreated( >+ const RtcEventProbeClusterCreated& other) >+ : RtcEvent(other.timestamp_us_), >+ id_(other.id_), >+ bitrate_bps_(other.bitrate_bps_), >+ min_probes_(other.min_probes_), >+ min_bytes_(other.min_bytes_) {} >+ > RtcEvent::Type RtcEventProbeClusterCreated::GetType() const { > return RtcEvent::Type::ProbeClusterCreated; > } >@@ -29,4 +39,8 @@ bool RtcEventProbeClusterCreated::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventProbeClusterCreated::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventProbeClusterCreated(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h >index 938ba4f32ef..3e8c21f5c92 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_cluster_created.h >@@ -11,26 +11,33 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_CLUSTER_CREATED_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_CLUSTER_CREATED_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { > > class RtcEventProbeClusterCreated final : public RtcEvent { > public: >- RtcEventProbeClusterCreated(int id, >- int bitrate_bps, >- int min_probes, >- int min_bytes); >+ RtcEventProbeClusterCreated(int32_t id, >+ int32_t bitrate_bps, >+ uint32_t min_probes, >+ uint32_t min_bytes); > ~RtcEventProbeClusterCreated() override = default; > > Type GetType() const override; > > bool IsConfigEvent() const override; > >- const int id_; >- const int bitrate_bps_; >- const int min_probes_; >- const int min_bytes_; >+ std::unique_ptr<RtcEvent> Copy() const override; >+ >+ const int32_t id_; >+ const int32_t bitrate_bps_; >+ const uint32_t min_probes_; >+ const uint32_t min_bytes_; >+ >+ private: >+ RtcEventProbeClusterCreated(const RtcEventProbeClusterCreated& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc >index 1242ab825a3..aa6091ca775 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.cc >@@ -10,13 +10,21 @@ > > #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventProbeResultFailure::RtcEventProbeResultFailure( >- int id, >+ int32_t id, > ProbeFailureReason failure_reason) > : id_(id), failure_reason_(failure_reason) {} > >+RtcEventProbeResultFailure::RtcEventProbeResultFailure( >+ const RtcEventProbeResultFailure& other) >+ : RtcEvent(other.timestamp_us_), >+ id_(other.id_), >+ failure_reason_(other.failure_reason_) {} >+ > RtcEvent::Type RtcEventProbeResultFailure::GetType() const { > return RtcEvent::Type::ProbeResultFailure; > } >@@ -25,4 +33,8 @@ bool RtcEventProbeResultFailure::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventProbeResultFailure::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventProbeResultFailure(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h >index 90ef4dec515..181c6940370 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_failure.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_FAILURE_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_FAILURE_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { >@@ -24,15 +26,20 @@ enum class ProbeFailureReason { > > class RtcEventProbeResultFailure final : public RtcEvent { > public: >- RtcEventProbeResultFailure(int id, ProbeFailureReason failure_reason); >+ RtcEventProbeResultFailure(int32_t id, ProbeFailureReason failure_reason); > ~RtcEventProbeResultFailure() override = default; > > Type GetType() const override; > > bool IsConfigEvent() const override; > >- const int id_; >+ std::unique_ptr<RtcEvent> Copy() const override; >+ >+ const int32_t id_; > const ProbeFailureReason failure_reason_; >+ >+ private: >+ RtcEventProbeResultFailure(const RtcEventProbeResultFailure& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc >index f7b06fe28e9..55907295deb 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.cc >@@ -10,11 +10,20 @@ > > #include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > >-RtcEventProbeResultSuccess::RtcEventProbeResultSuccess(int id, int bitrate_bps) >+RtcEventProbeResultSuccess::RtcEventProbeResultSuccess(int32_t id, >+ int32_t bitrate_bps) > : id_(id), bitrate_bps_(bitrate_bps) {} > >+RtcEventProbeResultSuccess::RtcEventProbeResultSuccess( >+ const RtcEventProbeResultSuccess& other) >+ : RtcEvent(other.timestamp_us_), >+ id_(other.id_), >+ bitrate_bps_(other.bitrate_bps_) {} >+ > RtcEvent::Type RtcEventProbeResultSuccess::GetType() const { > return RtcEvent::Type::ProbeResultSuccess; > } >@@ -23,4 +32,8 @@ bool RtcEventProbeResultSuccess::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventProbeResultSuccess::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventProbeResultSuccess(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h >index f8f02164d64..15ff1833bf0 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_probe_result_success.h >@@ -11,21 +11,28 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_SUCCESS_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_PROBE_RESULT_SUCCESS_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > > namespace webrtc { > > class RtcEventProbeResultSuccess final : public RtcEvent { > public: >- RtcEventProbeResultSuccess(int id, int bitrate_bps); >+ RtcEventProbeResultSuccess(int32_t id, int32_t bitrate_bps); > ~RtcEventProbeResultSuccess() override = default; > > Type GetType() const override; > > bool IsConfigEvent() const override; > >- const int id_; >- const int bitrate_bps_; >+ std::unique_ptr<RtcEvent> Copy() const override; >+ >+ const int32_t id_; >+ const int32_t bitrate_bps_; >+ >+ private: >+ RtcEventProbeResultSuccess(const RtcEventProbeResultSuccess& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc >index 1f0765e40cc..119938c7f71 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.cc >@@ -10,12 +10,19 @@ > > #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventRtcpPacketIncoming::RtcEventRtcpPacketIncoming( > rtc::ArrayView<const uint8_t> packet) > : packet_(packet.data(), packet.size()) {} > >+RtcEventRtcpPacketIncoming::RtcEventRtcpPacketIncoming( >+ const RtcEventRtcpPacketIncoming& other) >+ : RtcEvent(other.timestamp_us_), >+ packet_(other.packet_.data(), other.packet_.size()) {} >+ > RtcEventRtcpPacketIncoming::~RtcEventRtcpPacketIncoming() = default; > > RtcEvent::Type RtcEventRtcpPacketIncoming::GetType() const { >@@ -26,4 +33,8 @@ bool RtcEventRtcpPacketIncoming::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventRtcpPacketIncoming::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventRtcpPacketIncoming(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h >index f7af462c101..6d904953a48 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_INCOMING_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_INCOMING_H_ > >+#include <memory> >+ > #include "api/array_view.h" > #include "logging/rtc_event_log/events/rtc_event.h" > #include "rtc_base/buffer.h" >@@ -26,7 +28,12 @@ class RtcEventRtcpPacketIncoming final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > rtc::Buffer packet_; >+ >+ private: >+ RtcEventRtcpPacketIncoming(const RtcEventRtcpPacketIncoming& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc >index b2dfaf08677..4085ac0f313 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.cc >@@ -10,12 +10,19 @@ > > #include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h" > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventRtcpPacketOutgoing::RtcEventRtcpPacketOutgoing( > rtc::ArrayView<const uint8_t> packet) > : packet_(packet.data(), packet.size()) {} > >+RtcEventRtcpPacketOutgoing::RtcEventRtcpPacketOutgoing( >+ const RtcEventRtcpPacketOutgoing& other) >+ : RtcEvent(other.timestamp_us_), >+ packet_(other.packet_.data(), other.packet_.size()) {} >+ > RtcEventRtcpPacketOutgoing::~RtcEventRtcpPacketOutgoing() = default; > > RtcEvent::Type RtcEventRtcpPacketOutgoing::GetType() const { >@@ -26,4 +33,8 @@ bool RtcEventRtcpPacketOutgoing::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventRtcpPacketOutgoing::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventRtcpPacketOutgoing(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h >index 2c38ae08785..3aa9e7199ad 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_OUTGOING_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTCP_PACKET_OUTGOING_H_ > >+#include <memory> >+ > #include "api/array_view.h" > #include "logging/rtc_event_log/events/rtc_event.h" > #include "rtc_base/buffer.h" >@@ -26,7 +28,12 @@ class RtcEventRtcpPacketOutgoing final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > rtc::Buffer packet_; >+ >+ private: >+ RtcEventRtcpPacketOutgoing(const RtcEventRtcpPacketOutgoing& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc >index e0dcec5e793..8e15d021751 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.cc >@@ -10,6 +10,7 @@ > > #include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h" > >+#include "absl/memory/memory.h" > #include "modules/rtp_rtcp/source/rtp_packet_received.h" > > namespace webrtc { >@@ -20,6 +21,12 @@ RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming( > header_.CopyHeaderFrom(packet); > } > >+RtcEventRtpPacketIncoming::RtcEventRtpPacketIncoming( >+ const RtcEventRtpPacketIncoming& other) >+ : RtcEvent(other.timestamp_us_), packet_length_(other.packet_length_) { >+ header_.CopyHeaderFrom(other.header_); >+} >+ > RtcEventRtpPacketIncoming::~RtcEventRtpPacketIncoming() = default; > > RtcEvent::Type RtcEventRtpPacketIncoming::GetType() const { >@@ -30,4 +37,8 @@ bool RtcEventRtpPacketIncoming::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventRtpPacketIncoming::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventRtpPacketIncoming(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h >index 4aaf86f289b..6b141b6d576 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_INCOMING_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_INCOMING_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > #include "modules/rtp_rtcp/source/rtp_packet.h" > >@@ -27,8 +29,13 @@ class RtcEventRtpPacketIncoming final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > RtpPacket header_; // Only the packet's header will be stored here. > const size_t packet_length_; // Length before stripping away all but header. >+ >+ private: >+ RtcEventRtpPacketIncoming(const RtcEventRtpPacketIncoming& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc >index 207f76a511d..103440ad6e9 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.cc >@@ -10,6 +10,7 @@ > > #include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" > >+#include "absl/memory/memory.h" > #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" > > namespace webrtc { >@@ -21,6 +22,14 @@ RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing( > header_.CopyHeaderFrom(packet); > } > >+RtcEventRtpPacketOutgoing::RtcEventRtpPacketOutgoing( >+ const RtcEventRtpPacketOutgoing& other) >+ : RtcEvent(other.timestamp_us_), >+ packet_length_(other.packet_length_), >+ probe_cluster_id_(other.probe_cluster_id_) { >+ header_.CopyHeaderFrom(other.header_); >+} >+ > RtcEventRtpPacketOutgoing::~RtcEventRtpPacketOutgoing() = default; > > RtcEvent::Type RtcEventRtpPacketOutgoing::GetType() const { >@@ -31,4 +40,8 @@ bool RtcEventRtpPacketOutgoing::IsConfigEvent() const { > return false; > } > >+std::unique_ptr<RtcEvent> RtcEventRtpPacketOutgoing::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventRtpPacketOutgoing(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h >index 898cdce40ed..171a21c420e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h >@@ -11,6 +11,8 @@ > #ifndef LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_OUTGOING_H_ > #define LOGGING_RTC_EVENT_LOG_EVENTS_RTC_EVENT_RTP_PACKET_OUTGOING_H_ > >+#include <memory> >+ > #include "logging/rtc_event_log/events/rtc_event.h" > #include "modules/rtp_rtcp/source/rtp_packet.h" > >@@ -28,9 +30,14 @@ class RtcEventRtpPacketOutgoing final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > RtpPacket header_; // Only the packet's header will be stored here. > const size_t packet_length_; // Length before stripping away all but header. > const int probe_cluster_id_; >+ >+ private: >+ RtcEventRtpPacketOutgoing(const RtcEventRtpPacketOutgoing& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc >index 514974b2ec5..7f4dd9b7b80 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.cc >@@ -12,12 +12,19 @@ > > #include <utility> > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventVideoReceiveStreamConfig::RtcEventVideoReceiveStreamConfig( > std::unique_ptr<rtclog::StreamConfig> config) > : config_(std::move(config)) {} > >+RtcEventVideoReceiveStreamConfig::RtcEventVideoReceiveStreamConfig( >+ const RtcEventVideoReceiveStreamConfig& other) >+ : RtcEvent(other.timestamp_us_), >+ config_(absl::make_unique<rtclog::StreamConfig>(*other.config_)) {} >+ > RtcEventVideoReceiveStreamConfig::~RtcEventVideoReceiveStreamConfig() = default; > > RtcEvent::Type RtcEventVideoReceiveStreamConfig::GetType() const { >@@ -28,4 +35,9 @@ bool RtcEventVideoReceiveStreamConfig::IsConfigEvent() const { > return true; > } > >+std::unique_ptr<RtcEvent> RtcEventVideoReceiveStreamConfig::Copy() const { >+ return absl::WrapUnique<RtcEvent>( >+ new RtcEventVideoReceiveStreamConfig(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h >index 1d470e50ce3..c6263c3fdbe 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h >@@ -28,7 +28,13 @@ class RtcEventVideoReceiveStreamConfig final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const std::unique_ptr<const rtclog::StreamConfig> config_; >+ >+ private: >+ RtcEventVideoReceiveStreamConfig( >+ const RtcEventVideoReceiveStreamConfig& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc >index 9bb2b5e38e8..b4b78a8a52a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.cc >@@ -12,12 +12,19 @@ > > #include <utility> > >+#include "absl/memory/memory.h" >+ > namespace webrtc { > > RtcEventVideoSendStreamConfig::RtcEventVideoSendStreamConfig( > std::unique_ptr<rtclog::StreamConfig> config) > : config_(std::move(config)) {} > >+RtcEventVideoSendStreamConfig::RtcEventVideoSendStreamConfig( >+ const RtcEventVideoSendStreamConfig& other) >+ : RtcEvent(other.timestamp_us_), >+ config_(absl::make_unique<rtclog::StreamConfig>(*other.config_)) {} >+ > RtcEventVideoSendStreamConfig::~RtcEventVideoSendStreamConfig() = default; > > RtcEvent::Type RtcEventVideoSendStreamConfig::GetType() const { >@@ -28,4 +35,8 @@ bool RtcEventVideoSendStreamConfig::IsConfigEvent() const { > return true; > } > >+std::unique_ptr<RtcEvent> RtcEventVideoSendStreamConfig::Copy() const { >+ return absl::WrapUnique<RtcEvent>(new RtcEventVideoSendStreamConfig(*this)); >+} >+ > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h >index 97bdba9613b..3472f8855be 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/events/rtc_event_video_send_stream_config.h >@@ -28,7 +28,12 @@ class RtcEventVideoSendStreamConfig final : public RtcEvent { > > bool IsConfigEvent() const override; > >+ std::unique_ptr<RtcEvent> Copy() const override; >+ > const std::unique_ptr<const rtclog::StreamConfig> config_; >+ >+ private: >+ RtcEventVideoSendStreamConfig(const RtcEventVideoSendStreamConfig& other); > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.cc >new file mode 100644 >index 00000000000..55f4b582c78 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.cc >@@ -0,0 +1,41 @@ >+/* >+ * Copyright (c) 2018 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 "logging/rtc_event_log/fake_rtc_event_log.h" >+ >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "rtc_base/bind.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/logging.h" >+ >+namespace webrtc { >+ >+FakeRtcEventLog::FakeRtcEventLog(rtc::Thread* thread) : thread_(thread) { >+ RTC_DCHECK(thread_); >+} >+FakeRtcEventLog::~FakeRtcEventLog() = default; >+ >+bool FakeRtcEventLog::StartLogging(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) { >+ return true; >+} >+ >+void FakeRtcEventLog::StopLogging() { >+ invoker_.Flush(thread_); >+} >+ >+void FakeRtcEventLog::Log(std::unique_ptr<RtcEvent> event) { >+ RtcEvent::Type rtc_event_type = event->GetType(); >+ invoker_.AsyncInvoke<void>( >+ RTC_FROM_HERE, thread_, >+ rtc::Bind(&FakeRtcEventLog::IncrementEventCount, this, rtc_event_type)); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.h >new file mode 100644 >index 00000000000..c5ea08aa690 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log.h >@@ -0,0 +1,43 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_H_ >+#define LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_H_ >+ >+#include <map> >+#include <memory> >+ >+#include "logging/rtc_event_log/events/rtc_event.h" >+#include "logging/rtc_event_log/rtc_event_log.h" >+#include "rtc_base/asyncinvoker.h" >+#include "rtc_base/thread.h" >+ >+namespace webrtc { >+ >+class FakeRtcEventLog : public RtcEventLog { >+ public: >+ explicit FakeRtcEventLog(rtc::Thread* thread); >+ ~FakeRtcEventLog() override; >+ bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) override; >+ void StopLogging() override; >+ void Log(std::unique_ptr<RtcEvent> event) override; >+ int GetEventCount(RtcEvent::Type event_type) { return count_[event_type]; } >+ >+ private: >+ void IncrementEventCount(RtcEvent::Type event_type) { ++count_[event_type]; } >+ std::map<RtcEvent::Type, int> count_; >+ rtc::Thread* thread_; >+ rtc::AsyncInvoker invoker_; >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc >new file mode 100644 >index 00000000000..b3f638cbb4d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.cc >@@ -0,0 +1,34 @@ >+/* >+ * Copyright 2018 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 "logging/rtc_event_log/fake_rtc_event_log_factory.h" >+ >+#include <utility> >+ >+#include "logging/rtc_event_log/rtc_event_log.h" >+ >+namespace webrtc { >+ >+std::unique_ptr<RtcEventLog> FakeRtcEventLogFactory::CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type) { >+ std::unique_ptr<RtcEventLog> fake_event_log(new FakeRtcEventLog(thread())); >+ last_log_created_ = fake_event_log.get(); >+ return fake_event_log; >+} >+ >+std::unique_ptr<RtcEventLog> FakeRtcEventLogFactory::CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) { >+ std::unique_ptr<RtcEventLog> fake_event_log(new FakeRtcEventLog(thread())); >+ last_log_created_ = fake_event_log.get(); >+ return fake_event_log; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h >new file mode 100644 >index 00000000000..1160e5464c6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/fake_rtc_event_log_factory.h >@@ -0,0 +1,44 @@ >+/* >+ * Copyright 2018 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. >+ */ >+ >+#ifndef LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_FACTORY_H_ >+#define LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_FACTORY_H_ >+ >+#include <memory> >+ >+#include "logging/rtc_event_log/fake_rtc_event_log.h" >+#include "logging/rtc_event_log/rtc_event_log_factory_interface.h" >+#include "rtc_base/thread.h" >+ >+namespace webrtc { >+ >+class FakeRtcEventLogFactory : public RtcEventLogFactoryInterface { >+ public: >+ explicit FakeRtcEventLogFactory(rtc::Thread* thread) : thread_(thread) {} >+ ~FakeRtcEventLogFactory() override {} >+ >+ std::unique_ptr<RtcEventLog> CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type) override; >+ >+ std::unique_ptr<RtcEventLog> CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) override; >+ >+ webrtc::RtcEventLog* last_log_created() { return last_log_created_; } >+ rtc::Thread* thread() { return thread_; } >+ >+ private: >+ webrtc::RtcEventLog* last_log_created_; >+ rtc::Thread* thread_; >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_FAKE_RTC_EVENT_LOG_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.cc >new file mode 100644 >index 00000000000..5f91c5e7bdb >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.cc >@@ -0,0 +1,50 @@ >+/* >+ * Copyright (c) 2017 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 "logging/rtc_event_log/icelogger.h" >+ >+#include "absl/memory/memory.h" >+#include "logging/rtc_event_log/rtc_event_log.h" >+ >+namespace webrtc { >+ >+IceEventLog::IceEventLog() {} >+IceEventLog::~IceEventLog() {} >+ >+void IceEventLog::LogCandidatePairConfig( >+ IceCandidatePairConfigType type, >+ uint32_t candidate_pair_id, >+ const IceCandidatePairDescription& candidate_pair_desc) { >+ if (event_log_ == nullptr) { >+ return; >+ } >+ candidate_pair_desc_by_id_[candidate_pair_id] = candidate_pair_desc; >+ event_log_->Log(absl::make_unique<RtcEventIceCandidatePairConfig>( >+ type, candidate_pair_id, candidate_pair_desc)); >+} >+ >+void IceEventLog::LogCandidatePairEvent(IceCandidatePairEventType type, >+ uint32_t candidate_pair_id) { >+ if (event_log_ == nullptr) { >+ return; >+ } >+ event_log_->Log( >+ absl::make_unique<RtcEventIceCandidatePair>(type, candidate_pair_id)); >+} >+ >+void IceEventLog::DumpCandidatePairDescriptionToMemoryAsConfigEvents() const { >+ for (const auto& desc_id_pair : candidate_pair_desc_by_id_) { >+ event_log_->Log(absl::make_unique<RtcEventIceCandidatePairConfig>( >+ IceCandidatePairConfigType::kUpdated, desc_id_pair.first, >+ desc_id_pair.second)); >+ } >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.h >new file mode 100644 >index 00000000000..b590fd7cb32 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/icelogger.h >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (c) 2017 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. >+ */ >+ >+#ifndef LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ >+#define LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ >+ >+#include <unordered_map> >+ >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" >+ >+namespace webrtc { >+ >+class RtcEventLog; >+ >+// IceEventLog wraps RtcEventLog and provides structural logging of ICE-specific >+// events. The logged events are serialized with other RtcEvent's if protobuf is >+// enabled in the build. >+class IceEventLog { >+ public: >+ IceEventLog(); >+ ~IceEventLog(); >+ >+ void set_event_log(RtcEventLog* event_log) { event_log_ = event_log; } >+ >+ void LogCandidatePairConfig( >+ IceCandidatePairConfigType type, >+ uint32_t candidate_pair_id, >+ const IceCandidatePairDescription& candidate_pair_desc); >+ >+ void LogCandidatePairEvent(IceCandidatePairEventType type, >+ uint32_t candidate_pair_id); >+ >+ // This method constructs a config event for each candidate pair with their >+ // description and logs these config events. It is intended to be called when >+ // logging starts to ensure that we have at least one config for each >+ // candidate pair id. >+ void DumpCandidatePairDescriptionToMemoryAsConfigEvents() const; >+ >+ private: >+ RtcEventLog* event_log_ = nullptr; >+ std::unordered_map<uint32_t, IceCandidatePairDescription> >+ candidate_pair_desc_by_id_; >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_ICELOGGER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/video_capture/test/video_capture_main_mac.mm b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc >similarity index 56% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/modules/video_capture/test/video_capture_main_mac.mm >rename to Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc >index 680160fb9fb..240a4f66939 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/modules/video_capture/test/video_capture_main_mac.mm >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.cc >@@ -1,5 +1,5 @@ > /* >- * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. >+ * Copyright (c) 2018 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 >@@ -8,10 +8,11 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "test/gtest.h" >-#include "test/testsupport/mac/run_threaded_main_mac.h" >+#include "logging/rtc_event_log/mock/mock_rtc_event_log.h" > >-int ImplementThisToRunYourTest(int argc, char** argv) { >- testing::InitGoogleTest(&argc, argv); >- return RUN_ALL_TESTS(); >-} >+namespace webrtc { >+ >+MockRtcEventLog::MockRtcEventLog() = default; >+MockRtcEventLog::~MockRtcEventLog() = default; >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h >index 6f69169eff8..44207ff2baf 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/mock/mock_rtc_event_log.h >@@ -20,6 +20,9 @@ namespace webrtc { > > class MockRtcEventLog : public RtcEventLog { > public: >+ MockRtcEventLog(); >+ ~MockRtcEventLog(); >+ > virtual bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, > int64_t output_period_ms) { > return StartLoggingProxy(output.get(), output_period_ms); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/output/rtc_event_log_output_file_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/output/rtc_event_log_output_file_unittest.cc >index a2a02049614..c42a7111488 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/output/rtc_event_log_output_file_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/output/rtc_event_log_output_file_unittest.cc >@@ -8,12 +8,14 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include "logging/rtc_event_log/output/rtc_event_log_output_file.h" >+ > #include <fstream> > #include <memory> > #include <string> > >-#include "logging/rtc_event_log/output/rtc_event_log_output_file.h" >-#include "rtc_base/ptr_util.h" >+#include "absl/memory/memory.h" >+#include "rtc_base/checks.h" > #include "test/gtest.h" > #include "test/testsupport/fileutils.h" > >@@ -49,13 +51,14 @@ class RtcEventLogOutputFileTest : public ::testing::Test { > }; > > TEST_F(RtcEventLogOutputFileTest, NonDefectiveOutputsStartOutActive) { >- auto output_file = rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_); >+ auto output_file = >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_); > EXPECT_TRUE(output_file->IsActive()); > } > > TEST_F(RtcEventLogOutputFileTest, DefectiveOutputsStartOutInactive) { > const std::string illegal_filename = "/////////"; >- auto output_file = rtc::MakeUnique<RtcEventLogOutputFile>(illegal_filename); >+ auto output_file = absl::make_unique<RtcEventLogOutputFile>(illegal_filename); > EXPECT_FALSE(output_file->IsActive()); > } > >@@ -63,7 +66,8 @@ TEST_F(RtcEventLogOutputFileTest, DefectiveOutputsStartOutInactive) { > TEST_F(RtcEventLogOutputFileTest, UnlimitedOutputFile) { > const std::string output_str = "one two three"; > >- auto output_file = rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_); >+ auto output_file = >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_); > output_file->Write(output_str); > output_file.reset(); // Closing the file flushes the buffer to disk. > >@@ -74,7 +78,7 @@ TEST_F(RtcEventLogOutputFileTest, UnlimitedOutputFile) { > TEST_F(RtcEventLogOutputFileTest, LimitedOutputFileCappedToCapacity) { > // Fit two bytes, then the third should be rejected. > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, 2); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); > > output_file->Write("1"); > output_file->Write("2"); >@@ -94,7 +98,7 @@ TEST_F(RtcEventLogOutputFileTest, DoNotWritePartialLines) { > // Set a file size limit just shy of fitting the entire second line. > const size_t size_limit = output_str_1.length() + output_str_2.length() - 1; > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, size_limit); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, size_limit); > > output_file->Write(output_str_1); > output_file->Write(output_str_2); >@@ -105,20 +109,20 @@ TEST_F(RtcEventLogOutputFileTest, DoNotWritePartialLines) { > > TEST_F(RtcEventLogOutputFileTest, UnsuccessfulWriteReturnsFalse) { > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, 2); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); > EXPECT_FALSE(output_file->Write("abc")); > } > > TEST_F(RtcEventLogOutputFileTest, SuccessfulWriteReturnsTrue) { > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, 3); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, 3); > EXPECT_TRUE(output_file->Write("abc")); > } > > // Even if capacity is reached, a successful write leaves the output active. > TEST_F(RtcEventLogOutputFileTest, FileStillActiveAfterSuccessfulWrite) { > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, 3); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, 3); > ASSERT_TRUE(output_file->Write("abc")); > EXPECT_TRUE(output_file->IsActive()); > } >@@ -127,19 +131,18 @@ TEST_F(RtcEventLogOutputFileTest, FileStillActiveAfterSuccessfulWrite) { > // not yet been reached. > TEST_F(RtcEventLogOutputFileTest, FileInactiveAfterUnsuccessfulWrite) { > auto output_file = >- rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, 2); >+ absl::make_unique<RtcEventLogOutputFile>(output_file_name_, 2); > ASSERT_FALSE(output_file->Write("abc")); > EXPECT_FALSE(output_file->IsActive()); > } > > TEST_F(RtcEventLogOutputFileTest, AllowReasonableFileSizeLimits) { >- auto output_file = rtc::MakeUnique<RtcEventLogOutputFile>( >+ auto output_file = absl::make_unique<RtcEventLogOutputFile>( > output_file_name_, RtcEventLogOutputFile::kMaxReasonableFileSize); > EXPECT_TRUE(output_file->IsActive()); > } > > #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) >-#if !defined(WEBRTC_USE_MEMCHECK) // Crashing expected to leak memory. > TEST_F(RtcEventLogOutputFileTest, WritingToInactiveFileForbidden) { > RtcEventLogOutputFile output_file(output_file_name_, 2); > ASSERT_FALSE(output_file.Write("abc")); >@@ -154,12 +157,11 @@ TEST_F(RtcEventLogOutputFileTest, DisallowUnreasonableFileSizeLimits) { > auto create_output_file = [&] { > const size_t unreasonable_size = > RtcEventLogOutputFile::kMaxReasonableFileSize + 1; >- output_file = rtc::MakeUnique<RtcEventLogOutputFile>(output_file_name_, >- unreasonable_size); >+ output_file = absl::make_unique<RtcEventLogOutputFile>(output_file_name_, >+ unreasonable_size); > }; > EXPECT_DEATH(create_output_file(), ""); > } >-#endif // !WEBRTC_USE_MEMCHECK > #endif > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.cc >index 2173590662d..73a598d6b1e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.cc >@@ -1,5 +1,5 @@ > /* >- * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. >+ * Copyright (c) 2018 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 >@@ -10,371 +10,12 @@ > > #include "logging/rtc_event_log/rtc_event_log.h" > >-#include <atomic> >-#include <deque> >-#include <functional> >-#include <limits> >-#include <memory> >-#include <utility> >-#include <vector> >- >-#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h" >-#include "logging/rtc_event_log/output/rtc_event_log_output_file.h" >-#include "rtc_base/checks.h" >-#include "rtc_base/constructormagic.h" >-#include "rtc_base/event.h" >-#include "rtc_base/logging.h" >-#include "rtc_base/numerics/safe_conversions.h" >-#include "rtc_base/numerics/safe_minmax.h" >-#include "rtc_base/ptr_util.h" >-#include "rtc_base/sequenced_task_checker.h" >-#include "rtc_base/task_queue.h" >-#include "rtc_base/thread_annotations.h" >- > namespace webrtc { > >-#ifdef ENABLE_RTC_EVENT_LOG >- >-namespace { >-constexpr size_t kMaxEventsInHistory = 10000; >-// The config-history is supposed to be unbounded, but needs to have some bound >-// to prevent an attack via unreasonable memory use. >-constexpr size_t kMaxEventsInConfigHistory = 1000; >- >-// Observe a limit on the number of concurrent logs, so as not to run into >-// OS-imposed limits on open files and/or threads/task-queues. >-// TODO(eladalon): Known issue - there's a race over |rtc_event_log_count|. >-std::atomic<int> rtc_event_log_count(0); >- >-// TODO(eladalon): This class exists because C++11 doesn't allow transferring a >-// unique_ptr to a lambda (a copy constructor is required). We should get >-// rid of this when we move to C++14. >-template <typename T> >-class ResourceOwningTask final : public rtc::QueuedTask { >- public: >- ResourceOwningTask(std::unique_ptr<T> resource, >- std::function<void(std::unique_ptr<T>)> handler) >- : resource_(std::move(resource)), handler_(handler) {} >- >- bool Run() override { >- handler_(std::move(resource_)); >- return true; >- } >- >- private: >- std::unique_ptr<T> resource_; >- std::function<void(std::unique_ptr<T>)> handler_; >-}; >- >-std::unique_ptr<RtcEventLogEncoder> CreateEncoder( >- RtcEventLog::EncodingType type) { >- switch (type) { >- case RtcEventLog::EncodingType::Legacy: >- return rtc::MakeUnique<RtcEventLogEncoderLegacy>(); >- default: >- RTC_LOG(LS_ERROR) << "Unknown RtcEventLog encoder type (" << int(type) >- << ")"; >- RTC_NOTREACHED(); >- return std::unique_ptr<RtcEventLogEncoder>(nullptr); >- } >-} >- >-class RtcEventLogImpl final : public RtcEventLog { >- public: >- explicit RtcEventLogImpl(std::unique_ptr<RtcEventLogEncoder> event_encoder); >- ~RtcEventLogImpl() override; >- >- // TODO(eladalon): We should change these name to reflect that what we're >- // actually starting/stopping is the output of the log, not the log itself. >- bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, >- int64_t output_period_ms) override; >- void StopLogging() override; >- >- void Log(std::unique_ptr<RtcEvent> event) override; >- >- private: >- void LogToMemory(std::unique_ptr<RtcEvent> event) RTC_RUN_ON(&task_queue_); >- void LogEventsFromMemoryToOutput() RTC_RUN_ON(&task_queue_); >- >- void StopOutput() RTC_RUN_ON(&task_queue_); >- >- void WriteConfigsAndHistoryToOutput(const std::string& encoded_configs, >- const std::string& encoded_history) >- RTC_RUN_ON(&task_queue_); >- void WriteToOutput(const std::string& output_string) RTC_RUN_ON(&task_queue_); >- >- void StopLoggingInternal() RTC_RUN_ON(&task_queue_); >- >- void ScheduleOutput() RTC_RUN_ON(&task_queue_); >- >- // Make sure that the event log is "managed" - created/destroyed, as well >- // as started/stopped - from the same thread/task-queue. >- rtc::SequencedTaskChecker owner_sequence_checker_; >- >- // History containing all past configuration events. >- std::deque<std::unique_ptr<RtcEvent>> config_history_ >- RTC_ACCESS_ON(task_queue_); >- >- // History containing the most recent (non-configuration) events (~10s). >- std::deque<std::unique_ptr<RtcEvent>> history_ RTC_ACCESS_ON(task_queue_); >- >- size_t max_size_bytes_ RTC_ACCESS_ON(task_queue_); >- size_t written_bytes_ RTC_ACCESS_ON(task_queue_); >- >- std::unique_ptr<RtcEventLogEncoder> event_encoder_ RTC_ACCESS_ON(task_queue_); >- std::unique_ptr<RtcEventLogOutput> event_output_ RTC_ACCESS_ON(task_queue_); >- >- size_t num_config_events_written_ RTC_ACCESS_ON(task_queue_); >- int64_t output_period_ms_ RTC_ACCESS_ON(task_queue_); >- int64_t last_output_ms_ RTC_ACCESS_ON(task_queue_); >- bool output_scheduled_ RTC_ACCESS_ON(task_queue_); >- >- // Since we are posting tasks bound to |this|, it is critical that the event >- // log and it's members outlive the |task_queue_|. Keep the "task_queue_| >- // last to ensure it destructs first, or else tasks living on the queue might >- // access other members after they've been torn down. >- rtc::TaskQueue task_queue_; >- >- RTC_DISALLOW_COPY_AND_ASSIGN(RtcEventLogImpl); >-}; >- >-RtcEventLogImpl::RtcEventLogImpl( >- std::unique_ptr<RtcEventLogEncoder> event_encoder) >- : max_size_bytes_(std::numeric_limits<decltype(max_size_bytes_)>::max()), >- written_bytes_(0), >- event_encoder_(std::move(event_encoder)), >- num_config_events_written_(0), >- output_period_ms_(kImmediateOutput), >- last_output_ms_(rtc::TimeMillis()), >- output_scheduled_(false), >- task_queue_("rtc_event_log") {} >- >-RtcEventLogImpl::~RtcEventLogImpl() { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >- >- // If we're logging to the output, this will stop that. Blocking function. >- StopLogging(); >- >- int count = std::atomic_fetch_sub(&rtc_event_log_count, 1) - 1; >- RTC_DCHECK_GE(count, 0); >-} >- >-bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output, >- int64_t output_period_ms) { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >- >- RTC_DCHECK(output_period_ms == kImmediateOutput || output_period_ms > 0); >- >- if (!output->IsActive()) { >- // TODO(eladalon): We may want to remove the IsActive method. Otherwise >- // we probably want to be consistent and terminate any existing output. >- return false; >- } >- >- RTC_LOG(LS_INFO) << "Starting WebRTC event log."; >- >- const int64_t timestamp_us = rtc::TimeMicros(); >- >- // Binding to |this| is safe because |this| outlives the |task_queue_|. >- auto start = [this, timestamp_us](std::unique_ptr<RtcEventLogOutput> output) { >- RTC_DCHECK_RUN_ON(&task_queue_); >- RTC_DCHECK(output->IsActive()); >- event_output_ = std::move(output); >- num_config_events_written_ = 0; >- WriteToOutput(event_encoder_->EncodeLogStart(timestamp_us)); >- LogEventsFromMemoryToOutput(); >- }; >- >- task_queue_.PostTask(rtc::MakeUnique<ResourceOwningTask<RtcEventLogOutput>>( >- std::move(output), start)); >- >- return true; >-} >- >-void RtcEventLogImpl::StopLogging() { >- RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >- >- RTC_LOG(LS_INFO) << "Stopping WebRTC event log."; >- >- rtc::Event output_stopped(true, false); >- >- // Binding to |this| is safe because |this| outlives the |task_queue_|. >- task_queue_.PostTask([this, &output_stopped]() { >- RTC_DCHECK_RUN_ON(&task_queue_); >- if (event_output_) { >- RTC_DCHECK(event_output_->IsActive()); >- LogEventsFromMemoryToOutput(); >- } >- StopLoggingInternal(); >- output_stopped.Set(); >- }); >- >- output_stopped.Wait(rtc::Event::kForever); >- >- RTC_LOG(LS_INFO) << "WebRTC event log successfully stopped."; >-} >- >-void RtcEventLogImpl::Log(std::unique_ptr<RtcEvent> event) { >- RTC_DCHECK(event); >- >- // Binding to |this| is safe because |this| outlives the |task_queue_|. >- auto event_handler = [this](std::unique_ptr<RtcEvent> unencoded_event) { >- RTC_DCHECK_RUN_ON(&task_queue_); >- LogToMemory(std::move(unencoded_event)); >- if (event_output_) >- ScheduleOutput(); >- }; >- >- task_queue_.PostTask(rtc::MakeUnique<ResourceOwningTask<RtcEvent>>( >- std::move(event), event_handler)); >-} >- >-void RtcEventLogImpl::ScheduleOutput() { >- RTC_DCHECK(event_output_ && event_output_->IsActive()); >- if (history_.size() >= kMaxEventsInHistory) { >- // We have to emergency drain the buffer. We can't wait for the scheduled >- // output task because there might be other event incoming before that. >- LogEventsFromMemoryToOutput(); >- return; >- } >- >- if (output_period_ms_ == kImmediateOutput) { >- // We are already on the |task_queue_| so there is no reason to post a task >- // if we want to output immediately. >- LogEventsFromMemoryToOutput(); >- return; >- } >- >- if (!output_scheduled_) { >- output_scheduled_ = true; >- // Binding to |this| is safe because |this| outlives the |task_queue_|. >- auto output_task = [this]() { >- RTC_DCHECK_RUN_ON(&task_queue_); >- if (event_output_) { >- RTC_DCHECK(event_output_->IsActive()); >- LogEventsFromMemoryToOutput(); >- } >- output_scheduled_ = false; >- }; >- int64_t now_ms = rtc::TimeMillis(); >- int64_t time_since_output_ms = now_ms - last_output_ms_; >- uint32_t delay = rtc::SafeClamp(output_period_ms_ - time_since_output_ms, 0, >- output_period_ms_); >- task_queue_.PostDelayedTask(output_task, delay); >- } >-} >- >-void RtcEventLogImpl::LogToMemory(std::unique_ptr<RtcEvent> event) { >- std::deque<std::unique_ptr<RtcEvent>>& container = >- event->IsConfigEvent() ? config_history_ : history_; >- const size_t container_max_size = >- event->IsConfigEvent() ? kMaxEventsInConfigHistory : kMaxEventsInHistory; >- >- if (container.size() >= container_max_size) { >- RTC_DCHECK(!event_output_); // Shouldn't lose events if we have an output. >- container.pop_front(); >- } >- container.push_back(std::move(event)); >-} >- >-void RtcEventLogImpl::LogEventsFromMemoryToOutput() { >- RTC_DCHECK(event_output_ && event_output_->IsActive()); >- last_output_ms_ = rtc::TimeMillis(); >- >- // Serialize all stream configurations that haven't already been written to >- // this output. |num_config_events_written_| is used to track which configs we >- // have already written. (Note that the config may have been written to >- // previous outputs; configs are not discarded.) >- std::string encoded_configs; >- RTC_DCHECK_LE(num_config_events_written_, config_history_.size()); >- if (num_config_events_written_ < config_history_.size()) { >- const auto begin = config_history_.begin() + num_config_events_written_; >- const auto end = config_history_.end(); >- encoded_configs = event_encoder_->EncodeBatch(begin, end); >- num_config_events_written_ = config_history_.size(); >- } >- >- // Serialize the events in the event queue. Note that the write may fail, >- // for example if we are writing to a file and have reached the maximum limit. >- // We don't get any feedback if this happens, so we still remove the events >- // from the event log history. This is normally not a problem, but if another >- // log is started immediately after the first one becomes full, then one >- // cannot rely on the second log to contain everything that isn't in the first >- // log; one batch of events might be missing. >- std::string encoded_history = >- event_encoder_->EncodeBatch(history_.begin(), history_.end()); >- history_.clear(); >- >- WriteConfigsAndHistoryToOutput(encoded_configs, encoded_history); >-} >- >-void RtcEventLogImpl::WriteConfigsAndHistoryToOutput( >- const std::string& encoded_configs, >- const std::string& encoded_history) { >- // This function is used to merge the strings instead of calling the output >- // object twice with small strings. The function also avoids copying any >- // strings in the typical case where there are no config events. >- if (encoded_configs.size() == 0) { >- WriteToOutput(encoded_history); // Typical case. >- } else if (encoded_history.size() == 0) { >- WriteToOutput(encoded_configs); // Very unusual case. >- } else { >- WriteToOutput(encoded_configs + encoded_history); >- } >-} >- >-void RtcEventLogImpl::StopOutput() { >- max_size_bytes_ = std::numeric_limits<decltype(max_size_bytes_)>::max(); >- written_bytes_ = 0; >- event_output_.reset(); >-} >- >-void RtcEventLogImpl::StopLoggingInternal() { >- if (event_output_) { >- RTC_DCHECK(event_output_->IsActive()); >- const int64_t timestamp_us = rtc::TimeMicros(); >- event_output_->Write(event_encoder_->EncodeLogEnd(timestamp_us)); >- } >- StopOutput(); >-} >- >-void RtcEventLogImpl::WriteToOutput(const std::string& output_string) { >- RTC_DCHECK(event_output_ && event_output_->IsActive()); >- if (!event_output_->Write(output_string)) { >- RTC_LOG(LS_ERROR) << "Failed to write RTC event to output."; >- // The first failure closes the output. >- RTC_DCHECK(!event_output_->IsActive()); >- StopOutput(); // Clean-up. >- return; >- } >- written_bytes_ += output_string.size(); >-} >- >-} // namespace >- >-#endif // ENABLE_RTC_EVENT_LOG >- >-// RtcEventLog member functions. >-std::unique_ptr<RtcEventLog> RtcEventLog::Create(EncodingType encoding_type) { >-#ifdef ENABLE_RTC_EVENT_LOG >- // TODO(eladalon): Known issue - there's a race over |rtc_event_log_count|. >- constexpr int kMaxLogCount = 5; >- int count = 1 + std::atomic_fetch_add(&rtc_event_log_count, 1); >- if (count > kMaxLogCount) { >- RTC_LOG(LS_WARNING) << "Denied creation of additional WebRTC event logs. " >- << count - 1 << " logs open already."; >- std::atomic_fetch_sub(&rtc_event_log_count, 1); >- return CreateNull(); >- } >- auto encoder = CreateEncoder(encoding_type); >- return rtc::MakeUnique<RtcEventLogImpl>(std::move(encoder)); >-#else >- return CreateNull(); >-#endif // ENABLE_RTC_EVENT_LOG >-} >- >-std::unique_ptr<RtcEventLog> RtcEventLog::CreateNull() { >- return std::unique_ptr<RtcEventLog>(new RtcEventLogNullImpl()); >+bool RtcEventLogNullImpl::StartLogging( >+ std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) { >+ return false; > } > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.h >index 89ace2c9e95..0c714069024 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.h >@@ -17,11 +17,11 @@ > > #include "api/rtceventlogoutput.h" > #include "logging/rtc_event_log/events/rtc_event.h" >+#include "rtc_base/task_queue.h" > > namespace webrtc { > >-class Clock; >- >+// TODO(terelius): Move this to the parser. > enum PacketDirection { kIncomingPacket = 0, kOutgoingPacket }; > > class RtcEventLog { >@@ -38,13 +38,12 @@ class RtcEventLog { > > // Factory method to create an RtcEventLog object. > static std::unique_ptr<RtcEventLog> Create(EncodingType encoding_type); >- // TODO(nisse): webrtc::Clock is deprecated. Delete this method and >- // above forward declaration of Clock when >- // webrtc/system_wrappers/include/clock.h is deleted. >- static std::unique_ptr<RtcEventLog> Create(const Clock*, >- EncodingType encoding_type) { >- return Create(encoding_type); >- } >+ >+ // Factory method to create an RtcEventLog object which uses the given >+ // rtc::TaskQueue for emitting output. >+ static std::unique_ptr<RtcEventLog> Create( >+ EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue); > > // Create an RtcEventLog object that does nothing. > static std::unique_ptr<RtcEventLog> CreateNull(); >@@ -65,12 +64,10 @@ class RtcEventLog { > // No-op implementation is used if flag is not set, or in tests. > class RtcEventLogNullImpl : public RtcEventLog { > public: >- bool StartLogging(std::unique_ptr<RtcEventLogOutput>, >- int64_t) override { >- return false; >- } >+ bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) override; > void StopLogging() override {} >- void Log(std::unique_ptr<RtcEvent>) override {} >+ void Log(std::unique_ptr<RtcEvent> event) override {} > }; > > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.proto b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.proto >index 8d2e22a6f87..94e288e0245 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.proto >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log.proto >@@ -41,6 +41,8 @@ message Event { > BWE_PROBE_CLUSTER_CREATED_EVENT = 17; > BWE_PROBE_RESULT_EVENT = 18; > ALR_STATE_EVENT = 19; >+ ICE_CANDIDATE_PAIR_CONFIG = 20; >+ ICE_CANDIDATE_PAIR_EVENT = 21; > } > > // required - Indicates the type of this event >@@ -85,6 +87,12 @@ message Event { > > // required if type == ALR_STATE_EVENT > AlrState alr_state = 19; >+ >+ // required if type == ICE_CANDIDATE_PAIR_CONFIG >+ IceCandidatePairConfig ice_candidate_pair_config = 20; >+ >+ // required if type == ICE_CANDIDATE_PAIR_EVENT >+ IceCandidatePairEvent ice_candidate_pair_event = 21; > } > } > >@@ -101,7 +109,7 @@ message RtpPacket { > optional bytes header = 4; > > // optional - The probe cluster id. >- optional uint32 probe_cluster_id = 5; >+ optional int32 probe_cluster_id = 5; > > // Do not add code to log user payload data without a privacy review! > } >@@ -289,10 +297,10 @@ message AudioNetworkAdaptation { > > message BweProbeCluster { > // required - The id of this probe cluster. >- optional uint32 id = 1; >+ optional int32 id = 1; > > // required - The bitrate in bps that this probe cluster is meant to probe. >- optional uint64 bitrate_bps = 2; >+ optional int32 bitrate_bps = 2; > > // required - The minimum number of packets used to probe the given bitrate. > optional uint32 min_packets = 3; >@@ -303,7 +311,7 @@ message BweProbeCluster { > > message BweProbeResult { > // required - The id of this probe cluster. >- optional uint32 id = 1; >+ optional int32 id = 1; > > enum ResultType { > SUCCESS = 0; >@@ -316,10 +324,92 @@ message BweProbeResult { > optional ResultType result = 2; > > // optional - but required if result == SUCCESS. The resulting bitrate in bps. >- optional uint64 bitrate_bps = 3; >+ optional int32 bitrate_bps = 3; > } > > message AlrState { > // required - If we are in ALR or not. > optional bool in_alr = 1; > } >+ >+message IceCandidatePairConfig { >+ enum IceCandidatePairConfigType { >+ ADDED = 0; >+ UPDATED = 1; >+ DESTROYED = 2; >+ SELECTED = 3; >+ } >+ >+ enum IceCandidateType { >+ LOCAL = 0; >+ STUN = 1; >+ PRFLX = 2; >+ RELAY = 3; >+ UNKNOWN_CANDIDATE_TYPE = 4; >+ } >+ >+ enum Protocol { >+ UDP = 0; >+ TCP = 1; >+ SSLTCP = 2; >+ TLS = 3; >+ UNKNOWN_PROTOCOL = 4; >+ } >+ >+ enum AddressFamily { >+ IPV4 = 0; >+ IPV6 = 1; >+ UNKNOWN_ADDRESS_FAMILY = 2; >+ } >+ >+ enum NetworkType { >+ ETHERNET = 0; >+ LOOPBACK = 1; >+ WIFI = 2; >+ VPN = 3; >+ CELLULAR = 4; >+ UNKNOWN_NETWORK_TYPE = 5; >+ } >+ >+ // required >+ optional IceCandidatePairConfigType config_type = 1; >+ >+ // required >+ optional uint32 candidate_pair_id = 2; >+ >+ // required >+ optional IceCandidateType local_candidate_type = 3; >+ >+ // required >+ optional Protocol local_relay_protocol = 4; >+ >+ // required >+ optional NetworkType local_network_type = 5; >+ >+ // required >+ optional AddressFamily local_address_family = 6; >+ >+ // required >+ optional IceCandidateType remote_candidate_type = 7; >+ >+ // required >+ optional AddressFamily remote_address_family = 8; >+ >+ // required >+ optional Protocol candidate_pair_protocol = 9; >+} >+ >+message IceCandidatePairEvent { >+ enum IceCandidatePairEventType { >+ CHECK_SENT = 0; >+ CHECK_RECEIVED = 1; >+ CHECK_RESPONSE_SENT = 2; >+ CHECK_RESPONSE_RECEIVED = 3; >+ } >+ >+ // required >+ optional IceCandidatePairEventType event_type = 1; >+ >+ // required >+ optional uint32 candidate_pair_id = 2; >+} >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc >index c6fa12997b1..b62759b0d51 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2rtp_dump.cc >@@ -16,7 +16,7 @@ > #include <string> > > #include "logging/rtc_event_log/rtc_event_log.h" >-#include "logging/rtc_event_log/rtc_event_log_parser.h" >+#include "logging/rtc_event_log/rtc_event_log_parser_new.h" > #include "modules/rtp_rtcp/source/byte_io.h" > #include "modules/rtp_rtcp/source/rtp_utility.h" > #include "rtc_base/checks.h" >@@ -25,7 +25,7 @@ > > namespace { > >-using MediaType = webrtc::ParsedRtcEventLog::MediaType; >+using MediaType = webrtc::ParsedRtcEventLogNew::MediaType; > > DEFINE_bool( > audio, >@@ -84,8 +84,8 @@ int main(int argc, char* argv[]) { > " --help for usage.\n" > "Example usage:\n" + > program_name + " input.rel output.rtp\n"; >- if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || >- FLAG_help || argc != 3) { >+ if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || FLAG_help || >+ argc != 3) { > std::cout << usage; > if (FLAG_help) { > rtc::FlagList::Print(nullptr, false); >@@ -102,7 +102,7 @@ int main(int argc, char* argv[]) { > RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc_filter)) > << "Flag verification has failed."; > >- webrtc::ParsedRtcEventLog parsed_stream; >+ webrtc::ParsedRtcEventLogNew parsed_stream; > if (!parsed_stream.ParseFile(input_file)) { > std::cerr << "Error while parsing input file: " << input_file << std::endl; > return -1; >@@ -127,8 +127,8 @@ int main(int argc, char* argv[]) { > // some required fields and we attempt to access them. We could consider > // a softer failure option, but it does not seem useful to generate > // RTP dumps based on broken event logs. >- if (FLAG_rtp && >- parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) { >+ if (FLAG_rtp && parsed_stream.GetEventType(i) == >+ webrtc::ParsedRtcEventLogNew::EventType::RTP_EVENT) { > webrtc::test::RtpPacket packet; > webrtc::PacketDirection direction; > parsed_stream.GetRtpHeader(i, &direction, packet.data, &packet.length, >@@ -166,7 +166,7 @@ int main(int argc, char* argv[]) { > rtp_counter++; > } > if (FLAG_rtcp && parsed_stream.GetEventType(i) == >- webrtc::ParsedRtcEventLog::RTCP_EVENT) { >+ webrtc::ParsedRtcEventLogNew::EventType::RTCP_EVENT) { > webrtc::test::RtpPacket packet; > webrtc::PacketDirection direction; > parsed_stream.GetRtcpPacket(i, &direction, packet.data, &packet.length); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2stats.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2stats.cc >index f38322d5bd2..928c829f49f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2stats.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2stats.cc >@@ -166,6 +166,10 @@ std::string EventTypeToString(webrtc::rtclog::Event::EventType event_type) { > return "BWE_PROBE_RESULT"; > case webrtc::rtclog::Event::ALR_STATE_EVENT: > return "ALR_STATE_EVENT"; >+ case webrtc::rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: >+ return "ICE_CANDIDATE_PAIR_CONFIG"; >+ case webrtc::rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: >+ return "ICE_CANDIDATE_PAIR_EVENT"; > } > RTC_NOTREACHED(); > return "UNKNOWN_EVENT"; >@@ -185,8 +189,8 @@ int main(int argc, char* argv[]) { > " --help for usage.\n" > "Example usage:\n" + > program_name + " input.rel\n"; >- if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || >- FLAG_help || argc != 2) { >+ if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || FLAG_help || >+ argc != 2) { > std::cout << usage; > if (FLAG_help) { > rtc::FlagList::Print(nullptr, false); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2text.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2text.cc >index 42ff7324303..f08e6ece5ec 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2text.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log2text.cc >@@ -13,13 +13,11 @@ > #include <iomanip> // setfill, setw > #include <iostream> > #include <map> >-#include <sstream> > #include <string> > #include <utility> // pair > >-#include "call/video_config.h" > #include "common_types.h" // NOLINT(build/include) >-#include "logging/rtc_event_log/rtc_event_log_parser.h" >+#include "logging/rtc_event_log/rtc_event_log_parser_new.h" > #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor_config.h" > #include "modules/rtp_rtcp/source/rtcp_packet/bye.h" > #include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" >@@ -40,6 +38,7 @@ > #include "rtc_base/checks.h" > #include "rtc_base/flags.h" > #include "rtc_base/logging.h" >+#include "rtc_base/strings/string_builder.h" > > namespace { > >@@ -60,6 +59,7 @@ DEFINE_bool(rtcp, true, "Use --nortcp to exclude RTCP packets."); > DEFINE_bool(playout, true, "Use --noplayout to exclude audio playout events."); > DEFINE_bool(ana, true, "Use --noana to exclude ANA events."); > DEFINE_bool(probe, true, "Use --noprobe to exclude probe events."); >+DEFINE_bool(ice, true, "Use --noice to exclude ICE events."); > > DEFINE_bool(print_full_packets, > false, >@@ -72,7 +72,7 @@ DEFINE_string(ssrc, > "starting with 0x)."); > DEFINE_bool(help, false, "Prints this message."); > >-using MediaType = webrtc::ParsedRtcEventLog::MediaType; >+using MediaType = webrtc::ParsedRtcEventLogNew::MediaType; > > static uint32_t filtered_ssrc = 0; > >@@ -164,7 +164,7 @@ webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() { > return default_map; > } > >-void PrintSenderReport(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintSenderReport(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -181,7 +181,7 @@ void PrintSenderReport(const webrtc::ParsedRtcEventLog& parsed_stream, > << "\ttimestamp=" << sr.rtp_timestamp() << std::endl; > } > >-void PrintReceiverReport(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintReceiverReport(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -197,7 +197,7 @@ void PrintReceiverReport(const webrtc::ParsedRtcEventLog& parsed_stream, > << "\tssrc=" << rr.sender_ssrc() << std::endl; > } > >-void PrintXr(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintXr(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -222,7 +222,7 @@ void PrintSdes(const webrtc::rtcp::CommonHeader& rtcp_block, > RTC_NOTREACHED() << "SDES should have been redacted when writing the log"; > } > >-void PrintBye(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintBye(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -238,7 +238,7 @@ void PrintBye(const webrtc::ParsedRtcEventLog& parsed_stream, > << "\tssrc=" << bye.sender_ssrc() << std::endl; > } > >-void PrintRtpFeedback(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintRtpFeedback(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -318,7 +318,7 @@ void PrintRtpFeedback(const webrtc::ParsedRtcEventLog& parsed_stream, > } > } > >-void PrintPsFeedback(const webrtc::ParsedRtcEventLog& parsed_stream, >+void PrintPsFeedback(const webrtc::ParsedRtcEventLogNew& parsed_stream, > const webrtc::rtcp::CommonHeader& rtcp_block, > uint64_t log_timestamp, > webrtc::PacketDirection direction) { >@@ -369,30 +369,53 @@ void PrintPsFeedback(const webrtc::ParsedRtcEventLog& parsed_stream, > } > } > >+enum class InputSource { >+ STDIN, >+ FILE, >+}; >+ >+void PrintUsageGuide(const std::string& program_name) { >+ std::cout >+ << "Tool for printing packet information from an RtcEventLog as text.\n" >+ << "* Run " + program_name + " --help for usage.\n" >+ << "* Example usage for parsing a file:\n" >+ << " " << program_name + " input.rel\n" >+ << "* Example usage for parsing the stdin:\n" >+ << " " << program_name + "\n"; >+} >+ >+// TODO(eladalon): Return a stream or file descriptor instead. >+InputSource ParseCommandLineFlags(int argc, char* argv[]) { >+ if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) != 0) { >+ PrintUsageGuide(argv[0]); >+ exit(-1); >+ } >+ >+ if (FLAG_help) { >+ PrintUsageGuide(argv[0]); >+ std::cout << std::endl; >+ rtc::FlagList::Print(nullptr, false); >+ exit(0); >+ } >+ >+ switch (argc) { >+ case 1: >+ return InputSource::STDIN; >+ case 2: >+ return InputSource::FILE; >+ default: >+ PrintUsageGuide(argv[0]); >+ exit(-1); >+ } >+} >+ > } // namespace > > // This utility will print basic information about each packet to stdout. > // Note that parser will assert if the protobuf event is missing some required > // fields and we attempt to access them. We don't handle this at the moment. > int main(int argc, char* argv[]) { >- std::string program_name = argv[0]; >- std::string usage = >- "Tool for printing packet information from an RtcEventLog as text.\n" >- "Run " + >- program_name + >- " --help for usage.\n" >- "Example usage:\n" + >- program_name + " input.rel\n"; >- if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true) || >- FLAG_help || argc != 2) { >- std::cout << usage; >- if (FLAG_help) { >- rtc::FlagList::Print(nullptr, false); >- return 0; >- } >- return 1; >- } >- std::string input_file = argv[1]; >+ InputSource input_source = ParseCommandLineFlags(argc, argv); > > if (strlen(FLAG_ssrc) > 0) > RTC_CHECK(ParseSsrc(FLAG_ssrc)) << "Flag verification has failed."; >@@ -400,16 +423,30 @@ int main(int argc, char* argv[]) { > webrtc::RtpHeaderExtensionMap default_map = GetDefaultHeaderExtensionMap(); > bool default_map_used = false; > >- webrtc::ParsedRtcEventLog parsed_stream; >- if (!parsed_stream.ParseFile(input_file)) { >- std::cerr << "Error while parsing input file: " << input_file << std::endl; >- return -1; >+ webrtc::ParsedRtcEventLogNew parsed_stream; >+ >+ switch (input_source) { >+ case InputSource::STDIN: { >+ if (!parsed_stream.ParseStream(std::cin)) { >+ std::cerr << "Error while parsing input stream." << std::endl; >+ return -1; >+ } >+ break; >+ } >+ case InputSource::FILE: { >+ if (!parsed_stream.ParseFile(argv[1])) { >+ std::cerr << "Error while parsing input file: " << argv[1] << std::endl; >+ return -1; >+ } >+ break; >+ } >+ default: { RTC_NOTREACHED() << "Unsupported input source."; } > } > > for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) { > bool event_recognized = false; > switch (parsed_stream.GetEventType(i)) { >- case webrtc::ParsedRtcEventLog::UNKNOWN_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT: { > if (FLAG_unknown) { > std::cout << parsed_stream.GetTimestamp(i) << "\tUNKNOWN_EVENT" > << std::endl; >@@ -418,7 +455,7 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::LOG_START: { >+ case webrtc::ParsedRtcEventLogNew::EventType::LOG_START: { > if (FLAG_startstop) { > std::cout << parsed_stream.GetTimestamp(i) << "\tLOG_START" > << std::endl; >@@ -427,7 +464,7 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::LOG_END: { >+ case webrtc::ParsedRtcEventLogNew::EventType::LOG_END: { > if (FLAG_startstop) { > std::cout << parsed_stream.GetTimestamp(i) << "\tLOG_END" > << std::endl; >@@ -436,13 +473,13 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::RTP_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::RTP_EVENT: { > if (FLAG_rtp) { > size_t header_length; > size_t total_length; > uint8_t header[IP_PACKET_SIZE]; > webrtc::PacketDirection direction; >- webrtc::RtpHeaderExtensionMap* extension_map = >+ const webrtc::RtpHeaderExtensionMap* extension_map = > parsed_stream.GetRtpHeader(i, &direction, header, &header_length, > &total_length, nullptr); > >@@ -492,8 +529,8 @@ int main(int argc, char* argv[]) { > << parsed_header.extension.transmissionTimeOffset; > } > if (parsed_header.extension.hasAudioLevel) { >- std::cout << "\tAudioLevel=" << >- static_cast<int>(parsed_header.extension.audioLevel); >+ std::cout << "\tAudioLevel=" >+ << static_cast<int>(parsed_header.extension.audioLevel); > } > std::cout << std::endl; > if (FLAG_print_full_packets) { >@@ -513,7 +550,7 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::RTCP_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::RTCP_EVENT: { > if (FLAG_rtcp) { > size_t length; > uint8_t packet[IP_PACKET_SIZE]; >@@ -580,37 +617,34 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT: { > if (FLAG_playout) { >- uint32_t ssrc; >- parsed_stream.GetAudioPlayout(i, &ssrc); >- std::cout << parsed_stream.GetTimestamp(i) << "\tAUDIO_PLAYOUT" >- << "\tssrc=" << ssrc << std::endl; >+ auto audio_playout = parsed_stream.GetAudioPlayout(i); >+ std::cout << audio_playout.log_time_us() << "\tAUDIO_PLAYOUT" >+ << "\tssrc=" << audio_playout.ssrc << std::endl; > } > event_recognized = true; > break; > } > >- case webrtc::ParsedRtcEventLog::LOSS_BASED_BWE_UPDATE: { >+ case webrtc::ParsedRtcEventLogNew::EventType::LOSS_BASED_BWE_UPDATE: { > if (FLAG_bwe) { >- int32_t bitrate_bps; >- uint8_t fraction_loss; >- int32_t total_packets; >- parsed_stream.GetLossBasedBweUpdate(i, &bitrate_bps, &fraction_loss, >- &total_packets); >- std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(LOSS_BASED)" >- << "\tbitrate_bps=" << bitrate_bps << "\tfraction_loss=" >- << static_cast<unsigned>(fraction_loss) >- << "\ttotal_packets=" << total_packets << std::endl; >+ auto bwe_update = parsed_stream.GetLossBasedBweUpdate(i); >+ std::cout << bwe_update.log_time_us() << "\tBWE(LOSS_BASED)" >+ << "\tbitrate_bps=" << bwe_update.bitrate_bps >+ << "\tfraction_lost=" >+ << static_cast<unsigned>(bwe_update.fraction_lost) >+ << "\texpected_packets=" << bwe_update.expected_packets >+ << std::endl; > } > event_recognized = true; > break; > } > >- case webrtc::ParsedRtcEventLog::DELAY_BASED_BWE_UPDATE: { >+ case webrtc::ParsedRtcEventLogNew::EventType::DELAY_BASED_BWE_UPDATE: { > if (FLAG_bwe) { > auto bwe_update = parsed_stream.GetDelayBasedBweUpdate(i); >- std::cout << parsed_stream.GetTimestamp(i) << "\tBWE(DELAY_BASED)" >+ std::cout << bwe_update.log_time_us() << "\tBWE(DELAY_BASED)" > << "\tbitrate_bps=" << bwe_update.bitrate_bps > << "\tdetector_state=" > << static_cast<int>(bwe_update.detector_state) << std::endl; >@@ -619,7 +653,8 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType:: >+ VIDEO_RECEIVER_CONFIG_EVENT: { > if (FLAG_config && FLAG_video && FLAG_incoming) { > webrtc::rtclog::StreamConfig config = > parsed_stream.GetVideoReceiveConfig(i); >@@ -644,7 +679,7 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::VIDEO_SENDER_CONFIG_EVENT: { > if (FLAG_config && FLAG_video && FLAG_outgoing) { > std::vector<webrtc::rtclog::StreamConfig> configs = > parsed_stream.GetVideoSendConfig(i); >@@ -671,7 +706,8 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType:: >+ AUDIO_RECEIVER_CONFIG_EVENT: { > if (FLAG_config && FLAG_audio && FLAG_incoming) { > webrtc::rtclog::StreamConfig config = > parsed_stream.GetAudioReceiveConfig(i); >@@ -696,7 +732,7 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::AUDIO_SENDER_CONFIG_EVENT: { > if (FLAG_config && FLAG_audio && FLAG_outgoing) { > webrtc::rtclog::StreamConfig config = > parsed_stream.GetAudioSendConfig(i); >@@ -720,41 +756,43 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::AUDIO_NETWORK_ADAPTATION_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType:: >+ AUDIO_NETWORK_ADAPTATION_EVENT: { > if (FLAG_ana) { >- webrtc::AudioEncoderRuntimeConfig ana_config; >- parsed_stream.GetAudioNetworkAdaptation(i, &ana_config); >- std::stringstream ss; >- ss << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE"; >- if (ana_config.bitrate_bps) { >- ss << "\tbitrate_bps=" << *ana_config.bitrate_bps; >+ auto ana_event = parsed_stream.GetAudioNetworkAdaptation(i); >+ char buffer[300]; >+ rtc::SimpleStringBuilder builder(buffer); >+ builder << parsed_stream.GetTimestamp(i) << "\tANA_UPDATE"; >+ if (ana_event.config.bitrate_bps) { >+ builder << "\tbitrate_bps=" << *ana_event.config.bitrate_bps; > } >- if (ana_config.frame_length_ms) { >- ss << "\tframe_length_ms=" << *ana_config.frame_length_ms; >+ if (ana_event.config.frame_length_ms) { >+ builder << "\tframe_length_ms=" >+ << *ana_event.config.frame_length_ms; > } >- if (ana_config.uplink_packet_loss_fraction) { >- ss << "\tuplink_packet_loss_fraction=" >- << *ana_config.uplink_packet_loss_fraction; >+ if (ana_event.config.uplink_packet_loss_fraction) { >+ builder << "\tuplink_packet_loss_fraction=" >+ << *ana_event.config.uplink_packet_loss_fraction; > } >- if (ana_config.enable_fec) { >- ss << "\tenable_fec=" << *ana_config.enable_fec; >+ if (ana_event.config.enable_fec) { >+ builder << "\tenable_fec=" << *ana_event.config.enable_fec; > } >- if (ana_config.enable_dtx) { >- ss << "\tenable_dtx=" << *ana_config.enable_dtx; >+ if (ana_event.config.enable_dtx) { >+ builder << "\tenable_dtx=" << *ana_event.config.enable_dtx; > } >- if (ana_config.num_channels) { >- ss << "\tnum_channels=" << *ana_config.num_channels; >+ if (ana_event.config.num_channels) { >+ builder << "\tnum_channels=" << *ana_event.config.num_channels; > } >- std::cout << ss.str() << std::endl; >+ std::cout << builder.str() << std::endl; > } > event_recognized = true; > break; > } > >- case webrtc::ParsedRtcEventLog::BWE_PROBE_CLUSTER_CREATED_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType:: >+ BWE_PROBE_CLUSTER_CREATED_EVENT: { > if (FLAG_probe) { >- webrtc::ParsedRtcEventLog::BweProbeClusterCreatedEvent probe_event = >- parsed_stream.GetBweProbeClusterCreated(i); >+ auto probe_event = parsed_stream.GetBweProbeClusterCreated(i); > std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_CREATED(" > << probe_event.id << ")" > << "\tbitrate_bps=" << probe_event.bitrate_bps >@@ -765,42 +803,76 @@ int main(int argc, char* argv[]) { > break; > } > >- case webrtc::ParsedRtcEventLog::BWE_PROBE_RESULT_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::BWE_PROBE_FAILURE_EVENT: { > if (FLAG_probe) { >- webrtc::ParsedRtcEventLog::BweProbeResultEvent probe_result = >- parsed_stream.GetBweProbeResult(i); >- if (probe_result.failure_reason) { >- std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS(" >- << probe_result.id << ")" >- << "\tfailure_reason=" >- << static_cast<int>(*probe_result.failure_reason) >- << std::endl; >- } else { >- std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS(" >- << probe_result.id << ")" >- << "\tbitrate_bps=" << *probe_result.bitrate_bps >- << std::endl; >- } >+ webrtc::LoggedBweProbeFailureEvent probe_result = >+ parsed_stream.GetBweProbeFailure(i); >+ std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_FAILURE(" >+ << probe_result.id << ")" >+ << "\tfailure_reason=" >+ << static_cast<int>(probe_result.failure_reason) >+ << std::endl; > } > event_recognized = true; > break; > } > >- case webrtc::ParsedRtcEventLog::ALR_STATE_EVENT: { >+ case webrtc::ParsedRtcEventLogNew::EventType::BWE_PROBE_SUCCESS_EVENT: { >+ if (FLAG_probe) { >+ webrtc::LoggedBweProbeSuccessEvent probe_result = >+ parsed_stream.GetBweProbeSuccess(i); >+ std::cout << parsed_stream.GetTimestamp(i) << "\tPROBE_SUCCESS(" >+ << probe_result.id << ")" >+ << "\tbitrate_bps=" << probe_result.bitrate_bps >+ << std::endl; >+ } >+ event_recognized = true; >+ break; >+ } >+ >+ case webrtc::ParsedRtcEventLogNew::EventType::ALR_STATE_EVENT: { > if (FLAG_bwe) { >- webrtc::ParsedRtcEventLog::AlrStateEvent alr_state = >- parsed_stream.GetAlrState(i); >+ webrtc::LoggedAlrStateEvent alr_state = parsed_stream.GetAlrState(i); > std::cout << parsed_stream.GetTimestamp(i) << "\tALR_STATE" > << "\tin_alr=" << alr_state.in_alr << std::endl; > } > event_recognized = true; > break; > } >+ >+ case webrtc::ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_CONFIG: { >+ if (FLAG_ice) { >+ webrtc::LoggedIceCandidatePairConfig ice_cp_config = >+ parsed_stream.GetIceCandidatePairConfig(i); >+ // TODO(qingsi): convert the numeric representation of states to text >+ std::cout << parsed_stream.GetTimestamp(i) >+ << "\tICE_CANDIDATE_PAIR_CONFIG" >+ << "\ttype=" << static_cast<int>(ice_cp_config.type) >+ << std::endl; >+ } >+ event_recognized = true; >+ break; >+ } >+ >+ case webrtc::ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_EVENT: { >+ if (FLAG_ice) { >+ webrtc::LoggedIceCandidatePairEvent ice_cp_event = >+ parsed_stream.GetIceCandidatePairEvent(i); >+ // TODO(qingsi): convert the numeric representation of states to text >+ std::cout << parsed_stream.GetTimestamp(i) >+ << "\tICE_CANDIDATE_PAIR_EVENT" >+ << "\ttype=" << static_cast<int>(ice_cp_event.type) >+ << std::endl; >+ } >+ event_recognized = true; >+ break; >+ } > } > > if (!event_recognized) { >- std::cout << "Unrecognized event (" << parsed_stream.GetEventType(i) >- << ")" << std::endl; >+ std::cout << "Unrecognized event (" >+ << static_cast<int>(parsed_stream.GetEventType(i)) << ")" >+ << std::endl; > } > } > return 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.cc >index 566736c8b70..e9d983d96e4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.cc >@@ -10,6 +10,8 @@ > > #include "logging/rtc_event_log/rtc_event_log_factory.h" > >+#include <utility> >+ > #include "logging/rtc_event_log/rtc_event_log.h" > > namespace webrtc { >@@ -19,6 +21,12 @@ std::unique_ptr<RtcEventLog> RtcEventLogFactory::CreateRtcEventLog( > return RtcEventLog::Create(encoding_type); > } > >+std::unique_ptr<RtcEventLog> RtcEventLogFactory::CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) { >+ return RtcEventLog::Create(encoding_type, std::move(task_queue)); >+} >+ > std::unique_ptr<RtcEventLogFactoryInterface> CreateRtcEventLogFactory() { > return std::unique_ptr<RtcEventLogFactoryInterface>(new RtcEventLogFactory()); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.h >index 1b75d66c10d..7f61ca92a79 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory.h >@@ -14,6 +14,7 @@ > #include <memory> > > #include "logging/rtc_event_log/rtc_event_log_factory_interface.h" >+#include "rtc_base/task_queue.h" > > namespace webrtc { > >@@ -23,6 +24,10 @@ class RtcEventLogFactory : public RtcEventLogFactoryInterface { > > std::unique_ptr<RtcEventLog> CreateRtcEventLog( > RtcEventLog::EncodingType encoding_type) override; >+ >+ std::unique_ptr<RtcEventLog> CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) override; > }; > > std::unique_ptr<RtcEventLogFactoryInterface> CreateRtcEventLogFactory(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h >index a28002d7827..395f2dc9a0f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_factory_interface.h >@@ -14,6 +14,7 @@ > #include <memory> > > #include "logging/rtc_event_log/rtc_event_log.h" >+#include "rtc_base/task_queue.h" > > namespace webrtc { > >@@ -26,6 +27,10 @@ class RtcEventLogFactoryInterface { > > virtual std::unique_ptr<RtcEventLog> CreateRtcEventLog( > RtcEventLog::EncodingType encoding_type) = 0; >+ >+ virtual std::unique_ptr<RtcEventLog> CreateRtcEventLog( >+ RtcEventLog::EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) = 0; > }; > > std::unique_ptr<RtcEventLogFactoryInterface> CreateRtcEventLogFactory(); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_impl.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_impl.cc >new file mode 100644 >index 00000000000..554a0283fd6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_impl.cc >@@ -0,0 +1,379 @@ >+/* >+ * Copyright (c) 2015 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 "logging/rtc_event_log/rtc_event_log.h" >+ >+#include <deque> >+#include <functional> >+#include <limits> >+#include <memory> >+#include <utility> >+#include <vector> >+ >+#include "absl/memory/memory.h" >+#include "logging/rtc_event_log/encoder/rtc_event_log_encoder_legacy.h" >+#include "logging/rtc_event_log/output/rtc_event_log_output_file.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/constructormagic.h" >+#include "rtc_base/event.h" >+#include "rtc_base/logging.h" >+#include "rtc_base/numerics/safe_conversions.h" >+#include "rtc_base/numerics/safe_minmax.h" >+#include "rtc_base/sequenced_task_checker.h" >+#include "rtc_base/task_queue.h" >+#include "rtc_base/thread_annotations.h" >+ >+namespace webrtc { >+ >+#ifdef ENABLE_RTC_EVENT_LOG >+ >+namespace { >+constexpr size_t kMaxEventsInHistory = 10000; >+// The config-history is supposed to be unbounded, but needs to have some bound >+// to prevent an attack via unreasonable memory use. >+constexpr size_t kMaxEventsInConfigHistory = 1000; >+ >+// TODO(eladalon): This class exists because C++11 doesn't allow transferring a >+// unique_ptr to a lambda (a copy constructor is required). We should get >+// rid of this when we move to C++14. >+template <typename T> >+class ResourceOwningTask final : public rtc::QueuedTask { >+ public: >+ ResourceOwningTask(std::unique_ptr<T> resource, >+ std::function<void(std::unique_ptr<T>)> handler) >+ : resource_(std::move(resource)), handler_(handler) {} >+ >+ bool Run() override { >+ handler_(std::move(resource_)); >+ return true; >+ } >+ >+ private: >+ std::unique_ptr<T> resource_; >+ std::function<void(std::unique_ptr<T>)> handler_; >+}; >+ >+std::unique_ptr<RtcEventLogEncoder> CreateEncoder( >+ RtcEventLog::EncodingType type) { >+ switch (type) { >+ case RtcEventLog::EncodingType::Legacy: >+ return absl::make_unique<RtcEventLogEncoderLegacy>(); >+ default: >+ RTC_LOG(LS_ERROR) << "Unknown RtcEventLog encoder type (" << int(type) >+ << ")"; >+ RTC_NOTREACHED(); >+ return std::unique_ptr<RtcEventLogEncoder>(nullptr); >+ } >+} >+ >+class RtcEventLogImpl final : public RtcEventLog { >+ public: >+ RtcEventLogImpl(std::unique_ptr<RtcEventLogEncoder> event_encoder, >+ std::unique_ptr<rtc::TaskQueue> task_queue); >+ >+ ~RtcEventLogImpl() override; >+ >+ // TODO(eladalon): We should change these name to reflect that what we're >+ // actually starting/stopping is the output of the log, not the log itself. >+ bool StartLogging(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) override; >+ void StopLogging() override; >+ >+ void Log(std::unique_ptr<RtcEvent> event) override; >+ >+ private: >+ void LogToMemory(std::unique_ptr<RtcEvent> event) RTC_RUN_ON(task_queue_); >+ void LogEventsFromMemoryToOutput() RTC_RUN_ON(task_queue_); >+ >+ void StopOutput() RTC_RUN_ON(task_queue_); >+ >+ void WriteConfigsAndHistoryToOutput(const std::string& encoded_configs, >+ const std::string& encoded_history) >+ RTC_RUN_ON(task_queue_); >+ void WriteToOutput(const std::string& output_string) RTC_RUN_ON(task_queue_); >+ >+ void StopLoggingInternal() RTC_RUN_ON(task_queue_); >+ >+ void ScheduleOutput() RTC_RUN_ON(task_queue_); >+ >+ // Make sure that the event log is "managed" - created/destroyed, as well >+ // as started/stopped - from the same thread/task-queue. >+ rtc::SequencedTaskChecker owner_sequence_checker_; >+ >+ // History containing all past configuration events. >+ std::deque<std::unique_ptr<RtcEvent>> config_history_ >+ RTC_GUARDED_BY(*task_queue_); >+ >+ // History containing the most recent (non-configuration) events (~10s). >+ std::deque<std::unique_ptr<RtcEvent>> history_ RTC_GUARDED_BY(*task_queue_); >+ >+ size_t max_size_bytes_ RTC_GUARDED_BY(*task_queue_); >+ size_t written_bytes_ RTC_GUARDED_BY(*task_queue_); >+ >+ std::unique_ptr<RtcEventLogEncoder> event_encoder_ >+ RTC_GUARDED_BY(*task_queue_); >+ std::unique_ptr<RtcEventLogOutput> event_output_ RTC_GUARDED_BY(*task_queue_); >+ >+ size_t num_config_events_written_ RTC_GUARDED_BY(*task_queue_); >+ int64_t output_period_ms_ RTC_GUARDED_BY(*task_queue_); >+ int64_t last_output_ms_ RTC_GUARDED_BY(*task_queue_); >+ bool output_scheduled_ RTC_GUARDED_BY(*task_queue_); >+ >+ // Since we are posting tasks bound to |this|, it is critical that the event >+ // log and it's members outlive the |task_queue_|. Keep the "task_queue_| >+ // last to ensure it destructs first, or else tasks living on the queue might >+ // access other members after they've been torn down. >+ std::unique_ptr<rtc::TaskQueue> task_queue_; >+ >+ RTC_DISALLOW_COPY_AND_ASSIGN(RtcEventLogImpl); >+}; >+ >+RtcEventLogImpl::RtcEventLogImpl( >+ std::unique_ptr<RtcEventLogEncoder> event_encoder, >+ std::unique_ptr<rtc::TaskQueue> task_queue) >+ : max_size_bytes_(std::numeric_limits<decltype(max_size_bytes_)>::max()), >+ written_bytes_(0), >+ event_encoder_(std::move(event_encoder)), >+ num_config_events_written_(0), >+ output_period_ms_(kImmediateOutput), >+ last_output_ms_(rtc::TimeMillis()), >+ output_scheduled_(false), >+ task_queue_(std::move(task_queue)) { >+ RTC_DCHECK(task_queue_); >+} >+ >+RtcEventLogImpl::~RtcEventLogImpl() { >+ RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >+ >+ // If we're logging to the output, this will stop that. Blocking function. >+ StopLogging(); >+} >+ >+bool RtcEventLogImpl::StartLogging(std::unique_ptr<RtcEventLogOutput> output, >+ int64_t output_period_ms) { >+ RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >+ >+ RTC_DCHECK(output_period_ms == kImmediateOutput || output_period_ms > 0); >+ >+ if (!output->IsActive()) { >+ // TODO(eladalon): We may want to remove the IsActive method. Otherwise >+ // we probably want to be consistent and terminate any existing output. >+ return false; >+ } >+ >+ // TODO(terelius): The mapping between log timestamps and UTC should be stored >+ // in the event_log START event. >+ const int64_t timestamp_us = rtc::TimeMicros(); >+ const int64_t utc_time_us = rtc::TimeUTCMicros(); >+ RTC_LOG(LS_INFO) << "Starting WebRTC event log. (Timestamp, UTC) = " >+ << "(" << timestamp_us << ", " << utc_time_us << ")."; >+ >+ // Binding to |this| is safe because |this| outlives the |task_queue_|. >+ auto start = [this, timestamp_us](std::unique_ptr<RtcEventLogOutput> output) { >+ RTC_DCHECK_RUN_ON(task_queue_.get()); >+ RTC_DCHECK(output->IsActive()); >+ event_output_ = std::move(output); >+ num_config_events_written_ = 0; >+ WriteToOutput(event_encoder_->EncodeLogStart(timestamp_us)); >+ LogEventsFromMemoryToOutput(); >+ }; >+ >+ task_queue_->PostTask( >+ absl::make_unique<ResourceOwningTask<RtcEventLogOutput>>( >+ std::move(output), start)); >+ >+ return true; >+} >+ >+void RtcEventLogImpl::StopLogging() { >+ RTC_DCHECK_CALLED_SEQUENTIALLY(&owner_sequence_checker_); >+ >+ RTC_LOG(LS_INFO) << "Stopping WebRTC event log."; >+ >+ rtc::Event output_stopped(true, false); >+ >+ // Binding to |this| is safe because |this| outlives the |task_queue_|. >+ task_queue_->PostTask([this, &output_stopped]() { >+ RTC_DCHECK_RUN_ON(task_queue_.get()); >+ if (event_output_) { >+ RTC_DCHECK(event_output_->IsActive()); >+ LogEventsFromMemoryToOutput(); >+ } >+ StopLoggingInternal(); >+ output_stopped.Set(); >+ }); >+ >+ output_stopped.Wait(rtc::Event::kForever); >+ >+ RTC_LOG(LS_INFO) << "WebRTC event log successfully stopped."; >+} >+ >+void RtcEventLogImpl::Log(std::unique_ptr<RtcEvent> event) { >+ RTC_CHECK(event); >+ >+ // Binding to |this| is safe because |this| outlives the |task_queue_|. >+ auto event_handler = [this](std::unique_ptr<RtcEvent> unencoded_event) { >+ RTC_DCHECK_RUN_ON(task_queue_.get()); >+ LogToMemory(std::move(unencoded_event)); >+ if (event_output_) >+ ScheduleOutput(); >+ }; >+ >+ task_queue_->PostTask(absl::make_unique<ResourceOwningTask<RtcEvent>>( >+ std::move(event), event_handler)); >+} >+ >+void RtcEventLogImpl::ScheduleOutput() { >+ RTC_DCHECK(event_output_ && event_output_->IsActive()); >+ if (history_.size() >= kMaxEventsInHistory) { >+ // We have to emergency drain the buffer. We can't wait for the scheduled >+ // output task because there might be other event incoming before that. >+ LogEventsFromMemoryToOutput(); >+ return; >+ } >+ >+ if (output_period_ms_ == kImmediateOutput) { >+ // We are already on the |task_queue_| so there is no reason to post a task >+ // if we want to output immediately. >+ LogEventsFromMemoryToOutput(); >+ return; >+ } >+ >+ if (!output_scheduled_) { >+ output_scheduled_ = true; >+ // Binding to |this| is safe because |this| outlives the |task_queue_|. >+ auto output_task = [this]() { >+ RTC_DCHECK_RUN_ON(task_queue_.get()); >+ if (event_output_) { >+ RTC_DCHECK(event_output_->IsActive()); >+ LogEventsFromMemoryToOutput(); >+ } >+ output_scheduled_ = false; >+ }; >+ int64_t now_ms = rtc::TimeMillis(); >+ int64_t time_since_output_ms = now_ms - last_output_ms_; >+ uint32_t delay = rtc::SafeClamp(output_period_ms_ - time_since_output_ms, 0, >+ output_period_ms_); >+ task_queue_->PostDelayedTask(output_task, delay); >+ } >+} >+ >+void RtcEventLogImpl::LogToMemory(std::unique_ptr<RtcEvent> event) { >+ std::deque<std::unique_ptr<RtcEvent>>& container = >+ event->IsConfigEvent() ? config_history_ : history_; >+ const size_t container_max_size = >+ event->IsConfigEvent() ? kMaxEventsInConfigHistory : kMaxEventsInHistory; >+ >+ if (container.size() >= container_max_size) { >+ RTC_DCHECK(!event_output_); // Shouldn't lose events if we have an output. >+ container.pop_front(); >+ } >+ container.push_back(std::move(event)); >+} >+ >+void RtcEventLogImpl::LogEventsFromMemoryToOutput() { >+ RTC_DCHECK(event_output_ && event_output_->IsActive()); >+ last_output_ms_ = rtc::TimeMillis(); >+ >+ // Serialize all stream configurations that haven't already been written to >+ // this output. |num_config_events_written_| is used to track which configs we >+ // have already written. (Note that the config may have been written to >+ // previous outputs; configs are not discarded.) >+ std::string encoded_configs; >+ RTC_DCHECK_LE(num_config_events_written_, config_history_.size()); >+ if (num_config_events_written_ < config_history_.size()) { >+ const auto begin = config_history_.begin() + num_config_events_written_; >+ const auto end = config_history_.end(); >+ encoded_configs = event_encoder_->EncodeBatch(begin, end); >+ num_config_events_written_ = config_history_.size(); >+ } >+ >+ // Serialize the events in the event queue. Note that the write may fail, >+ // for example if we are writing to a file and have reached the maximum limit. >+ // We don't get any feedback if this happens, so we still remove the events >+ // from the event log history. This is normally not a problem, but if another >+ // log is started immediately after the first one becomes full, then one >+ // cannot rely on the second log to contain everything that isn't in the first >+ // log; one batch of events might be missing. >+ std::string encoded_history = >+ event_encoder_->EncodeBatch(history_.begin(), history_.end()); >+ history_.clear(); >+ >+ WriteConfigsAndHistoryToOutput(encoded_configs, encoded_history); >+} >+ >+void RtcEventLogImpl::WriteConfigsAndHistoryToOutput( >+ const std::string& encoded_configs, >+ const std::string& encoded_history) { >+ // This function is used to merge the strings instead of calling the output >+ // object twice with small strings. The function also avoids copying any >+ // strings in the typical case where there are no config events. >+ if (encoded_configs.size() == 0) { >+ WriteToOutput(encoded_history); // Typical case. >+ } else if (encoded_history.size() == 0) { >+ WriteToOutput(encoded_configs); // Very unusual case. >+ } else { >+ WriteToOutput(encoded_configs + encoded_history); >+ } >+} >+ >+void RtcEventLogImpl::StopOutput() { >+ max_size_bytes_ = std::numeric_limits<decltype(max_size_bytes_)>::max(); >+ written_bytes_ = 0; >+ event_output_.reset(); >+} >+ >+void RtcEventLogImpl::StopLoggingInternal() { >+ if (event_output_) { >+ RTC_DCHECK(event_output_->IsActive()); >+ const int64_t timestamp_us = rtc::TimeMicros(); >+ event_output_->Write(event_encoder_->EncodeLogEnd(timestamp_us)); >+ } >+ StopOutput(); >+} >+ >+void RtcEventLogImpl::WriteToOutput(const std::string& output_string) { >+ RTC_DCHECK(event_output_ && event_output_->IsActive()); >+ if (!event_output_->Write(output_string)) { >+ RTC_LOG(LS_ERROR) << "Failed to write RTC event to output."; >+ // The first failure closes the output. >+ RTC_DCHECK(!event_output_->IsActive()); >+ StopOutput(); // Clean-up. >+ return; >+ } >+ written_bytes_ += output_string.size(); >+} >+ >+} // namespace >+ >+#endif // ENABLE_RTC_EVENT_LOG >+ >+// RtcEventLog member functions. >+std::unique_ptr<RtcEventLog> RtcEventLog::Create(EncodingType encoding_type) { >+ return Create(encoding_type, >+ absl::make_unique<rtc::TaskQueue>("rtc_event_log")); >+} >+ >+std::unique_ptr<RtcEventLog> RtcEventLog::Create( >+ EncodingType encoding_type, >+ std::unique_ptr<rtc::TaskQueue> task_queue) { >+#ifdef ENABLE_RTC_EVENT_LOG >+ return absl::make_unique<RtcEventLogImpl>(CreateEncoder(encoding_type), >+ std::move(task_queue)); >+#else >+ return CreateNull(); >+#endif // ENABLE_RTC_EVENT_LOG >+} >+ >+std::unique_ptr<RtcEventLog> RtcEventLog::CreateNull() { >+ return std::unique_ptr<RtcEventLog>(new RtcEventLogNullImpl()); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc >index 194da57b6d1..27bb2b26d65 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.cc >@@ -76,6 +76,10 @@ ParsedRtcEventLog::EventType GetRuntimeEventType( > return ParsedRtcEventLog::EventType::BWE_PROBE_RESULT_EVENT; > case rtclog::Event::ALR_STATE_EVENT: > return ParsedRtcEventLog::EventType::ALR_STATE_EVENT; >+ case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: >+ return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_CONFIG; >+ case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: >+ return ParsedRtcEventLog::EventType::ICE_CANDIDATE_PAIR_EVENT; > } > return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; > } >@@ -94,6 +98,108 @@ BandwidthUsage GetRuntimeDetectorState( > return BandwidthUsage::kBwNormal; > } > >+IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType( >+ rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairConfig::ADDED: >+ return IceCandidatePairConfigType::kAdded; >+ case rtclog::IceCandidatePairConfig::UPDATED: >+ return IceCandidatePairConfigType::kUpdated; >+ case rtclog::IceCandidatePairConfig::DESTROYED: >+ return IceCandidatePairConfigType::kDestroyed; >+ case rtclog::IceCandidatePairConfig::SELECTED: >+ return IceCandidatePairConfigType::kSelected; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairConfigType::kAdded; >+} >+ >+IceCandidateType GetRuntimeIceCandidateType( >+ rtclog::IceCandidatePairConfig::IceCandidateType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairConfig::LOCAL: >+ return IceCandidateType::kLocal; >+ case rtclog::IceCandidatePairConfig::STUN: >+ return IceCandidateType::kStun; >+ case rtclog::IceCandidatePairConfig::PRFLX: >+ return IceCandidateType::kPrflx; >+ case rtclog::IceCandidatePairConfig::RELAY: >+ return IceCandidateType::kRelay; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE: >+ return IceCandidateType::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidateType::kUnknown; >+} >+ >+IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol( >+ rtclog::IceCandidatePairConfig::Protocol protocol) { >+ switch (protocol) { >+ case rtclog::IceCandidatePairConfig::UDP: >+ return IceCandidatePairProtocol::kUdp; >+ case rtclog::IceCandidatePairConfig::TCP: >+ return IceCandidatePairProtocol::kTcp; >+ case rtclog::IceCandidatePairConfig::SSLTCP: >+ return IceCandidatePairProtocol::kSsltcp; >+ case rtclog::IceCandidatePairConfig::TLS: >+ return IceCandidatePairProtocol::kTls; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL: >+ return IceCandidatePairProtocol::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairProtocol::kUnknown; >+} >+ >+IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily( >+ rtclog::IceCandidatePairConfig::AddressFamily address_family) { >+ switch (address_family) { >+ case rtclog::IceCandidatePairConfig::IPV4: >+ return IceCandidatePairAddressFamily::kIpv4; >+ case rtclog::IceCandidatePairConfig::IPV6: >+ return IceCandidatePairAddressFamily::kIpv6; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY: >+ return IceCandidatePairAddressFamily::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairAddressFamily::kUnknown; >+} >+ >+IceCandidateNetworkType GetRuntimeIceCandidateNetworkType( >+ rtclog::IceCandidatePairConfig::NetworkType network_type) { >+ switch (network_type) { >+ case rtclog::IceCandidatePairConfig::ETHERNET: >+ return IceCandidateNetworkType::kEthernet; >+ case rtclog::IceCandidatePairConfig::LOOPBACK: >+ return IceCandidateNetworkType::kLoopback; >+ case rtclog::IceCandidatePairConfig::WIFI: >+ return IceCandidateNetworkType::kWifi; >+ case rtclog::IceCandidatePairConfig::VPN: >+ return IceCandidateNetworkType::kVpn; >+ case rtclog::IceCandidatePairConfig::CELLULAR: >+ return IceCandidateNetworkType::kCellular; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE: >+ return IceCandidateNetworkType::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidateNetworkType::kUnknown; >+} >+ >+IceCandidatePairEventType GetRuntimeIceCandidatePairEventType( >+ rtclog::IceCandidatePairEvent::IceCandidatePairEventType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairEvent::CHECK_SENT: >+ return IceCandidatePairEventType::kCheckSent; >+ case rtclog::IceCandidatePairEvent::CHECK_RECEIVED: >+ return IceCandidatePairEventType::kCheckReceived; >+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT: >+ return IceCandidatePairEventType::kCheckResponseSent; >+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED: >+ return IceCandidatePairEventType::kCheckResponseReceived; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairEventType::kCheckSent; >+} >+ > std::pair<uint64_t, bool> ParseVarInt(std::istream& stream) { > uint64_t varint = 0; > for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) { >@@ -115,10 +221,9 @@ std::pair<uint64_t, bool> ParseVarInt(std::istream& stream) { > return std::make_pair(varint, false); > } > >-void GetHeaderExtensions( >- std::vector<RtpExtension>* header_extensions, >- const RepeatedPtrField<rtclog::RtpHeaderExtension>& >- proto_header_extensions) { >+void GetHeaderExtensions(std::vector<RtpExtension>* header_extensions, >+ const RepeatedPtrField<rtclog::RtpHeaderExtension>& >+ proto_header_extensions) { > header_extensions->clear(); > for (auto& p : proto_header_extensions) { > RTC_CHECK(p.has_name()); >@@ -670,6 +775,61 @@ ParsedRtcEventLog::AlrStateEvent ParsedRtcEventLog::GetAlrState( > return res; > } > >+ParsedRtcEventLog::IceCandidatePairConfig >+ParsedRtcEventLog::GetIceCandidatePairConfig(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& rtc_event = events_[index]; >+ RTC_CHECK(rtc_event.has_type()); >+ RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG); >+ IceCandidatePairConfig res; >+ const rtclog::IceCandidatePairConfig& config = >+ rtc_event.ice_candidate_pair_config(); >+ res.timestamp = GetTimestamp(index); >+ RTC_CHECK(config.has_config_type()); >+ res.type = GetRuntimeIceCandidatePairConfigType(config.config_type()); >+ RTC_CHECK(config.has_candidate_pair_id()); >+ res.candidate_pair_id = config.candidate_pair_id(); >+ RTC_CHECK(config.has_local_candidate_type()); >+ res.local_candidate_type = >+ GetRuntimeIceCandidateType(config.local_candidate_type()); >+ RTC_CHECK(config.has_local_relay_protocol()); >+ res.local_relay_protocol = >+ GetRuntimeIceCandidatePairProtocol(config.local_relay_protocol()); >+ RTC_CHECK(config.has_local_network_type()); >+ res.local_network_type = >+ GetRuntimeIceCandidateNetworkType(config.local_network_type()); >+ RTC_CHECK(config.has_local_address_family()); >+ res.local_address_family = >+ GetRuntimeIceCandidatePairAddressFamily(config.local_address_family()); >+ RTC_CHECK(config.has_remote_candidate_type()); >+ res.remote_candidate_type = >+ GetRuntimeIceCandidateType(config.remote_candidate_type()); >+ RTC_CHECK(config.has_remote_address_family()); >+ res.remote_address_family = >+ GetRuntimeIceCandidatePairAddressFamily(config.remote_address_family()); >+ RTC_CHECK(config.has_candidate_pair_protocol()); >+ res.candidate_pair_protocol = >+ GetRuntimeIceCandidatePairProtocol(config.candidate_pair_protocol()); >+ return res; >+} >+ >+ParsedRtcEventLog::IceCandidatePairEvent >+ParsedRtcEventLog::GetIceCandidatePairEvent(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& rtc_event = events_[index]; >+ RTC_CHECK(rtc_event.has_type()); >+ RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_EVENT); >+ IceCandidatePairEvent res; >+ const rtclog::IceCandidatePairEvent& event = >+ rtc_event.ice_candidate_pair_event(); >+ res.timestamp = GetTimestamp(index); >+ RTC_CHECK(event.has_event_type()); >+ res.type = GetRuntimeIceCandidatePairEventType(event.event_type()); >+ RTC_CHECK(event.has_candidate_pair_id()); >+ res.candidate_pair_id = event.candidate_pair_id(); >+ return res; >+} >+ > // Returns the MediaType for registered SSRCs. Search from the end to use last > // registered types first. > ParsedRtcEventLog::MediaType ParsedRtcEventLog::GetMediaType( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.h >index 64389187748..862a48d42c4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser.h >@@ -17,6 +17,8 @@ > > #include "call/video_receive_stream.h" > #include "call/video_send_stream.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" > #include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" > #include "logging/rtc_event_log/rtc_event_log.h" > #include "logging/rtc_event_log/rtc_stream_config.h" >@@ -55,8 +57,8 @@ class ParsedRtcEventLog { > struct BweProbeResultEvent { > uint64_t timestamp; > uint32_t id; >- rtc::Optional<uint64_t> bitrate_bps; >- rtc::Optional<ProbeFailureReason> failure_reason; >+ absl::optional<uint64_t> bitrate_bps; >+ absl::optional<ProbeFailureReason> failure_reason; > }; > > struct BweDelayBasedUpdate { >@@ -70,6 +72,25 @@ class ParsedRtcEventLog { > bool in_alr; > }; > >+ struct IceCandidatePairConfig { >+ uint64_t timestamp; >+ IceCandidatePairConfigType type; >+ uint32_t candidate_pair_id; >+ IceCandidateType local_candidate_type; >+ IceCandidatePairProtocol local_relay_protocol; >+ IceCandidateNetworkType local_network_type; >+ IceCandidatePairAddressFamily local_address_family; >+ IceCandidateType remote_candidate_type; >+ IceCandidatePairAddressFamily remote_address_family; >+ IceCandidatePairProtocol candidate_pair_protocol; >+ }; >+ >+ struct IceCandidatePairEvent { >+ uint64_t timestamp; >+ IceCandidatePairEventType type; >+ uint32_t candidate_pair_id; >+ }; >+ > enum EventType { > UNKNOWN_EVENT = 0, > LOG_START = 1, >@@ -86,7 +107,9 @@ class ParsedRtcEventLog { > AUDIO_NETWORK_ADAPTATION_EVENT = 16, > BWE_PROBE_CLUSTER_CREATED_EVENT = 17, > BWE_PROBE_RESULT_EVENT = 18, >- ALR_STATE_EVENT = 19 >+ ALR_STATE_EVENT = 19, >+ ICE_CANDIDATE_PAIR_CONFIG = 20, >+ ICE_CANDIDATE_PAIR_EVENT = 21, > }; > > enum class MediaType { ANY, AUDIO, VIDEO, DATA }; >@@ -188,6 +211,9 @@ class ParsedRtcEventLog { > > AlrStateEvent GetAlrState(size_t index) const; > >+ IceCandidatePairConfig GetIceCandidatePairConfig(size_t index) const; >+ IceCandidatePairEvent GetIceCandidatePairEvent(size_t index) const; >+ > private: > rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const; > std::vector<rtclog::StreamConfig> GetVideoSendConfig( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.cc >new file mode 100644 >index 00000000000..b2b32642828 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.cc >@@ -0,0 +1,1308 @@ >+/* >+ * Copyright (c) 2016 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 "logging/rtc_event_log/rtc_event_log_parser_new.h" >+ >+#include <stdint.h> >+#include <string.h> >+ >+#include <algorithm> >+#include <fstream> >+#include <istream> // no-presubmit-check TODO(webrtc:8982) >+#include <limits> >+#include <map> >+#include <utility> >+ >+#include "absl/memory/memory.h" >+#include "api/rtp_headers.h" >+#include "api/rtpparameters.h" >+#include "logging/rtc_event_log/rtc_event_log.h" >+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" >+#include "modules/remote_bitrate_estimator/include/bwe_defines.h" >+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" >+#include "modules/rtp_rtcp/source/byte_io.h" >+#include "modules/rtp_rtcp/source/rtp_header_extensions.h" >+#include "modules/rtp_rtcp/source/rtp_utility.h" >+#include "rtc_base/checks.h" >+#include "rtc_base/logging.h" >+#include "rtc_base/protobuf_utils.h" >+ >+namespace webrtc { >+ >+namespace { >+RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) { >+ switch (rtcp_mode) { >+ case rtclog::VideoReceiveConfig::RTCP_COMPOUND: >+ return RtcpMode::kCompound; >+ case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE: >+ return RtcpMode::kReducedSize; >+ } >+ RTC_NOTREACHED(); >+ return RtcpMode::kOff; >+} >+ >+ParsedRtcEventLogNew::EventType GetRuntimeEventType( >+ rtclog::Event::EventType event_type) { >+ switch (event_type) { >+ case rtclog::Event::UNKNOWN_EVENT: >+ return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT; >+ case rtclog::Event::LOG_START: >+ return ParsedRtcEventLogNew::EventType::LOG_START; >+ case rtclog::Event::LOG_END: >+ return ParsedRtcEventLogNew::EventType::LOG_END; >+ case rtclog::Event::RTP_EVENT: >+ return ParsedRtcEventLogNew::EventType::RTP_EVENT; >+ case rtclog::Event::RTCP_EVENT: >+ return ParsedRtcEventLogNew::EventType::RTCP_EVENT; >+ case rtclog::Event::AUDIO_PLAYOUT_EVENT: >+ return ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT; >+ case rtclog::Event::LOSS_BASED_BWE_UPDATE: >+ return ParsedRtcEventLogNew::EventType::LOSS_BASED_BWE_UPDATE; >+ case rtclog::Event::DELAY_BASED_BWE_UPDATE: >+ return ParsedRtcEventLogNew::EventType::DELAY_BASED_BWE_UPDATE; >+ case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: >+ return ParsedRtcEventLogNew::EventType::VIDEO_RECEIVER_CONFIG_EVENT; >+ case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: >+ return ParsedRtcEventLogNew::EventType::VIDEO_SENDER_CONFIG_EVENT; >+ case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT: >+ return ParsedRtcEventLogNew::EventType::AUDIO_RECEIVER_CONFIG_EVENT; >+ case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: >+ return ParsedRtcEventLogNew::EventType::AUDIO_SENDER_CONFIG_EVENT; >+ case rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT: >+ return ParsedRtcEventLogNew::EventType::AUDIO_NETWORK_ADAPTATION_EVENT; >+ case rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT: >+ return ParsedRtcEventLogNew::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT; >+ case rtclog::Event::BWE_PROBE_RESULT_EVENT: >+ // Probe successes and failures are currently stored in the same proto >+ // message, we are moving towards separate messages. Probe results >+ // therefore need special treatment in the parser. >+ return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT; >+ case rtclog::Event::ALR_STATE_EVENT: >+ return ParsedRtcEventLogNew::EventType::ALR_STATE_EVENT; >+ case rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG: >+ return ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_CONFIG; >+ case rtclog::Event::ICE_CANDIDATE_PAIR_EVENT: >+ return ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_EVENT; >+ } >+ return ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT; >+} >+ >+BandwidthUsage GetRuntimeDetectorState( >+ rtclog::DelayBasedBweUpdate::DetectorState detector_state) { >+ switch (detector_state) { >+ case rtclog::DelayBasedBweUpdate::BWE_NORMAL: >+ return BandwidthUsage::kBwNormal; >+ case rtclog::DelayBasedBweUpdate::BWE_UNDERUSING: >+ return BandwidthUsage::kBwUnderusing; >+ case rtclog::DelayBasedBweUpdate::BWE_OVERUSING: >+ return BandwidthUsage::kBwOverusing; >+ } >+ RTC_NOTREACHED(); >+ return BandwidthUsage::kBwNormal; >+} >+ >+IceCandidatePairConfigType GetRuntimeIceCandidatePairConfigType( >+ rtclog::IceCandidatePairConfig::IceCandidatePairConfigType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairConfig::ADDED: >+ return IceCandidatePairConfigType::kAdded; >+ case rtclog::IceCandidatePairConfig::UPDATED: >+ return IceCandidatePairConfigType::kUpdated; >+ case rtclog::IceCandidatePairConfig::DESTROYED: >+ return IceCandidatePairConfigType::kDestroyed; >+ case rtclog::IceCandidatePairConfig::SELECTED: >+ return IceCandidatePairConfigType::kSelected; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairConfigType::kAdded; >+} >+ >+IceCandidateType GetRuntimeIceCandidateType( >+ rtclog::IceCandidatePairConfig::IceCandidateType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairConfig::LOCAL: >+ return IceCandidateType::kLocal; >+ case rtclog::IceCandidatePairConfig::STUN: >+ return IceCandidateType::kStun; >+ case rtclog::IceCandidatePairConfig::PRFLX: >+ return IceCandidateType::kPrflx; >+ case rtclog::IceCandidatePairConfig::RELAY: >+ return IceCandidateType::kRelay; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_CANDIDATE_TYPE: >+ return IceCandidateType::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidateType::kUnknown; >+} >+ >+IceCandidatePairProtocol GetRuntimeIceCandidatePairProtocol( >+ rtclog::IceCandidatePairConfig::Protocol protocol) { >+ switch (protocol) { >+ case rtclog::IceCandidatePairConfig::UDP: >+ return IceCandidatePairProtocol::kUdp; >+ case rtclog::IceCandidatePairConfig::TCP: >+ return IceCandidatePairProtocol::kTcp; >+ case rtclog::IceCandidatePairConfig::SSLTCP: >+ return IceCandidatePairProtocol::kSsltcp; >+ case rtclog::IceCandidatePairConfig::TLS: >+ return IceCandidatePairProtocol::kTls; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_PROTOCOL: >+ return IceCandidatePairProtocol::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairProtocol::kUnknown; >+} >+ >+IceCandidatePairAddressFamily GetRuntimeIceCandidatePairAddressFamily( >+ rtclog::IceCandidatePairConfig::AddressFamily address_family) { >+ switch (address_family) { >+ case rtclog::IceCandidatePairConfig::IPV4: >+ return IceCandidatePairAddressFamily::kIpv4; >+ case rtclog::IceCandidatePairConfig::IPV6: >+ return IceCandidatePairAddressFamily::kIpv6; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_ADDRESS_FAMILY: >+ return IceCandidatePairAddressFamily::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairAddressFamily::kUnknown; >+} >+ >+IceCandidateNetworkType GetRuntimeIceCandidateNetworkType( >+ rtclog::IceCandidatePairConfig::NetworkType network_type) { >+ switch (network_type) { >+ case rtclog::IceCandidatePairConfig::ETHERNET: >+ return IceCandidateNetworkType::kEthernet; >+ case rtclog::IceCandidatePairConfig::LOOPBACK: >+ return IceCandidateNetworkType::kLoopback; >+ case rtclog::IceCandidatePairConfig::WIFI: >+ return IceCandidateNetworkType::kWifi; >+ case rtclog::IceCandidatePairConfig::VPN: >+ return IceCandidateNetworkType::kVpn; >+ case rtclog::IceCandidatePairConfig::CELLULAR: >+ return IceCandidateNetworkType::kCellular; >+ case rtclog::IceCandidatePairConfig::UNKNOWN_NETWORK_TYPE: >+ return IceCandidateNetworkType::kUnknown; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidateNetworkType::kUnknown; >+} >+ >+IceCandidatePairEventType GetRuntimeIceCandidatePairEventType( >+ rtclog::IceCandidatePairEvent::IceCandidatePairEventType type) { >+ switch (type) { >+ case rtclog::IceCandidatePairEvent::CHECK_SENT: >+ return IceCandidatePairEventType::kCheckSent; >+ case rtclog::IceCandidatePairEvent::CHECK_RECEIVED: >+ return IceCandidatePairEventType::kCheckReceived; >+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_SENT: >+ return IceCandidatePairEventType::kCheckResponseSent; >+ case rtclog::IceCandidatePairEvent::CHECK_RESPONSE_RECEIVED: >+ return IceCandidatePairEventType::kCheckResponseReceived; >+ } >+ RTC_NOTREACHED(); >+ return IceCandidatePairEventType::kCheckSent; >+} >+ >+// Return default values for header extensions, to use on streams without stored >+// mapping data. Currently this only applies to audio streams, since the mapping >+// is not stored in the event log. >+// TODO(ivoc): Remove this once this mapping is stored in the event log for >+// audio streams. Tracking bug: webrtc:6399 >+webrtc::RtpHeaderExtensionMap GetDefaultHeaderExtensionMap() { >+ webrtc::RtpHeaderExtensionMap default_map; >+ default_map.Register<AudioLevel>(webrtc::RtpExtension::kAudioLevelDefaultId); >+ default_map.Register<TransmissionOffset>( >+ webrtc::RtpExtension::kTimestampOffsetDefaultId); >+ default_map.Register<AbsoluteSendTime>( >+ webrtc::RtpExtension::kAbsSendTimeDefaultId); >+ default_map.Register<VideoOrientation>( >+ webrtc::RtpExtension::kVideoRotationDefaultId); >+ default_map.Register<VideoContentTypeExtension>( >+ webrtc::RtpExtension::kVideoContentTypeDefaultId); >+ default_map.Register<VideoTimingExtension>( >+ webrtc::RtpExtension::kVideoTimingDefaultId); >+ default_map.Register<TransportSequenceNumber>( >+ webrtc::RtpExtension::kTransportSequenceNumberDefaultId); >+ default_map.Register<PlayoutDelayLimits>( >+ webrtc::RtpExtension::kPlayoutDelayDefaultId); >+ return default_map; >+} >+ >+std::pair<uint64_t, bool> ParseVarInt( >+ std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) >+ uint64_t varint = 0; >+ for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) { >+ // The most significant bit of each byte is 0 if it is the last byte in >+ // the varint and 1 otherwise. Thus, we take the 7 least significant bits >+ // of each byte and shift them 7 bits for each byte read previously to get >+ // the (unsigned) integer. >+ int byte = stream.get(); >+ if (stream.eof()) { >+ return std::make_pair(varint, false); >+ } >+ RTC_DCHECK_GE(byte, 0); >+ RTC_DCHECK_LE(byte, 255); >+ varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * bytes_read); >+ if ((byte & 0x80) == 0) { >+ return std::make_pair(varint, true); >+ } >+ } >+ return std::make_pair(varint, false); >+} >+ >+void GetHeaderExtensions(std::vector<RtpExtension>* header_extensions, >+ const RepeatedPtrField<rtclog::RtpHeaderExtension>& >+ proto_header_extensions) { >+ header_extensions->clear(); >+ for (auto& p : proto_header_extensions) { >+ RTC_CHECK(p.has_name()); >+ RTC_CHECK(p.has_id()); >+ const std::string& name = p.name(); >+ int id = p.id(); >+ header_extensions->push_back(RtpExtension(name, id)); >+ } >+} >+ >+} // namespace >+ >+ParsedRtcEventLogNew::ParsedRtcEventLogNew( >+ UnconfiguredHeaderExtensions parse_unconfigured_header_extensions) >+ : parse_unconfigured_header_extensions_( >+ parse_unconfigured_header_extensions) { >+ Clear(); >+} >+ >+void ParsedRtcEventLogNew::Clear() { >+ events_.clear(); >+ default_extension_map_ = GetDefaultHeaderExtensionMap(); >+ >+ incoming_rtx_ssrcs_.clear(); >+ incoming_video_ssrcs_.clear(); >+ incoming_audio_ssrcs_.clear(); >+ outgoing_rtx_ssrcs_.clear(); >+ outgoing_video_ssrcs_.clear(); >+ outgoing_audio_ssrcs_.clear(); >+ >+ incoming_rtp_packets_map_.clear(); >+ outgoing_rtp_packets_map_.clear(); >+ incoming_rtp_packets_by_ssrc_.clear(); >+ outgoing_rtp_packets_by_ssrc_.clear(); >+ incoming_rtp_packet_views_by_ssrc_.clear(); >+ outgoing_rtp_packet_views_by_ssrc_.clear(); >+ >+ incoming_rtcp_packets_.clear(); >+ outgoing_rtcp_packets_.clear(); >+ >+ incoming_rr_.clear(); >+ outgoing_rr_.clear(); >+ incoming_sr_.clear(); >+ outgoing_sr_.clear(); >+ incoming_nack_.clear(); >+ outgoing_nack_.clear(); >+ incoming_remb_.clear(); >+ outgoing_remb_.clear(); >+ incoming_transport_feedback_.clear(); >+ outgoing_transport_feedback_.clear(); >+ >+ start_log_events_.clear(); >+ stop_log_events_.clear(); >+ audio_playout_events_.clear(); >+ audio_network_adaptation_events_.clear(); >+ bwe_probe_cluster_created_events_.clear(); >+ bwe_probe_failure_events_.clear(); >+ bwe_probe_success_events_.clear(); >+ bwe_delay_updates_.clear(); >+ bwe_loss_updates_.clear(); >+ alr_state_events_.clear(); >+ ice_candidate_pair_configs_.clear(); >+ ice_candidate_pair_events_.clear(); >+ audio_recv_configs_.clear(); >+ audio_send_configs_.clear(); >+ video_recv_configs_.clear(); >+ video_send_configs_.clear(); >+ >+ memset(last_incoming_rtcp_packet_, 0, IP_PACKET_SIZE); >+ last_incoming_rtcp_packet_length_ = 0; >+ >+ first_timestamp_ = std::numeric_limits<int64_t>::max(); >+ last_timestamp_ = std::numeric_limits<int64_t>::min(); >+ >+ incoming_rtp_extensions_maps_.clear(); >+ outgoing_rtp_extensions_maps_.clear(); >+} >+ >+bool ParsedRtcEventLogNew::ParseFile(const std::string& filename) { >+ std::ifstream file( // no-presubmit-check TODO(webrtc:8982) >+ filename, std::ios_base::in | std::ios_base::binary); >+ if (!file.good() || !file.is_open()) { >+ RTC_LOG(LS_WARNING) << "Could not open file for reading."; >+ return false; >+ } >+ >+ return ParseStream(file); >+} >+ >+bool ParsedRtcEventLogNew::ParseString(const std::string& s) { >+ std::istringstream stream( // no-presubmit-check TODO(webrtc:8982) >+ s, std::ios_base::in | std::ios_base::binary); >+ return ParseStream(stream); >+} >+ >+bool ParsedRtcEventLogNew::ParseStream( >+ std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) >+ Clear(); >+ bool success = ParseStreamInternal(stream); >+ >+ // ParseStreamInternal stores the RTP packets in a map indexed by SSRC. >+ // Since we dont need rapid lookup based on SSRC after parsing, we move the >+ // packets_streams from map to vector. >+ incoming_rtp_packets_by_ssrc_.reserve(incoming_rtp_packets_map_.size()); >+ for (const auto& kv : incoming_rtp_packets_map_) { >+ incoming_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamIncoming()); >+ incoming_rtp_packets_by_ssrc_.back().ssrc = kv.first; >+ incoming_rtp_packets_by_ssrc_.back().incoming_packets = >+ std::move(kv.second); >+ } >+ incoming_rtp_packets_map_.clear(); >+ outgoing_rtp_packets_by_ssrc_.reserve(outgoing_rtp_packets_map_.size()); >+ for (const auto& kv : outgoing_rtp_packets_map_) { >+ outgoing_rtp_packets_by_ssrc_.emplace_back(LoggedRtpStreamOutgoing()); >+ outgoing_rtp_packets_by_ssrc_.back().ssrc = kv.first; >+ outgoing_rtp_packets_by_ssrc_.back().outgoing_packets = >+ std::move(kv.second); >+ } >+ outgoing_rtp_packets_map_.clear(); >+ >+ // Build PacketViews for easier iteration over RTP packets >+ for (const auto& stream : incoming_rtp_packets_by_ssrc_) { >+ incoming_rtp_packet_views_by_ssrc_.emplace_back( >+ LoggedRtpStreamView(stream.ssrc, stream.incoming_packets.data(), >+ stream.incoming_packets.size())); >+ } >+ for (const auto& stream : outgoing_rtp_packets_by_ssrc_) { >+ outgoing_rtp_packet_views_by_ssrc_.emplace_back( >+ LoggedRtpStreamView(stream.ssrc, stream.outgoing_packets.data(), >+ stream.outgoing_packets.size())); >+ } >+ >+ return success; >+} >+ >+bool ParsedRtcEventLogNew::ParseStreamInternal( >+ std::istream& stream) { // no-presubmit-check TODO(webrtc:8982) >+ const size_t kMaxEventSize = (1u << 16) - 1; >+ std::vector<char> tmp_buffer(kMaxEventSize); >+ uint64_t tag; >+ uint64_t message_length; >+ bool success; >+ >+ RTC_DCHECK(stream.good()); >+ >+ while (1) { >+ // Check whether we have reached end of file. >+ stream.peek(); >+ if (stream.eof()) { >+ break; >+ } >+ >+ // Read the next message tag. The tag number is defined as >+ // (fieldnumber << 3) | wire_type. In our case, the field number is >+ // supposed to be 1 and the wire type for an >+ // length-delimited field is 2. >+ const uint64_t kExpectedTag = (1 << 3) | 2; >+ std::tie(tag, success) = ParseVarInt(stream); >+ if (!success) { >+ RTC_LOG(LS_WARNING) >+ << "Missing field tag from beginning of protobuf event."; >+ return false; >+ } else if (tag != kExpectedTag) { >+ RTC_LOG(LS_WARNING) >+ << "Unexpected field tag at beginning of protobuf event."; >+ return false; >+ } >+ >+ // Read the length field. >+ std::tie(message_length, success) = ParseVarInt(stream); >+ if (!success) { >+ RTC_LOG(LS_WARNING) << "Missing message length after protobuf field tag."; >+ return false; >+ } else if (message_length > kMaxEventSize) { >+ RTC_LOG(LS_WARNING) << "Protobuf message length is too large."; >+ return false; >+ } >+ >+ // Read the next protobuf event to a temporary char buffer. >+ stream.read(tmp_buffer.data(), message_length); >+ if (stream.gcount() != static_cast<int>(message_length)) { >+ RTC_LOG(LS_WARNING) << "Failed to read protobuf message from file."; >+ return false; >+ } >+ >+ // Parse the protobuf event from the buffer. >+ rtclog::Event event; >+ if (!event.ParseFromArray(tmp_buffer.data(), message_length)) { >+ RTC_LOG(LS_WARNING) << "Failed to parse protobuf message."; >+ return false; >+ } >+ >+ StoreParsedEvent(event); >+ events_.push_back(event); >+ } >+ return true; >+} >+ >+void ParsedRtcEventLogNew::StoreParsedEvent(const rtclog::Event& event) { >+ if (event.type() != rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT && >+ event.type() != rtclog::Event::VIDEO_SENDER_CONFIG_EVENT && >+ event.type() != rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT && >+ event.type() != rtclog::Event::AUDIO_SENDER_CONFIG_EVENT && >+ event.type() != rtclog::Event::LOG_START && >+ event.type() != rtclog::Event::LOG_END) { >+ RTC_CHECK(event.has_timestamp_us()); >+ int64_t timestamp = event.timestamp_us(); >+ first_timestamp_ = std::min(first_timestamp_, timestamp); >+ last_timestamp_ = std::max(last_timestamp_, timestamp); >+ } >+ >+ switch (GetEventType(event)) { >+ case ParsedRtcEventLogNew::EventType::VIDEO_RECEIVER_CONFIG_EVENT: { >+ rtclog::StreamConfig config = GetVideoReceiveConfig(event); >+ video_recv_configs_.emplace_back(GetTimestamp(event), config); >+ incoming_rtp_extensions_maps_[config.remote_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ // TODO(terelius): I don't understand the reason for configuring header >+ // extensions for the local SSRC. I think it should be removed, but for >+ // now I want to preserve the previous functionality. >+ incoming_rtp_extensions_maps_[config.local_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ incoming_video_ssrcs_.insert(config.remote_ssrc); >+ incoming_video_ssrcs_.insert(config.rtx_ssrc); >+ incoming_rtx_ssrcs_.insert(config.rtx_ssrc); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::VIDEO_SENDER_CONFIG_EVENT: { >+ std::vector<rtclog::StreamConfig> configs = GetVideoSendConfig(event); >+ video_send_configs_.emplace_back(GetTimestamp(event), configs); >+ for (const auto& config : configs) { >+ outgoing_rtp_extensions_maps_[config.local_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ outgoing_rtp_extensions_maps_[config.rtx_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ outgoing_video_ssrcs_.insert(config.local_ssrc); >+ outgoing_video_ssrcs_.insert(config.rtx_ssrc); >+ outgoing_rtx_ssrcs_.insert(config.rtx_ssrc); >+ } >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::AUDIO_RECEIVER_CONFIG_EVENT: { >+ rtclog::StreamConfig config = GetAudioReceiveConfig(event); >+ audio_recv_configs_.emplace_back(GetTimestamp(event), config); >+ incoming_rtp_extensions_maps_[config.remote_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ incoming_rtp_extensions_maps_[config.local_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ incoming_audio_ssrcs_.insert(config.remote_ssrc); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::AUDIO_SENDER_CONFIG_EVENT: { >+ rtclog::StreamConfig config = GetAudioSendConfig(event); >+ audio_send_configs_.emplace_back(GetTimestamp(event), config); >+ outgoing_rtp_extensions_maps_[config.local_ssrc] = >+ RtpHeaderExtensionMap(config.rtp_extensions); >+ outgoing_audio_ssrcs_.insert(config.local_ssrc); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::RTP_EVENT: { >+ PacketDirection direction; >+ uint8_t header[IP_PACKET_SIZE]; >+ size_t header_length; >+ size_t total_length; >+ const RtpHeaderExtensionMap* extension_map = GetRtpHeader( >+ event, &direction, header, &header_length, &total_length, nullptr); >+ RtpUtility::RtpHeaderParser rtp_parser(header, header_length); >+ RTPHeader parsed_header; >+ if (extension_map != nullptr) { >+ rtp_parser.Parse(&parsed_header, extension_map); >+ } else { >+ // Use the default extension map. >+ // TODO(terelius): This should be removed. GetRtpHeader will return the >+ // default map if the parser is configured for it. >+ // TODO(ivoc): Once configuration of audio streams is stored in the >+ // event log, this can be removed. >+ // Tracking bug: webrtc:6399 >+ rtp_parser.Parse(&parsed_header, &default_extension_map_); >+ } >+ RTC_CHECK(event.has_timestamp_us()); >+ uint64_t timestamp_us = event.timestamp_us(); >+ if (direction == kIncomingPacket) { >+ incoming_rtp_packets_map_[parsed_header.ssrc].push_back( >+ LoggedRtpPacketIncoming(timestamp_us, parsed_header, header_length, >+ total_length)); >+ } else { >+ outgoing_rtp_packets_map_[parsed_header.ssrc].push_back( >+ LoggedRtpPacketOutgoing(timestamp_us, parsed_header, header_length, >+ total_length)); >+ } >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::RTCP_EVENT: { >+ PacketDirection direction; >+ uint8_t packet[IP_PACKET_SIZE]; >+ size_t total_length; >+ GetRtcpPacket(event, &direction, packet, &total_length); >+ uint64_t timestamp_us = GetTimestamp(event); >+ RTC_CHECK_LE(total_length, IP_PACKET_SIZE); >+ if (direction == kIncomingPacket) { >+ // Currently incoming RTCP packets are logged twice, both for audio and >+ // video. Only act on one of them. Compare against the previous parsed >+ // incoming RTCP packet. >+ if (total_length == last_incoming_rtcp_packet_length_ && >+ memcmp(last_incoming_rtcp_packet_, packet, total_length) == 0) >+ break; >+ incoming_rtcp_packets_.push_back( >+ LoggedRtcpPacketIncoming(timestamp_us, packet, total_length)); >+ last_incoming_rtcp_packet_length_ = total_length; >+ memcpy(last_incoming_rtcp_packet_, packet, total_length); >+ } else { >+ outgoing_rtcp_packets_.push_back( >+ LoggedRtcpPacketOutgoing(timestamp_us, packet, total_length)); >+ } >+ rtcp::CommonHeader header; >+ const uint8_t* packet_end = packet + total_length; >+ for (const uint8_t* block = packet; block < packet_end; >+ block = header.NextPacket()) { >+ RTC_CHECK(header.Parse(block, packet_end - block)); >+ if (header.type() == rtcp::TransportFeedback::kPacketType && >+ header.fmt() == rtcp::TransportFeedback::kFeedbackMessageType) { >+ if (direction == kIncomingPacket) { >+ incoming_transport_feedback_.emplace_back(); >+ LoggedRtcpPacketTransportFeedback& parsed_block = >+ incoming_transport_feedback_.back(); >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (!parsed_block.transport_feedback.Parse(header)) >+ incoming_transport_feedback_.pop_back(); >+ } else { >+ outgoing_transport_feedback_.emplace_back(); >+ LoggedRtcpPacketTransportFeedback& parsed_block = >+ outgoing_transport_feedback_.back(); >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (!parsed_block.transport_feedback.Parse(header)) >+ outgoing_transport_feedback_.pop_back(); >+ } >+ } else if (header.type() == rtcp::SenderReport::kPacketType) { >+ LoggedRtcpPacketSenderReport parsed_block; >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (parsed_block.sr.Parse(header)) { >+ if (direction == kIncomingPacket) >+ incoming_sr_.push_back(std::move(parsed_block)); >+ else >+ outgoing_sr_.push_back(std::move(parsed_block)); >+ } >+ } else if (header.type() == rtcp::ReceiverReport::kPacketType) { >+ LoggedRtcpPacketReceiverReport parsed_block; >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (parsed_block.rr.Parse(header)) { >+ if (direction == kIncomingPacket) >+ incoming_rr_.push_back(std::move(parsed_block)); >+ else >+ outgoing_rr_.push_back(std::move(parsed_block)); >+ } >+ } else if (header.type() == rtcp::Remb::kPacketType && >+ header.fmt() == rtcp::Remb::kFeedbackMessageType) { >+ LoggedRtcpPacketRemb parsed_block; >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (parsed_block.remb.Parse(header)) { >+ if (direction == kIncomingPacket) >+ incoming_remb_.push_back(std::move(parsed_block)); >+ else >+ outgoing_remb_.push_back(std::move(parsed_block)); >+ } >+ } else if (header.type() == rtcp::Nack::kPacketType && >+ header.fmt() == rtcp::Nack::kFeedbackMessageType) { >+ LoggedRtcpPacketNack parsed_block; >+ parsed_block.timestamp_us = GetTimestamp(event); >+ if (parsed_block.nack.Parse(header)) { >+ if (direction == kIncomingPacket) >+ incoming_nack_.push_back(std::move(parsed_block)); >+ else >+ outgoing_nack_.push_back(std::move(parsed_block)); >+ } >+ } >+ } >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::LOG_START: { >+ start_log_events_.push_back(LoggedStartEvent(GetTimestamp(event))); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::LOG_END: { >+ stop_log_events_.push_back(LoggedStopEvent(GetTimestamp(event))); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT: { >+ LoggedAudioPlayoutEvent playout_event = GetAudioPlayout(event); >+ audio_playout_events_[playout_event.ssrc].push_back(playout_event); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::LOSS_BASED_BWE_UPDATE: { >+ bwe_loss_updates_.push_back(GetLossBasedBweUpdate(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::DELAY_BASED_BWE_UPDATE: { >+ bwe_delay_updates_.push_back(GetDelayBasedBweUpdate(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::AUDIO_NETWORK_ADAPTATION_EVENT: { >+ LoggedAudioNetworkAdaptationEvent ana_event = >+ GetAudioNetworkAdaptation(event); >+ audio_network_adaptation_events_.push_back(ana_event); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT: { >+ bwe_probe_cluster_created_events_.push_back( >+ GetBweProbeClusterCreated(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::BWE_PROBE_FAILURE_EVENT: { >+ bwe_probe_failure_events_.push_back(GetBweProbeFailure(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::BWE_PROBE_SUCCESS_EVENT: { >+ bwe_probe_success_events_.push_back(GetBweProbeSuccess(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::ALR_STATE_EVENT: { >+ alr_state_events_.push_back(GetAlrState(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_CONFIG: { >+ ice_candidate_pair_configs_.push_back(GetIceCandidatePairConfig(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::ICE_CANDIDATE_PAIR_EVENT: { >+ ice_candidate_pair_events_.push_back(GetIceCandidatePairEvent(event)); >+ break; >+ } >+ case ParsedRtcEventLogNew::EventType::UNKNOWN_EVENT: { >+ break; >+ } >+ } >+} >+ >+size_t ParsedRtcEventLogNew::GetNumberOfEvents() const { >+ return events_.size(); >+} >+ >+int64_t ParsedRtcEventLogNew::GetTimestamp(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetTimestamp(event); >+} >+ >+int64_t ParsedRtcEventLogNew::GetTimestamp(const rtclog::Event& event) const { >+ RTC_CHECK(event.has_timestamp_us()); >+ return event.timestamp_us(); >+} >+ >+ParsedRtcEventLogNew::EventType ParsedRtcEventLogNew::GetEventType( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetEventType(event); >+} >+ >+ParsedRtcEventLogNew::EventType ParsedRtcEventLogNew::GetEventType( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ if (event.type() == rtclog::Event::BWE_PROBE_RESULT_EVENT) { >+ RTC_CHECK(event.has_probe_result()); >+ RTC_CHECK(event.probe_result().has_result()); >+ if (event.probe_result().result() == rtclog::BweProbeResult::SUCCESS) >+ return ParsedRtcEventLogNew::EventType::BWE_PROBE_SUCCESS_EVENT; >+ return ParsedRtcEventLogNew::EventType::BWE_PROBE_FAILURE_EVENT; >+ } >+ return GetRuntimeEventType(event.type()); >+} >+ >+// The header must have space for at least IP_PACKET_SIZE bytes. >+const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLogNew::GetRtpHeader( >+ size_t index, >+ PacketDirection* incoming, >+ uint8_t* header, >+ size_t* header_length, >+ size_t* total_length, >+ int* probe_cluster_id) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetRtpHeader(event, incoming, header, header_length, total_length, >+ probe_cluster_id); >+} >+ >+const webrtc::RtpHeaderExtensionMap* ParsedRtcEventLogNew::GetRtpHeader( >+ const rtclog::Event& event, >+ PacketDirection* incoming, >+ uint8_t* header, >+ size_t* header_length, >+ size_t* total_length, >+ int* probe_cluster_id) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::RTP_EVENT); >+ RTC_CHECK(event.has_rtp_packet()); >+ const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); >+ // Get direction of packet. >+ RTC_CHECK(rtp_packet.has_incoming()); >+ if (incoming != nullptr) { >+ *incoming = rtp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; >+ } >+ // Get packet length. >+ RTC_CHECK(rtp_packet.has_packet_length()); >+ if (total_length != nullptr) { >+ *total_length = rtp_packet.packet_length(); >+ } >+ // Get header length. >+ RTC_CHECK(rtp_packet.has_header()); >+ if (header_length != nullptr) { >+ *header_length = rtp_packet.header().size(); >+ } >+ if (probe_cluster_id != nullptr) { >+ if (rtp_packet.has_probe_cluster_id()) { >+ *probe_cluster_id = rtp_packet.probe_cluster_id(); >+ RTC_CHECK_NE(*probe_cluster_id, PacedPacketInfo::kNotAProbe); >+ } else { >+ *probe_cluster_id = PacedPacketInfo::kNotAProbe; >+ } >+ } >+ // Get header contents. >+ if (header != nullptr) { >+ const size_t kMinRtpHeaderSize = 12; >+ RTC_CHECK_GE(rtp_packet.header().size(), kMinRtpHeaderSize); >+ RTC_CHECK_LE(rtp_packet.header().size(), >+ static_cast<size_t>(IP_PACKET_SIZE)); >+ memcpy(header, rtp_packet.header().data(), rtp_packet.header().size()); >+ uint32_t ssrc = ByteReader<uint32_t>::ReadBigEndian(header + 8); >+ auto& extensions_maps = rtp_packet.incoming() >+ ? incoming_rtp_extensions_maps_ >+ : outgoing_rtp_extensions_maps_; >+ auto it = extensions_maps.find(ssrc); >+ if (it != extensions_maps.end()) { >+ return &(it->second); >+ } >+ if (parse_unconfigured_header_extensions_ == >+ UnconfiguredHeaderExtensions::kAttemptWebrtcDefaultConfig) { >+ RTC_LOG(LS_WARNING) << "Using default header extension map for SSRC " >+ << ssrc; >+ extensions_maps.insert(std::make_pair(ssrc, default_extension_map_)); >+ return &default_extension_map_; >+ } >+ } >+ return nullptr; >+} >+ >+// The packet must have space for at least IP_PACKET_SIZE bytes. >+void ParsedRtcEventLogNew::GetRtcpPacket(size_t index, >+ PacketDirection* incoming, >+ uint8_t* packet, >+ size_t* length) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ GetRtcpPacket(event, incoming, packet, length); >+} >+ >+void ParsedRtcEventLogNew::GetRtcpPacket(const rtclog::Event& event, >+ PacketDirection* incoming, >+ uint8_t* packet, >+ size_t* length) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::RTCP_EVENT); >+ RTC_CHECK(event.has_rtcp_packet()); >+ const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); >+ // Get direction of packet. >+ RTC_CHECK(rtcp_packet.has_incoming()); >+ if (incoming != nullptr) { >+ *incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; >+ } >+ // Get packet length. >+ RTC_CHECK(rtcp_packet.has_packet_data()); >+ if (length != nullptr) { >+ *length = rtcp_packet.packet_data().size(); >+ } >+ // Get packet contents. >+ if (packet != nullptr) { >+ RTC_CHECK_LE(rtcp_packet.packet_data().size(), >+ static_cast<unsigned>(IP_PACKET_SIZE)); >+ memcpy(packet, rtcp_packet.packet_data().data(), >+ rtcp_packet.packet_data().size()); >+ } >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetVideoReceiveConfig( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ return GetVideoReceiveConfig(events_[index]); >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetVideoReceiveConfig( >+ const rtclog::Event& event) const { >+ rtclog::StreamConfig config; >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT); >+ RTC_CHECK(event.has_video_receiver_config()); >+ const rtclog::VideoReceiveConfig& receiver_config = >+ event.video_receiver_config(); >+ // Get SSRCs. >+ RTC_CHECK(receiver_config.has_remote_ssrc()); >+ config.remote_ssrc = receiver_config.remote_ssrc(); >+ RTC_CHECK(receiver_config.has_local_ssrc()); >+ config.local_ssrc = receiver_config.local_ssrc(); >+ config.rtx_ssrc = 0; >+ // Get RTCP settings. >+ RTC_CHECK(receiver_config.has_rtcp_mode()); >+ config.rtcp_mode = GetRuntimeRtcpMode(receiver_config.rtcp_mode()); >+ RTC_CHECK(receiver_config.has_remb()); >+ config.remb = receiver_config.remb(); >+ >+ // Get RTX map. >+ std::map<uint32_t, const rtclog::RtxConfig> rtx_map; >+ for (int i = 0; i < receiver_config.rtx_map_size(); i++) { >+ const rtclog::RtxMap& map = receiver_config.rtx_map(i); >+ RTC_CHECK(map.has_payload_type()); >+ RTC_CHECK(map.has_config()); >+ RTC_CHECK(map.config().has_rtx_ssrc()); >+ RTC_CHECK(map.config().has_rtx_payload_type()); >+ rtx_map.insert(std::make_pair(map.payload_type(), map.config())); >+ } >+ >+ // Get header extensions. >+ GetHeaderExtensions(&config.rtp_extensions, >+ receiver_config.header_extensions()); >+ // Get decoders. >+ config.codecs.clear(); >+ for (int i = 0; i < receiver_config.decoders_size(); i++) { >+ RTC_CHECK(receiver_config.decoders(i).has_name()); >+ RTC_CHECK(receiver_config.decoders(i).has_payload_type()); >+ int rtx_payload_type = 0; >+ auto rtx_it = rtx_map.find(receiver_config.decoders(i).payload_type()); >+ if (rtx_it != rtx_map.end()) { >+ rtx_payload_type = rtx_it->second.rtx_payload_type(); >+ if (config.rtx_ssrc != 0 && >+ config.rtx_ssrc != rtx_it->second.rtx_ssrc()) { >+ RTC_LOG(LS_WARNING) >+ << "RtcEventLog protobuf contained different SSRCs for " >+ "different received RTX payload types. Will only use " >+ "rtx_ssrc = " >+ << config.rtx_ssrc << "."; >+ } else { >+ config.rtx_ssrc = rtx_it->second.rtx_ssrc(); >+ } >+ } >+ config.codecs.emplace_back(receiver_config.decoders(i).name(), >+ receiver_config.decoders(i).payload_type(), >+ rtx_payload_type); >+ } >+ return config; >+} >+ >+std::vector<rtclog::StreamConfig> ParsedRtcEventLogNew::GetVideoSendConfig( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ return GetVideoSendConfig(events_[index]); >+} >+ >+std::vector<rtclog::StreamConfig> ParsedRtcEventLogNew::GetVideoSendConfig( >+ const rtclog::Event& event) const { >+ std::vector<rtclog::StreamConfig> configs; >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_SENDER_CONFIG_EVENT); >+ RTC_CHECK(event.has_video_sender_config()); >+ const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); >+ if (sender_config.rtx_ssrcs_size() > 0 && >+ sender_config.ssrcs_size() != sender_config.rtx_ssrcs_size()) { >+ RTC_LOG(WARNING) >+ << "VideoSendConfig is configured for RTX but the number of " >+ "SSRCs doesn't match the number of RTX SSRCs."; >+ } >+ configs.resize(sender_config.ssrcs_size()); >+ for (int i = 0; i < sender_config.ssrcs_size(); i++) { >+ // Get SSRCs. >+ configs[i].local_ssrc = sender_config.ssrcs(i); >+ if (sender_config.rtx_ssrcs_size() > 0 && >+ i < sender_config.rtx_ssrcs_size()) { >+ RTC_CHECK(sender_config.has_rtx_payload_type()); >+ configs[i].rtx_ssrc = sender_config.rtx_ssrcs(i); >+ } >+ // Get header extensions. >+ GetHeaderExtensions(&configs[i].rtp_extensions, >+ sender_config.header_extensions()); >+ >+ // Get the codec. >+ RTC_CHECK(sender_config.has_encoder()); >+ RTC_CHECK(sender_config.encoder().has_name()); >+ RTC_CHECK(sender_config.encoder().has_payload_type()); >+ configs[i].codecs.emplace_back( >+ sender_config.encoder().name(), sender_config.encoder().payload_type(), >+ sender_config.has_rtx_payload_type() ? sender_config.rtx_payload_type() >+ : 0); >+ } >+ return configs; >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioReceiveConfig( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ return GetAudioReceiveConfig(events_[index]); >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioReceiveConfig( >+ const rtclog::Event& event) const { >+ rtclog::StreamConfig config; >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT); >+ RTC_CHECK(event.has_audio_receiver_config()); >+ const rtclog::AudioReceiveConfig& receiver_config = >+ event.audio_receiver_config(); >+ // Get SSRCs. >+ RTC_CHECK(receiver_config.has_remote_ssrc()); >+ config.remote_ssrc = receiver_config.remote_ssrc(); >+ RTC_CHECK(receiver_config.has_local_ssrc()); >+ config.local_ssrc = receiver_config.local_ssrc(); >+ // Get header extensions. >+ GetHeaderExtensions(&config.rtp_extensions, >+ receiver_config.header_extensions()); >+ return config; >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioSendConfig( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ return GetAudioSendConfig(events_[index]); >+} >+ >+rtclog::StreamConfig ParsedRtcEventLogNew::GetAudioSendConfig( >+ const rtclog::Event& event) const { >+ rtclog::StreamConfig config; >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_SENDER_CONFIG_EVENT); >+ RTC_CHECK(event.has_audio_sender_config()); >+ const rtclog::AudioSendConfig& sender_config = event.audio_sender_config(); >+ // Get SSRCs. >+ RTC_CHECK(sender_config.has_ssrc()); >+ config.local_ssrc = sender_config.ssrc(); >+ // Get header extensions. >+ GetHeaderExtensions(&config.rtp_extensions, >+ sender_config.header_extensions()); >+ return config; >+} >+ >+LoggedAudioPlayoutEvent ParsedRtcEventLogNew::GetAudioPlayout( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetAudioPlayout(event); >+} >+ >+LoggedAudioPlayoutEvent ParsedRtcEventLogNew::GetAudioPlayout( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_PLAYOUT_EVENT); >+ RTC_CHECK(event.has_audio_playout_event()); >+ const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event(); >+ LoggedAudioPlayoutEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(playout_event.has_local_ssrc()); >+ res.ssrc = playout_event.local_ssrc(); >+ return res; >+} >+ >+LoggedBweLossBasedUpdate ParsedRtcEventLogNew::GetLossBasedBweUpdate( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetLossBasedBweUpdate(event); >+} >+ >+LoggedBweLossBasedUpdate ParsedRtcEventLogNew::GetLossBasedBweUpdate( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::LOSS_BASED_BWE_UPDATE); >+ RTC_CHECK(event.has_loss_based_bwe_update()); >+ const rtclog::LossBasedBweUpdate& loss_event = event.loss_based_bwe_update(); >+ >+ LoggedBweLossBasedUpdate bwe_update; >+ bwe_update.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(loss_event.has_bitrate_bps()); >+ bwe_update.bitrate_bps = loss_event.bitrate_bps(); >+ RTC_CHECK(loss_event.has_fraction_loss()); >+ bwe_update.fraction_lost = loss_event.fraction_loss(); >+ RTC_CHECK(loss_event.has_total_packets()); >+ bwe_update.expected_packets = loss_event.total_packets(); >+ return bwe_update; >+} >+ >+LoggedBweDelayBasedUpdate ParsedRtcEventLogNew::GetDelayBasedBweUpdate( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetDelayBasedBweUpdate(event); >+} >+ >+LoggedBweDelayBasedUpdate ParsedRtcEventLogNew::GetDelayBasedBweUpdate( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::DELAY_BASED_BWE_UPDATE); >+ RTC_CHECK(event.has_delay_based_bwe_update()); >+ const rtclog::DelayBasedBweUpdate& delay_event = >+ event.delay_based_bwe_update(); >+ >+ LoggedBweDelayBasedUpdate res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(delay_event.has_bitrate_bps()); >+ res.bitrate_bps = delay_event.bitrate_bps(); >+ RTC_CHECK(delay_event.has_detector_state()); >+ res.detector_state = GetRuntimeDetectorState(delay_event.detector_state()); >+ return res; >+} >+ >+LoggedAudioNetworkAdaptationEvent >+ParsedRtcEventLogNew::GetAudioNetworkAdaptation(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetAudioNetworkAdaptation(event); >+} >+ >+LoggedAudioNetworkAdaptationEvent >+ParsedRtcEventLogNew::GetAudioNetworkAdaptation( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT); >+ RTC_CHECK(event.has_audio_network_adaptation()); >+ const rtclog::AudioNetworkAdaptation& ana_event = >+ event.audio_network_adaptation(); >+ >+ LoggedAudioNetworkAdaptationEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ if (ana_event.has_bitrate_bps()) >+ res.config.bitrate_bps = ana_event.bitrate_bps(); >+ if (ana_event.has_enable_fec()) >+ res.config.enable_fec = ana_event.enable_fec(); >+ if (ana_event.has_enable_dtx()) >+ res.config.enable_dtx = ana_event.enable_dtx(); >+ if (ana_event.has_frame_length_ms()) >+ res.config.frame_length_ms = ana_event.frame_length_ms(); >+ if (ana_event.has_num_channels()) >+ res.config.num_channels = ana_event.num_channels(); >+ if (ana_event.has_uplink_packet_loss_fraction()) >+ res.config.uplink_packet_loss_fraction = >+ ana_event.uplink_packet_loss_fraction(); >+ return res; >+} >+ >+LoggedBweProbeClusterCreatedEvent >+ParsedRtcEventLogNew::GetBweProbeClusterCreated(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetBweProbeClusterCreated(event); >+} >+ >+LoggedBweProbeClusterCreatedEvent >+ParsedRtcEventLogNew::GetBweProbeClusterCreated( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT); >+ RTC_CHECK(event.has_probe_cluster()); >+ const rtclog::BweProbeCluster& pcc_event = event.probe_cluster(); >+ LoggedBweProbeClusterCreatedEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(pcc_event.has_id()); >+ res.id = pcc_event.id(); >+ RTC_CHECK(pcc_event.has_bitrate_bps()); >+ res.bitrate_bps = pcc_event.bitrate_bps(); >+ RTC_CHECK(pcc_event.has_min_packets()); >+ res.min_packets = pcc_event.min_packets(); >+ RTC_CHECK(pcc_event.has_min_bytes()); >+ res.min_bytes = pcc_event.min_bytes(); >+ return res; >+} >+ >+LoggedBweProbeFailureEvent ParsedRtcEventLogNew::GetBweProbeFailure( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetBweProbeFailure(event); >+} >+ >+LoggedBweProbeFailureEvent ParsedRtcEventLogNew::GetBweProbeFailure( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_RESULT_EVENT); >+ RTC_CHECK(event.has_probe_result()); >+ const rtclog::BweProbeResult& pr_event = event.probe_result(); >+ RTC_CHECK(pr_event.has_result()); >+ RTC_CHECK_NE(pr_event.result(), rtclog::BweProbeResult::SUCCESS); >+ >+ LoggedBweProbeFailureEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(pr_event.has_id()); >+ res.id = pr_event.id(); >+ RTC_CHECK(pr_event.has_result()); >+ if (pr_event.result() == >+ rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL) { >+ res.failure_reason = ProbeFailureReason::kInvalidSendReceiveInterval; >+ } else if (pr_event.result() == >+ rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO) { >+ res.failure_reason = ProbeFailureReason::kInvalidSendReceiveRatio; >+ } else if (pr_event.result() == rtclog::BweProbeResult::TIMEOUT) { >+ res.failure_reason = ProbeFailureReason::kTimeout; >+ } else { >+ RTC_NOTREACHED(); >+ } >+ RTC_CHECK(!pr_event.has_bitrate_bps()); >+ >+ return res; >+} >+ >+LoggedBweProbeSuccessEvent ParsedRtcEventLogNew::GetBweProbeSuccess( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetBweProbeSuccess(event); >+} >+ >+LoggedBweProbeSuccessEvent ParsedRtcEventLogNew::GetBweProbeSuccess( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PROBE_RESULT_EVENT); >+ RTC_CHECK(event.has_probe_result()); >+ const rtclog::BweProbeResult& pr_event = event.probe_result(); >+ RTC_CHECK(pr_event.has_result()); >+ RTC_CHECK_EQ(pr_event.result(), rtclog::BweProbeResult::SUCCESS); >+ >+ LoggedBweProbeSuccessEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(pr_event.has_id()); >+ res.id = pr_event.id(); >+ RTC_CHECK(pr_event.has_bitrate_bps()); >+ res.bitrate_bps = pr_event.bitrate_bps(); >+ >+ return res; >+} >+ >+LoggedAlrStateEvent ParsedRtcEventLogNew::GetAlrState(size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& event = events_[index]; >+ return GetAlrState(event); >+} >+ >+LoggedAlrStateEvent ParsedRtcEventLogNew::GetAlrState( >+ const rtclog::Event& event) const { >+ RTC_CHECK(event.has_type()); >+ RTC_CHECK_EQ(event.type(), rtclog::Event::ALR_STATE_EVENT); >+ RTC_CHECK(event.has_alr_state()); >+ const rtclog::AlrState& alr_event = event.alr_state(); >+ LoggedAlrStateEvent res; >+ res.timestamp_us = GetTimestamp(event); >+ RTC_CHECK(alr_event.has_in_alr()); >+ res.in_alr = alr_event.in_alr(); >+ >+ return res; >+} >+ >+LoggedIceCandidatePairConfig ParsedRtcEventLogNew::GetIceCandidatePairConfig( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& rtc_event = events_[index]; >+ return GetIceCandidatePairConfig(rtc_event); >+} >+ >+LoggedIceCandidatePairConfig ParsedRtcEventLogNew::GetIceCandidatePairConfig( >+ const rtclog::Event& rtc_event) const { >+ RTC_CHECK(rtc_event.has_type()); >+ RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_CONFIG); >+ LoggedIceCandidatePairConfig res; >+ const rtclog::IceCandidatePairConfig& config = >+ rtc_event.ice_candidate_pair_config(); >+ res.timestamp_us = GetTimestamp(rtc_event); >+ RTC_CHECK(config.has_config_type()); >+ res.type = GetRuntimeIceCandidatePairConfigType(config.config_type()); >+ RTC_CHECK(config.has_candidate_pair_id()); >+ res.candidate_pair_id = config.candidate_pair_id(); >+ RTC_CHECK(config.has_local_candidate_type()); >+ res.local_candidate_type = >+ GetRuntimeIceCandidateType(config.local_candidate_type()); >+ RTC_CHECK(config.has_local_relay_protocol()); >+ res.local_relay_protocol = >+ GetRuntimeIceCandidatePairProtocol(config.local_relay_protocol()); >+ RTC_CHECK(config.has_local_network_type()); >+ res.local_network_type = >+ GetRuntimeIceCandidateNetworkType(config.local_network_type()); >+ RTC_CHECK(config.has_local_address_family()); >+ res.local_address_family = >+ GetRuntimeIceCandidatePairAddressFamily(config.local_address_family()); >+ RTC_CHECK(config.has_remote_candidate_type()); >+ res.remote_candidate_type = >+ GetRuntimeIceCandidateType(config.remote_candidate_type()); >+ RTC_CHECK(config.has_remote_address_family()); >+ res.remote_address_family = >+ GetRuntimeIceCandidatePairAddressFamily(config.remote_address_family()); >+ RTC_CHECK(config.has_candidate_pair_protocol()); >+ res.candidate_pair_protocol = >+ GetRuntimeIceCandidatePairProtocol(config.candidate_pair_protocol()); >+ return res; >+} >+ >+LoggedIceCandidatePairEvent ParsedRtcEventLogNew::GetIceCandidatePairEvent( >+ size_t index) const { >+ RTC_CHECK_LT(index, GetNumberOfEvents()); >+ const rtclog::Event& rtc_event = events_[index]; >+ return GetIceCandidatePairEvent(rtc_event); >+} >+ >+LoggedIceCandidatePairEvent ParsedRtcEventLogNew::GetIceCandidatePairEvent( >+ const rtclog::Event& rtc_event) const { >+ RTC_CHECK(rtc_event.has_type()); >+ RTC_CHECK_EQ(rtc_event.type(), rtclog::Event::ICE_CANDIDATE_PAIR_EVENT); >+ LoggedIceCandidatePairEvent res; >+ const rtclog::IceCandidatePairEvent& event = >+ rtc_event.ice_candidate_pair_event(); >+ res.timestamp_us = GetTimestamp(rtc_event); >+ RTC_CHECK(event.has_event_type()); >+ res.type = GetRuntimeIceCandidatePairEventType(event.event_type()); >+ RTC_CHECK(event.has_candidate_pair_id()); >+ res.candidate_pair_id = event.candidate_pair_id(); >+ return res; >+} >+ >+// Returns the MediaType for registered SSRCs. Search from the end to use last >+// registered types first. >+ParsedRtcEventLogNew::MediaType ParsedRtcEventLogNew::GetMediaType( >+ uint32_t ssrc, >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ if (std::find(incoming_video_ssrcs_.begin(), incoming_video_ssrcs_.end(), >+ ssrc) != incoming_video_ssrcs_.end()) { >+ return MediaType::VIDEO; >+ } >+ if (std::find(incoming_audio_ssrcs_.begin(), incoming_audio_ssrcs_.end(), >+ ssrc) != incoming_audio_ssrcs_.end()) { >+ return MediaType::AUDIO; >+ } >+ } else { >+ if (std::find(outgoing_video_ssrcs_.begin(), outgoing_video_ssrcs_.end(), >+ ssrc) != outgoing_video_ssrcs_.end()) { >+ return MediaType::VIDEO; >+ } >+ if (std::find(outgoing_audio_ssrcs_.begin(), outgoing_audio_ssrcs_.end(), >+ ssrc) != outgoing_audio_ssrcs_.end()) { >+ return MediaType::AUDIO; >+ } >+ } >+ return MediaType::ANY; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.h >new file mode 100644 >index 00000000000..a4a130228c9 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_parser_new.h >@@ -0,0 +1,982 @@ >+/* >+ * Copyright (c) 2016 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. >+ */ >+#ifndef LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER_NEW_H_ >+#define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER_NEW_H_ >+ >+#include <iterator> >+#include <map> >+#include <set> >+#include <string> >+#include <utility> // pair >+#include <vector> >+ >+#include "call/video_receive_stream.h" >+#include "call/video_send_stream.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" >+#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" >+#include "logging/rtc_event_log/rtc_event_log.h" >+#include "logging/rtc_event_log/rtc_stream_config.h" >+#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" >+#include "modules/rtp_rtcp/include/rtp_header_extension_map.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/nack.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/remb.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" >+#include "rtc_base/ignore_wundef.h" >+ >+// Files generated at build-time by the protobuf compiler. >+RTC_PUSH_IGNORING_WUNDEF() >+#ifdef WEBRTC_ANDROID_PLATFORM_BUILD >+#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h" >+#else >+#include "logging/rtc_event_log/rtc_event_log.pb.h" >+#endif >+RTC_POP_IGNORING_WUNDEF() >+ >+namespace webrtc { >+ >+enum class BandwidthUsage; >+struct AudioEncoderRuntimeConfig; >+ >+struct LoggedAlrStateEvent { >+ int64_t timestamp_us; >+ bool in_alr; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedAudioPlayoutEvent { >+ int64_t timestamp_us; >+ uint32_t ssrc; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedAudioNetworkAdaptationEvent { >+ int64_t timestamp_us; >+ AudioEncoderRuntimeConfig config; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedBweDelayBasedUpdate { >+ int64_t timestamp_us; >+ int32_t bitrate_bps; >+ BandwidthUsage detector_state; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedBweLossBasedUpdate { >+ int64_t timestamp_us; >+ int32_t bitrate_bps; >+ uint8_t fraction_lost; >+ int32_t expected_packets; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedBweProbeClusterCreatedEvent { >+ int64_t timestamp_us; >+ int32_t id; >+ int32_t bitrate_bps; >+ uint32_t min_packets; >+ uint32_t min_bytes; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedBweProbeSuccessEvent { >+ int64_t timestamp_us; >+ int32_t id; >+ int32_t bitrate_bps; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedBweProbeFailureEvent { >+ int64_t timestamp_us; >+ int32_t id; >+ ProbeFailureReason failure_reason; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedIceCandidatePairConfig { >+ int64_t timestamp_us; >+ IceCandidatePairConfigType type; >+ uint32_t candidate_pair_id; >+ IceCandidateType local_candidate_type; >+ IceCandidatePairProtocol local_relay_protocol; >+ IceCandidateNetworkType local_network_type; >+ IceCandidatePairAddressFamily local_address_family; >+ IceCandidateType remote_candidate_type; >+ IceCandidatePairAddressFamily remote_address_family; >+ IceCandidatePairProtocol candidate_pair_protocol; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedIceCandidatePairEvent { >+ int64_t timestamp_us; >+ IceCandidatePairEventType type; >+ uint32_t candidate_pair_id; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtpPacket { >+ LoggedRtpPacket(uint64_t timestamp_us, >+ RTPHeader header, >+ size_t header_length, >+ size_t total_length) >+ : timestamp_us(timestamp_us), >+ header(header), >+ header_length(header_length), >+ total_length(total_length) {} >+ int64_t timestamp_us; >+ // TODO(terelius): This allocates space for 15 CSRCs even if none are used. >+ RTPHeader header; >+ size_t header_length; >+ size_t total_length; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtpPacketIncoming { >+ LoggedRtpPacketIncoming(uint64_t timestamp_us, >+ RTPHeader header, >+ size_t header_length, >+ size_t total_length) >+ : rtp(timestamp_us, header, header_length, total_length) {} >+ LoggedRtpPacket rtp; >+ int64_t log_time_us() const { return rtp.timestamp_us; } >+ int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } >+}; >+ >+struct LoggedRtpPacketOutgoing { >+ LoggedRtpPacketOutgoing(uint64_t timestamp_us, >+ RTPHeader header, >+ size_t header_length, >+ size_t total_length) >+ : rtp(timestamp_us, header, header_length, total_length) {} >+ LoggedRtpPacket rtp; >+ int64_t log_time_us() const { return rtp.timestamp_us; } >+ int64_t log_time_ms() const { return rtp.timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacket { >+ LoggedRtcpPacket(uint64_t timestamp_us, >+ const uint8_t* packet, >+ size_t total_length) >+ : timestamp_us(timestamp_us), raw_data(packet, packet + total_length) {} >+ int64_t timestamp_us; >+ std::vector<uint8_t> raw_data; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketIncoming { >+ LoggedRtcpPacketIncoming(uint64_t timestamp_us, >+ const uint8_t* packet, >+ size_t total_length) >+ : rtcp(timestamp_us, packet, total_length) {} >+ LoggedRtcpPacket rtcp; >+ int64_t log_time_us() const { return rtcp.timestamp_us; } >+ int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketOutgoing { >+ LoggedRtcpPacketOutgoing(uint64_t timestamp_us, >+ const uint8_t* packet, >+ size_t total_length) >+ : rtcp(timestamp_us, packet, total_length) {} >+ LoggedRtcpPacket rtcp; >+ int64_t log_time_us() const { return rtcp.timestamp_us; } >+ int64_t log_time_ms() const { return rtcp.timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketReceiverReport { >+ int64_t timestamp_us; >+ rtcp::ReceiverReport rr; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketSenderReport { >+ int64_t timestamp_us; >+ rtcp::SenderReport sr; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketRemb { >+ int64_t timestamp_us; >+ rtcp::Remb remb; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketNack { >+ int64_t timestamp_us; >+ rtcp::Nack nack; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedRtcpPacketTransportFeedback { >+ int64_t timestamp_us; >+ rtcp::TransportFeedback transport_feedback; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedStartEvent { >+ explicit LoggedStartEvent(uint64_t timestamp_us) >+ : timestamp_us(timestamp_us) {} >+ int64_t timestamp_us; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedStopEvent { >+ explicit LoggedStopEvent(uint64_t timestamp_us) >+ : timestamp_us(timestamp_us) {} >+ int64_t timestamp_us; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedAudioRecvConfig { >+ LoggedAudioRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) >+ : timestamp_us(timestamp_us), config(config) {} >+ int64_t timestamp_us; >+ rtclog::StreamConfig config; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedAudioSendConfig { >+ LoggedAudioSendConfig(int64_t timestamp_us, const rtclog::StreamConfig config) >+ : timestamp_us(timestamp_us), config(config) {} >+ int64_t timestamp_us; >+ rtclog::StreamConfig config; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedVideoRecvConfig { >+ LoggedVideoRecvConfig(int64_t timestamp_us, const rtclog::StreamConfig config) >+ : timestamp_us(timestamp_us), config(config) {} >+ int64_t timestamp_us; >+ rtclog::StreamConfig config; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+struct LoggedVideoSendConfig { >+ LoggedVideoSendConfig(int64_t timestamp_us, >+ const std::vector<rtclog::StreamConfig> configs) >+ : timestamp_us(timestamp_us), configs(configs) {} >+ int64_t timestamp_us; >+ std::vector<rtclog::StreamConfig> configs; >+ int64_t log_time_us() const { return timestamp_us; } >+ int64_t log_time_ms() const { return timestamp_us / 1000; } >+}; >+ >+template <typename T> >+class PacketView; >+ >+template <typename T> >+class PacketIterator { >+ friend class PacketView<T>; >+ >+ public: >+ // Standard iterator traits. >+ using difference_type = std::ptrdiff_t; >+ using value_type = T; >+ using pointer = T*; >+ using reference = T&; >+ using iterator_category = std::bidirectional_iterator_tag; >+ >+ // The default-contructed iterator is meaningless, but is required by the >+ // ForwardIterator concept. >+ PacketIterator() : ptr_(nullptr), element_size_(0) {} >+ PacketIterator(const PacketIterator& other) >+ : ptr_(other.ptr_), element_size_(other.element_size_) {} >+ PacketIterator(const PacketIterator&& other) >+ : ptr_(other.ptr_), element_size_(other.element_size_) {} >+ ~PacketIterator() = default; >+ >+ PacketIterator& operator=(const PacketIterator& other) { >+ ptr_ = other.ptr_; >+ element_size_ = other.element_size_; >+ return *this; >+ } >+ PacketIterator& operator=(const PacketIterator&& other) { >+ ptr_ = other.ptr_; >+ element_size_ = other.element_size_; >+ return *this; >+ } >+ >+ bool operator==(const PacketIterator<T>& other) const { >+ RTC_DCHECK_EQ(element_size_, other.element_size_); >+ return ptr_ == other.ptr_; >+ } >+ bool operator!=(const PacketIterator<T>& other) const { >+ RTC_DCHECK_EQ(element_size_, other.element_size_); >+ return ptr_ != other.ptr_; >+ } >+ >+ PacketIterator& operator++() { >+ ptr_ += element_size_; >+ return *this; >+ } >+ PacketIterator& operator--() { >+ ptr_ -= element_size_; >+ return *this; >+ } >+ PacketIterator operator++(int) { >+ PacketIterator iter_copy(ptr_, element_size_); >+ ptr_ += element_size_; >+ return iter_copy; >+ } >+ PacketIterator operator--(int) { >+ PacketIterator iter_copy(ptr_, element_size_); >+ ptr_ -= element_size_; >+ return iter_copy; >+ } >+ >+ T& operator*() { return *reinterpret_cast<T*>(ptr_); } >+ const T& operator*() const { return *reinterpret_cast<const T*>(ptr_); } >+ >+ private: >+ PacketIterator(typename std::conditional<std::is_const<T>::value, >+ const void*, >+ void*>::type p, >+ size_t s) >+ : ptr_(reinterpret_cast<decltype(ptr_)>(p)), element_size_(s) {} >+ >+ typename std::conditional<std::is_const<T>::value, const char*, char*>::type >+ ptr_; >+ size_t element_size_; >+}; >+ >+// Suppose that we have a struct S where we are only interested in a specific >+// member M. Given an array of S, PacketView can be used to treat the array >+// as an array of M, without exposing the type S to surrounding code and without >+// accessing the member through a virtual function. In this case, we want to >+// have a common view for incoming and outgoing RtpPackets, hence the PacketView >+// name. >+// Note that constructing a PacketView bypasses the typesystem, so the caller >+// has to take extra care when constructing these objects. The implementation >+// also requires that the containing struct is standard-layout (e.g. POD). >+// >+// Usage example: >+// struct A {...}; >+// struct B { A a; ...}; >+// struct C { A a; ...}; >+// size_t len = 10; >+// B* array1 = new B[len]; >+// C* array2 = new C[len]; >+// >+// PacketView<A> view1 = PacketView<A>::Create<B>(array1, len, offsetof(B, a)); >+// PacketView<A> view2 = PacketView<A>::Create<C>(array2, len, offsetof(C, a)); >+// >+// The following code works with either view1 or view2. >+// void f(PacketView<A> view) >+// for (A& a : view) { >+// DoSomething(a); >+// } >+template <typename T> >+class PacketView { >+ public: >+ template <typename U> >+ static PacketView Create(U* ptr, size_t num_elements, size_t offset) { >+ static_assert(std::is_standard_layout<U>::value, >+ "PacketView can only be created for standard layout types."); >+ static_assert(std::is_standard_layout<T>::value, >+ "PacketView can only be created for standard layout types."); >+ return PacketView(ptr, num_elements, offset, sizeof(U)); >+ } >+ >+ using iterator = PacketIterator<T>; >+ using const_iterator = PacketIterator<const T>; >+ using reverse_iterator = std::reverse_iterator<iterator>; >+ using const_reverse_iterator = std::reverse_iterator<const_iterator>; >+ >+ iterator begin() { return iterator(data_, element_size_); } >+ iterator end() { >+ auto end_ptr = data_ + num_elements_ * element_size_; >+ return iterator(end_ptr, element_size_); >+ } >+ >+ const_iterator begin() const { return const_iterator(data_, element_size_); } >+ const_iterator end() const { >+ auto end_ptr = data_ + num_elements_ * element_size_; >+ return const_iterator(end_ptr, element_size_); >+ } >+ >+ reverse_iterator rbegin() { return reverse_iterator(end()); } >+ reverse_iterator rend() { return reverse_iterator(begin()); } >+ >+ const_reverse_iterator rbegin() const { >+ return const_reverse_iterator(end()); >+ } >+ const_reverse_iterator rend() const { >+ return const_reverse_iterator(begin()); >+ } >+ >+ size_t size() const { return num_elements_; } >+ >+ T& operator[](size_t i) { >+ auto elem_ptr = data_ + i * element_size_; >+ return *reinterpret_cast<T*>(elem_ptr); >+ } >+ >+ const T& operator[](size_t i) const { >+ auto elem_ptr = data_ + i * element_size_; >+ return *reinterpret_cast<const T*>(elem_ptr); >+ } >+ >+ private: >+ PacketView(typename std::conditional<std::is_const<T>::value, >+ const void*, >+ void*>::type data, >+ size_t num_elements, >+ size_t offset, >+ size_t element_size) >+ : data_(reinterpret_cast<decltype(data_)>(data) + offset), >+ num_elements_(num_elements), >+ element_size_(element_size) {} >+ >+ typename std::conditional<std::is_const<T>::value, const char*, char*>::type >+ data_; >+ size_t num_elements_; >+ size_t element_size_; >+}; >+ >+class ParsedRtcEventLogNew { >+ friend class RtcEventLogTestHelper; >+ >+ public: >+ enum class EventType { >+ UNKNOWN_EVENT = 0, >+ LOG_START = 1, >+ LOG_END = 2, >+ RTP_EVENT = 3, >+ RTCP_EVENT = 4, >+ AUDIO_PLAYOUT_EVENT = 5, >+ LOSS_BASED_BWE_UPDATE = 6, >+ DELAY_BASED_BWE_UPDATE = 7, >+ VIDEO_RECEIVER_CONFIG_EVENT = 8, >+ VIDEO_SENDER_CONFIG_EVENT = 9, >+ AUDIO_RECEIVER_CONFIG_EVENT = 10, >+ AUDIO_SENDER_CONFIG_EVENT = 11, >+ AUDIO_NETWORK_ADAPTATION_EVENT = 16, >+ BWE_PROBE_CLUSTER_CREATED_EVENT = 17, >+ BWE_PROBE_FAILURE_EVENT = 18, >+ BWE_PROBE_SUCCESS_EVENT = 19, >+ ALR_STATE_EVENT = 20, >+ ICE_CANDIDATE_PAIR_CONFIG = 21, >+ ICE_CANDIDATE_PAIR_EVENT = 22, >+ }; >+ >+ enum class MediaType { ANY, AUDIO, VIDEO, DATA }; >+ enum class UnconfiguredHeaderExtensions { >+ kDontParse, >+ kAttemptWebrtcDefaultConfig >+ }; >+ >+ struct LoggedRtpStreamIncoming { >+ uint32_t ssrc; >+ std::vector<LoggedRtpPacketIncoming> incoming_packets; >+ }; >+ >+ struct LoggedRtpStreamOutgoing { >+ uint32_t ssrc; >+ std::vector<LoggedRtpPacketOutgoing> outgoing_packets; >+ }; >+ >+ struct LoggedRtpStreamView { >+ LoggedRtpStreamView(uint32_t ssrc, >+ const LoggedRtpPacketIncoming* ptr, >+ size_t num_elements) >+ : ssrc(ssrc), >+ packet_view(PacketView<const LoggedRtpPacket>::Create( >+ ptr, >+ num_elements, >+ offsetof(LoggedRtpPacketIncoming, rtp))) {} >+ LoggedRtpStreamView(uint32_t ssrc, >+ const LoggedRtpPacketOutgoing* ptr, >+ size_t num_elements) >+ : ssrc(ssrc), >+ packet_view(PacketView<const LoggedRtpPacket>::Create( >+ ptr, >+ num_elements, >+ offsetof(LoggedRtpPacketOutgoing, rtp))) {} >+ uint32_t ssrc; >+ PacketView<const LoggedRtpPacket> packet_view; >+ }; >+ >+ explicit ParsedRtcEventLogNew( >+ UnconfiguredHeaderExtensions parse_unconfigured_header_extensions = >+ UnconfiguredHeaderExtensions::kDontParse); >+ >+ // Clears previously parsed events and resets the ParsedRtcEventLogNew to an >+ // empty state. >+ void Clear(); >+ >+ // Reads an RtcEventLog file and returns true if parsing was successful. >+ bool ParseFile(const std::string& file_name); >+ >+ // Reads an RtcEventLog from a string and returns true if successful. >+ bool ParseString(const std::string& s); >+ >+ // Reads an RtcEventLog from an istream and returns true if successful. >+ bool ParseStream( >+ std::istream& stream); // no-presubmit-check TODO(webrtc:8982) >+ >+ // Returns the number of events in an EventStream. >+ size_t GetNumberOfEvents() const; >+ >+ // Reads the arrival timestamp (in microseconds) from a rtclog::Event. >+ int64_t GetTimestamp(size_t index) const; >+ int64_t GetTimestamp(const rtclog::Event& event) const; >+ >+ // Reads the event type of the rtclog::Event at |index|. >+ EventType GetEventType(size_t index) const; >+ EventType GetEventType(const rtclog::Event& event) const; >+ >+ // Reads the header, direction, header length and packet length from the RTP >+ // event at |index|, and stores the values in the corresponding output >+ // parameters. Each output parameter can be set to nullptr if that value >+ // isn't needed. >+ // NB: The header must have space for at least IP_PACKET_SIZE bytes. >+ // Returns: a pointer to a header extensions map acquired from parsing >+ // corresponding Audio/Video Sender/Receiver config events. >+ // Warning: if the same SSRC is reused by both video and audio streams during >+ // call, extensions maps may be incorrect (the last one would be returned). >+ const webrtc::RtpHeaderExtensionMap* GetRtpHeader( >+ size_t index, >+ PacketDirection* incoming, >+ uint8_t* header, >+ size_t* header_length, >+ size_t* total_length, >+ int* probe_cluster_id) const; >+ const webrtc::RtpHeaderExtensionMap* GetRtpHeader( >+ const rtclog::Event& event, >+ PacketDirection* incoming, >+ uint8_t* header, >+ size_t* header_length, >+ size_t* total_length, >+ int* probe_cluster_id) const; >+ >+ // Reads packet, direction and packet length from the RTCP event at |index|, >+ // and stores the values in the corresponding output parameters. >+ // Each output parameter can be set to nullptr if that value isn't needed. >+ // NB: The packet must have space for at least IP_PACKET_SIZE bytes. >+ void GetRtcpPacket(size_t index, >+ PacketDirection* incoming, >+ uint8_t* packet, >+ size_t* length) const; >+ void GetRtcpPacket(const rtclog::Event& event, >+ PacketDirection* incoming, >+ uint8_t* packet, >+ size_t* length) const; >+ >+ // Reads a video receive config event to a StreamConfig struct. >+ // Only the fields that are stored in the protobuf will be written. >+ rtclog::StreamConfig GetVideoReceiveConfig(size_t index) const; >+ >+ // Reads a video send config event to a StreamConfig struct. If the proto >+ // contains multiple SSRCs and RTX SSRCs (this used to be the case for >+ // simulcast streams) then we return one StreamConfig per SSRC,RTX_SSRC pair. >+ // Only the fields that are stored in the protobuf will be written. >+ std::vector<rtclog::StreamConfig> GetVideoSendConfig(size_t index) const; >+ >+ // Reads a audio receive config event to a StreamConfig struct. >+ // Only the fields that are stored in the protobuf will be written. >+ rtclog::StreamConfig GetAudioReceiveConfig(size_t index) const; >+ >+ // Reads a config event to a StreamConfig struct. >+ // Only the fields that are stored in the protobuf will be written. >+ rtclog::StreamConfig GetAudioSendConfig(size_t index) const; >+ >+ // Reads the SSRC from the audio playout event at |index|. The SSRC is stored >+ // in the output parameter ssrc. The output parameter can be set to nullptr >+ // and in that case the function only asserts that the event is well formed. >+ LoggedAudioPlayoutEvent GetAudioPlayout(size_t index) const; >+ >+ // Reads bitrate, fraction loss (as defined in RFC 1889) and total number of >+ // expected packets from the loss based BWE event at |index| and stores the >+ // values in >+ // the corresponding output parameters. Each output parameter can be set to >+ // nullptr if that >+ // value isn't needed. >+ LoggedBweLossBasedUpdate GetLossBasedBweUpdate(size_t index) const; >+ >+ // Reads bitrate and detector_state from the delay based BWE event at |index| >+ // and stores the values in the corresponding output parameters. Each output >+ // parameter can be set to nullptr if that >+ // value isn't needed. >+ LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate(size_t index) const; >+ >+ // Reads a audio network adaptation event to a (non-NULL) >+ // AudioEncoderRuntimeConfig struct. Only the fields that are >+ // stored in the protobuf will be written. >+ LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation( >+ size_t index) const; >+ >+ LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated( >+ size_t index) const; >+ >+ LoggedBweProbeFailureEvent GetBweProbeFailure(size_t index) const; >+ LoggedBweProbeSuccessEvent GetBweProbeSuccess(size_t index) const; >+ >+ MediaType GetMediaType(uint32_t ssrc, PacketDirection direction) const; >+ >+ LoggedAlrStateEvent GetAlrState(size_t index) const; >+ >+ LoggedIceCandidatePairConfig GetIceCandidatePairConfig(size_t index) const; >+ >+ LoggedIceCandidatePairEvent GetIceCandidatePairEvent(size_t index) const; >+ >+ // Configured SSRCs. >+ const std::set<uint32_t>& incoming_rtx_ssrcs() const { >+ return incoming_rtx_ssrcs_; >+ } >+ >+ const std::set<uint32_t>& incoming_video_ssrcs() const { >+ return incoming_video_ssrcs_; >+ } >+ >+ const std::set<uint32_t>& incoming_audio_ssrcs() const { >+ return incoming_audio_ssrcs_; >+ } >+ >+ const std::set<uint32_t>& outgoing_rtx_ssrcs() const { >+ return outgoing_rtx_ssrcs_; >+ } >+ >+ const std::set<uint32_t>& outgoing_video_ssrcs() const { >+ return outgoing_video_ssrcs_; >+ } >+ >+ const std::set<uint32_t>& outgoing_audio_ssrcs() const { >+ return outgoing_audio_ssrcs_; >+ } >+ >+ // Stream configurations. >+ const std::vector<LoggedAudioRecvConfig>& audio_recv_configs() const { >+ return audio_recv_configs_; >+ } >+ >+ const std::vector<LoggedAudioSendConfig>& audio_send_configs() const { >+ return audio_send_configs_; >+ } >+ >+ const std::vector<LoggedVideoRecvConfig>& video_recv_configs() const { >+ return video_recv_configs_; >+ } >+ >+ const std::vector<LoggedVideoSendConfig>& video_send_configs() const { >+ return video_send_configs_; >+ } >+ >+ // Beginning and end of log segments. >+ const std::vector<LoggedStartEvent>& start_log_events() const { >+ return start_log_events_; >+ } >+ >+ const std::vector<LoggedStopEvent>& stop_log_events() const { >+ return stop_log_events_; >+ } >+ >+ // Audio >+ const std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>& >+ audio_playout_events() const { >+ return audio_playout_events_; >+ } >+ >+ const std::vector<LoggedAudioNetworkAdaptationEvent>& >+ audio_network_adaptation_events() const { >+ return audio_network_adaptation_events_; >+ } >+ >+ // Bandwidth estimation >+ const std::vector<LoggedBweProbeClusterCreatedEvent>& >+ bwe_probe_cluster_created_events() const { >+ return bwe_probe_cluster_created_events_; >+ } >+ >+ const std::vector<LoggedBweProbeFailureEvent>& bwe_probe_failure_events() >+ const { >+ return bwe_probe_failure_events_; >+ } >+ >+ const std::vector<LoggedBweProbeSuccessEvent>& bwe_probe_success_events() >+ const { >+ return bwe_probe_success_events_; >+ } >+ >+ const std::vector<LoggedBweDelayBasedUpdate>& bwe_delay_updates() const { >+ return bwe_delay_updates_; >+ } >+ >+ const std::vector<LoggedBweLossBasedUpdate>& bwe_loss_updates() const { >+ return bwe_loss_updates_; >+ } >+ >+ const std::vector<LoggedAlrStateEvent>& alr_state_events() const { >+ return alr_state_events_; >+ } >+ >+ // ICE events >+ const std::vector<LoggedIceCandidatePairConfig>& ice_candidate_pair_configs() >+ const { >+ return ice_candidate_pair_configs_; >+ } >+ >+ const std::vector<LoggedIceCandidatePairEvent>& ice_candidate_pair_events() >+ const { >+ return ice_candidate_pair_events_; >+ } >+ >+ // RTP >+ const std::vector<LoggedRtpStreamIncoming>& incoming_rtp_packets_by_ssrc() >+ const { >+ return incoming_rtp_packets_by_ssrc_; >+ } >+ >+ const std::vector<LoggedRtpStreamOutgoing>& outgoing_rtp_packets_by_ssrc() >+ const { >+ return outgoing_rtp_packets_by_ssrc_; >+ } >+ >+ const std::vector<LoggedRtpStreamView>& rtp_packets_by_ssrc( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) >+ return incoming_rtp_packet_views_by_ssrc_; >+ else >+ return outgoing_rtp_packet_views_by_ssrc_; >+ } >+ >+ // RTCP >+ const std::vector<LoggedRtcpPacketIncoming>& incoming_rtcp_packets() const { >+ return incoming_rtcp_packets_; >+ } >+ >+ const std::vector<LoggedRtcpPacketOutgoing>& outgoing_rtcp_packets() const { >+ return outgoing_rtcp_packets_; >+ } >+ >+ const std::vector<LoggedRtcpPacketReceiverReport>& receiver_reports( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ return incoming_rr_; >+ } else { >+ return outgoing_rr_; >+ } >+ } >+ >+ const std::vector<LoggedRtcpPacketSenderReport>& sender_reports( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ return incoming_sr_; >+ } else { >+ return outgoing_sr_; >+ } >+ } >+ >+ const std::vector<LoggedRtcpPacketNack>& nacks( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ return incoming_nack_; >+ } else { >+ return outgoing_nack_; >+ } >+ } >+ >+ const std::vector<LoggedRtcpPacketRemb>& rembs( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ return incoming_remb_; >+ } else { >+ return outgoing_remb_; >+ } >+ } >+ >+ const std::vector<LoggedRtcpPacketTransportFeedback>& transport_feedbacks( >+ PacketDirection direction) const { >+ if (direction == kIncomingPacket) { >+ return incoming_transport_feedback_; >+ } else { >+ return outgoing_transport_feedback_; >+ } >+ } >+ >+ int64_t first_timestamp() const { return first_timestamp_; } >+ int64_t last_timestamp() const { return last_timestamp_; } >+ >+ private: >+ bool ParseStreamInternal( >+ std::istream& stream); // no-presubmit-check TODO(webrtc:8982) >+ >+ void StoreParsedEvent(const rtclog::Event& event); >+ >+ rtclog::StreamConfig GetVideoReceiveConfig(const rtclog::Event& event) const; >+ std::vector<rtclog::StreamConfig> GetVideoSendConfig( >+ const rtclog::Event& event) const; >+ rtclog::StreamConfig GetAudioReceiveConfig(const rtclog::Event& event) const; >+ rtclog::StreamConfig GetAudioSendConfig(const rtclog::Event& event) const; >+ >+ LoggedAudioPlayoutEvent GetAudioPlayout(const rtclog::Event& event) const; >+ >+ LoggedBweLossBasedUpdate GetLossBasedBweUpdate( >+ const rtclog::Event& event) const; >+ LoggedBweDelayBasedUpdate GetDelayBasedBweUpdate( >+ const rtclog::Event& event) const; >+ >+ LoggedAudioNetworkAdaptationEvent GetAudioNetworkAdaptation( >+ const rtclog::Event& event) const; >+ >+ LoggedBweProbeClusterCreatedEvent GetBweProbeClusterCreated( >+ const rtclog::Event& event) const; >+ LoggedBweProbeFailureEvent GetBweProbeFailure( >+ const rtclog::Event& event) const; >+ LoggedBweProbeSuccessEvent GetBweProbeSuccess( >+ const rtclog::Event& event) const; >+ >+ LoggedAlrStateEvent GetAlrState(const rtclog::Event& event) const; >+ >+ LoggedIceCandidatePairConfig GetIceCandidatePairConfig( >+ const rtclog::Event& event) const; >+ LoggedIceCandidatePairEvent GetIceCandidatePairEvent( >+ const rtclog::Event& event) const; >+ >+ std::vector<rtclog::Event> events_; >+ >+ struct Stream { >+ Stream(uint32_t ssrc, >+ MediaType media_type, >+ PacketDirection direction, >+ webrtc::RtpHeaderExtensionMap map) >+ : ssrc(ssrc), >+ media_type(media_type), >+ direction(direction), >+ rtp_extensions_map(map) {} >+ uint32_t ssrc; >+ MediaType media_type; >+ PacketDirection direction; >+ webrtc::RtpHeaderExtensionMap rtp_extensions_map; >+ }; >+ >+ const UnconfiguredHeaderExtensions parse_unconfigured_header_extensions_; >+ >+ // Make a default extension map for streams without configuration information. >+ // TODO(ivoc): Once configuration of audio streams is stored in the event log, >+ // this can be removed. Tracking bug: webrtc:6399 >+ RtpHeaderExtensionMap default_extension_map_; >+ >+ // Tracks what each stream is configured for. Note that a single SSRC can be >+ // in several sets. For example, the SSRC used for sending video over RTX >+ // will appear in both video_ssrcs_ and rtx_ssrcs_. In the unlikely case that >+ // an SSRC is reconfigured to a different media type mid-call, it will also >+ // appear in multiple sets. >+ std::set<uint32_t> incoming_rtx_ssrcs_; >+ std::set<uint32_t> incoming_video_ssrcs_; >+ std::set<uint32_t> incoming_audio_ssrcs_; >+ std::set<uint32_t> outgoing_rtx_ssrcs_; >+ std::set<uint32_t> outgoing_video_ssrcs_; >+ std::set<uint32_t> outgoing_audio_ssrcs_; >+ >+ // Maps an SSRC to the parsed RTP headers in that stream. Header extensions >+ // are parsed if the stream has been configured. This is only used for >+ // grouping the events by SSRC during parsing; the events are moved to >+ // incoming_rtp_packets_by_ssrc_ once the parsing is done. >+ std::map<uint32_t, std::vector<LoggedRtpPacketIncoming>> >+ incoming_rtp_packets_map_; >+ std::map<uint32_t, std::vector<LoggedRtpPacketOutgoing>> >+ outgoing_rtp_packets_map_; >+ >+ // RTP headers. >+ std::vector<LoggedRtpStreamIncoming> incoming_rtp_packets_by_ssrc_; >+ std::vector<LoggedRtpStreamOutgoing> outgoing_rtp_packets_by_ssrc_; >+ std::vector<LoggedRtpStreamView> incoming_rtp_packet_views_by_ssrc_; >+ std::vector<LoggedRtpStreamView> outgoing_rtp_packet_views_by_ssrc_; >+ >+ // Raw RTCP packets. >+ std::vector<LoggedRtcpPacketIncoming> incoming_rtcp_packets_; >+ std::vector<LoggedRtcpPacketOutgoing> outgoing_rtcp_packets_; >+ >+ // Parsed RTCP messages. Currently not separated based on SSRC. >+ std::vector<LoggedRtcpPacketReceiverReport> incoming_rr_; >+ std::vector<LoggedRtcpPacketReceiverReport> outgoing_rr_; >+ std::vector<LoggedRtcpPacketSenderReport> incoming_sr_; >+ std::vector<LoggedRtcpPacketSenderReport> outgoing_sr_; >+ std::vector<LoggedRtcpPacketNack> incoming_nack_; >+ std::vector<LoggedRtcpPacketNack> outgoing_nack_; >+ std::vector<LoggedRtcpPacketRemb> incoming_remb_; >+ std::vector<LoggedRtcpPacketRemb> outgoing_remb_; >+ std::vector<LoggedRtcpPacketTransportFeedback> incoming_transport_feedback_; >+ std::vector<LoggedRtcpPacketTransportFeedback> outgoing_transport_feedback_; >+ >+ std::vector<LoggedStartEvent> start_log_events_; >+ std::vector<LoggedStopEvent> stop_log_events_; >+ >+ std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>> >+ audio_playout_events_; >+ >+ std::vector<LoggedAudioNetworkAdaptationEvent> >+ audio_network_adaptation_events_; >+ >+ std::vector<LoggedBweProbeClusterCreatedEvent> >+ bwe_probe_cluster_created_events_; >+ >+ std::vector<LoggedBweProbeFailureEvent> bwe_probe_failure_events_; >+ std::vector<LoggedBweProbeSuccessEvent> bwe_probe_success_events_; >+ >+ std::vector<LoggedBweDelayBasedUpdate> bwe_delay_updates_; >+ >+ // A list of all updates from the send-side loss-based bandwidth estimator. >+ std::vector<LoggedBweLossBasedUpdate> bwe_loss_updates_; >+ >+ std::vector<LoggedAlrStateEvent> alr_state_events_; >+ >+ std::vector<LoggedIceCandidatePairConfig> ice_candidate_pair_configs_; >+ >+ std::vector<LoggedIceCandidatePairEvent> ice_candidate_pair_events_; >+ >+ std::vector<LoggedAudioRecvConfig> audio_recv_configs_; >+ std::vector<LoggedAudioSendConfig> audio_send_configs_; >+ std::vector<LoggedVideoRecvConfig> video_recv_configs_; >+ std::vector<LoggedVideoSendConfig> video_send_configs_; >+ >+ uint8_t last_incoming_rtcp_packet_[IP_PACKET_SIZE]; >+ uint8_t last_incoming_rtcp_packet_length_; >+ >+ int64_t first_timestamp_; >+ int64_t last_timestamp_; >+ >+ // The extension maps are mutable to allow us to insert the default >+ // configuration when parsing an RTP header for an unconfigured stream. >+ mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap> >+ incoming_rtp_extensions_maps_; >+ mutable std::map<uint32_t, webrtc::RtpHeaderExtensionMap> >+ outgoing_rtp_extensions_maps_; >+}; >+ >+} // namespace webrtc >+ >+#endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_PARSER_NEW_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc >index 1cea3138ab3..e238f848846 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest.cc >@@ -8,15 +8,15 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >+#include <algorithm> > #include <map> > #include <memory> >-#include <ostream> > #include <string> > #include <tuple> > #include <utility> > #include <vector> > >-#include "call/call.h" >+#include "absl/memory/memory.h" > #include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" > #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" > #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" >@@ -34,21 +34,13 @@ > #include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" > #include "logging/rtc_event_log/output/rtc_event_log_output_file.h" > #include "logging/rtc_event_log/rtc_event_log.h" >-#include "logging/rtc_event_log/rtc_event_log_parser.h" >+#include "logging/rtc_event_log/rtc_event_log_parser_new.h" > #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" > #include "logging/rtc_event_log/rtc_stream_config.h" >-#include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" >-#include "modules/remote_bitrate_estimator/include/bwe_defines.h" > #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" >-#include "modules/rtp_rtcp/source/rtcp_packet.h" >-#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" > #include "modules/rtp_rtcp/source/rtp_header_extensions.h" >-#include "modules/rtp_rtcp/source/rtp_packet_received.h" >-#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" >-#include "rtc_base/buffer.h" > #include "rtc_base/checks.h" > #include "rtc_base/fakeclock.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/random.h" > #include "test/gtest.h" > #include "test/testsupport/fileutils.h" >@@ -57,662 +49,653 @@ namespace webrtc { > > namespace { > >-const uint8_t kTransmissionTimeOffsetExtensionId = 1; >-const uint8_t kAbsoluteSendTimeExtensionId = 14; >-const uint8_t kTransportSequenceNumberExtensionId = 13; >-const uint8_t kAudioLevelExtensionId = 9; >-const uint8_t kVideoRotationExtensionId = 5; >- >-const uint8_t kExtensionIds[] = { >- kTransmissionTimeOffsetExtensionId, kAbsoluteSendTimeExtensionId, >- kTransportSequenceNumberExtensionId, kAudioLevelExtensionId, >- kVideoRotationExtensionId}; >-const RTPExtensionType kExtensionTypes[] = { >- RTPExtensionType::kRtpExtensionTransmissionTimeOffset, >- RTPExtensionType::kRtpExtensionAbsoluteSendTime, >- RTPExtensionType::kRtpExtensionTransportSequenceNumber, >- RTPExtensionType::kRtpExtensionAudioLevel, >- RTPExtensionType::kRtpExtensionVideoRotation}; >-const char* kExtensionNames[] = { >- RtpExtension::kTimestampOffsetUri, RtpExtension::kAbsSendTimeUri, >- RtpExtension::kTransportSequenceNumberUri, RtpExtension::kAudioLevelUri, >- RtpExtension::kVideoRotationUri}; >- >-const size_t kNumExtensions = 5; >- >-struct BweLossEvent { >- int32_t bitrate_bps; >- uint8_t fraction_loss; >- int32_t total_packets; >-}; >- >-// TODO(terelius): Merge with event type in parser once updated? >-enum class EventType { >- kIncomingRtp, >- kOutgoingRtp, >- kIncomingRtcp, >- kOutgoingRtcp, >- kAudioPlayout, >- kBweLossUpdate, >- kBweDelayUpdate, >- kVideoRecvConfig, >- kVideoSendConfig, >- kAudioRecvConfig, >- kAudioSendConfig, >- kAudioNetworkAdaptation, >- kBweProbeClusterCreated, >- kBweProbeResult, >-}; >- >-const std::map<EventType, std::string> event_type_to_string( >- {{EventType::kIncomingRtp, "RTP(in)"}, >- {EventType::kOutgoingRtp, "RTP(out)"}, >- {EventType::kIncomingRtcp, "RTCP(in)"}, >- {EventType::kOutgoingRtcp, "RTCP(out)"}, >- {EventType::kAudioPlayout, "PLAYOUT"}, >- {EventType::kBweLossUpdate, "BWE_LOSS"}, >- {EventType::kBweDelayUpdate, "BWE_DELAY"}, >- {EventType::kVideoRecvConfig, "VIDEO_RECV_CONFIG"}, >- {EventType::kVideoSendConfig, "VIDEO_SEND_CONFIG"}, >- {EventType::kAudioRecvConfig, "AUDIO_RECV_CONFIG"}, >- {EventType::kAudioSendConfig, "AUDIO_SEND_CONFIG"}, >- {EventType::kAudioNetworkAdaptation, "AUDIO_NETWORK_ADAPTATION"}, >- {EventType::kBweProbeClusterCreated, "BWE_PROBE_CREATED"}, >- {EventType::kBweProbeResult, "BWE_PROBE_RESULT"}}); >- >-const std::map<ParsedRtcEventLog::EventType, std::string> >- parsed_event_type_to_string( >- {{ParsedRtcEventLog::EventType::UNKNOWN_EVENT, "UNKNOWN_EVENT"}, >- {ParsedRtcEventLog::EventType::LOG_START, "LOG_START"}, >- {ParsedRtcEventLog::EventType::LOG_END, "LOG_END"}, >- {ParsedRtcEventLog::EventType::RTP_EVENT, "RTP"}, >- {ParsedRtcEventLog::EventType::RTCP_EVENT, "RTCP"}, >- {ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT, "AUDIO_PLAYOUT"}, >- {ParsedRtcEventLog::EventType::LOSS_BASED_BWE_UPDATE, >- "LOSS_BASED_BWE_UPDATE"}, >- {ParsedRtcEventLog::EventType::DELAY_BASED_BWE_UPDATE, >- "DELAY_BASED_BWE_UPDATE"}, >- {ParsedRtcEventLog::EventType::VIDEO_RECEIVER_CONFIG_EVENT, >- "VIDEO_RECV_CONFIG"}, >- {ParsedRtcEventLog::EventType::VIDEO_SENDER_CONFIG_EVENT, >- "VIDEO_SEND_CONFIG"}, >- {ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT, >- "AUDIO_RECV_CONFIG"}, >- {ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT, >- "AUDIO_SEND_CONFIG"}, >- {ParsedRtcEventLog::EventType::AUDIO_NETWORK_ADAPTATION_EVENT, >- "AUDIO_NETWORK_ADAPTATION"}, >- {ParsedRtcEventLog::EventType::BWE_PROBE_CLUSTER_CREATED_EVENT, >- "BWE_PROBE_CREATED"}, >- {ParsedRtcEventLog::EventType::BWE_PROBE_RESULT_EVENT, >- "BWE_PROBE_RESULT"}}); >-} // namespace >- >-void PrintActualEvents(const ParsedRtcEventLog& parsed_log, >- std::ostream& stream); >+RtpHeaderExtensionMap ExtensionMapWithAllSupportedExtensions() { >+ RtpHeaderExtensionMap all_extensions; >+ all_extensions.Register<AudioLevel>(RtpExtension::kAudioLevelDefaultId); >+ all_extensions.Register<TransmissionOffset>( >+ RtpExtension::kTimestampOffsetDefaultId); >+ all_extensions.Register<AbsoluteSendTime>( >+ RtpExtension::kAbsSendTimeDefaultId); >+ all_extensions.Register<VideoOrientation>( >+ RtpExtension::kVideoRotationDefaultId); >+ all_extensions.Register<TransportSequenceNumber>( >+ RtpExtension::kTransportSequenceNumberDefaultId); >+ return all_extensions; >+} > >-RtpPacketToSend GenerateOutgoingRtpPacket( >- const RtpHeaderExtensionMap* extensions, >- uint32_t csrcs_count, >- size_t packet_size, >- Random* prng) { >- RTC_CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions); >+struct EventCounts { >+ size_t audio_send_streams = 0; >+ size_t audio_recv_streams = 0; >+ size_t video_send_streams = 0; >+ size_t video_recv_streams = 0; >+ size_t alr_states = 0; >+ size_t audio_playouts = 0; >+ size_t ana_configs = 0; >+ size_t bwe_loss_events = 0; >+ size_t bwe_delay_events = 0; >+ size_t probe_creations = 0; >+ size_t probe_successes = 0; >+ size_t probe_failures = 0; >+ size_t ice_configs = 0; >+ size_t ice_events = 0; >+ size_t incoming_rtp_packets = 0; >+ size_t outgoing_rtp_packets = 0; >+ size_t incoming_rtcp_packets = 0; >+ size_t outgoing_rtcp_packets = 0; >+ >+ size_t total_nonconfig_events() const { >+ return alr_states + audio_playouts + ana_configs + bwe_loss_events + >+ bwe_delay_events + probe_creations + probe_successes + >+ probe_failures + ice_configs + ice_events + incoming_rtp_packets + >+ outgoing_rtp_packets + incoming_rtcp_packets + outgoing_rtcp_packets; >+ } > >- std::vector<uint32_t> csrcs; >- for (unsigned i = 0; i < csrcs_count; i++) { >- csrcs.push_back(prng->Rand<uint32_t>()); >+ size_t total_config_events() const { >+ return audio_send_streams + audio_recv_streams + video_send_streams + >+ video_recv_streams; > } > >- RtpPacketToSend rtp_packet(extensions, packet_size); >- rtp_packet.SetPayloadType(prng->Rand(127)); >- rtp_packet.SetMarker(prng->Rand<bool>()); >- rtp_packet.SetSequenceNumber(prng->Rand<uint16_t>()); >- rtp_packet.SetSsrc(prng->Rand<uint32_t>()); >- rtp_packet.SetTimestamp(prng->Rand<uint32_t>()); >- rtp_packet.SetCsrcs(csrcs); >- >- rtp_packet.SetExtension<TransmissionOffset>(prng->Rand(0x00ffffff)); >- rtp_packet.SetExtension<AudioLevel>(prng->Rand<bool>(), prng->Rand(127)); >- rtp_packet.SetExtension<AbsoluteSendTime>(prng->Rand(0x00ffffff)); >- rtp_packet.SetExtension<VideoOrientation>(prng->Rand(2)); >- rtp_packet.SetExtension<TransportSequenceNumber>(prng->Rand<uint16_t>()); >- >- size_t payload_size = packet_size - rtp_packet.headers_size(); >- uint8_t* payload = rtp_packet.AllocatePayload(payload_size); >- for (size_t i = 0; i < payload_size; i++) { >- payload[i] = prng->Rand<uint8_t>(); >+ size_t total_events() const { >+ return total_nonconfig_events() + total_config_events(); > } >- return rtp_packet; >-} >+}; > >-RtpPacketReceived GenerateIncomingRtpPacket( >- const RtpHeaderExtensionMap* extensions, >- uint32_t csrcs_count, >- size_t packet_size, >- Random* prng) { >- RtpPacketToSend packet_out = >- GenerateOutgoingRtpPacket(extensions, csrcs_count, packet_size, prng); >- RtpPacketReceived packet_in(extensions); >- packet_in.Parse(packet_out.data(), packet_out.size()); >- return packet_in; >-} >+class RtcEventLogSession >+ : public ::testing::TestWithParam<std::tuple<uint64_t, int64_t>> { >+ public: >+ RtcEventLogSession() >+ : seed_(std::get<0>(GetParam())), >+ prng_(seed_), >+ gen_(seed_ * 880001UL), >+ output_period_ms_(std::get<1>(GetParam())) { >+ clock_.SetTimeMicros(prng_.Rand<uint32_t>()); >+ // Find the name of the current test, in order to use it as a temporary >+ // filename. >+ // TODO(terelius): Use a general utility function to generate a temp file. >+ auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); >+ std::string test_name = >+ std::string(test_info->test_case_name()) + "_" + test_info->name(); >+ std::replace(test_name.begin(), test_name.end(), '/', '_'); >+ temp_filename_ = test::OutputPath() + test_name; >+ } > >-rtc::Buffer GenerateRtcpPacket(Random* prng) { >- rtcp::ReportBlock report_block; >- report_block.SetMediaSsrc(prng->Rand<uint32_t>()); // Remote SSRC. >- report_block.SetFractionLost(prng->Rand(50)); >+ // Create and buffer the config events and |num_events_before_log_start| >+ // randomized non-config events. Then call StartLogging and finally create and >+ // write the remaining non-config events. >+ void WriteLog(EventCounts count, size_t num_events_before_log_start); >+ void ReadAndVerifyLog(); > >- rtcp::SenderReport sender_report; >- sender_report.SetSenderSsrc(prng->Rand<uint32_t>()); >- sender_report.SetNtp(NtpTime(prng->Rand<uint32_t>(), prng->Rand<uint32_t>())); >- sender_report.SetPacketCount(prng->Rand<uint32_t>()); >- sender_report.AddReportBlock(report_block); >+ private: >+ void WriteAudioRecvConfigs(size_t audio_recv_streams, RtcEventLog* event_log); >+ void WriteAudioSendConfigs(size_t audio_send_streams, RtcEventLog* event_log); >+ void WriteVideoRecvConfigs(size_t video_recv_streams, RtcEventLog* event_log); >+ void WriteVideoSendConfigs(size_t video_send_streams, RtcEventLog* event_log); >+ >+ std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> incoming_extensions_; >+ std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>> outgoing_extensions_; >+ >+ // Config events. >+ std::vector<std::unique_ptr<RtcEventAudioSendStreamConfig>> >+ audio_send_config_list_; >+ std::vector<std::unique_ptr<RtcEventAudioReceiveStreamConfig>> >+ audio_recv_config_list_; >+ std::vector<std::unique_ptr<RtcEventVideoSendStreamConfig>> >+ video_send_config_list_; >+ std::vector<std::unique_ptr<RtcEventVideoReceiveStreamConfig>> >+ video_recv_config_list_; >+ >+ // Regular events. >+ std::vector<std::unique_ptr<RtcEventAlrState>> alr_state_list_; >+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventAudioPlayout>>> >+ audio_playout_map_; // Groups audio by SSRC. >+ std::vector<std::unique_ptr<RtcEventAudioNetworkAdaptation>> >+ ana_configs_list_; >+ std::vector<std::unique_ptr<RtcEventBweUpdateLossBased>> bwe_loss_list_; >+ std::vector<std::unique_ptr<RtcEventBweUpdateDelayBased>> bwe_delay_list_; >+ std::vector<std::unique_ptr<RtcEventProbeClusterCreated>> >+ probe_creation_list_; >+ std::vector<std::unique_ptr<RtcEventProbeResultSuccess>> probe_success_list_; >+ std::vector<std::unique_ptr<RtcEventProbeResultFailure>> probe_failure_list_; >+ std::vector<std::unique_ptr<RtcEventIceCandidatePairConfig>> ice_config_list_; >+ std::vector<std::unique_ptr<RtcEventIceCandidatePair>> ice_event_list_; >+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketIncoming>>> >+ incoming_rtp_map_; // Groups incoming RTP by SSRC. >+ std::map<uint32_t, std::vector<std::unique_ptr<RtcEventRtpPacketOutgoing>>> >+ outgoing_rtp_map_; // Groups outgoing RTP by SSRC. >+ std::vector<std::unique_ptr<RtcEventRtcpPacketIncoming>> incoming_rtcp_list_; >+ std::vector<std::unique_ptr<RtcEventRtcpPacketOutgoing>> outgoing_rtcp_list_; >+ >+ int64_t start_time_us_; >+ int64_t stop_time_us_; >+ >+ const uint64_t seed_; >+ Random prng_; >+ test::EventGenerator gen_; >+ int64_t output_period_ms_; >+ rtc::ScopedFakeClock clock_; >+ std::string temp_filename_; >+}; > >- return sender_report.Build(); >+bool SsrcUsed( >+ uint32_t ssrc, >+ const std::vector<std::pair<uint32_t, RtpHeaderExtensionMap>>& streams) { >+ for (const auto& kv : streams) { >+ if (kv.first == ssrc) >+ return true; >+ } >+ return false; > } > >-void GenerateVideoReceiveConfig(const RtpHeaderExtensionMap& extensions, >- rtclog::StreamConfig* config, >- Random* prng) { >- // Add SSRCs for the stream. >- config->remote_ssrc = prng->Rand<uint32_t>(); >- config->local_ssrc = prng->Rand<uint32_t>(); >- // Add extensions and settings for RTCP. >- config->rtcp_mode = >- prng->Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize; >- config->remb = prng->Rand<bool>(); >- config->rtx_ssrc = prng->Rand<uint32_t>(); >- config->codecs.emplace_back(prng->Rand<bool>() ? "VP8" : "H264", >- prng->Rand(1, 127), prng->Rand(1, 127)); >- // Add header extensions. >- for (unsigned i = 0; i < kNumExtensions; i++) { >- uint8_t id = extensions.GetId(kExtensionTypes[i]); >- if (id != RtpHeaderExtensionMap::kInvalidId) { >- config->rtp_extensions.emplace_back(kExtensionNames[i], id); >- } >+void RtcEventLogSession::WriteAudioRecvConfigs(size_t audio_recv_streams, >+ RtcEventLog* event_log) { >+ RTC_CHECK(event_log != nullptr); >+ uint32_t ssrc; >+ for (size_t i = 0; i < audio_recv_streams; i++) { >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ do { >+ ssrc = prng_.Rand<uint32_t>(); >+ } while (SsrcUsed(ssrc, incoming_extensions_)); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ incoming_extensions_.emplace_back(ssrc, extensions); >+ auto event = gen_.NewAudioReceiveStreamConfig(ssrc, extensions); >+ event_log->Log(event->Copy()); >+ audio_recv_config_list_.push_back(std::move(event)); > } > } > >-void GenerateVideoSendConfig(const RtpHeaderExtensionMap& extensions, >- rtclog::StreamConfig* config, >- Random* prng) { >- config->codecs.emplace_back(prng->Rand<bool>() ? "VP8" : "H264", >- prng->Rand(1, 127), prng->Rand(1, 127)); >- config->local_ssrc = prng->Rand<uint32_t>(); >- config->rtx_ssrc = prng->Rand<uint32_t>(); >- // Add header extensions. >- for (unsigned i = 0; i < kNumExtensions; i++) { >- uint8_t id = extensions.GetId(kExtensionTypes[i]); >- if (id != RtpHeaderExtensionMap::kInvalidId) { >- config->rtp_extensions.emplace_back(kExtensionNames[i], id); >- } >+void RtcEventLogSession::WriteAudioSendConfigs(size_t audio_send_streams, >+ RtcEventLog* event_log) { >+ RTC_CHECK(event_log != nullptr); >+ uint32_t ssrc; >+ for (size_t i = 0; i < audio_send_streams; i++) { >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ do { >+ ssrc = prng_.Rand<uint32_t>(); >+ } while (SsrcUsed(ssrc, outgoing_extensions_)); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ outgoing_extensions_.emplace_back(ssrc, extensions); >+ auto event = gen_.NewAudioSendStreamConfig(ssrc, extensions); >+ event_log->Log(event->Copy()); >+ audio_send_config_list_.push_back(std::move(event)); > } > } > >-void GenerateAudioReceiveConfig(const RtpHeaderExtensionMap& extensions, >- rtclog::StreamConfig* config, >- Random* prng) { >- // Add SSRCs for the stream. >- config->remote_ssrc = prng->Rand<uint32_t>(); >- config->local_ssrc = prng->Rand<uint32_t>(); >- // Add header extensions. >- for (unsigned i = 0; i < kNumExtensions; i++) { >- uint8_t id = extensions.GetId(kExtensionTypes[i]); >- if (id != RtpHeaderExtensionMap::kInvalidId) { >- config->rtp_extensions.emplace_back(kExtensionNames[i], id); >- } >+void RtcEventLogSession::WriteVideoRecvConfigs(size_t video_recv_streams, >+ RtcEventLog* event_log) { >+ RTC_CHECK(event_log != nullptr); >+ RTC_CHECK_GE(video_recv_streams, 1); >+ >+ // Force least one stream to use all header extensions, to ensure >+ // (statistically) that every extension is tested in packet creation. >+ RtpHeaderExtensionMap all_extensions = >+ ExtensionMapWithAllSupportedExtensions(); >+ >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ incoming_extensions_.emplace_back(prng_.Rand<uint32_t>(), all_extensions); >+ auto event = gen_.NewVideoReceiveStreamConfig(ssrc, all_extensions); >+ event_log->Log(event->Copy()); >+ video_recv_config_list_.push_back(std::move(event)); >+ for (size_t i = 1; i < video_recv_streams; i++) { >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ do { >+ ssrc = prng_.Rand<uint32_t>(); >+ } while (SsrcUsed(ssrc, incoming_extensions_)); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ incoming_extensions_.emplace_back(ssrc, extensions); >+ auto event = gen_.NewVideoReceiveStreamConfig(ssrc, extensions); >+ event_log->Log(event->Copy()); >+ video_recv_config_list_.push_back(std::move(event)); > } > } > >-void GenerateAudioSendConfig(const RtpHeaderExtensionMap& extensions, >- rtclog::StreamConfig* config, >- Random* prng) { >- // Add SSRC to the stream. >- config->local_ssrc = prng->Rand<uint32_t>(); >- // Add header extensions. >- for (unsigned i = 0; i < kNumExtensions; i++) { >- uint8_t id = extensions.GetId(kExtensionTypes[i]); >- if (id != RtpHeaderExtensionMap::kInvalidId) { >- config->rtp_extensions.emplace_back(kExtensionNames[i], id); >- } >+void RtcEventLogSession::WriteVideoSendConfigs(size_t video_send_streams, >+ RtcEventLog* event_log) { >+ RTC_CHECK(event_log != nullptr); >+ RTC_CHECK_GE(video_send_streams, 1); >+ >+ // Force least one stream to use all header extensions, to ensure >+ // (statistically) that every extension is tested in packet creation. >+ RtpHeaderExtensionMap all_extensions = >+ ExtensionMapWithAllSupportedExtensions(); >+ >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ uint32_t ssrc = prng_.Rand<uint32_t>(); >+ outgoing_extensions_.emplace_back(prng_.Rand<uint32_t>(), all_extensions); >+ auto event = gen_.NewVideoSendStreamConfig(ssrc, all_extensions); >+ event_log->Log(event->Copy()); >+ video_send_config_list_.push_back(std::move(event)); >+ for (size_t i = 1; i < video_send_streams; i++) { >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ do { >+ ssrc = prng_.Rand<uint32_t>(); >+ } while (SsrcUsed(ssrc, outgoing_extensions_)); >+ RtpHeaderExtensionMap extensions = gen_.NewRtpHeaderExtensionMap(); >+ outgoing_extensions_.emplace_back(ssrc, extensions); >+ auto event = gen_.NewVideoSendStreamConfig(ssrc, extensions); >+ event_log->Log(event->Copy()); >+ video_send_config_list_.push_back(std::move(event)); > } > } > >-BweLossEvent GenerateBweLossEvent(Random* prng) { >- BweLossEvent loss_event; >- loss_event.bitrate_bps = prng->Rand(6000, 10000000); >- loss_event.fraction_loss = prng->Rand<uint8_t>(); >- loss_event.total_packets = prng->Rand(1, 1000); >- return loss_event; >-} >+void RtcEventLogSession::WriteLog(EventCounts count, >+ size_t num_events_before_start) { >+ // TODO(terelius): Allow test to run with either a real or a fake clock_. >+ // Maybe always use the ScopedFakeClock, but conditionally SleepMs()? > >-void GenerateAudioNetworkAdaptation(const RtpHeaderExtensionMap& extensions, >- AudioEncoderRuntimeConfig* config, >- Random* prng) { >- config->bitrate_bps = prng->Rand(0, 3000000); >- config->enable_fec = prng->Rand<bool>(); >- config->enable_dtx = prng->Rand<bool>(); >- config->frame_length_ms = prng->Rand(10, 120); >- config->num_channels = prng->Rand(1, 2); >- config->uplink_packet_loss_fraction = prng->Rand<float>(); >-} >+ // The log file will be flushed to disk when the event_log goes out of scope. >+ std::unique_ptr<RtcEventLog> event_log( >+ RtcEventLog::Create(RtcEventLog::EncodingType::Legacy)); > >-class RtcEventLogSession >- : public ::testing::TestWithParam<std::tuple<uint64_t, int64_t>> { >- public: >- RtcEventLogSession() >- : prng(std::get<0>(GetParam())), >- output_period_ms(std::get<1>(GetParam())) {} >- void GenerateSessionDescription(size_t incoming_rtp_count, >- size_t outgoing_rtp_count, >- size_t incoming_rtcp_count, >- size_t outgoing_rtcp_count, >- size_t playout_count, >- size_t bwe_loss_count, >- size_t bwe_delay_count, >- const RtpHeaderExtensionMap& extensions, >- uint32_t csrcs_count); >- void WriteSession(); >- void ReadAndVerifySession(); >- void PrintExpectedEvents(std::ostream& stream); >+ // We can't send or receive packets without configured streams. >+ RTC_CHECK_GE(count.video_recv_streams, 1); >+ RTC_CHECK_GE(count.video_send_streams, 1); >+ >+ WriteAudioRecvConfigs(count.audio_recv_streams, event_log.get()); >+ WriteAudioSendConfigs(count.audio_send_streams, event_log.get()); >+ WriteVideoRecvConfigs(count.video_recv_streams, event_log.get()); >+ WriteVideoSendConfigs(count.video_send_streams, event_log.get()); >+ >+ size_t remaining_events = count.total_nonconfig_events(); >+ ASSERT_LE(num_events_before_start, remaining_events); >+ size_t remaining_events_at_start = remaining_events - num_events_before_start; >+ for (; remaining_events > 0; remaining_events--) { >+ if (remaining_events == remaining_events_at_start) { >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ event_log->StartLogging( >+ absl::make_unique<RtcEventLogOutputFile>(temp_filename_, 10000000), >+ output_period_ms_); >+ start_time_us_ = rtc::TimeMicros(); >+ } > >- private: >- std::vector<RtpPacketReceived> incoming_rtp_packets; >- std::vector<RtpPacketToSend> outgoing_rtp_packets; >- std::vector<rtc::Buffer> incoming_rtcp_packets; >- std::vector<rtc::Buffer> outgoing_rtcp_packets; >- std::vector<uint32_t> playout_ssrcs; >- std::vector<BweLossEvent> bwe_loss_updates; >- std::vector<std::pair<int32_t, BandwidthUsage> > bwe_delay_updates; >- std::vector<rtclog::StreamConfig> receiver_configs; >- std::vector<rtclog::StreamConfig> sender_configs; >- std::vector<EventType> event_types; >- Random prng; >- int64_t output_period_ms; >-}; >+ clock_.AdvanceTimeMicros(prng_.Rand(20) * 1000); >+ size_t selection = prng_.Rand(remaining_events - 1); > >-void RtcEventLogSession::GenerateSessionDescription( >- size_t incoming_rtp_count, >- size_t outgoing_rtp_count, >- size_t incoming_rtcp_count, >- size_t outgoing_rtcp_count, >- size_t playout_count, >- size_t bwe_loss_count, >- size_t bwe_delay_count, >- const RtpHeaderExtensionMap& extensions, >- uint32_t csrcs_count) { >- // Create configuration for the video receive stream. >- receiver_configs.push_back(rtclog::StreamConfig()); >- GenerateVideoReceiveConfig(extensions, &receiver_configs.back(), &prng); >- event_types.push_back(EventType::kVideoRecvConfig); >- >- // Create configuration for the video send stream. >- sender_configs.push_back(rtclog::StreamConfig()); >- GenerateVideoSendConfig(extensions, &sender_configs.back(), &prng); >- event_types.push_back(EventType::kVideoSendConfig); >- const size_t config_count = 2; >- >- // Create incoming and outgoing RTP packets containing random data. >- for (size_t i = 0; i < incoming_rtp_count; i++) { >- size_t packet_size = prng.Rand(1000, 1100); >- incoming_rtp_packets.push_back(GenerateIncomingRtpPacket( >- &extensions, csrcs_count, packet_size, &prng)); >- event_types.push_back(EventType::kIncomingRtp); >+ if (selection < count.alr_states) { >+ auto event = gen_.NewAlrState(); >+ event_log->Log(event->Copy()); >+ alr_state_list_.push_back(std::move(event)); >+ count.alr_states--; >+ continue; >+ } >+ selection -= count.alr_states; >+ >+ if (selection < count.audio_playouts) { >+ size_t stream = prng_.Rand(incoming_extensions_.size() - 1); >+ // This might be a video SSRC, but the parser does not use the config. >+ uint32_t ssrc = incoming_extensions_[stream].first; >+ auto event = gen_.NewAudioPlayout(ssrc); >+ event_log->Log(event->Copy()); >+ audio_playout_map_[ssrc].push_back(std::move(event)); >+ count.audio_playouts--; >+ continue; >+ } >+ selection -= count.audio_playouts; >+ >+ if (selection < count.ana_configs) { >+ auto event = gen_.NewAudioNetworkAdaptation(); >+ event_log->Log(event->Copy()); >+ ana_configs_list_.push_back(std::move(event)); >+ count.ana_configs--; >+ continue; >+ } >+ selection -= count.ana_configs; >+ >+ if (selection < count.bwe_loss_events) { >+ auto event = gen_.NewBweUpdateLossBased(); >+ event_log->Log(event->Copy()); >+ bwe_loss_list_.push_back(std::move(event)); >+ count.bwe_loss_events--; >+ continue; >+ } >+ selection -= count.bwe_loss_events; >+ >+ if (selection < count.bwe_delay_events) { >+ auto event = gen_.NewBweUpdateDelayBased(); >+ event_log->Log(event->Copy()); >+ bwe_delay_list_.push_back(std::move(event)); >+ count.bwe_delay_events--; >+ continue; >+ } >+ selection -= count.bwe_delay_events; >+ >+ if (selection < count.probe_creations) { >+ auto event = gen_.NewProbeClusterCreated(); >+ event_log->Log(event->Copy()); >+ probe_creation_list_.push_back(std::move(event)); >+ count.probe_creations--; >+ continue; >+ } >+ selection -= count.probe_creations; >+ >+ if (selection < count.probe_successes) { >+ auto event = gen_.NewProbeResultSuccess(); >+ event_log->Log(event->Copy()); >+ probe_success_list_.push_back(std::move(event)); >+ count.probe_successes--; >+ continue; >+ } >+ selection -= count.probe_successes; >+ >+ if (selection < count.probe_failures) { >+ auto event = gen_.NewProbeResultFailure(); >+ event_log->Log(event->Copy()); >+ probe_failure_list_.push_back(std::move(event)); >+ count.probe_failures--; >+ continue; >+ } >+ selection -= count.probe_failures; >+ >+ if (selection < count.ice_configs) { >+ auto event = gen_.NewIceCandidatePairConfig(); >+ event_log->Log(event->Copy()); >+ ice_config_list_.push_back(std::move(event)); >+ count.ice_configs--; >+ continue; >+ } >+ selection -= count.ice_configs; >+ >+ if (selection < count.ice_events) { >+ auto event = gen_.NewIceCandidatePair(); >+ event_log->Log(event->Copy()); >+ ice_event_list_.push_back(std::move(event)); >+ count.ice_events--; >+ continue; >+ } >+ selection -= count.ice_events; >+ >+ if (selection < count.incoming_rtp_packets) { >+ size_t stream = prng_.Rand(incoming_extensions_.size() - 1); >+ uint32_t ssrc = incoming_extensions_[stream].first; >+ auto event = >+ gen_.NewRtpPacketIncoming(ssrc, incoming_extensions_[stream].second); >+ event_log->Log(event->Copy()); >+ incoming_rtp_map_[ssrc].push_back(std::move(event)); >+ count.incoming_rtp_packets--; >+ continue; >+ } >+ selection -= count.incoming_rtp_packets; >+ >+ if (selection < count.outgoing_rtp_packets) { >+ size_t stream = prng_.Rand(outgoing_extensions_.size() - 1); >+ uint32_t ssrc = outgoing_extensions_[stream].first; >+ auto event = >+ gen_.NewRtpPacketOutgoing(ssrc, outgoing_extensions_[stream].second); >+ event_log->Log(event->Copy()); >+ outgoing_rtp_map_[ssrc].push_back(std::move(event)); >+ count.outgoing_rtp_packets--; >+ continue; >+ } >+ selection -= count.outgoing_rtp_packets; >+ >+ if (selection < count.incoming_rtcp_packets) { >+ auto event = gen_.NewRtcpPacketIncoming(); >+ event_log->Log(event->Copy()); >+ incoming_rtcp_list_.push_back(std::move(event)); >+ count.incoming_rtcp_packets--; >+ continue; >+ } >+ selection -= count.incoming_rtcp_packets; >+ >+ if (selection < count.outgoing_rtcp_packets) { >+ auto event = gen_.NewRtcpPacketOutgoing(); >+ event_log->Log(event->Copy()); >+ outgoing_rtcp_list_.push_back(std::move(event)); >+ count.outgoing_rtcp_packets--; >+ continue; >+ } >+ selection -= count.outgoing_rtcp_packets; >+ >+ RTC_NOTREACHED(); > } >- for (size_t i = 0; i < outgoing_rtp_count; i++) { >- size_t packet_size = prng.Rand(1000, 1100); >- outgoing_rtp_packets.push_back(GenerateOutgoingRtpPacket( >- &extensions, csrcs_count, packet_size, &prng)); >- event_types.push_back(EventType::kOutgoingRtp); >+ >+ event_log->StopLogging(); >+ stop_time_us_ = rtc::TimeMicros(); >+ >+ ASSERT_EQ(count.total_nonconfig_events(), static_cast<size_t>(0)); >+} >+ >+// Read the file and verify that what we read back from the event log is the >+// same as what we wrote down. >+void RtcEventLogSession::ReadAndVerifyLog() { >+ // Read the generated file from disk. >+ ParsedRtcEventLogNew parsed_log; >+ ASSERT_TRUE(parsed_log.ParseFile(temp_filename_)); >+ >+ // Start and stop events. >+ auto& parsed_start_log_events = parsed_log.start_log_events(); >+ ASSERT_EQ(parsed_start_log_events.size(), static_cast<size_t>(1)); >+ EXPECT_TRUE( >+ test::VerifyLoggedStartEvent(start_time_us_, parsed_start_log_events[0])); >+ >+ auto& parsed_stop_log_events = parsed_log.stop_log_events(); >+ ASSERT_EQ(parsed_stop_log_events.size(), static_cast<size_t>(1)); >+ EXPECT_TRUE( >+ test::VerifyLoggedStopEvent(stop_time_us_, parsed_stop_log_events[0])); >+ >+ auto& parsed_alr_state_events = parsed_log.alr_state_events(); >+ ASSERT_EQ(parsed_alr_state_events.size(), alr_state_list_.size()); >+ for (size_t i = 0; i < parsed_alr_state_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedAlrStateEvent(*alr_state_list_[i], >+ parsed_alr_state_events[i])); > } >- // Create incoming and outgoing RTCP packets containing random data. >- for (size_t i = 0; i < incoming_rtcp_count; i++) { >- incoming_rtcp_packets.push_back(GenerateRtcpPacket(&prng)); >- event_types.push_back(EventType::kIncomingRtcp); >+ >+ const auto& parsed_audio_playout_map = parsed_log.audio_playout_events(); >+ ASSERT_EQ(parsed_audio_playout_map.size(), audio_playout_map_.size()); >+ for (const auto& kv : parsed_audio_playout_map) { >+ uint32_t ssrc = kv.first; >+ const auto& parsed_audio_playout_stream = kv.second; >+ const auto& audio_playout_stream = audio_playout_map_[ssrc]; >+ ASSERT_EQ(parsed_audio_playout_stream.size(), audio_playout_stream.size()); >+ for (size_t i = 0; i < parsed_audio_playout_map.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedAudioPlayoutEvent( >+ *audio_playout_stream[i], parsed_audio_playout_stream[i])); >+ } > } >- for (size_t i = 0; i < outgoing_rtcp_count; i++) { >- outgoing_rtcp_packets.push_back(GenerateRtcpPacket(&prng)); >- event_types.push_back(EventType::kOutgoingRtcp); >+ >+ auto& parsed_audio_network_adaptation_events = >+ parsed_log.audio_network_adaptation_events(); >+ ASSERT_EQ(parsed_audio_network_adaptation_events.size(), >+ ana_configs_list_.size()); >+ for (size_t i = 0; i < parsed_audio_network_adaptation_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedAudioNetworkAdaptationEvent( >+ *ana_configs_list_[i], parsed_audio_network_adaptation_events[i])); > } >- // Create random SSRCs to use when logging AudioPlayout events. >- for (size_t i = 0; i < playout_count; i++) { >- playout_ssrcs.push_back(prng.Rand<uint32_t>()); >- event_types.push_back(EventType::kAudioPlayout); >+ >+ auto& parsed_bwe_delay_updates = parsed_log.bwe_delay_updates(); >+ ASSERT_EQ(parsed_bwe_delay_updates.size(), bwe_delay_list_.size()); >+ for (size_t i = 0; i < parsed_bwe_delay_updates.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedBweDelayBasedUpdate( >+ *bwe_delay_list_[i], parsed_bwe_delay_updates[i])); > } >- // Create random bitrate updates for LossBasedBwe. >- for (size_t i = 0; i < bwe_loss_count; i++) { >- bwe_loss_updates.push_back(GenerateBweLossEvent(&prng)); >- event_types.push_back(EventType::kBweLossUpdate); >+ >+ auto& parsed_bwe_loss_updates = parsed_log.bwe_loss_updates(); >+ ASSERT_EQ(parsed_bwe_loss_updates.size(), bwe_loss_list_.size()); >+ for (size_t i = 0; i < parsed_bwe_loss_updates.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedBweLossBasedUpdate( >+ *bwe_loss_list_[i], parsed_bwe_loss_updates[i])); > } >- // Create random bitrate updates for DelayBasedBwe. >- for (size_t i = 0; i < bwe_delay_count; i++) { >- bwe_delay_updates.push_back(std::make_pair( >- prng.Rand(6000, 10000000), prng.Rand<bool>() >- ? BandwidthUsage::kBwOverusing >- : BandwidthUsage::kBwUnderusing)); >- event_types.push_back(EventType::kBweDelayUpdate); >+ >+ auto& parsed_bwe_probe_cluster_created_events = >+ parsed_log.bwe_probe_cluster_created_events(); >+ ASSERT_EQ(parsed_bwe_probe_cluster_created_events.size(), >+ probe_creation_list_.size()); >+ for (size_t i = 0; i < parsed_bwe_probe_cluster_created_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedBweProbeClusterCreatedEvent( >+ *probe_creation_list_[i], parsed_bwe_probe_cluster_created_events[i])); > } > >- // Order the events randomly. The configurations are stored in a separate >- // buffer, so they might be written before any othe events. Hence, we can't >- // mix the config events with other events. >- for (size_t i = config_count; i < event_types.size(); i++) { >- size_t other = prng.Rand(static_cast<uint32_t>(i), >- static_cast<uint32_t>(event_types.size() - 1)); >- RTC_CHECK(i <= other && other < event_types.size()); >- std::swap(event_types[i], event_types[other]); >+ auto& parsed_bwe_probe_failure_events = parsed_log.bwe_probe_failure_events(); >+ ASSERT_EQ(parsed_bwe_probe_failure_events.size(), probe_failure_list_.size()); >+ for (size_t i = 0; i < parsed_bwe_probe_failure_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedBweProbeFailureEvent( >+ *probe_failure_list_[i], parsed_bwe_probe_failure_events[i])); > } >-} > >-void RtcEventLogSession::WriteSession() { >- // Find the name of the current test, in order to use it as a temporary >- // filename. >- auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); >- std::string test_name = test_info->name(); >- std::replace(test_name.begin(), test_name.end(), '/', '_'); >- const std::string temp_filename = >- test::OutputPath() + "RtcEventLogTest_" + test_name; >+ auto& parsed_bwe_probe_success_events = parsed_log.bwe_probe_success_events(); >+ ASSERT_EQ(parsed_bwe_probe_success_events.size(), probe_success_list_.size()); >+ for (size_t i = 0; i < parsed_bwe_probe_success_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedBweProbeSuccessEvent( >+ *probe_success_list_[i], parsed_bwe_probe_success_events[i])); >+ } > >- rtc::ScopedFakeClock fake_clock; >- fake_clock.SetTimeMicros(prng.Rand<uint32_t>()); >+ auto& parsed_ice_candidate_pair_configs = >+ parsed_log.ice_candidate_pair_configs(); >+ ASSERT_EQ(parsed_ice_candidate_pair_configs.size(), ice_config_list_.size()); >+ for (size_t i = 0; i < parsed_ice_candidate_pair_configs.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedIceCandidatePairConfig( >+ *ice_config_list_[i], parsed_ice_candidate_pair_configs[i])); >+ } > >- // When log_dumper goes out of scope, it causes the log file to be flushed >- // to disk. >- std::unique_ptr<RtcEventLog> log_dumper( >- RtcEventLog::Create(RtcEventLog::EncodingType::Legacy)); >+ auto& parsed_ice_candidate_pair_events = >+ parsed_log.ice_candidate_pair_events(); >+ ASSERT_EQ(parsed_ice_candidate_pair_events.size(), >+ parsed_ice_candidate_pair_events.size()); >+ for (size_t i = 0; i < parsed_ice_candidate_pair_events.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedIceCandidatePairEvent( >+ *ice_event_list_[i], parsed_ice_candidate_pair_events[i])); >+ } > >- size_t incoming_rtp_written = 0; >- size_t outgoing_rtp_written = 0; >- size_t incoming_rtcp_written = 0; >- size_t outgoing_rtcp_written = 0; >- size_t playouts_written = 0; >- size_t bwe_loss_written = 0; >- size_t bwe_delay_written = 0; >- size_t recv_configs_written = 0; >- size_t send_configs_written = 0; >- >- for (size_t i = 0; i < event_types.size(); i++) { >- fake_clock.AdvanceTimeMicros(prng.Rand(1, 1000)); >- if (i == event_types.size() / 2) >- log_dumper->StartLogging( >- rtc::MakeUnique<RtcEventLogOutputFile>(temp_filename, 10000000), >- output_period_ms); >- switch (event_types[i]) { >- case EventType::kIncomingRtp: >- RTC_CHECK(incoming_rtp_written < incoming_rtp_packets.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventRtpPacketIncoming>( >- incoming_rtp_packets[incoming_rtp_written++])); >- break; >- case EventType::kOutgoingRtp: { >- RTC_CHECK(outgoing_rtp_written < outgoing_rtp_packets.size()); >- constexpr int kNotAProbe = PacedPacketInfo::kNotAProbe; // Compiler... >- log_dumper->Log(rtc::MakeUnique<RtcEventRtpPacketOutgoing>( >- outgoing_rtp_packets[outgoing_rtp_written++], kNotAProbe)); >- break; >- } >- case EventType::kIncomingRtcp: >- RTC_CHECK(incoming_rtcp_written < incoming_rtcp_packets.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventRtcpPacketIncoming>( >- incoming_rtcp_packets[incoming_rtcp_written++])); >- break; >- case EventType::kOutgoingRtcp: >- RTC_CHECK(outgoing_rtcp_written < outgoing_rtcp_packets.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventRtcpPacketOutgoing>( >- outgoing_rtcp_packets[outgoing_rtcp_written++])); >- break; >- case EventType::kAudioPlayout: >- RTC_CHECK(playouts_written < playout_ssrcs.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventAudioPlayout>( >- playout_ssrcs[playouts_written++])); >- break; >- case EventType::kBweLossUpdate: >- RTC_CHECK(bwe_loss_written < bwe_loss_updates.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventBweUpdateLossBased>( >- bwe_loss_updates[bwe_loss_written].bitrate_bps, >- bwe_loss_updates[bwe_loss_written].fraction_loss, >- bwe_loss_updates[bwe_loss_written].total_packets)); >- bwe_loss_written++; >- break; >- case EventType::kBweDelayUpdate: >- RTC_CHECK(bwe_delay_written < bwe_delay_updates.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventBweUpdateDelayBased>( >- bwe_delay_updates[bwe_delay_written].first, >- bwe_delay_updates[bwe_delay_written].second)); >- bwe_delay_written++; >- break; >- case EventType::kVideoRecvConfig: >- RTC_CHECK(recv_configs_written < receiver_configs.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventVideoReceiveStreamConfig>( >- rtc::MakeUnique<rtclog::StreamConfig>( >- receiver_configs[recv_configs_written++]))); >- break; >- case EventType::kVideoSendConfig: >- RTC_CHECK(send_configs_written < sender_configs.size()); >- log_dumper->Log(rtc::MakeUnique<RtcEventVideoSendStreamConfig>( >- rtc::MakeUnique<rtclog::StreamConfig>( >- sender_configs[send_configs_written++]))); >- break; >- case EventType::kAudioRecvConfig: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kAudioSendConfig: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kAudioNetworkAdaptation: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kBweProbeClusterCreated: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kBweProbeResult: >- // Not implemented >- RTC_NOTREACHED(); >- break; >+ auto& parsed_incoming_rtp_packets_by_ssrc = >+ parsed_log.incoming_rtp_packets_by_ssrc(); >+ ASSERT_EQ(parsed_incoming_rtp_packets_by_ssrc.size(), >+ incoming_rtp_map_.size()); >+ for (const auto& kv : parsed_incoming_rtp_packets_by_ssrc) { >+ uint32_t ssrc = kv.ssrc; >+ const auto& parsed_rtp_stream = kv.incoming_packets; >+ const auto& rtp_stream = incoming_rtp_map_[ssrc]; >+ ASSERT_EQ(parsed_rtp_stream.size(), rtp_stream.size()); >+ for (size_t i = 0; i < parsed_rtp_stream.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedRtpPacketIncoming(*rtp_stream[i], >+ parsed_rtp_stream[i])); > } > } > >- log_dumper->StopLogging(); >-} >- >-// Read the file and verify that what we read back from the event log is the >-// same as what we wrote down. >-void RtcEventLogSession::ReadAndVerifySession() { >- // Find the name of the current test, in order to use it as a temporary >- // filename. >- auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); >- std::string test_name = test_info->name(); >- std::replace(test_name.begin(), test_name.end(), '/', '_'); >- const std::string temp_filename = >- test::OutputPath() + "RtcEventLogTest_" + test_name; >- >- // Read the generated file from disk. >- ParsedRtcEventLog parsed_log; >- ASSERT_TRUE(parsed_log.ParseFile(temp_filename)); >- EXPECT_GE(5000u, event_types.size() + 2); // The events must fit. >- EXPECT_EQ(event_types.size() + 2, parsed_log.GetNumberOfEvents()); >- >- size_t incoming_rtp_read = 0; >- size_t outgoing_rtp_read = 0; >- size_t incoming_rtcp_read = 0; >- size_t outgoing_rtcp_read = 0; >- size_t playouts_read = 0; >- size_t bwe_loss_read = 0; >- size_t bwe_delay_read = 0; >- size_t recv_configs_read = 0; >- size_t send_configs_read = 0; >- >- RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0); >- >- for (size_t i = 0; i < event_types.size(); i++) { >- switch (event_types[i]) { >- case EventType::kIncomingRtp: >- RTC_CHECK(incoming_rtp_read < incoming_rtp_packets.size()); >- RtcEventLogTestHelper::VerifyIncomingRtpEvent( >- parsed_log, i + 1, incoming_rtp_packets[incoming_rtp_read++]); >- break; >- case EventType::kOutgoingRtp: >- RTC_CHECK(outgoing_rtp_read < outgoing_rtp_packets.size()); >- RtcEventLogTestHelper::VerifyOutgoingRtpEvent( >- parsed_log, i + 1, outgoing_rtp_packets[outgoing_rtp_read++]); >- break; >- case EventType::kIncomingRtcp: >- RTC_CHECK(incoming_rtcp_read < incoming_rtcp_packets.size()); >- RtcEventLogTestHelper::VerifyRtcpEvent( >- parsed_log, i + 1, kIncomingPacket, >- incoming_rtcp_packets[incoming_rtcp_read].data(), >- incoming_rtcp_packets[incoming_rtcp_read].size()); >- incoming_rtcp_read++; >- break; >- case EventType::kOutgoingRtcp: >- RTC_CHECK(outgoing_rtcp_read < outgoing_rtcp_packets.size()); >- RtcEventLogTestHelper::VerifyRtcpEvent( >- parsed_log, i + 1, kOutgoingPacket, >- outgoing_rtcp_packets[outgoing_rtcp_read].data(), >- outgoing_rtcp_packets[outgoing_rtcp_read].size()); >- outgoing_rtcp_read++; >- break; >- case EventType::kAudioPlayout: >- RTC_CHECK(playouts_read < playout_ssrcs.size()); >- RtcEventLogTestHelper::VerifyPlayoutEvent( >- parsed_log, i + 1, playout_ssrcs[playouts_read++]); >- break; >- case EventType::kBweLossUpdate: >- RTC_CHECK(bwe_loss_read < bwe_loss_updates.size()); >- RtcEventLogTestHelper::VerifyBweLossEvent( >- parsed_log, i + 1, bwe_loss_updates[bwe_loss_read].bitrate_bps, >- bwe_loss_updates[bwe_loss_read].fraction_loss, >- bwe_loss_updates[bwe_loss_read].total_packets); >- bwe_loss_read++; >- break; >- case EventType::kBweDelayUpdate: >- RTC_CHECK(bwe_delay_read < bwe_delay_updates.size()); >- RtcEventLogTestHelper::VerifyBweDelayEvent( >- parsed_log, i + 1, bwe_delay_updates[bwe_delay_read].first, >- bwe_delay_updates[bwe_delay_read].second); >- bwe_delay_read++; >- break; >- case EventType::kVideoRecvConfig: >- RTC_CHECK(recv_configs_read < receiver_configs.size()); >- RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig( >- parsed_log, i + 1, receiver_configs[recv_configs_read++]); >- break; >- case EventType::kVideoSendConfig: >- RTC_CHECK(send_configs_read < sender_configs.size()); >- RtcEventLogTestHelper::VerifyVideoSendStreamConfig( >- parsed_log, i + 1, sender_configs[send_configs_read++]); >- break; >- case EventType::kAudioRecvConfig: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kAudioSendConfig: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kAudioNetworkAdaptation: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kBweProbeClusterCreated: >- // Not implemented >- RTC_NOTREACHED(); >- break; >- case EventType::kBweProbeResult: >- // Not implemented >- RTC_NOTREACHED(); >- break; >+ auto& parsed_outgoing_rtp_packets_by_ssrc = >+ parsed_log.outgoing_rtp_packets_by_ssrc(); >+ ASSERT_EQ(parsed_outgoing_rtp_packets_by_ssrc.size(), >+ outgoing_rtp_map_.size()); >+ for (const auto& kv : parsed_outgoing_rtp_packets_by_ssrc) { >+ uint32_t ssrc = kv.ssrc; >+ const auto& parsed_rtp_stream = kv.outgoing_packets; >+ const auto& rtp_stream = outgoing_rtp_map_[ssrc]; >+ ASSERT_EQ(parsed_rtp_stream.size(), rtp_stream.size()); >+ for (size_t i = 0; i < parsed_rtp_stream.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedRtpPacketOutgoing(*rtp_stream[i], >+ parsed_rtp_stream[i])); > } > } > >- RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log, >- parsed_log.GetNumberOfEvents() - 1); >- >- // Clean up temporary file - can be pretty slow. >- remove(temp_filename.c_str()); >-} >- >-void RtcEventLogSession::PrintExpectedEvents(std::ostream& stream) { >- for (size_t i = 0; i < event_types.size(); i++) { >- auto it = event_type_to_string.find(event_types[i]); >- RTC_CHECK(it != event_type_to_string.end()); >- stream << it->second << " "; >+ auto& parsed_incoming_rtcp_packets = parsed_log.incoming_rtcp_packets(); >+ ASSERT_EQ(parsed_incoming_rtcp_packets.size(), incoming_rtcp_list_.size()); >+ for (size_t i = 0; i < parsed_incoming_rtcp_packets.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedRtcpPacketIncoming( >+ *incoming_rtcp_list_[i], parsed_incoming_rtcp_packets[i])); > } >- stream << std::endl; >-} > >-void PrintActualEvents(const ParsedRtcEventLog& parsed_log, >- std::ostream& stream) { >- for (size_t i = 0; i < parsed_log.GetNumberOfEvents(); i++) { >- auto it = parsed_event_type_to_string.find(parsed_log.GetEventType(i)); >- RTC_CHECK(it != parsed_event_type_to_string.end()); >- stream << it->second << " "; >+ auto& parsed_outgoing_rtcp_packets = parsed_log.outgoing_rtcp_packets(); >+ ASSERT_EQ(parsed_outgoing_rtcp_packets.size(), outgoing_rtcp_list_.size()); >+ for (size_t i = 0; i < parsed_outgoing_rtcp_packets.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedRtcpPacketOutgoing( >+ *outgoing_rtcp_list_[i], parsed_outgoing_rtcp_packets[i])); >+ } >+ auto& parsed_audio_recv_configs = parsed_log.audio_recv_configs(); >+ ASSERT_EQ(parsed_audio_recv_configs.size(), audio_recv_config_list_.size()); >+ for (size_t i = 0; i < parsed_audio_recv_configs.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedAudioRecvConfig( >+ *audio_recv_config_list_[i], parsed_audio_recv_configs[i])); >+ } >+ auto& parsed_audio_send_configs = parsed_log.audio_send_configs(); >+ ASSERT_EQ(parsed_audio_send_configs.size(), audio_send_config_list_.size()); >+ for (size_t i = 0; i < parsed_audio_send_configs.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedAudioSendConfig( >+ *audio_send_config_list_[i], parsed_audio_send_configs[i])); >+ } >+ auto& parsed_video_recv_configs = parsed_log.video_recv_configs(); >+ ASSERT_EQ(parsed_video_recv_configs.size(), video_recv_config_list_.size()); >+ for (size_t i = 0; i < parsed_video_recv_configs.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedVideoRecvConfig( >+ *video_recv_config_list_[i], parsed_video_recv_configs[i])); >+ } >+ auto& parsed_video_send_configs = parsed_log.video_send_configs(); >+ ASSERT_EQ(parsed_video_send_configs.size(), video_send_config_list_.size()); >+ for (size_t i = 0; i < parsed_video_send_configs.size(); i++) { >+ EXPECT_TRUE(test::VerifyLoggedVideoSendConfig( >+ *video_send_config_list_[i], parsed_video_send_configs[i])); > } >- stream << std::endl; >-} > >-TEST_P(RtcEventLogSession, LogSessionAndReadBack) { >- RtpHeaderExtensionMap extensions; >- GenerateSessionDescription(3, // Number of incoming RTP packets. >- 2, // Number of outgoing RTP packets. >- 1, // Number of incoming RTCP packets. >- 1, // Number of outgoing RTCP packets. >- 0, // Number of playout events. >- 0, // Number of BWE loss events. >- 0, // Number of BWE delay events. >- extensions, // No extensions. >- 0); // Number of contributing sources. >- WriteSession(); >- ReadAndVerifySession(); >+ // Clean up temporary file - can be pretty slow. >+ remove(temp_filename_.c_str()); > } > >-TEST_P(RtcEventLogSession, LogSessionAndReadBackWith2Extensions) { >- RtpHeaderExtensionMap extensions; >- extensions.Register(kRtpExtensionAbsoluteSendTime, >- kAbsoluteSendTimeExtensionId); >- extensions.Register(kRtpExtensionTransportSequenceNumber, >- kTransportSequenceNumberExtensionId); >- GenerateSessionDescription(4, 4, 1, 1, 0, 0, 0, extensions, 0); >- WriteSession(); >- ReadAndVerifySession(); >-} >+} // namespace > >-TEST_P(RtcEventLogSession, LogSessionAndReadBackWithAllExtensions) { >- RtpHeaderExtensionMap extensions; >- for (uint32_t i = 0; i < kNumExtensions; i++) { >- extensions.Register(kExtensionTypes[i], kExtensionIds[i]); >- } >- GenerateSessionDescription(5, 4, 1, 1, 3, 2, 2, extensions, 2); >- WriteSession(); >- ReadAndVerifySession(); >+TEST_P(RtcEventLogSession, StartLoggingFromBeginning) { >+ EventCounts count; >+ count.audio_send_streams = 2; >+ count.audio_recv_streams = 2; >+ count.video_send_streams = 3; >+ count.video_recv_streams = 4; >+ count.alr_states = 4; >+ count.audio_playouts = 100; >+ count.ana_configs = 3; >+ count.bwe_loss_events = 20; >+ count.bwe_delay_events = 20; >+ count.probe_creations = 4; >+ count.probe_successes = 2; >+ count.probe_failures = 2; >+ count.ice_configs = 3; >+ count.ice_events = 10; >+ count.incoming_rtp_packets = 100; >+ count.outgoing_rtp_packets = 100; >+ count.incoming_rtcp_packets = 20; >+ count.outgoing_rtcp_packets = 20; >+ >+ WriteLog(count, 0); >+ ReadAndVerifyLog(); > } > >-TEST_P(RtcEventLogSession, LogLongSessionAndReadBack) { >- RtpHeaderExtensionMap extensions; >- for (uint32_t i = 0; i < kNumExtensions; i++) { >- extensions.Register(kExtensionTypes[i], kExtensionIds[i]); >- } >- GenerateSessionDescription(1000, 1000, 250, 250, 200, 100, 100, extensions, >- 1); >- WriteSession(); >- ReadAndVerifySession(); >+TEST_P(RtcEventLogSession, StartLoggingInTheMiddle) { >+ EventCounts count; >+ count.audio_send_streams = 3; >+ count.audio_recv_streams = 4; >+ count.video_send_streams = 5; >+ count.video_recv_streams = 6; >+ count.alr_states = 10; >+ count.audio_playouts = 500; >+ count.ana_configs = 10; >+ count.bwe_loss_events = 50; >+ count.bwe_delay_events = 50; >+ count.probe_creations = 10; >+ count.probe_successes = 5; >+ count.probe_failures = 5; >+ count.ice_configs = 10; >+ count.ice_events = 20; >+ count.incoming_rtp_packets = 500; >+ count.outgoing_rtp_packets = 500; >+ count.incoming_rtcp_packets = 50; >+ count.outgoing_rtcp_packets = 50; >+ >+ WriteLog(count, 500); >+ ReadAndVerifyLog(); > } > > TEST(RtcEventLogTest, CircularBufferKeepsMostRecentEvents) { >+ // TODO(terelius): Maybe make a separate RtcEventLogImplTest that can access >+ // the size of the cyclic buffer? > constexpr size_t kNumEvents = 20000; > constexpr int64_t kStartTime = 1000000; >+ constexpr int32_t kStartBitrate = 1000000; > > auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); >- std::string test_name = test_info->name(); >+ std::string test_name = >+ std::string(test_info->test_case_name()) + "_" + test_info->name(); > std::replace(test_name.begin(), test_name.end(), '/', '_'); >- const std::string temp_filename = >- test::OutputPath() + "RtcEventLogTest_" + test_name; >+ const std::string temp_filename = test::OutputPath() + test_name; > >- rtc::ScopedFakeClock fake_clock; >- fake_clock.SetTimeMicros(kStartTime); >+ std::unique_ptr<rtc::ScopedFakeClock> fake_clock = >+ absl::make_unique<rtc::ScopedFakeClock>(); >+ fake_clock->SetTimeMicros(kStartTime); > > // When log_dumper goes out of scope, it causes the log file to be flushed > // to disk. >@@ -722,50 +705,62 @@ TEST(RtcEventLogTest, CircularBufferKeepsMostRecentEvents) { > for (size_t i = 0; i < kNumEvents; i++) { > // The purpose of the test is to verify that the log can handle > // more events than what fits in the internal circular buffer. The exact >- // type of events does not matter so we chose AudioPlayouts for simplicity. >- // We use the index as an ssrc to get a strict relationship between the ssrc >- // and the timestamp. We use this for some basic consistency checks when we >- // read back. >- log_dumper->Log(rtc::MakeUnique<RtcEventAudioPlayout>(i)); >- fake_clock.AdvanceTimeMicros(10000); >+ // type of events does not matter so we chose ProbeSuccess events for >+ // simplicity. >+ // We base the various values on the index. We use this for some basic >+ // consistency checks when we read back. >+ log_dumper->Log(absl::make_unique<RtcEventProbeResultSuccess>( >+ i, kStartBitrate + i * 1000)); >+ fake_clock->AdvanceTimeMicros(10000); > } >+ int64_t start_time_us = rtc::TimeMicros(); > log_dumper->StartLogging( >- rtc::MakeUnique<RtcEventLogOutputFile>(temp_filename, 10000000), >+ absl::make_unique<RtcEventLogOutputFile>(temp_filename, 10000000), > RtcEventLog::kImmediateOutput); >+ fake_clock->AdvanceTimeMicros(10000); >+ int64_t stop_time_us = rtc::TimeMicros(); > log_dumper->StopLogging(); > > // Read the generated file from disk. >- ParsedRtcEventLog parsed_log; >+ ParsedRtcEventLogNew parsed_log; > ASSERT_TRUE(parsed_log.ParseFile(temp_filename)); >+ >+ const auto& start_log_events = parsed_log.start_log_events(); >+ ASSERT_EQ(start_log_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedStartEvent(start_time_us, start_log_events[0])); >+ >+ const auto& stop_log_events = parsed_log.stop_log_events(); >+ ASSERT_EQ(stop_log_events.size(), 1u); >+ EXPECT_TRUE(test::VerifyLoggedStopEvent(stop_time_us, stop_log_events[0])); >+ >+ const auto& probe_success_events = parsed_log.bwe_probe_success_events(); > // If the following fails, it probably means that kNumEvents isn't larger > // than the size of the cyclic buffer in the event log. Try increasing > // kNumEvents. >- EXPECT_LT(parsed_log.GetNumberOfEvents(), kNumEvents); >- // We expect a start event, some number of playouts events and a stop event. >- EXPECT_GT(parsed_log.GetNumberOfEvents(), 2u); >- >- RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0); >- rtc::Optional<int64_t> last_timestamp; >- rtc::Optional<uint32_t> last_ssrc; >- for (size_t i = 1; i < parsed_log.GetNumberOfEvents() - 1; i++) { >- EXPECT_EQ(parsed_log.GetEventType(i), >- ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT); >- uint32_t ssrc; >- parsed_log.GetAudioPlayout(i, &ssrc); >- int64_t timestamp = parsed_log.GetTimestamp(i); >- EXPECT_LT(ssrc, kNumEvents); >- EXPECT_EQ(static_cast<int64_t>(kStartTime + 10000 * ssrc), timestamp); >- if (last_ssrc) >- EXPECT_EQ(ssrc, *last_ssrc + 1); >- if (last_timestamp) >- EXPECT_EQ(timestamp, *last_timestamp + 10000); >- last_ssrc = ssrc; >- last_timestamp = timestamp; >+ EXPECT_LT(probe_success_events.size(), kNumEvents); >+ >+ ASSERT_GT(probe_success_events.size(), 1u); >+ int64_t first_timestamp_us = probe_success_events[0].timestamp_us; >+ uint32_t first_id = probe_success_events[0].id; >+ int32_t first_bitrate_bps = probe_success_events[0].bitrate_bps; >+ // We want to reset the time to what we used when generating the events, but >+ // the fake clock implementation DCHECKS if time moves backwards. We therefore >+ // recreate the clock. However we must ensure that the old fake_clock is >+ // destroyed before the new one is created, so we have to reset() first. >+ fake_clock.reset(); >+ fake_clock = absl::make_unique<rtc::ScopedFakeClock>(); >+ fake_clock->SetTimeMicros(first_timestamp_us); >+ for (size_t i = 1; i < probe_success_events.size(); i++) { >+ fake_clock->AdvanceTimeMicros(10000); >+ ASSERT_TRUE(test::VerifyLoggedBweProbeSuccessEvent( >+ RtcEventProbeResultSuccess(first_id + i, first_bitrate_bps + i * 1000), >+ probe_success_events[i])); > } >- RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log, >- parsed_log.GetNumberOfEvents() - 1); > } > >+// TODO(terelius): Verify parser behavior if the timestamps are not >+// monotonically increasing in the log. >+ > INSTANTIATE_TEST_CASE_P( > RtcEventLogTest, > RtcEventLogSession, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc >index 23e15b5033b..273539c1aca 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.cc >@@ -10,610 +10,809 @@ > > #include "logging/rtc_event_log/rtc_event_log_unittest_helper.h" > >-#include <string.h> >+#include <string.h> // memcmp > >-#include <string> >+#include <limits> >+#include <memory> >+#include <numeric> >+#include <utility> > #include <vector> > > #include "modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" > #include "modules/remote_bitrate_estimator/include/bwe_defines.h" >+#include "modules/rtp_rtcp/include/rtp_cvo.h" >+#include "modules/rtp_rtcp/source/rtp_header_extensions.h" >+#include "modules/rtp_rtcp/source/rtp_packet_received.h" >+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" > #include "rtc_base/checks.h" >-#include "test/gmock.h" >-#include "test/gtest.h" >-#include "test/testsupport/fileutils.h" >- >-// Files generated at build-time by the protobuf compiler. >-#ifdef WEBRTC_ANDROID_PLATFORM_BUILD >-#include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h" >-#else >-#include "logging/rtc_event_log/rtc_event_log.pb.h" >-#endif > > namespace webrtc { > >+namespace test { >+ > namespace { > >-BandwidthUsage GetRuntimeDetectorState( >- rtclog::DelayBasedBweUpdate::DetectorState detector_state) { >- switch (detector_state) { >- case rtclog::DelayBasedBweUpdate::BWE_NORMAL: >- return BandwidthUsage::kBwNormal; >- case rtclog::DelayBasedBweUpdate::BWE_UNDERUSING: >- return BandwidthUsage::kBwUnderusing; >- case rtclog::DelayBasedBweUpdate::BWE_OVERUSING: >- return BandwidthUsage::kBwOverusing; >- } >- RTC_NOTREACHED(); >- return BandwidthUsage::kBwNormal; >-} >- >-rtclog::BweProbeResult::ResultType GetProbeResultType( >- ProbeFailureReason failure_reason) { >- switch (failure_reason) { >- case ProbeFailureReason::kInvalidSendReceiveInterval: >- return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_INTERVAL; >- case ProbeFailureReason::kInvalidSendReceiveRatio: >- return rtclog::BweProbeResult::INVALID_SEND_RECEIVE_RATIO; >- case ProbeFailureReason::kTimeout: >- return rtclog::BweProbeResult::TIMEOUT; >- case ProbeFailureReason::kLast: >- RTC_NOTREACHED(); >+struct ExtensionPair { >+ RTPExtensionType type; >+ const char* name; >+}; >+ >+constexpr int kMaxCsrcs = 3; >+ >+// Maximum serialized size of a header extension, including 1 byte ID. >+constexpr int kMaxExtensionSizeBytes = 4; >+constexpr int kMaxNumExtensions = 5; >+ >+constexpr ExtensionPair kExtensions[kMaxNumExtensions] = { >+ {RTPExtensionType::kRtpExtensionTransmissionTimeOffset, >+ RtpExtension::kTimestampOffsetUri}, >+ {RTPExtensionType::kRtpExtensionAbsoluteSendTime, >+ RtpExtension::kAbsSendTimeUri}, >+ {RTPExtensionType::kRtpExtensionTransportSequenceNumber, >+ RtpExtension::kTransportSequenceNumberUri}, >+ {RTPExtensionType::kRtpExtensionAudioLevel, RtpExtension::kAudioLevelUri}, >+ {RTPExtensionType::kRtpExtensionVideoRotation, >+ RtpExtension::kVideoRotationUri}}; >+ >+template <typename T> >+void ShuffleInPlace(Random* prng, rtc::ArrayView<T> array) { >+ RTC_DCHECK_LE(array.size(), std::numeric_limits<uint32_t>::max()); >+ for (uint32_t i = 0; i + 1 < array.size(); i++) { >+ uint32_t other = prng->Rand(i, static_cast<uint32_t>(array.size() - 1)); >+ std::swap(array[i], array[other]); > } >- RTC_NOTREACHED(); >- return rtclog::BweProbeResult::SUCCESS; > } > } // namespace > >-// Checks that the event has a timestamp, a type and exactly the data field >-// corresponding to the type. >-::testing::AssertionResult IsValidBasicEvent(const rtclog::Event& event) { >- if (!event.has_timestamp_us()) { >- return ::testing::AssertionFailure() << "Event has no timestamp"; >- } >- if (!event.has_type()) { >- return ::testing::AssertionFailure() << "Event has no event type"; >+std::unique_ptr<RtcEventAlrState> EventGenerator::NewAlrState() { >+ return absl::make_unique<RtcEventAlrState>(prng_.Rand<bool>()); >+} >+ >+std::unique_ptr<RtcEventAudioPlayout> EventGenerator::NewAudioPlayout( >+ uint32_t ssrc) { >+ return absl::make_unique<RtcEventAudioPlayout>(ssrc); >+} >+ >+std::unique_ptr<RtcEventAudioNetworkAdaptation> >+EventGenerator::NewAudioNetworkAdaptation() { >+ std::unique_ptr<AudioEncoderRuntimeConfig> config = >+ absl::make_unique<AudioEncoderRuntimeConfig>(); >+ >+ config->bitrate_bps = prng_.Rand(0, 3000000); >+ config->enable_fec = prng_.Rand<bool>(); >+ config->enable_dtx = prng_.Rand<bool>(); >+ config->frame_length_ms = prng_.Rand(10, 120); >+ config->num_channels = prng_.Rand(1, 2); >+ config->uplink_packet_loss_fraction = prng_.Rand<float>(); >+ >+ return absl::make_unique<RtcEventAudioNetworkAdaptation>(std::move(config)); >+} >+ >+std::unique_ptr<RtcEventBweUpdateDelayBased> >+EventGenerator::NewBweUpdateDelayBased() { >+ constexpr int32_t kMaxBweBps = 20000000; >+ int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps); >+ BandwidthUsage state = static_cast<BandwidthUsage>( >+ prng_.Rand(static_cast<uint32_t>(BandwidthUsage::kLast) - 1)); >+ return absl::make_unique<RtcEventBweUpdateDelayBased>(bitrate_bps, state); >+} >+ >+std::unique_ptr<RtcEventBweUpdateLossBased> >+EventGenerator::NewBweUpdateLossBased() { >+ constexpr int32_t kMaxBweBps = 20000000; >+ constexpr int32_t kMaxPackets = 1000; >+ int32_t bitrate_bps = prng_.Rand(0, kMaxBweBps); >+ uint8_t fraction_lost = prng_.Rand<uint8_t>(); >+ int32_t total_packets = prng_.Rand(1, kMaxPackets); >+ >+ return absl::make_unique<RtcEventBweUpdateLossBased>( >+ bitrate_bps, fraction_lost, total_packets); >+} >+ >+std::unique_ptr<RtcEventProbeClusterCreated> >+EventGenerator::NewProbeClusterCreated() { >+ constexpr int kMaxBweBps = 20000000; >+ constexpr int kMaxNumProbes = 10000; >+ int id = prng_.Rand(1, kMaxNumProbes); >+ int bitrate_bps = prng_.Rand(0, kMaxBweBps); >+ int min_probes = prng_.Rand(5, 50); >+ int min_bytes = prng_.Rand(500, 50000); >+ >+ return absl::make_unique<RtcEventProbeClusterCreated>(id, bitrate_bps, >+ min_probes, min_bytes); >+} >+ >+std::unique_ptr<RtcEventProbeResultFailure> >+EventGenerator::NewProbeResultFailure() { >+ constexpr int kMaxNumProbes = 10000; >+ int id = prng_.Rand(1, kMaxNumProbes); >+ ProbeFailureReason reason = static_cast<ProbeFailureReason>( >+ prng_.Rand(static_cast<uint32_t>(ProbeFailureReason::kLast) - 1)); >+ >+ return absl::make_unique<RtcEventProbeResultFailure>(id, reason); >+} >+ >+std::unique_ptr<RtcEventProbeResultSuccess> >+EventGenerator::NewProbeResultSuccess() { >+ constexpr int kMaxBweBps = 20000000; >+ constexpr int kMaxNumProbes = 10000; >+ int id = prng_.Rand(1, kMaxNumProbes); >+ int bitrate_bps = prng_.Rand(0, kMaxBweBps); >+ >+ return absl::make_unique<RtcEventProbeResultSuccess>(id, bitrate_bps); >+} >+ >+std::unique_ptr<RtcEventIceCandidatePairConfig> >+EventGenerator::NewIceCandidatePairConfig() { >+ IceCandidateType local_candidate_type = static_cast<IceCandidateType>( >+ prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1)); >+ IceCandidateNetworkType local_network_type = >+ static_cast<IceCandidateNetworkType>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidateNetworkType::kNumValues) - 1)); >+ IceCandidatePairAddressFamily local_address_family = >+ static_cast<IceCandidatePairAddressFamily>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - >+ 1)); >+ IceCandidateType remote_candidate_type = static_cast<IceCandidateType>( >+ prng_.Rand(static_cast<uint32_t>(IceCandidateType::kNumValues) - 1)); >+ IceCandidatePairAddressFamily remote_address_family = >+ static_cast<IceCandidatePairAddressFamily>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidatePairAddressFamily::kNumValues) - >+ 1)); >+ IceCandidatePairProtocol protocol_type = >+ static_cast<IceCandidatePairProtocol>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidatePairProtocol::kNumValues) - 1)); >+ >+ IceCandidatePairDescription desc; >+ desc.local_candidate_type = local_candidate_type; >+ desc.local_relay_protocol = protocol_type; >+ desc.local_network_type = local_network_type; >+ desc.local_address_family = local_address_family; >+ desc.remote_candidate_type = remote_candidate_type; >+ desc.remote_address_family = remote_address_family; >+ desc.candidate_pair_protocol = protocol_type; >+ >+ IceCandidatePairConfigType type = >+ static_cast<IceCandidatePairConfigType>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidatePairConfigType::kNumValues) - 1)); >+ uint32_t pair_id = prng_.Rand<uint32_t>(); >+ return absl::make_unique<RtcEventIceCandidatePairConfig>(type, pair_id, desc); >+} >+ >+std::unique_ptr<RtcEventIceCandidatePair> >+EventGenerator::NewIceCandidatePair() { >+ IceCandidatePairEventType type = >+ static_cast<IceCandidatePairEventType>(prng_.Rand( >+ static_cast<uint32_t>(IceCandidatePairEventType::kNumValues) - 1)); >+ uint32_t pair_id = prng_.Rand<uint32_t>(); >+ >+ return absl::make_unique<RtcEventIceCandidatePair>(type, pair_id); >+} >+ >+rtcp::ReportBlock EventGenerator::NewReportBlock() { >+ rtcp::ReportBlock report_block; >+ report_block.SetMediaSsrc(prng_.Rand<uint32_t>()); >+ report_block.SetFractionLost(prng_.Rand<uint8_t>()); >+ // cumulative_lost is a 3-byte signed value. >+ RTC_DCHECK(report_block.SetCumulativeLost( >+ prng_.Rand(-(1 << 23) + 1, (1 << 23) - 1))); >+ report_block.SetExtHighestSeqNum(prng_.Rand<uint32_t>()); >+ report_block.SetJitter(prng_.Rand<uint32_t>()); >+ report_block.SetLastSr(prng_.Rand<uint32_t>()); >+ report_block.SetDelayLastSr(prng_.Rand<uint32_t>()); >+ return report_block; >+} >+ >+rtcp::SenderReport EventGenerator::NewSenderReport() { >+ rtcp::SenderReport sender_report; >+ sender_report.SetSenderSsrc(prng_.Rand<uint32_t>()); >+ sender_report.SetNtp(NtpTime(prng_.Rand<uint32_t>(), prng_.Rand<uint32_t>())); >+ sender_report.SetPacketCount(prng_.Rand<uint32_t>()); >+ sender_report.AddReportBlock(NewReportBlock()); >+ return sender_report; >+} >+ >+rtcp::ReceiverReport EventGenerator::NewReceiverReport() { >+ rtcp::ReceiverReport receiver_report; >+ receiver_report.SetSenderSsrc(prng_.Rand<uint32_t>()); >+ receiver_report.AddReportBlock(NewReportBlock()); >+ return receiver_report; >+} >+ >+std::unique_ptr<RtcEventRtcpPacketIncoming> >+EventGenerator::NewRtcpPacketIncoming() { >+ // TODO(terelius): Test the other RTCP types too. >+ switch (prng_.Rand(0, 1)) { >+ case 0: { >+ rtcp::SenderReport sender_report = NewSenderReport(); >+ rtc::Buffer buffer = sender_report.Build(); >+ return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); >+ } >+ case 1: { >+ rtcp::ReceiverReport receiver_report = NewReceiverReport(); >+ rtc::Buffer buffer = receiver_report.Build(); >+ return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); >+ } >+ default: >+ RTC_NOTREACHED(); >+ rtc::Buffer buffer; >+ return absl::make_unique<RtcEventRtcpPacketIncoming>(buffer); > } >- rtclog::Event_EventType type = event.type(); >- if ((type == rtclog::Event::RTP_EVENT) != event.has_rtp_packet()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_rtp_packet() ? "" : "no ") << "RTP packet"; >+} >+ >+std::unique_ptr<RtcEventRtcpPacketOutgoing> >+EventGenerator::NewRtcpPacketOutgoing() { >+ // TODO(terelius): Test the other RTCP types too. >+ switch (prng_.Rand(0, 1)) { >+ case 0: { >+ rtcp::SenderReport sender_report = NewSenderReport(); >+ rtc::Buffer buffer = sender_report.Build(); >+ return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); >+ } >+ case 1: { >+ rtcp::ReceiverReport receiver_report = NewReceiverReport(); >+ rtc::Buffer buffer = receiver_report.Build(); >+ return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); >+ } >+ default: >+ RTC_NOTREACHED(); >+ rtc::Buffer buffer; >+ return absl::make_unique<RtcEventRtcpPacketOutgoing>(buffer); > } >- if ((type == rtclog::Event::RTCP_EVENT) != event.has_rtcp_packet()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_rtcp_packet() ? "" : "no ") << "RTCP packet"; >+} >+ >+void EventGenerator::RandomizeRtpPacket( >+ size_t packet_size, >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map, >+ RtpPacket* rtp_packet) { >+ constexpr int kMaxPayloadType = 127; >+ rtp_packet->SetPayloadType(prng_.Rand(kMaxPayloadType)); >+ rtp_packet->SetMarker(prng_.Rand<bool>()); >+ rtp_packet->SetSequenceNumber(prng_.Rand<uint16_t>()); >+ rtp_packet->SetSsrc(ssrc); >+ rtp_packet->SetTimestamp(prng_.Rand<uint32_t>()); >+ >+ uint32_t csrcs_count = prng_.Rand(0, kMaxCsrcs); >+ std::vector<uint32_t> csrcs; >+ for (size_t i = 0; i < csrcs_count; i++) { >+ csrcs.push_back(prng_.Rand<uint32_t>()); > } >- if ((type == rtclog::Event::LOSS_BASED_BWE_UPDATE) != >- event.has_loss_based_bwe_update()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_loss_based_bwe_update() ? "" : "no ") << "loss update"; >+ rtp_packet->SetCsrcs(csrcs); >+ >+ if (extension_map.IsRegistered(TransmissionOffset::kId)) >+ rtp_packet->SetExtension<TransmissionOffset>(prng_.Rand(0x00ffffff)); >+ if (extension_map.IsRegistered(AudioLevel::kId)) >+ rtp_packet->SetExtension<AudioLevel>(prng_.Rand<bool>(), prng_.Rand(127)); >+ if (extension_map.IsRegistered(AbsoluteSendTime::kId)) >+ rtp_packet->SetExtension<AbsoluteSendTime>(prng_.Rand(0x00ffffff)); >+ if (extension_map.IsRegistered(VideoOrientation::kId)) >+ rtp_packet->SetExtension<VideoOrientation>(prng_.Rand(3)); >+ if (extension_map.IsRegistered(TransportSequenceNumber::kId)) >+ rtp_packet->SetExtension<TransportSequenceNumber>(prng_.Rand<uint16_t>()); >+ >+ RTC_DCHECK_GE(packet_size, rtp_packet->headers_size()); >+ size_t payload_size = packet_size - rtp_packet->headers_size(); >+ RTC_CHECK_LE(rtp_packet->headers_size() + payload_size, IP_PACKET_SIZE); >+ uint8_t* payload = rtp_packet->AllocatePayload(payload_size); >+ RTC_DCHECK(payload != nullptr); >+ for (size_t i = 0; i < payload_size; i++) { >+ payload[i] = prng_.Rand<uint8_t>(); > } >- if ((type == rtclog::Event::DELAY_BASED_BWE_UPDATE) != >- event.has_delay_based_bwe_update()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_delay_based_bwe_update() ? "" : "no ") >- << "delay update"; >+} >+ >+std::unique_ptr<RtcEventRtpPacketIncoming> EventGenerator::NewRtpPacketIncoming( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map) { >+ // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. >+ constexpr size_t kMaxHeaderSize = >+ 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; >+ size_t packet_size = >+ prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1)); >+ >+ RtpPacketReceived rtp_packet(&extension_map); >+ RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet); >+ >+ return absl::make_unique<RtcEventRtpPacketIncoming>(rtp_packet); >+} >+ >+std::unique_ptr<RtcEventRtpPacketOutgoing> EventGenerator::NewRtpPacketOutgoing( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map) { >+ // 12 bytes RTP header, 4 bytes for 0xBEDE + alignment, 4 bytes per CSRC. >+ constexpr size_t kMaxHeaderSize = >+ 16 + 4 * kMaxCsrcs + kMaxExtensionSizeBytes * kMaxNumExtensions; >+ size_t packet_size = >+ prng_.Rand(kMaxHeaderSize, static_cast<uint32_t>(IP_PACKET_SIZE - 1)); >+ >+ RtpPacketToSend rtp_packet(&extension_map, packet_size); >+ RandomizeRtpPacket(packet_size, ssrc, extension_map, &rtp_packet); >+ >+ int probe_cluster_id = prng_.Rand(0, 100000); >+ return absl::make_unique<RtcEventRtpPacketOutgoing>(rtp_packet, >+ probe_cluster_id); >+} >+ >+RtpHeaderExtensionMap EventGenerator::NewRtpHeaderExtensionMap() { >+ RtpHeaderExtensionMap extension_map; >+ std::vector<int> id(RtpExtension::kMaxId - RtpExtension::kMinId + 1); >+ std::iota(id.begin(), id.end(), RtpExtension::kMinId); >+ ShuffleInPlace(&prng_, rtc::ArrayView<int>(id)); >+ >+ if (prng_.Rand<bool>()) { >+ extension_map.Register<AudioLevel>(id[0]); > } >- if ((type == rtclog::Event::AUDIO_PLAYOUT_EVENT) != >- event.has_audio_playout_event()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_audio_playout_event() ? "" : "no ") >- << "audio_playout event"; >+ if (prng_.Rand<bool>()) { >+ extension_map.Register<TransmissionOffset>(id[1]); > } >- if ((type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT) != >- event.has_video_receiver_config()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_video_receiver_config() ? "" : "no ") >- << "receiver config"; >+ if (prng_.Rand<bool>()) { >+ extension_map.Register<AbsoluteSendTime>(id[2]); > } >- if ((type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT) != >- event.has_video_sender_config()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_video_sender_config() ? "" : "no ") << "sender config"; >+ if (prng_.Rand<bool>()) { >+ extension_map.Register<VideoOrientation>(id[3]); > } >- if ((type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT) != >- event.has_audio_receiver_config()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_audio_receiver_config() ? "" : "no ") >- << "audio receiver config"; >+ if (prng_.Rand<bool>()) { >+ extension_map.Register<TransportSequenceNumber>(id[4]); > } >- if ((type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT) != >- event.has_audio_sender_config()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_audio_sender_config() ? "" : "no ") >- << "audio sender config"; >+ >+ return extension_map; >+} >+ >+std::unique_ptr<RtcEventAudioReceiveStreamConfig> >+EventGenerator::NewAudioReceiveStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions) { >+ auto config = absl::make_unique<rtclog::StreamConfig>(); >+ // Add SSRCs for the stream. >+ config->remote_ssrc = ssrc; >+ config->local_ssrc = prng_.Rand<uint32_t>(); >+ // Add header extensions. >+ for (size_t i = 0; i < kMaxNumExtensions; i++) { >+ uint8_t id = extensions.GetId(kExtensions[i].type); >+ if (id != RtpHeaderExtensionMap::kInvalidId) { >+ config->rtp_extensions.emplace_back(kExtensions[i].name, id); >+ } > } >- if ((type == rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT) != >- event.has_audio_network_adaptation()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_audio_network_adaptation() ? "" : "no ") >- << "audio network adaptation"; >+ >+ return absl::make_unique<RtcEventAudioReceiveStreamConfig>(std::move(config)); >+} >+ >+std::unique_ptr<RtcEventAudioSendStreamConfig> >+EventGenerator::NewAudioSendStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions) { >+ auto config = absl::make_unique<rtclog::StreamConfig>(); >+ // Add SSRC to the stream. >+ config->local_ssrc = ssrc; >+ // Add header extensions. >+ for (size_t i = 0; i < kMaxNumExtensions; i++) { >+ uint8_t id = extensions.GetId(kExtensions[i].type); >+ if (id != RtpHeaderExtensionMap::kInvalidId) { >+ config->rtp_extensions.emplace_back(kExtensions[i].name, id); >+ } > } >- if ((type == rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT) != >- event.has_probe_cluster()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_probe_cluster() ? "" : "no ") << "bwe probe cluster"; >+ return absl::make_unique<RtcEventAudioSendStreamConfig>(std::move(config)); >+} >+ >+std::unique_ptr<RtcEventVideoReceiveStreamConfig> >+EventGenerator::NewVideoReceiveStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions) { >+ auto config = absl::make_unique<rtclog::StreamConfig>(); >+ >+ // Add SSRCs for the stream. >+ config->remote_ssrc = ssrc; >+ config->local_ssrc = prng_.Rand<uint32_t>(); >+ // Add extensions and settings for RTCP. >+ config->rtcp_mode = >+ prng_.Rand<bool>() ? RtcpMode::kCompound : RtcpMode::kReducedSize; >+ config->remb = prng_.Rand<bool>(); >+ config->rtx_ssrc = prng_.Rand<uint32_t>(); >+ config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264", >+ prng_.Rand(127), prng_.Rand(127)); >+ // Add header extensions. >+ for (size_t i = 0; i < kMaxNumExtensions; i++) { >+ uint8_t id = extensions.GetId(kExtensions[i].type); >+ if (id != RtpHeaderExtensionMap::kInvalidId) { >+ config->rtp_extensions.emplace_back(kExtensions[i].name, id); >+ } > } >- if ((type == rtclog::Event::BWE_PROBE_RESULT_EVENT) != >- event.has_probe_result()) { >- return ::testing::AssertionFailure() >- << "Event of type " << type << " has " >- << (event.has_probe_result() ? "" : "no ") << "bwe probe result"; >+ return absl::make_unique<RtcEventVideoReceiveStreamConfig>(std::move(config)); >+} >+ >+std::unique_ptr<RtcEventVideoSendStreamConfig> >+EventGenerator::NewVideoSendStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions) { >+ auto config = absl::make_unique<rtclog::StreamConfig>(); >+ >+ config->codecs.emplace_back(prng_.Rand<bool>() ? "VP8" : "H264", >+ prng_.Rand(127), prng_.Rand(127)); >+ config->local_ssrc = ssrc; >+ config->rtx_ssrc = prng_.Rand<uint32_t>(); >+ // Add header extensions. >+ for (size_t i = 0; i < kMaxNumExtensions; i++) { >+ uint8_t id = extensions.GetId(kExtensions[i].type); >+ if (id != RtpHeaderExtensionMap::kInvalidId) { >+ config->rtp_extensions.emplace_back(kExtensions[i].name, id); >+ } > } >- return ::testing::AssertionSuccess(); >+ return absl::make_unique<RtcEventVideoSendStreamConfig>(std::move(config)); >+} >+ >+bool VerifyLoggedAlrStateEvent(const RtcEventAlrState& original_event, >+ const LoggedAlrStateEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.in_alr_ != logged_event.in_alr) >+ return false; >+ return true; > } > >-void VerifyStreamConfigsAreEqual(const rtclog::StreamConfig& config_1, >- const rtclog::StreamConfig& config_2) { >- EXPECT_EQ(config_1.remote_ssrc, config_2.remote_ssrc); >- EXPECT_EQ(config_1.local_ssrc, config_2.local_ssrc); >- EXPECT_EQ(config_1.rtx_ssrc, config_2.rtx_ssrc); >- EXPECT_EQ(config_1.rtcp_mode, config_2.rtcp_mode); >- EXPECT_EQ(config_1.remb, config_2.remb); >+bool VerifyLoggedAudioPlayoutEvent( >+ const RtcEventAudioPlayout& original_event, >+ const LoggedAudioPlayoutEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.ssrc_ != logged_event.ssrc) >+ return false; >+ return true; >+} > >- ASSERT_EQ(config_1.rtp_extensions.size(), config_2.rtp_extensions.size()); >- for (size_t i = 0; i < config_2.rtp_extensions.size(); i++) { >- EXPECT_EQ(config_1.rtp_extensions[i].uri, config_2.rtp_extensions[i].uri); >- EXPECT_EQ(config_1.rtp_extensions[i].id, config_2.rtp_extensions[i].id); >- } >- ASSERT_EQ(config_1.codecs.size(), config_2.codecs.size()); >- for (size_t i = 0; i < config_2.codecs.size(); i++) { >- EXPECT_EQ(config_1.codecs[i].payload_name, config_2.codecs[i].payload_name); >- EXPECT_EQ(config_1.codecs[i].payload_type, config_2.codecs[i].payload_type); >- EXPECT_EQ(config_1.codecs[i].rtx_payload_type, >- config_2.codecs[i].rtx_payload_type); >- } >+bool VerifyLoggedAudioNetworkAdaptationEvent( >+ const RtcEventAudioNetworkAdaptation& original_event, >+ const LoggedAudioNetworkAdaptationEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.config_->bitrate_bps != logged_event.config.bitrate_bps) >+ return false; >+ if (original_event.config_->enable_dtx != logged_event.config.enable_dtx) >+ return false; >+ if (original_event.config_->enable_fec != logged_event.config.enable_fec) >+ return false; >+ if (original_event.config_->frame_length_ms != >+ logged_event.config.frame_length_ms) >+ return false; >+ if (original_event.config_->num_channels != logged_event.config.num_channels) >+ return false; >+ if (original_event.config_->uplink_packet_loss_fraction != >+ logged_event.config.uplink_packet_loss_fraction) >+ return false; >+ >+ return true; > } > >-void RtcEventLogTestHelper::VerifyVideoReceiveStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT, event.type()); >- const rtclog::VideoReceiveConfig& receiver_config = >- event.video_receiver_config(); >- // Check SSRCs. >- ASSERT_TRUE(receiver_config.has_remote_ssrc()); >- EXPECT_EQ(config.remote_ssrc, receiver_config.remote_ssrc()); >- ASSERT_TRUE(receiver_config.has_local_ssrc()); >- EXPECT_EQ(config.local_ssrc, receiver_config.local_ssrc()); >- // Check RTCP settings. >- ASSERT_TRUE(receiver_config.has_rtcp_mode()); >- if (config.rtcp_mode == RtcpMode::kCompound) { >- EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_COMPOUND, >- receiver_config.rtcp_mode()); >- } else { >- EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE, >- receiver_config.rtcp_mode()); >- } >- ASSERT_TRUE(receiver_config.has_remb()); >- EXPECT_EQ(config.remb, receiver_config.remb()); >- // Check RTX map. >- for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) { >- ASSERT_TRUE(rtx_map.has_payload_type()); >- ASSERT_TRUE(rtx_map.has_config()); >- const rtclog::RtxConfig& rtx_config = rtx_map.config(); >- ASSERT_TRUE(rtx_config.has_rtx_ssrc()); >- ASSERT_TRUE(rtx_config.has_rtx_payload_type()); >- >- EXPECT_EQ(config.rtx_ssrc, rtx_config.rtx_ssrc()); >- auto codec_found = >- std::find_if(config.codecs.begin(), config.codecs.end(), >- [&rtx_map](const rtclog::StreamConfig::Codec& codec) { >- return rtx_map.payload_type() == codec.payload_type; >- }); >- ASSERT_TRUE(codec_found != config.codecs.end()); >- EXPECT_EQ(rtx_config.rtx_payload_type(), codec_found->rtx_payload_type); >+bool VerifyLoggedBweDelayBasedUpdate( >+ const RtcEventBweUpdateDelayBased& original_event, >+ const LoggedBweDelayBasedUpdate& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.bitrate_bps_ != logged_event.bitrate_bps) >+ return false; >+ if (original_event.detector_state_ != logged_event.detector_state) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedBweLossBasedUpdate( >+ const RtcEventBweUpdateLossBased& original_event, >+ const LoggedBweLossBasedUpdate& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.bitrate_bps_ != logged_event.bitrate_bps) >+ return false; >+ if (original_event.fraction_loss_ != logged_event.fraction_lost) >+ return false; >+ if (original_event.total_packets_ != logged_event.expected_packets) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedBweProbeClusterCreatedEvent( >+ const RtcEventProbeClusterCreated& original_event, >+ const LoggedBweProbeClusterCreatedEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.id_ != logged_event.id) >+ return false; >+ if (original_event.bitrate_bps_ != logged_event.bitrate_bps) >+ return false; >+ if (original_event.min_probes_ != logged_event.min_packets) >+ return false; >+ if (original_event.min_bytes_ != logged_event.min_bytes) >+ return false; >+ >+ return true; >+} >+ >+bool VerifyLoggedBweProbeFailureEvent( >+ const RtcEventProbeResultFailure& original_event, >+ const LoggedBweProbeFailureEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.id_ != logged_event.id) >+ return false; >+ if (original_event.failure_reason_ != logged_event.failure_reason) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedBweProbeSuccessEvent( >+ const RtcEventProbeResultSuccess& original_event, >+ const LoggedBweProbeSuccessEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (original_event.id_ != logged_event.id) >+ return false; >+ if (original_event.bitrate_bps_ != logged_event.bitrate_bps) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedIceCandidatePairConfig( >+ const RtcEventIceCandidatePairConfig& original_event, >+ const LoggedIceCandidatePairConfig& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.type_ != logged_event.type) >+ return false; >+ if (original_event.candidate_pair_id_ != logged_event.candidate_pair_id) >+ return false; >+ if (original_event.candidate_pair_desc_.local_candidate_type != >+ logged_event.local_candidate_type) >+ return false; >+ if (original_event.candidate_pair_desc_.local_relay_protocol != >+ logged_event.local_relay_protocol) >+ return false; >+ if (original_event.candidate_pair_desc_.local_network_type != >+ logged_event.local_network_type) >+ return false; >+ if (original_event.candidate_pair_desc_.local_address_family != >+ logged_event.local_address_family) >+ return false; >+ if (original_event.candidate_pair_desc_.remote_candidate_type != >+ logged_event.remote_candidate_type) >+ return false; >+ if (original_event.candidate_pair_desc_.remote_address_family != >+ logged_event.remote_address_family) >+ return false; >+ if (original_event.candidate_pair_desc_.candidate_pair_protocol != >+ logged_event.candidate_pair_protocol) >+ return false; >+ >+ return true; >+} >+ >+bool VerifyLoggedIceCandidatePairEvent( >+ const RtcEventIceCandidatePair& original_event, >+ const LoggedIceCandidatePairEvent& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.type_ != logged_event.type) >+ return false; >+ if (original_event.candidate_pair_id_ != logged_event.candidate_pair_id) >+ return false; >+ >+ return true; >+} >+ >+bool VerifyLoggedRtpHeader(const RtpPacket& original_header, >+ const RTPHeader& logged_header) { >+ // Standard RTP header. >+ if (original_header.Marker() != logged_header.markerBit) >+ return false; >+ if (original_header.PayloadType() != logged_header.payloadType) >+ return false; >+ if (original_header.SequenceNumber() != logged_header.sequenceNumber) >+ return false; >+ if (original_header.Timestamp() != logged_header.timestamp) >+ return false; >+ if (original_header.Ssrc() != logged_header.ssrc) >+ return false; >+ if (original_header.Csrcs().size() != logged_header.numCSRCs) >+ return false; >+ for (size_t i = 0; i < logged_header.numCSRCs; i++) { >+ if (original_header.Csrcs()[i] != logged_header.arrOfCSRCs[i]) >+ return false; > } >- // Check header extensions. >- ASSERT_EQ(static_cast<int>(config.rtp_extensions.size()), >- receiver_config.header_extensions_size()); >- for (int i = 0; i < receiver_config.header_extensions_size(); i++) { >- ASSERT_TRUE(receiver_config.header_extensions(i).has_name()); >- ASSERT_TRUE(receiver_config.header_extensions(i).has_id()); >- const std::string& name = receiver_config.header_extensions(i).name(); >- int id = receiver_config.header_extensions(i).id(); >- EXPECT_EQ(config.rtp_extensions[i].id, id); >- EXPECT_EQ(config.rtp_extensions[i].uri, name); >+ >+ if (original_header.padding_size() != logged_header.paddingLength) >+ return false; >+ if (original_header.headers_size() != logged_header.headerLength) >+ return false; >+ >+ // TransmissionOffset header extension. >+ if (original_header.HasExtension<TransmissionOffset>() != >+ logged_header.extension.hasTransmissionTimeOffset) >+ return false; >+ if (logged_header.extension.hasTransmissionTimeOffset) { >+ int32_t offset; >+ original_header.GetExtension<TransmissionOffset>(&offset); >+ if (offset != logged_header.extension.transmissionTimeOffset) >+ return false; > } >- // Check decoders. >- ASSERT_EQ(static_cast<int>(config.codecs.size()), >- receiver_config.decoders_size()); >- for (int i = 0; i < receiver_config.decoders_size(); i++) { >- ASSERT_TRUE(receiver_config.decoders(i).has_name()); >- ASSERT_TRUE(receiver_config.decoders(i).has_payload_type()); >- const std::string& decoder_name = receiver_config.decoders(i).name(); >- int decoder_type = receiver_config.decoders(i).payload_type(); >- EXPECT_EQ(config.codecs[i].payload_name, decoder_name); >- EXPECT_EQ(config.codecs[i].payload_type, decoder_type); >+ >+ // AbsoluteSendTime header extension. >+ if (original_header.HasExtension<AbsoluteSendTime>() != >+ logged_header.extension.hasAbsoluteSendTime) >+ return false; >+ if (logged_header.extension.hasAbsoluteSendTime) { >+ uint32_t sendtime; >+ original_header.GetExtension<AbsoluteSendTime>(&sendtime); >+ if (sendtime != logged_header.extension.absoluteSendTime) >+ return false; > } > >- // Check consistency of the parser. >- rtclog::StreamConfig parsed_config = parsed_log.GetVideoReceiveConfig(index); >- VerifyStreamConfigsAreEqual(config, parsed_config); >-} >- >-void RtcEventLogTestHelper::VerifyVideoSendStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT, event.type()); >- const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); >- >- EXPECT_EQ(config.local_ssrc, sender_config.ssrcs(0)); >- EXPECT_EQ(config.rtx_ssrc, sender_config.rtx_ssrcs(0)); >- >- // Check header extensions. >- ASSERT_EQ(static_cast<int>(config.rtp_extensions.size()), >- sender_config.header_extensions_size()); >- for (int i = 0; i < sender_config.header_extensions_size(); i++) { >- ASSERT_TRUE(sender_config.header_extensions(i).has_name()); >- ASSERT_TRUE(sender_config.header_extensions(i).has_id()); >- const std::string& name = sender_config.header_extensions(i).name(); >- int id = sender_config.header_extensions(i).id(); >- EXPECT_EQ(config.rtp_extensions[i].id, id); >- EXPECT_EQ(config.rtp_extensions[i].uri, name); >+ // TransportSequenceNumber header extension. >+ if (original_header.HasExtension<TransportSequenceNumber>() != >+ logged_header.extension.hasTransportSequenceNumber) >+ return false; >+ if (logged_header.extension.hasTransportSequenceNumber) { >+ uint16_t seqnum; >+ original_header.GetExtension<TransportSequenceNumber>(&seqnum); >+ if (seqnum != logged_header.extension.transportSequenceNumber) >+ return false; > } >- // Check encoder. >- ASSERT_TRUE(sender_config.has_encoder()); >- ASSERT_TRUE(sender_config.encoder().has_name()); >- ASSERT_TRUE(sender_config.encoder().has_payload_type()); >- EXPECT_EQ(config.codecs[0].payload_name, sender_config.encoder().name()); >- EXPECT_EQ(config.codecs[0].payload_type, >- sender_config.encoder().payload_type()); >- >- EXPECT_EQ(config.codecs[0].rtx_payload_type, >- sender_config.rtx_payload_type()); >- >- // Check consistency of the parser. >- std::vector<rtclog::StreamConfig> parsed_configs = >- parsed_log.GetVideoSendConfig(index); >- ASSERT_EQ(1u, parsed_configs.size()); >- VerifyStreamConfigsAreEqual(config, parsed_configs[0]); >-} >- >-void RtcEventLogTestHelper::VerifyAudioReceiveStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT, event.type()); >- const rtclog::AudioReceiveConfig& receiver_config = >- event.audio_receiver_config(); >- // Check SSRCs. >- ASSERT_TRUE(receiver_config.has_remote_ssrc()); >- EXPECT_EQ(config.remote_ssrc, receiver_config.remote_ssrc()); >- ASSERT_TRUE(receiver_config.has_local_ssrc()); >- EXPECT_EQ(config.local_ssrc, receiver_config.local_ssrc()); >- // Check header extensions. >- ASSERT_EQ(static_cast<int>(config.rtp_extensions.size()), >- receiver_config.header_extensions_size()); >- for (int i = 0; i < receiver_config.header_extensions_size(); i++) { >- ASSERT_TRUE(receiver_config.header_extensions(i).has_name()); >- ASSERT_TRUE(receiver_config.header_extensions(i).has_id()); >- const std::string& name = receiver_config.header_extensions(i).name(); >- int id = receiver_config.header_extensions(i).id(); >- EXPECT_EQ(config.rtp_extensions[i].id, id); >- EXPECT_EQ(config.rtp_extensions[i].uri, name); >+ >+ // AudioLevel header extension. >+ if (original_header.HasExtension<AudioLevel>() != >+ logged_header.extension.hasAudioLevel) >+ return false; >+ if (logged_header.extension.hasAudioLevel) { >+ bool voice_activity; >+ uint8_t audio_level; >+ original_header.GetExtension<AudioLevel>(&voice_activity, &audio_level); >+ if (voice_activity != logged_header.extension.voiceActivity) >+ return false; >+ if (audio_level != logged_header.extension.audioLevel) >+ return false; > } > >- // Check consistency of the parser. >- rtclog::StreamConfig parsed_config = parsed_log.GetAudioReceiveConfig(index); >- EXPECT_EQ(config.remote_ssrc, parsed_config.remote_ssrc); >- EXPECT_EQ(config.local_ssrc, parsed_config.local_ssrc); >- // Check header extensions. >- EXPECT_EQ(config.rtp_extensions.size(), parsed_config.rtp_extensions.size()); >- for (size_t i = 0; i < parsed_config.rtp_extensions.size(); i++) { >- EXPECT_EQ(config.rtp_extensions[i].uri, >- parsed_config.rtp_extensions[i].uri); >- EXPECT_EQ(config.rtp_extensions[i].id, parsed_config.rtp_extensions[i].id); >+ // VideoOrientation header extension. >+ if (original_header.HasExtension<VideoOrientation>() != >+ logged_header.extension.hasVideoRotation) >+ return false; >+ if (logged_header.extension.hasVideoRotation) { >+ uint8_t rotation; >+ original_header.GetExtension<VideoOrientation>(&rotation); >+ if (ConvertCVOByteToVideoRotation(rotation) != >+ logged_header.extension.videoRotation) >+ return false; > } >+ >+ return true; >+} >+ >+bool VerifyLoggedRtpPacketIncoming( >+ const RtcEventRtpPacketIncoming& original_event, >+ const LoggedRtpPacketIncoming& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.header_.headers_size() != logged_event.rtp.header_length) >+ return false; >+ >+ if (original_event.packet_length_ != logged_event.rtp.total_length) >+ return false; >+ >+ if (!VerifyLoggedRtpHeader(original_event.header_, logged_event.rtp.header)) >+ return false; >+ >+ return true; >+} >+ >+bool VerifyLoggedRtpPacketOutgoing( >+ const RtcEventRtpPacketOutgoing& original_event, >+ const LoggedRtpPacketOutgoing& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.header_.headers_size() != logged_event.rtp.header_length) >+ return false; >+ >+ if (original_event.packet_length_ != logged_event.rtp.total_length) >+ return false; >+ >+ // TODO(terelius): Probe cluster ID isn't parsed, used or tested. Unless >+ // someone has a strong reason to keep it, it'll be removed. >+ >+ if (!VerifyLoggedRtpHeader(original_event.header_, logged_event.rtp.header)) >+ return false; >+ >+ return true; > } > >-void RtcEventLogTestHelper::VerifyAudioSendStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::AUDIO_SENDER_CONFIG_EVENT, event.type()); >- const rtclog::AudioSendConfig& sender_config = event.audio_sender_config(); >- // Check SSRCs. >- EXPECT_EQ(config.local_ssrc, sender_config.ssrc()); >- // Check header extensions. >- ASSERT_EQ(static_cast<int>(config.rtp_extensions.size()), >- sender_config.header_extensions_size()); >- for (int i = 0; i < sender_config.header_extensions_size(); i++) { >- ASSERT_TRUE(sender_config.header_extensions(i).has_name()); >- ASSERT_TRUE(sender_config.header_extensions(i).has_id()); >- const std::string& name = sender_config.header_extensions(i).name(); >- int id = sender_config.header_extensions(i).id(); >- EXPECT_EQ(config.rtp_extensions[i].id, id); >- EXPECT_EQ(config.rtp_extensions[i].uri, name); >+bool VerifyLoggedRtcpPacketIncoming( >+ const RtcEventRtcpPacketIncoming& original_event, >+ const LoggedRtcpPacketIncoming& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.packet_.size() != logged_event.rtcp.raw_data.size()) >+ return false; >+ if (memcmp(original_event.packet_.data(), logged_event.rtcp.raw_data.data(), >+ original_event.packet_.size()) != 0) { >+ return false; > } >+ return true; >+} > >- // Check consistency of the parser. >- rtclog::StreamConfig parsed_config = parsed_log.GetAudioSendConfig(index); >- VerifyStreamConfigsAreEqual(config, parsed_config); >-} >- >-void RtcEventLogTestHelper::VerifyIncomingRtpEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const RtpPacketReceived& expected_packet) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type()); >- const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); >- ASSERT_TRUE(rtp_packet.has_incoming()); >- EXPECT_TRUE(rtp_packet.incoming()); >- ASSERT_TRUE(rtp_packet.has_packet_length()); >- EXPECT_EQ(expected_packet.size(), rtp_packet.packet_length()); >- size_t header_size = expected_packet.headers_size(); >- ASSERT_TRUE(rtp_packet.has_header()); >- EXPECT_THAT(testing::make_tuple(expected_packet.data(), header_size), >- testing::ElementsAreArray(rtp_packet.header().data(), >- rtp_packet.header().size())); >- >- // Check consistency of the parser. >- PacketDirection parsed_direction; >- uint8_t parsed_header[1500]; >- size_t parsed_header_size, parsed_total_size; >- parsed_log.GetRtpHeader(index, &parsed_direction, parsed_header, >- &parsed_header_size, &parsed_total_size, nullptr); >- EXPECT_EQ(kIncomingPacket, parsed_direction); >- EXPECT_THAT(testing::make_tuple(expected_packet.data(), header_size), >- testing::ElementsAreArray(parsed_header, parsed_header_size)); >- EXPECT_EQ(expected_packet.size(), parsed_total_size); >-} >- >-void RtcEventLogTestHelper::VerifyOutgoingRtpEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const RtpPacketToSend& expected_packet) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type()); >- const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); >- ASSERT_TRUE(rtp_packet.has_incoming()); >- EXPECT_FALSE(rtp_packet.incoming()); >- ASSERT_TRUE(rtp_packet.has_packet_length()); >- EXPECT_EQ(expected_packet.size(), rtp_packet.packet_length()); >- size_t header_size = expected_packet.headers_size(); >- ASSERT_TRUE(rtp_packet.has_header()); >- EXPECT_THAT(testing::make_tuple(expected_packet.data(), header_size), >- testing::ElementsAreArray(rtp_packet.header().data(), >- rtp_packet.header().size())); >- >- // Check consistency of the parser. >- PacketDirection parsed_direction; >- uint8_t parsed_header[1500]; >- size_t parsed_header_size, parsed_total_size; >- parsed_log.GetRtpHeader(index, &parsed_direction, parsed_header, >- &parsed_header_size, &parsed_total_size, nullptr); >- EXPECT_EQ(kOutgoingPacket, parsed_direction); >- EXPECT_THAT(testing::make_tuple(expected_packet.data(), header_size), >- testing::ElementsAreArray(parsed_header, parsed_header_size)); >- EXPECT_EQ(expected_packet.size(), parsed_total_size); >-} >- >-void RtcEventLogTestHelper::VerifyRtcpEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- PacketDirection direction, >- const uint8_t* packet, >- size_t total_size) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type()); >- const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); >- ASSERT_TRUE(rtcp_packet.has_incoming()); >- EXPECT_EQ(direction == kIncomingPacket, rtcp_packet.incoming()); >- ASSERT_TRUE(rtcp_packet.has_packet_data()); >- ASSERT_EQ(total_size, rtcp_packet.packet_data().size()); >- for (size_t i = 0; i < total_size; i++) { >- EXPECT_EQ(packet[i], static_cast<uint8_t>(rtcp_packet.packet_data()[i])); >+bool VerifyLoggedRtcpPacketOutgoing( >+ const RtcEventRtcpPacketOutgoing& original_event, >+ const LoggedRtcpPacketOutgoing& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ >+ if (original_event.packet_.size() != logged_event.rtcp.raw_data.size()) >+ return false; >+ if (memcmp(original_event.packet_.data(), logged_event.rtcp.raw_data.data(), >+ original_event.packet_.size()) != 0) { >+ return false; > } >+ return true; >+} > >- // Check consistency of the parser. >- PacketDirection parsed_direction; >- uint8_t parsed_packet[1500]; >- size_t parsed_total_size; >- parsed_log.GetRtcpPacket(index, &parsed_direction, parsed_packet, >- &parsed_total_size); >- EXPECT_EQ(direction, parsed_direction); >- ASSERT_EQ(total_size, parsed_total_size); >- EXPECT_EQ(0, std::memcmp(packet, parsed_packet, total_size)); >+bool VerifyLoggedStartEvent(int64_t start_time_us, >+ const LoggedStartEvent& logged_event) { >+ if (start_time_us != logged_event.log_time_us()) >+ return false; >+ return true; > } > >-void RtcEventLogTestHelper::VerifyPlayoutEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t ssrc) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::AUDIO_PLAYOUT_EVENT, event.type()); >- const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event(); >- ASSERT_TRUE(playout_event.has_local_ssrc()); >- EXPECT_EQ(ssrc, playout_event.local_ssrc()); >- >- // Check consistency of the parser. >- uint32_t parsed_ssrc; >- parsed_log.GetAudioPlayout(index, &parsed_ssrc); >- EXPECT_EQ(ssrc, parsed_ssrc); >-} >- >-void RtcEventLogTestHelper::VerifyBweLossEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- int32_t bitrate, >- uint8_t fraction_loss, >- int32_t total_packets) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::LOSS_BASED_BWE_UPDATE, event.type()); >- const rtclog::LossBasedBweUpdate& bwe_event = event.loss_based_bwe_update(); >- ASSERT_TRUE(bwe_event.has_bitrate_bps()); >- EXPECT_EQ(bitrate, bwe_event.bitrate_bps()); >- ASSERT_TRUE(bwe_event.has_fraction_loss()); >- EXPECT_EQ(fraction_loss, bwe_event.fraction_loss()); >- ASSERT_TRUE(bwe_event.has_total_packets()); >- EXPECT_EQ(total_packets, bwe_event.total_packets()); >- >- // Check consistency of the parser. >- int32_t parsed_bitrate; >- uint8_t parsed_fraction_loss; >- int32_t parsed_total_packets; >- parsed_log.GetLossBasedBweUpdate( >- index, &parsed_bitrate, &parsed_fraction_loss, &parsed_total_packets); >- EXPECT_EQ(bitrate, parsed_bitrate); >- EXPECT_EQ(fraction_loss, parsed_fraction_loss); >- EXPECT_EQ(total_packets, parsed_total_packets); >-} >- >-void RtcEventLogTestHelper::VerifyBweDelayEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- int32_t bitrate, >- BandwidthUsage detector_state) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- ASSERT_EQ(rtclog::Event::DELAY_BASED_BWE_UPDATE, event.type()); >- const rtclog::DelayBasedBweUpdate& bwe_event = event.delay_based_bwe_update(); >- ASSERT_TRUE(bwe_event.has_bitrate_bps()); >- EXPECT_EQ(bitrate, bwe_event.bitrate_bps()); >- ASSERT_TRUE(bwe_event.has_detector_state()); >- EXPECT_EQ(detector_state, >- GetRuntimeDetectorState(bwe_event.detector_state())); >- >- // Check consistency of the parser. >- ParsedRtcEventLog::BweDelayBasedUpdate res = >- parsed_log.GetDelayBasedBweUpdate(index); >- EXPECT_EQ(res.bitrate_bps, bitrate); >- EXPECT_EQ(res.detector_state, detector_state); >-} >- >-void RtcEventLogTestHelper::VerifyAudioNetworkAdaptation( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const AudioEncoderRuntimeConfig& config) { >- AudioEncoderRuntimeConfig parsed_config; >- parsed_log.GetAudioNetworkAdaptation(index, &parsed_config); >- EXPECT_EQ(config.bitrate_bps, parsed_config.bitrate_bps); >- EXPECT_EQ(config.enable_dtx, parsed_config.enable_dtx); >- EXPECT_EQ(config.enable_fec, parsed_config.enable_fec); >- EXPECT_EQ(config.frame_length_ms, parsed_config.frame_length_ms); >- EXPECT_EQ(config.num_channels, parsed_config.num_channels); >- EXPECT_EQ(config.uplink_packet_loss_fraction, >- parsed_config.uplink_packet_loss_fraction); >-} >- >-void RtcEventLogTestHelper::VerifyLogStartEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- EXPECT_EQ(rtclog::Event::LOG_START, event.type()); >-} >- >-void RtcEventLogTestHelper::VerifyLogEndEvent( >- const ParsedRtcEventLog& parsed_log, >- size_t index) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- EXPECT_EQ(rtclog::Event::LOG_END, event.type()); >-} >- >-void RtcEventLogTestHelper::VerifyBweProbeCluster( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- uint32_t bitrate_bps, >- uint32_t min_probes, >- uint32_t min_bytes) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- EXPECT_EQ(rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT, event.type()); >- >- const rtclog::BweProbeCluster& bwe_event = event.probe_cluster(); >- ASSERT_TRUE(bwe_event.has_id()); >- EXPECT_EQ(id, bwe_event.id()); >- ASSERT_TRUE(bwe_event.has_bitrate_bps()); >- EXPECT_EQ(bitrate_bps, bwe_event.bitrate_bps()); >- ASSERT_TRUE(bwe_event.has_min_packets()); >- EXPECT_EQ(min_probes, bwe_event.min_packets()); >- ASSERT_TRUE(bwe_event.has_min_bytes()); >- EXPECT_EQ(min_bytes, bwe_event.min_bytes()); >- >- // TODO(philipel): Verify the parser when parsing has been implemented. >-} >- >-void RtcEventLogTestHelper::VerifyProbeResultSuccess( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- uint32_t bitrate_bps) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- EXPECT_EQ(rtclog::Event::BWE_PROBE_RESULT_EVENT, event.type()); >- >- const rtclog::BweProbeResult& bwe_event = event.probe_result(); >- ASSERT_TRUE(bwe_event.has_id()); >- EXPECT_EQ(id, bwe_event.id()); >- ASSERT_TRUE(bwe_event.has_bitrate_bps()); >- EXPECT_EQ(bitrate_bps, bwe_event.bitrate_bps()); >- ASSERT_TRUE(bwe_event.has_result()); >- EXPECT_EQ(rtclog::BweProbeResult::SUCCESS, bwe_event.result()); >- >- // TODO(philipel): Verify the parser when parsing has been implemented. >-} >- >-void RtcEventLogTestHelper::VerifyProbeResultFailure( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- ProbeFailureReason failure_reason) { >- ASSERT_LT(index, parsed_log.events_.size()); >- const rtclog::Event& event = parsed_log.events_[index]; >- ASSERT_TRUE(IsValidBasicEvent(event)); >- EXPECT_EQ(rtclog::Event::BWE_PROBE_RESULT_EVENT, event.type()); >- >- const rtclog::BweProbeResult& bwe_event = event.probe_result(); >- ASSERT_TRUE(bwe_event.has_id()); >- EXPECT_EQ(id, bwe_event.id()); >- ASSERT_TRUE(bwe_event.has_result()); >- EXPECT_EQ(GetProbeResultType(failure_reason), bwe_event.result()); >- ASSERT_FALSE(bwe_event.has_bitrate_bps()); >- >- // TODO(philipel): Verify the parser when parsing has been implemented. >+bool VerifyLoggedStopEvent(int64_t stop_time_us, >+ const LoggedStopEvent& logged_event) { >+ if (stop_time_us != logged_event.log_time_us()) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedAudioRecvConfig( >+ const RtcEventAudioReceiveStreamConfig& original_event, >+ const LoggedAudioRecvConfig& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (*original_event.config_ != logged_event.config) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedAudioSendConfig( >+ const RtcEventAudioSendStreamConfig& original_event, >+ const LoggedAudioSendConfig& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (*original_event.config_ != logged_event.config) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedVideoRecvConfig( >+ const RtcEventVideoReceiveStreamConfig& original_event, >+ const LoggedVideoRecvConfig& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ if (*original_event.config_ != logged_event.config) >+ return false; >+ return true; >+} >+ >+bool VerifyLoggedVideoSendConfig( >+ const RtcEventVideoSendStreamConfig& original_event, >+ const LoggedVideoSendConfig& logged_event) { >+ if (original_event.timestamp_us_ != logged_event.log_time_us()) >+ return false; >+ // TODO(terelius): In the past, we allowed storing multiple RtcStreamConfigs >+ // in the same RtcEventVideoSendStreamConfig. Look into whether we should drop >+ // backwards compatibility in the parser. >+ if (logged_event.configs.size() != 1) >+ return false; >+ if (*original_event.config_ != logged_event.configs[0]) >+ return false; >+ return true; > } > >+} // namespace test > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h >index 630f160a185..d67469c0ffa 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_event_log_unittest_helper.h >@@ -11,81 +11,180 @@ > #ifndef LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_ > #define LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_ > >-#include "call/call.h" >-#include "logging/rtc_event_log/rtc_event_log_parser.h" >-#include "modules/rtp_rtcp/source/rtp_packet_received.h" >-#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" >+#include <memory> >+ >+#include "logging/rtc_event_log/events/rtc_event.h" >+#include "logging/rtc_event_log/events/rtc_event_alr_state.h" >+#include "logging/rtc_event_log/events/rtc_event_audio_network_adaptation.h" >+#include "logging/rtc_event_log/events/rtc_event_audio_playout.h" >+#include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" >+#include "logging/rtc_event_log/events/rtc_event_audio_send_stream_config.h" >+#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h" >+#include "logging/rtc_event_log/events/rtc_event_bwe_update_loss_based.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair.h" >+#include "logging/rtc_event_log/events/rtc_event_ice_candidate_pair_config.h" >+#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" >+#include "logging/rtc_event_log/events/rtc_event_probe_result_failure.h" >+#include "logging/rtc_event_log/events/rtc_event_probe_result_success.h" >+#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_incoming.h" >+#include "logging/rtc_event_log/events/rtc_event_rtcp_packet_outgoing.h" >+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_incoming.h" >+#include "logging/rtc_event_log/events/rtc_event_rtp_packet_outgoing.h" >+#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h" >+#include "logging/rtc_event_log/events/rtc_event_video_send_stream_config.h" >+#include "logging/rtc_event_log/rtc_event_log_parser_new.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/receiver_report.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h" >+#include "modules/rtp_rtcp/source/rtcp_packet/sender_report.h" >+#include "rtc_base/random.h" > > namespace webrtc { > >-class RtcEventLogTestHelper { >+namespace test { >+ >+class EventGenerator { > public: >- static void VerifyVideoReceiveStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config); >- static void VerifyVideoSendStreamConfig(const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config); >- static void VerifyAudioReceiveStreamConfig( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config); >- static void VerifyAudioSendStreamConfig(const ParsedRtcEventLog& parsed_log, >- size_t index, >- const rtclog::StreamConfig& config); >- static void VerifyIncomingRtpEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- const RtpPacketReceived& expected_packet); >- static void VerifyOutgoingRtpEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- const RtpPacketToSend& expected_packet); >- static void VerifyRtcpEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- PacketDirection direction, >- const uint8_t* packet, >- size_t total_size); >- static void VerifyPlayoutEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t ssrc); >- static void VerifyBweLossEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- int32_t bitrate, >- uint8_t fraction_loss, >- int32_t total_packets); >- static void VerifyBweDelayEvent(const ParsedRtcEventLog& parsed_log, >- size_t index, >- int32_t bitrate, >- BandwidthUsage detector_state); >- >- static void VerifyAudioNetworkAdaptation( >- const ParsedRtcEventLog& parsed_log, >- size_t index, >- const AudioEncoderRuntimeConfig& config); >- >- static void VerifyLogStartEvent(const ParsedRtcEventLog& parsed_log, >- size_t index); >- static void VerifyLogEndEvent(const ParsedRtcEventLog& parsed_log, >- size_t index); >- >- static void VerifyBweProbeCluster(const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- uint32_t bitrate_bps, >- uint32_t min_probes, >- uint32_t min_bytes); >- >- static void VerifyProbeResultSuccess(const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- uint32_t bitrate_bps); >- >- static void VerifyProbeResultFailure(const ParsedRtcEventLog& parsed_log, >- size_t index, >- uint32_t id, >- ProbeFailureReason failure_reason); >+ explicit EventGenerator(uint64_t seed) : prng_(seed) {} >+ >+ std::unique_ptr<RtcEventAlrState> NewAlrState(); >+ >+ std::unique_ptr<RtcEventAudioPlayout> NewAudioPlayout(uint32_t ssrc); >+ >+ std::unique_ptr<RtcEventAudioNetworkAdaptation> NewAudioNetworkAdaptation(); >+ >+ std::unique_ptr<RtcEventBweUpdateDelayBased> NewBweUpdateDelayBased(); >+ >+ std::unique_ptr<RtcEventBweUpdateLossBased> NewBweUpdateLossBased(); >+ >+ std::unique_ptr<RtcEventProbeClusterCreated> NewProbeClusterCreated(); >+ >+ std::unique_ptr<RtcEventProbeResultFailure> NewProbeResultFailure(); >+ >+ std::unique_ptr<RtcEventProbeResultSuccess> NewProbeResultSuccess(); >+ >+ std::unique_ptr<RtcEventIceCandidatePairConfig> NewIceCandidatePairConfig(); >+ >+ std::unique_ptr<RtcEventIceCandidatePair> NewIceCandidatePair(); >+ >+ std::unique_ptr<RtcEventRtcpPacketIncoming> NewRtcpPacketIncoming(); >+ >+ std::unique_ptr<RtcEventRtcpPacketOutgoing> NewRtcpPacketOutgoing(); >+ >+ void RandomizeRtpPacket(size_t packet_size, >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map, >+ RtpPacket* rtp_packet); >+ >+ std::unique_ptr<RtcEventRtpPacketIncoming> NewRtpPacketIncoming( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map); >+ >+ std::unique_ptr<RtcEventRtpPacketOutgoing> NewRtpPacketOutgoing( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extension_map); >+ >+ RtpHeaderExtensionMap NewRtpHeaderExtensionMap(); >+ >+ std::unique_ptr<RtcEventAudioReceiveStreamConfig> NewAudioReceiveStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions); >+ >+ std::unique_ptr<RtcEventAudioSendStreamConfig> NewAudioSendStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions); >+ >+ std::unique_ptr<RtcEventVideoReceiveStreamConfig> NewVideoReceiveStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions); >+ >+ std::unique_ptr<RtcEventVideoSendStreamConfig> NewVideoSendStreamConfig( >+ uint32_t ssrc, >+ const RtpHeaderExtensionMap& extensions); >+ >+ private: >+ rtcp::ReportBlock NewReportBlock(); >+ rtcp::SenderReport NewSenderReport(); >+ rtcp::ReceiverReport NewReceiverReport(); >+ >+ Random prng_; > }; > >+bool VerifyLoggedAlrStateEvent(const RtcEventAlrState& original_event, >+ const LoggedAlrStateEvent& logged_event); >+ >+bool VerifyLoggedAudioPlayoutEvent(const RtcEventAudioPlayout& original_event, >+ const LoggedAudioPlayoutEvent& logged_event); >+ >+bool VerifyLoggedAudioNetworkAdaptationEvent( >+ const RtcEventAudioNetworkAdaptation& original_event, >+ const LoggedAudioNetworkAdaptationEvent& logged_event); >+ >+bool VerifyLoggedBweDelayBasedUpdate( >+ const RtcEventBweUpdateDelayBased& original_event, >+ const LoggedBweDelayBasedUpdate& logged_event); >+ >+bool VerifyLoggedBweLossBasedUpdate( >+ const RtcEventBweUpdateLossBased& original_event, >+ const LoggedBweLossBasedUpdate& logged_event); >+ >+bool VerifyLoggedBweProbeClusterCreatedEvent( >+ const RtcEventProbeClusterCreated& original_event, >+ const LoggedBweProbeClusterCreatedEvent& logged_event); >+ >+bool VerifyLoggedBweProbeFailureEvent( >+ const RtcEventProbeResultFailure& original_event, >+ const LoggedBweProbeFailureEvent& logged_event); >+ >+bool VerifyLoggedBweProbeSuccessEvent( >+ const RtcEventProbeResultSuccess& original_event, >+ const LoggedBweProbeSuccessEvent& logged_event); >+ >+bool VerifyLoggedIceCandidatePairConfig( >+ const RtcEventIceCandidatePairConfig& original_event, >+ const LoggedIceCandidatePairConfig& logged_event); >+ >+bool VerifyLoggedIceCandidatePairEvent( >+ const RtcEventIceCandidatePair& original_event, >+ const LoggedIceCandidatePairEvent& logged_event); >+ >+bool VerifyLoggedRtpPacketIncoming( >+ const RtcEventRtpPacketIncoming& original_event, >+ const LoggedRtpPacketIncoming& logged_event); >+ >+bool VerifyLoggedRtpPacketOutgoing( >+ const RtcEventRtpPacketOutgoing& original_event, >+ const LoggedRtpPacketOutgoing& logged_event); >+ >+bool VerifyLoggedRtcpPacketIncoming( >+ const RtcEventRtcpPacketIncoming& original_event, >+ const LoggedRtcpPacketIncoming& logged_event); >+ >+bool VerifyLoggedRtcpPacketOutgoing( >+ const RtcEventRtcpPacketOutgoing& original_event, >+ const LoggedRtcpPacketOutgoing& logged_event); >+ >+bool VerifyLoggedStartEvent(int64_t start_time_us, >+ const LoggedStartEvent& logged_event); >+bool VerifyLoggedStopEvent(int64_t stop_time_us, >+ const LoggedStopEvent& logged_event); >+ >+bool VerifyLoggedAudioRecvConfig( >+ const RtcEventAudioReceiveStreamConfig& original_event, >+ const LoggedAudioRecvConfig& logged_event); >+ >+bool VerifyLoggedAudioSendConfig( >+ const RtcEventAudioSendStreamConfig& original_event, >+ const LoggedAudioSendConfig& logged_event); >+ >+bool VerifyLoggedVideoRecvConfig( >+ const RtcEventVideoReceiveStreamConfig& original_event, >+ const LoggedVideoRecvConfig& logged_event); >+ >+bool VerifyLoggedVideoSendConfig( >+ const RtcEventVideoSendStreamConfig& original_event, >+ const LoggedVideoSendConfig& logged_event); >+ >+} // namespace test > } // namespace webrtc > > #endif // LOGGING_RTC_EVENT_LOG_RTC_EVENT_LOG_UNITTEST_HELPER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.cc >index b43c6dd6f36..d4d30d00bc5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.cc >@@ -17,6 +17,8 @@ StreamConfig::StreamConfig() {} > > StreamConfig::~StreamConfig() {} > >+StreamConfig::StreamConfig(const StreamConfig& other) = default; >+ > bool StreamConfig::operator==(const StreamConfig& other) const { > return local_ssrc == other.local_ssrc && remote_ssrc == other.remote_ssrc && > rtx_ssrc == other.rtx_ssrc && rsid == other.rsid && >@@ -24,12 +26,16 @@ bool StreamConfig::operator==(const StreamConfig& other) const { > rtp_extensions == other.rtp_extensions && codecs == other.codecs; > } > >+bool StreamConfig::operator!=(const StreamConfig& other) const { >+ return !(*this == other); >+} >+ > StreamConfig::Codec::Codec(const std::string& payload_name, > int payload_type, > int rtx_payload_type) >- : payload_name(payload_name), >- payload_type(payload_type), >- rtx_payload_type(rtx_payload_type) {} >+ : payload_name(payload_name), >+ payload_type(payload_type), >+ rtx_payload_type(rtx_payload_type) {} > > bool StreamConfig::Codec::operator==(const Codec& other) const { > return payload_name == other.payload_name && >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.h b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.h >index 771ba66c6a4..d95c8359ece 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/logging/rtc_event_log/rtc_stream_config.h >@@ -23,9 +23,11 @@ namespace rtclog { > > struct StreamConfig { > StreamConfig(); >+ StreamConfig(const StreamConfig& other); > ~StreamConfig(); > > bool operator==(const StreamConfig& other) const; >+ bool operator!=(const StreamConfig& other) const; > > uint32_t local_ssrc = 0; > uint32_t remote_ssrc = 0; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/BUILD.gn b/Source/ThirdParty/libwebrtc/Source/webrtc/media/BUILD.gn >index 0dc20b4acb6..3042ac2a865 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/BUILD.gn >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/BUILD.gn >@@ -26,15 +26,6 @@ config("rtc_media_defines_config") { > ] > } > >-config("rtc_media_warnings_config") { >- # GN orders flags on a target before flags from configs. The default config >- # adds these flags so to cancel them out they need to come from a config and >- # cannot be on the target directly. >- if (!is_win) { >- cflags = [ "-Wno-deprecated-declarations" ] >- } >-} >- > rtc_source_set("rtc_h264_profile_id") { > visibility = [ "*" ] > sources = [ >@@ -49,9 +40,30 @@ rtc_source_set("rtc_h264_profile_id") { > > deps = [ > "..:webrtc_common", >- "../api:optional", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", >+ ] >+} >+ >+rtc_source_set("rtc_media_config") { >+ visibility = [ "*" ] >+ sources = [ >+ "base/mediaconfig.h", >+ ] >+} >+ >+rtc_source_set("rtc_vp9_profile") { >+ sources = [ >+ "base/vp9_profile.cc", >+ "base/vp9_profile.h", >+ ] >+ >+ deps = [ >+ "..:webrtc_common", >+ "../api/video_codecs:video_codecs_api", >+ "../rtc_base:rtc_base_approved", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > >@@ -60,8 +72,12 @@ rtc_static_library("rtc_media_base") { > defines = [] > libs = [] > deps = [ >+ "../api:audio_options_api", > "../rtc_base:checks", >+ "../rtc_base:rtc_base_approved", >+ "../rtc_base:rtc_task_queue", > "../rtc_base:sanitizer", >+ "../rtc_base:sequenced_task_checker", > "../rtc_base:stringutils", > ] > sources = [ >@@ -72,6 +88,7 @@ rtc_static_library("rtc_media_base") { > "base/codec.h", > "base/cryptoparams.h", > "base/device.h", >+ "base/mediachannel.cc", > "base/mediachannel.h", > "base/mediaconstants.cc", > "base/mediaconstants.h", >@@ -105,20 +122,22 @@ rtc_static_library("rtc_media_base") { > > deps += [ > ":rtc_h264_profile_id", >+ ":rtc_media_config", >+ ":rtc_vp9_profile", > "..:webrtc_common", > "../api:libjingle_peerconnection_api", >- "../api:optional", >- "../api:video_frame_api", >- "../api:video_frame_api_i420", > "../api/audio_codecs:audio_codecs_api", >+ "../api/video:video_frame", >+ "../api/video:video_frame_i420", > "../api/video_codecs:video_codecs_api", > "../call:call_interfaces", >- "../call:video_stream_api", > "../common_video", > "../modules/audio_processing:audio_processing_statistics", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/third_party/sigslot", > "../system_wrappers:field_trial_api", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > > if (!build_with_mozilla) { >@@ -142,11 +161,13 @@ rtc_static_library("rtc_constants") { > > rtc_static_library("rtc_internal_video_codecs") { > visibility = [ "*" ] >+ allow_poison = [ "software_video_codecs" ] > defines = [] > libs = [] > deps = [ > ":rtc_h264_profile_id", > "../modules/video_coding:video_codec_interface", >+ "//third_party/abseil-cpp/absl/memory", > ] > sources = [ > "engine/convert_legacy_video_factory.cc", >@@ -155,43 +176,25 @@ rtc_static_library("rtc_internal_video_codecs") { > "engine/internaldecoderfactory.h", > "engine/internalencoderfactory.cc", > "engine/internalencoderfactory.h", >+ "engine/multiplexcodecfactory.cc", >+ "engine/multiplexcodecfactory.h", > "engine/scopedvideodecoder.cc", > "engine/scopedvideodecoder.h", > "engine/scopedvideoencoder.cc", > "engine/scopedvideoencoder.h", >- "engine/simulcast.cc", >- "engine/simulcast.h", > "engine/simulcast_encoder_adapter.cc", > "engine/simulcast_encoder_adapter.h", >- "engine/stereocodecfactory.cc", >- "engine/stereocodecfactory.h", >- "engine/videodecodersoftwarefallbackwrapper.cc", >- "engine/videodecodersoftwarefallbackwrapper.h", >- "engine/videoencodersoftwarefallbackwrapper.cc", >- "engine/videoencodersoftwarefallbackwrapper.h", > "engine/vp8_encoder_simulcast_proxy.cc", > "engine/vp8_encoder_simulcast_proxy.h", >- "engine/webrtcvideodecoderfactory.cc", > "engine/webrtcvideodecoderfactory.h", >- "engine/webrtcvideoencoderfactory.cc", > "engine/webrtcvideoencoderfactory.h", > ] > >- configs += [ ":rtc_media_warnings_config" ] >- > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > >- if (is_win) { >- cflags = [ >- "/wd4245", # conversion from "int" to "size_t", signed/unsigned mismatch. >- "/wd4267", # conversion from "size_t" to "int", possible loss of data. >- "/wd4389", # signed/unsigned mismatch. >- ] >- } >- > include_dirs = [] > > public_configs = [] >@@ -199,14 +202,16 @@ rtc_static_library("rtc_internal_video_codecs") { > ":rtc_constants", > ":rtc_media_base", > "..:webrtc_common", >- "../api:video_frame_api_i420", >+ "../api/video:video_bitrate_allocation", >+ "../api/video:video_frame_i420", >+ "../api/video_codecs:rtc_software_fallback_wrappers", > "../api/video_codecs:video_codecs_api", > "../call:call_interfaces", > "../call:video_stream_api", >+ "../modules/video_coding:video_coding_utility", > "../modules/video_coding:webrtc_h264", >- "../modules/video_coding:webrtc_stereo", >+ "../modules/video_coding:webrtc_multiplex", > "../modules/video_coding:webrtc_vp8", >- "../modules/video_coding:webrtc_vp8_helpers", > "../modules/video_coding:webrtc_vp9", > "../rtc_base:checks", > "../rtc_base:rtc_base_approved", >@@ -220,12 +225,20 @@ rtc_static_library("rtc_internal_video_codecs") { > > rtc_static_library("rtc_audio_video") { > visibility = [ "*" ] >+ allow_poison = [ >+ "audio_codecs", # TODO(bugs.webrtc.org/8396): Remove. >+ "software_video_codecs", # TODO(bugs.webrtc.org/7925): Remove. >+ ] > defines = [] > libs = [] > deps = [ >+ "../modules/audio_processing/aec_dump:aec_dump", > "../modules/video_coding:video_codec_interface", > "../modules/video_coding:video_coding", >+ "../modules/video_coding:video_coding_utility", >+ "../rtc_base:audio_format_to_string", > "../rtc_base:checks", >+ "../rtc_base/third_party/base64", > ] > > sources = [ >@@ -236,33 +249,29 @@ rtc_static_library("rtc_audio_video") { > "engine/nullwebrtcvideoengine.h", > "engine/payload_type_mapper.cc", > "engine/payload_type_mapper.h", >+ "engine/simulcast.cc", >+ "engine/simulcast.h", > "engine/webrtcmediaengine.cc", > "engine/webrtcmediaengine.h", > "engine/webrtcvideocapturer.cc", > "engine/webrtcvideocapturer.h", > "engine/webrtcvideocapturerfactory.cc", > "engine/webrtcvideocapturerfactory.h", >+ "engine/webrtcvideodecoderfactory.cc", >+ "engine/webrtcvideodecoderfactory.h", >+ "engine/webrtcvideoencoderfactory.cc", >+ "engine/webrtcvideoencoderfactory.h", > "engine/webrtcvideoengine.cc", > "engine/webrtcvideoengine.h", > "engine/webrtcvoiceengine.cc", > "engine/webrtcvoiceengine.h", > ] > >- configs += [ ":rtc_media_warnings_config" ] >- > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > >- if (is_win) { >- cflags = [ >- "/wd4245", # conversion from "int" to "size_t", signed/unsigned mismatch. >- "/wd4267", # conversion from "size_t" to "int", possible loss of data. >- "/wd4389", # signed/unsigned mismatch. >- ] >- } >- > if (rtc_enable_intelligibility_enhancer) { > defines += [ "WEBRTC_INTELLIGIBILITY_ENHANCER=1" ] > } else { >@@ -289,24 +298,27 @@ rtc_static_library("rtc_audio_video") { > } else { > deps += [ "../modules/audio_processing/aec_dump:null_aec_dump_factory" ] > } >+ if (rtc_use_builtin_sw_codecs) { >+ deps += [ ":rtc_internal_video_codecs" ] >+ } > deps += [ > ":rtc_constants", >- ":rtc_internal_video_codecs", > ":rtc_media_base", > "..:webrtc_common", > "../api:call_api", > "../api:libjingle_peerconnection_api", >- "../api:optional", > "../api:transport_api", >- "../api:video_frame_api", >- "../api:video_frame_api_i420", > "../api/audio_codecs:audio_codecs_api", >+ "../api/video:video_frame", >+ "../api/video:video_frame_i420", >+ "../api/video_codecs:rtc_software_fallback_wrappers", > "../api/video_codecs:video_codecs_api", > "../call", > "../call:call_interfaces", > "../call:video_stream_api", > "../common_video:common_video", > "../modules/audio_device:audio_device", >+ "../modules/audio_device:audio_device_impl", > "../modules/audio_mixer:audio_mixer_impl", > "../modules/audio_processing:audio_processing", > "../modules/video_capture:video_capture_module", >@@ -317,7 +329,7 @@ rtc_static_library("rtc_audio_video") { > "../system_wrappers", > "../system_wrappers:field_trial_api", > "../system_wrappers:metrics_api", >- "../voice_engine", >+ "//third_party/abseil-cpp/absl/types:optional", > ] > } > >@@ -338,21 +350,11 @@ rtc_static_library("rtc_data") { > ] > } > >- configs += [ ":rtc_media_warnings_config" ] >- > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > >- if (is_win) { >- cflags = [ >- "/wd4245", # conversion from "int" to "size_t", signed/unsigned mismatch. >- "/wd4267", # conversion from "size_t" to "int", possible loss of data. >- "/wd4389", # signed/unsigned mismatch. >- ] >- } >- > if (rtc_enable_sctp && rtc_build_usrsctp) { > include_dirs = [ > # TODO(jiayl): move this into the public_configs of >@@ -370,12 +372,17 @@ rtc_static_library("rtc_data") { > "../p2p:rtc_p2p", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >+ "../rtc_base/third_party/sigslot", > "../system_wrappers", > ] > } > > rtc_source_set("rtc_media") { > visibility = [ "*" ] >+ allow_poison = [ >+ "audio_codecs", # TODO(bugs.webrtc.org/8396): Remove. >+ "software_video_codecs", # TODO(bugs.webrtc.org/7925): Remove. >+ ] > deps = [ > ":rtc_audio_video", > ":rtc_data", >@@ -383,23 +390,15 @@ rtc_source_set("rtc_media") { > } > > if (rtc_include_tests) { >- config("rtc_unittest_main_config") { >- # GN orders flags on a target before flags from configs. The default config >- # adds -Wall, and this flag have to be after -Wall -- so they need to >- # come from a config and can"t be on the target directly. >- if (is_clang && is_ios) { >- cflags = [ "-Wno-unused-variable" ] >- } >- } >- > rtc_source_set("rtc_media_tests_utils") { > testonly = true > >+ defines = [] > include_dirs = [] > deps = [ > ":rtc_audio_video", > "../api:libjingle_peerconnection_api", >- "../api:video_frame_api_i420", >+ "../api/video:video_frame_i420", > "../call:video_stream_api", > "../common_video:common_video", > "../modules/audio_coding:rent_a_codec", >@@ -409,16 +408,21 @@ if (rtc_include_tests) { > "../modules/video_coding:video_coding_utility", > "../p2p:rtc_p2p", > "../rtc_base:checks", >+ "../rtc_base:rtc_task_queue", > "../rtc_base:stringutils", >+ "//third_party/abseil-cpp/absl/memory", > ] > sources = [ >+ "base/fakeframesource.cc", >+ "base/fakeframesource.h", > "base/fakemediaengine.h", > "base/fakenetworkinterface.h", > "base/fakertp.cc", > "base/fakertp.h", >+ "base/fakevideocapturer.cc", > "base/fakevideocapturer.h", >+ "base/fakevideorenderer.cc", > "base/fakevideorenderer.h", >- "base/test/mock_mediachannel.h", > "base/testutils.cc", > "base/testutils.h", > "engine/fakewebrtccall.cc", >@@ -426,52 +430,40 @@ if (rtc_include_tests) { > "engine/fakewebrtcdeviceinfo.h", > "engine/fakewebrtcvcmfactory.h", > "engine/fakewebrtcvideocapturemodule.h", >+ "engine/fakewebrtcvideoengine.cc", > "engine/fakewebrtcvideoengine.h", > ] > >- configs += [ ":rtc_unittest_main_config" ] >- > if (!build_with_chromium && is_clang) { > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] > } > >+ if (rtc_use_h264) { >+ defines += [ "WEBRTC_USE_H264" ] >+ } >+ > deps += [ > ":rtc_internal_video_codecs", > ":rtc_media", > ":rtc_media_base", > "..:webrtc_common", > "../api:call_api", >- "../api:video_frame_api", >+ "../api/video:video_bitrate_allocation", >+ "../api/video:video_frame", > "../api/video_codecs:video_codecs_api", > "../call:call_interfaces", >+ "../call:mock_rtp_interfaces", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", > "../rtc_base:rtc_base_tests_utils", >+ "../rtc_base:rtc_task_queue_for_test", >+ "../rtc_base/third_party/sigslot", > "../test:test_support", >- "//testing/gmock", > "//testing/gtest", > ] > } > >- config("rtc_media_unittests_config") { >- # GN orders flags on a target before flags from configs. The default config >- # adds -Wall, and this flag have to be after -Wall -- so they need to >- # come from a config and can"t be on the target directly. >- # TODO(kjellander): Make the code compile without disabling these flags. >- # See https://bugs.webrtc.org/3307. >- if (is_clang && is_win) { >- cflags = [ >- # See https://bugs.chromium.org/p/webrtc/issues/detail?id=6266 >- # for -Wno-sign-compare >- "-Wno-sign-compare", >- ] >- } >- if (!is_win) { >- cflags = [ "-Wno-sign-compare" ] >- } >- } >- > rtc_media_unittests_resources = [ > "../resources/media/captured-320x240-2s-48.frames", > "../resources/media/faces.1280x720_P420.yuv", >@@ -500,14 +492,19 @@ if (rtc_include_tests) { > ":rtc_audio_video", > ":rtc_constants", > ":rtc_data", >- "../api:video_frame_api_i420", >+ "../api/video:video_frame_i420", > "../modules/audio_processing:mocks", >+ "../modules/rtp_rtcp", > "../modules/video_coding:video_codec_interface", >+ "../modules/video_coding:webrtc_vp8", > "../pc:rtc_pc", > "../pc:rtc_pc_base", > "../rtc_base:checks", >+ "../rtc_base:rtc_task_queue", > "../rtc_base:stringutils", > "../test:field_trial", >+ "../test:test_common", >+ "//third_party/abseil-cpp/absl/memory", > ] > sources = [ > "base/codec_unittest.cc", >@@ -519,16 +516,13 @@ if (rtc_include_tests) { > "base/videobroadcaster_unittest.cc", > "base/videocapturer_unittest.cc", > "base/videocommon_unittest.cc", >- "base/videoengine_unittest.h", > "engine/apm_helpers_unittest.cc", > "engine/internaldecoderfactory_unittest.cc", >+ "engine/multiplexcodecfactory_unittest.cc", > "engine/nullwebrtcvideoengine_unittest.cc", > "engine/payload_type_mapper_unittest.cc", > "engine/simulcast_encoder_adapter_unittest.cc", > "engine/simulcast_unittest.cc", >- "engine/stereocodecfactory_unittest.cc", >- "engine/videodecodersoftwarefallbackwrapper_unittest.cc", >- "engine/videoencodersoftwarefallbackwrapper_unittest.cc", > "engine/vp8_encoder_simulcast_proxy_unittest.cc", > "engine/webrtcmediaengine_unittest.cc", > "engine/webrtcvideocapturer_unittest.cc", >@@ -546,8 +540,6 @@ if (rtc_include_tests) { > sources += [ "sctp/sctptransport_unittest.cc" ] > } > >- configs += [ ":rtc_media_unittests_config" ] >- > if (rtc_use_h264) { > defines += [ "WEBRTC_USE_H264" ] > } >@@ -558,18 +550,8 @@ if (rtc_include_tests) { > defines += [ "WEBRTC_OPUS_SUPPORT_120MS_PTIME=0" ] > } > >- if (is_win) { >- cflags = [ >- "/wd4245", # conversion from int to size_t, signed/unsigned mismatch. >- "/wd4373", # virtual function override. >- "/wd4389", # signed/unsigned mismatch. >- ] >- } >- > if (!build_with_chromium && is_clang) { > suppressed_configs += [ >- "//build/config/clang:extra_warnings", >- > # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). > "//build/config/clang:find_bad_constructs", > ] >@@ -591,22 +573,26 @@ if (rtc_include_tests) { > ":rtc_media", > ":rtc_media_base", > ":rtc_media_tests_utils", >+ ":rtc_vp9_profile", >+ "../api:create_simulcast_test_fixture_api", > "../api:libjingle_peerconnection_api", > "../api:mock_video_codec_factory", >- "../api:video_frame_api", >+ "../api:simulcast_test_fixture_api", > "../api/audio_codecs:builtin_audio_decoder_factory", > "../api/audio_codecs:builtin_audio_encoder_factory", >+ "../api/video:video_bitrate_allocation", >+ "../api/video:video_frame", >+ "../api/video_codecs:builtin_video_decoder_factory", >+ "../api/video_codecs:builtin_video_encoder_factory", > "../api/video_codecs:video_codecs_api", > "../audio", > "../call:call_interfaces", > "../common_video:common_video", > "../logging:rtc_event_log_api", >+ "../logging:rtc_event_log_impl_base", > "../modules/audio_device:mock_audio_device", > "../modules/audio_processing:audio_processing", >- "../modules/video_coding:simulcast_test_utility", >- "../modules/video_coding:video_coding_utility", >- "../modules/video_coding:webrtc_vp8", >- "../modules/video_coding:webrtc_vp8_helpers", >+ "../modules/video_coding:simulcast_test_fixture_impl", > "../p2p:p2p_test_utils", > "../rtc_base:rtc_base", > "../rtc_base:rtc_base_approved", >@@ -617,7 +603,6 @@ if (rtc_include_tests) { > "../test:audio_codec_mocks", > "../test:test_support", > "../test:video_test_common", >- "../voice_engine:voice_engine", > ] > } > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/DEPS b/Source/ThirdParty/libwebrtc/Source/webrtc/media/DEPS >index 7a266a23faf..ab54b440369 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/DEPS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/DEPS >@@ -10,11 +10,11 @@ include_rules = [ > "+modules/rtp_rtcp", > "+modules/video_capture", > "+modules/video_coding", >+ "+modules/video_coding/utility", > "+p2p", > "+pc", > "+sound", > "+system_wrappers", >- "+voice_engine", > "+usrsctplib", > "+third_party/libyuv", > ] >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/media/OWNERS >index bf977f493e7..2688b07b00d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/OWNERS >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/OWNERS >@@ -3,7 +3,6 @@ mflodman@webrtc.org > perkj@webrtc.org > pthatcher@webrtc.org > solenberg@webrtc.org >-deadbeef@webrtc.org > > # These are for the common case of adding or renaming files. If you're doing > # structural changes, please get a review from a reviewer in this file. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.cc >index 5a7168bfb86..11952770a46 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.cc >@@ -22,6 +22,7 @@ AdaptedVideoTrackSource::AdaptedVideoTrackSource(int required_alignment) > : video_adapter_(required_alignment) { > thread_checker_.DetachFromThread(); > } >+AdaptedVideoTrackSource::~AdaptedVideoTrackSource() = default; > > bool AdaptedVideoTrackSource::GetStats(Stats* stats) { > rtc::CritScope lock(&stats_crit_); >@@ -103,8 +104,8 @@ bool AdaptedVideoTrackSource::AdaptFrame(int width, > } > > if (!video_adapter_.AdaptFrameResolution( >- width, height, time_us * rtc::kNumNanosecsPerMicrosec, >- crop_width, crop_height, out_width, out_height)) { >+ width, height, time_us * rtc::kNumNanosecsPerMicrosec, crop_width, >+ crop_height, out_width, out_height)) { > broadcaster_.OnDiscardedFrame(); > // VideoAdapter dropped the frame. > return false; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.h >index 0db381f5fbc..7e7ba7eeed1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/adaptedvideotracksource.h >@@ -26,6 +26,7 @@ class AdaptedVideoTrackSource > : public webrtc::Notifier<webrtc::VideoTrackSourceInterface> { > public: > AdaptedVideoTrackSource(); >+ ~AdaptedVideoTrackSource() override; > > protected: > // Allows derived classes to initialize |video_adapter_| with a custom >@@ -74,7 +75,7 @@ class AdaptedVideoTrackSource > cricket::VideoAdapter video_adapter_; > > rtc::CriticalSection stats_crit_; >- rtc::Optional<Stats> stats_ RTC_GUARDED_BY(stats_crit_); >+ absl::optional<Stats> stats_ RTC_GUARDED_BY(stats_crit_); > > VideoBroadcaster broadcaster_; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.cc >index 98e52d68489..ee7eda343b3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.cc >@@ -11,21 +11,23 @@ > #include "media/base/codec.h" > > #include <algorithm> >-#include <sstream> > > #include "media/base/h264_profile_level_id.h" >+#include "media/base/vp9_profile.h" > #include "rtc_base/checks.h" > #include "rtc_base/logging.h" > #include "rtc_base/stringencode.h" >+#include "rtc_base/strings/string_builder.h" > #include "rtc_base/stringutils.h" > > namespace cricket { > > FeedbackParams::FeedbackParams() = default; >+FeedbackParams::~FeedbackParams() = default; > > bool FeedbackParam::operator==(const FeedbackParam& other) const { > return _stricmp(other.id().c_str(), id().c_str()) == 0 && >- _stricmp(other.param().c_str(), param().c_str()) == 0; >+ _stricmp(other.param().c_str(), param().c_str()) == 0; > } > > bool FeedbackParams::operator==(const FeedbackParams& other) const { >@@ -117,7 +119,7 @@ void Codec::SetParam(const std::string& name, const std::string& value) { > params[name] = value; > } > >-void Codec::SetParam(const std::string& name, int value) { >+void Codec::SetParam(const std::string& name, int value) { > params[name] = rtc::ToString(value); > } > >@@ -142,6 +144,7 @@ webrtc::RtpCodecParameters Codec::ToCodecParameters() const { > codec_params.payload_type = id; > codec_params.name = name; > codec_params.clock_rate = clockrate; >+ codec_params.parameters.insert(params.begin(), params.end()); > return codec_params; > } > >@@ -152,8 +155,7 @@ AudioCodec::AudioCodec(int id, > size_t channels) > : Codec(id, name, clockrate), bitrate(bitrate), channels(channels) {} > >-AudioCodec::AudioCodec() : Codec(), bitrate(0), channels(0) { >-} >+AudioCodec::AudioCodec() : Codec(), bitrate(0), channels(0) {} > > AudioCodec::AudioCodec(const AudioCodec& c) = default; > AudioCodec::AudioCodec(AudioCodec&& c) = default; >@@ -175,17 +177,18 @@ bool AudioCodec::Matches(const AudioCodec& codec) const { > // Preference is ignored. > // TODO(juberti): Treat a zero clockrate as 8000Hz, the RTP default clockrate. > return Codec::Matches(codec) && >- ((codec.clockrate == 0 /*&& clockrate == 8000*/) || >+ ((codec.clockrate == 0 /*&& clockrate == 8000*/) || > clockrate == codec.clockrate) && >- (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) && >- ((codec.channels < 2 && channels < 2) || channels == codec.channels); >+ (codec.bitrate == 0 || bitrate <= 0 || bitrate == codec.bitrate) && >+ ((codec.channels < 2 && channels < 2) || channels == codec.channels); > } > > std::string AudioCodec::ToString() const { >- std::ostringstream os; >- os << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate >+ char buf[256]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "AudioCodec[" << id << ":" << name << ":" << clockrate << ":" << bitrate > << ":" << channels << "]"; >- return os.str(); >+ return sb.str(); > } > > webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const { >@@ -196,9 +199,10 @@ webrtc::RtpCodecParameters AudioCodec::ToCodecParameters() const { > } > > std::string VideoCodec::ToString() const { >- std::ostringstream os; >- os << "VideoCodec[" << id << ":" << name << "]"; >- return os.str(); >+ char buf[256]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "VideoCodec[" << id << ":" << name << "]"; >+ return sb.str(); > } > > webrtc::RtpCodecParameters VideoCodec::ToCodecParameters() const { >@@ -244,11 +248,33 @@ bool VideoCodec::operator==(const VideoCodec& c) const { > return Codec::operator==(c); > } > >+static bool IsSameH264PacketizationMode(const CodecParameterMap& ours, >+ const CodecParameterMap& theirs) { >+ // If packetization-mode is not present, default to "0". >+ // https://tools.ietf.org/html/rfc6184#section-6.2 >+ std::string our_packetization_mode = "0"; >+ std::string their_packetization_mode = "0"; >+ auto ours_it = ours.find(kH264FmtpPacketizationMode); >+ if (ours_it != ours.end()) { >+ our_packetization_mode = ours_it->second; >+ } >+ auto theirs_it = theirs.find(kH264FmtpPacketizationMode); >+ if (theirs_it != theirs.end()) { >+ their_packetization_mode = theirs_it->second; >+ } >+ return our_packetization_mode == their_packetization_mode; >+} >+ > bool VideoCodec::Matches(const VideoCodec& other) const { > if (!Codec::Matches(other)) > return false; > if (CodecNamesEq(name.c_str(), kH264CodecName)) >- return webrtc::H264::IsSameH264Profile(params, other.params); >+ return webrtc::H264::IsSameH264Profile(params, other.params) && >+ IsSameH264PacketizationMode(params, other.params); >+#if !defined(RTC_DISABLE_VP9) >+ if (CodecNamesEq(name.c_str(), kVp9CodecName)) >+ return webrtc::IsSameVP9Profile(params, other.params); >+#endif > return true; > } > >@@ -312,9 +338,10 @@ DataCodec& DataCodec::operator=(const DataCodec& c) = default; > DataCodec& DataCodec::operator=(DataCodec&& c) = default; > > std::string DataCodec::ToString() const { >- std::ostringstream os; >- os << "DataCodec[" << id << ":" << name << "]"; >- return os.str(); >+ char buf[256]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "DataCodec[" << id << ":" << name << "]"; >+ return sb.str(); > } > > bool HasNack(const Codec& codec) { >@@ -327,6 +354,11 @@ bool HasRemb(const Codec& codec) { > FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); > } > >+bool HasRrtr(const Codec& codec) { >+ return codec.HasFeedbackParam( >+ FeedbackParam(kRtcpFbParamRrtr, kParamValueEmpty)); >+} >+ > bool HasTransportCc(const Codec& codec) { > return codec.HasFeedbackParam( > FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); >@@ -359,9 +391,14 @@ bool IsSameCodec(const std::string& name1, > // If different names (case insensitive), then not same formats. > if (!CodecNamesEq(name1, name2)) > return false; >- // For every format besides H264, comparing names is enough. >- return !CodecNamesEq(name1.c_str(), kH264CodecName) || >- webrtc::H264::IsSameH264Profile(params1, params2); >+ // For every format besides H264 and VP9, comparing names is enough. >+ if (CodecNamesEq(name1.c_str(), kH264CodecName)) >+ return webrtc::H264::IsSameH264Profile(params1, params2); >+#if !defined(RTC_DISABLE_VP9) >+ if (CodecNamesEq(name1.c_str(), kVp9CodecName)) >+ return webrtc::IsSameVP9Profile(params1, params2); >+#endif >+ return true; > } > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.h >index 6a2dcf4529e..db133f6e27f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec.h >@@ -29,26 +29,24 @@ class FeedbackParam { > public: > FeedbackParam() = default; > FeedbackParam(const std::string& id, const std::string& param) >- : id_(id), >- param_(param) { >- } >+ : id_(id), param_(param) {} > explicit FeedbackParam(const std::string& id) >- : id_(id), >- param_(kParamValueEmpty) { >- } >+ : id_(id), param_(kParamValueEmpty) {} >+ > bool operator==(const FeedbackParam& other) const; > > const std::string& id() const { return id_; } > const std::string& param() const { return param_; } > > private: >- std::string id_; // e.g. "nack", "ccm" >+ std::string id_; // e.g. "nack", "ccm" > std::string param_; // e.g. "", "rpsi", "fir" > }; > > class FeedbackParams { > public: > FeedbackParams(); >+ ~FeedbackParams(); > bool operator==(const FeedbackParams& other) const; > > bool Has(const FeedbackParam& param) const; >@@ -57,6 +55,7 @@ class FeedbackParams { > void Intersect(const FeedbackParams& from); > > const std::vector<FeedbackParam>& params() const { return params_; } >+ > private: > bool HasDuplicateEntries() const; > >@@ -100,9 +99,7 @@ struct Codec { > > bool operator==(const Codec& c) const; > >- bool operator!=(const Codec& c) const { >- return !(*this == c); >- } >+ bool operator!=(const Codec& c) const { return !(*this == c); } > > protected: > // A Codec can't be created without a subclass. >@@ -142,33 +139,9 @@ struct AudioCodec : public Codec { > > bool operator==(const AudioCodec& c) const; > >- bool operator!=(const AudioCodec& c) const { >- return !(*this == c); >- } >+ bool operator!=(const AudioCodec& c) const { return !(*this == c); } > }; > >-inline std::ostream& operator<<(std::ostream& os, const AudioCodec& ac) { >- os << "{id: " << ac.id; >- os << ", name: " << ac.name; >- os << ", clockrate: " << ac.clockrate; >- os << ", bitrate: " << ac.bitrate; >- os << ", channels: " << ac.channels; >- os << ", params: {"; >- const char* sep = ""; >- for (const auto& kv : ac.params) { >- os << sep << kv.first << ": " << kv.second; >- sep = ", "; >- } >- os << "}, feedback_params: {"; >- sep = ""; >- for (const FeedbackParam& fp : ac.feedback_params.params()) { >- os << sep << fp.id() << ": " << fp.param(); >- sep = ", "; >- } >- os << "}}"; >- return os; >-} >- > struct VideoCodec : public Codec { > // Creates a codec with the given parameters. > VideoCodec(int id, const std::string& name); >@@ -195,9 +168,7 @@ struct VideoCodec : public Codec { > > bool operator==(const VideoCodec& c) const; > >- bool operator!=(const VideoCodec& c) const { >- return !(*this == c); >- } >+ bool operator!=(const VideoCodec& c) const { return !(*this == c); } > > static VideoCodec CreateRtxCodec(int rtx_payload_type, > int associated_payload_type); >@@ -248,6 +219,7 @@ bool CodecNamesEq(const std::string& name1, const std::string& name2); > bool CodecNamesEq(const char* name1, const char* name2); > bool HasNack(const Codec& codec); > bool HasRemb(const Codec& codec); >+bool HasRrtr(const Codec& codec); > bool HasTransportCc(const Codec& codec); > // Returns the first codec in |supported_codecs| that matches |codec|, or > // nullptr if no codec matches. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec_unittest.cc >index 03d8684c64a..54396a92447 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/codec_unittest.cc >@@ -9,6 +9,8 @@ > */ > > #include "media/base/codec.h" >+ >+#include "media/base/vp9_profile.h" > #include "rtc_base/gunit.h" > > using cricket::AudioCodec; >@@ -186,6 +188,75 @@ TEST(CodecTest, TestVideoCodecMatches) { > EXPECT_FALSE(c1.Matches(VideoCodec(95, "V"))); > } > >+// VP9 codecs compare profile information. >+TEST(CodecTest, TestVP9CodecMatches) { >+ const char kProfile0[] = "0"; >+ const char kProfile2[] = "2"; >+ >+ VideoCodec c_no_profile(95, cricket::kVp9CodecName); >+ VideoCodec c_profile0(95, cricket::kVp9CodecName); >+ c_profile0.params[webrtc::kVP9FmtpProfileId] = kProfile0; >+ >+ EXPECT_TRUE(c_profile0.Matches(c_no_profile)); >+ >+ { >+ VideoCodec c_profile0_eq(95, cricket::kVp9CodecName); >+ c_profile0_eq.params[webrtc::kVP9FmtpProfileId] = kProfile0; >+ EXPECT_TRUE(c_profile0.Matches(c_profile0_eq)); >+ } >+ >+ { >+ VideoCodec c_profile2(95, cricket::kVp9CodecName); >+ c_profile2.params[webrtc::kVP9FmtpProfileId] = kProfile2; >+ EXPECT_FALSE(c_profile0.Matches(c_profile2)); >+ EXPECT_FALSE(c_no_profile.Matches(c_profile2)); >+ } >+ >+ { >+ VideoCodec c_no_profile_eq(95, cricket::kVp9CodecName); >+ EXPECT_TRUE(c_no_profile.Matches(c_no_profile_eq)); >+ } >+} >+ >+// Matching H264 codecs also need to have matching profile-level-id and >+// packetization-mode. >+TEST(CodecTest, TestH264CodecMatches) { >+ const char kProfileLevelId1[] = "42e01f"; >+ const char kProfileLevelId2[] = "42a01e"; >+ >+ VideoCodec pli_1_pm_0(95, "H264"); >+ pli_1_pm_0.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1; >+ pli_1_pm_0.params[cricket::kH264FmtpPacketizationMode] = "0"; >+ >+ { >+ VideoCodec pli_1_pm_blank(95, "H264"); >+ pli_1_pm_blank.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1; >+ pli_1_pm_blank.params.erase( >+ pli_1_pm_blank.params.find(cricket::kH264FmtpPacketizationMode)); >+ >+ // Matches since if packetization-mode is not specified it defaults to "0". >+ EXPECT_TRUE(pli_1_pm_0.Matches(pli_1_pm_blank)); >+ } >+ >+ { >+ VideoCodec pli_1_pm_1(95, "H264"); >+ pli_1_pm_1.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId1; >+ pli_1_pm_1.params[cricket::kH264FmtpPacketizationMode] = "1"; >+ >+ // Does not match since packetization-mode is different. >+ EXPECT_FALSE(pli_1_pm_0.Matches(pli_1_pm_1)); >+ } >+ >+ { >+ VideoCodec pli_2_pm_0(95, "H264"); >+ pli_2_pm_0.params[cricket::kH264FmtpProfileLevelId] = kProfileLevelId2; >+ pli_2_pm_0.params[cricket::kH264FmtpPacketizationMode] = "0"; >+ >+ // Does not match since profile-level-id is different. >+ EXPECT_FALSE(pli_1_pm_0.Matches(pli_2_pm_0)); >+ } >+} >+ > TEST(CodecTest, TestDataCodecMatches) { > // Test a codec with a static payload type. > DataCodec c0(95, "D"); >@@ -308,19 +379,27 @@ TEST(CodecTest, TestValidateCodecFormat) { > } > > TEST(CodecTest, TestToCodecParameters) { >- const VideoCodec v(96, "V"); >+ VideoCodec v(96, "V"); >+ v.SetParam("p1", "v1"); > webrtc::RtpCodecParameters codec_params_1 = v.ToCodecParameters(); > EXPECT_EQ(96, codec_params_1.payload_type); > EXPECT_EQ(cricket::MEDIA_TYPE_VIDEO, codec_params_1.kind); > EXPECT_EQ("V", codec_params_1.name); > EXPECT_EQ(cricket::kVideoCodecClockrate, codec_params_1.clock_rate); >- EXPECT_EQ(rtc::nullopt, codec_params_1.num_channels); >+ EXPECT_EQ(absl::nullopt, codec_params_1.num_channels); >+ ASSERT_EQ(1u, codec_params_1.parameters.size()); >+ EXPECT_EQ("p1", codec_params_1.parameters.begin()->first); >+ EXPECT_EQ("v1", codec_params_1.parameters.begin()->second); > >- const AudioCodec a(97, "A", 44100, 20000, 2); >+ AudioCodec a(97, "A", 44100, 20000, 2); >+ a.SetParam("p1", "a1"); > webrtc::RtpCodecParameters codec_params_2 = a.ToCodecParameters(); > EXPECT_EQ(97, codec_params_2.payload_type); > EXPECT_EQ(cricket::MEDIA_TYPE_AUDIO, codec_params_2.kind); > EXPECT_EQ("A", codec_params_2.name); > EXPECT_EQ(44100, codec_params_2.clock_rate); > EXPECT_EQ(2, codec_params_2.num_channels); >+ ASSERT_EQ(1u, codec_params_2.parameters.size()); >+ EXPECT_EQ("p1", codec_params_2.parameters.begin()->first); >+ EXPECT_EQ("a1", codec_params_2.parameters.begin()->second); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/device.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/device.h >index f47293823f5..7910c974008 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/device.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/device.h >@@ -20,12 +20,8 @@ namespace cricket { > // Used to represent an audio or video capture or render device. > struct Device { > Device() {} >- Device(const std::string& name, int id) >- : name(name), >- id(rtc::ToString(id)) { >- } >- Device(const std::string& name, const std::string& id) >- : name(name), id(id) {} >+ Device(const std::string& name, int id) : name(name), id(rtc::ToString(id)) {} >+ Device(const std::string& name, const std::string& id) : name(name), id(id) {} > > std::string name; > std::string id; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.cc >new file mode 100644 >index 00000000000..ffc3eee773f >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.cc >@@ -0,0 +1,71 @@ >+/* >+ * Copyright (c) 2018 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 "media/base/fakeframesource.h" >+ >+#include "api/video/i420_buffer.h" >+#include "rtc_base/checks.h" >+ >+namespace cricket { >+ >+FakeFrameSource::FakeFrameSource(int width, int height, int interval_us) >+ : width_(width), height_(height), interval_us_(interval_us) { >+ RTC_CHECK_GT(width_, 0); >+ RTC_CHECK_GT(height_, 0); >+ RTC_CHECK_GT(interval_us_, 0); >+} >+ >+webrtc::VideoRotation FakeFrameSource::GetRotation() const { >+ return rotation_; >+} >+ >+void FakeFrameSource::SetRotation(webrtc::VideoRotation rotation) { >+ rotation_ = rotation; >+} >+ >+webrtc::VideoFrame FakeFrameSource::GetFrameRotationApplied() { >+ switch (rotation_) { >+ case webrtc::kVideoRotation_0: >+ case webrtc::kVideoRotation_180: >+ return GetFrame(width_, height_, webrtc::kVideoRotation_0, interval_us_); >+ case webrtc::kVideoRotation_90: >+ case webrtc::kVideoRotation_270: >+ return GetFrame(height_, width_, webrtc::kVideoRotation_0, interval_us_); >+ } >+ RTC_NOTREACHED() << "Invalid rotation value: " << static_cast<int>(rotation_); >+ // Without this return, the Windows Visual Studio compiler complains >+ // "not all control paths return a value". >+ return GetFrame(); >+} >+ >+webrtc::VideoFrame FakeFrameSource::GetFrame() { >+ return GetFrame(width_, height_, rotation_, interval_us_); >+} >+ >+webrtc::VideoFrame FakeFrameSource::GetFrame(int width, >+ int height, >+ webrtc::VideoRotation rotation, >+ int interval_us) { >+ RTC_CHECK_GT(width, 0); >+ RTC_CHECK_GT(height, 0); >+ RTC_CHECK_GT(interval_us, 0); >+ >+ rtc::scoped_refptr<webrtc::I420Buffer> buffer( >+ webrtc::I420Buffer::Create(width, height)); >+ >+ buffer->InitializeData(); >+ webrtc::VideoFrame frame = >+ webrtc::VideoFrame(buffer, rotation, next_timestamp_us_); >+ >+ next_timestamp_us_ += interval_us; >+ return frame; >+} >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.h >new file mode 100644 >index 00000000000..db440457c03 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakeframesource.h >@@ -0,0 +1,47 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef MEDIA_BASE_FAKEFRAMESOURCE_H_ >+#define MEDIA_BASE_FAKEFRAMESOURCE_H_ >+ >+#include "api/video/video_frame.h" >+ >+#include "rtc_base/timeutils.h" >+ >+namespace cricket { >+ >+class FakeFrameSource { >+ public: >+ FakeFrameSource(int width, int height, int interval_us); >+ >+ webrtc::VideoRotation GetRotation() const; >+ void SetRotation(webrtc::VideoRotation rotation); >+ >+ webrtc::VideoFrame GetFrame(); >+ webrtc::VideoFrame GetFrameRotationApplied(); >+ >+ // Override configuration. >+ webrtc::VideoFrame GetFrame(int width, >+ int height, >+ webrtc::VideoRotation rotation, >+ int interval_us); >+ >+ private: >+ const int width_; >+ const int height_; >+ const int interval_us_; >+ >+ webrtc::VideoRotation rotation_ = webrtc::kVideoRotation_0; >+ int64_t next_timestamp_us_ = rtc::kNumMicrosecsPerMillisec; >+}; >+ >+} // namespace cricket >+ >+#endif // MEDIA_BASE_FAKEFRAMESOURCE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakemediaengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakemediaengine.h >index 609b62f910a..5d381f7b41a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakemediaengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakemediaengine.h >@@ -20,6 +20,7 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" > #include "api/call/audio_sink.h" > #include "media/base/audiosource.h" > #include "media/base/mediaengine.h" >@@ -30,7 +31,6 @@ > #include "rtc_base/checks.h" > #include "rtc_base/copyonwritebuffer.h" > #include "rtc_base/networkroute.h" >-#include "rtc_base/ptr_util.h" > #include "rtc_base/stringutils.h" > > using webrtc::RtpExtension; >@@ -42,7 +42,8 @@ class FakeVideoEngine; > class FakeVoiceEngine; > > // A common helper class that handles sending and receiving RTP/RTCP packets. >-template <class Base> class RtpHelper : public Base { >+template <class Base> >+class RtpHelper : public Base { > public: > RtpHelper() > : sending_(false), >@@ -110,7 +111,7 @@ template <class Base> class RtpHelper : public Base { > } > send_streams_.push_back(sp); > rtp_send_parameters_[sp.first_ssrc()] = >- CreateRtpParametersWithOneEncoding(); >+ CreateRtpParametersWithEncodings(sp); > return true; > } > virtual bool RemoveSendStream(uint32_t ssrc) { >@@ -145,16 +146,17 @@ template <class Base> class RtpHelper : public Base { > } > return webrtc::RtpParameters(); > } >- virtual bool SetRtpSendParameters(uint32_t ssrc, >- const webrtc::RtpParameters& parameters) { >+ virtual webrtc::RTCError SetRtpSendParameters( >+ uint32_t ssrc, >+ const webrtc::RtpParameters& parameters) { > auto parameters_iterator = rtp_send_parameters_.find(ssrc); > if (parameters_iterator != rtp_send_parameters_.end()) { > parameters_iterator->second = parameters; >- return true; >+ return webrtc::RTCError::OK(); > } > // Replicate the behavior of the real media channel: return false > // when setting parameters for unknown SSRCs. >- return false; >+ return webrtc::RTCError(webrtc::RTCErrorType::INTERNAL_ERROR); > } > > virtual webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const { >@@ -216,9 +218,7 @@ template <class Base> class RtpHelper : public Base { > const RtcpParameters& send_rtcp_parameters() { return send_rtcp_parameters_; } > const RtcpParameters& recv_rtcp_parameters() { return recv_rtcp_parameters_; } > >- bool ready_to_send() const { >- return ready_to_send_; >- } >+ bool ready_to_send() const { return ready_to_send_; } > > int transport_overhead_per_packet() const { > return transport_overhead_per_packet_; >@@ -269,9 +269,7 @@ template <class Base> class RtpHelper : public Base { > const rtc::PacketTime& packet_time) { > rtcp_packets_.push_back(std::string(packet->data<char>(), packet->size())); > } >- virtual void OnReadyToSend(bool ready) { >- ready_to_send_ = ready; >- } >+ virtual void OnReadyToSend(bool ready) { ready_to_send_ = ready; } > > virtual void OnNetworkRouteChanged(const std::string& transport_name, > const rtc::NetworkRoute& network_route) { >@@ -310,9 +308,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> { > public: > struct DtmfInfo { > DtmfInfo(uint32_t ssrc, int event_code, int duration) >- : ssrc(ssrc), >- event_code(event_code), >- duration(duration) {} >+ : ssrc(ssrc), event_code(event_code), duration(duration) {} > uint32_t ssrc; > int event_code; > int duration; >@@ -381,9 +377,6 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> { > return true; > } > >- virtual bool GetActiveStreams(StreamList* streams) { return true; } >- virtual int GetOutputLevel() { return 0; } >- > virtual bool CanInsertDtmf() { > for (std::vector<AudioCodec>::const_iterator it = send_codecs_.begin(); > it != send_codecs_.end(); ++it) { >@@ -394,9 +387,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> { > } > return false; > } >- virtual bool InsertDtmf(uint32_t ssrc, >- int event_code, >- int duration) { >+ virtual bool InsertDtmf(uint32_t ssrc, int event_code, int duration) { > dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration)); > return true; > } >@@ -488,7 +479,7 @@ class FakeVoiceMediaChannel : public RtpHelper<VoiceMediaChannel> { > RTC_CHECK(it->second->source() == source); > } else { > local_sinks_.insert(std::make_pair( >- ssrc, rtc::MakeUnique<VoiceChannelAudioSink>(source))); >+ ssrc, absl::make_unique<VoiceChannelAudioSink>(source))); > } > } else { > if (it != local_sinks_.end()) { >@@ -579,13 +570,9 @@ class FakeVideoMediaChannel : public RtpHelper<VideoMediaChannel> { > bool SetSend(bool send) override { return set_sending(send); } > bool SetVideoSend( > uint32_t ssrc, >- bool enable, > const VideoOptions* options, > rtc::VideoSourceInterface<webrtc::VideoFrame>* source) override { >- if (!RtpHelper<VideoMediaChannel>::MuteStream(ssrc, !enable)) { >- return false; >- } >- if (enable && options) { >+ if (options) { > if (!SetOptions(*options)) { > return false; > } >@@ -741,9 +728,7 @@ class FakeDataMediaChannel : public RtpHelper<DataMediaChannel> { > // and FakeVideoEngine. > class FakeBaseEngine { > public: >- FakeBaseEngine() >- : options_changed_(false), >- fail_create_channel_(false) {} >+ FakeBaseEngine() : options_changed_(false), fail_create_channel_(false) {} > void set_fail_create_channel(bool fail) { fail_create_channel_ = fail; } > > RtpCapabilities GetCapabilities() const { return capabilities_; } >@@ -881,8 +866,8 @@ class FakeVideoEngine : public FakeBaseEngine { > friend class FakeMediaEngine; > }; > >-class FakeMediaEngine : >- public CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine> { >+class FakeMediaEngine >+ : public CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine> { > public: > FakeMediaEngine() > : CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine>(std::tuple<>(), >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakenetworkinterface.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakenetworkinterface.h >index 3d98d1f9177..98d9c469a52 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakenetworkinterface.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakenetworkinterface.h >@@ -37,8 +37,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, > conf_(false), > sendbuf_size_(-1), > recvbuf_size_(-1), >- dscp_(rtc::DSCP_NO_CHANGE) { >- } >+ dscp_(rtc::DSCP_NO_CHANGE) {} > > void SetDestination(MediaChannel* dest) { dest_ = dest; } > >@@ -125,8 +124,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, > rtp_packets_.push_back(*packet); > if (conf_) { > for (size_t i = 0; i < conf_sent_ssrcs_.size(); ++i) { >- if (!SetRtpSsrc(packet->data(), packet->size(), >- conf_sent_ssrcs_[i])) { >+ if (!SetRtpSsrc(packet->data(), packet->size(), conf_sent_ssrcs_[i])) { > return false; > } > PostMessage(ST_RTP, *packet); >@@ -148,8 +146,7 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, > return true; > } > >- virtual int SetOption(SocketType type, rtc::Socket::Option opt, >- int option) { >+ virtual int SetOption(SocketType type, rtc::Socket::Option opt, int option) { > if (opt == rtc::Socket::OPT_SNDBUF) { > sendbuf_size_ = option; > } else if (opt == rtc::Socket::OPT_RCVBUF) { >@@ -166,15 +163,12 @@ class FakeNetworkInterface : public MediaChannel::NetworkInterface, > > virtual void OnMessage(rtc::Message* msg) { > rtc::TypedMessageData<rtc::CopyOnWriteBuffer>* msg_data = >- static_cast<rtc::TypedMessageData<rtc::CopyOnWriteBuffer>*>( >- msg->pdata); >+ static_cast<rtc::TypedMessageData<rtc::CopyOnWriteBuffer>*>(msg->pdata); > if (dest_) { > if (msg->message_id == ST_RTP) { >- dest_->OnPacketReceived(&msg_data->data(), >- rtc::CreatePacketTime(0)); >+ dest_->OnPacketReceived(&msg_data->data(), rtc::CreatePacketTime(0)); > } else { >- dest_->OnRtcpReceived(&msg_data->data(), >- rtc::CreatePacketTime(0)); >+ dest_->OnRtcpReceived(&msg_data->data(), rtc::CreatePacketTime(0)); > } > } > delete msg_data; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.cc >index be1631b73f7..fc9a058b87c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.cc >@@ -13,9 +13,12 @@ > #include "media/base/fakertp.h" > #include "rtc_base/gunit.h" > >-void CompareHeaderExtensions(const char* packet1, size_t packet1_size, >- const char* packet2, size_t packet2_size, >- const std::vector<int> encrypted_headers, bool expect_equal) { >+void CompareHeaderExtensions(const char* packet1, >+ size_t packet1_size, >+ const char* packet2, >+ size_t packet2_size, >+ const std::vector<int> encrypted_headers, >+ bool expect_equal) { > // Sanity check: packets must be large enough to contain the RTP header and > // extensions header. > RTC_CHECK_GE(packet1_size, 12 + 4); >@@ -36,7 +39,7 @@ void CompareHeaderExtensions(const char* packet1, size_t packet1_size, > RTC_CHECK_GE(packet2_size, 12 + 4 + extension_words * 4); > while (extension_data1 < extension_end1) { > uint8_t id = (*extension_data1 & 0xf0) >> 4; >- uint8_t len = (*extension_data1 & 0x0f) +1; >+ uint8_t len = (*extension_data1 & 0x0f) + 1; > extension_data1++; > extension_data2++; > EXPECT_LE(extension_data1, extension_end1); >@@ -48,8 +51,8 @@ void CompareHeaderExtensions(const char* packet1, size_t packet1_size, > // The header extension doesn't get encrypted if the id is not in the > // list of header extensions to encrypt. > if (expect_equal || >- std::find(encrypted_headers.begin(), encrypted_headers.end(), id) >- == encrypted_headers.end()) { >+ std::find(encrypted_headers.begin(), encrypted_headers.end(), id) == >+ encrypted_headers.end()) { > EXPECT_EQ(0, memcmp(extension_data1, extension_data2, len)); > } else { > EXPECT_NE(0, memcmp(extension_data1, extension_data2, len)); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.h >index 6786bab6d92..946f302b00d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakertp.h >@@ -13,33 +13,28 @@ > #ifndef MEDIA_BASE_FAKERTP_H_ > #define MEDIA_BASE_FAKERTP_H_ > >+#include <cstddef> // size_t > #include <vector> > > // A typical PCMU RTP packet. > // PT=0, SN=1, TS=0, SSRC=1 > // all data FF > static const unsigned char kPcmuFrame[] = { >- 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, > }; > > static const int kHeaderExtensionIDs[] = {1, 4}; >@@ -48,93 +43,81 @@ static const int kHeaderExtensionIDs[] = {1, 4}; > // PT=0, SN=1, TS=0, SSRC=1 > // all data FF > static const unsigned char kPcmuFrameWithExtensions[] = { >- 0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >- // RFC 5285, section 4.2. One-Byte Header. >- 0xBE, 0xDE, >- // Header extension length 6 * 32 bits. >- 0x00, 0x06, >- // 8 bytes header id 1. >- 0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27, 0x48, >- // 3 bytes header id 2. >- 0x22, 0x00, 0x00, 0xC8, >- // 1 byte header id 3. >- 0x30, 0x8E, >- // 7 bytes header id 4. >- 0x46, 0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, >- // 1 byte header padding. >- 0x00, >- // Payload data. >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0x90, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >+ // RFC 5285, section 4.2. One-Byte Header. >+ 0xBE, 0xDE, >+ // Header extension length 6 * 32 bits. >+ 0x00, 0x06, >+ // 8 bytes header id 1. >+ 0x17, 0x41, 0x42, 0x73, 0xA4, 0x75, 0x26, 0x27, 0x48, >+ // 3 bytes header id 2. >+ 0x22, 0x00, 0x00, 0xC8, >+ // 1 byte header id 3. >+ 0x30, 0x8E, >+ // 7 bytes header id 4. >+ 0x46, 0x55, 0x99, 0x63, 0x86, 0xB3, 0x95, 0xFB, >+ // 1 byte header padding. >+ 0x00, >+ // Payload data. >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, > }; > > // A typical Receiver Report RTCP packet. > // PT=RR, LN=1, SSRC=1 > // send SSRC=2, all other fields 0 > static const unsigned char kRtcpReport[] = { >- 0x80, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, >- 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >-}; >+ 0x80, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, >+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; > > // PT = 97, TS = 0, Seq = 1, SSRC = 2 > // H264 - NRI = 1, Type = 1, bit stream = FF > > static const unsigned char kH264Packet[] = { >- 0x80, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, >- 0x21, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0x80, 0x61, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, >+ 0x21, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, >+ 0xFF, 0xFF, 0xFF, 0xFF, > }; > > // PT= 101, SN=2, TS=3, SSRC = 4 > static const unsigned char kDataPacket[] = { >- 0x80, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, >- 0x00, 0x00, 0x00, 0x00, >- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, >+ 0x80, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, >+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, > }; > > // This expects both packets to be based on kPcmuFrameWithExtensions. > // Header extensions with an id in "encrypted_headers" are expected to be > // different in the packets unless "expect_equal" is set to "true". >-void CompareHeaderExtensions(const char* packet1, size_t packet1_size, >- const char* packet2, size_t packet2_size, >- const std::vector<int> encrypted_headers, bool expect_equal); >+void CompareHeaderExtensions(const char* packet1, >+ size_t packet1_size, >+ const char* packet2, >+ size_t packet2_size, >+ const std::vector<int> encrypted_headers, >+ bool expect_equal); > > #endif // MEDIA_BASE_FAKERTP_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.cc >new file mode 100644 >index 00000000000..94900ba37b6 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.cc >@@ -0,0 +1,158 @@ >+/* >+ * Copyright (c) 2018 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 "media/base/fakevideocapturer.h" >+ >+#include "rtc_base/arraysize.h" >+ >+namespace cricket { >+ >+FakeVideoCapturer::FakeVideoCapturer(bool is_screencast) >+ : running_(false), >+ is_screencast_(is_screencast), >+ rotation_(webrtc::kVideoRotation_0) { >+ // Default supported formats. Use ResetSupportedFormats to over write. >+ using cricket::VideoFormat; >+ static const VideoFormat formats[] = { >+ {1280, 720, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, >+ {640, 480, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, >+ {320, 240, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, >+ {160, 120, VideoFormat::FpsToInterval(30), cricket::FOURCC_I420}, >+ {1280, 720, VideoFormat::FpsToInterval(60), cricket::FOURCC_I420}, >+ }; >+ ResetSupportedFormats({&formats[0], &formats[arraysize(formats)]}); >+} >+ >+FakeVideoCapturer::FakeVideoCapturer() : FakeVideoCapturer(false) {} >+ >+FakeVideoCapturer::~FakeVideoCapturer() { >+ SignalDestroyed(this); >+} >+ >+void FakeVideoCapturer::ResetSupportedFormats( >+ const std::vector<cricket::VideoFormat>& formats) { >+ SetSupportedFormats(formats); >+} >+ >+bool FakeVideoCapturer::CaptureFrame() { >+ if (!GetCaptureFormat()) { >+ return false; >+ } >+ RTC_CHECK_EQ(GetCaptureFormat()->fourcc, FOURCC_I420); >+ return CaptureFrame(frame_source_->GetFrame()); >+} >+ >+bool FakeVideoCapturer::CaptureCustomFrame(int width, int height) { >+ // Default to 30fps. >+ // TODO(nisse): Would anything break if we always stick to >+ // the configure frame interval? >+ return CaptureFrame(frame_source_->GetFrame(width, height, rotation_, >+ rtc::kNumMicrosecsPerSec / 30)); >+} >+ >+bool FakeVideoCapturer::CaptureFrame(const webrtc::VideoFrame& frame) { >+ if (!running_) { >+ return false; >+ } >+ >+ int adapted_width; >+ int adapted_height; >+ int crop_width; >+ int crop_height; >+ int crop_x; >+ int crop_y; >+ >+ // TODO(nisse): It's a bit silly to have this logic in a fake >+ // class. Child classes of VideoCapturer are expected to call >+ // AdaptFrame, and the test case >+ // VideoCapturerTest.SinkWantsMaxPixelAndMaxPixelCountStepUp >+ // depends on this. >+ if (AdaptFrame(frame.width(), frame.height(), frame.timestamp_us(), >+ frame.timestamp_us(), &adapted_width, &adapted_height, >+ &crop_width, &crop_height, &crop_x, &crop_y, nullptr)) { >+ rtc::scoped_refptr<webrtc::I420Buffer> buffer( >+ webrtc::I420Buffer::Create(adapted_width, adapted_height)); >+ buffer->InitializeData(); >+ >+ OnFrame(webrtc::VideoFrame(buffer, frame.rotation(), frame.timestamp_us()), >+ frame.width(), frame.height()); >+ } >+ >+ return true; >+} >+ >+cricket::CaptureState FakeVideoCapturer::Start( >+ const cricket::VideoFormat& format) { >+ SetCaptureFormat(&format); >+ running_ = true; >+ SetCaptureState(cricket::CS_RUNNING); >+ frame_source_ = absl::make_unique<FakeFrameSource>( >+ format.width, format.height, >+ format.interval / rtc::kNumNanosecsPerMicrosec); >+ frame_source_->SetRotation(rotation_); >+ return cricket::CS_RUNNING; >+} >+ >+void FakeVideoCapturer::Stop() { >+ running_ = false; >+ SetCaptureFormat(NULL); >+ SetCaptureState(cricket::CS_STOPPED); >+} >+ >+bool FakeVideoCapturer::IsRunning() { >+ return running_; >+} >+ >+bool FakeVideoCapturer::IsScreencast() const { >+ return is_screencast_; >+} >+ >+bool FakeVideoCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) { >+ fourccs->push_back(cricket::FOURCC_I420); >+ fourccs->push_back(cricket::FOURCC_MJPG); >+ return true; >+} >+ >+void FakeVideoCapturer::SetRotation(webrtc::VideoRotation rotation) { >+ rotation_ = rotation; >+ if (frame_source_) >+ frame_source_->SetRotation(rotation_); >+} >+ >+webrtc::VideoRotation FakeVideoCapturer::GetRotation() { >+ return rotation_; >+} >+ >+FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue( >+ bool is_screencast) >+ : FakeVideoCapturer(is_screencast) {} >+ >+FakeVideoCapturerWithTaskQueue::FakeVideoCapturerWithTaskQueue() {} >+ >+bool FakeVideoCapturerWithTaskQueue::CaptureFrame() { >+ if (task_queue_.IsCurrent()) >+ return FakeVideoCapturer::CaptureFrame(); >+ bool ret = false; >+ task_queue_.SendTask( >+ [this, &ret]() { ret = FakeVideoCapturer::CaptureFrame(); }); >+ return ret; >+} >+ >+bool FakeVideoCapturerWithTaskQueue::CaptureCustomFrame(int width, int height) { >+ if (task_queue_.IsCurrent()) >+ return FakeVideoCapturer::CaptureCustomFrame(width, height); >+ bool ret = false; >+ task_queue_.SendTask([this, &ret, width, height]() { >+ ret = FakeVideoCapturer::CaptureCustomFrame(width, height); >+ }); >+ return ret; >+} >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.h >index 536fe16356e..4a49f4504ad 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideocapturer.h >@@ -18,8 +18,10 @@ > > #include "api/video/i420_buffer.h" > #include "api/video/video_frame.h" >+#include "media/base/fakeframesource.h" > #include "media/base/videocapturer.h" > #include "media/base/videocommon.h" >+#include "rtc_base/task_queue_for_test.h" > #include "rtc_base/timeutils.h" > > namespace cricket { >@@ -27,124 +29,50 @@ namespace cricket { > // Fake video capturer that allows the test to manually pump in frames. > class FakeVideoCapturer : public cricket::VideoCapturer { > public: >- explicit FakeVideoCapturer(bool is_screencast) >- : running_(false), >- initial_timestamp_(rtc::TimeNanos()), >- next_timestamp_(rtc::kNumNanosecsPerMillisec), >- is_screencast_(is_screencast), >- rotation_(webrtc::kVideoRotation_0) { >- // Default supported formats. Use ResetSupportedFormats to over write. >- std::vector<cricket::VideoFormat> formats; >- formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(160, 120, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_I420)); >- ResetSupportedFormats(formats); >- } >- FakeVideoCapturer() : FakeVideoCapturer(false) {} >- >- ~FakeVideoCapturer() { >- SignalDestroyed(this); >- } >- >- void ResetSupportedFormats(const std::vector<cricket::VideoFormat>& formats) { >- SetSupportedFormats(formats); >- } >- bool CaptureFrame() { >- if (!GetCaptureFormat()) { >- return false; >- } >- return CaptureCustomFrame(GetCaptureFormat()->width, >- GetCaptureFormat()->height, >- GetCaptureFormat()->interval, >- GetCaptureFormat()->fourcc); >- } >- bool CaptureCustomFrame(int width, int height, uint32_t fourcc) { >- // Default to 30fps. >- return CaptureCustomFrame(width, height, rtc::kNumNanosecsPerSec / 30, >- fourcc); >- } >- bool CaptureCustomFrame(int width, >- int height, >- int64_t timestamp_interval, >- uint32_t fourcc) { >- if (!running_) { >- return false; >- } >- RTC_CHECK(fourcc == FOURCC_I420); >- RTC_CHECK(width > 0); >- RTC_CHECK(height > 0); >- >- int adapted_width; >- int adapted_height; >- int crop_width; >- int crop_height; >- int crop_x; >- int crop_y; >- >- // TODO(nisse): It's a bit silly to have this logic in a fake >- // class. Child classes of VideoCapturer are expected to call >- // AdaptFrame, and the test case >- // VideoCapturerTest.SinkWantsMaxPixelAndMaxPixelCountStepUp >- // depends on this. >- if (AdaptFrame(width, height, >- next_timestamp_ / rtc::kNumNanosecsPerMicrosec, >- next_timestamp_ / rtc::kNumNanosecsPerMicrosec, >- &adapted_width, &adapted_height, &crop_width, &crop_height, >- &crop_x, &crop_y, nullptr)) { >- rtc::scoped_refptr<webrtc::I420Buffer> buffer( >- webrtc::I420Buffer::Create(adapted_width, adapted_height)); >- buffer->InitializeData(); >- >- OnFrame(webrtc::VideoFrame( >- buffer, rotation_, >- next_timestamp_ / rtc::kNumNanosecsPerMicrosec), >- width, height); >- } >- next_timestamp_ += timestamp_interval; >- >- return true; >- } >+ explicit FakeVideoCapturer(bool is_screencast); >+ FakeVideoCapturer(); >+ >+ ~FakeVideoCapturer() override; >+ >+ void ResetSupportedFormats(const std::vector<cricket::VideoFormat>& formats); >+ virtual bool CaptureFrame(); >+ virtual bool CaptureCustomFrame(int width, int height); > > sigslot::signal1<FakeVideoCapturer*> SignalDestroyed; > >- cricket::CaptureState Start(const cricket::VideoFormat& format) override { >- SetCaptureFormat(&format); >- running_ = true; >- SetCaptureState(cricket::CS_RUNNING); >- return cricket::CS_RUNNING; >- } >- void Stop() override { >- running_ = false; >- SetCaptureFormat(NULL); >- SetCaptureState(cricket::CS_STOPPED); >- } >- bool IsRunning() override { return running_; } >- bool IsScreencast() const override { return is_screencast_; } >- bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) override { >- fourccs->push_back(cricket::FOURCC_I420); >- fourccs->push_back(cricket::FOURCC_MJPG); >- return true; >- } >- >- void SetRotation(webrtc::VideoRotation rotation) { >- rotation_ = rotation; >- } >- >- webrtc::VideoRotation GetRotation() { return rotation_; } >+ cricket::CaptureState Start(const cricket::VideoFormat& format) override; >+ void Stop() override; >+ bool IsRunning() override; >+ bool IsScreencast() const override; >+ bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) override; >+ >+ void SetRotation(webrtc::VideoRotation rotation); >+ >+ webrtc::VideoRotation GetRotation(); > > private: >+ bool CaptureFrame(const webrtc::VideoFrame& frame); >+ > bool running_; >- int64_t initial_timestamp_; >- int64_t next_timestamp_; > const bool is_screencast_; >+ // Duplicates FakeFrameSource::rotation_, but needed to support >+ // SetRotation before Start. > webrtc::VideoRotation rotation_; >+ std::unique_ptr<FakeFrameSource> frame_source_; >+}; >+ >+// Inherits from FakeVideoCapturer but adds a TaskQueue so that frames can be >+// delivered on a TaskQueue as expected by VideoSinkInterface implementations. >+class FakeVideoCapturerWithTaskQueue : public FakeVideoCapturer { >+ public: >+ explicit FakeVideoCapturerWithTaskQueue(bool is_screencast); >+ FakeVideoCapturerWithTaskQueue(); >+ >+ bool CaptureFrame() override; >+ bool CaptureCustomFrame(int width, int height) override; >+ >+ protected: >+ rtc::test::TaskQueueForTest task_queue_{"FakeVideoCapturerWithTaskQueue"}; > }; > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.cc >new file mode 100644 >index 00000000000..fdd789a4b7d >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.cc >@@ -0,0 +1,33 @@ >+/* >+ * Copyright (c) 2018 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 "media/base/fakevideorenderer.h" >+ >+namespace cricket { >+ >+FakeVideoRenderer::FakeVideoRenderer() = default; >+ >+void FakeVideoRenderer::OnFrame(const webrtc::VideoFrame& frame) { >+ rtc::CritScope cs(&crit_); >+ // TODO(zhurunz) Check with VP8 team to see if we can remove this >+ // tolerance on Y values. Some unit tests produce Y values close >+ // to 16 rather than close to zero, for supposedly black frames. >+ // Largest value observed is 34, e.g., running >+ // PeerConnectionIntegrationTest.SendAndReceive16To9AspectRatio. >+ black_frame_ = CheckFrameColorYuv(0, 48, 128, 128, 128, 128, &frame); >+ // Treat unexpected frame size as error. >+ ++num_rendered_frames_; >+ width_ = frame.width(); >+ height_ = frame.height(); >+ rotation_ = frame.rotation(); >+ timestamp_us_ = frame.timestamp_us(); >+} >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.h >index fa9aff70f52..f072c729e66 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/fakevideorenderer.h >@@ -12,7 +12,7 @@ > #define MEDIA_BASE_FAKEVIDEORENDERER_H_ > > #include "api/video/video_frame.h" >-#include "api/videosinkinterface.h" >+#include "api/video/video_sink_interface.h" > #include "rtc_base/criticalsection.h" > #include "rtc_base/logging.h" > >@@ -21,30 +21,9 @@ namespace cricket { > // Faked video renderer that has a callback for actions on rendering. > class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> { > public: >- FakeVideoRenderer() >- : errors_(0), >- width_(0), >- height_(0), >- rotation_(webrtc::kVideoRotation_0), >- timestamp_us_(0), >- num_rendered_frames_(0), >- black_frame_(false) {} >+ FakeVideoRenderer(); > >- virtual void OnFrame(const webrtc::VideoFrame& frame) { >- rtc::CritScope cs(&crit_); >- // TODO(zhurunz) Check with VP8 team to see if we can remove this >- // tolerance on Y values. Some unit tests produce Y values close >- // to 16 rather than close to zero, for supposedly black frames. >- // Largest value observed is 34, e.g., running >- // PeerConnectionIntegrationTest.SendAndReceive16To9AspectRatio. >- black_frame_ = CheckFrameColorYuv(0, 48, 128, 128, 128, 128, &frame); >- // Treat unexpected frame size as error. >- ++num_rendered_frames_; >- width_ = frame.width(); >- height_ = frame.height(); >- rotation_ = frame.rotation(); >- timestamp_us_ = frame.timestamp_us(); >- } >+ void OnFrame(const webrtc::VideoFrame& frame) override; > > int errors() const { return errors_; } > int width() const { >@@ -127,13 +106,13 @@ class FakeVideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> { > return true; > } > >- int errors_; >- int width_; >- int height_; >- webrtc::VideoRotation rotation_; >- int64_t timestamp_us_; >- int num_rendered_frames_; >- bool black_frame_; >+ int errors_ = 0; >+ int width_ = 0; >+ int height_ = 0; >+ webrtc::VideoRotation rotation_ = webrtc::kVideoRotation_0; >+ int64_t timestamp_us_ = 0; >+ int num_rendered_frames_ = 0; >+ bool black_frame_ = false; > rtc::CriticalSection crit_; > }; > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.cc >index 4731c18f404..65a6cf0cc91 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.cc >@@ -112,19 +112,19 @@ static constexpr LevelConstraint kLevelConstraints[] = { > {245760, 8192, webrtc::H264::kLevel4_1}, > {522240, 8704, webrtc::H264::kLevel4_2}, > {589824, 22080, webrtc::H264::kLevel5}, >- {983040, 3684, webrtc::H264::kLevel5_1}, >- {2073600, 3684, webrtc::H264::kLevel5_2}, >+ {983040, 36864, webrtc::H264::kLevel5_1}, >+ {2073600, 36864, webrtc::H264::kLevel5_2}, > }; > > } // anonymous namespace > >-rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { >+absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str) { > // The string should consist of 3 bytes in hexadecimal format. > if (strlen(str) != 6u) >- return rtc::nullopt; >+ return absl::nullopt; > const uint32_t profile_level_id_numeric = strtol(str, nullptr, 16); > if (profile_level_id_numeric == 0) >- return rtc::nullopt; >+ return absl::nullopt; > > // Separate into three bytes. > const uint8_t level_idc = >@@ -159,7 +159,7 @@ rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { > break; > default: > // Unrecognized level_idc. >- return rtc::nullopt; >+ return absl::nullopt; > } > > // Parse profile_idc/profile_iop into a Profile enum. >@@ -171,10 +171,10 @@ rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str) { > } > > // Unrecognized profile_idc/profile_iop combination. >- return rtc::nullopt; >+ return absl::nullopt; > } > >-rtc::Optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) { >+absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) { > static const int kPixelsPerMacroblock = 16 * 16; > > for (int i = arraysize(kLevelConstraints) - 1; i >= 0; --i) { >@@ -188,10 +188,10 @@ rtc::Optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps) { > } > > // No level supported. >- return rtc::nullopt; >+ return absl::nullopt; > } > >-rtc::Optional<ProfileLevelId> ParseSdpProfileLevelId( >+absl::optional<ProfileLevelId> ParseSdpProfileLevelId( > const CodecParameterMap& params) { > // TODO(magjed): The default should really be kProfileBaseline and kLevel1 > // according to the spec: https://tools.ietf.org/html/rfc6184#section-8.1. In >@@ -209,7 +209,7 @@ rtc::Optional<ProfileLevelId> ParseSdpProfileLevelId( > : ParseProfileLevelId(profile_level_id_it->second.c_str()); > } > >-rtc::Optional<std::string> ProfileLevelIdToString( >+absl::optional<std::string> ProfileLevelIdToString( > const ProfileLevelId& profile_level_id) { > // Handle special case level == 1b. > if (profile_level_id.level == kLevel1_b) { >@@ -222,7 +222,7 @@ rtc::Optional<std::string> ProfileLevelIdToString( > return {"4d100b"}; > // Level 1b is not allowed for other profiles. > default: >- return rtc::nullopt; >+ return absl::nullopt; > } > } > >@@ -245,7 +245,7 @@ rtc::Optional<std::string> ProfileLevelIdToString( > break; > // Unrecognized profile. > default: >- return rtc::nullopt; >+ return absl::nullopt; > } > > char str[7]; >@@ -267,9 +267,9 @@ void GenerateProfileLevelIdForAnswer( > } > > // Parse profile-level-ids. >- const rtc::Optional<ProfileLevelId> local_profile_level_id = >+ const absl::optional<ProfileLevelId> local_profile_level_id = > ParseSdpProfileLevelId(local_supported_params); >- const rtc::Optional<ProfileLevelId> remote_profile_level_id = >+ const absl::optional<ProfileLevelId> remote_profile_level_id = > ParseSdpProfileLevelId(remote_offered_params); > // The local and remote codec must have valid and equal H264 Profiles. > RTC_DCHECK(local_profile_level_id); >@@ -297,9 +297,9 @@ void GenerateProfileLevelIdForAnswer( > > bool IsSameH264Profile(const CodecParameterMap& params1, > const CodecParameterMap& params2) { >- const rtc::Optional<webrtc::H264::ProfileLevelId> profile_level_id = >+ const absl::optional<webrtc::H264::ProfileLevelId> profile_level_id = > webrtc::H264::ParseSdpProfileLevelId(params1); >- const rtc::Optional<webrtc::H264::ProfileLevelId> other_profile_level_id = >+ const absl::optional<webrtc::H264::ProfileLevelId> other_profile_level_id = > webrtc::H264::ParseSdpProfileLevelId(params2); > // Compare H264 profiles, but not levels. > return profile_level_id && other_profile_level_id && >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.h >index 28899e53d98..b4ff88369c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/h264_profile_level_id.h >@@ -14,7 +14,7 @@ > #include <map> > #include <string> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "common_types.h" // NOLINT(build/include) > > namespace webrtc { >@@ -46,7 +46,7 @@ enum Level { > }; > > struct ProfileLevelId { >- ProfileLevelId(Profile profile, Level level) >+ constexpr ProfileLevelId(Profile profile, Level level) > : profile(profile), level(level) {} > Profile profile; > Level level; >@@ -55,24 +55,24 @@ struct ProfileLevelId { > // Parse profile level id that is represented as a string of 3 hex bytes. > // Nothing will be returned if the string is not a recognized H264 > // profile level id. >-rtc::Optional<ProfileLevelId> ParseProfileLevelId(const char* str); >+absl::optional<ProfileLevelId> ParseProfileLevelId(const char* str); > > // Parse profile level id that is represented as a string of 3 hex bytes > // contained in an SDP key-value map. A default profile level id will be > // returned if the profile-level-id key is missing. Nothing will be returned if > // the key is present but the string is invalid. >-rtc::Optional<ProfileLevelId> ParseSdpProfileLevelId( >+absl::optional<ProfileLevelId> ParseSdpProfileLevelId( > const CodecParameterMap& params); > > // Given that a decoder supports up to a given frame size (in pixels) at up to a > // given number of frames per second, return the highest H.264 level where it > // can guarantee that it will be able to support all valid encoded streams that > // are within that level. >-rtc::Optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps); >+absl::optional<Level> SupportedLevel(int max_frame_pixel_count, float max_fps); > > // Returns canonical string representation as three hex bytes of the profile > // level id, or returns nothing for invalid profile level ids. >-rtc::Optional<std::string> ProfileLevelIdToString( >+absl::optional<std::string> ProfileLevelIdToString( > const ProfileLevelId& profile_level_id); > > // Generate codec parameters that will be used as answer in an SDP negotiation >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.cc >new file mode 100644 >index 00000000000..019739d051c >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.cc >@@ -0,0 +1,86 @@ >+/* >+ * Copyright (c) 2018 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 "media/base/mediachannel.h" >+ >+namespace cricket { >+ >+VideoOptions::VideoOptions() = default; >+VideoOptions::~VideoOptions() = default; >+ >+void MediaChannel::SetInterface(NetworkInterface* iface) { >+ rtc::CritScope cs(&network_interface_crit_); >+ network_interface_ = iface; >+ SetDscp(enable_dscp_ ? PreferredDscp() : rtc::DSCP_DEFAULT); >+} >+ >+rtc::DiffServCodePoint MediaChannel::PreferredDscp() const { >+ return rtc::DSCP_DEFAULT; >+} >+ >+int MediaChannel::GetRtpSendTimeExtnId() const { >+ return -1; >+} >+ >+MediaSenderInfo::MediaSenderInfo() = default; >+MediaSenderInfo::~MediaSenderInfo() = default; >+ >+MediaReceiverInfo::MediaReceiverInfo() = default; >+MediaReceiverInfo::~MediaReceiverInfo() = default; >+ >+VoiceSenderInfo::VoiceSenderInfo() = default; >+VoiceSenderInfo::~VoiceSenderInfo() = default; >+ >+VoiceReceiverInfo::VoiceReceiverInfo() = default; >+VoiceReceiverInfo::~VoiceReceiverInfo() = default; >+ >+VideoSenderInfo::VideoSenderInfo() = default; >+VideoSenderInfo::~VideoSenderInfo() = default; >+ >+VideoReceiverInfo::VideoReceiverInfo() = default; >+VideoReceiverInfo::~VideoReceiverInfo() = default; >+ >+VoiceMediaInfo::VoiceMediaInfo() = default; >+VoiceMediaInfo::~VoiceMediaInfo() = default; >+ >+VideoMediaInfo::VideoMediaInfo() = default; >+VideoMediaInfo::~VideoMediaInfo() = default; >+ >+DataMediaInfo::DataMediaInfo() = default; >+DataMediaInfo::~DataMediaInfo() = default; >+ >+AudioSendParameters::AudioSendParameters() = default; >+AudioSendParameters::~AudioSendParameters() = default; >+ >+std::map<std::string, std::string> AudioSendParameters::ToStringMap() const { >+ auto params = RtpSendParameters<AudioCodec>::ToStringMap(); >+ params["options"] = options.ToString(); >+ return params; >+} >+ >+VideoSendParameters::VideoSendParameters() = default; >+VideoSendParameters::~VideoSendParameters() = default; >+ >+std::map<std::string, std::string> VideoSendParameters::ToStringMap() const { >+ auto params = RtpSendParameters<VideoCodec>::ToStringMap(); >+ params["conference_mode"] = (conference_mode ? "yes" : "no"); >+ return params; >+} >+ >+DataMediaChannel::DataMediaChannel() = default; >+DataMediaChannel::DataMediaChannel(const MediaConfig& config) >+ : MediaChannel(config) {} >+DataMediaChannel::~DataMediaChannel() = default; >+ >+bool DataMediaChannel::GetStats(DataMediaInfo* info) { >+ return true; >+} >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.h >index 89d35b79da5..f0e16583230 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediachannel.h >@@ -17,40 +17,40 @@ > #include <utility> > #include <vector> > >+#include "absl/types/optional.h" > #include "api/audio_codecs/audio_encoder.h" >-#include "api/optional.h" >+#include "api/audio_options.h" >+#include "api/rtcerror.h" > #include "api/rtpparameters.h" > #include "api/rtpreceiverinterface.h" > #include "api/video/video_content_type.h" >+#include "api/video/video_sink_interface.h" >+#include "api/video/video_source_interface.h" > #include "api/video/video_timing.h" >-#include "api/videosinkinterface.h" >-#include "api/videosourceinterface.h" >-#include "call/video_config.h" >+#include "api/video_codecs/video_encoder_config.h" > #include "media/base/codec.h" >+#include "media/base/mediaconfig.h" > #include "media/base/mediaconstants.h" > #include "media/base/streamparams.h" > #include "modules/audio_processing/include/audio_processing_statistics.h" > #include "rtc_base/asyncpacketsocket.h" >-#include "rtc_base/basictypes.h" > #include "rtc_base/buffer.h" > #include "rtc_base/copyonwritebuffer.h" > #include "rtc_base/dscp.h" > #include "rtc_base/logging.h" > #include "rtc_base/networkroute.h" >-#include "rtc_base/sigslot.h" > #include "rtc_base/socket.h" > #include "rtc_base/stringencode.h" >- >+#include "rtc_base/third_party/sigslot/sigslot.h" > > namespace rtc { >-class RateLimiter; > class Timing; > } > > namespace webrtc { > class AudioSinkInterface; > class VideoFrame; >-} >+} // namespace webrtc > > namespace cricket { > >@@ -62,7 +62,8 @@ struct VideoFormat; > const int kScreencastDefaultFps = 5; > > template <class T> >-static std::string ToStringIfSet(const char* key, const rtc::Optional<T>& val) { >+static std::string ToStringIfSet(const char* key, >+ const absl::optional<T>& val) { > std::string str; > if (val) { > str = key; >@@ -75,249 +76,26 @@ static std::string ToStringIfSet(const char* key, const rtc::Optional<T>& val) { > > template <class T> > static std::string VectorToString(const std::vector<T>& vals) { >- std::ostringstream ost; >- ost << "["; >- for (size_t i = 0; i < vals.size(); ++i) { >- if (i > 0) { >- ost << ", "; >- } >- ost << vals[i].ToString(); >+ std::ostringstream ost; // no-presubmit-check TODO(webrtc:8982) >+ ost << "["; >+ for (size_t i = 0; i < vals.size(); ++i) { >+ if (i > 0) { >+ ost << ", "; > } >- ost << "]"; >- return ost.str(); >-} >- >-// Construction-time settings, passed on when creating >-// MediaChannels. >-struct MediaConfig { >- // Set DSCP value on packets. This flag comes from the >- // PeerConnection constraint 'googDscp'. >- bool enable_dscp = false; >- >- // Video-specific config. >- struct Video { >- // Enable WebRTC CPU Overuse Detection. This flag comes from the >- // PeerConnection constraint 'googCpuOveruseDetection'. >- bool enable_cpu_overuse_detection = true; >- >- // Enable WebRTC suspension of video. No video frames will be sent >- // when the bitrate is below the configured minimum bitrate. This >- // flag comes from the PeerConnection constraint >- // 'googSuspendBelowMinBitrate', and WebRtcVideoChannel copies it >- // to VideoSendStream::Config::suspend_below_min_bitrate. >- bool suspend_below_min_bitrate = false; >- >- // Set to true if the renderer has an algorithm of frame selection. >- // If the value is true, then WebRTC will hand over a frame as soon as >- // possible without delay, and rendering smoothness is completely the duty >- // of the renderer; >- // If the value is false, then WebRTC is responsible to delay frame release >- // in order to increase rendering smoothness. >- // >- // This flag comes from PeerConnection's RtcConfiguration, but is >- // currently only set by the command line flag >- // 'disable-rtc-smoothness-algorithm'. >- // WebRtcVideoChannel::AddRecvStream copies it to the created >- // WebRtcVideoReceiveStream, where it is returned by the >- // SmoothsRenderedFrames method. This method is used by the >- // VideoReceiveStream, where the value is passed on to the >- // IncomingVideoStream constructor. >- bool disable_prerenderer_smoothing = false; >- >- // Enables periodic bandwidth probing in application-limited region. >- bool periodic_alr_bandwidth_probing = false; >- } video; >- >- bool operator==(const MediaConfig& o) const { >- return enable_dscp == o.enable_dscp && >- video.enable_cpu_overuse_detection == >- o.video.enable_cpu_overuse_detection && >- video.suspend_below_min_bitrate == >- o.video.suspend_below_min_bitrate && >- video.disable_prerenderer_smoothing == >- o.video.disable_prerenderer_smoothing && >- video.periodic_alr_bandwidth_probing == >- o.video.periodic_alr_bandwidth_probing; >- } >- >- bool operator!=(const MediaConfig& o) const { return !(*this == o); } >-}; >- >-// Options that can be applied to a VoiceMediaChannel or a VoiceMediaEngine. >-// Used to be flags, but that makes it hard to selectively apply options. >-// We are moving all of the setting of options to structs like this, >-// but some things currently still use flags. >-struct AudioOptions { >- void SetAll(const AudioOptions& change) { >- SetFrom(&echo_cancellation, change.echo_cancellation); >-#if defined(WEBRTC_IOS) >- SetFrom(&ios_force_software_aec_HACK, change.ios_force_software_aec_HACK); >-#endif >- SetFrom(&auto_gain_control, change.auto_gain_control); >- SetFrom(&noise_suppression, change.noise_suppression); >- SetFrom(&highpass_filter, change.highpass_filter); >- SetFrom(&stereo_swapping, change.stereo_swapping); >- SetFrom(&audio_jitter_buffer_max_packets, >- change.audio_jitter_buffer_max_packets); >- SetFrom(&audio_jitter_buffer_fast_accelerate, >- change.audio_jitter_buffer_fast_accelerate); >- SetFrom(&typing_detection, change.typing_detection); >- SetFrom(&aecm_generate_comfort_noise, change.aecm_generate_comfort_noise); >- SetFrom(&experimental_agc, change.experimental_agc); >- SetFrom(&extended_filter_aec, change.extended_filter_aec); >- SetFrom(&delay_agnostic_aec, change.delay_agnostic_aec); >- SetFrom(&experimental_ns, change.experimental_ns); >- SetFrom(&intelligibility_enhancer, change.intelligibility_enhancer); >- SetFrom(&level_control, change.level_control); >- SetFrom(&residual_echo_detector, change.residual_echo_detector); >- SetFrom(&tx_agc_target_dbov, change.tx_agc_target_dbov); >- SetFrom(&tx_agc_digital_compression_gain, >- change.tx_agc_digital_compression_gain); >- SetFrom(&tx_agc_limiter, change.tx_agc_limiter); >- SetFrom(&combined_audio_video_bwe, change.combined_audio_video_bwe); >- SetFrom(&audio_network_adaptor, change.audio_network_adaptor); >- SetFrom(&audio_network_adaptor_config, change.audio_network_adaptor_config); >- SetFrom(&level_control_initial_peak_level_dbfs, >- change.level_control_initial_peak_level_dbfs); >- } >- >- bool operator==(const AudioOptions& o) const { >- return echo_cancellation == o.echo_cancellation && >-#if defined(WEBRTC_IOS) >- ios_force_software_aec_HACK == o.ios_force_software_aec_HACK && >-#endif >- auto_gain_control == o.auto_gain_control && >- noise_suppression == o.noise_suppression && >- highpass_filter == o.highpass_filter && >- stereo_swapping == o.stereo_swapping && >- audio_jitter_buffer_max_packets == >- o.audio_jitter_buffer_max_packets && >- audio_jitter_buffer_fast_accelerate == >- o.audio_jitter_buffer_fast_accelerate && >- typing_detection == o.typing_detection && >- aecm_generate_comfort_noise == o.aecm_generate_comfort_noise && >- experimental_agc == o.experimental_agc && >- extended_filter_aec == o.extended_filter_aec && >- delay_agnostic_aec == o.delay_agnostic_aec && >- experimental_ns == o.experimental_ns && >- intelligibility_enhancer == o.intelligibility_enhancer && >- level_control == o.level_control && >- residual_echo_detector == o.residual_echo_detector && >- tx_agc_target_dbov == o.tx_agc_target_dbov && >- tx_agc_digital_compression_gain == >- o.tx_agc_digital_compression_gain && >- tx_agc_limiter == o.tx_agc_limiter && >- combined_audio_video_bwe == o.combined_audio_video_bwe && >- audio_network_adaptor == o.audio_network_adaptor && >- audio_network_adaptor_config == o.audio_network_adaptor_config && >- level_control_initial_peak_level_dbfs == >- o.level_control_initial_peak_level_dbfs; >- } >- bool operator!=(const AudioOptions& o) const { return !(*this == o); } >- >- std::string ToString() const { >- std::ostringstream ost; >- ost << "AudioOptions {"; >- ost << ToStringIfSet("aec", echo_cancellation); >-#if defined(WEBRTC_IOS) >- ost << ToStringIfSet("ios_force_software_aec_HACK", >- ios_force_software_aec_HACK); >-#endif >- ost << ToStringIfSet("agc", auto_gain_control); >- ost << ToStringIfSet("ns", noise_suppression); >- ost << ToStringIfSet("hf", highpass_filter); >- ost << ToStringIfSet("swap", stereo_swapping); >- ost << ToStringIfSet("audio_jitter_buffer_max_packets", >- audio_jitter_buffer_max_packets); >- ost << ToStringIfSet("audio_jitter_buffer_fast_accelerate", >- audio_jitter_buffer_fast_accelerate); >- ost << ToStringIfSet("typing", typing_detection); >- ost << ToStringIfSet("comfort_noise", aecm_generate_comfort_noise); >- ost << ToStringIfSet("experimental_agc", experimental_agc); >- ost << ToStringIfSet("extended_filter_aec", extended_filter_aec); >- ost << ToStringIfSet("delay_agnostic_aec", delay_agnostic_aec); >- ost << ToStringIfSet("experimental_ns", experimental_ns); >- ost << ToStringIfSet("intelligibility_enhancer", intelligibility_enhancer); >- ost << ToStringIfSet("level_control", level_control); >- ost << ToStringIfSet("level_control_initial_peak_level_dbfs", >- level_control_initial_peak_level_dbfs); >- ost << ToStringIfSet("residual_echo_detector", residual_echo_detector); >- ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov); >- ost << ToStringIfSet("tx_agc_digital_compression_gain", >- tx_agc_digital_compression_gain); >- ost << ToStringIfSet("tx_agc_limiter", tx_agc_limiter); >- ost << ToStringIfSet("combined_audio_video_bwe", combined_audio_video_bwe); >- ost << ToStringIfSet("audio_network_adaptor", audio_network_adaptor); >- // The adaptor config is a serialized proto buffer and therefore not human >- // readable. So we comment out the following line. >- // ost << ToStringIfSet("audio_network_adaptor_config", >- // audio_network_adaptor_config); >- ost << "}"; >- return ost.str(); >+ ost << vals[i].ToString(); > } >- >- // Audio processing that attempts to filter away the output signal from >- // later inbound pickup. >- rtc::Optional<bool> echo_cancellation; >-#if defined(WEBRTC_IOS) >- // Forces software echo cancellation on iOS. This is a temporary workaround >- // (until Apple fixes the bug) for a device with non-functioning AEC. May >- // improve performance on that particular device, but will cause unpredictable >- // behavior in all other cases. See http://bugs.webrtc.org/8682. >- rtc::Optional<bool> ios_force_software_aec_HACK; >-#endif >- // Audio processing to adjust the sensitivity of the local mic dynamically. >- rtc::Optional<bool> auto_gain_control; >- // Audio processing to filter out background noise. >- rtc::Optional<bool> noise_suppression; >- // Audio processing to remove background noise of lower frequencies. >- rtc::Optional<bool> highpass_filter; >- // Audio processing to swap the left and right channels. >- rtc::Optional<bool> stereo_swapping; >- // Audio receiver jitter buffer (NetEq) max capacity in number of packets. >- rtc::Optional<int> audio_jitter_buffer_max_packets; >- // Audio receiver jitter buffer (NetEq) fast accelerate mode. >- rtc::Optional<bool> audio_jitter_buffer_fast_accelerate; >- // Audio processing to detect typing. >- rtc::Optional<bool> typing_detection; >- rtc::Optional<bool> aecm_generate_comfort_noise; >- rtc::Optional<bool> experimental_agc; >- rtc::Optional<bool> extended_filter_aec; >- rtc::Optional<bool> delay_agnostic_aec; >- rtc::Optional<bool> experimental_ns; >- rtc::Optional<bool> intelligibility_enhancer; >- rtc::Optional<bool> level_control; >- // Specifies an optional initialization value for the level controller. >- rtc::Optional<float> level_control_initial_peak_level_dbfs; >- // Note that tx_agc_* only applies to non-experimental AGC. >- rtc::Optional<bool> residual_echo_detector; >- rtc::Optional<uint16_t> tx_agc_target_dbov; >- rtc::Optional<uint16_t> tx_agc_digital_compression_gain; >- rtc::Optional<bool> tx_agc_limiter; >- // Enable combined audio+bandwidth BWE. >- // TODO(pthatcher): This flag is set from the >- // "googCombinedAudioVideoBwe", but not used anywhere. So delete it, >- // and check if any other AudioOptions members are unused. >- rtc::Optional<bool> combined_audio_video_bwe; >- // Enable audio network adaptor. >- rtc::Optional<bool> audio_network_adaptor; >- // Config string for audio network adaptor. >- rtc::Optional<std::string> audio_network_adaptor_config; >- >- private: >- template <typename T> >- static void SetFrom(rtc::Optional<T>* s, const rtc::Optional<T>& o) { >- if (o) { >- *s = o; >- } >- } >-}; >+ ost << "]"; >+ return ost.str(); >+} > > // Options that can be applied to a VideoMediaChannel or a VideoMediaEngine. > // Used to be flags, but that makes it hard to selectively apply options. > // We are moving all of the setting of options to structs like this, > // but some things currently still use flags. > struct VideoOptions { >+ VideoOptions(); >+ ~VideoOptions(); >+ > void SetAll(const VideoOptions& change) { > SetFrom(&video_noise_reduction, change.video_noise_reduction); > SetFrom(&screencast_min_bitrate_kbps, change.screencast_min_bitrate_kbps); >@@ -345,20 +123,20 @@ struct VideoOptions { > // Enable denoising? This flag comes from the getUserMedia > // constraint 'googNoiseReduction', and WebRtcVideoEngine passes it > // on to the codec options. Disabled by default. >- rtc::Optional<bool> video_noise_reduction; >+ absl::optional<bool> video_noise_reduction; > // Force screencast to use a minimum bitrate. This flag comes from > // the PeerConnection constraint 'googScreencastMinBitrate'. It is > // copied to the encoder config by WebRtcVideoChannel. >- rtc::Optional<int> screencast_min_bitrate_kbps; >+ absl::optional<int> screencast_min_bitrate_kbps; > // Set by screencast sources. Implies selection of encoding settings > // suitable for screencast. Most likely not the right way to do > // things, e.g., screencast of a text document and screencast of a > // youtube video have different needs. >- rtc::Optional<bool> is_screencast; >+ absl::optional<bool> is_screencast; > > private: > template <typename T> >- static void SetFrom(rtc::Optional<T>* s, const rtc::Optional<T>& o) { >+ static void SetFrom(absl::optional<T>* s, const absl::optional<T>& o) { > if (o) { > *s = o; > } >@@ -392,7 +170,8 @@ class MediaChannel : public sigslot::has_slots<> { > const rtc::PacketOptions& options) = 0; > virtual bool SendRtcp(rtc::CopyOnWriteBuffer* packet, > const rtc::PacketOptions& options) = 0; >- virtual int SetOption(SocketType type, rtc::Socket::Option opt, >+ virtual int SetOption(SocketType type, >+ rtc::Socket::Option opt, > int option) = 0; > virtual ~NetworkInterface() {} > }; >@@ -400,17 +179,11 @@ class MediaChannel : public sigslot::has_slots<> { > explicit MediaChannel(const MediaConfig& config) > : enable_dscp_(config.enable_dscp), network_interface_(NULL) {} > MediaChannel() : enable_dscp_(false), network_interface_(NULL) {} >- virtual ~MediaChannel() {} >+ ~MediaChannel() override {} > > // Sets the abstract interface class for sending RTP/RTCP data. >- virtual void SetInterface(NetworkInterface *iface) { >- rtc::CritScope cs(&network_interface_crit_); >- network_interface_ = iface; >- SetDscp(enable_dscp_ ? PreferredDscp() : rtc::DSCP_DEFAULT); >- } >- virtual rtc::DiffServCodePoint PreferredDscp() const { >- return rtc::DSCP_DEFAULT; >- } >+ virtual void SetInterface(NetworkInterface* iface); >+ virtual rtc::DiffServCodePoint PreferredDscp() const; > // Called when a RTP packet is received. > virtual void OnPacketReceived(rtc::CopyOnWriteBuffer* packet, > const rtc::PacketTime& packet_time) = 0; >@@ -427,11 +200,13 @@ class MediaChannel : public sigslot::has_slots<> { > // by sp. > virtual bool AddSendStream(const StreamParams& sp) = 0; > // Removes an outgoing media stream. >- // ssrc must be the first SSRC of the media stream if the stream uses >- // multiple SSRCs. >+ // SSRC must be the first SSRC of the media stream if the stream uses >+ // multiple SSRCs. In the case of an ssrc of 0, the possibly cached >+ // StreamParams is removed. > virtual bool RemoveSendStream(uint32_t ssrc) = 0; >- // Creates a new incoming media stream with SSRCs and CNAME as described >- // by sp. >+ // Creates a new incoming media stream with SSRCs, CNAME as described >+ // by sp. In the case of a sp without SSRCs, the unsignaled sp is cached >+ // to be used later for unsignaled streams received. > virtual bool AddRecvStream(const StreamParams& sp) = 0; > // Removes an incoming media stream. > // ssrc must be the first SSRC of the media stream if the stream uses >@@ -439,9 +214,7 @@ class MediaChannel : public sigslot::has_slots<> { > virtual bool RemoveRecvStream(uint32_t ssrc) = 0; > > // Returns the absoulte sendtime extension id value from media channel. >- virtual int GetRtpSendTimeExtnId() const { >- return -1; >- } >+ virtual int GetRtpSendTimeExtnId() const; > > // Base method to send packet using NetworkInterface. > bool SendPacket(rtc::CopyOnWriteBuffer* packet, >@@ -468,13 +241,9 @@ class MediaChannel : public sigslot::has_slots<> { > // This method sets DSCP |value| on both RTP and RTCP channels. > int SetDscp(rtc::DiffServCodePoint value) { > int ret; >- ret = SetOption(NetworkInterface::ST_RTP, >- rtc::Socket::OPT_DSCP, >- value); >+ ret = SetOption(NetworkInterface::ST_RTP, rtc::Socket::OPT_DSCP, value); > if (ret == 0) { >- ret = SetOption(NetworkInterface::ST_RTCP, >- rtc::Socket::OPT_DSCP, >- value); >+ ret = SetOption(NetworkInterface::ST_RTCP, rtc::Socket::OPT_DSCP, value); > } > return ret; > } >@@ -516,9 +285,9 @@ struct SsrcReceiverInfo { > }; > > struct MediaSenderInfo { >- void add_ssrc(const SsrcSenderInfo& stat) { >- local_stats.push_back(stat); >- } >+ MediaSenderInfo(); >+ ~MediaSenderInfo(); >+ void add_ssrc(const SsrcSenderInfo& stat) { local_stats.push_back(stat); } > // Temporary utility function for call sites that only provide SSRC. > // As more info is added into SsrcSenderInfo, this function should go away. > void add_ssrc(uint32_t ssrc) { >@@ -535,11 +304,15 @@ struct MediaSenderInfo { > } > return retval; > } >+ // Returns true if the media has been connected. >+ bool connected() const { return local_stats.size() > 0; } > // Utility accessor for clients that make the assumption only one ssrc > // exists per media. > // This will eventually go away. >+ // Call sites that compare this to zero should use connected() instead. >+ // https://bugs.webrtc.org/8694 > uint32_t ssrc() const { >- if (local_stats.size() > 0) { >+ if (connected()) { > return local_stats[0].ssrc; > } else { > return 0; >@@ -551,15 +324,15 @@ struct MediaSenderInfo { > float fraction_lost = 0.0f; > int64_t rtt_ms = 0; > std::string codec_name; >- rtc::Optional<int> codec_payload_type; >+ absl::optional<int> codec_payload_type; > std::vector<SsrcSenderInfo> local_stats; > std::vector<SsrcReceiverInfo> remote_stats; > }; > > struct MediaReceiverInfo { >- void add_ssrc(const SsrcReceiverInfo& stat) { >- local_stats.push_back(stat); >- } >+ MediaReceiverInfo(); >+ ~MediaReceiverInfo(); >+ void add_ssrc(const SsrcReceiverInfo& stat) { local_stats.push_back(stat); } > // Temporary utility function for call sites that only provide SSRC. > // As more info is added into SsrcSenderInfo, this function should go away. > void add_ssrc(uint32_t ssrc) { >@@ -575,11 +348,15 @@ struct MediaReceiverInfo { > } > return retval; > } >+ // Returns true if the media has been connected. >+ bool connected() const { return local_stats.size() > 0; } > // Utility accessor for clients that make the assumption only one ssrc > // exists per media. > // This will eventually go away. >+ // Call sites that compare this to zero should use connected(); >+ // https://bugs.webrtc.org/8694 > uint32_t ssrc() const { >- if (local_stats.size() > 0) { >+ if (connected()) { > return local_stats[0].ssrc; > } else { > return 0; >@@ -591,12 +368,14 @@ struct MediaReceiverInfo { > int packets_lost = 0; > float fraction_lost = 0.0f; > std::string codec_name; >- rtc::Optional<int> codec_payload_type; >+ absl::optional<int> codec_payload_type; > std::vector<SsrcReceiverInfo> local_stats; > std::vector<SsrcSenderInfo> remote_stats; > }; > > struct VoiceSenderInfo : public MediaSenderInfo { >+ VoiceSenderInfo(); >+ ~VoiceSenderInfo(); > int ext_seqnum = 0; > int jitter_ms = 0; > int audio_level = 0; >@@ -618,6 +397,8 @@ struct VoiceSenderInfo : public MediaSenderInfo { > }; > > struct VoiceReceiverInfo : public MediaReceiverInfo { >+ VoiceReceiverInfo(); >+ ~VoiceReceiverInfo(); > int ext_seqnum = 0; > int jitter_ms = 0; > int jitter_buffer_ms = 0; >@@ -661,10 +442,11 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { > }; > > struct VideoSenderInfo : public MediaSenderInfo { >+ VideoSenderInfo(); >+ ~VideoSenderInfo(); > std::vector<SsrcGroup> ssrc_groups; > // TODO(hbos): Move this to |VideoMediaInfo::send_codecs|? > std::string encoder_implementation_name; >- int packets_cached = 0; > int firs_rcvd = 0; > int plis_rcvd = 0; > int nacks_rcvd = 0; >@@ -673,18 +455,21 @@ struct VideoSenderInfo : public MediaSenderInfo { > int framerate_input = 0; > int framerate_sent = 0; > int nominal_bitrate = 0; >- int preferred_bitrate = 0; > int adapt_reason = 0; > int adapt_changes = 0; > int avg_encode_ms = 0; > int encode_usage_percent = 0; > uint32_t frames_encoded = 0; > bool has_entered_low_resolution = false; >- rtc::Optional<uint64_t> qp_sum; >+ absl::optional<uint64_t> qp_sum; > webrtc::VideoContentType content_type = webrtc::VideoContentType::UNSPECIFIED; >+ // https://w3c.github.io/webrtc-stats/#dom-rtcvideosenderstats-hugeframessent >+ uint32_t huge_frames_sent = 0; > }; > > struct VideoReceiverInfo : public MediaReceiverInfo { >+ VideoReceiverInfo(); >+ ~VideoReceiverInfo(); > std::vector<SsrcGroup> ssrc_groups; > // TODO(hbos): Move this to |VideoMediaInfo::receive_codecs|? > std::string decoder_implementation_name; >@@ -704,7 +489,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo { > uint32_t frames_received = 0; > uint32_t frames_decoded = 0; > uint32_t frames_rendered = 0; >- rtc::Optional<uint64_t> qp_sum; >+ absl::optional<uint64_t> qp_sum; > int64_t interframe_delay_max_ms = -1; > > webrtc::VideoContentType content_type = webrtc::VideoContentType::UNSPECIFIED; >@@ -734,7 +519,7 @@ struct VideoReceiverInfo : public MediaReceiverInfo { > > // Timing frame info: all important timestamps for a full lifetime of a > // single 'timing frame'. >- rtc::Optional<webrtc::TimingFrameInfo> timing_frame_info; >+ absl::optional<webrtc::TimingFrameInfo> timing_frame_info; > }; > > struct DataSenderInfo : public MediaSenderInfo { >@@ -759,6 +544,8 @@ struct BandwidthEstimationInfo { > typedef std::map<int, webrtc::RtpCodecParameters> RtpCodecParametersMap; > > struct VoiceMediaInfo { >+ VoiceMediaInfo(); >+ ~VoiceMediaInfo(); > void Clear() { > senders.clear(); > receivers.clear(); >@@ -772,6 +559,8 @@ struct VoiceMediaInfo { > }; > > struct VideoMediaInfo { >+ VideoMediaInfo(); >+ ~VideoMediaInfo(); > void Clear() { > senders.clear(); > receivers.clear(); >@@ -789,6 +578,8 @@ struct VideoMediaInfo { > }; > > struct DataMediaInfo { >+ DataMediaInfo(); >+ ~DataMediaInfo(); > void Clear() { > senders.clear(); > receivers.clear(); >@@ -803,67 +594,71 @@ struct RtcpParameters { > > template <class Codec> > struct RtpParameters { >- virtual std::string ToString() const { >- std::ostringstream ost; >- ost << "{"; >- ost << "codecs: " << VectorToString(codecs) << ", "; >- ost << "extensions: " << VectorToString(extensions); >- ost << "}"; >- return ost.str(); >- } >+ virtual ~RtpParameters() = default; > > std::vector<Codec> codecs; > std::vector<webrtc::RtpExtension> extensions; > // TODO(pthatcher): Add streams. > RtcpParameters rtcp; >- virtual ~RtpParameters() = default; >-}; > >-// TODO(deadbeef): Rename to RtpSenderParameters, since they're intended to >-// encapsulate all the parameters needed for an RtpSender. >-template <class Codec> >-struct RtpSendParameters : RtpParameters<Codec> { >- std::string ToString() const override { >+ std::string ToString() const { > std::ostringstream ost; > ost << "{"; >- ost << "codecs: " << VectorToString(this->codecs) << ", "; >- ost << "extensions: " << VectorToString(this->extensions) << ", "; >- ost << "max_bandwidth_bps: " << max_bandwidth_bps << ", "; >+ const char* separator = ""; >+ for (const auto& entry : ToStringMap()) { >+ ost << separator << entry.first << ": " << entry.second; >+ separator = ", "; >+ } > ost << "}"; > return ost.str(); > } > >- int max_bandwidth_bps = -1; >+ protected: >+ virtual std::map<std::string, std::string> ToStringMap() const { >+ return {{"codecs", VectorToString(codecs)}, >+ {"extensions", VectorToString(extensions)}}; >+ } > }; > >-struct AudioSendParameters : RtpSendParameters<AudioCodec> { >- std::string ToString() const override { >- std::ostringstream ost; >- ost << "{"; >- ost << "codecs: " << VectorToString(this->codecs) << ", "; >- ost << "extensions: " << VectorToString(this->extensions) << ", "; >- ost << "max_bandwidth_bps: " << max_bandwidth_bps << ", "; >- ost << "options: " << options.ToString(); >- ost << "}"; >- return ost.str(); >+// TODO(deadbeef): Rename to RtpSenderParameters, since they're intended to >+// encapsulate all the parameters needed for an RtpSender. >+template <class Codec> >+struct RtpSendParameters : RtpParameters<Codec> { >+ int max_bandwidth_bps = -1; >+ // This is the value to be sent in the MID RTP header extension (if the header >+ // extension in included in the list of extensions). >+ std::string mid; >+ >+ protected: >+ std::map<std::string, std::string> ToStringMap() const override { >+ auto params = RtpParameters<Codec>::ToStringMap(); >+ params["max_bandwidth_bps"] = rtc::ToString(max_bandwidth_bps); >+ params["mid"] = (mid.empty() ? "<not set>" : mid); >+ return params; > } >+}; > >+struct AudioSendParameters : RtpSendParameters<AudioCodec> { >+ AudioSendParameters(); >+ ~AudioSendParameters() override; > AudioOptions options; >-}; > >-struct AudioRecvParameters : RtpParameters<AudioCodec> { >+ protected: >+ std::map<std::string, std::string> ToStringMap() const override; > }; > >+struct AudioRecvParameters : RtpParameters<AudioCodec> {}; >+ > class VoiceMediaChannel : public MediaChannel { > public: > VoiceMediaChannel() {} > explicit VoiceMediaChannel(const MediaConfig& config) > : MediaChannel(config) {} >- virtual ~VoiceMediaChannel() {} >+ ~VoiceMediaChannel() override {} > virtual bool SetSendParameters(const AudioSendParameters& params) = 0; > virtual bool SetRecvParameters(const AudioRecvParameters& params) = 0; > virtual webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const = 0; >- virtual bool SetRtpSendParameters( >+ virtual webrtc::RTCError SetRtpSendParameters( > uint32_t ssrc, > const webrtc::RtpParameters& parameters) = 0; > // Get the receive parameters for the incoming stream identified by |ssrc|. >@@ -885,11 +680,6 @@ class VoiceMediaChannel : public MediaChannel { > bool enable, > const AudioOptions* options, > AudioSource* source) = 0; >- // Gets current energy levels for all incoming streams. >- typedef std::vector<std::pair<uint32_t, int>> StreamList; >- virtual bool GetActiveStreams(StreamList* actives) = 0; >- // Get the current energy level of the stream sent to the speaker. >- virtual int GetOutputLevel() = 0; > // Set speaker output volume of the specified ssrc. > virtual bool SetOutputVolume(uint32_t ssrc, double volume) = 0; > // Returns if the telephone-event has been negotiated. >@@ -912,6 +702,8 @@ class VoiceMediaChannel : public MediaChannel { > // TODO(deadbeef): Rename to VideoSenderParameters, since they're intended to > // encapsulate all the parameters needed for a video RtpSender. > struct VideoSendParameters : RtpSendParameters<VideoCodec> { >+ VideoSendParameters(); >+ ~VideoSendParameters() override; > // Use conference mode? This flag comes from the remote > // description's SDP line 'a=x-google-flag:conference', copied over > // by VideoChannel::SetRemoteContent_w, and ultimately used by >@@ -919,24 +711,26 @@ struct VideoSendParameters : RtpSendParameters<VideoCodec> { > // WebRtcVideoChannel::WebRtcVideoSendStream::CreateVideoEncoderConfig. > // The special screencast behaviour is disabled by default. > bool conference_mode = false; >+ >+ protected: >+ std::map<std::string, std::string> ToStringMap() const override; > }; > > // TODO(deadbeef): Rename to VideoReceiverParameters, since they're intended to > // encapsulate all the parameters needed for a video RtpReceiver. >-struct VideoRecvParameters : RtpParameters<VideoCodec> { >-}; >+struct VideoRecvParameters : RtpParameters<VideoCodec> {}; > > class VideoMediaChannel : public MediaChannel { > public: > VideoMediaChannel() {} > explicit VideoMediaChannel(const MediaConfig& config) > : MediaChannel(config) {} >- virtual ~VideoMediaChannel() {} >+ ~VideoMediaChannel() override {} > > virtual bool SetSendParameters(const VideoSendParameters& params) = 0; > virtual bool SetRecvParameters(const VideoRecvParameters& params) = 0; > virtual webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const = 0; >- virtual bool SetRtpSendParameters( >+ virtual webrtc::RTCError SetRtpSendParameters( > uint32_t ssrc, > const webrtc::RtpParameters& parameters) = 0; > // Get the receive parameters for the incoming stream identified by |ssrc|. >@@ -957,7 +751,6 @@ class VideoMediaChannel : public MediaChannel { > // The |ssrc| must correspond to a registered send stream. > virtual bool SetVideoSend( > uint32_t ssrc, >- bool enable, > const VideoOptions* options, > rtc::VideoSourceInterface<webrtc::VideoFrame>* source) = 0; > // Sets the sink object to be used for the specified stream. >@@ -1033,47 +826,34 @@ struct SendDataParams { > > enum SendDataResult { SDR_SUCCESS, SDR_ERROR, SDR_BLOCK }; > >-struct DataSendParameters : RtpSendParameters<DataCodec> { >- std::string ToString() const { >- std::ostringstream ost; >- // Options and extensions aren't used. >- ost << "{"; >- ost << "codecs: " << VectorToString(codecs) << ", "; >- ost << "max_bandwidth_bps: " << max_bandwidth_bps; >- ost << "}"; >- return ost.str(); >- } >-}; >+struct DataSendParameters : RtpSendParameters<DataCodec> {}; > >-struct DataRecvParameters : RtpParameters<DataCodec> { >-}; >+struct DataRecvParameters : RtpParameters<DataCodec> {}; > > class DataMediaChannel : public MediaChannel { > public: >- DataMediaChannel() {} >- explicit DataMediaChannel(const MediaConfig& config) : MediaChannel(config) {} >- virtual ~DataMediaChannel() {} >+ DataMediaChannel(); >+ explicit DataMediaChannel(const MediaConfig& config); >+ ~DataMediaChannel() override; > > virtual bool SetSendParameters(const DataSendParameters& params) = 0; > virtual bool SetRecvParameters(const DataRecvParameters& params) = 0; > > // TODO(pthatcher): Implement this. >- virtual bool GetStats(DataMediaInfo*) { return true; } >+ virtual bool GetStats(DataMediaInfo* info); > > virtual bool SetSend(bool send) = 0; > virtual bool SetReceive(bool receive) = 0; > >- virtual void OnNetworkRouteChanged(const std::string&, >- const rtc::NetworkRoute&) {} >+ void OnNetworkRouteChanged(const std::string& transport_name, >+ const rtc::NetworkRoute& network_route) override {} > >- virtual bool SendData( >- const SendDataParams& params, >- const rtc::CopyOnWriteBuffer& payload, >- SendDataResult* result = NULL) = 0; >+ virtual bool SendData(const SendDataParams& params, >+ const rtc::CopyOnWriteBuffer& payload, >+ SendDataResult* result = NULL) = 0; > // Signals when data is received (params, data, len) >- sigslot::signal3<const ReceiveDataParams&, >- const char*, >- size_t> SignalDataReceived; >+ sigslot::signal3<const ReceiveDataParams&, const char*, size_t> >+ SignalDataReceived; > // Signal when the media channel is ready to send the stream. Arguments are: > // writable(bool) > sigslot::signal1<bool> SignalReadyToSend; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconfig.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconfig.h >new file mode 100644 >index 00000000000..eda387e3191 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconfig.h >@@ -0,0 +1,82 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef MEDIA_BASE_MEDIACONFIG_H_ >+#define MEDIA_BASE_MEDIACONFIG_H_ >+ >+namespace cricket { >+ >+// Construction-time settings, passed on when creating >+// MediaChannels. >+struct MediaConfig { >+ // Set DSCP value on packets. This flag comes from the >+ // PeerConnection constraint 'googDscp'. >+ bool enable_dscp = false; >+ >+ // Video-specific config. >+ struct Video { >+ // Enable WebRTC CPU Overuse Detection. This flag comes from the >+ // PeerConnection constraint 'googCpuOveruseDetection'. >+ bool enable_cpu_adaptation = true; >+ >+ // Enable WebRTC suspension of video. No video frames will be sent >+ // when the bitrate is below the configured minimum bitrate. This >+ // flag comes from the PeerConnection constraint >+ // 'googSuspendBelowMinBitrate', and WebRtcVideoChannel copies it >+ // to VideoSendStream::Config::suspend_below_min_bitrate. >+ bool suspend_below_min_bitrate = false; >+ >+ // Set to true if the renderer has an algorithm of frame selection. >+ // If the value is true, then WebRTC will hand over a frame as soon as >+ // possible without delay, and rendering smoothness is completely the duty >+ // of the renderer; >+ // If the value is false, then WebRTC is responsible to delay frame release >+ // in order to increase rendering smoothness. >+ // >+ // This flag comes from PeerConnection's RtcConfiguration, but is >+ // currently only set by the command line flag >+ // 'disable-rtc-smoothness-algorithm'. >+ // WebRtcVideoChannel::AddRecvStream copies it to the created >+ // WebRtcVideoReceiveStream, where it is returned by the >+ // SmoothsRenderedFrames method. This method is used by the >+ // VideoReceiveStream, where the value is passed on to the >+ // IncomingVideoStream constructor. >+ bool enable_prerenderer_smoothing = true; >+ >+ // Enables periodic bandwidth probing in application-limited region. >+ bool periodic_alr_bandwidth_probing = false; >+ >+ // Enables the new method to estimate the cpu load from encoding, used for >+ // cpu adaptation. This flag is intended to be controlled primarily by a >+ // Chrome origin-trial. >+ // TODO(bugs.webrtc.org/8504): If all goes well, the flag will be removed >+ // together with the old method of estimation. >+ bool experiment_cpu_load_estimator = false; >+ } video; >+ >+ bool operator==(const MediaConfig& o) const { >+ return enable_dscp == o.enable_dscp && >+ video.enable_cpu_adaptation == o.video.enable_cpu_adaptation && >+ video.suspend_below_min_bitrate == >+ o.video.suspend_below_min_bitrate && >+ video.enable_prerenderer_smoothing == >+ o.video.enable_prerenderer_smoothing && >+ video.periodic_alr_bandwidth_probing == >+ o.video.periodic_alr_bandwidth_probing && >+ video.experiment_cpu_load_estimator == >+ o.video.experiment_cpu_load_estimator; >+ } >+ >+ bool operator!=(const MediaConfig& o) const { return !(*this == o); } >+}; >+ >+} // namespace cricket >+ >+#endif // MEDIA_BASE_MEDIACONFIG_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.cc >index 9496d9f60ca..522adf3c699 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.cc >@@ -25,7 +25,7 @@ const float kProcessCpuThreshold = 0.10f; > const char kRtxCodecName[] = "rtx"; > const char kRedCodecName[] = "red"; > const char kUlpfecCodecName[] = "ulpfec"; >-const char kStereoCodecName[] = "stereo"; >+const char kMultiplexCodecName[] = "multiplex"; > > // TODO(brandtr): Change this to 'flexfec' when we are confident that the > // header format is not changing anymore. >@@ -39,12 +39,12 @@ const char kCodecParamAssociatedCodecName[] = "acn"; > > const char kOpusCodecName[] = "opus"; > const char kIsacCodecName[] = "ISAC"; >-const char kL16CodecName[] = "L16"; >+const char kL16CodecName[] = "L16"; > const char kG722CodecName[] = "G722"; > const char kIlbcCodecName[] = "ILBC"; > const char kPcmuCodecName[] = "PCMU"; > const char kPcmaCodecName[] = "PCMA"; >-const char kCnCodecName[] = "CN"; >+const char kCnCodecName[] = "CN"; > const char kDtmfCodecName[] = "telephone-event"; > > // draft-spittka-payload-rtp-opus-03.txt >@@ -86,6 +86,7 @@ const char kRtcpFbParamTransportCc[] = "transport-cc"; > > const char kRtcpFbParamCcm[] = "ccm"; > const char kRtcpFbCcmParamFir[] = "fir"; >+const char kRtcpFbParamRrtr[] = "rrtr"; > const char kCodecParamMaxBitrate[] = "x-google-max-bitrate"; > const char kCodecParamMinBitrate[] = "x-google-min-bitrate"; > const char kCodecParamStartBitrate[] = "x-google-start-bitrate"; >@@ -112,4 +113,8 @@ const char kH264FmtpSpropParameterSets[] = "sprop-parameter-sets"; > const char kH264ProfileLevelConstrainedBaseline[] = "42e01f"; > > const int kDefaultVideoMaxFramerate = 60; >+ >+const size_t kConferenceMaxNumSpatialLayers = 3; >+const size_t kConferenceMaxNumTemporalLayers = 3; >+const size_t kConferenceDefaultNumTemporalLayers = 3; > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.h >index 58a66d917a8..14c49baf72c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaconstants.h >@@ -30,7 +30,7 @@ extern const char kRtxCodecName[]; > extern const char kRedCodecName[]; > extern const char kUlpfecCodecName[]; > extern const char kFlexfecCodecName[]; >-extern const char kStereoCodecName[]; >+extern const char kMultiplexCodecName[]; > > extern const char kFlexfecFmtpRepairWindow[]; > >@@ -101,6 +101,9 @@ extern const char kRtcpFbParamTransportCc[]; > // ccm submessages according to RFC 5104 > extern const char kRtcpFbParamCcm[]; > extern const char kRtcpFbCcmParamFir[]; >+// Receiver reference time report >+// https://tools.ietf.org/html/rfc3611 section 4.4 >+extern const char kRtcpFbParamRrtr[]; > // Google specific parameters > extern const char kCodecParamMaxBitrate[]; > extern const char kCodecParamMinBitrate[]; >@@ -134,6 +137,10 @@ extern const char kH264FmtpSpropParameterSets[]; > extern const char kH264ProfileLevelConstrainedBaseline[]; > > extern const int kDefaultVideoMaxFramerate; >+ >+extern const size_t kConferenceMaxNumSpatialLayers; >+extern const size_t kConferenceMaxNumTemporalLayers; >+extern const size_t kConferenceDefaultNumTemporalLayers; > } // namespace cricket > > #endif // MEDIA_BASE_MEDIACONSTANTS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.cc >index 281ddbb76f7..b0fede3a2a5 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.cc >@@ -10,25 +10,10 @@ > > #include "media/base/mediaengine.h" > >-#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) >- > namespace cricket { > >-MediaEngineFactory::MediaEngineCreateFunction >- MediaEngineFactory::create_function_ = NULL; >- >-MediaEngineFactory::MediaEngineCreateFunction >- MediaEngineFactory::SetCreateFunction(MediaEngineCreateFunction function) { >- MediaEngineCreateFunction old_function = create_function_; >- create_function_ = function; >- return old_function; >-} >- >-}; // namespace cricket >- >-#endif // DISABLE_MEDIA_ENGINE_FACTORY >- >-namespace cricket { >+RtpCapabilities::RtpCapabilities() = default; >+RtpCapabilities::~RtpCapabilities() = default; > > webrtc::RtpParameters CreateRtpParametersWithOneEncoding() { > webrtc::RtpParameters parameters; >@@ -37,4 +22,19 @@ webrtc::RtpParameters CreateRtpParametersWithOneEncoding() { > return parameters; > } > >+webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp) { >+ std::vector<uint32_t> primary_ssrcs; >+ sp.GetPrimarySsrcs(&primary_ssrcs); >+ size_t encoding_count = primary_ssrcs.size(); >+ >+ std::vector<webrtc::RtpEncodingParameters> encodings(encoding_count); >+ for (size_t i = 0; i < encodings.size(); ++i) { >+ encodings[i].ssrc = primary_ssrcs[i]; >+ } >+ webrtc::RtpParameters parameters; >+ parameters.encodings = encodings; >+ parameters.rtcp.cname = sp.cname; >+ return parameters; >+} >+ > }; // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.h >index 483a96b7e89..57979c27574 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/mediaengine.h >@@ -29,20 +29,18 @@ > #include "media/base/videocommon.h" > #include "rtc_base/platform_file.h" > >-#if defined(GOOGLE_CHROME_BUILD) || defined(CHROMIUM_BUILD) >-#define DISABLE_MEDIA_ENGINE_FACTORY >-#endif >- > namespace webrtc { > class AudioDeviceModule; > class AudioMixer; > class AudioProcessing; > class Call; >-} >+} // namespace webrtc > > namespace cricket { > > struct RtpCapabilities { >+ RtpCapabilities(); >+ ~RtpCapabilities(); > std::vector<webrtc::RtpExtension> header_extensions; > }; > >@@ -72,9 +70,6 @@ class MediaEngineInterface { > const MediaConfig& config, > const VideoOptions& options) = 0; > >- // Gets the current microphone level, as a value between 0 and 10. >- virtual int GetInputLevel() = 0; >- > virtual const std::vector<AudioCodec>& audio_send_codecs() = 0; > virtual const std::vector<AudioCodec>& audio_recv_codecs() = 0; > virtual RtpCapabilities GetAudioCapabilities() = 0; >@@ -90,25 +85,6 @@ class MediaEngineInterface { > virtual void StopAecDump() = 0; > }; > >- >-#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) >-class MediaEngineFactory { >- public: >- typedef cricket::MediaEngineInterface* (*MediaEngineCreateFunction)(); >- // Creates a media engine, using either the compiled system default or the >- // creation function specified in SetCreateFunction, if specified. >- static MediaEngineInterface* Create(); >- // Sets the function used when calling Create. If unset, the compiled system >- // default will be used. Returns the old create function, or NULL if one >- // wasn't set. Likewise, NULL can be used as the |function| parameter to >- // reset to the default behavior. >- static MediaEngineCreateFunction SetCreateFunction( >- MediaEngineCreateFunction function); >- private: >- static MediaEngineCreateFunction create_function_; >-}; >-#endif >- > // CompositeMediaEngine constructs a MediaEngine from separate > // voice and video engine classes. > template <class VOICE, class VIDEO> >@@ -141,7 +117,6 @@ class CompositeMediaEngine : public MediaEngineInterface { > return video().CreateChannel(call, config, options); > } > >- virtual int GetInputLevel() { return voice().GetInputLevel(); } > virtual const std::vector<AudioCodec>& audio_send_codecs() { > return voice().send_codecs(); > } >@@ -182,6 +157,7 @@ class DataEngineInterface { > }; > > webrtc::RtpParameters CreateRtpParametersWithOneEncoding(); >+webrtc::RtpParameters CreateRtpParametersWithEncodings(StreamParams sp); > > } // namespace cricket > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.cc >index 7cb5fa85859..fc2b73141ed 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.cc >@@ -17,9 +17,9 @@ > #include "media/base/rtputils.h" > #include "media/base/streamparams.h" > #include "rtc_base/copyonwritebuffer.h" >+#include "rtc_base/data_rate_limiter.h" > #include "rtc_base/helpers.h" > #include "rtc_base/logging.h" >-#include "rtc_base/ratelimiter.h" > #include "rtc_base/sanitizer.h" > #include "rtc_base/stringutils.h" > >@@ -28,9 +28,7 @@ namespace cricket { > // We want to avoid IP fragmentation. > static const size_t kDataMaxRtpPacketLen = 1200U; > // We reserve space after the RTP header for future wiggle room. >-static const unsigned char kReservedSpace[] = { >- 0x00, 0x00, 0x00, 0x00 >-}; >+static const unsigned char kReservedSpace[] = {0x00, 0x00, 0x00, 0x00}; > > // Amount of overhead SRTP may take. We need to leave room in the > // buffer for it, otherwise SRTP will fail later. If SRTP ever uses >@@ -42,8 +40,7 @@ RtpDataEngine::RtpDataEngine() { > DataCodec(kGoogleRtpDataCodecPlType, kGoogleRtpDataCodecName)); > } > >-DataMediaChannel* RtpDataEngine::CreateChannel( >- const MediaConfig& config) { >+DataMediaChannel* RtpDataEngine::CreateChannel(const MediaConfig& config) { > return new RtpDataMediaChannel(config); > } > >@@ -64,21 +61,19 @@ RtpDataMediaChannel::RtpDataMediaChannel(const MediaConfig& config) > void RtpDataMediaChannel::Construct() { > sending_ = false; > receiving_ = false; >- send_limiter_.reset(new rtc::RateLimiter(kDataMaxBandwidth / 8, 1.0)); >+ send_limiter_.reset(new rtc::DataRateLimiter(kDataMaxBandwidth / 8, 1.0)); > } > >- > RtpDataMediaChannel::~RtpDataMediaChannel() { > std::map<uint32_t, RtpClock*>::const_iterator iter; > for (iter = rtp_clock_by_send_ssrc_.begin(); >- iter != rtp_clock_by_send_ssrc_.end(); >- ++iter) { >+ iter != rtp_clock_by_send_ssrc_.end(); ++iter) { > delete iter->second; > } > } > > void RTC_NO_SANITIZE("float-cast-overflow") // bugs.webrtc.org/8204 >-RtpClock::Tick(double now, int* seq_num, uint32_t* timestamp) { >+ RtpClock::Tick(double now, int* seq_num, uint32_t* timestamp) { > *seq_num = ++last_seq_num_; > *timestamp = timestamp_offset_ + static_cast<uint32_t>(now * clockrate_); > // UBSan: 5.92374e+10 is outside the range of representable values of type >@@ -155,9 +150,9 @@ bool RtpDataMediaChannel::AddSendStream(const StreamParams& stream) { > send_streams_.push_back(stream); > // TODO(pthatcher): This should be per-stream, not per-ssrc. > // And we should probably allow more than one per stream. >- rtp_clock_by_send_ssrc_[stream.first_ssrc()] = new RtpClock( >- kDataCodecClockrate, >- rtc::CreateRandomNonZeroId(), rtc::CreateRandomNonZeroId()); >+ rtp_clock_by_send_ssrc_[stream.first_ssrc()] = >+ new RtpClock(kDataCodecClockrate, rtc::CreateRandomNonZeroId(), >+ rtc::CreateRandomNonZeroId()); > > RTC_LOG(LS_INFO) << "Added data send stream '" << stream.id > << "' with ssrc=" << stream.first_ssrc(); >@@ -198,22 +193,15 @@ bool RtpDataMediaChannel::RemoveRecvStream(uint32_t ssrc) { > return true; > } > >-void RtpDataMediaChannel::OnPacketReceived( >- rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) { >+void RtpDataMediaChannel::OnPacketReceived(rtc::CopyOnWriteBuffer* packet, >+ const rtc::PacketTime& packet_time) { > RtpHeader header; > if (!GetRtpHeader(packet->cdata(), packet->size(), &header)) { >- // Don't want to log for every corrupt packet. >- // RTC_LOG(LS_WARNING) << "Could not read rtp header from packet of length " >- // << packet->length() << "."; > return; > } > > size_t header_length; > if (!GetRtpHeaderLen(packet->cdata(), packet->size(), &header_length)) { >- // Don't want to log for every corrupt packet. >- // RTC_LOG(LS_WARNING) << "Could not read rtp header" >- // << length from packet of length " >- // << packet->length() << "."; > return; > } > const char* data = >@@ -227,12 +215,6 @@ void RtpDataMediaChannel::OnPacketReceived( > } > > if (!FindCodecById(recv_codecs_, header.payload_type)) { >- // For bundling, this will be logged for every message. >- // So disable this logging. >- // RTC_LOG(LS_WARNING) << "Not receiving packet " >- // << header.ssrc << ":" << header.seq_num >- // << " (" << data_len << ")" >- // << " because unknown payload id: " << header.payload_type; > return; > } > >@@ -261,16 +243,15 @@ bool RtpDataMediaChannel::SetMaxSendBandwidth(int bps) { > if (bps <= 0) { > bps = kDataMaxBandwidth; > } >- send_limiter_.reset(new rtc::RateLimiter(bps / 8, 1.0)); >+ send_limiter_.reset(new rtc::DataRateLimiter(bps / 8, 1.0)); > RTC_LOG(LS_INFO) << "RtpDataMediaChannel::SetSendBandwidth to " << bps > << "bps."; > return true; > } > >-bool RtpDataMediaChannel::SendData( >- const SendDataParams& params, >- const rtc::CopyOnWriteBuffer& payload, >- SendDataResult* result) { >+bool RtpDataMediaChannel::SendData(const SendDataParams& params, >+ const rtc::CopyOnWriteBuffer& payload, >+ SendDataResult* result) { > if (result) { > // If we return true, we'll set this to SDR_SUCCESS. > *result = SDR_ERROR; >@@ -323,8 +304,8 @@ bool RtpDataMediaChannel::SendData( > RtpHeader header; > header.payload_type = found_codec->id; > header.ssrc = params.ssrc; >- rtp_clock_by_send_ssrc_[header.ssrc]->Tick( >- now, &header.seq_num, &header.timestamp); >+ rtp_clock_by_send_ssrc_[header.ssrc]->Tick(now, &header.seq_num, >+ &header.timestamp); > > rtc::CopyOnWriteBuffer packet(kMinRtpPacketLen, packet_len); > if (!SetRtpHeader(packet.data(), packet.size(), header)) { >@@ -340,7 +321,9 @@ bool RtpDataMediaChannel::SendData( > << ", timestamp=" << header.timestamp > << ", len=" << payload.size(); > >- MediaChannel::SendPacket(&packet, rtc::PacketOptions()); >+ rtc::PacketOptions options; >+ options.info_signaled_after_sent.packet_type = rtc::PacketType::kData; >+ MediaChannel::SendPacket(&packet, options); > send_limiter_->Use(packet_len, now); > if (result) { > *result = SDR_SUCCESS; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.h >index 64e083b0fd9..966d0c81514 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine.h >@@ -20,6 +20,10 @@ > #include "media/base/mediaconstants.h" > #include "media/base/mediaengine.h" > >+namespace rtc { >+class DataRateLimiter; >+} >+ > namespace cricket { > > struct DataCodec; >@@ -30,9 +34,7 @@ class RtpDataEngine : public DataEngineInterface { > > virtual DataMediaChannel* CreateChannel(const MediaConfig& config); > >- virtual const std::vector<DataCodec>& data_codecs() { >- return data_codecs_; >- } >+ virtual const std::vector<DataCodec>& data_codecs() { return data_codecs_; } > > private: > std::vector<DataCodec> data_codecs_; >@@ -84,10 +86,9 @@ class RtpDataMediaChannel : public DataMediaChannel { > virtual void OnRtcpReceived(rtc::CopyOnWriteBuffer* packet, > const rtc::PacketTime& packet_time) {} > virtual void OnReadyToSend(bool ready) {} >- virtual bool SendData( >- const SendDataParams& params, >- const rtc::CopyOnWriteBuffer& payload, >- SendDataResult* result); >+ virtual bool SendData(const SendDataParams& params, >+ const rtc::CopyOnWriteBuffer& payload, >+ SendDataResult* result); > virtual rtc::DiffServCodePoint PreferredDscp() const; > > private: >@@ -103,7 +104,7 @@ class RtpDataMediaChannel : public DataMediaChannel { > std::vector<StreamParams> send_streams_; > std::vector<StreamParams> recv_streams_; > std::map<uint32_t, RtpClock*> rtp_clock_by_send_ssrc_; >- std::unique_ptr<rtc::RateLimiter> send_limiter_; >+ std::unique_ptr<rtc::DataRateLimiter> send_limiter_; > }; > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine_unittest.cc >index a05c3de2649..c15c55f5e62 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtpdataengine_unittest.cc >@@ -24,9 +24,9 @@ class FakeDataReceiver : public sigslot::has_slots<> { > public: > FakeDataReceiver() : has_received_data_(false) {} > >- void OnDataReceived( >- const cricket::ReceiveDataParams& params, >- const char* data, size_t len) { >+ void OnDataReceived(const cricket::ReceiveDataParams& params, >+ const char* data, >+ size_t len) { > has_received_data_ = true; > last_received_data_ = std::string(data, len); > last_received_data_len_ = len; >@@ -74,34 +74,24 @@ class RtpDataMediaChannelTest : public testing::Test { > cricket::RtpDataMediaChannel* channel = > static_cast<cricket::RtpDataMediaChannel*>(dme->CreateChannel(config)); > channel->SetInterface(iface_.get()); >- channel->SignalDataReceived.connect( >- receiver_.get(), &FakeDataReceiver::OnDataReceived); >+ channel->SignalDataReceived.connect(receiver_.get(), >+ &FakeDataReceiver::OnDataReceived); > return channel; > } > >- FakeDataReceiver* receiver() { >- return receiver_.get(); >- } >+ FakeDataReceiver* receiver() { return receiver_.get(); } > >- bool HasReceivedData() { >- return receiver_->has_received_data(); >- } >+ bool HasReceivedData() { return receiver_->has_received_data(); } > >- std::string GetReceivedData() { >- return receiver_->last_received_data(); >- } >+ std::string GetReceivedData() { return receiver_->last_received_data(); } > >- size_t GetReceivedDataLen() { >- return receiver_->last_received_data_len(); >- } >+ size_t GetReceivedDataLen() { return receiver_->last_received_data_len(); } > > cricket::ReceiveDataParams GetReceivedDataParams() { > return receiver_->last_received_data_params(); > } > >- bool HasSentData(int count) { >- return (iface_->NumRtpPackets() > count); >- } >+ bool HasSentData(int count) { return (iface_->NumRtpPackets() > count); } > > std::string GetSentData(int index) { > // Assume RTP header of length 12 >@@ -202,8 +192,7 @@ TEST_F(RtpDataMediaChannelTest, SendData) { > unsigned char data[] = "food"; > rtc::CopyOnWriteBuffer payload(data, 4); > unsigned char padded_data[] = { >- 0x00, 0x00, 0x00, 0x00, >- 'f', 'o', 'o', 'd', >+ 0x00, 0x00, 0x00, 0x00, 'f', 'o', 'o', 'd', > }; > cricket::SendDataResult result; > >@@ -246,8 +235,7 @@ TEST_F(RtpDataMediaChannelTest, SendData) { > EXPECT_EQ(cricket::SDR_SUCCESS, result); > ASSERT_TRUE(HasSentData(0)); > EXPECT_EQ(sizeof(padded_data), GetSentData(0).length()); >- EXPECT_EQ(0, memcmp( >- padded_data, GetSentData(0).data(), sizeof(padded_data))); >+ EXPECT_EQ(0, memcmp(padded_data, GetSentData(0).data(), sizeof(padded_data))); > cricket::RtpHeader header0 = GetSentDataHeader(0); > EXPECT_NE(0, header0.seq_num); > EXPECT_NE(0U, header0.timestamp); >@@ -260,8 +248,7 @@ TEST_F(RtpDataMediaChannelTest, SendData) { > EXPECT_TRUE(dmc->SendData(params, payload, &result)); > ASSERT_TRUE(HasSentData(1)); > EXPECT_EQ(sizeof(padded_data), GetSentData(1).length()); >- EXPECT_EQ(0, memcmp( >- padded_data, GetSentData(1).data(), sizeof(padded_data))); >+ EXPECT_EQ(0, memcmp(padded_data, GetSentData(1).data(), sizeof(padded_data))); > cricket::RtpHeader header1 = GetSentDataHeader(1); > EXPECT_EQ(header1.ssrc, 42U); > EXPECT_EQ(header1.payload_type, 103); >@@ -322,11 +309,9 @@ TEST_F(RtpDataMediaChannelTest, SendDataRate) { > > TEST_F(RtpDataMediaChannelTest, ReceiveData) { > // PT= 103, SN=2, TS=3, SSRC = 4, data = "abcde" >- unsigned char data[] = { >- 0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2A, >- 0x00, 0x00, 0x00, 0x00, >- 'a', 'b', 'c', 'd', 'e' >- }; >+ unsigned char data[] = {0x80, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00, >+ 0x03, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, >+ 0x00, 0x00, 'a', 'b', 'c', 'd', 'e'}; > rtc::CopyOnWriteBuffer packet(data, sizeof(data)); > > std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel()); >@@ -364,9 +349,7 @@ TEST_F(RtpDataMediaChannelTest, ReceiveData) { > } > > TEST_F(RtpDataMediaChannelTest, InvalidRtpPackets) { >- unsigned char data[] = { >- 0x80, 0x65, 0x00, 0x02 >- }; >+ unsigned char data[] = {0x80, 0x65, 0x00, 0x02}; > rtc::CopyOnWriteBuffer packet(data, sizeof(data)); > > std::unique_ptr<cricket::RtpDataMediaChannel> dmc(CreateChannel()); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.cc >index d0ba1cf72b0..ee34cb101e6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.cc >@@ -35,9 +35,8 @@ namespace { > // Fake auth tag written by the sender when external authentication is enabled. > // HMAC in packet will be compared against this value before updating packet > // with actual HMAC value. >-static const uint8_t kFakeAuthTag[10] = { >- 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd >-}; >+static const uint8_t kFakeAuthTag[10] = {0xba, 0xdd, 0xba, 0xdd, 0xba, >+ 0xdd, 0xba, 0xdd, 0xba, 0xdd}; > > void UpdateAbsSendTimeExtensionValue(uint8_t* extension_data, > size_t length, >@@ -99,10 +98,10 @@ void UpdateRtpAuthTag(uint8_t* rtp, > size_t auth_required_length = length - tag_length + kRocLength; > > uint8_t output[64]; >- size_t result = rtc::ComputeHmac( >- rtc::DIGEST_SHA_1, &packet_time_params.srtp_auth_key[0], >- packet_time_params.srtp_auth_key.size(), rtp, >- auth_required_length, output, sizeof(output)); >+ size_t result = >+ rtc::ComputeHmac(rtc::DIGEST_SHA_1, &packet_time_params.srtp_auth_key[0], >+ packet_time_params.srtp_auth_key.size(), rtp, >+ auth_required_length, output, sizeof(output)); > > if (result < tag_length) { > RTC_NOTREACHED(); >@@ -205,18 +204,21 @@ bool GetRtpSsrc(const void* data, size_t len, uint32_t* value) { > } > > bool GetRtpHeaderLen(const void* data, size_t len, size_t* value) { >- if (!data || len < kMinRtpPacketLen || !value) return false; >+ if (!data || len < kMinRtpPacketLen || !value) >+ return false; > const uint8_t* header = static_cast<const uint8_t*>(data); > // Get base header size + length of CSRCs (not counting extension yet). > size_t header_size = kMinRtpPacketLen + (header[0] & 0xF) * sizeof(uint32_t); >- if (len < header_size) return false; >+ if (len < header_size) >+ return false; > // If there's an extension, read and add in the extension size. > if (header[0] & 0x10) { > if (len < header_size + sizeof(uint32_t)) > return false; > header_size += > ((rtc::GetBE16(header + header_size + 2) + 1) * sizeof(uint32_t)); >- if (len < header_size) return false; >+ if (len < header_size) >+ return false; > } > *value = header_size; > return true; >@@ -241,11 +243,14 @@ bool GetRtcpType(const void* data, size_t len, int* value) { > // to send non-compound packets only to feedback messages. > bool GetRtcpSsrc(const void* data, size_t len, uint32_t* value) { > // Packet should be at least of 8 bytes, to get SSRC from a RTCP packet. >- if (!data || len < kMinRtcpPacketLen + 4 || !value) return false; >+ if (!data || len < kMinRtcpPacketLen + 4 || !value) >+ return false; > int pl_type; >- if (!GetRtcpType(data, len, &pl_type)) return false; >+ if (!GetRtcpType(data, len, &pl_type)) >+ return false; > // SDES packet parsing is not supported. >- if (pl_type == kRtcpTypeSDES) return false; >+ if (pl_type == kRtcpTypeSDES) >+ return false; > *value = rtc::GetBE32(static_cast<const uint8_t*>(data) + 4); > return true; > } >@@ -256,8 +261,8 @@ bool SetRtpSsrc(void* data, size_t len, uint32_t value) { > > // Assumes version 2, no padding, no extensions, no csrcs. > bool SetRtpHeader(void* data, size_t len, const RtpHeader& header) { >- if (!IsValidRtpPayloadType(header.payload_type) || >- header.seq_num < 0 || header.seq_num > UINT16_MAX) { >+ if (!IsValidRtpPayloadType(header.payload_type) || header.seq_num < 0 || >+ header.seq_num > static_cast<int>(UINT16_MAX)) { > return false; > } > return (SetUint8(data, kRtpFlagsOffset, kRtpVersion << 6) && >@@ -275,6 +280,16 @@ bool IsRtpPacket(const void* data, size_t len) { > return (static_cast<const uint8_t*>(data)[0] >> 6) == kRtpVersion; > } > >+// Check the RTP payload type. If 63 < payload type < 96, it's RTCP. >+// For additional details, see http://tools.ietf.org/html/rfc5761. >+bool IsRtcpPacket(const char* data, size_t len) { >+ if (len < 2) { >+ return false; >+ } >+ char pt = data[1] & 0x7F; >+ return (63 < pt) && (pt < 96); >+} >+ > bool IsValidRtpPayloadType(int payload_type) { > return payload_type >= 0 && payload_type <= 127; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.h >index 0b7205cf8f5..0fd9a59816b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils.h >@@ -31,13 +31,13 @@ struct RtpHeader { > }; > > enum RtcpTypes { >- kRtcpTypeSR = 200, // Sender report payload type. >- kRtcpTypeRR = 201, // Receiver report payload type. >- kRtcpTypeSDES = 202, // SDES payload type. >- kRtcpTypeBye = 203, // BYE payload type. >- kRtcpTypeApp = 204, // APP payload type. >- kRtcpTypeRTPFB = 205, // Transport layer Feedback message payload type. >- kRtcpTypePSFB = 206, // Payload-specific Feedback message payload type. >+ kRtcpTypeSR = 200, // Sender report payload type. >+ kRtcpTypeRR = 201, // Receiver report payload type. >+ kRtcpTypeSDES = 202, // SDES payload type. >+ kRtcpTypeBye = 203, // BYE payload type. >+ kRtcpTypeApp = 204, // APP payload type. >+ kRtcpTypeRTPFB = 205, // Transport layer Feedback message payload type. >+ kRtcpTypePSFB = 206, // Payload-specific Feedback message payload type. > }; > > bool GetRtpPayloadType(const void* data, size_t len, int* value); >@@ -55,6 +55,7 @@ bool SetRtpHeader(void* data, size_t len, const RtpHeader& header); > > bool IsRtpPacket(const void* data, size_t len); > >+bool IsRtcpPacket(const char* data, size_t len); > // True if |payload type| is 0-127. > bool IsValidRtpPayloadType(int payload_type); > >@@ -84,7 +85,6 @@ bool ApplyPacketOptions(uint8_t* data, > const rtc::PacketTimeUpdateParams& packet_time_params, > uint64_t time_us); > >- > } // namespace cricket > > #endif // MEDIA_BASE_RTPUTILS_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils_unittest.cc >index a71eac7a076..08b4d4f4bd4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/rtputils_unittest.cc >@@ -10,78 +10,68 @@ > > #include <vector> > >-#include "media/base/rtputils.h" > #include "media/base/fakertp.h" >+#include "media/base/rtputils.h" > #include "rtc_base/asyncpacketsocket.h" > #include "rtc_base/gunit.h" > > namespace cricket { > > static const uint8_t kRtpPacketWithMarker[] = { >- 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 >-}; >+ 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; > // 3 CSRCs (0x01020304, 0x12345678, 0xAABBCCDD) > // Extension (0xBEDE, 0x1122334455667788) > static const uint8_t kRtpPacketWithMarkerAndCsrcAndExtension[] = { > 0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, > 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, >- 0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 >-}; >-static const uint8_t kInvalidPacket[] = { 0x80, 0x00 }; >+ 0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; >+static const uint8_t kInvalidPacket[] = {0x80, 0x00}; > static const uint8_t kInvalidPacketWithCsrc[] = { > 0x83, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >- 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC >-}; >+ 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC}; > static const uint8_t kInvalidPacketWithCsrcAndExtension1[] = { >- 0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, >- 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, >- 0xBE, 0xDE, 0x00 >-}; >+ 0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, >+ 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, 0xBE, 0xDE, 0x00}; > static const uint8_t kInvalidPacketWithCsrcAndExtension2[] = { > 0x93, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, > 0x01, 0x02, 0x03, 0x04, 0x12, 0x34, 0x56, 0x78, 0xAA, 0xBB, 0xCC, 0xDD, >- 0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 >-}; >+ 0xBE, 0xDE, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; > > // PT = 206, FMT = 1, Sender SSRC = 0x1111, Media SSRC = 0x1111 > // No FCI information is needed for PLI. > static const uint8_t kNonCompoundRtcpPliFeedbackPacket[] = { >- 0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11 >-}; >+ 0x81, 0xCE, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x11, 0x11}; > > // Packet has only mandatory fixed RTCP header > // PT = 204, SSRC = 0x1111 >-static const uint8_t kNonCompoundRtcpAppPacket[] = { >- 0x81, 0xCC, 0x00, 0x0C, 0x00, 0x00, 0x11, 0x11 >-}; >+static const uint8_t kNonCompoundRtcpAppPacket[] = {0x81, 0xCC, 0x00, 0x0C, >+ 0x00, 0x00, 0x11, 0x11}; > > // PT = 202, Source count = 0 >-static const uint8_t kNonCompoundRtcpSDESPacket[] = { >- 0x80, 0xCA, 0x00, 0x00 >-}; >+static const uint8_t kNonCompoundRtcpSDESPacket[] = {0x80, 0xCA, 0x00, 0x00}; > >-static uint8_t kFakeTag[4] = { 0xba, 0xdd, 0xba, 0xdd }; >+static uint8_t kFakeTag[4] = {0xba, 0xdd, 0xba, 0xdd}; > static uint8_t kTestKey[] = "12345678901234567890"; >-static uint8_t kTestAstValue[3] = { 0xaa, 0xbb, 0xcc }; >+static uint8_t kTestAstValue[3] = {0xaa, 0xbb, 0xcc}; > > // Valid rtp Message with 2 byte header extension. > static uint8_t kRtpMsgWith2ByteExtnHeader[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x90, 0x00, 0x00, 0x00, > 0x00, 0x00, 0x00, 0x00, > 0xAA, 0xBB, 0xCC, 0XDD, // SSRC > 0x10, 0x00, 0x00, 0x01, // 2 Byte header extension > 0x01, 0x00, 0x00, 0x00 >+ // clang-format on > }; > > // RTP packet with single byte extension header of length 4 bytes. > // Extension id = 3 and length = 3 > static uint8_t kRtpMsgWithAbsSendTimeExtension[] = { >- 0x90, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, >- 0xBE, 0xDE, 0x00, 0x02, >- 0x22, 0x00, 0x02, 0x1c, >- 0x32, 0xaa, 0xbb, 0xcc, >+ 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0xBE, 0xDE, 0x00, 0x02, 0x22, 0x00, 0x02, 0x1c, 0x32, 0xaa, 0xbb, 0xcc, > }; > > // Index of AbsSendTimeExtn data in message |kRtpMsgWithAbsSendTimeExtension|. >@@ -123,11 +113,10 @@ TEST(RtpUtilsTest, GetRtp) { > } > > TEST(RtpUtilsTest, SetRtpHeader) { >- uint8_t packet[] = { >- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 >- }; >+ uint8_t packet[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; > >- RtpHeader header = { 9, 1111, 2222u, 3333u }; >+ RtpHeader header = {9, 1111, 2222u, 3333u}; > EXPECT_TRUE(SetRtpHeader(packet, sizeof(packet), header)); > > // Bits: 10 0 0 0000 >@@ -172,33 +161,31 @@ TEST(RtpUtilsTest, GetRtcp) { > > uint32_t ssrc; > EXPECT_TRUE(GetRtcpSsrc(kNonCompoundRtcpPliFeedbackPacket, >- sizeof(kNonCompoundRtcpPliFeedbackPacket), >- &ssrc)); >+ sizeof(kNonCompoundRtcpPliFeedbackPacket), &ssrc)); > EXPECT_TRUE(GetRtcpSsrc(kNonCompoundRtcpAppPacket, >- sizeof(kNonCompoundRtcpAppPacket), >- &ssrc)); >+ sizeof(kNonCompoundRtcpAppPacket), &ssrc)); > EXPECT_FALSE(GetRtcpSsrc(kNonCompoundRtcpSDESPacket, >- sizeof(kNonCompoundRtcpSDESPacket), >- &ssrc)); >+ sizeof(kNonCompoundRtcpSDESPacket), &ssrc)); > } > > // Invalid RTP packets. > TEST(RtpUtilsTest, InvalidRtpHeader) { > // Rtp message with invalid length. > const uint8_t kRtpMsgWithInvalidLength[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, > 0xAA, 0xBB, 0xCC, 0XDD, // SSRC > 0xDD, 0xCC, 0xBB, 0xAA, // Only 1 CSRC, but CC count is 4. >+ // clang-format on > }; > EXPECT_FALSE(ValidateRtpHeader(kRtpMsgWithInvalidLength, > sizeof(kRtpMsgWithInvalidLength), nullptr)); > > // Rtp message with single byte header extension, invalid extension length. > const uint8_t kRtpMsgWithInvalidExtnLength[] = { >- 0x90, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, >- 0x00, 0x00, 0x00, 0x00, >- 0xBE, 0xDE, 0x0A, 0x00, // Extn length - 0x0A00 >+ 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, 0xBE, 0xDE, 0x0A, 0x00, // Extn length - 0x0A00 > }; > EXPECT_FALSE(ValidateRtpHeader(kRtpMsgWithInvalidExtnLength, > sizeof(kRtpMsgWithInvalidExtnLength), >@@ -232,6 +219,8 @@ TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInTurnSendIndication) { > // A valid STUN indication message with a valid RTP header in data attribute > // payload field and no extension bit set. > uint8_t message_without_extension[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x00, 0x16, 0x00, 0x18, // length of > 0x21, 0x12, 0xA4, 0x42, // magic cookie > '0', '1', '2', '3', // transaction id >@@ -243,6 +232,7 @@ TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInTurnSendIndication) { > 0x80, 0x00, 0x00, 0x00, // RTP packet. > 0x00, 0x00, 0x00, 0x00, > 0x00, 0x00, 0x00, 0x00, >+ // clang-format on > }; > EXPECT_TRUE(UpdateRtpAbsSendTimeExtension( > message_without_extension, sizeof(message_without_extension), 3, 0)); >@@ -250,6 +240,8 @@ TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInTurnSendIndication) { > // A valid STUN indication message with a valid RTP header and a extension > // header. > uint8_t message[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x00, 0x16, 0x00, 0x24, // length of > 0x21, 0x12, 0xA4, 0x42, // magic cookie > '0', '1', '2', '3', // transaction id >@@ -261,6 +253,7 @@ TEST(RtpUtilsTest, UpdateAbsSendTimeExtensionInTurnSendIndication) { > 0x90, 0x00, 0x00, 0x00, // RTP packet. > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xDE, > 0x00, 0x02, 0x22, 0xaa, 0xbb, 0xcc, 0x32, 0xaa, 0xbb, 0xcc, >+ // clang-format on > }; > EXPECT_TRUE(UpdateRtpAbsSendTimeExtension(message, sizeof(message), 3, 0)); > } >@@ -349,5 +342,4 @@ TEST(RtpUtilsTest, ApplyPacketOptionsWithAuthParamsAndAbsSendTime) { > sizeof(kExpectedTimestamp))); > } > >- > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.cc >index fd61a87ffd7..154baf69470 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.cc >@@ -11,7 +11,9 @@ > #include "media/base/streamparams.h" > > #include <list> >-#include <sstream> >+ >+#include "rtc_base/checks.h" >+#include "rtc_base/strings/string_builder.h" > > namespace cricket { > namespace { >@@ -20,7 +22,7 @@ namespace { > void AddStream(std::vector<StreamParams>* streams, const StreamParams& stream) { > streams->push_back(stream); > } >-} >+} // namespace > > const char kFecSsrcGroupSemantics[] = "FEC"; > const char kFecFrSsrcGroupSemantics[] = "FEC-FR"; >@@ -36,18 +38,21 @@ bool GetStream(const StreamParamsVec& streams, > return found != nullptr; > } > >-bool MediaStreams::GetAudioStream( >- const StreamSelector& selector, StreamParams* stream) { >+MediaStreams::MediaStreams() = default; >+MediaStreams::~MediaStreams() = default; >+ >+bool MediaStreams::GetAudioStream(const StreamSelector& selector, >+ StreamParams* stream) { > return GetStream(audio_, selector, stream); > } > >-bool MediaStreams::GetVideoStream( >- const StreamSelector& selector, StreamParams* stream) { >+bool MediaStreams::GetVideoStream(const StreamSelector& selector, >+ StreamParams* stream) { > return GetStream(video_, selector, stream); > } > >-bool MediaStreams::GetDataStream( >- const StreamSelector& selector, StreamParams* stream) { >+bool MediaStreams::GetDataStream(const StreamSelector& selector, >+ StreamParams* stream) { > return GetStream(data_, selector, stream); > } > >@@ -69,81 +74,98 @@ void MediaStreams::AddDataStream(const StreamParams& stream) { > AddStream(&data_, stream); > } > >-bool MediaStreams::RemoveAudioStream( >- const StreamSelector& selector) { >+bool MediaStreams::RemoveAudioStream(const StreamSelector& selector) { > return RemoveStream(&audio_, selector); > } > >-bool MediaStreams::RemoveVideoStream( >- const StreamSelector& selector) { >+bool MediaStreams::RemoveVideoStream(const StreamSelector& selector) { > return RemoveStream(&video_, selector); > } > >-bool MediaStreams::RemoveDataStream( >- const StreamSelector& selector) { >+bool MediaStreams::RemoveDataStream(const StreamSelector& selector) { > return RemoveStream(&data_, selector); > } > > static std::string SsrcsToString(const std::vector<uint32_t>& ssrcs) { >- std::ostringstream ost; >- ost << "ssrcs:["; >+ char buf[1024]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "ssrcs:["; > for (std::vector<uint32_t>::const_iterator it = ssrcs.begin(); > it != ssrcs.end(); ++it) { > if (it != ssrcs.begin()) { >- ost << ","; >+ sb << ","; > } >- ost << *it; >+ sb << *it; > } >- ost << "]"; >- return ost.str(); >+ sb << "]"; >+ return sb.str(); > } > >+SsrcGroup::SsrcGroup(const std::string& usage, >+ const std::vector<uint32_t>& ssrcs) >+ : semantics(usage), ssrcs(ssrcs) {} >+SsrcGroup::SsrcGroup(const SsrcGroup&) = default; >+SsrcGroup::SsrcGroup(SsrcGroup&&) = default; >+SsrcGroup::~SsrcGroup() = default; >+ >+SsrcGroup& SsrcGroup::operator=(const SsrcGroup&) = default; >+SsrcGroup& SsrcGroup::operator=(SsrcGroup&&) = default; >+ > bool SsrcGroup::has_semantics(const std::string& semantics_in) const { > return (semantics == semantics_in && ssrcs.size() > 0); > } > > std::string SsrcGroup::ToString() const { >- std::ostringstream ost; >- ost << "{"; >- ost << "semantics:" << semantics << ";"; >- ost << SsrcsToString(ssrcs); >- ost << "}"; >- return ost.str(); >+ char buf[1024]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "{"; >+ sb << "semantics:" << semantics << ";"; >+ sb << SsrcsToString(ssrcs); >+ sb << "}"; >+ return sb.str(); > } > >+StreamParams::StreamParams() = default; >+StreamParams::StreamParams(const StreamParams&) = default; >+StreamParams::StreamParams(StreamParams&&) = default; >+StreamParams::~StreamParams() = default; >+StreamParams& StreamParams::operator=(const StreamParams&) = default; >+StreamParams& StreamParams::operator=(StreamParams&&) = default; >+ > std::string StreamParams::ToString() const { >- std::ostringstream ost; >- ost << "{"; >+ char buf[2 * 1024]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << "{"; > if (!groupid.empty()) { >- ost << "groupid:" << groupid << ";"; >+ sb << "groupid:" << groupid << ";"; > } > if (!id.empty()) { >- ost << "id:" << id << ";"; >+ sb << "id:" << id << ";"; > } >- ost << SsrcsToString(ssrcs) << ";"; >- ost << "ssrc_groups:"; >+ sb << SsrcsToString(ssrcs) << ";"; >+ sb << "ssrc_groups:"; > for (std::vector<SsrcGroup>::const_iterator it = ssrc_groups.begin(); > it != ssrc_groups.end(); ++it) { > if (it != ssrc_groups.begin()) { >- ost << ","; >+ sb << ","; > } >- ost << it->ToString(); >- } >- ost << ";"; >- if (!type.empty()) { >- ost << "type:" << type << ";"; >- } >- if (!display.empty()) { >- ost << "display:" << display << ";"; >+ sb << it->ToString(); > } >+ sb << ";"; > if (!cname.empty()) { >- ost << "cname:" << cname << ";"; >+ sb << "cname:" << cname << ";"; > } >- if (!sync_label.empty()) { >- ost << "sync_label:" << sync_label; >+ sb << "stream_ids:"; >+ for (std::vector<std::string>::const_iterator it = stream_ids_.begin(); >+ it != stream_ids_.end(); ++it) { >+ if (it != stream_ids_.begin()) { >+ sb << ","; >+ } >+ sb << *it; > } >- ost << "}"; >- return ost.str(); >+ sb << ";"; >+ sb << "}"; >+ return sb.str(); > } > void StreamParams::GetPrimarySsrcs(std::vector<uint32_t>* ssrcs) const { > const SsrcGroup* sim_group = get_ssrc_group(kSimSsrcGroupSemantics); >@@ -187,9 +209,8 @@ bool StreamParams::GetSecondarySsrc(const std::string& semantics, > uint32_t* secondary_ssrc) const { > for (std::vector<SsrcGroup>::const_iterator it = ssrc_groups.begin(); > it != ssrc_groups.end(); ++it) { >- if (it->has_semantics(semantics) && >- it->ssrcs.size() >= 2 && >- it->ssrcs[0] == primary_ssrc) { >+ if (it->has_semantics(semantics) && it->ssrcs.size() >= 2 && >+ it->ssrcs[0] == primary_ssrc) { > *secondary_ssrc = it->ssrcs[1]; > return true; > } >@@ -197,6 +218,18 @@ bool StreamParams::GetSecondarySsrc(const std::string& semantics, > return false; > } > >+std::vector<std::string> StreamParams::stream_ids() const { >+ return stream_ids_; >+} >+ >+void StreamParams::set_stream_ids(const std::vector<std::string>& stream_ids) { >+ stream_ids_ = stream_ids; >+} >+ >+std::string StreamParams::first_stream_id() const { >+ return stream_ids_.empty() ? "" : stream_ids_[0]; >+} >+ > bool IsOneSsrcStream(const StreamParams& sp) { > if (sp.ssrcs.size() == 1 && sp.ssrc_groups.empty()) { > return true; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.h >index 1b2ebfa8711..488b61d0404 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams.h >@@ -43,25 +43,38 @@ extern const char kFidSsrcGroupSemantics[]; > extern const char kSimSsrcGroupSemantics[]; > > struct SsrcGroup { >- SsrcGroup(const std::string& usage, const std::vector<uint32_t>& ssrcs) >- : semantics(usage), ssrcs(ssrcs) {} >+ SsrcGroup(const std::string& usage, const std::vector<uint32_t>& ssrcs); >+ SsrcGroup(const SsrcGroup&); >+ SsrcGroup(SsrcGroup&&); >+ ~SsrcGroup(); >+ SsrcGroup& operator=(const SsrcGroup&); >+ SsrcGroup& operator=(SsrcGroup&&); > > bool operator==(const SsrcGroup& other) const { > return (semantics == other.semantics && ssrcs == other.ssrcs); > } >- bool operator!=(const SsrcGroup &other) const { >- return !(*this == other); >- } >+ bool operator!=(const SsrcGroup& other) const { return !(*this == other); } > > bool has_semantics(const std::string& semantics) const; > > std::string ToString() const; > >- std::string semantics; // e.g FIX, FEC, SIM. >+ std::string semantics; // e.g FIX, FEC, SIM. > std::vector<uint32_t> ssrcs; // SSRCs of this type. > }; > >+// StreamParams is used to represent a sender/track in a SessionDescription. >+// In Plan B, this means that multiple StreamParams can exist within one >+// MediaContentDescription, while in UnifiedPlan this means that there is one >+// StreamParams per MediaContentDescription. > struct StreamParams { >+ StreamParams(); >+ StreamParams(const StreamParams&); >+ StreamParams(StreamParams&&); >+ ~StreamParams(); >+ StreamParams& operator=(const StreamParams&); >+ StreamParams& operator=(StreamParams&&); >+ > static StreamParams CreateLegacy(uint32_t ssrc) { > StreamParams stream; > stream.ssrcs.push_back(ssrc); >@@ -69,18 +82,11 @@ struct StreamParams { > } > > bool operator==(const StreamParams& other) const { >- return (groupid == other.groupid && >- id == other.id && >- ssrcs == other.ssrcs && >- ssrc_groups == other.ssrc_groups && >- type == other.type && >- display == other.display && >- cname == other.cname && >- sync_label == other.sync_label); >- } >- bool operator!=(const StreamParams &other) const { >- return !(*this == other); >+ return (groupid == other.groupid && id == other.id && >+ ssrcs == other.ssrcs && ssrc_groups == other.ssrc_groups && >+ cname == other.cname && stream_ids_ == other.stream_ids_); > } >+ bool operator!=(const StreamParams& other) const { return !(*this == other); } > > uint32_t first_ssrc() const { > if (ssrcs.empty()) { >@@ -89,16 +95,12 @@ struct StreamParams { > > return ssrcs[0]; > } >- bool has_ssrcs() const { >- return !ssrcs.empty(); >- } >+ bool has_ssrcs() const { return !ssrcs.empty(); } > bool has_ssrc(uint32_t ssrc) const { > return std::find(ssrcs.begin(), ssrcs.end(), ssrc) != ssrcs.end(); > } > void add_ssrc(uint32_t ssrc) { ssrcs.push_back(ssrc); } >- bool has_ssrc_groups() const { >- return !ssrc_groups.empty(); >- } >+ bool has_ssrc_groups() const { return !ssrc_groups.empty(); } > bool has_ssrc_group(const std::string& semantics) const { > return (get_ssrc_group(semantics) != NULL); > } >@@ -146,22 +148,30 @@ struct StreamParams { > void GetFidSsrcs(const std::vector<uint32_t>& primary_ssrcs, > std::vector<uint32_t>* fid_ssrcs) const; > >+ // Stream ids serialized to SDP. >+ std::vector<std::string> stream_ids() const; >+ void set_stream_ids(const std::vector<std::string>& stream_ids); >+ >+ // Returns the first stream id or "" if none exist. This method exists only >+ // as temporary backwards compatibility with the old sync_label. >+ std::string first_stream_id() const; >+ > std::string ToString() const; > > // Resource of the MUC jid of the participant of with this stream. > // For 1:1 calls, should be left empty (which means remote streams >- // and local streams should not be mixed together). >+ // and local streams should not be mixed together). This is not used >+ // internally and should be deprecated. > std::string groupid; >- // Unique per-groupid, not across all groupids >+ // A unique identifier of the StreamParams object. When the SDP is created, >+ // this comes from the track ID of the sender that the StreamParams object >+ // is associated with. > std::string id; >+ // There may be no SSRCs stored in unsignaled case when stream_ids are >+ // signaled with a=msid lines. > std::vector<uint32_t> ssrcs; // All SSRCs for this source > std::vector<SsrcGroup> ssrc_groups; // e.g. FID, FEC, SIM >- // Examples: "camera", "screencast" >- std::string type; >- // Friendly name describing stream >- std::string display; >- std::string cname; // RTCP CNAME >- std::string sync_label; // Friendly name of cname. >+ std::string cname; // RTCP CNAME > > private: > bool AddSecondarySsrc(const std::string& semantics, >@@ -170,18 +180,22 @@ struct StreamParams { > bool GetSecondarySsrc(const std::string& semantics, > uint32_t primary_ssrc, > uint32_t* secondary_ssrc) const; >+ >+ // The stream IDs of the sender that the StreamParams object is associated >+ // with. In Plan B this should always be size of 1, while in Unified Plan this >+ // could be none or multiple stream IDs. >+ std::vector<std::string> stream_ids_; > }; > > // A Stream can be selected by either groupid+id or ssrc. > struct StreamSelector { > explicit StreamSelector(uint32_t ssrc) : ssrc(ssrc) {} > >- StreamSelector(const std::string& groupid, >- const std::string& streamid) : >- ssrc(0), >- groupid(groupid), >- streamid(streamid) { >- } >+ StreamSelector(const std::string& groupid, const std::string& streamid) >+ : ssrc(0), groupid(groupid), streamid(streamid) {} >+ >+ explicit StreamSelector(const std::string& streamid) >+ : ssrc(0), streamid(streamid) {} > > bool Matches(const StreamParams& stream) const { > if (ssrc == 0) { >@@ -206,7 +220,8 @@ typedef std::vector<StreamParams> StreamParamsVec; > // See https://code.google.com/p/webrtc/issues/detail?id=4107 > struct MediaStreams { > public: >- MediaStreams() {} >+ MediaStreams(); >+ ~MediaStreams(); > void CopyFrom(const MediaStreams& sources); > > bool empty() const { >@@ -221,12 +236,9 @@ struct MediaStreams { > const std::vector<StreamParams>& data() const { return data_; } > > // Gets a stream, returning true if found. >- bool GetAudioStream( >- const StreamSelector& selector, StreamParams* stream); >- bool GetVideoStream( >- const StreamSelector& selector, StreamParams* stream); >- bool GetDataStream( >- const StreamSelector& selector, StreamParams* stream); >+ bool GetAudioStream(const StreamSelector& selector, StreamParams* stream); >+ bool GetVideoStream(const StreamSelector& selector, StreamParams* stream); >+ bool GetDataStream(const StreamSelector& selector, StreamParams* stream); > // Adds a stream. > void AddAudioStream(const StreamParams& stream); > void AddVideoStream(const StreamParams& stream); >@@ -259,10 +271,15 @@ StreamParams* GetStream(StreamParamsVec& streams, Condition condition) { > return found == streams.end() ? nullptr : &(*found); > } > >+inline bool HasStreamWithNoSsrcs(const StreamParamsVec& streams) { >+ return GetStream(streams, >+ [](const StreamParams& sp) { return !sp.has_ssrcs(); }); >+} >+ > inline const StreamParams* GetStreamBySsrc(const StreamParamsVec& streams, > uint32_t ssrc) { >- return GetStream(streams, >- [&ssrc](const StreamParams& sp) { return sp.has_ssrc(ssrc); }); >+ return GetStream( >+ streams, [&ssrc](const StreamParams& sp) { return sp.has_ssrc(ssrc); }); > } > > inline const StreamParams* GetStreamByIds(const StreamParamsVec& streams, >@@ -276,16 +293,16 @@ inline const StreamParams* GetStreamByIds(const StreamParamsVec& streams, > inline StreamParams* GetStreamByIds(StreamParamsVec& streams, > const std::string& groupid, > const std::string& id) { >- return GetStream(streams, >- [&groupid, &id](const StreamParams& sp) { >- return sp.groupid == groupid && sp.id == id; >- }); >+ return GetStream(streams, [&groupid, &id](const StreamParams& sp) { >+ return sp.groupid == groupid && sp.id == id; >+ }); > } > > inline const StreamParams* GetStream(const StreamParamsVec& streams, > const StreamSelector& selector) { >- return GetStream(streams, >- [&selector](const StreamParams& sp) { return selector.Matches(sp); }); >+ return GetStream(streams, [&selector](const StreamParams& sp) { >+ return selector.Matches(sp); >+ }); > } > > template <class Condition> >@@ -300,21 +317,21 @@ bool RemoveStream(StreamParamsVec* streams, Condition condition) { > // Removes the stream from streams. Returns true if a stream is > // found and removed. > inline bool RemoveStream(StreamParamsVec* streams, >- const StreamSelector& selector) { >- return RemoveStream(streams, >- [&selector](const StreamParams& sp) { return selector.Matches(sp); }); >+ const StreamSelector& selector) { >+ return RemoveStream(streams, [&selector](const StreamParams& sp) { >+ return selector.Matches(sp); >+ }); > } > inline bool RemoveStreamBySsrc(StreamParamsVec* streams, uint32_t ssrc) { >- return RemoveStream(streams, >- [&ssrc](const StreamParams& sp) { return sp.has_ssrc(ssrc); }); >+ return RemoveStream( >+ streams, [&ssrc](const StreamParams& sp) { return sp.has_ssrc(ssrc); }); > } > inline bool RemoveStreamByIds(StreamParamsVec* streams, > const std::string& groupid, > const std::string& id) { >- return RemoveStream(streams, >- [&groupid, &id](const StreamParams& sp) { >- return sp.groupid == groupid && sp.id == id; >- }); >+ return RemoveStream(streams, [&groupid, &id](const StreamParams& sp) { >+ return sp.groupid == groupid && sp.id == id; >+ }); > } > > // Checks if |sp| defines parameters for a single primary stream. There may >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams_unittest.cc >index 6e934ae7d6f..c43a955fb6f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/streamparams_unittest.cc >@@ -32,10 +32,10 @@ static cricket::StreamParams CreateStreamParamsWithSsrcGroup( > > TEST(SsrcGroup, EqualNotEqual) { > cricket::SsrcGroup ssrc_groups[] = { >- cricket::SsrcGroup("ABC", MAKE_VECTOR(kSsrcs1)), >- cricket::SsrcGroup("ABC", MAKE_VECTOR(kSsrcs2)), >- cricket::SsrcGroup("Abc", MAKE_VECTOR(kSsrcs2)), >- cricket::SsrcGroup("abc", MAKE_VECTOR(kSsrcs2)), >+ cricket::SsrcGroup("ABC", MAKE_VECTOR(kSsrcs1)), >+ cricket::SsrcGroup("ABC", MAKE_VECTOR(kSsrcs2)), >+ cricket::SsrcGroup("Abc", MAKE_VECTOR(kSsrcs2)), >+ cricket::SsrcGroup("abc", MAKE_VECTOR(kSsrcs2)), > }; > > for (size_t i = 0; i < arraysize(ssrc_groups); ++i) { >@@ -69,7 +69,7 @@ TEST(StreamParams, CreateLegacy) { > EXPECT_EQ(ssrc, one_sp.first_ssrc()); > EXPECT_TRUE(one_sp.has_ssrcs()); > EXPECT_TRUE(one_sp.has_ssrc(ssrc)); >- EXPECT_FALSE(one_sp.has_ssrc(ssrc+1)); >+ EXPECT_FALSE(one_sp.has_ssrc(ssrc + 1)); > EXPECT_FALSE(one_sp.has_ssrc_groups()); > EXPECT_EQ(0U, one_sp.ssrc_groups.size()); > } >@@ -96,6 +96,17 @@ TEST(StreamParams, GetSsrcGroup) { > EXPECT_EQ(&sp.ssrc_groups[0], sp.get_ssrc_group("XYZ")); > } > >+TEST(StreamParams, HasStreamWithNoSsrcs) { >+ cricket::StreamParams sp_1 = cricket::StreamParams::CreateLegacy(kSsrcs1[0]); >+ cricket::StreamParams sp_2 = cricket::StreamParams::CreateLegacy(kSsrcs2[0]); >+ std::vector<cricket::StreamParams> streams({sp_1, sp_2}); >+ EXPECT_FALSE(HasStreamWithNoSsrcs(streams)); >+ >+ cricket::StreamParams unsignaled_stream; >+ streams.push_back(unsignaled_stream); >+ EXPECT_TRUE(HasStreamWithNoSsrcs(streams)); >+} >+ > TEST(StreamParams, EqualNotEqual) { > cricket::StreamParams l1 = cricket::StreamParams::CreateLegacy(1); > cricket::StreamParams l2 = cricket::StreamParams::CreateLegacy(2); >@@ -138,7 +149,7 @@ TEST(StreamParams, FidFunctions) { > std::vector<uint32_t> fid_vector; > fid_vector.push_back(13); > cricket::SsrcGroup invalid_fid_group(cricket::kFidSsrcGroupSemantics, >- fid_vector); >+ fid_vector); > cricket::StreamParams sp_invalid; > sp_invalid.add_ssrc(13); > sp_invalid.ssrc_groups.push_back(invalid_fid_group); >@@ -208,8 +219,11 @@ TEST(StreamParams, FecFrFunctions) { > TEST(StreamParams, ToString) { > cricket::StreamParams sp = > CreateStreamParamsWithSsrcGroup("XYZ", kSsrcs2, arraysize(kSsrcs2)); >- EXPECT_STREQ("{ssrcs:[1,2];ssrc_groups:{semantics:XYZ;ssrcs:[1,2]};}", >- sp.ToString().c_str()); >+ sp.set_stream_ids({"stream_id"}); >+ EXPECT_STREQ( >+ "{ssrcs:[1,2];ssrc_groups:{semantics:XYZ;ssrcs:[1,2]};stream_ids:stream_" >+ "id;}", >+ sp.ToString().c_str()); > } > > TEST(StreamParams, TestIsOneSsrcStream_LegacyStream) { >@@ -247,10 +261,8 @@ TEST(StreamParams, TestIsOneSsrcStream_SimulcastStream) { > } > > TEST(StreamParams, TestIsOneSsrcStream_SimRtxStream) { >- cricket::StreamParams stream = >- cricket::CreateSimWithRtxStreamParams("cname", >- MAKE_VECTOR(kSsrcs3), >- MAKE_VECTOR(kRtxSsrcs3)); >+ cricket::StreamParams stream = cricket::CreateSimWithRtxStreamParams( >+ "cname", MAKE_VECTOR(kSsrcs3), MAKE_VECTOR(kRtxSsrcs3)); > EXPECT_FALSE(cricket::IsOneSsrcStream(stream)); > } > >@@ -274,19 +286,15 @@ TEST(StreamParams, TestIsSimulcastStream_SimulcastStream) { > } > > TEST(StreamParams, TestIsSimulcastStream_SimRtxStream) { >- cricket::StreamParams stream = >- cricket::CreateSimWithRtxStreamParams("cname", >- MAKE_VECTOR(kSsrcs3), >- MAKE_VECTOR(kRtxSsrcs3)); >+ cricket::StreamParams stream = cricket::CreateSimWithRtxStreamParams( >+ "cname", MAKE_VECTOR(kSsrcs3), MAKE_VECTOR(kRtxSsrcs3)); > EXPECT_TRUE(cricket::IsSimulcastStream(stream)); > } > > TEST(StreamParams, TestIsSimulcastStream_InvalidStreams) { > // stream1 has extra non-sim, non-fid ssrc. >- cricket::StreamParams stream1 = >- cricket::CreateSimWithRtxStreamParams("cname", >- MAKE_VECTOR(kSsrcs3), >- MAKE_VECTOR(kRtxSsrcs3)); >+ cricket::StreamParams stream1 = cricket::CreateSimWithRtxStreamParams( >+ "cname", MAKE_VECTOR(kSsrcs3), MAKE_VECTOR(kRtxSsrcs3)); > stream1.add_ssrc(25); > EXPECT_FALSE(cricket::IsSimulcastStream(stream1)); > >@@ -294,7 +302,9 @@ TEST(StreamParams, TestIsSimulcastStream_InvalidStreams) { > cricket::StreamParams stream2; > stream2.add_ssrc(13); > EXPECT_TRUE(stream2.AddFidSsrc(13, 14)); >- std::remove(stream2.ssrcs.begin(), stream2.ssrcs.end(), 13u); >+ stream2.ssrcs.erase( >+ std::remove(stream2.ssrcs.begin(), stream2.ssrcs.end(), 13u), >+ stream2.ssrcs.end()); > EXPECT_FALSE(cricket::IsSimulcastStream(stream2)); > > // stream3 has two SIM groups. >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/test/mock_mediachannel.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/test/mock_mediachannel.h >deleted file mode 100644 >index fdfbf3440e7..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/test/mock_mediachannel.h >+++ /dev/null >@@ -1,35 +0,0 @@ >-/* >- * Copyright 2016 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. >- */ >- >-#ifndef MEDIA_BASE_TEST_MOCK_MEDIACHANNEL_H_ >-#define MEDIA_BASE_TEST_MOCK_MEDIACHANNEL_H_ >- >-#include "media/base/fakemediaengine.h" >-#include "test/gmock.h" >- >-namespace webrtc { >- >-class MockVideoMediaChannel : public cricket::FakeVideoMediaChannel { >- public: >- MockVideoMediaChannel() >- : cricket::FakeVideoMediaChannel(nullptr, cricket::VideoOptions()) {} >- MOCK_METHOD1(GetStats, bool(cricket::VideoMediaInfo*)); >-}; >- >-class MockVoiceMediaChannel : public cricket::FakeVoiceMediaChannel { >- public: >- MockVoiceMediaChannel() >- : cricket::FakeVoiceMediaChannel(nullptr, cricket::AudioOptions()) {} >- MOCK_METHOD1(GetStats, bool(cricket::VoiceMediaInfo*)); >-}; >- >-} // namespace webrtc >- >-#endif // MEDIA_BASE_TEST_MOCK_MEDIACHANNEL_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.cc >index f92d4013eb1..93c2bc98aef 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.cc >@@ -29,7 +29,8 @@ namespace cricket { > ///////////////////////////////////////////////////////////////////////// > void RawRtpPacket::WriteToByteBuffer(uint32_t in_ssrc, > rtc::ByteBufferWriter* buf) const { >- if (!buf) return; >+ if (!buf) >+ return; > > buf->WriteUInt8(ver_to_cc); > buf->WriteUInt8(m_to_pt); >@@ -40,7 +41,8 @@ void RawRtpPacket::WriteToByteBuffer(uint32_t in_ssrc, > } > > bool RawRtpPacket::ReadFromByteBuffer(rtc::ByteBufferReader* buf) { >- if (!buf) return false; >+ if (!buf) >+ return false; > > bool ret = true; > ret &= buf->ReadUInt8(&ver_to_cc); >@@ -56,19 +58,17 @@ bool RawRtpPacket::SameExceptSeqNumTimestampSsrc(const RawRtpPacket& packet, > uint16_t seq, > uint32_t ts, > uint32_t ssc) const { >- return sequence_number == seq && >- timestamp == ts && >- ver_to_cc == packet.ver_to_cc && >- m_to_pt == packet.m_to_pt && >- ssrc == ssc && >- 0 == memcmp(payload, packet.payload, sizeof(payload)); >+ return sequence_number == seq && timestamp == ts && >+ ver_to_cc == packet.ver_to_cc && m_to_pt == packet.m_to_pt && >+ ssrc == ssc && 0 == memcmp(payload, packet.payload, sizeof(payload)); > } > > ///////////////////////////////////////////////////////////////////////// > // Implementation of RawRtcpPacket > ///////////////////////////////////////////////////////////////////////// >-void RawRtcpPacket::WriteToByteBuffer(rtc::ByteBufferWriter *buf) const { >- if (!buf) return; >+void RawRtcpPacket::WriteToByteBuffer(rtc::ByteBufferWriter* buf) const { >+ if (!buf) >+ return; > > buf->WriteUInt8(ver_to_count); > buf->WriteUInt8(type); >@@ -77,7 +77,8 @@ void RawRtcpPacket::WriteToByteBuffer(rtc::ByteBufferWriter *buf) const { > } > > bool RawRtcpPacket::ReadFromByteBuffer(rtc::ByteBufferReader* buf) { >- if (!buf) return false; >+ if (!buf) >+ return false; > > bool ret = true; > ret &= buf->ReadUInt8(&ver_to_count); >@@ -88,10 +89,9 @@ bool RawRtcpPacket::ReadFromByteBuffer(rtc::ByteBufferReader* buf) { > } > > bool RawRtcpPacket::EqualsTo(const RawRtcpPacket& packet) const { >- return ver_to_count == packet.ver_to_count && >- type == packet.type && >- length == packet.length && >- 0 == memcmp(payload, packet.payload, sizeof(payload)); >+ return ver_to_count == packet.ver_to_count && type == packet.type && >+ length == packet.length && >+ 0 == memcmp(payload, packet.payload, sizeof(payload)); > } > > // Implementation of VideoCaptureListener. >@@ -103,7 +103,7 @@ VideoCapturerListener::VideoCapturerListener(VideoCapturer* capturer) > frame_height_(0), > resolution_changed_(false) { > capturer->SignalStateChange.connect(this, >- &VideoCapturerListener::OnStateChange); >+ &VideoCapturerListener::OnStateChange); > capturer->AddOrUpdateSink(this, rtc::VideoSinkWants()); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.h >index 2cee107b303..c84696236b4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/testutils.h >@@ -18,14 +18,13 @@ > #include "media/base/videocapturer.h" > #include "media/base/videocommon.h" > #include "rtc_base/arraysize.h" >-#include "rtc_base/basictypes.h" >-#include "rtc_base/sigslot.h" >+#include "rtc_base/third_party/sigslot/sigslot.h" > > namespace rtc { > class ByteBufferReader; > class ByteBufferWriter; > class StreamInterface; >-} >+} // namespace rtc > > namespace webrtc { > class VideoFrame; >@@ -38,7 +37,8 @@ namespace cricket { > // Returns size of ARGB image. > #define ARGB_SIZE(w, h) (w * h * 4) > >-template <class T> inline std::vector<T> MakeVector(const T a[], size_t s) { >+template <class T> >+inline std::vector<T> MakeVector(const T a[], size_t s) { > return std::vector<T>(a, a + s); > } > #define MAKE_VECTOR(a) cricket::MakeVector(a, arraysize(a)) >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/turnutils_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/turnutils_unittest.cc >index ca1282760bf..e953c2519c1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/turnutils_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/turnutils_unittest.cc >@@ -50,12 +50,15 @@ TEST(TurnUtilsTest, InvalidTurnSendIndicationMessages) { > > // Stun Send Indication message with no DATA attribute in message. > const uint8_t kTurnSendIndicatinMsgWithNoDataAttribute[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x00, 0x16, 0x00, 0x08, // length of > 0x21, 0x12, 0xA4, 0x42, // magic cookie > '0', '1', '2', '3', // transaction id > '4', '5', '6', '7', '8', '9', 'a', 'b', > 0x00, 0x20, 0x00, 0x04, // Mapped address. > 0x00, 0x00, 0x00, 0x00, >+ // clang-format on > }; > EXPECT_FALSE( > UnwrapTurnPacket(kTurnSendIndicatinMsgWithNoDataAttribute, >@@ -72,6 +75,8 @@ TEST(TurnUtilsTest, ValidTurnSendIndicationMessage) { > // A valid STUN indication message with a valid RTP header in data attribute > // payload field and no extension bit set. > const uint8_t kTurnSendIndicationMsgWithoutRtpExtension[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x00, 0x16, 0x00, 0x18, // length of > 0x21, 0x12, 0xA4, 0x42, // magic cookie > '0', '1', '2', '3', // transaction id >@@ -81,11 +86,12 @@ TEST(TurnUtilsTest, ValidTurnSendIndicationMessage) { > 0x00, 0x13, 0x00, 0x0C, // Data attribute. > 0x80, 0x00, 0x00, 0x00, // RTP packet. > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ // clang-format on > }; >- EXPECT_TRUE(UnwrapTurnPacket( >- kTurnSendIndicationMsgWithoutRtpExtension, >- sizeof(kTurnSendIndicationMsgWithoutRtpExtension), &content_pos, >- &content_size)); >+ EXPECT_TRUE( >+ UnwrapTurnPacket(kTurnSendIndicationMsgWithoutRtpExtension, >+ sizeof(kTurnSendIndicationMsgWithoutRtpExtension), >+ &content_pos, &content_size)); > EXPECT_EQ(12U, content_size); > EXPECT_EQ(32U, content_pos); > } >@@ -93,15 +99,18 @@ TEST(TurnUtilsTest, ValidTurnSendIndicationMessage) { > // Verify that parsing of valid TURN Channel Messages. > TEST(TurnUtilsTest, ValidTurnChannelMessages) { > const uint8_t kTurnChannelMsgWithRtpPacket[] = { >+ // clang-format off >+ // clang formatting doesn't respect inline comments. > 0x40, 0x00, 0x00, 0x0C, > 0x80, 0x00, 0x00, 0x00, // RTP packet. > 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ // clang-format on > }; > > size_t content_pos = 0, content_size = 0; >- EXPECT_TRUE(UnwrapTurnPacket( >- kTurnChannelMsgWithRtpPacket, >- sizeof(kTurnChannelMsgWithRtpPacket), &content_pos, &content_size)); >+ EXPECT_TRUE(UnwrapTurnPacket(kTurnChannelMsgWithRtpPacket, >+ sizeof(kTurnChannelMsgWithRtpPacket), >+ &content_pos, &content_size)); > EXPECT_EQ(12U, content_size); > EXPECT_EQ(4U, content_pos); > } >@@ -113,8 +122,8 @@ TEST(TurnUtilsTest, ChannelMessageZeroLength) { > EXPECT_TRUE(UnwrapTurnPacket(kTurnChannelMsgWithZeroLength, > sizeof(kTurnChannelMsgWithZeroLength), > &content_pos, &content_size)); >- EXPECT_EQ(4, content_pos); >- EXPECT_EQ(0, content_size); >+ EXPECT_EQ(4u, content_pos); >+ EXPECT_EQ(0u, content_size); > } > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.cc >index 553c2c320ba..c966713848a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.cc >@@ -16,7 +16,7 @@ > #include <limits> > #include <utility> > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "media/base/mediaconstants.h" > #include "media/base/videocommon.h" > #include "rtc_base/arraysize.h" >@@ -194,8 +194,8 @@ bool VideoAdapter::AdaptFrameResolution(int in_width, > } > > // Calculate how the input should be cropped. >- if (!requested_format_ || >- requested_format_->width == 0 || requested_format_->height == 0) { >+ if (!requested_format_ || requested_format_->width == 0 || >+ requested_format_->height == 0) { > *cropped_width = in_width; > *cropped_height = in_height; > } else { >@@ -236,8 +236,8 @@ bool VideoAdapter::AdaptFrameResolution(int in_width, > if (scale.numerator != scale.denominator) > ++frames_scaled_; > >- if (previous_width_ && (previous_width_ != *out_width || >- previous_height_ != *out_height)) { >+ if (previous_width_ && >+ (previous_width_ != *out_width || previous_height_ != *out_height)) { > ++adaption_changes_; > RTC_LOG(LS_INFO) << "Frame size changed: scaled " << frames_scaled_ > << " / out " << frames_out_ << " / in " << frames_in_ >@@ -255,14 +255,15 @@ bool VideoAdapter::AdaptFrameResolution(int in_width, > return true; > } > >-void VideoAdapter::OnOutputFormatRequest(const VideoFormat& format) { >+void VideoAdapter::OnOutputFormatRequest( >+ const absl::optional<VideoFormat>& format) { > rtc::CritScope cs(&critical_section_); > requested_format_ = format; >- next_frame_timestamp_ns_ = rtc::nullopt; >+ next_frame_timestamp_ns_ = absl::nullopt; > } > > void VideoAdapter::OnResolutionFramerateRequest( >- const rtc::Optional<int>& target_pixel_count, >+ const absl::optional<int>& target_pixel_count, > int max_pixel_count, > int max_framerate_fps) { > rtc::CritScope cs(&critical_section_); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.h >index 5b3d13841b3..4bb65748812 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter.h >@@ -11,7 +11,7 @@ > #ifndef MEDIA_BASE_VIDEOADAPTER_H_ > #define MEDIA_BASE_VIDEOADAPTER_H_ > >-#include "api/optional.h" >+#include "absl/types/optional.h" > #include "media/base/videocommon.h" > #include "rtc_base/constructormagic.h" > #include "rtc_base/criticalsection.h" >@@ -48,7 +48,7 @@ class VideoAdapter { > // requested aspect ratio is orientation agnostic and will be adjusted to > // maintain the input orientation, so it doesn't matter if e.g. 1280x720 or > // 720x1280 is requested. >- void OnOutputFormatRequest(const VideoFormat& format); >+ void OnOutputFormatRequest(const absl::optional<VideoFormat>& format); > > // Requests the output frame size from |AdaptFrameResolution| to have as close > // as possible to |target_pixel_count| pixels (if set) but no more than >@@ -58,7 +58,7 @@ class VideoAdapter { > // Set |max_pixel_count| and/or |max_framerate_fps| to > // std::numeric_limit<int>::max() if no upper limit is desired. > void OnResolutionFramerateRequest( >- const rtc::Optional<int>& target_pixel_count, >+ const absl::optional<int>& target_pixel_count, > int max_pixel_count, > int max_framerate_fps); > >@@ -75,13 +75,13 @@ class VideoAdapter { > // Resolution must be divisible by this factor. > const int required_resolution_alignment_; > // The target timestamp for the next frame based on requested format. >- rtc::Optional<int64_t> next_frame_timestamp_ns_ >+ absl::optional<int64_t> next_frame_timestamp_ns_ > RTC_GUARDED_BY(critical_section_); > > // Max number of pixels requested via calls to OnOutputFormatRequest, > // OnResolutionRequest respectively. > // The adapted output format is the minimum of these. >- rtc::Optional<VideoFormat> requested_format_ >+ absl::optional<VideoFormat> requested_format_ > RTC_GUARDED_BY(critical_section_); > int resolution_request_target_pixel_count_ RTC_GUARDED_BY(critical_section_); > int resolution_request_max_pixel_count_ RTC_GUARDED_BY(critical_section_); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter_unittest.cc >index 039d1da6366..c5e05b70d69 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoadapter_unittest.cc >@@ -15,7 +15,8 @@ > #include <string> > #include <vector> > >-#include "media/base/fakevideocapturer.h" >+#include "absl/memory/memory.h" >+#include "media/base/fakeframesource.h" > #include "media/base/mediachannel.h" > #include "media/base/testutils.h" > #include "media/base/videoadapter.h" >@@ -24,29 +25,26 @@ > > namespace cricket { > namespace { >+const int kWidth = 1280; >+const int kHeight = 720; > const int kDefaultFps = 30; > } // namespace > > class VideoAdapterTest : public testing::Test { > public: >- virtual void SetUp() { >- capturer_.reset(new FakeVideoCapturer); >- capture_format_ = capturer_->GetSupportedFormats()->at(0); >- capture_format_.interval = VideoFormat::FpsToInterval(kDefaultFps); >- >- listener_.reset(new VideoCapturerListener(&adapter_)); >- capturer_->AddOrUpdateSink(listener_.get(), rtc::VideoSinkWants()); >- } >- >- virtual void TearDown() { >- // Explicitly disconnect the VideoCapturer before to avoid data races >- // (frames delivered to VideoCapturerListener while it's being destructed). >- capturer_->RemoveSink(listener_.get()); >+ void SetUp() override { >+ capture_format_ = {kWidth, kHeight, VideoFormat::FpsToInterval(kDefaultFps), >+ cricket::FOURCC_I420}; >+ frame_source_ = absl::make_unique<FakeFrameSource>( >+ kWidth, kHeight, >+ VideoFormat::FpsToInterval(kDefaultFps) / rtc::kNumNanosecsPerMicrosec); >+ >+ adapter_wrapper_ = absl::make_unique<VideoAdapterWrapper>(&adapter_); > } > > protected: >- class VideoCapturerListener >- : public rtc::VideoSinkInterface<webrtc::VideoFrame> { >+ // Wrap a VideoAdapter and collect stats. >+ class VideoAdapterWrapper { > public: > struct Stats { > int captured_frames; >@@ -59,7 +57,7 @@ class VideoAdapterTest : public testing::Test { > int out_height; > }; > >- explicit VideoCapturerListener(VideoAdapter* adapter) >+ explicit VideoAdapterWrapper(VideoAdapter* adapter) > : video_adapter_(adapter), > cropped_width_(0), > cropped_height_(0), >@@ -69,8 +67,7 @@ class VideoAdapterTest : public testing::Test { > dropped_frames_(0), > last_adapt_was_no_op_(false) {} > >- void OnFrame(const webrtc::VideoFrame& frame) { >- rtc::CritScope lock(&crit_); >+ void AdaptFrame(const webrtc::VideoFrame& frame) { > const int in_width = frame.width(); > const int in_height = frame.height(); > int cropped_width; >@@ -95,7 +92,6 @@ class VideoAdapterTest : public testing::Test { > } > > Stats GetStats() { >- rtc::CritScope lock(&crit_); > Stats stats; > stats.captured_frames = captured_frames_; > stats.dropped_frames = dropped_frames_; >@@ -108,7 +104,6 @@ class VideoAdapterTest : public testing::Test { > } > > private: >- rtc::CriticalSection crit_; > VideoAdapter* video_adapter_; > int cropped_width_; > int cropped_height_; >@@ -119,8 +114,7 @@ class VideoAdapterTest : public testing::Test { > bool last_adapt_was_no_op_; > }; > >- >- void VerifyAdaptedResolution(const VideoCapturerListener::Stats& stats, >+ void VerifyAdaptedResolution(const VideoAdapterWrapper::Stats& stats, > int cropped_width, > int cropped_height, > int out_width, >@@ -131,25 +125,24 @@ class VideoAdapterTest : public testing::Test { > EXPECT_EQ(out_height, stats.out_height); > } > >- std::unique_ptr<FakeVideoCapturer> capturer_; >+ std::unique_ptr<FakeFrameSource> frame_source_; > VideoAdapter adapter_; > int cropped_width_; > int cropped_height_; > int out_width_; > int out_height_; >- std::unique_ptr<VideoCapturerListener> listener_; >+ std::unique_ptr<VideoAdapterWrapper> adapter_wrapper_; > VideoFormat capture_format_; > }; > > // Do not adapt the frame rate or the resolution. Expect no frame drop, no > // cropping, and no resolution change. > TEST_F(VideoAdapterTest, AdaptNothing) { >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no frame drop and no resolution change. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(0, stats.dropped_frames); > VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height, >@@ -158,15 +151,14 @@ TEST_F(VideoAdapterTest, AdaptNothing) { > } > > TEST_F(VideoAdapterTest, AdaptZeroInterval) { >- VideoFormat format = capturer_->GetSupportedFormats()->at(0); >+ VideoFormat format = capture_format_; > format.interval = 0; > adapter_.OnOutputFormatRequest(format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no crash and that frames aren't dropped. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(0, stats.dropped_frames); > VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height, >@@ -179,49 +171,48 @@ TEST_F(VideoAdapterTest, AdaptFramerateToHalf) { > VideoFormat request_format = capture_format_; > request_format.interval *= 2; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > > // Capture 10 frames and verify that every other frame is dropped. The first > // frame should not be dropped. >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 1); >- EXPECT_EQ(0, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 1); >+ EXPECT_EQ(0, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 2); >- EXPECT_EQ(1, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 2); >+ EXPECT_EQ(1, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 3); >- EXPECT_EQ(1, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 3); >+ EXPECT_EQ(1, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 4); >- EXPECT_EQ(2, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 4); >+ EXPECT_EQ(2, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 5); >- EXPECT_EQ(2, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 5); >+ EXPECT_EQ(2, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 6); >- EXPECT_EQ(3, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 6); >+ EXPECT_EQ(3, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 7); >- EXPECT_EQ(3, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 7); >+ EXPECT_EQ(3, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 8); >- EXPECT_EQ(4, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 8); >+ EXPECT_EQ(4, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 9); >- EXPECT_EQ(4, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 9); >+ EXPECT_EQ(4, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 10); >- EXPECT_EQ(5, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 10); >+ EXPECT_EQ(5, adapter_wrapper_->GetStats().dropped_frames); > } > > // Adapt the frame rate to be two thirds of the capture rate at the beginning. >@@ -231,49 +222,48 @@ TEST_F(VideoAdapterTest, AdaptFramerateToTwoThirds) { > VideoFormat request_format = capture_format_; > request_format.interval = request_format.interval * 3 / 2; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > > // Capture 10 frames and verify that every third frame is dropped. The first > // frame should not be dropped. >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 1); >- EXPECT_EQ(0, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 1); >+ EXPECT_EQ(0, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 2); >- EXPECT_EQ(0, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 2); >+ EXPECT_EQ(0, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 3); >- EXPECT_EQ(1, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 3); >+ EXPECT_EQ(1, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 4); >- EXPECT_EQ(1, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 4); >+ EXPECT_EQ(1, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 5); >- EXPECT_EQ(1, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 5); >+ EXPECT_EQ(1, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 6); >- EXPECT_EQ(2, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 6); >+ EXPECT_EQ(2, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 7); >- EXPECT_EQ(2, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 7); >+ EXPECT_EQ(2, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 8); >- EXPECT_EQ(2, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 8); >+ EXPECT_EQ(2, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 9); >- EXPECT_EQ(3, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 9); >+ EXPECT_EQ(3, adapter_wrapper_->GetStats().dropped_frames); > >- capturer_->CaptureFrame(); >- EXPECT_GE(listener_->GetStats().captured_frames, 10); >- EXPECT_EQ(3, listener_->GetStats().dropped_frames); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); >+ EXPECT_GE(adapter_wrapper_->GetStats().captured_frames, 10); >+ EXPECT_EQ(3, adapter_wrapper_->GetStats().dropped_frames); > } > > // Request frame rate twice as high as captured frame rate. Expect no frame >@@ -282,12 +272,11 @@ TEST_F(VideoAdapterTest, AdaptFramerateHighLimit) { > VideoFormat request_format = capture_format_; > request_format.interval /= 2; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no frame drop. >- EXPECT_EQ(0, listener_->GetStats().dropped_frames); >+ EXPECT_EQ(0, adapter_wrapper_->GetStats().dropped_frames); > } > > // After the first timestamp, add a big offset to the timestamps. Expect that >@@ -370,37 +359,35 @@ TEST_F(VideoAdapterTest, AdaptFramerateTimestampJitter) { > TEST_F(VideoAdapterTest, AdaptFramerateOntheFly) { > VideoFormat request_format = capture_format_; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no frame drop before adaptation. >- EXPECT_EQ(0, listener_->GetStats().dropped_frames); >+ EXPECT_EQ(0, adapter_wrapper_->GetStats().dropped_frames); > > // Adapat the frame rate. > request_format.interval *= 2; > adapter_.OnOutputFormatRequest(request_format); > > for (int i = 0; i < 20; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify frame drop after adaptation. >- EXPECT_GT(listener_->GetStats().dropped_frames, 0); >+ EXPECT_GT(adapter_wrapper_->GetStats().dropped_frames, 0); > } > > // Do not adapt the frame rate or the resolution. Expect no frame drop, no > // cropping, and no resolution change. >-TEST_F(VideoAdapterTest, OnFramerateRequestMax) { >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, >+TEST_F(VideoAdapterTest, AdaptFramerateRequestMax) { >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, > std::numeric_limits<int>::max(), > std::numeric_limits<int>::max()); > >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no frame drop and no resolution change. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(0, stats.dropped_frames); > VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height, >@@ -408,30 +395,28 @@ TEST_F(VideoAdapterTest, OnFramerateRequestMax) { > EXPECT_TRUE(stats.last_adapt_was_no_op); > } > >-TEST_F(VideoAdapterTest, OnFramerateRequestZero) { >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, >+TEST_F(VideoAdapterTest, AdaptFramerateRequestZero) { >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, > std::numeric_limits<int>::max(), 0); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no crash and that frames aren't dropped. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(10, stats.dropped_frames); > } > > // Adapt the frame rate to be half of the capture rate at the beginning. Expect > // the number of dropped frames to be half of the number the captured frames. >-TEST_F(VideoAdapterTest, OnFramerateRequestHalf) { >+TEST_F(VideoAdapterTest, AdaptFramerateRequestHalf) { > adapter_.OnResolutionFramerateRequest( >- rtc::nullopt, std::numeric_limits<int>::max(), kDefaultFps / 2); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); >+ absl::nullopt, std::numeric_limits<int>::max(), kDefaultFps / 2); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no crash and that frames aren't dropped. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(5, stats.dropped_frames); > VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height, >@@ -505,12 +490,11 @@ TEST_F(VideoAdapterTest, AdaptResolution) { > request_format.width /= 2; > request_format.height /= 2; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no frame drop, no cropping, and resolution change. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_EQ(0, stats.dropped_frames); > VerifyAdaptedResolution(stats, capture_format_.width, capture_format_.height, > request_format.width, request_format.height); >@@ -522,38 +506,36 @@ TEST_F(VideoAdapterTest, AdaptResolution) { > TEST_F(VideoAdapterTest, AdaptResolutionOnTheFly) { > VideoFormat request_format = capture_format_; > adapter_.OnOutputFormatRequest(request_format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify no resolution change before adaptation. >- VerifyAdaptedResolution(listener_->GetStats(), >- capture_format_.width, capture_format_.height, >- request_format.width, request_format.height); >+ VerifyAdaptedResolution(adapter_wrapper_->GetStats(), capture_format_.width, >+ capture_format_.height, request_format.width, >+ request_format.height); > > // Adapt the frame resolution. > request_format.width /= 2; > request_format.height /= 2; > adapter_.OnOutputFormatRequest(request_format); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify resolution change after adaptation. >- VerifyAdaptedResolution(listener_->GetStats(), >- capture_format_.width, capture_format_.height, >- request_format.width, request_format.height); >+ VerifyAdaptedResolution(adapter_wrapper_->GetStats(), capture_format_.width, >+ capture_format_.height, request_format.width, >+ request_format.height); > } > > // Drop all frames. > TEST_F(VideoAdapterTest, DropAllFrames) { > VideoFormat format; // with resolution 0x0. > adapter_.OnOutputFormatRequest(format); >- EXPECT_EQ(CS_RUNNING, capturer_->Start(capture_format_)); > for (int i = 0; i < 10; ++i) >- capturer_->CaptureFrame(); >+ adapter_wrapper_->AdaptFrame(frame_source_->GetFrame()); > > // Verify all frames are dropped. >- VideoCapturerListener::Stats stats = listener_->GetStats(); >+ VideoAdapterWrapper::Stats stats = adapter_wrapper_->GetStats(); > EXPECT_GE(stats.captured_frames, 10); > EXPECT_EQ(stats.captured_frames, stats.dropped_frames); > } >@@ -750,7 +732,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestInSmallSteps) { > EXPECT_EQ(720, out_height_); > > // Adapt down one step. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 1280 * 720 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 1280 * 720 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -761,7 +743,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestInSmallSteps) { > EXPECT_EQ(540, out_height_); > > // Adapt down one step more. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 960 * 540 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 960 * 540 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -772,7 +754,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestInSmallSteps) { > EXPECT_EQ(360, out_height_); > > // Adapt down one step more. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 360 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 360 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -828,7 +810,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestMaxZero) { > EXPECT_EQ(1280, out_width_); > EXPECT_EQ(720, out_height_); > >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 0, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 0, > std::numeric_limits<int>::max()); > EXPECT_FALSE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -837,7 +819,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestMaxZero) { > > TEST_F(VideoAdapterTest, TestOnResolutionRequestInLargeSteps) { > // Large step down. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 360 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 360 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -860,7 +842,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestInLargeSteps) { > } > > TEST_F(VideoAdapterTest, TestOnOutputFormatRequestCapsMaxResolution) { >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 360 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 360 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -880,7 +862,7 @@ TEST_F(VideoAdapterTest, TestOnOutputFormatRequestCapsMaxResolution) { > EXPECT_EQ(480, out_width_); > EXPECT_EQ(270, out_height_); > >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 960 * 720, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 960 * 720, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -900,7 +882,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestReset) { > EXPECT_EQ(1280, out_width_); > EXPECT_EQ(720, out_height_); > >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 360 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 360 - 1, > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, > &cropped_width_, &cropped_height_, >@@ -910,7 +892,7 @@ TEST_F(VideoAdapterTest, TestOnResolutionRequestReset) { > EXPECT_EQ(480, out_width_); > EXPECT_EQ(270, out_height_); > >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, > std::numeric_limits<int>::max(), > std::numeric_limits<int>::max()); > EXPECT_TRUE(adapter_.AdaptFrameResolution(1280, 720, 0, >@@ -936,7 +918,7 @@ TEST_F(VideoAdapterTest, TestCroppingWithResolutionRequest) { > EXPECT_EQ(360, out_height_); > > // Adapt down one step. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 360 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 360 - 1, > std::numeric_limits<int>::max()); > // Expect cropping to 16:9 format and 3/4 scaling. > EXPECT_TRUE(adapter_.AdaptFrameResolution(640, 480, 0, >@@ -948,7 +930,7 @@ TEST_F(VideoAdapterTest, TestCroppingWithResolutionRequest) { > EXPECT_EQ(270, out_height_); > > // Adapt down one step more. >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 480 * 270 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 480 * 270 - 1, > std::numeric_limits<int>::max()); > // Expect cropping to 16:9 format and 1/2 scaling. > EXPECT_TRUE(adapter_.AdaptFrameResolution(640, 480, 0, >@@ -1000,7 +982,7 @@ TEST_F(VideoAdapterTest, TestCroppingOddResolution) { > // Ask for 640x360 (16:9 aspect), with 3/16 scaling. > adapter_.OnOutputFormatRequest( > VideoFormat(640, 360, 0, FOURCC_I420)); >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, > 640 * 360 * 3 / 16 * 3 / 16, > std::numeric_limits<int>::max()); > >@@ -1022,8 +1004,7 @@ TEST_F(VideoAdapterTest, TestAdaptToVerySmallResolution) { > const int w = 1920; > const int h = 1080; > adapter_.OnOutputFormatRequest(VideoFormat(w, h, 0, FOURCC_I420)); >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, >- w * h * 1 / 16 * 1 / 16, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, w * h * 1 / 16 * 1 / 16, > std::numeric_limits<int>::max()); > > // Send 1920x1080 (16:9 aspect). >@@ -1070,7 +1051,7 @@ TEST_F(VideoAdapterTest, AdaptFrameResolutionDropWithResolutionRequest) { > &cropped_width_, &cropped_height_, > &out_width_, &out_height_)); > >- adapter_.OnResolutionFramerateRequest(rtc::nullopt, 640 * 480 - 1, >+ adapter_.OnResolutionFramerateRequest(absl::nullopt, 640 * 480 - 1, > std::numeric_limits<int>::max()); > > // Still expect all frames to be dropped >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.cc >index d2a9c54116d..a16a327b072 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.cc >@@ -21,6 +21,7 @@ namespace rtc { > VideoBroadcaster::VideoBroadcaster() { > thread_checker_.DetachFromThread(); > } >+VideoBroadcaster::~VideoBroadcaster() = default; > > void VideoBroadcaster::AddOrUpdateSink( > VideoSinkInterface<webrtc::VideoFrame>* sink, >@@ -64,9 +65,9 @@ void VideoBroadcaster::OnFrame(const webrtc::VideoFrame& frame) { > continue; > } > if (sink_pair.wants.black_frames) { >- sink_pair.sink->OnFrame(webrtc::VideoFrame( >- GetBlackFrameBuffer(frame.width(), frame.height()), frame.rotation(), >- frame.timestamp_us())); >+ sink_pair.sink->OnFrame( >+ webrtc::VideoFrame(GetBlackFrameBuffer(frame.width(), frame.height()), >+ frame.rotation(), frame.timestamp_us())); > } else { > sink_pair.sink->OnFrame(frame); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.h >index c19f3f75192..119769d2cf7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster.h >@@ -16,7 +16,7 @@ > #include <vector> > > #include "api/video/video_frame.h" >-#include "api/videosinkinterface.h" >+#include "api/video/video_sink_interface.h" > #include "media/base/videosourcebase.h" > #include "rtc_base/criticalsection.h" > #include "rtc_base/thread_checker.h" >@@ -33,6 +33,7 @@ class VideoBroadcaster : public VideoSourceBase, > public VideoSinkInterface<webrtc::VideoFrame> { > public: > VideoBroadcaster(); >+ ~VideoBroadcaster() override; > void AddOrUpdateSink(VideoSinkInterface<webrtc::VideoFrame>* sink, > const VideoSinkWants& wants) override; > void RemoveSink(VideoSinkInterface<webrtc::VideoFrame>* sink) override; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster_unittest.cc >index 0f2057ebe0e..a8c38848204 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videobroadcaster_unittest.cc >@@ -10,17 +10,16 @@ > > #include <limits> > >-#include "media/base/videobroadcaster.h" > #include "api/video/i420_buffer.h" > #include "api/video/video_frame.h" > #include "media/base/fakevideorenderer.h" >+#include "media/base/videobroadcaster.h" > #include "rtc_base/gunit.h" > > using rtc::VideoBroadcaster; > using rtc::VideoSinkWants; > using cricket::FakeVideoRenderer; > >- > TEST(VideoBroadcasterTest, frame_wanted) { > VideoBroadcaster broadcaster; > EXPECT_FALSE(broadcaster.frame_wanted()); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.cc >index f6e05ba5d51..f8420dc1ad6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.cc >@@ -27,8 +27,6 @@ static const int64_t kMaxDistance = ~(static_cast<int64_t>(1) << 63); > #ifdef WEBRTC_LINUX > static const int kYU12Penalty = 16; // Needs to be higher than MJPG index. > #endif >-static const char* kSimulcastScreenshareFieldTrialName = >- "WebRTC-SimulcastScreenshare"; > > } // namespace > >@@ -40,6 +38,8 @@ VideoCapturer::VideoCapturer() : apply_rotation_(false) { > Construct(); > } > >+VideoCapturer::~VideoCapturer() {} >+ > void VideoCapturer::Construct() { > enable_camera_list_ = false; > capture_state_ = CS_STOPPED; >@@ -65,6 +65,10 @@ bool VideoCapturer::StartCapturing(const VideoFormat& capture_format) { > return true; > } > >+bool VideoCapturer::apply_rotation() { >+ return apply_rotation_; >+} >+ > void VideoCapturer::SetSupportedFormats( > const std::vector<VideoFormat>& formats) { > // This method is OK to call during initialization on a separate thread. >@@ -178,10 +182,7 @@ bool VideoCapturer::AdaptFrame(int width, > return false; > } > >- bool simulcast_screenshare_enabled = >- webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName); >- if (enable_video_adapter_ && >- (!IsScreencast() || simulcast_screenshare_enabled)) { >+ if (enable_video_adapter_) { > if (!video_adapter_.AdaptFrameResolution( > width, height, camera_time_us * rtc::kNumNanosecsPerMicrosec, > crop_width, crop_height, out_width, out_height)) { >@@ -319,9 +320,10 @@ int64_t VideoCapturer::GetFormatDistance(const VideoFormat& desired, > // Require camera fps to be at least 96% of what is requested, or higher, > // if resolution differs. 96% allows for slight variations in fps. e.g. 29.97 > if (delta_fps < 0) { >- float min_desirable_fps = delta_w ? >- VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f : >- VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f; >+ float min_desirable_fps = >+ delta_w >+ ? VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f >+ : VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f; > delta_fps = -delta_fps; > if (supported_fps < min_desirable_fps) { > distance |= static_cast<int64_t>(1) << 62; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.h >index 219e03643fb..826e38fa5a1 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer.h >@@ -20,13 +20,13 @@ > #include <string> > #include <vector> > >-#include "api/videosourceinterface.h" >+#include "api/video/video_source_interface.h" > #include "media/base/videoadapter.h" > #include "media/base/videobroadcaster.h" > #include "media/base/videocommon.h" > #include "rtc_base/constructormagic.h" > #include "rtc_base/criticalsection.h" >-#include "rtc_base/sigslot.h" >+#include "rtc_base/third_party/sigslot/sigslot.h" > #include "rtc_base/thread_checker.h" > #include "rtc_base/timestampaligner.h" > >@@ -38,12 +38,12 @@ namespace cricket { > > // Current state of the capturer. > enum CaptureState { >- CS_STOPPED, // The capturer has been stopped or hasn't started yet. >- CS_STARTING, // The capturer is in the process of starting. Note, it may >- // still fail to start. >- CS_RUNNING, // The capturer has been started successfully and is now >- // capturing. >- CS_FAILED, // The capturer failed to start. >+ CS_STOPPED, // The capturer has been stopped or hasn't started yet. >+ CS_STARTING, // The capturer is in the process of starting. Note, it may >+ // still fail to start. >+ CS_RUNNING, // The capturer has been started successfully and is now >+ // capturing. >+ CS_FAILED, // The capturer failed to start. > }; > > // VideoCapturer is an abstract class that defines the interfaces for video >@@ -77,7 +77,7 @@ class VideoCapturer : public sigslot::has_slots<>, > public: > VideoCapturer(); > >- virtual ~VideoCapturer() {} >+ ~VideoCapturer() override; > > // Gets the id of the underlying device, which is available after the capturer > // is initialized. Can be used to determine if two capturers reference the >@@ -126,19 +126,15 @@ class VideoCapturer : public sigslot::has_slots<>, > // Note that the width and height of the captured frames may differ from the > // capture format. For example, the capture format is HD but the captured > // frames may be smaller than HD. >- const VideoFormat* GetCaptureFormat() const { >- return capture_format_.get(); >- } >+ const VideoFormat* GetCaptureFormat() const { return capture_format_.get(); } > > // Stop the video capturer. > virtual void Stop() = 0; > // Check if the video capturer is running. > virtual bool IsRunning() = 0; >- CaptureState capture_state() const { >- return capture_state_; >- } >+ CaptureState capture_state() const { return capture_state_; } > >- virtual bool apply_rotation() { return apply_rotation_; } >+ virtual bool apply_rotation(); > > // Returns true if the capturer is screencasting. This can be used to > // implement screencast specific behavior. >@@ -154,9 +150,7 @@ class VideoCapturer : public sigslot::has_slots<>, > void set_enable_camera_list(bool enable_camera_list) { > enable_camera_list_ = enable_camera_list; > } >- bool enable_camera_list() { >- return enable_camera_list_; >- } >+ bool enable_camera_list() { return enable_camera_list_; } > > // Signal all capture state changes that are not a direct result of calling > // Start(). >@@ -227,9 +221,7 @@ class VideoCapturer : public sigslot::has_slots<>, > virtual bool GetPreferredFourccs(std::vector<uint32_t>* fourccs) = 0; > > // mutators to set private attributes >- void SetId(const std::string& id) { >- id_ = id; >- } >+ void SetId(const std::string& id) { id_ = id; } > > void SetCaptureFormat(const VideoFormat* format) { > capture_format_.reset(format ? new VideoFormat(*format) : NULL); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer_unittest.cc >index 7450694d218..080f4a08cae 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocapturer_unittest.cc >@@ -21,7 +21,7 @@ > #include "rtc_base/logging.h" > #include "rtc_base/thread.h" > >-using cricket::FakeVideoCapturer; >+using cricket::FakeVideoCapturerWithTaskQueue; > > namespace { > >@@ -31,9 +31,7 @@ const int kMinHdHeight = 720; > > } // namespace > >-class VideoCapturerTest >- : public sigslot::has_slots<>, >- public testing::Test { >+class VideoCapturerTest : public sigslot::has_slots<>, public testing::Test { > public: > VideoCapturerTest() > : capture_state_(cricket::CS_STOPPED), num_state_changes_(0) { >@@ -42,8 +40,8 @@ class VideoCapturerTest > > protected: > void InitCapturer(bool is_screencast) { >- capturer_ = std::unique_ptr<FakeVideoCapturer>( >- new FakeVideoCapturer(is_screencast)); >+ capturer_ = std::unique_ptr<FakeVideoCapturerWithTaskQueue>( >+ new FakeVideoCapturerWithTaskQueue(is_screencast)); > capturer_->SignalStateChange.connect(this, > &VideoCapturerTest::OnStateChange); > capturer_->AddOrUpdateSink(&renderer_, rtc::VideoSinkWants()); >@@ -58,7 +56,7 @@ class VideoCapturerTest > cricket::CaptureState capture_state() { return capture_state_; } > int num_state_changes() { return num_state_changes_; } > >- std::unique_ptr<cricket::FakeVideoCapturer> capturer_; >+ std::unique_ptr<FakeVideoCapturerWithTaskQueue> capturer_; > cricket::CaptureState capture_state_; > int num_state_changes_; > cricket::FakeVideoRenderer renderer_; >@@ -67,11 +65,10 @@ class VideoCapturerTest > > TEST_F(VideoCapturerTest, CaptureState) { > EXPECT_TRUE(capturer_->enable_video_adapter()); >- EXPECT_EQ(cricket::CS_RUNNING, capturer_->Start(cricket::VideoFormat( >- 640, >- 480, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_I420))); >+ EXPECT_EQ(cricket::CS_RUNNING, >+ capturer_->Start(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420))); > EXPECT_TRUE(capturer_->IsRunning()); > EXPECT_EQ_WAIT(cricket::CS_RUNNING, capture_state(), kMsCallbackWait); > EXPECT_EQ(1, num_state_changes()); >@@ -327,9 +324,8 @@ TEST_F(VideoCapturerTest, SinkWantsMaxPixelAndMaxPixelCountStepUp) { > } > > TEST_F(VideoCapturerTest, TestFourccMatch) { >- cricket::VideoFormat desired(640, 480, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_ANY); >+ cricket::VideoFormat desired( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY); > cricket::VideoFormat best; > EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best)); > EXPECT_EQ(640, best.width); >@@ -344,9 +340,8 @@ TEST_F(VideoCapturerTest, TestFourccMatch) { > } > > TEST_F(VideoCapturerTest, TestResolutionMatch) { >- cricket::VideoFormat desired(1920, 1080, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_ANY); >+ cricket::VideoFormat desired( >+ 1920, 1080, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY); > cricket::VideoFormat best; > // Ask for 1920x1080. Get HD 1280x720 which is the highest. > EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best)); >@@ -390,21 +385,22 @@ TEST_F(VideoCapturerTest, TestResolutionMatch) { > TEST_F(VideoCapturerTest, TestHDResolutionMatch) { > // Add some HD formats typical of a mediocre HD webcam. > std::vector<cricket::VideoFormat> formats; >- formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(960, 544, >- cricket::VideoFormat::FpsToInterval(24), cricket::FOURCC_I420)); >- formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420)); >+ formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ formats.push_back(cricket::VideoFormat( >+ 960, 544, cricket::VideoFormat::FpsToInterval(24), cricket::FOURCC_I420)); >+ formats.push_back( >+ cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(15), >+ cricket::FOURCC_I420)); > formats.push_back(cricket::VideoFormat(2592, 1944, >- cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420)); >+ cricket::VideoFormat::FpsToInterval(7), >+ cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(formats); > >- cricket::VideoFormat desired(960, 720, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_ANY); >+ cricket::VideoFormat desired( >+ 960, 720, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY); > cricket::VideoFormat best; > // Ask for 960x720 30 fps. Get qHD 24 fps > EXPECT_TRUE(capturer_->GetBestCaptureFormat(desired, &best)); >@@ -484,19 +480,19 @@ TEST_F(VideoCapturerTest, TestHDResolutionMatch) { > // Some cameras support 320x240 and 320x640. Verify we choose 320x240. > TEST_F(VideoCapturerTest, TestStrangeFormats) { > std::vector<cricket::VideoFormat> supported_formats; >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(320, 640, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 640, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > std::vector<cricket::VideoFormat> required_formats; >- required_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- required_formats.push_back(cricket::VideoFormat(320, 200, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- required_formats.push_back(cricket::VideoFormat(320, 180, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ required_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ required_formats.push_back(cricket::VideoFormat( >+ 320, 200, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ required_formats.push_back(cricket::VideoFormat( >+ 320, 180, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > cricket::VideoFormat best; > for (size_t i = 0; i < required_formats.size(); ++i) { > EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best)); >@@ -505,10 +501,10 @@ TEST_F(VideoCapturerTest, TestStrangeFormats) { > } > > supported_formats.clear(); >- supported_formats.push_back(cricket::VideoFormat(320, 640, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 640, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > for (size_t i = 0; i < required_formats.size(); ++i) { >@@ -522,19 +518,19 @@ TEST_F(VideoCapturerTest, TestStrangeFormats) { > TEST_F(VideoCapturerTest, TestPoorFpsFormats) { > // all formats are low framerate > std::vector<cricket::VideoFormat> supported_formats; >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 1280, 720, cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > std::vector<cricket::VideoFormat> required_formats; >- required_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- required_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ required_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ required_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > cricket::VideoFormat best; > for (size_t i = 0; i < required_formats.size(); ++i) { > EXPECT_TRUE(capturer_->GetBestCaptureFormat(required_formats[i], &best)); >@@ -544,12 +540,12 @@ TEST_F(VideoCapturerTest, TestPoorFpsFormats) { > > // Increase framerate of 320x240. Expect low fps VGA avoided. > supported_formats.clear(); >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(7), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 1280, 720, cricket::VideoFormat::FpsToInterval(2), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > for (size_t i = 0; i < required_formats.size(); ++i) { >@@ -563,12 +559,12 @@ TEST_F(VideoCapturerTest, TestPoorFpsFormats) { > // the frame rate properly. > TEST_F(VideoCapturerTest, TestSameSizeDifferentFpsFormats) { > std::vector<cricket::VideoFormat> supported_formats; >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(320, 240, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 320, 240, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > std::vector<cricket::VideoFormat> required_formats = supported_formats; >@@ -586,23 +582,24 @@ TEST_F(VideoCapturerTest, TestSameSizeDifferentFpsFormats) { > TEST_F(VideoCapturerTest, TestFpsFormats) { > // We have VGA but low fps. Choose VGA, not HD > std::vector<cricket::VideoFormat> supported_formats; >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 400, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 360, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back( >+ cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > std::vector<cricket::VideoFormat> required_formats; >- required_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY)); >- required_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_ANY)); >- required_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY)); >+ required_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_ANY)); >+ required_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(20), cricket::FOURCC_ANY)); >+ required_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(10), cricket::FOURCC_ANY)); > cricket::VideoFormat best; > > // Expect 30 fps to choose 30 fps format. >@@ -625,16 +622,17 @@ TEST_F(VideoCapturerTest, TestFpsFormats) { > > // We have VGA 60 fps and 15 fps. Choose best fps. > supported_formats.clear(); >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_MJPG)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 400, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 360, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back( >+ cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(60), cricket::FOURCC_MJPG)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(15), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > // Expect 30 fps to choose 60 fps format and will set best fps to 60. >@@ -659,12 +657,12 @@ TEST_F(VideoCapturerTest, TestFpsFormats) { > TEST_F(VideoCapturerTest, TestRequest16x10_9) { > std::vector<cricket::VideoFormat> supported_formats; > // We do not support HD, expect 4x3 for 4x3, 16x10, and 16x9 requests. >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 400, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 360, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > std::vector<cricket::VideoFormat> required_formats = supported_formats; >@@ -678,14 +676,14 @@ TEST_F(VideoCapturerTest, TestRequest16x10_9) { > > // We do not support 16x9 HD, expect 4x3 for 4x3, 16x10, and 16x9 requests. > supported_formats.clear(); >- supported_formats.push_back(cricket::VideoFormat(960, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 400, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 360, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 960, 720, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > // Expect 4x3, 16x10, and 16x9 requests are respected. >@@ -697,14 +695,15 @@ TEST_F(VideoCapturerTest, TestRequest16x10_9) { > > // We support 16x9HD, Expect 4x3, 16x10, and 16x9 requests are respected. > supported_formats.clear(); >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 480, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 400, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(640, 360, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back( >+ cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 400, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back(cricket::VideoFormat( >+ 640, 360, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > > // Expect 4x3 for 4x3 and 16x10 requests. >@@ -722,7 +721,8 @@ TEST_F(VideoCapturerTest, TestRequest16x10_9) { > > bool HdFormatInList(const std::vector<cricket::VideoFormat>& formats) { > for (std::vector<cricket::VideoFormat>::const_iterator found = >- formats.begin(); found != formats.end(); ++found) { >+ formats.begin(); >+ found != formats.end(); ++found) { > if (found->height >= kMinHdHeight) { > return true; > } >@@ -734,13 +734,11 @@ TEST_F(VideoCapturerTest, Whitelist) { > // The definition of HD only applies to the height. Set the HD width to the > // smallest legal number to document this fact in this test. > const int kMinHdWidth = 1; >- cricket::VideoFormat hd_format(kMinHdWidth, >- kMinHdHeight, >+ cricket::VideoFormat hd_format(kMinHdWidth, kMinHdHeight, > cricket::VideoFormat::FpsToInterval(30), > cricket::FOURCC_I420); >- cricket::VideoFormat vga_format(640, 480, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_I420); >+ cricket::VideoFormat vga_format( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420); > std::vector<cricket::VideoFormat> formats = *capturer_->GetSupportedFormats(); > formats.push_back(hd_format); > >@@ -760,15 +758,16 @@ TEST_F(VideoCapturerTest, Whitelist) { > } > > TEST_F(VideoCapturerTest, BlacklistAllFormats) { >- cricket::VideoFormat vga_format(640, 480, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_I420); >+ cricket::VideoFormat vga_format( >+ 640, 480, cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420); > std::vector<cricket::VideoFormat> supported_formats; > // Mock a device that only supports HD formats. >- supported_formats.push_back(cricket::VideoFormat(1280, 720, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >- supported_formats.push_back(cricket::VideoFormat(1920, 1080, >- cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420)); >+ supported_formats.push_back( >+ cricket::VideoFormat(1280, 720, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420)); >+ supported_formats.push_back( >+ cricket::VideoFormat(1920, 1080, cricket::VideoFormat::FpsToInterval(30), >+ cricket::FOURCC_I420)); > capturer_->ResetSupportedFormats(supported_formats); > EXPECT_EQ(2u, capturer_->GetSupportedFormats()->size()); > // Now, enable the list, which would exclude both formats. However, since >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.cc >index e5168b55ca4..9def96c4697 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.cc >@@ -12,9 +12,9 @@ > > #include <limits.h> // For INT_MAX > #include <math.h> >-#include <sstream> > > #include "rtc_base/arraysize.h" >+#include "rtc_base/strings/string_builder.h" > > namespace cricket { > >@@ -24,20 +24,20 @@ struct FourCCAliasEntry { > }; > > static const FourCCAliasEntry kFourCCAliases[] = { >- {FOURCC_IYUV, FOURCC_I420}, >- {FOURCC_YU16, FOURCC_I422}, >- {FOURCC_YU24, FOURCC_I444}, >- {FOURCC_YUYV, FOURCC_YUY2}, >- {FOURCC_YUVS, FOURCC_YUY2}, >- {FOURCC_HDYC, FOURCC_UYVY}, >- {FOURCC_2VUY, FOURCC_UYVY}, >- {FOURCC_JPEG, FOURCC_MJPG}, // Note: JPEG has DHT while MJPG does not. >- {FOURCC_DMB1, FOURCC_MJPG}, >- {FOURCC_BA81, FOURCC_BGGR}, >- {FOURCC_RGB3, FOURCC_RAW}, >- {FOURCC_BGR3, FOURCC_24BG}, >- {FOURCC_CM32, FOURCC_BGRA}, >- {FOURCC_CM24, FOURCC_RAW}, >+ {FOURCC_IYUV, FOURCC_I420}, >+ {FOURCC_YU16, FOURCC_I422}, >+ {FOURCC_YU24, FOURCC_I444}, >+ {FOURCC_YUYV, FOURCC_YUY2}, >+ {FOURCC_YUVS, FOURCC_YUY2}, >+ {FOURCC_HDYC, FOURCC_UYVY}, >+ {FOURCC_2VUY, FOURCC_UYVY}, >+ {FOURCC_JPEG, FOURCC_MJPG}, // Note: JPEG has DHT while MJPG does not. >+ {FOURCC_DMB1, FOURCC_MJPG}, >+ {FOURCC_BA81, FOURCC_BGGR}, >+ {FOURCC_RGB3, FOURCC_RAW}, >+ {FOURCC_BGR3, FOURCC_24BG}, >+ {FOURCC_CM32, FOURCC_BGRA}, >+ {FOURCC_CM24, FOURCC_RAW}, > }; > > uint32_t CanonicalFourCC(uint32_t fourcc) { >@@ -62,7 +62,7 @@ const int64_t VideoFormat::kMinimumInterval; // Initialized in header. > std::string VideoFormat::ToString() const { > std::string fourcc_name = GetFourccName(fourcc) + " "; > for (std::string::const_iterator i = fourcc_name.begin(); >- i < fourcc_name.end(); ++i) { >+ i < fourcc_name.end(); ++i) { > // Test character is printable; Avoid isprint() which asserts on negatives. > if (*i < 32 || *i >= 127) { > fourcc_name = ""; >@@ -70,10 +70,11 @@ std::string VideoFormat::ToString() const { > } > } > >- std::ostringstream ss; >- ss << fourcc_name << width << "x" << height << "x" >+ char buf[256]; >+ rtc::SimpleStringBuilder sb(buf); >+ sb << fourcc_name << width << "x" << height << "x" > << IntervalToFpsFloat(interval); >- return ss.str(); >+ return sb.str(); > } > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.h >index 7415883eca4..0ffd989cb65 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videocommon.h >@@ -30,8 +30,7 @@ const uint32_t kDummyVideoSsrc = 0xFFFFFFFF; > > // Minimum interval is 10k fps. > #define FPS_TO_INTERVAL(fps) \ >- (fps ? rtc::kNumNanosecsPerSec / fps : \ >- rtc::kNumNanosecsPerSec / 10000) >+ (fps ? rtc::kNumNanosecsPerSec / fps : rtc::kNumNanosecsPerSec / 10000) > > ////////////////////////////////////////////////////////////////////////////// > // Definition of FourCC codes >@@ -39,7 +38,7 @@ const uint32_t kDummyVideoSsrc = 0xFFFFFFFF; > // Convert four characters to a FourCC code. > // Needs to be a macro otherwise the OS X compiler complains when the kFormat* > // constants are used in a switch. >-#define CRICKET_FOURCC(a, b, c, d) \ >+#define CRICKET_FOURCC(a, b, c, d) \ > ((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) | \ > (static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24)) > // Some pages discussing FourCC codes: >@@ -73,7 +72,7 @@ enum FourCC { > FOURCC_BGRA = CRICKET_FOURCC('B', 'G', 'R', 'A'), > FOURCC_ABGR = CRICKET_FOURCC('A', 'B', 'G', 'R'), > FOURCC_24BG = CRICKET_FOURCC('2', '4', 'B', 'G'), >- FOURCC_RAW = CRICKET_FOURCC('r', 'a', 'w', ' '), >+ FOURCC_RAW = CRICKET_FOURCC('r', 'a', 'w', ' '), > FOURCC_RGBA = CRICKET_FOURCC('R', 'G', 'B', 'A'), > FOURCC_RGBP = CRICKET_FOURCC('R', 'G', 'B', 'P'), // bgr565. > FOURCC_RGBO = CRICKET_FOURCC('R', 'G', 'B', 'O'), // abgr1555. >@@ -144,8 +143,8 @@ inline std::string GetFourccName(uint32_t fourcc) { > > // VideoFormat with Plain Old Data for global variables. > struct VideoFormatPod { >- int width; // Number of pixels. >- int height; // Number of pixels. >+ int width; // Number of pixels. >+ int height; // Number of pixels. > int64_t interval; // Nanoseconds. > uint32_t fourcc; // Color space. FOURCC_ANY means that any color space is OK. > }; >@@ -154,9 +153,7 @@ struct VideoFormat : VideoFormatPod { > static const int64_t kMinimumInterval = > rtc::kNumNanosecsPerSec / 10000; // 10k fps. > >- VideoFormat() { >- Construct(0, 0, 0, 0); >- } >+ VideoFormat() { Construct(0, 0, 0, 0); } > > VideoFormat(int w, int h, int64_t interval_ns, uint32_t cc) { > Construct(w, h, interval_ns, cc); >@@ -189,12 +186,12 @@ struct VideoFormat : VideoFormatPod { > return 0.f; > } > return static_cast<float>(rtc::kNumNanosecsPerSec) / >- static_cast<float>(interval); >+ static_cast<float>(interval); > } > > bool operator==(const VideoFormat& format) const { > return width == format.width && height == format.height && >- interval == format.interval && fourcc == format.fourcc; >+ interval == format.interval && fourcc == format.fourcc; > } > > bool operator!=(const VideoFormat& format) const { >@@ -203,10 +200,10 @@ struct VideoFormat : VideoFormatPod { > > bool operator<(const VideoFormat& format) const { > return (fourcc < format.fourcc) || >- (fourcc == format.fourcc && width < format.width) || >- (fourcc == format.fourcc && width == format.width && >+ (fourcc == format.fourcc && width < format.width) || >+ (fourcc == format.fourcc && width == format.width && > height < format.height) || >- (fourcc == format.fourcc && width == format.width && >+ (fourcc == format.fourcc && width == format.width && > height == format.height && interval > format.interval); > } > >@@ -219,7 +216,7 @@ struct VideoFormat : VideoFormatPod { > // and frame rate. > bool IsPixelRateLess(const VideoFormat& format) const { > return width * height * framerate() < >- format.width * format.height * format.framerate(); >+ format.width * format.height * format.framerate(); > } > > // Get a string presentation in the form of "fourcc width x height x fps" >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoengine_unittest.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoengine_unittest.h >deleted file mode 100644 >index acbfc8d69a2..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videoengine_unittest.h >+++ /dev/null >@@ -1,944 +0,0 @@ >-/* >- * Copyright (c) 2014 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. >- */ >- >-#ifndef MEDIA_BASE_VIDEOENGINE_UNITTEST_H_ // NOLINT >-#define MEDIA_BASE_VIDEOENGINE_UNITTEST_H_ >- >-#include <memory> >-#include <string> >-#include <vector> >- >-#include "call/call.h" >-#include "logging/rtc_event_log/rtc_event_log.h" >-#include "media/base/fakenetworkinterface.h" >-#include "media/base/fakevideocapturer.h" >-#include "media/base/fakevideorenderer.h" >-#include "media/base/mediachannel.h" >-#include "media/base/streamparams.h" >-#include "media/engine/fakewebrtccall.h" >-#include "rtc_base/bytebuffer.h" >-#include "rtc_base/gunit.h" >-#include "rtc_base/timeutils.h" >- >-namespace cricket { >-class WebRtcVideoEncoderFactory; >-class WebRtcVideoDecoderFactory; >-} // namespace cricket >- >-#define EXPECT_FRAME_WAIT(c, w, h, t) \ >- EXPECT_EQ_WAIT((c), renderer_.num_rendered_frames(), (t)); \ >- EXPECT_EQ((w), renderer_.width()); \ >- EXPECT_EQ((h), renderer_.height()); \ >- EXPECT_EQ(0, renderer_.errors()); \ >- >-#define EXPECT_FRAME_ON_RENDERER_WAIT(r, c, w, h, t) \ >- EXPECT_EQ_WAIT((c), (r).num_rendered_frames(), (t)); \ >- EXPECT_EQ((w), (r).width()); \ >- EXPECT_EQ((h), (r).height()); \ >- EXPECT_EQ(0, (r).errors()); \ >- >-#define EXPECT_GT_FRAME_ON_RENDERER_WAIT(r, c, w, h, t) \ >- EXPECT_TRUE_WAIT((r).num_rendered_frames() >= (c) && \ >- (w) == (r).width() && \ >- (h) == (r).height(), (t)); \ >- EXPECT_EQ(0, (r).errors()); >- >-static const uint32_t kTimeout = 5000U; >-static const uint32_t kDefaultReceiveSsrc = 0; >-static const uint32_t kSsrc = 1234u; >-static const uint32_t kRtxSsrc = 4321u; >-static const uint32_t kSsrcs4[] = {1, 2, 3, 4}; >-static const int kVideoWidth = 640; >-static const int kVideoHeight = 360; >-static const int kFramerate = 30; >- >-inline bool IsEqualCodec(const cricket::VideoCodec& a, >- const cricket::VideoCodec& b) { >- return a.id == b.id && a.name == b.name; >-} >- >-template<class E, class C> >-class VideoMediaChannelTest : public testing::Test, >- public sigslot::has_slots<> { >- protected: >- VideoMediaChannelTest<E, C>() >- : call_(webrtc::Call::Create(webrtc::Call::Config(&event_log_))), >- engine_(std::unique_ptr<cricket::WebRtcVideoEncoderFactory>(), >- std::unique_ptr<cricket::WebRtcVideoDecoderFactory>()) {} >- >- virtual cricket::VideoCodec DefaultCodec() = 0; >- >- virtual cricket::StreamParams DefaultSendStreamParams() { >- return cricket::StreamParams::CreateLegacy(kSsrc); >- } >- >- virtual void SetUp() { >- cricket::MediaConfig media_config; >- // Disabling cpu overuse detection actually disables quality scaling too; it >- // implies DegradationPreference kMaintainResolution. Automatic scaling >- // needs to be disabled, otherwise, tests which check the size of received >- // frames become flaky. >- media_config.video.enable_cpu_overuse_detection = false; >- channel_.reset(engine_.CreateChannel(call_.get(), media_config, >- cricket::VideoOptions())); >- channel_->OnReadyToSend(true); >- EXPECT_TRUE(channel_.get() != NULL); >- network_interface_.SetDestination(channel_.get()); >- channel_->SetInterface(&network_interface_); >- cricket::VideoRecvParameters parameters; >- parameters.codecs = engine_.codecs(); >- channel_->SetRecvParameters(parameters); >- EXPECT_TRUE(channel_->AddSendStream(DefaultSendStreamParams())); >- video_capturer_.reset(CreateFakeVideoCapturer()); >- cricket::VideoFormat format(640, 480, >- cricket::VideoFormat::FpsToInterval(kFramerate), >- cricket::FOURCC_I420); >- EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(format)); >- EXPECT_TRUE( >- channel_->SetVideoSend(kSsrc, true, nullptr, video_capturer_.get())); >- } >- >- virtual cricket::FakeVideoCapturer* CreateFakeVideoCapturer() { >- return new cricket::FakeVideoCapturer(); >- } >- >- // Utility method to setup an additional stream to send and receive video. >- // Used to test send and recv between two streams. >- void SetUpSecondStream() { >- SetUpSecondStreamWithNoRecv(); >- // Setup recv for second stream. >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(kSsrc + 2))); >- // Make the second renderer available for use by a new stream. >- EXPECT_TRUE(channel_->SetSink(kSsrc + 2, &renderer2_)); >- } >- // Setup an additional stream just to send video. Defer add recv stream. >- // This is required if you want to test unsignalled recv of video rtp packets. >- void SetUpSecondStreamWithNoRecv() { >- // SetUp() already added kSsrc make sure duplicate SSRCs cant be added. >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(kSsrc))); >- EXPECT_TRUE(channel_->SetSink(kSsrc, &renderer_)); >- EXPECT_FALSE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(kSsrc))); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(kSsrc + 2))); >- // We dont add recv for the second stream. >- >- // Setup the receive and renderer for second stream after send. >- video_capturer_2_.reset(CreateFakeVideoCapturer()); >- cricket::VideoFormat format(640, 480, >- cricket::VideoFormat::FpsToInterval(kFramerate), >- cricket::FOURCC_I420); >- EXPECT_EQ(cricket::CS_RUNNING, video_capturer_2_->Start(format)); >- >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc + 2, true, nullptr, >- video_capturer_2_.get())); >- } >- virtual void TearDown() { >- channel_.reset(); >- } >- bool SetDefaultCodec() { >- return SetOneCodec(DefaultCodec()); >- } >- >- bool SetOneCodec(int pt, const char* name) { >- return SetOneCodec(cricket::VideoCodec(pt, name)); >- } >- bool SetOneCodec(const cricket::VideoCodec& codec) { >- cricket::VideoFormat capture_format( >- kVideoWidth, kVideoHeight, >- cricket::VideoFormat::FpsToInterval(kFramerate), cricket::FOURCC_I420); >- >- if (video_capturer_) { >- EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format)); >- } >- if (video_capturer_2_) { >- EXPECT_EQ(cricket::CS_RUNNING, video_capturer_2_->Start(capture_format)); >- } >- >- bool sending = channel_->sending(); >- bool success = SetSend(false); >- if (success) { >- cricket::VideoSendParameters parameters; >- parameters.codecs.push_back(codec); >- success = channel_->SetSendParameters(parameters); >- } >- if (success) { >- success = SetSend(sending); >- } >- return success; >- } >- bool SetSend(bool send) { >- return channel_->SetSend(send); >- } >- int DrainOutgoingPackets() { >- int packets = 0; >- do { >- packets = NumRtpPackets(); >- // 100 ms should be long enough. >- rtc::Thread::Current()->ProcessMessages(100); >- } while (NumRtpPackets() > packets); >- return NumRtpPackets(); >- } >- bool SendFrame() { >- if (video_capturer_2_) { >- video_capturer_2_->CaptureFrame(); >- } >- return video_capturer_.get() && >- video_capturer_->CaptureFrame(); >- } >- bool WaitAndSendFrame(int wait_ms) { >- bool ret = rtc::Thread::Current()->ProcessMessages(wait_ms); >- ret &= SendFrame(); >- return ret; >- } >- // Sends frames and waits for the decoder to be fully initialized. >- // Returns the number of frames that were sent. >- int WaitForDecoder() { >-#if defined(HAVE_OPENMAX) >- // Send enough frames for the OpenMAX decoder to continue processing, and >- // return the number of frames sent. >- // Send frames for a full kTimeout's worth of 15fps video. >- int frame_count = 0; >- while (frame_count < static_cast<int>(kTimeout) / 66) { >- EXPECT_TRUE(WaitAndSendFrame(66)); >- ++frame_count; >- } >- return frame_count; >-#else >- return 0; >-#endif >- } >- bool SendCustomVideoFrame(int w, int h) { >- if (!video_capturer_.get()) return false; >- return video_capturer_->CaptureCustomFrame(w, h, cricket::FOURCC_I420); >- } >- int NumRtpBytes() { >- return network_interface_.NumRtpBytes(); >- } >- int NumRtpBytes(uint32_t ssrc) { >- return network_interface_.NumRtpBytes(ssrc); >- } >- int NumRtpPackets() { >- return network_interface_.NumRtpPackets(); >- } >- int NumRtpPackets(uint32_t ssrc) { >- return network_interface_.NumRtpPackets(ssrc); >- } >- int NumSentSsrcs() { >- return network_interface_.NumSentSsrcs(); >- } >- const rtc::CopyOnWriteBuffer* GetRtpPacket(int index) { >- return network_interface_.GetRtpPacket(index); >- } >- int NumRtcpPackets() { >- return network_interface_.NumRtcpPackets(); >- } >- const rtc::CopyOnWriteBuffer* GetRtcpPacket(int index) { >- return network_interface_.GetRtcpPacket(index); >- } >- static int GetPayloadType(const rtc::CopyOnWriteBuffer* p) { >- int pt = -1; >- ParseRtpPacket(p, NULL, &pt, NULL, NULL, NULL, NULL); >- return pt; >- } >- static bool ParseRtpPacket(const rtc::CopyOnWriteBuffer* p, >- bool* x, >- int* pt, >- int* seqnum, >- uint32_t* tstamp, >- uint32_t* ssrc, >- std::string* payload) { >- rtc::ByteBufferReader buf(p->data<char>(), p->size()); >- uint8_t u08 = 0; >- uint16_t u16 = 0; >- uint32_t u32 = 0; >- >- // Read X and CC fields. >- if (!buf.ReadUInt8(&u08)) return false; >- bool extension = ((u08 & 0x10) != 0); >- uint8_t cc = (u08 & 0x0F); >- if (x) *x = extension; >- >- // Read PT field. >- if (!buf.ReadUInt8(&u08)) return false; >- if (pt) *pt = (u08 & 0x7F); >- >- // Read Sequence Number field. >- if (!buf.ReadUInt16(&u16)) return false; >- if (seqnum) *seqnum = u16; >- >- // Read Timestamp field. >- if (!buf.ReadUInt32(&u32)) return false; >- if (tstamp) *tstamp = u32; >- >- // Read SSRC field. >- if (!buf.ReadUInt32(&u32)) return false; >- if (ssrc) *ssrc = u32; >- >- // Skip CSRCs. >- for (uint8_t i = 0; i < cc; ++i) { >- if (!buf.ReadUInt32(&u32)) return false; >- } >- >- // Skip extension header. >- if (extension) { >- // Read Profile-specific extension header ID >- if (!buf.ReadUInt16(&u16)) return false; >- >- // Read Extension header length >- if (!buf.ReadUInt16(&u16)) return false; >- uint16_t ext_header_len = u16; >- >- // Read Extension header >- for (uint16_t i = 0; i < ext_header_len; ++i) { >- if (!buf.ReadUInt32(&u32)) return false; >- } >- } >- >- if (payload) { >- return buf.ReadString(payload, buf.Length()); >- } >- return true; >- } >- >- // Parse all RTCP packet, from start_index to stop_index, and count how many >- // FIR (PT=206 and FMT=4 according to RFC 5104). If successful, set the count >- // and return true. >- bool CountRtcpFir(int start_index, int stop_index, int* fir_count) { >- int count = 0; >- for (int i = start_index; i < stop_index; ++i) { >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtcpPacket(i)); >- rtc::ByteBufferReader buf(p->data<char>(), p->size()); >- size_t total_len = 0; >- // The packet may be a compound RTCP packet. >- while (total_len < p->size()) { >- // Read FMT, type and length. >- uint8_t fmt = 0; >- uint8_t type = 0; >- uint16_t length = 0; >- if (!buf.ReadUInt8(&fmt)) return false; >- fmt &= 0x1F; >- if (!buf.ReadUInt8(&type)) return false; >- if (!buf.ReadUInt16(&length)) return false; >- buf.Consume(length * 4); // Skip RTCP data. >- total_len += (length + 1) * 4; >- if ((192 == type) || ((206 == type) && (4 == fmt))) { >- ++count; >- } >- } >- } >- >- if (fir_count) { >- *fir_count = count; >- } >- return true; >- } >- >- // Test that SetSend works. >- void SetSend() { >- EXPECT_FALSE(channel_->sending()); >- EXPECT_TRUE( >- channel_->SetVideoSend(kSsrc, true, nullptr, video_capturer_.get())); >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- EXPECT_FALSE(channel_->sending()); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->sending()); >- EXPECT_TRUE(SendFrame()); >- EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); >- EXPECT_TRUE(SetSend(false)); >- EXPECT_FALSE(channel_->sending()); >- } >- // Test that SetSend fails without codecs being set. >- void SetSendWithoutCodecs() { >- EXPECT_FALSE(channel_->sending()); >- EXPECT_FALSE(SetSend(true)); >- EXPECT_FALSE(channel_->sending()); >- } >- // Test that we properly set the send and recv buffer sizes by the time >- // SetSend is called. >- void SetSendSetsTransportBufferSizes() { >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_EQ(64 * 1024, network_interface_.sendbuf_size()); >- EXPECT_EQ(64 * 1024, network_interface_.recvbuf_size()); >- } >- // Tests that we can send frames and the right payload type is used. >- void Send(const cricket::VideoCodec& codec) { >- EXPECT_TRUE(SetOneCodec(codec)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(SendFrame()); >- EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- EXPECT_EQ(codec.id, GetPayloadType(p.get())); >- } >- // Tests that we can send and receive frames. >- void SendAndReceive(const cricket::VideoCodec& codec) { >- EXPECT_TRUE(SetOneCodec(codec)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_EQ(0, renderer_.num_rendered_frames()); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- EXPECT_EQ(codec.id, GetPayloadType(p.get())); >- } >- void SendReceiveManyAndGetStats(const cricket::VideoCodec& codec, >- int duration_sec, int fps) { >- EXPECT_TRUE(SetOneCodec(codec)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_EQ(0, renderer_.num_rendered_frames()); >- for (int i = 0; i < duration_sec; ++i) { >- for (int frame = 1; frame <= fps; ++frame) { >- EXPECT_TRUE(WaitAndSendFrame(1000 / fps)); >- EXPECT_FRAME_WAIT(frame + i * fps, kVideoWidth, kVideoHeight, kTimeout); >- } >- } >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- EXPECT_EQ(codec.id, GetPayloadType(p.get())); >- } >- >- // Test that stats work properly for a 1-1 call. >- void GetStats() { >- const int kDurationSec = 3; >- const int kFps = 10; >- SendReceiveManyAndGetStats(DefaultCodec(), kDurationSec, kFps); >- >- cricket::VideoMediaInfo info; >- EXPECT_TRUE(channel_->GetStats(&info)); >- >- ASSERT_EQ(1U, info.senders.size()); >- // TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload? >- // For webrtc, bytes_sent does not include the RTP header length. >- EXPECT_GT(info.senders[0].bytes_sent, 0); >- EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent); >- EXPECT_EQ(0.0, info.senders[0].fraction_lost); >- ASSERT_TRUE(info.senders[0].codec_payload_type); >- EXPECT_EQ(DefaultCodec().id, *info.senders[0].codec_payload_type); >- EXPECT_EQ(0, info.senders[0].firs_rcvd); >- EXPECT_EQ(0, info.senders[0].plis_rcvd); >- EXPECT_EQ(0, info.senders[0].nacks_rcvd); >- EXPECT_EQ(kVideoWidth, info.senders[0].send_frame_width); >- EXPECT_EQ(kVideoHeight, info.senders[0].send_frame_height); >- EXPECT_GT(info.senders[0].framerate_input, 0); >- EXPECT_GT(info.senders[0].framerate_sent, 0); >- >- EXPECT_EQ(1U, info.send_codecs.count(DefaultCodec().id)); >- EXPECT_EQ(DefaultCodec().ToCodecParameters(), >- info.send_codecs[DefaultCodec().id]); >- >- ASSERT_EQ(1U, info.receivers.size()); >- EXPECT_EQ(1U, info.senders[0].ssrcs().size()); >- EXPECT_EQ(1U, info.receivers[0].ssrcs().size()); >- EXPECT_EQ(info.senders[0].ssrcs()[0], info.receivers[0].ssrcs()[0]); >- ASSERT_TRUE(info.receivers[0].codec_payload_type); >- EXPECT_EQ(DefaultCodec().id, *info.receivers[0].codec_payload_type); >- EXPECT_EQ(NumRtpBytes(), info.receivers[0].bytes_rcvd); >- EXPECT_EQ(NumRtpPackets(), info.receivers[0].packets_rcvd); >- EXPECT_EQ(0.0, info.receivers[0].fraction_lost); >- EXPECT_EQ(0, info.receivers[0].packets_lost); >- // TODO(asapersson): Not set for webrtc. Handle missing stats. >- // EXPECT_EQ(0, info.receivers[0].packets_concealed); >- EXPECT_EQ(0, info.receivers[0].firs_sent); >- EXPECT_EQ(0, info.receivers[0].plis_sent); >- EXPECT_EQ(0, info.receivers[0].nacks_sent); >- EXPECT_EQ(kVideoWidth, info.receivers[0].frame_width); >- EXPECT_EQ(kVideoHeight, info.receivers[0].frame_height); >- EXPECT_GT(info.receivers[0].framerate_rcvd, 0); >- EXPECT_GT(info.receivers[0].framerate_decoded, 0); >- EXPECT_GT(info.receivers[0].framerate_output, 0); >- >- EXPECT_EQ(1U, info.receive_codecs.count(DefaultCodec().id)); >- EXPECT_EQ(DefaultCodec().ToCodecParameters(), >- info.receive_codecs[DefaultCodec().id]); >- } >- >- cricket::VideoSenderInfo GetSenderStats(size_t i) { >- cricket::VideoMediaInfo info; >- EXPECT_TRUE(channel_->GetStats(&info)); >- return info.senders[i]; >- } >- >- cricket::VideoReceiverInfo GetReceiverStats(size_t i) { >- cricket::VideoMediaInfo info; >- EXPECT_TRUE(channel_->GetStats(&info)); >- return info.receivers[i]; >- } >- >- // Test that stats work properly for a conf call with multiple recv streams. >- void GetStatsMultipleRecvStreams() { >- cricket::FakeVideoRenderer renderer1, renderer2; >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- cricket::VideoSendParameters parameters; >- parameters.codecs.push_back(DefaultCodec()); >- parameters.conference_mode = true; >- EXPECT_TRUE(channel_->SetSendParameters(parameters)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(1))); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(2))); >- EXPECT_TRUE(channel_->SetSink(1, &renderer1)); >- EXPECT_TRUE(channel_->SetSink(2, &renderer2)); >- EXPECT_EQ(0, renderer1.num_rendered_frames()); >- EXPECT_EQ(0, renderer2.num_rendered_frames()); >- std::vector<uint32_t> ssrcs; >- ssrcs.push_back(1); >- ssrcs.push_back(2); >- network_interface_.SetConferenceMode(true, ssrcs); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, kVideoWidth, kVideoHeight, >- kTimeout); >- EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1, kVideoWidth, kVideoHeight, >- kTimeout); >- >- EXPECT_TRUE(channel_->SetSend(false)); >- >- cricket::VideoMediaInfo info; >- EXPECT_TRUE(channel_->GetStats(&info)); >- ASSERT_EQ(1U, info.senders.size()); >- // TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload? >- // For webrtc, bytes_sent does not include the RTP header length. >- EXPECT_GT(GetSenderStats(0).bytes_sent, 0); >- EXPECT_EQ_WAIT(NumRtpPackets(), GetSenderStats(0).packets_sent, kTimeout); >- EXPECT_EQ(kVideoWidth, GetSenderStats(0).send_frame_width); >- EXPECT_EQ(kVideoHeight, GetSenderStats(0).send_frame_height); >- >- ASSERT_EQ(2U, info.receivers.size()); >- for (size_t i = 0; i < info.receivers.size(); ++i) { >- EXPECT_EQ(1U, GetReceiverStats(i).ssrcs().size()); >- EXPECT_EQ(i + 1, GetReceiverStats(i).ssrcs()[0]); >- EXPECT_EQ_WAIT(NumRtpBytes(), GetReceiverStats(i).bytes_rcvd, kTimeout); >- EXPECT_EQ_WAIT(NumRtpPackets(), GetReceiverStats(i).packets_rcvd, >- kTimeout); >- EXPECT_EQ_WAIT(kVideoWidth, GetReceiverStats(i).frame_width, kTimeout); >- EXPECT_EQ_WAIT(kVideoHeight, GetReceiverStats(i).frame_height, kTimeout); >- } >- } >- // Test that stats work properly for a conf call with multiple send streams. >- void GetStatsMultipleSendStreams() { >- // Normal setup; note that we set the SSRC explicitly to ensure that >- // it will come first in the senders map. >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- cricket::VideoSendParameters parameters; >- parameters.codecs.push_back(DefaultCodec()); >- parameters.conference_mode = true; >- EXPECT_TRUE(channel_->SetSendParameters(parameters)); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(kSsrc))); >- EXPECT_TRUE(channel_->SetSink(kSsrc, &renderer_)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(SendFrame()); >- EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- >- // Add an additional capturer, and hook up a renderer to receive it. >- cricket::FakeVideoRenderer renderer2; >- std::unique_ptr<cricket::FakeVideoCapturer> capturer( >- CreateFakeVideoCapturer()); >- const int kTestWidth = 160; >- const int kTestHeight = 120; >- cricket::VideoFormat format(kTestWidth, kTestHeight, >- cricket::VideoFormat::FpsToInterval(5), >- cricket::FOURCC_I420); >- EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format)); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(5678))); >- EXPECT_TRUE(channel_->SetVideoSend(5678, true, nullptr, capturer.get())); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(5678))); >- EXPECT_TRUE(channel_->SetSink(5678, &renderer2)); >- EXPECT_TRUE(capturer->CaptureCustomFrame( >- kTestWidth, kTestHeight, cricket::FOURCC_I420)); >- EXPECT_FRAME_ON_RENDERER_WAIT( >- renderer2, 1, kTestWidth, kTestHeight, kTimeout); >- >- // Get stats, and make sure they are correct for two senders. We wait until >- // the number of expected packets have been sent to avoid races where we >- // check stats before it has been updated. >- cricket::VideoMediaInfo info; >- for (uint32_t i = 0; i < kTimeout; ++i) { >- rtc::Thread::Current()->ProcessMessages(1); >- EXPECT_TRUE(channel_->GetStats(&info)); >- ASSERT_EQ(2U, info.senders.size()); >- if (info.senders[0].packets_sent + info.senders[1].packets_sent == >- NumRtpPackets()) { >- // Stats have been updated for both sent frames, expectations can be >- // checked now. >- break; >- } >- } >- EXPECT_EQ(NumRtpPackets(), >- info.senders[0].packets_sent + info.senders[1].packets_sent) >- << "Timed out while waiting for packet counts for all sent packets."; >- EXPECT_EQ(1U, info.senders[0].ssrcs().size()); >- EXPECT_EQ(1234U, info.senders[0].ssrcs()[0]); >- EXPECT_EQ(kVideoWidth, info.senders[0].send_frame_width); >- EXPECT_EQ(kVideoHeight, info.senders[0].send_frame_height); >- EXPECT_EQ(1U, info.senders[1].ssrcs().size()); >- EXPECT_EQ(5678U, info.senders[1].ssrcs()[0]); >- EXPECT_EQ(kTestWidth, info.senders[1].send_frame_width); >- EXPECT_EQ(kTestHeight, info.senders[1].send_frame_height); >- // The capturer must be unregistered here as it runs out of it's scope next. >- channel_->SetVideoSend(5678, true, nullptr, nullptr); >- } >- >- // Test that we can set the bandwidth. >- void SetSendBandwidth() { >- cricket::VideoSendParameters parameters; >- parameters.codecs.push_back(DefaultCodec()); >- parameters.max_bandwidth_bps = -1; // <= 0 means unlimited. >- EXPECT_TRUE(channel_->SetSendParameters(parameters)); >- parameters.max_bandwidth_bps = 128 * 1024; >- EXPECT_TRUE(channel_->SetSendParameters(parameters)); >- } >- // Test that we can set the SSRC for the default send source. >- void SetSendSsrc() { >- EXPECT_TRUE(SetDefaultCodec()); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(SendFrame()); >- EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); >- uint32_t ssrc = 0; >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); >- EXPECT_EQ(kSsrc, ssrc); >- // Packets are being paced out, so these can mismatch between the first and >- // second call to NumRtpPackets until pending packets are paced out. >- EXPECT_EQ_WAIT(NumRtpPackets(), NumRtpPackets(ssrc), kTimeout); >- EXPECT_EQ_WAIT(NumRtpBytes(), NumRtpBytes(ssrc), kTimeout); >- EXPECT_EQ(1, NumSentSsrcs()); >- EXPECT_EQ(0, NumRtpPackets(kSsrc - 1)); >- EXPECT_EQ(0, NumRtpBytes(kSsrc - 1)); >- } >- // Test that we can set the SSRC even after codecs are set. >- void SetSendSsrcAfterSetCodecs() { >- // Remove stream added in Setup. >- EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); >- EXPECT_TRUE(SetDefaultCodec()); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(999))); >- EXPECT_TRUE( >- channel_->SetVideoSend(999u, true, nullptr, video_capturer_.get())); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(WaitAndSendFrame(0)); >- EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout); >- uint32_t ssrc = 0; >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); >- EXPECT_EQ(999u, ssrc); >- // Packets are being paced out, so these can mismatch between the first and >- // second call to NumRtpPackets until pending packets are paced out. >- EXPECT_EQ_WAIT(NumRtpPackets(), NumRtpPackets(ssrc), kTimeout); >- EXPECT_EQ_WAIT(NumRtpBytes(), NumRtpBytes(ssrc), kTimeout); >- EXPECT_EQ(1, NumSentSsrcs()); >- EXPECT_EQ(0, NumRtpPackets(kSsrc)); >- EXPECT_EQ(0, NumRtpBytes(kSsrc)); >- } >- // Test that we can set the default video renderer before and after >- // media is received. >- void SetSink() { >- uint8_t data1[] = { >- 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; >- >- rtc::CopyOnWriteBuffer packet1(data1, sizeof(data1)); >- rtc::SetBE32(packet1.data() + 8, kSsrc); >- channel_->SetSink(kDefaultReceiveSsrc, NULL); >- EXPECT_TRUE(SetDefaultCodec()); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_EQ(0, renderer_.num_rendered_frames()); >- channel_->OnPacketReceived(&packet1, rtc::PacketTime()); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- } >- >- // Tests empty StreamParams is rejected. >- void RejectEmptyStreamParams() { >- // Remove the send stream that was added during Setup. >- EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); >- >- cricket::StreamParams empty; >- EXPECT_FALSE(channel_->AddSendStream(empty)); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(789u))); >- } >- >- // Tests setting up and configuring a send stream. >- void AddRemoveSendStreams() { >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- EXPECT_GT(NumRtpPackets(), 0); >- uint32_t ssrc = 0; >- size_t last_packet = NumRtpPackets() - 1; >- std::unique_ptr<const rtc::CopyOnWriteBuffer> >- p(GetRtpPacket(static_cast<int>(last_packet))); >- ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); >- EXPECT_EQ(kSsrc, ssrc); >- >- // Remove the send stream that was added during Setup. >- EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); >- int rtp_packets = NumRtpPackets(); >- >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(789u))); >- EXPECT_TRUE( >- channel_->SetVideoSend(789u, true, nullptr, video_capturer_.get())); >- EXPECT_EQ(rtp_packets, NumRtpPackets()); >- // Wait 30ms to guarantee the engine does not drop the frame. >- EXPECT_TRUE(WaitAndSendFrame(30)); >- EXPECT_TRUE_WAIT(NumRtpPackets() > rtp_packets, kTimeout); >- >- last_packet = NumRtpPackets() - 1; >- p.reset(GetRtpPacket(static_cast<int>(last_packet))); >- ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL); >- EXPECT_EQ(789u, ssrc); >- } >- >- // Tests the behavior of incoming streams in a conference scenario. >- void SimulateConference() { >- cricket::FakeVideoRenderer renderer1, renderer2; >- EXPECT_TRUE(SetDefaultCodec()); >- cricket::VideoSendParameters parameters; >- parameters.codecs.push_back(DefaultCodec()); >- parameters.conference_mode = true; >- EXPECT_TRUE(channel_->SetSendParameters(parameters)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(1))); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(2))); >- EXPECT_TRUE(channel_->SetSink(1, &renderer1)); >- EXPECT_TRUE(channel_->SetSink(2, &renderer2)); >- EXPECT_EQ(0, renderer1.num_rendered_frames()); >- EXPECT_EQ(0, renderer2.num_rendered_frames()); >- std::vector<uint32_t> ssrcs; >- ssrcs.push_back(1); >- ssrcs.push_back(2); >- network_interface_.SetConferenceMode(true, ssrcs); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, kVideoWidth, kVideoHeight, >- kTimeout); >- EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1, kVideoWidth, kVideoHeight, >- kTimeout); >- >- std::unique_ptr<const rtc::CopyOnWriteBuffer> p(GetRtpPacket(0)); >- EXPECT_EQ(DefaultCodec().id, GetPayloadType(p.get())); >- EXPECT_EQ(kVideoWidth, renderer1.width()); >- EXPECT_EQ(kVideoHeight, renderer1.height()); >- EXPECT_EQ(kVideoWidth, renderer2.width()); >- EXPECT_EQ(kVideoHeight, renderer2.height()); >- EXPECT_TRUE(channel_->RemoveRecvStream(2)); >- EXPECT_TRUE(channel_->RemoveRecvStream(1)); >- } >- >- // Tests that we can add and remove capturers and frames are sent out properly >- void AddRemoveCapturer() { >- cricket::VideoCodec codec = DefaultCodec(); >- const int time_between_send_ms = >- cricket::VideoFormat::FpsToInterval(kFramerate); >- EXPECT_TRUE(SetOneCodec(codec)); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_EQ(0, renderer_.num_rendered_frames()); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- std::unique_ptr<cricket::FakeVideoCapturer> capturer( >- CreateFakeVideoCapturer()); >- >- // TODO(nisse): This testcase fails if we don't configure >- // screencast. It's unclear why, I see nothing obvious in this >- // test which is related to screencast logic. >- cricket::VideoOptions video_options; >- video_options.is_screencast = true; >- channel_->SetVideoSend(kSsrc, true, &video_options, nullptr); >- >- cricket::VideoFormat format(480, 360, >- cricket::VideoFormat::FpsToInterval(30), >- cricket::FOURCC_I420); >- EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format)); >- // All capturers start generating frames with the same timestamp. ViE does >- // not allow the same timestamp to be used. Capture one frame before >- // associating the capturer with the channel. >- EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, >- cricket::FOURCC_I420)); >- >- int captured_frames = 1; >- for (int iterations = 0; iterations < 2; ++iterations) { >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, capturer.get())); >- rtc::Thread::Current()->ProcessMessages(time_between_send_ms); >- EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, >- cricket::FOURCC_I420)); >- ++captured_frames; >- // Wait until frame of right size is captured. >- EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= captured_frames && >- format.width == renderer_.width() && >- format.height == renderer_.height() && >- !renderer_.black_frame(), kTimeout); >- EXPECT_GE(renderer_.num_rendered_frames(), captured_frames); >- EXPECT_EQ(format.width, renderer_.width()); >- EXPECT_EQ(format.height, renderer_.height()); >- captured_frames = renderer_.num_rendered_frames() + 1; >- EXPECT_FALSE(renderer_.black_frame()); >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr)); >- // Make sure a black frame is generated within the specified timeout. >- // The black frame should be the resolution of the previous frame to >- // prevent expensive encoder reconfigurations. >- EXPECT_TRUE_WAIT(renderer_.num_rendered_frames() >= captured_frames && >- format.width == renderer_.width() && >- format.height == renderer_.height() && >- renderer_.black_frame(), kTimeout); >- EXPECT_GE(renderer_.num_rendered_frames(), captured_frames); >- EXPECT_EQ(format.width, renderer_.width()); >- EXPECT_EQ(format.height, renderer_.height()); >- EXPECT_TRUE(renderer_.black_frame()); >- >- // The black frame has the same timestamp as the next frame since it's >- // timestamp is set to the last frame's timestamp + interval. WebRTC will >- // not render a frame with the same timestamp so capture another frame >- // with the frame capturer to increment the next frame's timestamp. >- EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height, >- cricket::FOURCC_I420)); >- } >- } >- >- // Tests that if SetVideoSend is called with a NULL capturer after the >- // capturer was already removed, the application doesn't crash (and no black >- // frame is sent). >- void RemoveCapturerWithoutAdd() { >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- EXPECT_TRUE(SetSend(true)); >- EXPECT_TRUE(channel_->SetSink(kDefaultReceiveSsrc, &renderer_)); >- EXPECT_EQ(0, renderer_.num_rendered_frames()); >- EXPECT_TRUE(SendFrame()); >- EXPECT_FRAME_WAIT(1, kVideoWidth, kVideoHeight, kTimeout); >- // Wait for one frame so they don't get dropped because we send frames too >- // tightly. >- rtc::Thread::Current()->ProcessMessages(30); >- // Remove the capturer. >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr)); >- >- // No capturer was added, so this SetVideoSend shouldn't do anything. >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr)); >- rtc::Thread::Current()->ProcessMessages(300); >- // Verify no more frames were sent. >- EXPECT_EQ(1, renderer_.num_rendered_frames()); >- } >- >- // Tests that we can add and remove capturer as unique sources. >- void AddRemoveCapturerMultipleSources() { >- // WebRTC implementation will drop frames if pushed to quickly. Wait the >- // interval time to avoid that. >- // WebRTC implementation will drop frames if pushed to quickly. Wait the >- // interval time to avoid that. >- // Set up the stream associated with the engine. >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(kSsrc))); >- EXPECT_TRUE(channel_->SetSink(kSsrc, &renderer_)); >- cricket::VideoFormat capture_format; // default format >- capture_format.interval = cricket::VideoFormat::FpsToInterval(kFramerate); >- // Set up additional stream 1. >- cricket::FakeVideoRenderer renderer1; >- EXPECT_FALSE(channel_->SetSink(1, &renderer1)); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(1))); >- EXPECT_TRUE(channel_->SetSink(1, &renderer1)); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(1))); >- std::unique_ptr<cricket::FakeVideoCapturer> capturer1( >- CreateFakeVideoCapturer()); >- EXPECT_EQ(cricket::CS_RUNNING, capturer1->Start(capture_format)); >- // Set up additional stream 2. >- cricket::FakeVideoRenderer renderer2; >- EXPECT_FALSE(channel_->SetSink(2, &renderer2)); >- EXPECT_TRUE(channel_->AddRecvStream( >- cricket::StreamParams::CreateLegacy(2))); >- EXPECT_TRUE(channel_->SetSink(2, &renderer2)); >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(2))); >- std::unique_ptr<cricket::FakeVideoCapturer> capturer2( >- CreateFakeVideoCapturer()); >- EXPECT_EQ(cricket::CS_RUNNING, capturer2->Start(capture_format)); >- // State for all the streams. >- EXPECT_TRUE(SetOneCodec(DefaultCodec())); >- // A limitation in the lmi implementation requires that SetVideoSend() is >- // called after SetOneCodec(). >- // TODO(hellner): this seems like an unnecessary constraint, fix it. >- EXPECT_TRUE(channel_->SetVideoSend(1, true, nullptr, capturer1.get())); >- EXPECT_TRUE(channel_->SetVideoSend(2, true, nullptr, capturer2.get())); >- EXPECT_TRUE(SetSend(true)); >- // Test capturer associated with engine. >- const int kTestWidth = 160; >- const int kTestHeight = 120; >- EXPECT_TRUE(capturer1->CaptureCustomFrame( >- kTestWidth, kTestHeight, cricket::FOURCC_I420)); >- EXPECT_FRAME_ON_RENDERER_WAIT( >- renderer1, 1, kTestWidth, kTestHeight, kTimeout); >- // Capture a frame with additional capturer2, frames should be received >- EXPECT_TRUE(capturer2->CaptureCustomFrame( >- kTestWidth, kTestHeight, cricket::FOURCC_I420)); >- EXPECT_FRAME_ON_RENDERER_WAIT( >- renderer2, 1, kTestWidth, kTestHeight, kTimeout); >- // Successfully remove the capturer. >- EXPECT_TRUE(channel_->SetVideoSend(kSsrc, true, nullptr, nullptr)); >- // The capturers must be unregistered here as it runs out of it's scope >- // next. >- EXPECT_TRUE(channel_->SetVideoSend(1, true, nullptr, nullptr)); >- EXPECT_TRUE(channel_->SetVideoSend(2, true, nullptr, nullptr)); >- } >- >- // Test that multiple send streams can be created and deleted properly. >- void MultipleSendStreams() { >- // Remove stream added in Setup. I.e. remove stream corresponding to default >- // channel. >- EXPECT_TRUE(channel_->RemoveSendStream(kSsrc)); >- const unsigned int kSsrcsSize = sizeof(kSsrcs4)/sizeof(kSsrcs4[0]); >- for (unsigned int i = 0; i < kSsrcsSize; ++i) { >- EXPECT_TRUE(channel_->AddSendStream( >- cricket::StreamParams::CreateLegacy(kSsrcs4[i]))); >- } >- // Delete one of the non default channel streams, let the destructor delete >- // the remaining ones. >- EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1])); >- // Stream should already be deleted. >- EXPECT_FALSE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1])); >- } >- >- // Two streams one channel tests. >- >- // Tests that we can send and receive frames. >- void TwoStreamsSendAndReceive(const cricket::VideoCodec& codec) { >- SetUpSecondStream(); >- // Test sending and receiving on first stream. >- SendAndReceive(codec); >- // Test sending and receiving on second stream. >- EXPECT_EQ_WAIT(1, renderer2_.num_rendered_frames(), kTimeout); >- EXPECT_GT(NumRtpPackets(), 0); >- EXPECT_EQ(1, renderer2_.num_rendered_frames()); >- } >- >- webrtc::RtcEventLogNullImpl event_log_; >- const std::unique_ptr<webrtc::Call> call_; >- E engine_; >- std::unique_ptr<cricket::FakeVideoCapturer> video_capturer_; >- std::unique_ptr<cricket::FakeVideoCapturer> video_capturer_2_; >- std::unique_ptr<C> channel_; >- cricket::FakeNetworkInterface network_interface_; >- cricket::FakeVideoRenderer renderer_; >- >- // Used by test cases where 2 streams are run on the same channel. >- cricket::FakeVideoRenderer renderer2_; >-}; >- >-#endif // MEDIA_BASE_VIDEOENGINE_UNITTEST_H_ NOLINT >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.cc >index 299795fca6f..b193b9ff65d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.cc >@@ -17,6 +17,7 @@ namespace rtc { > VideoSourceBase::VideoSourceBase() { > thread_checker_.DetachFromThread(); > } >+VideoSourceBase::~VideoSourceBase() = default; > > void VideoSourceBase::AddOrUpdateSink( > VideoSinkInterface<webrtc::VideoFrame>* sink, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.h >index 35f85bb5304..74ad280343a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/videosourcebase.h >@@ -14,7 +14,7 @@ > #include <vector> > > #include "api/video/video_frame.h" >-#include "api/videosourceinterface.h" >+#include "api/video/video_source_interface.h" > #include "rtc_base/thread_checker.h" > > namespace rtc { >@@ -23,6 +23,7 @@ namespace rtc { > class VideoSourceBase : public VideoSourceInterface<webrtc::VideoFrame> { > public: > VideoSourceBase(); >+ ~VideoSourceBase() override; > void AddOrUpdateSink(VideoSinkInterface<webrtc::VideoFrame>* sink, > const VideoSinkWants& wants) override; > void RemoveSink(VideoSinkInterface<webrtc::VideoFrame>* sink) override; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.cc >new file mode 100644 >index 00000000000..a28a912762a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.cc >@@ -0,0 +1,63 @@ >+/* >+ * Copyright (c) 2018 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 "media/base/vp9_profile.h" >+ >+#include "rtc_base/string_to_number.h" >+ >+namespace webrtc { >+ >+// Profile information for VP9 video. >+const char kVP9FmtpProfileId[] = "x-google-profile-id"; >+ >+std::string VP9ProfileToString(VP9Profile profile) { >+ switch (profile) { >+ case VP9Profile::kProfile0: >+ return "0"; >+ case VP9Profile::kProfile2: >+ return "2"; >+ } >+ return "0"; >+} >+ >+absl::optional<VP9Profile> StringToVP9Profile(const std::string& str) { >+ const absl::optional<int> i = rtc::StringToNumber<int>(str); >+ if (!i.has_value()) >+ return absl::nullopt; >+ >+ switch (i.value()) { >+ case 0: >+ return VP9Profile::kProfile0; >+ case 2: >+ return VP9Profile::kProfile2; >+ default: >+ return absl::nullopt; >+ } >+ return absl::nullopt; >+} >+ >+absl::optional<VP9Profile> ParseSdpForVP9Profile( >+ const SdpVideoFormat::Parameters& params) { >+ const auto profile_it = params.find(kVP9FmtpProfileId); >+ if (profile_it == params.end()) >+ return VP9Profile::kProfile0; >+ const std::string& profile_str = profile_it->second; >+ return StringToVP9Profile(profile_str); >+} >+ >+bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1, >+ const SdpVideoFormat::Parameters& params2) { >+ const absl::optional<VP9Profile> profile = ParseSdpForVP9Profile(params1); >+ const absl::optional<VP9Profile> other_profile = >+ ParseSdpForVP9Profile(params2); >+ return profile && other_profile && profile == other_profile; >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.h >new file mode 100644 >index 00000000000..5cc1d166a87 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/base/vp9_profile.h >@@ -0,0 +1,53 @@ >+/* >+ * Copyright (c) 2018 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. >+ */ >+ >+#ifndef MEDIA_BASE_VP9_PROFILE_H_ >+#define MEDIA_BASE_VP9_PROFILE_H_ >+ >+#include <map> >+#include <string> >+ >+#include "absl/types/optional.h" >+#include "api/video_codecs/sdp_video_format.h" >+#include "common_types.h" // NOLINT(build/include) >+ >+namespace webrtc { >+ >+// Profile information for VP9 video. >+extern const char kVP9FmtpProfileId[]; >+ >+enum class VP9Profile { >+ kProfile0, >+ kProfile2, >+}; >+ >+// Helper functions to convert VP9Profile to std::string. Returns "0" by >+// default. >+std::string VP9ProfileToString(VP9Profile profile); >+ >+// Helper functions to convert std::string to VP9Profile. Returns null if given >+// an invalid profile string. >+absl::optional<VP9Profile> StringToVP9Profile(const std::string& str); >+ >+// Parse profile that is represented as a string of single digit contained in an >+// SDP key-value map. A default profile(kProfile0) will be returned if the >+// profile key is missing. Nothing will be returned if the key is present but >+// the string is invalid. >+absl::optional<VP9Profile> ParseSdpForVP9Profile( >+ const SdpVideoFormat::Parameters& params); >+ >+// Returns true if the parameters have the same VP9 profile, or neither contains >+// VP9 profile. >+bool IsSameVP9Profile(const SdpVideoFormat::Parameters& params1, >+ const SdpVideoFormat::Parameters& params2); >+ >+} // namespace webrtc >+ >+#endif // MEDIA_BASE_VP9_PROFILE_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/OWNERS b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/OWNERS >new file mode 100644 >index 00000000000..421e88bf3ae >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/OWNERS >@@ -0,0 +1 @@ >+per-file simulcast*=sprang@webrtc.org >\ No newline at end of file >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/adm_helpers.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/adm_helpers.cc >index 119cc644510..7ec6575413b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/adm_helpers.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/adm_helpers.cc >@@ -27,7 +27,7 @@ namespace adm_helpers { > // the ADM functions, depending on the ID type. > #if defined(WEBRTC_WIN) > #define AUDIO_DEVICE_ID \ >- (AudioDeviceModule::WindowsDeviceType::kDefaultCommunicationDevice) >+ (AudioDeviceModule::WindowsDeviceType::kDefaultCommunicationDevice) > #else > #define AUDIO_DEVICE_ID (0u) > #endif // defined(WEBRTC_WIN) >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.cc >index cf5dde27ddf..ea37cb44f46 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.cc >@@ -31,7 +31,8 @@ void Init(AudioProcessing* apm) { > GainControl* gc = apm->gain_control(); > if (gc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) { > RTC_DLOG(LS_ERROR) << "Failed to set analog level limits with minimum: " >- << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel; >+ << kMinVolumeLevel >+ << " and maximum: " << kMaxVolumeLevel; > } > } > >@@ -44,8 +45,7 @@ AgcConfig GetAgcConfig(AudioProcessing* apm) { > return result; > } > >-void SetAgcConfig(AudioProcessing* apm, >- const AgcConfig& config) { >+void SetAgcConfig(AudioProcessing* apm, const AgcConfig& config) { > RTC_DCHECK(apm); > GainControl* gc = apm->gain_control(); > if (gc->set_target_level_dbfs(config.targetLeveldBOv) != 0) { >@@ -62,8 +62,7 @@ void SetAgcConfig(AudioProcessing* apm, > } > } > >-void SetAgcStatus(AudioProcessing* apm, >- bool enable) { >+void SetAgcStatus(AudioProcessing* apm, bool enable) { > RTC_DCHECK(apm); > #if defined(WEBRTC_IOS) || defined(WEBRTC_ANDROID) > GainControl::Mode agc_mode = GainControl::kFixedDigital; >@@ -82,9 +81,7 @@ void SetAgcStatus(AudioProcessing* apm, > RTC_LOG(LS_INFO) << "AGC set to " << enable << " with mode " << agc_mode; > } > >-void SetEcStatus(AudioProcessing* apm, >- bool enable, >- EcModes mode) { >+void SetEcStatus(AudioProcessing* apm, bool enable, EcModes mode) { > RTC_DCHECK(apm); > RTC_DCHECK(mode == kEcConference || mode == kEcAecm) << "mode: " << mode; > EchoCancellation* ec = apm->echo_cancellation(); >@@ -99,8 +96,7 @@ void SetEcStatus(AudioProcessing* apm, > RTC_LOG(LS_ERROR) << "Failed to enable/disable AEC: " << enable; > return; > } >- if (ec->set_suppression_level(EchoCancellation::kHighSuppression) >- != 0) { >+ if (ec->set_suppression_level(EchoCancellation::kHighSuppression) != 0) { > RTC_LOG(LS_ERROR) << "Failed to set high AEC aggressiveness."; > return; > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.h >index 42465fcec07..f775d8a4736 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers.h >@@ -18,8 +18,8 @@ namespace webrtc { > class AudioProcessing; > > enum EcModes { >- kEcConference, // Conferencing default (aggressive AEC). >- kEcAecm, // AEC mobile. >+ kEcConference, // Conferencing default (aggressive AEC). >+ kEcAecm, // AEC mobile. > }; > > struct AgcConfig { >@@ -32,13 +32,9 @@ namespace apm_helpers { > > void Init(AudioProcessing* apm); > AgcConfig GetAgcConfig(AudioProcessing* apm); >-void SetAgcConfig(AudioProcessing* apm, >- const AgcConfig& config); >-void SetAgcStatus(AudioProcessing* apm, >- bool enable); >-void SetEcStatus(AudioProcessing* apm, >- bool enable, >- EcModes mode); >+void SetAgcConfig(AudioProcessing* apm, const AgcConfig& config); >+void SetAgcStatus(AudioProcessing* apm, bool enable); >+void SetEcStatus(AudioProcessing* apm, bool enable, EcModes mode); > void SetEcMetricsStatus(AudioProcessing* apm, bool enable); > void SetAecmMode(AudioProcessing* apm, bool enable_cng); > void SetNsStatus(AudioProcessing* apm, bool enable); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers_unittest.cc >index bad24af83bb..1f22963152f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/apm_helpers_unittest.cc >@@ -18,7 +18,7 @@ > namespace webrtc { > namespace { > >-constexpr AgcConfig kDefaultAgcConfig = { 3, 9, true }; >+constexpr AgcConfig kDefaultAgcConfig = {3, 9, true}; > > struct TestHelper { > TestHelper() { >@@ -60,8 +60,7 @@ struct TestHelper { > > TEST(ApmHelpersTest, AgcConfig_DefaultConfiguration) { > TestHelper helper; >- AgcConfig agc_config = >- apm_helpers::GetAgcConfig(helper.apm()); >+ AgcConfig agc_config = apm_helpers::GetAgcConfig(helper.apm()); > > EXPECT_EQ(kDefaultAgcConfig.targetLeveldBOv, agc_config.targetLeveldBOv); > EXPECT_EQ(kDefaultAgcConfig.digitalCompressionGaindB, >@@ -70,19 +69,16 @@ TEST(ApmHelpersTest, AgcConfig_DefaultConfiguration) { > } > > TEST(ApmHelpersTest, AgcConfig_GetAndSet) { >- const AgcConfig agc_config = { 11, 17, false }; >+ const AgcConfig agc_config = {11, 17, false}; > > TestHelper helper; > apm_helpers::SetAgcConfig(helper.apm(), agc_config); >- AgcConfig actual_config = >- apm_helpers::GetAgcConfig(helper.apm()); >+ AgcConfig actual_config = apm_helpers::GetAgcConfig(helper.apm()); > > EXPECT_EQ(agc_config.digitalCompressionGaindB, > actual_config.digitalCompressionGaindB); >- EXPECT_EQ(agc_config.limiterEnable, >- actual_config.limiterEnable); >- EXPECT_EQ(agc_config.targetLeveldBOv, >- actual_config.targetLeveldBOv); >+ EXPECT_EQ(agc_config.limiterEnable, actual_config.limiterEnable); >+ EXPECT_EQ(agc_config.targetLeveldBOv, actual_config.targetLeveldBOv); > } > > TEST(ApmHelpersTest, AgcStatus_DefaultMode) { >@@ -189,7 +185,7 @@ TEST(ApmHelpersTest, AecmMode_DefaultMode) { > TestHelper helper; > EchoControlMobile* ecm = helper.apm()->echo_control_mobile(); > EXPECT_EQ(EchoControlMobile::kSpeakerphone, ecm->routing_mode()); >- EXPECT_TRUE(ecm->is_comfort_noise_enabled()); >+ EXPECT_FALSE(ecm->is_comfort_noise_enabled()); > } > > TEST(ApmHelpersTest, AecmMode_EnableDisableCng) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.cc >index a5b46f81ab5..e6447bcc9f3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.cc >@@ -13,21 +13,21 @@ > #include <utility> > #include <vector> > >+#include "absl/memory/memory.h" > #include "api/video_codecs/video_decoder_factory.h" >+#include "api/video_codecs/video_decoder_software_fallback_wrapper.h" > #include "api/video_codecs/video_encoder_factory.h" >+#include "api/video_codecs/video_encoder_software_fallback_wrapper.h" > #include "media/base/h264_profile_level_id.h" > #include "media/engine/internaldecoderfactory.h" > #include "media/engine/internalencoderfactory.h" > #include "media/engine/scopedvideodecoder.h" > #include "media/engine/scopedvideoencoder.h" > #include "media/engine/simulcast_encoder_adapter.h" >-#include "media/engine/videodecodersoftwarefallbackwrapper.h" >-#include "media/engine/videoencodersoftwarefallbackwrapper.h" > #include "media/engine/vp8_encoder_simulcast_proxy.h" > #include "media/engine/webrtcvideodecoderfactory.h" > #include "media/engine/webrtcvideoencoderfactory.h" > #include "rtc_base/checks.h" >-#include "rtc_base/ptr_util.h" > > namespace cricket { > >@@ -98,9 +98,14 @@ class EncoderAdapter : public webrtc::VideoEncoderFactory { > std::unique_ptr<WebRtcVideoEncoderFactory> external_encoder_factory) > : internal_encoder_factory_(new webrtc::InternalEncoderFactory()), > external_encoder_factory_( >- rtc::MakeUnique<CricketToWebRtcEncoderFactory>( >+ absl::make_unique<CricketToWebRtcEncoderFactory>( > std::move(external_encoder_factory))) {} > >+ explicit EncoderAdapter( >+ std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory) >+ : internal_encoder_factory_(new webrtc::InternalEncoderFactory()), >+ external_encoder_factory_(std::move(external_encoder_factory)) {} >+ > webrtc::VideoEncoderFactory::CodecInfo QueryVideoEncoder( > const webrtc::SdpVideoFormat& format) const override { > if (IsFormatSupported(external_encoder_factory_->GetSupportedFormats(), >@@ -125,8 +130,8 @@ class EncoderAdapter : public webrtc::VideoEncoderFactory { > format)) { > internal_encoder = > CodecNamesEq(format.name.c_str(), kVp8CodecName) >- ? rtc::MakeUnique<webrtc::VP8EncoderSimulcastProxy>( >- internal_encoder_factory_.get()) >+ ? absl::make_unique<webrtc::VP8EncoderSimulcastProxy>( >+ internal_encoder_factory_.get(), format) > : internal_encoder_factory_->CreateVideoEncoder(format); > } > >@@ -136,15 +141,15 @@ class EncoderAdapter : public webrtc::VideoEncoderFactory { > format)) { > external_encoder = > CodecNamesEq(format.name.c_str(), kVp8CodecName) >- ? rtc::MakeUnique<webrtc::SimulcastEncoderAdapter>( >- external_encoder_factory_.get()) >+ ? absl::make_unique<webrtc::SimulcastEncoderAdapter>( >+ external_encoder_factory_.get(), format) > : external_encoder_factory_->CreateVideoEncoder(format); > } > > if (internal_encoder && external_encoder) { > // Both internal SW encoder and external HW encoder available - create > // fallback encoder. >- return rtc::MakeUnique<webrtc::VideoEncoderSoftwareFallbackWrapper>( >+ return webrtc::CreateVideoEncoderSoftwareFallbackWrapper( > std::move(internal_encoder), std::move(external_encoder)); > } > return external_encoder ? std::move(external_encoder) >@@ -171,51 +176,90 @@ class EncoderAdapter : public webrtc::VideoEncoderFactory { > const std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory_; > }; > >+// Converts the cricket::WebRtcVideoDecoderFactory to a >+// webrtc::VideoDecoderFactory (without adding any SW fallback). >+class CricketToWebRtcDecoderFactory : public webrtc::VideoDecoderFactory { >+ public: >+ explicit CricketToWebRtcDecoderFactory( >+ std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory) >+ : external_decoder_factory_(std::move(external_decoder_factory)) {} >+ >+ std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder( >+ const webrtc::SdpVideoFormat& format) override { >+ if (external_decoder_factory_ != nullptr) { >+ return CreateScopedVideoDecoder(external_decoder_factory_.get(), >+ VideoCodec(format), {}); >+ } >+ return nullptr; >+ } >+ >+ std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override { >+ // This is not implemented for the legacy decoder factory. >+ RTC_NOTREACHED(); >+ return std::vector<webrtc::SdpVideoFormat>(); >+ } >+ >+ private: >+ const std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory_; >+}; >+ > // This class combines an external factory with the internal factory and adds >-// internal SW codecs, simulcast, and SW fallback wrappers. >+// internal SW codecs and SW fallback wrappers. > class DecoderAdapter : public webrtc::VideoDecoderFactory { > public: > explicit DecoderAdapter( > std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory) >- : external_decoder_factory_(std::move(external_decoder_factory)) {} >+ : internal_decoder_factory_(new webrtc::InternalDecoderFactory()), >+ external_decoder_factory_( >+ absl::make_unique<CricketToWebRtcDecoderFactory>( >+ std::move(external_decoder_factory))) {} >+ >+ explicit DecoderAdapter( >+ std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory) >+ : internal_decoder_factory_(new webrtc::InternalDecoderFactory()), >+ external_decoder_factory_(std::move(external_decoder_factory)) {} > > std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder( > const webrtc::SdpVideoFormat& format) override { > std::unique_ptr<webrtc::VideoDecoder> internal_decoder; >- webrtc::InternalDecoderFactory internal_decoder_factory; >- if (IsFormatSupported(internal_decoder_factory.GetSupportedFormats(), >+ if (IsFormatSupported(internal_decoder_factory_->GetSupportedFormats(), > format)) { >- internal_decoder = internal_decoder_factory.CreateVideoDecoder(format); >+ internal_decoder = internal_decoder_factory_->CreateVideoDecoder(format); > } > >- const VideoCodec codec(format); >- const VideoDecoderParams params = {}; >+ std::unique_ptr<webrtc::VideoDecoder> external_decoder = nullptr; > if (external_decoder_factory_ != nullptr) { >- std::unique_ptr<webrtc::VideoDecoder> external_decoder = >- CreateScopedVideoDecoder(external_decoder_factory_.get(), codec, >- params); >- if (external_decoder) { >- if (!internal_decoder) >- return external_decoder; >- // Both external and internal decoder available - create fallback >- // wrapper. >- return std::unique_ptr<webrtc::VideoDecoder>( >- new webrtc::VideoDecoderSoftwareFallbackWrapper( >- std::move(internal_decoder), std::move(external_decoder))); >- } >+ external_decoder = external_decoder_factory_->CreateVideoDecoder(format); > } > >- return internal_decoder; >+ if (internal_decoder && external_decoder) { >+ // Both internal SW decoder and external HW decoder available - create >+ // fallback decoder. >+ return webrtc::CreateVideoDecoderSoftwareFallbackWrapper( >+ std::move(internal_decoder), std::move(external_decoder)); >+ } >+ return external_decoder ? std::move(external_decoder) >+ : std::move(internal_decoder); > } > > std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override { >- // This is not implemented for the legacy decoder factory. >- RTC_NOTREACHED(); >- return std::vector<webrtc::SdpVideoFormat>(); >+ std::vector<webrtc::SdpVideoFormat> formats = >+ internal_decoder_factory_->GetSupportedFormats(); >+ >+ // Add external codecs. >+ for (const webrtc::SdpVideoFormat& format : >+ external_decoder_factory_->GetSupportedFormats()) { >+ // Don't add same codec twice. >+ if (!IsFormatSupported(formats, format)) >+ formats.push_back(format); >+ } >+ >+ return formats; > } > > private: >- const std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory_; >+ const std::unique_ptr<webrtc::VideoDecoderFactory> internal_decoder_factory_; >+ const std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory_; > }; > > } // namespace >@@ -226,10 +270,22 @@ std::unique_ptr<webrtc::VideoEncoderFactory> ConvertVideoEncoderFactory( > new EncoderAdapter(std::move(external_encoder_factory))); > } > >+std::unique_ptr<webrtc::VideoEncoderFactory> ConvertVideoEncoderFactory( >+ std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory) { >+ return std::unique_ptr<webrtc::VideoEncoderFactory>( >+ new EncoderAdapter(std::move(external_encoder_factory))); >+} >+ > std::unique_ptr<webrtc::VideoDecoderFactory> ConvertVideoDecoderFactory( > std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory) { > return std::unique_ptr<webrtc::VideoDecoderFactory>( > new DecoderAdapter(std::move(external_decoder_factory))); > } > >+std::unique_ptr<webrtc::VideoDecoderFactory> ConvertVideoDecoderFactory( >+ std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory) { >+ return std::unique_ptr<webrtc::VideoDecoderFactory>( >+ new DecoderAdapter(std::move(external_decoder_factory))); >+} >+ > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.h >index 5bd3580a6f1..9d0d154910e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/convert_legacy_video_factory.h >@@ -30,9 +30,15 @@ class WebRtcVideoDecoderFactory; > std::unique_ptr<webrtc::VideoEncoderFactory> ConvertVideoEncoderFactory( > std::unique_ptr<WebRtcVideoEncoderFactory> external_encoder_factory); > >+std::unique_ptr<webrtc::VideoEncoderFactory> ConvertVideoEncoderFactory( >+ std::unique_ptr<webrtc::VideoEncoderFactory> external_encoder_factory); >+ > std::unique_ptr<webrtc::VideoDecoderFactory> ConvertVideoDecoderFactory( > std::unique_ptr<WebRtcVideoDecoderFactory> external_decoder_factory); > >+std::unique_ptr<webrtc::VideoDecoderFactory> ConvertVideoDecoderFactory( >+ std::unique_ptr<webrtc::VideoDecoderFactory> external_decoder_factory); >+ > } // namespace cricket > > #endif // MEDIA_ENGINE_CONVERT_LEGACY_VIDEO_FACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.cc >index 5dcfd762e9d..24ae019d08b 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.cc >@@ -90,7 +90,7 @@ bool FakeAudioReceiveStream::VerifyLastPacket(const uint8_t* data, > > bool FakeAudioReceiveStream::DeliverRtp(const uint8_t* packet, > size_t length, >- const webrtc::PacketTime& packet_time) { >+ int64_t /* packet_time_us */) { > ++received_packets_; > last_packet_.SetData(packet, length); > return true; >@@ -123,7 +123,7 @@ FakeVideoSendStream::FakeVideoSendStream( > framerate_scaling_enabled_(false), > source_(nullptr), > num_swapped_frames_(0) { >- RTC_DCHECK(config.encoder_settings.encoder != NULL); >+ RTC_DCHECK(config.encoder_settings.encoder_factory != nullptr); > ReconfigureVideoEncoder(std::move(encoder_config)); > } > >@@ -156,7 +156,7 @@ bool FakeVideoSendStream::GetVp8Settings( > return false; > } > >- *settings = vpx_settings_.vp8; >+ *settings = codec_specific_settings_.vp8; > return true; > } > >@@ -166,7 +166,17 @@ bool FakeVideoSendStream::GetVp9Settings( > return false; > } > >- *settings = vpx_settings_.vp9; >+ *settings = codec_specific_settings_.vp9; >+ return true; >+} >+ >+bool FakeVideoSendStream::GetH264Settings( >+ webrtc::VideoCodecH264* settings) const { >+ if (!codec_settings_set_) { >+ return false; >+ } >+ >+ *settings = codec_specific_settings_.h264; > return true; > } > >@@ -224,24 +234,31 @@ void FakeVideoSendStream::ReconfigureVideoEncoder( > } else { > width = height = 0; > } >- video_streams_ = config.video_stream_factory->CreateEncoderStreams( >- width, height, config); >+ video_streams_ = >+ config.video_stream_factory->CreateEncoderStreams(width, height, config); > if (config.encoder_specific_settings != NULL) { >- if (config_.encoder_settings.payload_name == "VP8") { >- config.encoder_specific_settings->FillVideoCodecVp8(&vpx_settings_.vp8); >+ const unsigned char num_temporal_layers = static_cast<unsigned char>( >+ video_streams_.back().num_temporal_layers.value_or(1)); >+ if (config_.rtp.payload_name == "VP8") { >+ config.encoder_specific_settings->FillVideoCodecVp8( >+ &codec_specific_settings_.vp8); > if (!video_streams_.empty()) { >- vpx_settings_.vp8.numberOfTemporalLayers = static_cast<unsigned char>( >- video_streams_.back().temporal_layer_thresholds_bps.size() + 1); >+ codec_specific_settings_.vp8.numberOfTemporalLayers = >+ num_temporal_layers; > } >- } else if (config_.encoder_settings.payload_name == "VP9") { >- config.encoder_specific_settings->FillVideoCodecVp9(&vpx_settings_.vp9); >+ } else if (config_.rtp.payload_name == "VP9") { >+ config.encoder_specific_settings->FillVideoCodecVp9( >+ &codec_specific_settings_.vp9); > if (!video_streams_.empty()) { >- vpx_settings_.vp9.numberOfTemporalLayers = static_cast<unsigned char>( >- video_streams_.back().temporal_layer_thresholds_bps.size() + 1); >+ codec_specific_settings_.vp9.numberOfTemporalLayers = >+ num_temporal_layers; > } >+ } else if (config_.rtp.payload_name == "H264") { >+ config.encoder_specific_settings->FillVideoCodecH264( >+ &codec_specific_settings_.h264); > } else { > ADD_FAILURE() << "Unsupported encoder payload: " >- << config_.encoder_settings.payload_name; >+ << config_.rtp.payload_name; > } > } > codec_settings_set_ = config.encoder_specific_settings != NULL; >@@ -249,6 +266,17 @@ void FakeVideoSendStream::ReconfigureVideoEncoder( > ++num_encoder_reconfigurations_; > } > >+void FakeVideoSendStream::UpdateActiveSimulcastLayers( >+ const std::vector<bool> active_layers) { >+ sending_ = false; >+ for (const bool active_layer : active_layers) { >+ if (active_layer) { >+ sending_ = true; >+ break; >+ } >+ } >+} >+ > void FakeVideoSendStream::Start() { > sending_ = true; > } >@@ -259,26 +287,24 @@ void FakeVideoSendStream::Stop() { > > void FakeVideoSendStream::SetSource( > rtc::VideoSourceInterface<webrtc::VideoFrame>* source, >- const webrtc::VideoSendStream::DegradationPreference& >- degradation_preference) { >- RTC_DCHECK(source != source_); >+ const webrtc::DegradationPreference& degradation_preference) { > if (source_) > source_->RemoveSink(this); > source_ = source; > switch (degradation_preference) { >- case DegradationPreference::kMaintainFramerate: >+ case webrtc::DegradationPreference::MAINTAIN_FRAMERATE: > resolution_scaling_enabled_ = true; > framerate_scaling_enabled_ = false; > break; >- case DegradationPreference::kMaintainResolution: >+ case webrtc::DegradationPreference::MAINTAIN_RESOLUTION: > resolution_scaling_enabled_ = false; > framerate_scaling_enabled_ = true; > break; >- case DegradationPreference::kBalanced: >+ case webrtc::DegradationPreference::BALANCED: > resolution_scaling_enabled_ = true; > framerate_scaling_enabled_ = true; > break; >- case DegradationPreference::kDegradationDisabled: >+ case webrtc::DegradationPreference::DISABLED: > resolution_scaling_enabled_ = false; > framerate_scaling_enabled_ = false; > break; >@@ -297,7 +323,10 @@ void FakeVideoSendStream::InjectVideoSinkWants( > > FakeVideoReceiveStream::FakeVideoReceiveStream( > webrtc::VideoReceiveStream::Config config) >- : config_(std::move(config)), receiving_(false) {} >+ : config_(std::move(config)), >+ receiving_(false), >+ num_added_secondary_sinks_(0), >+ num_removed_secondary_sinks_(0) {} > > const webrtc::VideoReceiveStream::Config& FakeVideoReceiveStream::GetConfig() > const { >@@ -335,10 +364,22 @@ void FakeVideoReceiveStream::EnableEncodedFrameRecording(rtc::PlatformFile file, > } > > void FakeVideoReceiveStream::AddSecondarySink( >- webrtc::RtpPacketSinkInterface* sink) {} >+ webrtc::RtpPacketSinkInterface* sink) { >+ ++num_added_secondary_sinks_; >+} > > void FakeVideoReceiveStream::RemoveSecondarySink( >- const webrtc::RtpPacketSinkInterface* sink) {} >+ const webrtc::RtpPacketSinkInterface* sink) { >+ ++num_removed_secondary_sinks_; >+} >+ >+int FakeVideoReceiveStream::GetNumAddedSecondarySinks() const { >+ return num_added_secondary_sinks_; >+} >+ >+int FakeVideoReceiveStream::GetNumRemovedSecondarySinks() const { >+ return num_removed_secondary_sinks_; >+} > > FakeFlexfecReceiveStream::FakeFlexfecReceiveStream( > const webrtc::FlexfecReceiveStream::Config& config) >@@ -358,9 +399,8 @@ void FakeFlexfecReceiveStream::OnRtpPacket(const webrtc::RtpPacketReceived&) { > RTC_NOTREACHED() << "Not implemented."; > } > >-FakeCall::FakeCall(const webrtc::Call::Config& config) >- : config_(config), >- audio_network_state_(webrtc::kNetworkUp), >+FakeCall::FakeCall() >+ : audio_network_state_(webrtc::kNetworkUp), > video_network_state_(webrtc::kNetworkUp), > num_created_send_streams_(0), > num_created_receive_streams_(0), >@@ -374,10 +414,6 @@ FakeCall::~FakeCall() { > EXPECT_EQ(0u, audio_receive_streams_.size()); > } > >-webrtc::Call::Config FakeCall::GetConfig() const { >- return config_; >-} >- > const std::vector<FakeVideoSendStream*>& FakeCall::GetVideoSendStreams() { > return video_send_streams_; > } >@@ -546,10 +582,9 @@ webrtc::PacketReceiver* FakeCall::Receiver() { > return this; > } > >-FakeCall::DeliveryStatus FakeCall::DeliverPacket( >- webrtc::MediaType media_type, >- rtc::CopyOnWriteBuffer packet, >- const webrtc::PacketTime& packet_time) { >+FakeCall::DeliveryStatus FakeCall::DeliverPacket(webrtc::MediaType media_type, >+ rtc::CopyOnWriteBuffer packet, >+ int64_t packet_time_us) { > EXPECT_GE(packet.size(), 12u); > RTC_DCHECK(media_type == webrtc::MediaType::AUDIO || > media_type == webrtc::MediaType::VIDEO); >@@ -567,7 +602,7 @@ FakeCall::DeliveryStatus FakeCall::DeliverPacket( > if (media_type == webrtc::MediaType::AUDIO) { > for (auto receiver : audio_receive_streams_) { > if (receiver->GetConfig().rtp.remote_ssrc == ssrc) { >- receiver->DeliverRtp(packet.cdata(), packet.size(), packet_time); >+ receiver->DeliverRtp(packet.cdata(), packet.size(), packet_time_us); > return DELIVERY_OK; > } > } >@@ -591,16 +626,6 @@ webrtc::Call::Stats FakeCall::GetStats() const { > return stats_; > } > >-void FakeCall::SetBitrateConfig( >- const webrtc::Call::Config::BitrateConfig& bitrate_config) { >- config_.bitrate_config = bitrate_config; >-} >- >-void FakeCall::SetBitrateConfigMask( >- const webrtc::Call::Config::BitrateConfigMask& mask) { >- // TODO(zstein): not implemented >-} >- > void FakeCall::SetBitrateAllocationStrategy( > std::unique_ptr<rtc::BitrateAllocationStrategy> > bitrate_allocation_strategy) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.h >index cd9f1eb2cbf..8f8270915c6 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtccall.h >@@ -29,10 +29,11 @@ > #include "call/audio_send_stream.h" > #include "call/call.h" > #include "call/flexfec_receive_stream.h" >-#include "modules/rtp_rtcp/source/rtp_packet_received.h" >-#include "rtc_base/buffer.h" >+#include "call/test/mock_rtp_transport_controller_send.h" > #include "call/video_receive_stream.h" > #include "call/video_send_stream.h" >+#include "modules/rtp_rtcp/source/rtp_packet_received.h" >+#include "rtc_base/buffer.h" > > namespace cricket { > class FakeAudioSendStream final : public webrtc::AudioSendStream { >@@ -44,8 +45,8 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { > int duration_ms = 0; > }; > >- explicit FakeAudioSendStream( >- int id, const webrtc::AudioSendStream::Config& config); >+ explicit FakeAudioSendStream(int id, >+ const webrtc::AudioSendStream::Config& config); > > int id() const { return id_; } > const webrtc::AudioSendStream::Config& GetConfig() const override; >@@ -61,7 +62,9 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { > void Stop() override { sending_ = false; } > void SendAudioData(std::unique_ptr<webrtc::AudioFrame> audio_frame) override { > } >- bool SendTelephoneEvent(int payload_type, int payload_frequency, int event, >+ bool SendTelephoneEvent(int payload_type, >+ int payload_frequency, >+ int event, > int duration_ms) override; > void SetMuted(bool muted) override; > webrtc::AudioSendStream::Stats GetStats() const override; >@@ -79,7 +82,8 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { > class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream { > public: > explicit FakeAudioReceiveStream( >- int id, const webrtc::AudioReceiveStream::Config& config); >+ int id, >+ const webrtc::AudioReceiveStream::Config& config); > > int id() const { return id_; } > const webrtc::AudioReceiveStream::Config& GetConfig() const; >@@ -88,9 +92,7 @@ class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream { > bool VerifyLastPacket(const uint8_t* data, size_t length) const; > const webrtc::AudioSinkInterface* sink() const { return sink_; } > float gain() const { return gain_; } >- bool DeliverRtp(const uint8_t* packet, >- size_t length, >- const webrtc::PacketTime& packet_time); >+ bool DeliverRtp(const uint8_t* packet, size_t length, int64_t packet_time_us); > bool started() const { return started_; } > > private: >@@ -100,7 +102,6 @@ class FakeAudioReceiveStream final : public webrtc::AudioReceiveStream { > void Stop() override { started_ = false; } > > webrtc::AudioReceiveStream::Stats GetStats() const override; >- int GetOutputLevel() const override { return 0; } > void SetSink(webrtc::AudioSinkInterface* sink) override; > void SetGain(float gain) override; > std::vector<webrtc::RtpSource> GetSources() const override { >@@ -131,6 +132,7 @@ class FakeVideoSendStream final > bool IsSending() const; > bool GetVp8Settings(webrtc::VideoCodecVP8* settings) const; > bool GetVp9Settings(webrtc::VideoCodecVP9* settings) const; >+ bool GetH264Settings(webrtc::VideoCodecH264* settings) const; > > int GetNumberOfSwappedFrames() const; > int GetLastWidth() const; >@@ -159,11 +161,13 @@ class FakeVideoSendStream final > void OnFrame(const webrtc::VideoFrame& frame) override; > > // webrtc::VideoSendStream implementation. >+ void UpdateActiveSimulcastLayers( >+ const std::vector<bool> active_layers) override; > void Start() override; > void Stop() override; >- void SetSource(rtc::VideoSourceInterface<webrtc::VideoFrame>* source, >- const webrtc::VideoSendStream::DegradationPreference& >- degradation_preference) override; >+ void SetSource( >+ rtc::VideoSourceInterface<webrtc::VideoFrame>* source, >+ const webrtc::DegradationPreference& degradation_preference) override; > webrtc::VideoSendStream::Stats GetStats() override; > void ReconfigureVideoEncoder(webrtc::VideoEncoderConfig config) override; > >@@ -174,15 +178,16 @@ class FakeVideoSendStream final > rtc::VideoSinkWants sink_wants_; > > bool codec_settings_set_; >- union VpxSettings { >+ union CodecSpecificSettings { > webrtc::VideoCodecVP8 vp8; > webrtc::VideoCodecVP9 vp9; >- } vpx_settings_; >+ webrtc::VideoCodecH264 h264; >+ } codec_specific_settings_; > bool resolution_scaling_enabled_; > bool framerate_scaling_enabled_; > rtc::VideoSourceInterface<webrtc::VideoFrame>* source_; > int num_swapped_frames_; >- rtc::Optional<webrtc::VideoFrame> last_frame_; >+ absl::optional<webrtc::VideoFrame> last_frame_; > webrtc::VideoSendStream::Stats stats_; > int num_encoder_reconfigurations_ = 0; > }; >@@ -205,6 +210,9 @@ class FakeVideoReceiveStream final : public webrtc::VideoReceiveStream { > void AddSecondarySink(webrtc::RtpPacketSinkInterface* sink) override; > void RemoveSecondarySink(const webrtc::RtpPacketSinkInterface* sink) override; > >+ int GetNumAddedSecondarySinks() const; >+ int GetNumRemovedSecondarySinks() const; >+ > private: > // webrtc::VideoReceiveStream implementation. > void Start() override; >@@ -215,6 +223,9 @@ class FakeVideoReceiveStream final : public webrtc::VideoReceiveStream { > webrtc::VideoReceiveStream::Config config_; > bool receiving_; > webrtc::VideoReceiveStream::Stats stats_; >+ >+ int num_added_secondary_sinks_; >+ int num_removed_secondary_sinks_; > }; > > class FakeFlexfecReceiveStream final : public webrtc::FlexfecReceiveStream { >@@ -234,10 +245,13 @@ class FakeFlexfecReceiveStream final : public webrtc::FlexfecReceiveStream { > > class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { > public: >- explicit FakeCall(const webrtc::Call::Config& config); >+ FakeCall(); > ~FakeCall() override; > >- webrtc::Call::Config GetConfig() const; >+ webrtc::MockRtpTransportControllerSend* GetMockTransportControllerSend() { >+ return &transport_controller_send_; >+ } >+ > const std::vector<FakeVideoSendStream*>& GetVideoSendStreams(); > const std::vector<FakeVideoReceiveStream*>& GetVideoReceiveStreams(); > >@@ -290,26 +304,28 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { > > DeliveryStatus DeliverPacket(webrtc::MediaType media_type, > rtc::CopyOnWriteBuffer packet, >- const webrtc::PacketTime& packet_time) override; >+ int64_t packet_time_us) override; >+ >+ webrtc::RtpTransportControllerSendInterface* GetTransportControllerSend() >+ override { >+ return &transport_controller_send_; >+ } > > webrtc::Call::Stats GetStats() const override; > >- void SetBitrateConfig( >- const webrtc::Call::Config::BitrateConfig& bitrate_config) override; >- void SetBitrateConfigMask( >- const webrtc::Call::Config::BitrateConfigMask& mask) override; > void SetBitrateAllocationStrategy( > std::unique_ptr<rtc::BitrateAllocationStrategy> > bitrate_allocation_strategy) override; >- void OnNetworkRouteChanged(const std::string& transport_name, >- const rtc::NetworkRoute& network_route) override {} >+ > void SignalChannelNetworkState(webrtc::MediaType media, > webrtc::NetworkState state) override; > void OnTransportOverheadChanged(webrtc::MediaType media, > int transport_overhead_per_packet) override; > void OnSentPacket(const rtc::SentPacket& sent_packet) override; > >- webrtc::Call::Config config_; >+ testing::NiceMock<webrtc::MockRtpTransportControllerSend> >+ transport_controller_send_; >+ > webrtc::NetworkState audio_network_state_; > webrtc::NetworkState video_network_state_; > rtc::SentPacket last_sent_packet_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcdeviceinfo.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcdeviceinfo.h >index 51a5b8e50cb..7103b4c3437 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcdeviceinfo.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcdeviceinfo.h >@@ -33,9 +33,10 @@ class FakeWebRtcDeviceInfo : public webrtc::VideoCaptureModule::DeviceInfo { > } > void AddCapability(const std::string& device_id, > const webrtc::VideoCaptureCapability& cap) { >- Device* dev = GetDeviceById( >- reinterpret_cast<const char*>(device_id.c_str())); >- if (!dev) return; >+ Device* dev = >+ GetDeviceById(reinterpret_cast<const char*>(device_id.c_str())); >+ if (!dev) >+ return; > dev->caps.push_back(cap); > } > virtual uint32_t NumberOfDevices() { >@@ -49,28 +50,32 @@ class FakeWebRtcDeviceInfo : public webrtc::VideoCaptureModule::DeviceInfo { > char* product_id, > uint32_t product_id_len) { > Device* dev = GetDeviceByIndex(device_num); >- if (!dev) return -1; >+ if (!dev) >+ return -1; > rtc::strcpyn(reinterpret_cast<char*>(device_name), device_name_len, >- dev->name.c_str()); >+ dev->name.c_str()); > rtc::strcpyn(reinterpret_cast<char*>(device_id), device_id_len, >- dev->id.c_str()); >+ dev->id.c_str()); > if (product_id) { > rtc::strcpyn(reinterpret_cast<char*>(product_id), product_id_len, >- dev->product.c_str()); >+ dev->product.c_str()); > } > return 0; > } > virtual int32_t NumberOfCapabilities(const char* device_id) { > Device* dev = GetDeviceById(device_id); >- if (!dev) return -1; >+ if (!dev) >+ return -1; > return static_cast<int32_t>(dev->caps.size()); > } > virtual int32_t GetCapability(const char* device_id, > const uint32_t device_cap_num, > webrtc::VideoCaptureCapability& cap) { > Device* dev = GetDeviceById(device_id); >- if (!dev) return -1; >- if (device_cap_num >= dev->caps.size()) return -1; >+ if (!dev) >+ return -1; >+ if (device_cap_num >= dev->caps.size()) >+ return -1; > cap = dev->caps[device_cap_num]; > return 0; > } >@@ -84,9 +89,11 @@ class FakeWebRtcDeviceInfo : public webrtc::VideoCaptureModule::DeviceInfo { > webrtc::VideoCaptureCapability& resulting) { > return -1; // not implemented > } >- virtual int32_t DisplayCaptureSettingsDialogBox( >- const char* device_id, const char* dialog_title, >- void* parent, uint32_t x, uint32_t y) { >+ virtual int32_t DisplayCaptureSettingsDialogBox(const char* device_id, >+ const char* dialog_title, >+ void* parent, >+ uint32_t x, >+ uint32_t y) { > return -1; // not implemented > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvcmfactory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvcmfactory.h >index 70931e129a1..41ec98df8b7 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvcmfactory.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvcmfactory.h >@@ -23,9 +23,10 @@ class FakeWebRtcVcmFactory : public cricket::WebRtcVcmFactoryInterface { > public: > virtual rtc::scoped_refptr<webrtc::VideoCaptureModule> Create( > const char* device_id) { >- if (!device_info.GetDeviceById(device_id)) return NULL; >+ if (!device_info.GetDeviceById(device_id)) >+ return NULL; > rtc::scoped_refptr<FakeWebRtcVideoCaptureModule> module( >- new rtc::RefCountedObject<FakeWebRtcVideoCaptureModule>(this)); >+ new rtc::RefCountedObject<FakeWebRtcVideoCaptureModule>()); > modules.push_back(module); > return module; > } >@@ -34,16 +35,8 @@ class FakeWebRtcVcmFactory : public cricket::WebRtcVcmFactoryInterface { > } > virtual void DestroyDeviceInfo(webrtc::VideoCaptureModule::DeviceInfo* info) { > } >- void OnDestroyed(webrtc::VideoCaptureModule* module) { >- std::remove(modules.begin(), modules.end(), module); >- } > FakeWebRtcDeviceInfo device_info; > std::vector<rtc::scoped_refptr<FakeWebRtcVideoCaptureModule>> modules; > }; > >-FakeWebRtcVideoCaptureModule::~FakeWebRtcVideoCaptureModule() { >- if (factory_) >- factory_->OnDestroyed(this); >-} >- > #endif // MEDIA_ENGINE_FAKEWEBRTCVCMFACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideocapturemodule.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideocapturemodule.h >index bf23a112774..47f1393c3f3 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideocapturemodule.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideocapturemodule.h >@@ -16,22 +16,22 @@ > #include "api/video/i420_buffer.h" > #include "media/base/testutils.h" > #include "media/engine/webrtcvideocapturer.h" >- >-class FakeWebRtcVcmFactory; >+#include "rtc_base/task_queue_for_test.h" > > // Fake class for mocking out webrtc::VideoCaptureModule. > class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule { > public: >- explicit FakeWebRtcVideoCaptureModule(FakeWebRtcVcmFactory* factory) >- : factory_(factory), callback_(NULL), running_(false) {} >- ~FakeWebRtcVideoCaptureModule(); >+ FakeWebRtcVideoCaptureModule() >+ : callback_(NULL), running_(false) {} >+ ~FakeWebRtcVideoCaptureModule() {} > void RegisterCaptureDataCallback( > rtc::VideoSinkInterface<webrtc::VideoFrame>* callback) override { > callback_ = callback; > } > void DeRegisterCaptureDataCallback() override { callback_ = NULL; } > int32_t StartCapture(const webrtc::VideoCaptureCapability& cap) override { >- if (running_) return -1; >+ if (running_) >+ return -1; > cap_ = cap; > running_ = true; > return 0; >@@ -45,7 +45,8 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule { > } > bool CaptureStarted() override { return running_; } > int32_t CaptureSettings(webrtc::VideoCaptureCapability& settings) override { >- if (!running_) return -1; >+ if (!running_) >+ return -1; > settings = cap_; > return 0; > } >@@ -60,25 +61,24 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule { > return true; // Rotation compensation is turned on. > } > void SendFrame(int w, int h) { >- if (!running_) return; >+ if (!running_ || !callback_) >+ return; > >- rtc::scoped_refptr<webrtc::I420Buffer> buffer = >- webrtc::I420Buffer::Create(w, h); >- // Initialize memory to satisfy DrMemory tests. See >- // https://bugs.chromium.org/p/libyuv/issues/detail?id=377 >- buffer->InitializeData(); >- if (callback_) { >- callback_->OnFrame( >- webrtc::VideoFrame(buffer, 0, 0, webrtc::kVideoRotation_0)); >- } >+ task_queue_.SendTask([this, w, h]() { >+ rtc::scoped_refptr<webrtc::I420Buffer> buffer = >+ webrtc::I420Buffer::Create(w, h); >+ // Initialize memory to satisfy DrMemory tests. See >+ // https://bugs.chromium.org/p/libyuv/issues/detail?id=377 >+ buffer->InitializeData(); >+ callback_->OnFrame(webrtc::VideoFrame(buffer, webrtc::kVideoRotation_0, >+ 0 /* timestamp_us */)); >+ }); > } > >- const webrtc::VideoCaptureCapability& cap() const { >- return cap_; >- } >+ const webrtc::VideoCaptureCapability& cap() const { return cap_; } > > private: >- FakeWebRtcVcmFactory* factory_; >+ rtc::test::TaskQueueForTest task_queue_{"FakeWebRtcVideoCaptureModule"}; > rtc::VideoSinkInterface<webrtc::VideoFrame>* callback_; > bool running_; > webrtc::VideoCaptureCapability cap_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.cc >new file mode 100644 >index 00000000000..7081b64933a >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.cc >@@ -0,0 +1,296 @@ >+/* >+ * Copyright (c) 2018 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 "media/engine/fakewebrtcvideoengine.h" >+ >+#include "media/base/codec.h" >+#include "media/engine/simulcast_encoder_adapter.h" >+#include "media/engine/webrtcvideodecoderfactory.h" >+#include "media/engine/webrtcvideoencoderfactory.h" >+#include "modules/video_coding/include/video_error_codes.h" >+#include "rtc_base/gunit.h" >+#include "rtc_base/stringutils.h" >+ >+namespace cricket { >+ >+namespace { >+ >+static const int kEventTimeoutMs = 10000; >+ >+bool IsFormatSupported( >+ const std::vector<webrtc::SdpVideoFormat>& supported_formats, >+ const webrtc::SdpVideoFormat& format) { >+ for (const webrtc::SdpVideoFormat& supported_format : supported_formats) { >+ if (IsSameCodec(format.name, format.parameters, supported_format.name, >+ supported_format.parameters)) { >+ return true; >+ } >+ } >+ return false; >+} >+ >+} // namespace >+ >+// Decoder. >+FakeWebRtcVideoDecoder::FakeWebRtcVideoDecoder( >+ FakeWebRtcVideoDecoderFactory* factory) >+ : num_frames_received_(0), factory_(factory) {} >+ >+FakeWebRtcVideoDecoder::~FakeWebRtcVideoDecoder() { >+ if (factory_) { >+ factory_->DecoderDestroyed(this); >+ } >+} >+ >+int32_t FakeWebRtcVideoDecoder::InitDecode(const webrtc::VideoCodec*, int32_t) { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoDecoder::Decode(const webrtc::EncodedImage&, >+ bool, >+ const webrtc::CodecSpecificInfo*, >+ int64_t) { >+ num_frames_received_++; >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoDecoder::RegisterDecodeCompleteCallback( >+ webrtc::DecodedImageCallback*) { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoDecoder::Release() { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int FakeWebRtcVideoDecoder::GetNumFramesReceived() const { >+ return num_frames_received_; >+} >+ >+// Decoder factory. >+FakeWebRtcVideoDecoderFactory::FakeWebRtcVideoDecoderFactory() >+ : num_created_decoders_(0) {} >+ >+std::vector<webrtc::SdpVideoFormat> >+FakeWebRtcVideoDecoderFactory::GetSupportedFormats() const { >+ std::vector<webrtc::SdpVideoFormat> formats; >+ >+ for (const webrtc::SdpVideoFormat& format : supported_codec_formats_) { >+ // Don't add same codec twice. >+ if (!IsFormatSupported(formats, format)) >+ formats.push_back(format); >+ } >+ >+ return formats; >+} >+ >+std::unique_ptr<webrtc::VideoDecoder> >+FakeWebRtcVideoDecoderFactory::CreateVideoDecoder( >+ const webrtc::SdpVideoFormat& format) { >+ if (IsFormatSupported(supported_codec_formats_, format)) { >+ num_created_decoders_++; >+ std::unique_ptr<FakeWebRtcVideoDecoder> decoder = >+ absl::make_unique<FakeWebRtcVideoDecoder>(this); >+ decoders_.push_back(decoder.get()); >+ return decoder; >+ } >+ >+ return nullptr; >+} >+ >+void FakeWebRtcVideoDecoderFactory::DecoderDestroyed( >+ FakeWebRtcVideoDecoder* decoder) { >+ decoders_.erase(std::remove(decoders_.begin(), decoders_.end(), decoder), >+ decoders_.end()); >+} >+ >+void FakeWebRtcVideoDecoderFactory::AddSupportedVideoCodecType( >+ const webrtc::SdpVideoFormat& format) { >+ supported_codec_formats_.push_back(format); >+} >+ >+int FakeWebRtcVideoDecoderFactory::GetNumCreatedDecoders() { >+ return num_created_decoders_; >+} >+ >+const std::vector<FakeWebRtcVideoDecoder*>& >+FakeWebRtcVideoDecoderFactory::decoders() { >+ return decoders_; >+} >+ >+// Encoder. >+FakeWebRtcVideoEncoder::FakeWebRtcVideoEncoder( >+ FakeWebRtcVideoEncoderFactory* factory) >+ : init_encode_event_(false, false), >+ num_frames_encoded_(0), >+ factory_(factory) {} >+ >+FakeWebRtcVideoEncoder::~FakeWebRtcVideoEncoder() { >+ if (factory_) { >+ factory_->EncoderDestroyed(this); >+ } >+} >+ >+int32_t FakeWebRtcVideoEncoder::InitEncode( >+ const webrtc::VideoCodec* codecSettings, >+ int32_t numberOfCores, >+ size_t maxPayloadSize) { >+ rtc::CritScope lock(&crit_); >+ codec_settings_ = *codecSettings; >+ init_encode_event_.Set(); >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoEncoder::Encode( >+ const webrtc::VideoFrame& inputImage, >+ const webrtc::CodecSpecificInfo* codecSpecificInfo, >+ const std::vector<webrtc::FrameType>* frame_types) { >+ rtc::CritScope lock(&crit_); >+ ++num_frames_encoded_; >+ init_encode_event_.Set(); >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoEncoder::RegisterEncodeCompleteCallback( >+ webrtc::EncodedImageCallback* callback) { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoEncoder::Release() { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoEncoder::SetChannelParameters(uint32_t packetLoss, >+ int64_t rtt) { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+int32_t FakeWebRtcVideoEncoder::SetRateAllocation( >+ const webrtc::VideoBitrateAllocation& allocation, >+ uint32_t framerate) { >+ return WEBRTC_VIDEO_CODEC_OK; >+} >+ >+bool FakeWebRtcVideoEncoder::WaitForInitEncode() { >+ return init_encode_event_.Wait(kEventTimeoutMs); >+} >+ >+webrtc::VideoCodec FakeWebRtcVideoEncoder::GetCodecSettings() { >+ rtc::CritScope lock(&crit_); >+ return codec_settings_; >+} >+ >+int FakeWebRtcVideoEncoder::GetNumEncodedFrames() { >+ rtc::CritScope lock(&crit_); >+ return num_frames_encoded_; >+} >+ >+// Video encoder factory. >+FakeWebRtcVideoEncoderFactory::FakeWebRtcVideoEncoderFactory() >+ : created_video_encoder_event_(false, false), >+ num_created_encoders_(0), >+ encoders_have_internal_sources_(false), >+ vp8_factory_mode_(false) {} >+ >+std::vector<webrtc::SdpVideoFormat> >+FakeWebRtcVideoEncoderFactory::GetSupportedFormats() const { >+ std::vector<webrtc::SdpVideoFormat> formats; >+ >+ for (const webrtc::SdpVideoFormat& format : formats_) { >+ // Don't add same codec twice. >+ if (!IsFormatSupported(formats, format)) >+ formats.push_back(format); >+ } >+ >+ return formats; >+} >+ >+std::unique_ptr<webrtc::VideoEncoder> >+FakeWebRtcVideoEncoderFactory::CreateVideoEncoder( >+ const webrtc::SdpVideoFormat& format) { >+ rtc::CritScope lock(&crit_); >+ std::unique_ptr<webrtc::VideoEncoder> encoder; >+ if (IsFormatSupported(formats_, format)) { >+ if (CodecNamesEq(format.name.c_str(), kVp8CodecName) && >+ !vp8_factory_mode_) { >+ // The simulcast adapter will ask this factory for multiple VP8 >+ // encoders. Enter vp8_factory_mode so that we now create these encoders >+ // instead of more adapters. >+ vp8_factory_mode_ = true; >+ encoder = >+ absl::make_unique<webrtc::SimulcastEncoderAdapter>(this, format); >+ } else { >+ num_created_encoders_++; >+ created_video_encoder_event_.Set(); >+ encoder = absl::make_unique<FakeWebRtcVideoEncoder>(this); >+ encoders_.push_back(static_cast<FakeWebRtcVideoEncoder*>(encoder.get())); >+ } >+ } >+ return encoder; >+} >+ >+webrtc::VideoEncoderFactory::CodecInfo >+FakeWebRtcVideoEncoderFactory::QueryVideoEncoder( >+ const webrtc::SdpVideoFormat& format) const { >+ webrtc::VideoEncoderFactory::CodecInfo info; >+ info.has_internal_source = encoders_have_internal_sources_; >+ info.is_hardware_accelerated = true; >+ return info; >+} >+ >+bool FakeWebRtcVideoEncoderFactory::WaitForCreatedVideoEncoders( >+ int num_encoders) { >+ int64_t start_offset_ms = rtc::TimeMillis(); >+ int64_t wait_time = kEventTimeoutMs; >+ do { >+ if (GetNumCreatedEncoders() >= num_encoders) >+ return true; >+ wait_time = kEventTimeoutMs - (rtc::TimeMillis() - start_offset_ms); >+ } while (wait_time > 0 && created_video_encoder_event_.Wait(wait_time)); >+ return false; >+} >+ >+void FakeWebRtcVideoEncoderFactory::EncoderDestroyed( >+ FakeWebRtcVideoEncoder* encoder) { >+ rtc::CritScope lock(&crit_); >+ encoders_.erase(std::remove(encoders_.begin(), encoders_.end(), encoder), >+ encoders_.end()); >+} >+ >+void FakeWebRtcVideoEncoderFactory::set_encoders_have_internal_sources( >+ bool internal_source) { >+ encoders_have_internal_sources_ = internal_source; >+} >+ >+void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodec( >+ const webrtc::SdpVideoFormat& format) { >+ formats_.push_back(format); >+} >+ >+void FakeWebRtcVideoEncoderFactory::AddSupportedVideoCodecType( >+ const std::string& name) { >+ // This is to match the default H264 params of cricket::VideoCodec. >+ cricket::VideoCodec video_codec(name); >+ formats_.push_back( >+ webrtc::SdpVideoFormat(video_codec.name, video_codec.params)); >+} >+ >+int FakeWebRtcVideoEncoderFactory::GetNumCreatedEncoders() { >+ rtc::CritScope lock(&crit_); >+ return num_created_encoders_; >+} >+ >+const std::vector<FakeWebRtcVideoEncoder*> >+FakeWebRtcVideoEncoderFactory::encoders() { >+ rtc::CritScope lock(&crit_); >+ return encoders_; >+} >+ >+} // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.h >index 2153f6be386..f4287a31d26 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/fakewebrtcvideoengine.h >@@ -11,248 +11,124 @@ > #ifndef MEDIA_ENGINE_FAKEWEBRTCVIDEOENGINE_H_ > #define MEDIA_ENGINE_FAKEWEBRTCVIDEOENGINE_H_ > >-#include <map> >-#include <set> >-#include <vector> >+#include <memory> > #include <string> >+#include <vector> > >+#include "absl/memory/memory.h" > #include "api/video_codecs/video_decoder.h" >+#include "api/video_codecs/video_decoder_factory.h" > #include "api/video_codecs/video_encoder.h" >-#include "media/base/codec.h" >-#include "media/engine/webrtcvideodecoderfactory.h" >-#include "media/engine/webrtcvideoencoderfactory.h" >-#include "modules/video_coding/include/video_error_codes.h" >-#include "rtc_base/basictypes.h" >+#include "api/video_codecs/video_encoder_factory.h" > #include "rtc_base/criticalsection.h" >-#include "rtc_base/gunit.h" >-#include "rtc_base/stringutils.h" >+#include "rtc_base/event.h" > #include "rtc_base/thread_annotations.h" > > namespace cricket { >-static const int kEventTimeoutMs = 10000; >+ >+class FakeWebRtcVideoDecoderFactory; >+class FakeWebRtcVideoEncoderFactory; > > // Fake class for mocking out webrtc::VideoDecoder > class FakeWebRtcVideoDecoder : public webrtc::VideoDecoder { > public: >- FakeWebRtcVideoDecoder() : num_frames_received_(0) {} >- >- virtual int32_t InitDecode(const webrtc::VideoCodec*, int32_t) { >- return WEBRTC_VIDEO_CODEC_OK; >- } >+ explicit FakeWebRtcVideoDecoder(FakeWebRtcVideoDecoderFactory* factory); >+ ~FakeWebRtcVideoDecoder(); > >- virtual int32_t Decode(const webrtc::EncodedImage&, >- bool, >- const webrtc::RTPFragmentationHeader*, >- const webrtc::CodecSpecificInfo*, >- int64_t) { >- num_frames_received_++; >- return WEBRTC_VIDEO_CODEC_OK; >- } >+ int32_t InitDecode(const webrtc::VideoCodec*, int32_t) override; >+ int32_t Decode(const webrtc::EncodedImage&, >+ bool, >+ const webrtc::CodecSpecificInfo*, >+ int64_t) override; >+ int32_t RegisterDecodeCompleteCallback( >+ webrtc::DecodedImageCallback*) override; >+ int32_t Release() override; > >- virtual int32_t RegisterDecodeCompleteCallback( >- webrtc::DecodedImageCallback*) { >- return WEBRTC_VIDEO_CODEC_OK; >- } >- >- virtual int32_t Release() { return WEBRTC_VIDEO_CODEC_OK; } >- >- int GetNumFramesReceived() const { >- return num_frames_received_; >- } >+ int GetNumFramesReceived() const; > > private: > int num_frames_received_; >+ FakeWebRtcVideoDecoderFactory* factory_; > }; > >-// Fake class for mocking out WebRtcVideoDecoderFactory. >-class FakeWebRtcVideoDecoderFactory : public WebRtcVideoDecoderFactory { >+// Fake class for mocking out webrtc::VideoDecoderFactory. >+class FakeWebRtcVideoDecoderFactory : public webrtc::VideoDecoderFactory { > public: >- FakeWebRtcVideoDecoderFactory() >- : num_created_decoders_(0) { >- } >- >- virtual webrtc::VideoDecoder* CreateVideoDecoder( >- webrtc::VideoCodecType type) { >- if (supported_codec_types_.count(type) == 0) { >- return NULL; >- } >- FakeWebRtcVideoDecoder* decoder = new FakeWebRtcVideoDecoder(); >- decoders_.push_back(decoder); >- num_created_decoders_++; >- return decoder; >- } >+ FakeWebRtcVideoDecoderFactory(); > >- virtual webrtc::VideoDecoder* CreateVideoDecoderWithParams( >- webrtc::VideoCodecType type, >- VideoDecoderParams params) { >- params_.push_back(params); >- return CreateVideoDecoder(type); >- } >+ std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override; >+ std::unique_ptr<webrtc::VideoDecoder> CreateVideoDecoder( >+ const webrtc::SdpVideoFormat& format) override; > >- virtual void DestroyVideoDecoder(webrtc::VideoDecoder* decoder) { >- decoders_.erase( >- std::remove(decoders_.begin(), decoders_.end(), decoder), >- decoders_.end()); >- delete decoder; >- } >- >- void AddSupportedVideoCodecType(webrtc::VideoCodecType type) { >- supported_codec_types_.insert(type); >- } >- >- int GetNumCreatedDecoders() { >- return num_created_decoders_; >- } >- >- const std::vector<FakeWebRtcVideoDecoder*>& decoders() { >- return decoders_; >- } >- >- const std::vector<VideoDecoderParams>& params() { return params_; } >+ void DecoderDestroyed(FakeWebRtcVideoDecoder* decoder); >+ void AddSupportedVideoCodecType(const webrtc::SdpVideoFormat& format); >+ int GetNumCreatedDecoders(); >+ const std::vector<FakeWebRtcVideoDecoder*>& decoders(); > > private: >- std::set<webrtc::VideoCodecType> supported_codec_types_; >+ std::vector<webrtc::SdpVideoFormat> supported_codec_formats_; > std::vector<FakeWebRtcVideoDecoder*> decoders_; > int num_created_decoders_; >- std::vector<VideoDecoderParams> params_; > }; > > // Fake class for mocking out webrtc::VideoEnoder > class FakeWebRtcVideoEncoder : public webrtc::VideoEncoder { > public: >- FakeWebRtcVideoEncoder() >- : init_encode_event_(false, false), num_frames_encoded_(0) {} >+ explicit FakeWebRtcVideoEncoder(FakeWebRtcVideoEncoderFactory* factory); >+ ~FakeWebRtcVideoEncoder(); > > int32_t InitEncode(const webrtc::VideoCodec* codecSettings, > int32_t numberOfCores, >- size_t maxPayloadSize) override { >- rtc::CritScope lock(&crit_); >- codec_settings_ = *codecSettings; >- init_encode_event_.Set(); >- return WEBRTC_VIDEO_CODEC_OK; >- } >- >- bool WaitForInitEncode() { return init_encode_event_.Wait(kEventTimeoutMs); } >- >- webrtc::VideoCodec GetCodecSettings() { >- rtc::CritScope lock(&crit_); >- return codec_settings_; >- } >- >+ size_t maxPayloadSize) override; > int32_t Encode(const webrtc::VideoFrame& inputImage, > const webrtc::CodecSpecificInfo* codecSpecificInfo, >- const std::vector<webrtc::FrameType>* frame_types) override { >- rtc::CritScope lock(&crit_); >- ++num_frames_encoded_; >- init_encode_event_.Set(); >- return WEBRTC_VIDEO_CODEC_OK; >- } >- >+ const std::vector<webrtc::FrameType>* frame_types) override; > int32_t RegisterEncodeCompleteCallback( >- webrtc::EncodedImageCallback* callback) override { >- return WEBRTC_VIDEO_CODEC_OK; >- } >- >- int32_t Release() override { return WEBRTC_VIDEO_CODEC_OK; } >- >- int32_t SetChannelParameters(uint32_t packetLoss, int64_t rtt) override { >- return WEBRTC_VIDEO_CODEC_OK; >- } >- >- int32_t SetRateAllocation(const webrtc::BitrateAllocation& allocation, >- uint32_t framerate) override { >- return WEBRTC_VIDEO_CODEC_OK; >- } >+ webrtc::EncodedImageCallback* callback) override; >+ int32_t Release() override; >+ int32_t SetChannelParameters(uint32_t packetLoss, int64_t rtt) override; >+ int32_t SetRateAllocation(const webrtc::VideoBitrateAllocation& allocation, >+ uint32_t framerate) override; > >- int GetNumEncodedFrames() { >- rtc::CritScope lock(&crit_); >- return num_frames_encoded_; >- } >+ bool WaitForInitEncode(); >+ webrtc::VideoCodec GetCodecSettings(); >+ int GetNumEncodedFrames(); > > private: > rtc::CriticalSection crit_; > rtc::Event init_encode_event_; > int num_frames_encoded_ RTC_GUARDED_BY(crit_); > webrtc::VideoCodec codec_settings_ RTC_GUARDED_BY(crit_); >+ FakeWebRtcVideoEncoderFactory* factory_; > }; > >-// Fake class for mocking out WebRtcVideoEncoderFactory. >-class FakeWebRtcVideoEncoderFactory : public WebRtcVideoEncoderFactory { >+// Fake class for mocking out webrtc::VideoEncoderFactory. >+class FakeWebRtcVideoEncoderFactory : public webrtc::VideoEncoderFactory { > public: >- FakeWebRtcVideoEncoderFactory() >- : created_video_encoder_event_(false, false), >- num_created_encoders_(0), >- encoders_have_internal_sources_(false) {} >- >- webrtc::VideoEncoder* CreateVideoEncoder( >- const cricket::VideoCodec& codec) override { >- rtc::CritScope lock(&crit_); >- if (!FindMatchingCodec(codecs_, codec)) >- return nullptr; >- FakeWebRtcVideoEncoder* encoder = new FakeWebRtcVideoEncoder(); >- encoders_.push_back(encoder); >- num_created_encoders_++; >- created_video_encoder_event_.Set(); >- return encoder; >- } >- >- bool WaitForCreatedVideoEncoders(int num_encoders) { >- int64_t start_offset_ms = rtc::TimeMillis(); >- int64_t wait_time = kEventTimeoutMs; >- do { >- if (GetNumCreatedEncoders() >= num_encoders) >- return true; >- wait_time = kEventTimeoutMs - (rtc::TimeMillis() - start_offset_ms); >- } while (wait_time > 0 && created_video_encoder_event_.Wait(wait_time)); >- return false; >- } >- >- void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) override { >- rtc::CritScope lock(&crit_); >- encoders_.erase( >- std::remove(encoders_.begin(), encoders_.end(), encoder), >- encoders_.end()); >- delete encoder; >- } >- >- const std::vector<cricket::VideoCodec>& supported_codecs() const override { >- return codecs_; >- } >- >- bool EncoderTypeHasInternalSource( >- webrtc::VideoCodecType type) const override { >- return encoders_have_internal_sources_; >- } >- >- void set_encoders_have_internal_sources(bool internal_source) { >- encoders_have_internal_sources_ = internal_source; >- } >- >- void AddSupportedVideoCodec(const cricket::VideoCodec& codec) { >- codecs_.push_back(codec); >- } >- >- void AddSupportedVideoCodecType(const std::string& name) { >- codecs_.push_back(cricket::VideoCodec(name)); >- } >- >- int GetNumCreatedEncoders() { >- rtc::CritScope lock(&crit_); >- return num_created_encoders_; >- } >- >- const std::vector<FakeWebRtcVideoEncoder*> encoders() { >- rtc::CritScope lock(&crit_); >- return encoders_; >- } >+ FakeWebRtcVideoEncoderFactory(); >+ >+ std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override; >+ std::unique_ptr<webrtc::VideoEncoder> CreateVideoEncoder( >+ const webrtc::SdpVideoFormat& format) override; >+ CodecInfo QueryVideoEncoder( >+ const webrtc::SdpVideoFormat& format) const override; >+ >+ bool WaitForCreatedVideoEncoders(int num_encoders); >+ void EncoderDestroyed(FakeWebRtcVideoEncoder* encoder); >+ void set_encoders_have_internal_sources(bool internal_source); >+ void AddSupportedVideoCodec(const webrtc::SdpVideoFormat& format); >+ void AddSupportedVideoCodecType(const std::string& name); >+ int GetNumCreatedEncoders(); >+ const std::vector<FakeWebRtcVideoEncoder*> encoders(); > > private: > rtc::CriticalSection crit_; > rtc::Event created_video_encoder_event_; >- std::vector<cricket::VideoCodec> codecs_; >+ std::vector<webrtc::SdpVideoFormat> formats_; > std::vector<FakeWebRtcVideoEncoder*> encoders_ RTC_GUARDED_BY(crit_); > int num_created_encoders_ RTC_GUARDED_BY(crit_); > bool encoders_have_internal_sources_; >+ bool vp8_factory_mode_; > }; > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internaldecoderfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internaldecoderfactory.cc >index 57daca256c4..df74773c86d 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internaldecoderfactory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internaldecoderfactory.cc >@@ -10,6 +10,7 @@ > > #include "media/engine/internaldecoderfactory.h" > >+#include "api/video_codecs/sdp_video_format.h" > #include "media/base/mediaconstants.h" > #include "modules/video_coding/codecs/h264/include/h264.h" > #include "modules/video_coding/codecs/vp8/include/vp8.h" >@@ -19,13 +20,29 @@ > > namespace webrtc { > >+namespace { >+ >+bool IsFormatSupported( >+ const std::vector<webrtc::SdpVideoFormat>& supported_formats, >+ const webrtc::SdpVideoFormat& format) { >+ for (const webrtc::SdpVideoFormat& supported_format : supported_formats) { >+ if (cricket::IsSameCodec(format.name, format.parameters, >+ supported_format.name, >+ supported_format.parameters)) { >+ return true; >+ } >+ } >+ return false; >+} >+ >+} // namespace >+ > std::vector<SdpVideoFormat> InternalDecoderFactory::GetSupportedFormats() > const { > std::vector<SdpVideoFormat> formats; >- if (VP8Decoder::IsSupported()) >- formats.push_back(SdpVideoFormat(cricket::kVp8CodecName)); >- if (VP9Decoder::IsSupported()) >- formats.push_back(SdpVideoFormat(cricket::kVp9CodecName)); >+ formats.push_back(SdpVideoFormat(cricket::kVp8CodecName)); >+ for (const SdpVideoFormat& format : SupportedVP9Codecs()) >+ formats.push_back(format); > for (const SdpVideoFormat& h264_format : SupportedH264Codecs()) > formats.push_back(h264_format); > return formats; >@@ -33,18 +50,19 @@ std::vector<SdpVideoFormat> InternalDecoderFactory::GetSupportedFormats() > > std::unique_ptr<VideoDecoder> InternalDecoderFactory::CreateVideoDecoder( > const SdpVideoFormat& format) { >+ if (!IsFormatSupported(GetSupportedFormats(), format)) { >+ RTC_LOG(LS_ERROR) << "Trying to create decoder for unsupported format"; >+ return nullptr; >+ } >+ > if (cricket::CodecNamesEq(format.name, cricket::kVp8CodecName)) > return VP8Decoder::Create(); >- >- if (cricket::CodecNamesEq(format.name, cricket::kVp9CodecName)) { >- RTC_DCHECK(VP9Decoder::IsSupported()); >+ if (cricket::CodecNamesEq(format.name, cricket::kVp9CodecName)) > return VP9Decoder::Create(); >- } >- > if (cricket::CodecNamesEq(format.name, cricket::kH264CodecName)) > return H264Decoder::Create(); > >- RTC_LOG(LS_ERROR) << "Trying to create decoder for unsupported format"; >+ RTC_NOTREACHED(); > return nullptr; > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internalencoderfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internalencoderfactory.cc >index 0390646add4..e6c3c2e72fd 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internalencoderfactory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/internalencoderfactory.cc >@@ -12,6 +12,7 @@ > > #include <utility> > >+#include "api/video_codecs/sdp_video_format.h" > #include "modules/video_coding/codecs/h264/include/h264.h" > #include "modules/video_coding/codecs/vp8/include/vp8.h" > #include "modules/video_coding/codecs/vp9/include/vp9.h" >@@ -22,14 +23,11 @@ namespace webrtc { > std::vector<SdpVideoFormat> InternalEncoderFactory::GetSupportedFormats() > const { > std::vector<SdpVideoFormat> supported_codecs; >- if (VP8Encoder::IsSupported()) >- supported_codecs.push_back(SdpVideoFormat(cricket::kVp8CodecName)); >- if (webrtc::VP9Encoder::IsSupported()) >- supported_codecs.push_back(SdpVideoFormat(cricket::kVp9CodecName)); >- >+ supported_codecs.push_back(SdpVideoFormat(cricket::kVp8CodecName)); >+ for (const webrtc::SdpVideoFormat& format : webrtc::SupportedVP9Codecs()) >+ supported_codecs.push_back(format); > for (const webrtc::SdpVideoFormat& format : webrtc::SupportedH264Codecs()) > supported_codecs.push_back(format); >- > return supported_codecs; > } > >@@ -45,13 +43,10 @@ std::unique_ptr<VideoEncoder> InternalEncoderFactory::CreateVideoEncoder( > const SdpVideoFormat& format) { > if (cricket::CodecNamesEq(format.name, cricket::kVp8CodecName)) > return VP8Encoder::Create(); >- > if (cricket::CodecNamesEq(format.name, cricket::kVp9CodecName)) >- return VP9Encoder::Create(); >- >+ return VP9Encoder::Create(cricket::VideoCodec(format)); > if (cricket::CodecNamesEq(format.name, cricket::kH264CodecName)) > return H264Encoder::Create(cricket::VideoCodec(format)); >- > RTC_LOG(LS_ERROR) << "Trying to created encoder of unsupported format " > << format.name; > return nullptr; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.cc >new file mode 100644 >index 00000000000..236a2e81acc >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.cc >@@ -0,0 +1,118 @@ >+/* >+ * Copyright (c) 2017 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 "media/engine/multiplexcodecfactory.h" >+ >+#include <utility> >+ >+#include "api/video_codecs/sdp_video_format.h" >+#include "media/base/codec.h" >+#include "media/base/mediaconstants.h" >+#include "modules/video_coding/codecs/multiplex/include/multiplex_decoder_adapter.h" >+#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h" >+#include "rtc_base/logging.h" >+ >+namespace { >+ >+bool IsMultiplexCodec(const cricket::VideoCodec& codec) { >+ return cricket::CodecNamesEq(codec.name.c_str(), >+ cricket::kMultiplexCodecName); >+} >+ >+} // anonymous namespace >+ >+namespace webrtc { >+ >+constexpr const char* kMultiplexAssociatedCodecName = cricket::kVp9CodecName; >+ >+MultiplexEncoderFactory::MultiplexEncoderFactory( >+ std::unique_ptr<VideoEncoderFactory> factory, >+ bool supports_augmenting_data) >+ : factory_(std::move(factory)), >+ supports_augmenting_data_(supports_augmenting_data) {} >+ >+std::vector<SdpVideoFormat> MultiplexEncoderFactory::GetSupportedFormats() >+ const { >+ std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats(); >+ for (const auto& format : formats) { >+ if (cricket::CodecNamesEq(format.name, kMultiplexAssociatedCodecName)) { >+ SdpVideoFormat multiplex_format = format; >+ multiplex_format.parameters[cricket::kCodecParamAssociatedCodecName] = >+ format.name; >+ multiplex_format.name = cricket::kMultiplexCodecName; >+ formats.push_back(multiplex_format); >+ break; >+ } >+ } >+ return formats; >+} >+ >+VideoEncoderFactory::CodecInfo MultiplexEncoderFactory::QueryVideoEncoder( >+ const SdpVideoFormat& format) const { >+ if (!IsMultiplexCodec(cricket::VideoCodec(format))) >+ return factory_->QueryVideoEncoder(format); >+ return factory_->QueryVideoEncoder( >+ SdpVideoFormat(kMultiplexAssociatedCodecName)); >+} >+ >+std::unique_ptr<VideoEncoder> MultiplexEncoderFactory::CreateVideoEncoder( >+ const SdpVideoFormat& format) { >+ if (!IsMultiplexCodec(cricket::VideoCodec(format))) >+ return factory_->CreateVideoEncoder(format); >+ const auto& it = >+ format.parameters.find(cricket::kCodecParamAssociatedCodecName); >+ if (it == format.parameters.end()) { >+ RTC_LOG(LS_ERROR) << "No assicated codec for multiplex."; >+ return nullptr; >+ } >+ SdpVideoFormat associated_format = format; >+ associated_format.name = it->second; >+ return std::unique_ptr<VideoEncoder>(new MultiplexEncoderAdapter( >+ factory_.get(), associated_format, supports_augmenting_data_)); >+} >+ >+MultiplexDecoderFactory::MultiplexDecoderFactory( >+ std::unique_ptr<VideoDecoderFactory> factory, >+ bool supports_augmenting_data) >+ : factory_(std::move(factory)), >+ supports_augmenting_data_(supports_augmenting_data) {} >+ >+std::vector<SdpVideoFormat> MultiplexDecoderFactory::GetSupportedFormats() >+ const { >+ std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats(); >+ for (const auto& format : formats) { >+ if (cricket::CodecNamesEq(format.name, kMultiplexAssociatedCodecName)) { >+ SdpVideoFormat multiplex_format = format; >+ multiplex_format.parameters[cricket::kCodecParamAssociatedCodecName] = >+ format.name; >+ multiplex_format.name = cricket::kMultiplexCodecName; >+ formats.push_back(multiplex_format); >+ } >+ } >+ return formats; >+} >+ >+std::unique_ptr<VideoDecoder> MultiplexDecoderFactory::CreateVideoDecoder( >+ const SdpVideoFormat& format) { >+ if (!IsMultiplexCodec(cricket::VideoCodec(format))) >+ return factory_->CreateVideoDecoder(format); >+ const auto& it = >+ format.parameters.find(cricket::kCodecParamAssociatedCodecName); >+ if (it == format.parameters.end()) { >+ RTC_LOG(LS_ERROR) << "No assicated codec for multiplex."; >+ return nullptr; >+ } >+ SdpVideoFormat associated_format = format; >+ associated_format.name = it->second; >+ return std::unique_ptr<VideoDecoder>(new MultiplexDecoderAdapter( >+ factory_.get(), associated_format, supports_augmenting_data_)); >+} >+ >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.h >new file mode 100644 >index 00000000000..030904f1b84 >--- /dev/null >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory.h >@@ -0,0 +1,61 @@ >+/* >+ * Copyright (c) 2017 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. >+ */ >+ >+#ifndef MEDIA_ENGINE_MULTIPLEXCODECFACTORY_H_ >+#define MEDIA_ENGINE_MULTIPLEXCODECFACTORY_H_ >+ >+#include <memory> >+#include <vector> >+ >+#include "api/video_codecs/video_decoder_factory.h" >+#include "api/video_codecs/video_encoder_factory.h" >+ >+namespace webrtc { >+ >+class MultiplexEncoderFactory : public VideoEncoderFactory { >+ public: >+ // supports_augmenting_data defines if the encoder would support augmenting >+ // data in that case the encoder expects video frame buffer of type >+ // AugmentedVideoFrameBuffer the encoder would encode the attached buffer and >+ // data together if the flag is not set any frame buffer can be passed in >+ MultiplexEncoderFactory(std::unique_ptr<VideoEncoderFactory> factory, >+ bool supports_augmenting_data = false); >+ >+ std::vector<SdpVideoFormat> GetSupportedFormats() const override; >+ CodecInfo QueryVideoEncoder(const SdpVideoFormat& format) const override; >+ std::unique_ptr<VideoEncoder> CreateVideoEncoder( >+ const SdpVideoFormat& format) override; >+ >+ private: >+ std::unique_ptr<VideoEncoderFactory> factory_; >+ const bool supports_augmenting_data_; >+}; >+ >+class MultiplexDecoderFactory : public VideoDecoderFactory { >+ public: >+ // supports_augmenting_data defines if the decoder would support augmenting >+ // data in that case the decoder expects the encoded video frame to contain >+ // augmenting_data it is expected that the sender is using MultiplexEncoder >+ // with supports_augmenting_data set >+ MultiplexDecoderFactory(std::unique_ptr<VideoDecoderFactory> factory, >+ bool supports_augmenting_data = false); >+ >+ std::vector<SdpVideoFormat> GetSupportedFormats() const override; >+ std::unique_ptr<VideoDecoder> CreateVideoDecoder( >+ const SdpVideoFormat& format) override; >+ >+ private: >+ std::unique_ptr<VideoDecoderFactory> factory_; >+ const bool supports_augmenting_data_; >+}; >+ >+} // namespace webrtc >+ >+#endif // MEDIA_ENGINE_MULTIPLEXCODECFACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory_unittest.cc >similarity index 79% >rename from Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory_unittest.cc >rename to Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory_unittest.cc >index a86eff04aca..bc30f60c6d4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/multiplexcodecfactory_unittest.cc >@@ -8,7 +8,7 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include "media/engine/stereocodecfactory.h" >+#include "media/engine/multiplexcodecfactory.h" > > #include <utility> > >@@ -22,24 +22,24 @@ > > namespace webrtc { > >-TEST(StereoDecoderFactory, CreateVideoDecoder) { >+TEST(MultiplexDecoderFactory, CreateVideoDecoder) { > std::unique_ptr<VideoDecoderFactory> internal_factory( > new InternalDecoderFactory()); >- StereoDecoderFactory factory(std::move(internal_factory)); >+ MultiplexDecoderFactory factory(std::move(internal_factory)); > std::unique_ptr<VideoDecoder> decoder = > factory.CreateVideoDecoder(SdpVideoFormat( >- cricket::kStereoCodecName, >+ cricket::kMultiplexCodecName, > {{cricket::kCodecParamAssociatedCodecName, cricket::kVp9CodecName}})); > EXPECT_TRUE(decoder); > } > >-TEST(StereoEncoderFactory, CreateVideoEncoder) { >+TEST(MultiplexEncoderFactory, CreateVideoEncoder) { > std::unique_ptr<VideoEncoderFactory> internal_factory( > new InternalEncoderFactory()); >- StereoEncoderFactory factory(std::move(internal_factory)); >+ MultiplexEncoderFactory factory(std::move(internal_factory)); > std::unique_ptr<VideoEncoder> encoder = > factory.CreateVideoEncoder(SdpVideoFormat( >- cricket::kStereoCodecName, >+ cricket::kMultiplexCodecName, > {{cricket::kCodecParamAssociatedCodecName, cricket::kVp9CodecName}})); > EXPECT_TRUE(encoder); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/nullwebrtcvideoengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/nullwebrtcvideoengine.h >index 0ff997d7ad3..9af0f9b130c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/nullwebrtcvideoengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/nullwebrtcvideoengine.h >@@ -22,7 +22,6 @@ class Call; > > } // namespace webrtc > >- > namespace cricket { > > class VideoMediaChannel; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.cc >index 1927f43a00e..5d2fb6757c4 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.cc >@@ -30,52 +30,55 @@ PayloadTypeMapper::PayloadTypeMapper() > // mapping within the exclusive range. > : next_unused_payload_type_(96), > max_payload_type_(127), >- mappings_({ >- // Static payload type assignments according to RFC 3551. >- {{"PCMU", 8000, 1}, 0}, >- {{"GSM", 8000, 1}, 3}, >- {{"G723", 8000, 1}, 4}, >- {{"DVI4", 8000, 1}, 5}, >- {{"DVI4", 16000, 1}, 6}, >- {{"LPC", 8000, 1}, 7}, >- {{"PCMA", 8000, 1}, 8}, >- {{"G722", 8000, 1}, 9}, >- {{"L16", 44100, 2}, 10}, >- {{"L16", 44100, 1}, 11}, >- {{"QCELP", 8000, 1}, 12}, >- {{"CN", 8000, 1}, 13}, >- // RFC 4566 is a bit ambiguous on the contents of the "encoding >- // parameters" field, which, for audio, encodes the number of >- // channels. It is "optional and may be omitted if the number of >- // channels is one". Does that necessarily imply that an omitted >- // encoding parameter means one channel? Since RFC 3551 doesn't >- // specify a value for this parameter for MPA, I've included both 0 >- // and 1 here, to increase the chances it will be correctly used if >- // someone implements an MPEG audio encoder/decoder. >- {{"MPA", 90000, 0}, 14}, >- {{"MPA", 90000, 1}, 14}, >- {{"G728", 8000, 1}, 15}, >- {{"DVI4", 11025, 1}, 16}, >- {{"DVI4", 22050, 1}, 17}, >- {{"G729", 8000, 1}, 18}, >- >- // Payload type assignments currently used by WebRTC. >- // Includes data to reduce collisions (and thus reassignments) >- {{kGoogleRtpDataCodecName, 0, 0}, kGoogleRtpDataCodecPlType}, >- {{kIlbcCodecName, 8000, 1}, 102}, >- {{kIsacCodecName, 16000, 1}, 103}, >- {{kIsacCodecName, 32000, 1}, 104}, >- {{kCnCodecName, 16000, 1}, 105}, >- {{kCnCodecName, 32000, 1}, 106}, >- {{kGoogleSctpDataCodecName, 0, 0}, kGoogleSctpDataCodecPlType}, >- {{kOpusCodecName, 48000, 2, >- {{"minptime", "10"}, {"useinbandfec", "1"}}}, 111}, >- // TODO(solenberg): Remove the hard coded 16k,32k,48k DTMF once we >- // assign payload types dynamically for send side as well. >- {{kDtmfCodecName, 48000, 1}, 110}, >- {{kDtmfCodecName, 32000, 1}, 112}, >- {{kDtmfCodecName, 16000, 1}, 113}, >- {{kDtmfCodecName, 8000, 1}, 126}}) { >+ mappings_( >+ {// Static payload type assignments according to RFC 3551. >+ {{"PCMU", 8000, 1}, 0}, >+ {{"GSM", 8000, 1}, 3}, >+ {{"G723", 8000, 1}, 4}, >+ {{"DVI4", 8000, 1}, 5}, >+ {{"DVI4", 16000, 1}, 6}, >+ {{"LPC", 8000, 1}, 7}, >+ {{"PCMA", 8000, 1}, 8}, >+ {{"G722", 8000, 1}, 9}, >+ {{"L16", 44100, 2}, 10}, >+ {{"L16", 44100, 1}, 11}, >+ {{"QCELP", 8000, 1}, 12}, >+ {{"CN", 8000, 1}, 13}, >+ // RFC 4566 is a bit ambiguous on the contents of the "encoding >+ // parameters" field, which, for audio, encodes the number of >+ // channels. It is "optional and may be omitted if the number of >+ // channels is one". Does that necessarily imply that an omitted >+ // encoding parameter means one channel? Since RFC 3551 doesn't >+ // specify a value for this parameter for MPA, I've included both 0 >+ // and 1 here, to increase the chances it will be correctly used if >+ // someone implements an MPEG audio encoder/decoder. >+ {{"MPA", 90000, 0}, 14}, >+ {{"MPA", 90000, 1}, 14}, >+ {{"G728", 8000, 1}, 15}, >+ {{"DVI4", 11025, 1}, 16}, >+ {{"DVI4", 22050, 1}, 17}, >+ {{"G729", 8000, 1}, 18}, >+ >+ // Payload type assignments currently used by WebRTC. >+ // Includes data to reduce collisions (and thus reassignments) >+ {{kGoogleRtpDataCodecName, 0, 0}, kGoogleRtpDataCodecPlType}, >+ {{kIlbcCodecName, 8000, 1}, 102}, >+ {{kIsacCodecName, 16000, 1}, 103}, >+ {{kIsacCodecName, 32000, 1}, 104}, >+ {{kCnCodecName, 16000, 1}, 105}, >+ {{kCnCodecName, 32000, 1}, 106}, >+ {{kGoogleSctpDataCodecName, 0, 0}, kGoogleSctpDataCodecPlType}, >+ {{kOpusCodecName, >+ 48000, >+ 2, >+ {{"minptime", "10"}, {"useinbandfec", "1"}}}, >+ 111}, >+ // TODO(solenberg): Remove the hard coded 16k,32k,48k DTMF once we >+ // assign payload types dynamically for send side as well. >+ {{kDtmfCodecName, 48000, 1}, 110}, >+ {{kDtmfCodecName, 32000, 1}, 112}, >+ {{kDtmfCodecName, 16000, 1}, 113}, >+ {{kDtmfCodecName, 8000, 1}, 126}}) { > // TODO(ossu): Try to keep this as change-proof as possible until we're able > // to remove the payload type constants from everywhere in the code. > for (const auto& mapping : mappings_) { >@@ -85,7 +88,7 @@ PayloadTypeMapper::PayloadTypeMapper() > > PayloadTypeMapper::~PayloadTypeMapper() = default; > >-rtc::Optional<int> PayloadTypeMapper::GetMappingFor( >+absl::optional<int> PayloadTypeMapper::GetMappingFor( > const webrtc::SdpAudioFormat& format) { > auto iter = mappings_.find(format); > if (iter != mappings_.end()) >@@ -102,19 +105,19 @@ rtc::Optional<int> PayloadTypeMapper::GetMappingFor( > } > } > >- return rtc::nullopt; >+ return absl::nullopt; > } > >-rtc::Optional<int> PayloadTypeMapper::FindMappingFor( >+absl::optional<int> PayloadTypeMapper::FindMappingFor( > const webrtc::SdpAudioFormat& format) const { > auto iter = mappings_.find(format); > if (iter != mappings_.end()) > return iter->second; > >- return rtc::nullopt; >+ return absl::nullopt; > } > >-rtc::Optional<AudioCodec> PayloadTypeMapper::ToAudioCodec( >+absl::optional<AudioCodec> PayloadTypeMapper::ToAudioCodec( > const webrtc::SdpAudioFormat& format) { > // TODO(ossu): We can safely set bitrate to zero here, since that field is > // not presented in the SDP. It is used to ferry around some target bitrate >@@ -129,7 +132,7 @@ rtc::Optional<AudioCodec> PayloadTypeMapper::ToAudioCodec( > return std::move(codec); > } > >- return rtc::nullopt; >+ return absl::nullopt; > } > > bool PayloadTypeMapper::SdpAudioFormatOrdering::operator()( >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.h >index 914c08c97ba..d8ab4a4261f 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper.h >@@ -14,8 +14,8 @@ > #include <map> > #include <set> > >+#include "absl/types/optional.h" > #include "api/audio_codecs/audio_format.h" >-#include "api/optional.h" > #include "media/base/codec.h" > > namespace cricket { >@@ -30,15 +30,16 @@ class PayloadTypeMapper { > // Finds the current payload type for |format| or assigns a new one, if no > // current mapping exists. Will return an empty value if it was unable to > // create a mapping, i.e. if all dynamic payload type ids have been used up. >- rtc::Optional<int> GetMappingFor(const webrtc::SdpAudioFormat& format); >+ absl::optional<int> GetMappingFor(const webrtc::SdpAudioFormat& format); > > // Finds the current payload type for |format|, if any. Returns an empty value > // if no payload type mapping exists for the format. >- rtc::Optional<int> FindMappingFor(const webrtc::SdpAudioFormat& format) const; >+ absl::optional<int> FindMappingFor( >+ const webrtc::SdpAudioFormat& format) const; > > // Like GetMappingFor, but fills in an AudioCodec structure with the necessary > // information instead. >- rtc::Optional<AudioCodec> ToAudioCodec(const webrtc::SdpAudioFormat& format); >+ absl::optional<AudioCodec> ToAudioCodec(const webrtc::SdpAudioFormat& format); > > private: > struct SdpAudioFormatOrdering { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper_unittest.cc >index 96d56c28d2f..979ce61dccc 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/payload_type_mapper_unittest.cc >@@ -22,42 +22,45 @@ class PayloadTypeMapperTest : public testing::Test { > }; > > TEST_F(PayloadTypeMapperTest, StaticPayloadTypes) { >- EXPECT_EQ(0, mapper_.FindMappingFor({"pcmu", 8000, 1})); >- EXPECT_EQ(3, mapper_.FindMappingFor({"gsm", 8000, 1})); >- EXPECT_EQ(4, mapper_.FindMappingFor({"g723", 8000, 1})); >- EXPECT_EQ(5, mapper_.FindMappingFor({"dvi4", 8000, 1})); >- EXPECT_EQ(6, mapper_.FindMappingFor({"dvi4", 16000, 1})); >- EXPECT_EQ(7, mapper_.FindMappingFor({"lpc", 8000, 1})); >- EXPECT_EQ(8, mapper_.FindMappingFor({"pcma", 8000, 1})); >- EXPECT_EQ(9, mapper_.FindMappingFor({"g722", 8000, 1})); >- EXPECT_EQ(10, mapper_.FindMappingFor({"l16", 44100, 2})); >- EXPECT_EQ(11, mapper_.FindMappingFor({"l16", 44100, 1})); >- EXPECT_EQ(12, mapper_.FindMappingFor({"qcelp", 8000, 1})); >- EXPECT_EQ(13, mapper_.FindMappingFor({"cn", 8000, 1})); >- EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 0})); >- EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 1})); >- EXPECT_EQ(15, mapper_.FindMappingFor({"g728", 8000, 1})); >- EXPECT_EQ(16, mapper_.FindMappingFor({"dvi4", 11025, 1})); >- EXPECT_EQ(17, mapper_.FindMappingFor({"dvi4", 22050, 1})); >- EXPECT_EQ(18, mapper_.FindMappingFor({"g729", 8000, 1})); >+ EXPECT_EQ(0, mapper_.FindMappingFor({"pcmu", 8000, 1})); >+ EXPECT_EQ(3, mapper_.FindMappingFor({"gsm", 8000, 1})); >+ EXPECT_EQ(4, mapper_.FindMappingFor({"g723", 8000, 1})); >+ EXPECT_EQ(5, mapper_.FindMappingFor({"dvi4", 8000, 1})); >+ EXPECT_EQ(6, mapper_.FindMappingFor({"dvi4", 16000, 1})); >+ EXPECT_EQ(7, mapper_.FindMappingFor({"lpc", 8000, 1})); >+ EXPECT_EQ(8, mapper_.FindMappingFor({"pcma", 8000, 1})); >+ EXPECT_EQ(9, mapper_.FindMappingFor({"g722", 8000, 1})); >+ EXPECT_EQ(10, mapper_.FindMappingFor({"l16", 44100, 2})); >+ EXPECT_EQ(11, mapper_.FindMappingFor({"l16", 44100, 1})); >+ EXPECT_EQ(12, mapper_.FindMappingFor({"qcelp", 8000, 1})); >+ EXPECT_EQ(13, mapper_.FindMappingFor({"cn", 8000, 1})); >+ EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 0})); >+ EXPECT_EQ(14, mapper_.FindMappingFor({"mpa", 90000, 1})); >+ EXPECT_EQ(15, mapper_.FindMappingFor({"g728", 8000, 1})); >+ EXPECT_EQ(16, mapper_.FindMappingFor({"dvi4", 11025, 1})); >+ EXPECT_EQ(17, mapper_.FindMappingFor({"dvi4", 22050, 1})); >+ EXPECT_EQ(18, mapper_.FindMappingFor({"g729", 8000, 1})); > } > > TEST_F(PayloadTypeMapperTest, WebRTCPayloadTypes) { > // Tests that the payload mapper knows about the audio and data formats we've > // been using in WebRTC, with their hard coded values. >- auto data_mapping = [this] (const char *name) { >+ auto data_mapping = [this](const char* name) { > return mapper_.FindMappingFor({name, 0, 0}); > }; > EXPECT_EQ(kGoogleRtpDataCodecPlType, data_mapping(kGoogleRtpDataCodecName)); > EXPECT_EQ(kGoogleSctpDataCodecPlType, data_mapping(kGoogleSctpDataCodecName)); > >- EXPECT_EQ(102, mapper_.FindMappingFor({kIlbcCodecName, 8000, 1})); >+ EXPECT_EQ(102, mapper_.FindMappingFor({kIlbcCodecName, 8000, 1})); > EXPECT_EQ(103, mapper_.FindMappingFor({kIsacCodecName, 16000, 1})); > EXPECT_EQ(104, mapper_.FindMappingFor({kIsacCodecName, 32000, 1})); >- EXPECT_EQ(105, mapper_.FindMappingFor({kCnCodecName, 16000, 1})); >- EXPECT_EQ(106, mapper_.FindMappingFor({kCnCodecName, 32000, 1})); >- EXPECT_EQ(111, mapper_.FindMappingFor({kOpusCodecName, 48000, 2, >- {{"minptime", "10"}, {"useinbandfec", "1"}}})); >+ EXPECT_EQ(105, mapper_.FindMappingFor({kCnCodecName, 16000, 1})); >+ EXPECT_EQ(106, mapper_.FindMappingFor({kCnCodecName, 32000, 1})); >+ EXPECT_EQ(111, mapper_.FindMappingFor( >+ {kOpusCodecName, >+ 48000, >+ 2, >+ {{"minptime", "10"}, {"useinbandfec", "1"}}})); > // TODO(solenberg): Remove 16k, 32k, 48k DTMF checks once these payload types > // are dynamically assigned. > EXPECT_EQ(110, mapper_.FindMappingFor({kDtmfCodecName, 48000, 1})); >@@ -83,7 +86,7 @@ TEST_F(PayloadTypeMapperTest, ValidDynamicPayloadTypes) { > std::set<int> used_payload_types; > for (int i = 0; i != 256; ++i) { > std::string format_name = "unknown_format_" + std::to_string(i); >- webrtc::SdpAudioFormat format(format_name.c_str(), i*100, (i % 2) + 1); >+ webrtc::SdpAudioFormat format(format_name.c_str(), i * 100, (i % 2) + 1); > auto opt_payload_type = mapper_.GetMappingFor(format); > bool mapper_is_full = false; > >@@ -124,7 +127,7 @@ TEST_F(PayloadTypeMapperTest, ToAudioCodec) { > EXPECT_TRUE(opt_audio_codec); > > if (opt_payload_type && opt_audio_codec) { >- int payload_type = *opt_payload_type; >+ int payload_type = *opt_payload_type; > const AudioCodec& codec = *opt_audio_codec; > > EXPECT_EQ(codec.id, payload_type); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideodecoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideodecoder.cc >index a9f85378ab5..733132b0801 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideodecoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideodecoder.cc >@@ -30,7 +30,6 @@ class ScopedVideoDecoder : public webrtc::VideoDecoder { > int32_t Release() override; > int32_t Decode(const webrtc::EncodedImage& input_image, > bool missing_frames, >- const webrtc::RTPFragmentationHeader* fragmentation, > const webrtc::CodecSpecificInfo* codec_specific_info, > int64_t render_time_ms) override; > bool PrefersLateDecoding() const override; >@@ -64,11 +63,10 @@ int32_t ScopedVideoDecoder::Release() { > int32_t ScopedVideoDecoder::Decode( > const webrtc::EncodedImage& input_image, > bool missing_frames, >- const webrtc::RTPFragmentationHeader* fragmentation, > const webrtc::CodecSpecificInfo* codec_specific_info, > int64_t render_time_ms) { >- return decoder_->Decode(input_image, missing_frames, fragmentation, >- codec_specific_info, render_time_ms); >+ return decoder_->Decode(input_image, missing_frames, codec_specific_info, >+ render_time_ms); > } > > bool ScopedVideoDecoder::PrefersLateDecoding() const { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideoencoder.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideoencoder.cc >index 0f563641f63..026654e0720 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideoencoder.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/scopedvideoencoder.cc >@@ -12,6 +12,7 @@ > > #include <vector> > >+#include "api/video/video_bitrate_allocation.h" > #include "api/video_codecs/video_encoder.h" > > namespace cricket { >@@ -34,10 +35,9 @@ class ScopedVideoEncoder : public webrtc::VideoEncoder { > const std::vector<webrtc::FrameType>* frame_types) override; > int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; > int32_t SetRates(uint32_t bitrate, uint32_t framerate) override; >- int32_t SetRateAllocation(const webrtc::BitrateAllocation& allocation, >+ int32_t SetRateAllocation(const webrtc::VideoBitrateAllocation& allocation, > uint32_t framerate) override; > ScalingSettings GetScalingSettings() const override; >- int32_t SetPeriodicKeyFrames(bool enable) override; > bool SupportsNativeHandle() const override; > const char* ImplementationName() const override; > >@@ -85,7 +85,7 @@ int32_t ScopedVideoEncoder::SetRates(uint32_t bitrate, uint32_t framerate) { > } > > int32_t ScopedVideoEncoder::SetRateAllocation( >- const webrtc::BitrateAllocation& allocation, >+ const webrtc::VideoBitrateAllocation& allocation, > uint32_t framerate) { > return encoder_->SetRateAllocation(allocation, framerate); > } >@@ -95,10 +95,6 @@ webrtc::VideoEncoder::ScalingSettings ScopedVideoEncoder::GetScalingSettings() > return encoder_->GetScalingSettings(); > } > >-int32_t ScopedVideoEncoder::SetPeriodicKeyFrames(bool enable) { >- return encoder_->SetPeriodicKeyFrames(enable); >-} >- > bool ScopedVideoEncoder::SupportsNativeHandle() const { > return encoder_->SupportsNativeHandle(); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.cc >index 6d68453f7b6..dc05081acea 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.cc >@@ -15,12 +15,26 @@ > #include "media/base/streamparams.h" > #include "media/engine/constants.h" > #include "media/engine/simulcast.h" >+#include "modules/video_coding/utility/simulcast_rate_allocator.h" > #include "rtc_base/arraysize.h" > #include "rtc_base/logging.h" > #include "system_wrappers/include/field_trial.h" > > namespace cricket { > >+namespace { >+ >+// Limits for legacy conference screensharing mode. Currently used for the >+// lower of the two simulcast streams. >+constexpr int kScreenshareDefaultTl0BitrateKbps = 200; >+constexpr int kScreenshareDefaultTl1BitrateKbps = 1000; >+ >+// Max bitrate for the higher one of the two simulcast stream used for screen >+// content. >+constexpr int kScreenshareHighStreamMaxBitrateBps = 1600000; >+ >+} // namespace >+ > struct SimulcastFormat { > int width; > int height; >@@ -41,6 +55,7 @@ struct SimulcastFormat { > // These tables describe from which resolution we can use how many > // simulcast layers at what bitrates (maximum, target, and minimum). > // Important!! Keep this table from high resolution to low resolution. >+// clang-format off > const SimulcastFormat kSimulcastFormats[] = { > {1920, 1080, 3, 5000, 4000, 800}, > {1280, 720, 3, 2500, 2500, 600}, >@@ -50,23 +65,34 @@ const SimulcastFormat kSimulcastFormats[] = { > {320, 180, 1, 200, 150, 30}, > {0, 0, 1, 200, 150, 30} > }; >+// clang-format on >+ >+const int kMaxScreenshareSimulcastLayers = 2; > >-const int kMaxScreenshareSimulcastStreams = 2; >- >-// Multiway: Number of temporal layers for each simulcast stream, for maximum >-// possible number of simulcast streams |kMaxSimulcastStreams|. The array >-// goes from lowest resolution at position 0 to highest resolution. >-// For example, first three elements correspond to say: QVGA, VGA, WHD. >-static const int >- kDefaultConferenceNumberOfTemporalLayers[webrtc::kMaxSimulcastStreams] = >- {3, 3, 3, 3}; >- >-void GetSimulcastSsrcs(const StreamParams& sp, std::vector<uint32_t>* ssrcs) { >- const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics); >- if (sim_group) { >- ssrcs->insert( >- ssrcs->end(), sim_group->ssrcs.begin(), sim_group->ssrcs.end()); >+// Multiway: Number of temporal layers for each simulcast stream. >+int DefaultNumberOfTemporalLayers(int simulcast_id) { >+ RTC_CHECK_GE(simulcast_id, 0); >+ RTC_CHECK_LT(simulcast_id, webrtc::kMaxSimulcastStreams); >+ >+ const int kDefaultNumTemporalLayers = 3; >+ >+ const std::string group_name = >+ webrtc::field_trial::FindFullName("WebRTC-VP8ConferenceTemporalLayers"); >+ if (group_name.empty()) >+ return kDefaultNumTemporalLayers; >+ >+ int num_temporal_layers = kDefaultNumTemporalLayers; >+ if (sscanf(group_name.c_str(), "%d", &num_temporal_layers) == 1 && >+ num_temporal_layers > 0 && >+ num_temporal_layers <= webrtc::kMaxTemporalStreams) { >+ return num_temporal_layers; > } >+ >+ RTC_LOG(LS_WARNING) << "Attempt to set number of temporal layers to " >+ "incorrect value: " >+ << group_name; >+ >+ return kDefaultNumTemporalLayers; > } > > int FindSimulcastFormatIndex(int width, int height) { >@@ -98,7 +124,7 @@ int FindSimulcastFormatIndex(int width, int height, size_t max_layers) { > } > > // Simulcast stream width and height must both be dividable by >-// |2 ^ simulcast_layers - 1|. >+// |2 ^ (simulcast_layers - 1)|. > int NormalizeSimulcastSize(int size, size_t simulcast_layers) { > const int base2_exponent = static_cast<int>(simulcast_layers) - 1; > return ((size >> base2_exponent) << base2_exponent); >@@ -132,181 +158,206 @@ void SlotSimulcastMaxResolution(size_t max_layers, int* width, int* height) { > << " height:" << *height; > } > >-int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& streams) { >+void BoostMaxSimulcastLayer(int max_bitrate_bps, >+ std::vector<webrtc::VideoStream>* layers) { >+ if (layers->empty()) >+ return; >+ >+ // Spend additional bits to boost the max layer. >+ int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(*layers); >+ if (bitrate_left_bps > 0) { >+ layers->back().max_bitrate_bps += bitrate_left_bps; >+ } >+} >+ >+int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& layers) { >+ if (layers.empty()) >+ return 0; >+ > int total_max_bitrate_bps = 0; >- for (size_t s = 0; s < streams.size() - 1; ++s) { >- total_max_bitrate_bps += streams[s].target_bitrate_bps; >+ for (size_t s = 0; s < layers.size() - 1; ++s) { >+ total_max_bitrate_bps += layers[s].target_bitrate_bps; > } >- total_max_bitrate_bps += streams.back().max_bitrate_bps; >+ total_max_bitrate_bps += layers.back().max_bitrate_bps; > return total_max_bitrate_bps; > } > >-std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_streams, >- int width, >- int height, >- int max_bitrate_bps, >- double bitrate_priority, >- int max_qp, >- int max_framerate, >- bool is_screencast) { >- size_t num_simulcast_layers; >- if (is_screencast) { >- if (UseSimulcastScreenshare()) { >- num_simulcast_layers = >- std::min<int>(max_streams, kMaxScreenshareSimulcastStreams); >- } else { >- num_simulcast_layers = 1; >- } >+std::vector<webrtc::VideoStream> GetSimulcastConfig( >+ size_t max_layers, >+ int width, >+ int height, >+ int /*max_bitrate_bps*/, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool is_screenshare, >+ bool temporal_layers_supported) { >+ if (is_screenshare) { >+ return GetScreenshareLayers(max_layers, width, height, bitrate_priority, >+ max_qp, max_framerate, >+ temporal_layers_supported); > } else { >- num_simulcast_layers = FindSimulcastMaxLayers(width, height); >+ return GetNormalSimulcastLayers(max_layers, width, height, bitrate_priority, >+ max_qp, max_framerate, >+ temporal_layers_supported); > } >+} > >- if (num_simulcast_layers > max_streams) { >- // If the number of SSRCs in the group differs from our target >- // number of simulcast streams for current resolution, switch down >- // to a resolution that matches our number of SSRCs. >- SlotSimulcastMaxResolution(max_streams, &width, &height); >- num_simulcast_layers = max_streams; >+std::vector<webrtc::VideoStream> GetNormalSimulcastLayers( >+ size_t max_layers, >+ int width, >+ int height, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool temporal_layers_supported) { >+ // TODO(bugs.webrtc.org/8785): Currently if the resolution isn't large enough >+ // (defined in kSimulcastFormats) we scale down the number of simulcast >+ // layers. Consider changing this so that the application can have more >+ // control over exactly how many simulcast layers are used. >+ size_t num_simulcast_layers = FindSimulcastMaxLayers(width, height); >+ if (num_simulcast_layers > max_layers) { >+ // TODO(bugs.webrtc.org/8486): This scales down the resolution if the >+ // number of simulcast layers created by the application isn't sufficient >+ // (defined in kSimulcastFormats). For example if the input frame's >+ // resolution is HD, but there are only 2 simulcast layers, the >+ // resolution gets scaled down to VGA. Consider taking this logic out to >+ // allow the application more control over the resolutions. >+ SlotSimulcastMaxResolution(max_layers, &width, &height); >+ num_simulcast_layers = max_layers; > } >- std::vector<webrtc::VideoStream> streams; >- streams.resize(num_simulcast_layers); >- >- if (is_screencast) { >- ScreenshareLayerConfig config = ScreenshareLayerConfig::GetDefault(); >- // For legacy screenshare in conference mode, tl0 and tl1 bitrates are >- // piggybacked on the VideoCodec struct as target and max bitrates, >- // respectively. See eg. webrtc::VP8EncoderImpl::SetRates(). >- streams[0].width = width; >- streams[0].height = height; >- streams[0].max_qp = max_qp; >- streams[0].max_framerate = 5; >- streams[0].min_bitrate_bps = kMinVideoBitrateBps; >- streams[0].target_bitrate_bps = config.tl0_bitrate_kbps * 1000; >- streams[0].max_bitrate_bps = config.tl1_bitrate_kbps * 1000; >- streams[0].temporal_layer_thresholds_bps.clear(); >- streams[0].temporal_layer_thresholds_bps.push_back(config.tl0_bitrate_kbps * >- 1000); >- >- // With simulcast enabled, add another spatial layer. This one will have a >- // more normal layout, with the regular 3 temporal layer pattern and no fps >- // restrictions. The base simulcast stream will still use legacy setup. >- if (num_simulcast_layers == kMaxScreenshareSimulcastStreams) { >- // Add optional upper simulcast layer. >- // Lowest temporal layers of a 3 layer setup will have 40% of the total >- // bitrate allocation for that stream. Make sure the gap between the >- // target of the lower stream and first temporal layer of the higher one >- // is at most 2x the bitrate, so that upswitching is not hampered by >- // stalled bitrate estimates. >- int max_bitrate_bps = 2 * ((streams[0].target_bitrate_bps * 10) / 4); >- // Cap max bitrate so it isn't overly high for the given resolution. >- max_bitrate_bps = std::min<int>( >- max_bitrate_bps, FindSimulcastMaxBitrateBps(width, height)); >- >- streams[1].width = width; >- streams[1].height = height; >- streams[1].max_qp = max_qp; >- streams[1].max_framerate = max_framerate; >- // Three temporal layers means two thresholds. >- streams[1].temporal_layer_thresholds_bps.resize(2); >- streams[1].min_bitrate_bps = streams[0].target_bitrate_bps * 2; >- streams[1].target_bitrate_bps = max_bitrate_bps; >- streams[1].max_bitrate_bps = max_bitrate_bps; >- } >- } else { >- // Format width and height has to be divisible by |2 ^ number_streams - 1|. >- width = NormalizeSimulcastSize(width, num_simulcast_layers); >- height = NormalizeSimulcastSize(height, num_simulcast_layers); >- >- // Add simulcast sub-streams from lower resolution to higher resolutions. >- // Add simulcast streams, from highest resolution (|s| = number_streams -1) >- // to lowest resolution at |s| = 0. >- for (size_t s = num_simulcast_layers - 1;; --s) { >- streams[s].width = width; >- streams[s].height = height; >- // TODO(pbos): Fill actual temporal-layer bitrate thresholds. >- streams[s].max_qp = max_qp; >- streams[s].temporal_layer_thresholds_bps.resize( >- kDefaultConferenceNumberOfTemporalLayers[s] - 1); >- streams[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height); >- streams[s].target_bitrate_bps = >- FindSimulcastTargetBitrateBps(width, height); >- streams[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height); >- streams[s].max_framerate = max_framerate; >- >- width /= 2; >- height /= 2; >- >- if (s == 0) >- break; >- } >- >- // Spend additional bits to boost the max stream. >- int bitrate_left_bps = max_bitrate_bps - GetTotalMaxBitrateBps(streams); >- if (bitrate_left_bps > 0) { >- streams.back().max_bitrate_bps += bitrate_left_bps; >+ std::vector<webrtc::VideoStream> layers(num_simulcast_layers); >+ >+ // Format width and height has to be divisible by |2 ^ num_simulcast_layers - >+ // 1|. >+ width = NormalizeSimulcastSize(width, num_simulcast_layers); >+ height = NormalizeSimulcastSize(height, num_simulcast_layers); >+ // Add simulcast streams, from highest resolution (|s| = num_simulcast_layers >+ // -1) to lowest resolution at |s| = 0. >+ for (size_t s = num_simulcast_layers - 1;; --s) { >+ layers[s].width = width; >+ layers[s].height = height; >+ // TODO(pbos): Fill actual temporal-layer bitrate thresholds. >+ layers[s].max_qp = max_qp; >+ layers[s].num_temporal_layers = >+ temporal_layers_supported ? DefaultNumberOfTemporalLayers(s) >+ : 0; >+ layers[s].max_bitrate_bps = FindSimulcastMaxBitrateBps(width, height); >+ layers[s].target_bitrate_bps = FindSimulcastTargetBitrateBps(width, height); >+ int num_temporal_layers = DefaultNumberOfTemporalLayers(s); >+ if (s == 0) { >+ // If alternative number temporal layers is selected, adjust the >+ // bitrate of the lowest simulcast stream so that absolute bitrate for >+ // the base temporal layer matches the bitrate for the base temporal >+ // layer with the default 3 simulcast streams. Otherwise we risk a >+ // higher threshold for receiving a feed at all. >+ float rate_factor = 1.0; >+ if (num_temporal_layers == 3) { >+ if (webrtc::field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) { >+ // Shortened pattern increases TL0 bitrate from 40% to 60%. >+ rate_factor = 0.4 / 0.6; >+ } >+ } else { >+ rate_factor = >+ webrtc::SimulcastRateAllocator::GetTemporalRateAllocation(3, 0) / >+ webrtc::SimulcastRateAllocator::GetTemporalRateAllocation( >+ num_temporal_layers, 0); >+ } >+ >+ layers[s].max_bitrate_bps = >+ static_cast<int>(layers[s].max_bitrate_bps * rate_factor); >+ layers[s].target_bitrate_bps = >+ static_cast<int>(layers[s].target_bitrate_bps * rate_factor); > } >- } >- >- // The bitrate priority currently implemented on a per-sender level, so we >- // just set it for the first video stream. >- streams[0].bitrate_priority = bitrate_priority; >- return streams; >-} >- >-static const int kScreenshareMinBitrateKbps = 50; >-static const int kScreenshareMaxBitrateKbps = 6000; >-static const int kScreenshareDefaultTl0BitrateKbps = 200; >-static const int kScreenshareDefaultTl1BitrateKbps = 1000; >- >-static const char* kScreencastLayerFieldTrialName = >- "WebRTC-ScreenshareLayerRates"; >-static const char* kSimulcastScreenshareFieldTrialName = >- "WebRTC-SimulcastScreenshare"; >- >-ScreenshareLayerConfig::ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate) >- : tl0_bitrate_kbps(tl0_bitrate), tl1_bitrate_kbps(tl1_bitrate) { >-} >+ layers[s].min_bitrate_bps = FindSimulcastMinBitrateBps(width, height); >+ layers[s].max_framerate = max_framerate; > >-ScreenshareLayerConfig ScreenshareLayerConfig::GetDefault() { >- std::string group = >- webrtc::field_trial::FindFullName(kScreencastLayerFieldTrialName); >+ width /= 2; >+ height /= 2; > >- ScreenshareLayerConfig config(kScreenshareDefaultTl0BitrateKbps, >- kScreenshareDefaultTl1BitrateKbps); >- if (!group.empty() && !FromFieldTrialGroup(group, &config)) { >- RTC_LOG(LS_WARNING) << "Unable to parse WebRTC-ScreenshareLayerRates" >- " field trial group: '" >- << group << "'."; >+ if (s == 0) { >+ break; >+ } > } >- return config; >+ // Currently the relative bitrate priority of the sender is controlled by >+ // the value of the lowest VideoStream. >+ // TODO(bugs.webrtc.org/8630): The web specification describes being able to >+ // control relative bitrate for each individual simulcast layer, but this >+ // is currently just implemented per rtp sender. >+ layers[0].bitrate_priority = bitrate_priority; >+ return layers; > } > >-bool ScreenshareLayerConfig::FromFieldTrialGroup( >- const std::string& group, >- ScreenshareLayerConfig* config) { >- // Parse field trial group name, containing bitrates for tl0 and tl1. >- int tl0_bitrate; >- int tl1_bitrate; >- if (sscanf(group.c_str(), "%d-%d", &tl0_bitrate, &tl1_bitrate) != 2) { >- return false; >- } >+std::vector<webrtc::VideoStream> GetScreenshareLayers( >+ size_t max_layers, >+ int width, >+ int height, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool temporal_layers_supported) { >+ size_t num_simulcast_layers = >+ std::min<int>(max_layers, kMaxScreenshareSimulcastLayers); >+ >+ std::vector<webrtc::VideoStream> layers(num_simulcast_layers); >+ // For legacy screenshare in conference mode, tl0 and tl1 bitrates are >+ // piggybacked on the VideoCodec struct as target and max bitrates, >+ // respectively. See eg. webrtc::LibvpxVp8Encoder::SetRates(). >+ layers[0].width = width; >+ layers[0].height = height; >+ layers[0].max_qp = max_qp; >+ layers[0].max_framerate = 5; >+ layers[0].min_bitrate_bps = kMinVideoBitrateBps; >+ layers[0].target_bitrate_bps = kScreenshareDefaultTl0BitrateKbps * 1000; >+ layers[0].max_bitrate_bps = kScreenshareDefaultTl1BitrateKbps * 1000; >+ layers[0].num_temporal_layers = temporal_layers_supported ? 2 : 0; >+ >+ // With simulcast enabled, add another spatial layer. This one will have a >+ // more normal layout, with the regular 3 temporal layer pattern and no fps >+ // restrictions. The base simulcast layer will still use legacy setup. >+ if (num_simulcast_layers == kMaxScreenshareSimulcastLayers) { >+ // Add optional upper simulcast layer. >+ const int num_temporal_layers = DefaultNumberOfTemporalLayers(1); >+ int max_bitrate_bps; >+ if (!temporal_layers_supported) { >+ // Set the max bitrate to where the base layer would have been if temporal >+ // layer were enabled. >+ max_bitrate_bps = static_cast<int>( >+ kScreenshareHighStreamMaxBitrateBps * >+ webrtc::SimulcastRateAllocator::GetTemporalRateAllocation( >+ num_temporal_layers, 0)); >+ } else if (DefaultNumberOfTemporalLayers(1) != 3 || >+ webrtc::field_trial::IsEnabled("WebRTC-UseShortVP8TL3Pattern")) { >+ // Experimental temporal layer mode used, use increased max bitrate. >+ max_bitrate_bps = kScreenshareHighStreamMaxBitrateBps; >+ } else { >+ // Keep current bitrates with default 3tl/8 frame settings. >+ // Lowest temporal layers of a 3 layer setup will have 40% of the total >+ // bitrate allocation for that simulcast layer. Make sure the gap between >+ // the target of the lower simulcast layer and first temporal layer of the >+ // higher one is at most 2x the bitrate, so that upswitching is not >+ // hampered by stalled bitrate estimates. >+ max_bitrate_bps = 2 * ((layers[0].target_bitrate_bps * 10) / 4); >+ } > >- // Sanity check. >- if (tl0_bitrate < kScreenshareMinBitrateKbps || >- tl0_bitrate > kScreenshareMaxBitrateKbps || >- tl1_bitrate < kScreenshareMinBitrateKbps || >- tl1_bitrate > kScreenshareMaxBitrateKbps || tl0_bitrate > tl1_bitrate) { >- return false; >+ // Cap max bitrate so it isn't overly high for the given resolution. >+ max_bitrate_bps = std::min<int>(max_bitrate_bps, >+ FindSimulcastMaxBitrateBps(width, height)); >+ layers[1].width = width; >+ layers[1].height = height; >+ layers[1].max_qp = max_qp; >+ layers[1].max_framerate = max_framerate; >+ layers[1].num_temporal_layers = >+ temporal_layers_supported ? DefaultNumberOfTemporalLayers(1) : 0; >+ layers[1].min_bitrate_bps = layers[0].target_bitrate_bps * 2; >+ layers[1].target_bitrate_bps = max_bitrate_bps; >+ layers[1].max_bitrate_bps = max_bitrate_bps; > } > >- config->tl0_bitrate_kbps = tl0_bitrate; >- config->tl1_bitrate_kbps = tl1_bitrate; >- >- return true; >-} >- >-bool UseSimulcastScreenshare() { >- return webrtc::field_trial::IsEnabled(kSimulcastScreenshareFieldTrialName); >+ // The bitrate priority currently implemented on a per-sender level, so we >+ // just set it for the first simulcast layer. >+ layers[0].bitrate_priority = bitrate_priority; >+ return layers; > } > > } // namespace cricket >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.h >index 31fdcae80b5..84583bca36c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast.h >@@ -11,54 +11,52 @@ > #ifndef MEDIA_ENGINE_SIMULCAST_H_ > #define MEDIA_ENGINE_SIMULCAST_H_ > >-#include <string> > #include <vector> > >-#include "call/video_config.h" >-#include "rtc_base/basictypes.h" >+#include "api/video_codecs/video_encoder_config.h" > > namespace cricket { >-struct StreamParams; >- >-// TODO(sprang): Remove this, as we're moving away from temporal layer mode. >-// Config for use with screen cast when temporal layers are enabled. >-struct ScreenshareLayerConfig { >- public: >- ScreenshareLayerConfig(int tl0_bitrate, int tl1_bitrate); >- >- // Bitrates, for temporal layers 0 and 1. >- int tl0_bitrate_kbps; >- int tl1_bitrate_kbps; >- >- static ScreenshareLayerConfig GetDefault(); >- >- // Parse bitrate from group name on format "(tl0_bitrate)-(tl1_bitrate)", >- // eg. "100-1000" for the default rates. >- static bool FromFieldTrialGroup(const std::string& group, >- ScreenshareLayerConfig* config); >-}; >- >-// TODO(pthatcher): Write unit tests just for these functions, >-// independent of WebrtcVideoEngine. > >+// Gets the total maximum bitrate for the |streams|. > int GetTotalMaxBitrateBps(const std::vector<webrtc::VideoStream>& streams); > >-// Get the ssrcs of the SIM group from the stream params. >-void GetSimulcastSsrcs(const StreamParams& sp, std::vector<uint32_t>* ssrcs); >- >-// Get simulcast settings. >-// TODO(sprang): Remove default parameter when it's not longer referenced. >-std::vector<webrtc::VideoStream> GetSimulcastConfig(size_t max_streams, >- int width, >- int height, >- int max_bitrate_bps, >- double bitrate_priority, >- int max_qp, >- int max_framerate, >- bool is_screencast = false); >- >-bool UseSimulcastScreenshare(); >- >+// Adds any bitrate of |max_bitrate_bps| that is above the total maximum bitrate >+// for the |layers| to the highest quality layer. >+void BoostMaxSimulcastLayer(int max_bitrate_bps, >+ std::vector<webrtc::VideoStream>* layers); >+ >+// Gets simulcast settings. >+// TODO(asapersson): Remove max_bitrate_bps. >+std::vector<webrtc::VideoStream> GetSimulcastConfig( >+ size_t max_layers, >+ int width, >+ int height, >+ int /*max_bitrate_bps*/, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool is_screenshare, >+ bool temporal_layers_supported = true); >+ >+// Gets the simulcast config layers for a non-screensharing case. >+std::vector<webrtc::VideoStream> GetNormalSimulcastLayers( >+ size_t max_layers, >+ int width, >+ int height, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool temporal_layers_supported = true); >+ >+// Gets simulcast config layers for screenshare settings. >+std::vector<webrtc::VideoStream> GetScreenshareLayers( >+ size_t max_layers, >+ int width, >+ int height, >+ double bitrate_priority, >+ int max_qp, >+ int max_framerate, >+ bool temporal_layers_supported = true); > } // namespace cricket > > #endif // MEDIA_ENGINE_SIMULCAST_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.cc >index ea54e662938..d58a7a7d2a2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.cc >@@ -12,12 +12,11 @@ > > #include <algorithm> > >- > #include "api/video/i420_buffer.h" >+#include "api/video/video_bitrate_allocation.h" > #include "api/video_codecs/video_encoder_factory.h" > #include "media/engine/scopedvideoencoder.h" >-#include "modules/video_coding/codecs/vp8/screenshare_layers.h" >-#include "modules/video_coding/codecs/vp8/simulcast_rate_allocator.h" >+#include "modules/video_coding/utility/simulcast_rate_allocator.h" > #include "rtc_base/checks.h" > #include "system_wrappers/include/clock.h" > #include "third_party/libyuv/include/libyuv/scale.h" >@@ -76,7 +75,8 @@ int VerifyCodec(const webrtc::VideoCodec* inst) { > if (inst->width <= 1 || inst->height <= 1) { > return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; > } >- if (inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) { >+ if (inst->codecType == webrtc::kVideoCodecVP8 && >+ inst->VP8().automaticResizeOn && inst->numberOfSimulcastStreams > 1) { > return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; > } > return WEBRTC_VIDEO_CODEC_OK; >@@ -103,57 +103,19 @@ class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback { > webrtc::SimulcastEncoderAdapter* const adapter_; > const size_t stream_idx_; > }; >- >-// Utility class used to adapt the simulcast id as reported by the temporal >-// layers factory, since each sub-encoder will report stream 0. >-class TemporalLayersFactoryAdapter : public webrtc::TemporalLayersFactory { >- public: >- TemporalLayersFactoryAdapter(int adapted_simulcast_id, >- const TemporalLayersFactory& tl_factory) >- : adapted_simulcast_id_(adapted_simulcast_id), tl_factory_(tl_factory) {} >- ~TemporalLayersFactoryAdapter() override {} >- webrtc::TemporalLayers* Create(int simulcast_id, >- int temporal_layers, >- uint8_t initial_tl0_pic_idx) const override { >- return tl_factory_.Create(adapted_simulcast_id_, temporal_layers, >- initial_tl0_pic_idx); >- } >- std::unique_ptr<webrtc::TemporalLayersChecker> CreateChecker( >- int simulcast_id, >- int temporal_layers, >- uint8_t initial_tl0_pic_idx) const override { >- return tl_factory_.CreateChecker(adapted_simulcast_id_, temporal_layers, >- initial_tl0_pic_idx); >- } >- >- const int adapted_simulcast_id_; >- const TemporalLayersFactory& tl_factory_; >-}; >- > } // namespace > > namespace webrtc { > >-SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory) >+SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory, >+ const SdpVideoFormat& format) > : inited_(0), > factory_(factory), >- cricket_factory_(nullptr), >+ video_format_(format), > encoded_complete_callback_(nullptr), > implementation_name_("SimulcastEncoderAdapter") { >- // The adapter is typically created on the worker thread, but operated on >- // the encoder task queue. >- encoder_queue_.Detach(); >+ RTC_DCHECK(factory_); > >- memset(&codec_, 0, sizeof(webrtc::VideoCodec)); >-} >- >-SimulcastEncoderAdapter::SimulcastEncoderAdapter( >- cricket::WebRtcVideoEncoderFactory* factory) >- : inited_(0), >- factory_(nullptr), >- cricket_factory_(factory), >- encoded_complete_callback_(nullptr), >- implementation_name_("SimulcastEncoderAdapter") { > // The adapter is typically created on the worker thread, but operated on > // the encoder task queue. > encoder_queue_.Detach(); >@@ -217,8 +179,8 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst, > } > > codec_ = *inst; >- SimulcastRateAllocator rate_allocator(codec_, nullptr); >- BitrateAllocation allocation = rate_allocator.GetAllocation( >+ SimulcastRateAllocator rate_allocator(codec_); >+ VideoBitrateAllocation allocation = rate_allocator.GetAllocation( > codec_.startBitrate * 1000, codec_.maxFramerate); > std::vector<uint32_t> start_bitrates; > for (int i = 0; i < kMaxSimulcastStreams; ++i) { >@@ -243,11 +205,8 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst, > PopulateStreamCodec(codec_, i, start_bitrate_kbps, > highest_resolution_stream, &stream_codec); > } >- TemporalLayersFactoryAdapter tl_factory_adapter(i, >- *codec_.VP8()->tl_factory); >- stream_codec.VP8()->tl_factory = &tl_factory_adapter; > >- // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl. >+ // TODO(ronghuawu): Remove once this is handled in LibvpxVp8Encoder. > if (stream_codec.qpMax < kDefaultMinQp) { > stream_codec.qpMax = kDefaultMaxQp; > } >@@ -260,9 +219,8 @@ int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst, > encoder = std::move(stored_encoders_.top()); > stored_encoders_.pop(); > } else { >- encoder = factory_ ? factory_->CreateVideoEncoder(SdpVideoFormat("VP8")) >- : CreateScopedVideoEncoder(cricket_factory_, >- cricket::VideoCodec("VP8")); >+ encoder = factory_->CreateVideoEncoder(SdpVideoFormat( >+ codec_.codecType == webrtc::kVideoCodecVP8 ? "VP8" : "H264")); > } > > ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size); >@@ -412,8 +370,9 @@ int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss, > return WEBRTC_VIDEO_CODEC_OK; > } > >-int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate, >- uint32_t new_framerate) { >+int SimulcastEncoderAdapter::SetRateAllocation( >+ const VideoBitrateAllocation& bitrate, >+ uint32_t new_framerate) { > RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_); > > if (!Initialized()) { >@@ -455,7 +414,7 @@ int SimulcastEncoderAdapter::SetRateAllocation(const BitrateAllocation& bitrate, > > // Slice the temporal layers out of the full allocation and pass it on to > // the encoder handling the current simulcast stream. >- BitrateAllocation stream_allocation; >+ VideoBitrateAllocation stream_allocation; > for (int i = 0; i < kMaxTemporalStreams; ++i) { > if (bitrate.HasBitrate(stream_idx, i)) { > stream_allocation.SetBitrate(0, i, bitrate.GetBitrate(stream_idx, i)); >@@ -477,8 +436,11 @@ EncodedImageCallback::Result SimulcastEncoderAdapter::OnEncodedImage( > const RTPFragmentationHeader* fragmentation) { > CodecSpecificInfo stream_codec_specific = *codecSpecificInfo; > stream_codec_specific.codec_name = implementation_name_.c_str(); >- CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8); >- vp8Info->simulcastIdx = stream_idx; >+ if (stream_codec_specific.codecType == webrtc::kVideoCodecVP8) { >+ stream_codec_specific.codecSpecific.VP8.simulcastIdx = stream_idx; >+ } else if (stream_codec_specific.codecType == webrtc::kVideoCodecH264) { >+ stream_codec_specific.codecSpecific.H264.simulcast_idx = stream_idx; >+ } > > return encoded_complete_callback_->OnEncodedImage( > encodedImage, &stream_codec_specific, fragmentation); >@@ -493,8 +455,6 @@ void SimulcastEncoderAdapter::PopulateStreamCodec( > *stream_codec = inst; > > // Stream specific settings. >- stream_codec->VP8()->numberOfTemporalLayers = >- inst.simulcastStream[stream_index].numberOfTemporalLayers; > stream_codec->numberOfSimulcastStreams = 0; > stream_codec->width = inst.simulcastStream[stream_index].width; > stream_codec->height = inst.simulcastStream[stream_index].height; >@@ -503,19 +463,24 @@ void SimulcastEncoderAdapter::PopulateStreamCodec( > stream_codec->qpMax = inst.simulcastStream[stream_index].qpMax; > // Settings that are based on stream/resolution. > const bool lowest_resolution_stream = (stream_index == 0); >- if (lowest_resolution_stream) { >+ if (lowest_resolution_stream && inst.mode != VideoCodecMode::kScreensharing) { > // Settings for lowest spatial resolutions. > stream_codec->qpMax = kLowestResMaxQp; > } >- if (!highest_resolution_stream) { >- // For resolutions below CIF, set the codec |complexity| parameter to >- // kComplexityHigher, which maps to cpu_used = -4. >- int pixels_per_frame = stream_codec->width * stream_codec->height; >- if (pixels_per_frame < 352 * 288) { >- stream_codec->VP8()->complexity = webrtc::kComplexityHigher; >+ if (inst.codecType == webrtc::kVideoCodecVP8) { >+ stream_codec->VP8()->numberOfTemporalLayers = >+ inst.simulcastStream[stream_index].numberOfTemporalLayers; >+ if (!highest_resolution_stream) { >+ // For resolutions below CIF, set the codec |complexity| parameter to >+ // kComplexityHigher, which maps to cpu_used = -4. >+ int pixels_per_frame = stream_codec->width * stream_codec->height; >+ if (pixels_per_frame < 352 * 288) { >+ stream_codec->VP8()->complexity = >+ webrtc::VideoCodecComplexity::kComplexityHigher; >+ } >+ // Turn off denoising for all streams but the highest resolution. >+ stream_codec->VP8()->denoisingOn = false; > } >- // Turn off denoising for all streams but the highest resolution. >- stream_codec->VP8()->denoisingOn = false; > } > // TODO(ronghuawu): what to do with targetBitrate. > >@@ -550,7 +515,7 @@ VideoEncoder::ScalingSettings SimulcastEncoderAdapter::GetScalingSettings() > // RTC_DCHECK_CALLED_SEQUENTIALLY(&encoder_queue_); > // Turn off quality scaling for simulcast. > if (!Initialized() || NumberOfStreams(codec_) != 1) { >- return VideoEncoder::ScalingSettings(false); >+ return VideoEncoder::ScalingSettings::kOff; > } > return streaminfos_[0].encoder->GetScalingSettings(); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.h >index 9650cd39a8b..af830d7ab80 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter.h >@@ -19,7 +19,7 @@ > #include <vector> > > #include "media/engine/webrtcvideoencoderfactory.h" >-#include "modules/video_coding/codecs/vp8/include/vp8.h" >+#include "modules/video_coding/include/video_codec_interface.h" > #include "rtc_base/atomicops.h" > #include "rtc_base/sequenced_task_checker.h" > >@@ -32,11 +32,10 @@ class VideoEncoderFactory; > // webrtc::VideoEncoder instances with the given VideoEncoderFactory. > // The object is created and destroyed on the worker thread, but all public > // interfaces should be called from the encoder task queue. >-class SimulcastEncoderAdapter : public VP8Encoder { >+class SimulcastEncoderAdapter : public VideoEncoder { > public: >- explicit SimulcastEncoderAdapter(VideoEncoderFactory* factory); >- // Deprecated - use webrtc::VideoEncoderFactory instead. >- explicit SimulcastEncoderAdapter(cricket::WebRtcVideoEncoderFactory* factory); >+ explicit SimulcastEncoderAdapter(VideoEncoderFactory* factory, >+ const SdpVideoFormat& format); > virtual ~SimulcastEncoderAdapter(); > > // Implements VideoEncoder. >@@ -49,7 +48,7 @@ class SimulcastEncoderAdapter : public VP8Encoder { > const std::vector<FrameType>* frame_types) override; > int RegisterEncodeCompleteCallback(EncodedImageCallback* callback) override; > int SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; >- int SetRateAllocation(const BitrateAllocation& bitrate, >+ int SetRateAllocation(const VideoBitrateAllocation& bitrate, > uint32_t new_framerate) override; > > // Eventual handler for the contained encoders' EncodedImageCallbacks, but >@@ -100,7 +99,7 @@ class SimulcastEncoderAdapter : public VP8Encoder { > > volatile int inited_; // Accessed atomically. > VideoEncoderFactory* const factory_; >- cricket::WebRtcVideoEncoderFactory* const cricket_factory_; >+ const SdpVideoFormat video_format_; > VideoCodec codec_; > std::vector<StreamInfo> streaminfos_; > EncodedImageCallback* encoded_complete_callback_; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter_unittest.cc >index 8087d7be0bb..5f1eebe0d03 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_encoder_adapter_unittest.cc >@@ -12,85 +12,136 @@ > #include <memory> > #include <vector> > >+#include "absl/memory/memory.h" >+#include "api/test/create_simulcast_test_fixture.h" >+#include "api/test/simulcast_test_fixture.h" > #include "api/video_codecs/sdp_video_format.h" > #include "api/video_codecs/video_encoder_factory.h" > #include "common_video/include/video_frame_buffer.h" > #include "media/engine/internalencoderfactory.h" > #include "media/engine/simulcast_encoder_adapter.h" >-#include "modules/video_coding/codecs/vp8/simulcast_test_utility.h" >+#include "modules/video_coding/codecs/vp8/include/vp8.h" > #include "modules/video_coding/include/video_codec_interface.h" >-#include "rtc_base/ptr_util.h" >+#include "modules/video_coding/utility/simulcast_test_fixture_impl.h" >+#include "test/function_video_decoder_factory.h" >+#include "test/function_video_encoder_factory.h" > #include "test/gmock.h" >+#include "test/gtest.h" >+ >+using ::testing::_; >+using ::testing::Return; > > namespace webrtc { >-namespace testing { >+namespace test { > >-class TestSimulcastEncoderAdapter : public TestVp8Simulcast { >- public: >- TestSimulcastEncoderAdapter() : factory_(new InternalEncoderFactory()) {} >+namespace { > >- protected: >- std::unique_ptr<VP8Encoder> CreateEncoder() override { >- return rtc::MakeUnique<SimulcastEncoderAdapter>(factory_.get()); >- } >- std::unique_ptr<VP8Decoder> CreateDecoder() override { >- return VP8Decoder::Create(); >- } >+constexpr int kDefaultWidth = 1280; >+constexpr int kDefaultHeight = 720; > >- private: >- std::unique_ptr<VideoEncoderFactory> factory_; >-}; >+std::unique_ptr<SimulcastTestFixture> CreateSpecificSimulcastTestFixture( >+ VideoEncoderFactory* internal_encoder_factory) { >+ std::unique_ptr<VideoEncoderFactory> encoder_factory = >+ absl::make_unique<FunctionVideoEncoderFactory>( >+ [internal_encoder_factory]() { >+ return absl::make_unique<SimulcastEncoderAdapter>( >+ internal_encoder_factory, >+ SdpVideoFormat(cricket::kVp8CodecName)); >+ }); >+ std::unique_ptr<VideoDecoderFactory> decoder_factory = >+ absl::make_unique<FunctionVideoDecoderFactory>( >+ []() { return VP8Decoder::Create(); }); >+ return CreateSimulcastTestFixture(std::move(encoder_factory), >+ std::move(decoder_factory), >+ SdpVideoFormat(cricket::kVp8CodecName)); >+} >+ >+} // namespace >+ >+TEST(SimulcastEncoderAdapterSimulcastTest, TestKeyFrameRequestsOnAllStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestKeyFrameRequestsOnAllStreams(); >+} > >-TEST_F(TestSimulcastEncoderAdapter, TestKeyFrameRequestsOnAllStreams) { >- TestVp8Simulcast::TestKeyFrameRequestsOnAllStreams(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestPaddingAllStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestPaddingAllStreams(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestPaddingAllStreams) { >- TestVp8Simulcast::TestPaddingAllStreams(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestPaddingTwoStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestPaddingTwoStreams(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreams) { >- TestVp8Simulcast::TestPaddingTwoStreams(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestPaddingTwoStreamsOneMaxedOut) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestPaddingTwoStreamsOneMaxedOut(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestPaddingTwoStreamsOneMaxedOut) { >- TestVp8Simulcast::TestPaddingTwoStreamsOneMaxedOut(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestPaddingOneStream) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestPaddingOneStream(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStream) { >- TestVp8Simulcast::TestPaddingOneStream(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestPaddingOneStreamTwoMaxedOut) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestPaddingOneStreamTwoMaxedOut(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestPaddingOneStreamTwoMaxedOut) { >- TestVp8Simulcast::TestPaddingOneStreamTwoMaxedOut(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestSendAllStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestSendAllStreams(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestSendAllStreams) { >- TestVp8Simulcast::TestSendAllStreams(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestDisablingStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestDisablingStreams(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestDisablingStreams) { >- TestVp8Simulcast::TestDisablingStreams(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestActiveStreams) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestActiveStreams(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneStream) { >- TestVp8Simulcast::TestSwitchingToOneStream(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestSwitchingToOneStream) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestSwitchingToOneStream(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestSwitchingToOneOddStream) { >- TestVp8Simulcast::TestSwitchingToOneOddStream(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestSwitchingToOneOddStream) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestSwitchingToOneOddStream(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestStrideEncodeDecode) { >- TestVp8Simulcast::TestStrideEncodeDecode(); >+TEST(SimulcastEncoderAdapterSimulcastTest, TestStrideEncodeDecode) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestStrideEncodeDecode(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestSaptioTemporalLayers333PatternEncoder) { >- TestVp8Simulcast::TestSaptioTemporalLayers333PatternEncoder(); >+TEST(SimulcastEncoderAdapterSimulcastTest, >+ TestSpatioTemporalLayers333PatternEncoder) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestSpatioTemporalLayers333PatternEncoder(); > } > >-TEST_F(TestSimulcastEncoderAdapter, TestSpatioTemporalLayers321PatternEncoder) { >- TestVp8Simulcast::TestSpatioTemporalLayers321PatternEncoder(); >+TEST(SimulcastEncoderAdapterSimulcastTest, >+ TestSpatioTemporalLayers321PatternEncoder) { >+ InternalEncoderFactory internal_encoder_factory; >+ auto fixture = CreateSpecificSimulcastTestFixture(&internal_encoder_factory); >+ fixture->TestSpatioTemporalLayers321PatternEncoder(); > } > > class MockVideoEncoder; >@@ -119,7 +170,7 @@ class MockVideoEncoderFactory : public VideoEncoderFactory { > class MockVideoEncoder : public VideoEncoder { > public: > explicit MockVideoEncoder(MockVideoEncoderFactory* factory) >- : factory_(factory) {} >+ : factory_(factory), callback_(nullptr) {} > > // TODO(nisse): Valid overrides commented out, because the gmock > // methods don't use any override declarations, and we want to avoid >@@ -146,7 +197,7 @@ class MockVideoEncoder : public VideoEncoder { > > MOCK_METHOD0(Release, int32_t()); > >- int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation, >+ int32_t SetRateAllocation(const VideoBitrateAllocation& bitrate_allocation, > uint32_t framerate) { > last_set_bitrate_ = bitrate_allocation; > return 0; >@@ -169,6 +220,7 @@ class MockVideoEncoder : public VideoEncoder { > image._encodedHeight = height; > CodecSpecificInfo codec_specific_info; > memset(&codec_specific_info, 0, sizeof(codec_specific_info)); >+ codec_specific_info.codecType = webrtc::kVideoCodecVP8; > callback_->OnEncodedImage(image, &codec_specific_info, nullptr); > } > >@@ -180,7 +232,7 @@ class MockVideoEncoder : public VideoEncoder { > init_encode_return_value_ = value; > } > >- BitrateAllocation last_set_bitrate() const { return last_set_bitrate_; } >+ VideoBitrateAllocation last_set_bitrate() const { return last_set_bitrate_; } > > MOCK_CONST_METHOD0(ImplementationName, const char*()); > >@@ -188,7 +240,7 @@ class MockVideoEncoder : public VideoEncoder { > MockVideoEncoderFactory* const factory_; > bool supports_native_handle_ = false; > int32_t init_encode_return_value_ = 0; >- BitrateAllocation last_set_bitrate_; >+ VideoBitrateAllocation last_set_bitrate_; > > VideoCodec codec_; > EncodedImageCallback* callback_; >@@ -246,8 +298,8 @@ class TestSimulcastEncoderAdapterFakeHelper { > > // Can only be called once as the SimulcastEncoderAdapter will take the > // ownership of |factory_|. >- VP8Encoder* CreateMockEncoderAdapter() { >- return new SimulcastEncoderAdapter(factory_.get()); >+ VideoEncoder* CreateMockEncoderAdapter() { >+ return new SimulcastEncoderAdapter(factory_.get(), SdpVideoFormat("VP8")); > } > > void ExpectCallSetChannelParameters(uint32_t packetLoss, int64_t rtt) { >@@ -307,11 +359,10 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > } > > void SetupCodec() { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); >- tl_factory_.SetListener(rate_allocator_.get()); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); > EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); > adapter_->RegisterEncodeCompleteCallback(this); > } >@@ -320,7 +371,6 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > const VideoCodec& target = > helper_->factory()->encoders()[stream_index]->codec(); > EXPECT_EQ(ref.codecType, target.codecType); >- EXPECT_EQ(0, strcmp(ref.plName, target.plName)); > EXPECT_EQ(ref.plType, target.plType); > EXPECT_EQ(ref.width, target.width); > EXPECT_EQ(ref.height, target.height); >@@ -328,14 +378,10 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > EXPECT_EQ(ref.maxBitrate, target.maxBitrate); > EXPECT_EQ(ref.minBitrate, target.minBitrate); > EXPECT_EQ(ref.maxFramerate, target.maxFramerate); >- EXPECT_EQ(ref.VP8().pictureLossIndicationOn, >- target.VP8().pictureLossIndicationOn); > EXPECT_EQ(ref.VP8().complexity, target.VP8().complexity); >- EXPECT_EQ(ref.VP8().resilience, target.VP8().resilience); > EXPECT_EQ(ref.VP8().numberOfTemporalLayers, > target.VP8().numberOfTemporalLayers); > EXPECT_EQ(ref.VP8().denoisingOn, target.VP8().denoisingOn); >- EXPECT_EQ(ref.VP8().errorConcealmentOn, target.VP8().errorConcealmentOn); > EXPECT_EQ(ref.VP8().automaticResizeOn, target.VP8().automaticResizeOn); > EXPECT_EQ(ref.VP8().frameDroppingOn, target.VP8().frameDroppingOn); > EXPECT_EQ(ref.VP8().keyFrameInterval, target.VP8().keyFrameInterval); >@@ -351,7 +397,6 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > *ref_codec = codec_; > ref_codec->VP8()->numberOfTemporalLayers = > kTestTemporalLayerProfile[stream_index]; >- ref_codec->VP8()->tl_factory = &tl_factory_; > ref_codec->width = codec_.simulcastStream[stream_index].width; > ref_codec->height = codec_.simulcastStream[stream_index].height; > ref_codec->maxBitrate = codec_.simulcastStream[stream_index].maxBitrate; >@@ -366,7 +411,8 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > // stream 0, the lowest resolution stream. > InitRefCodec(0, &ref_codec); > ref_codec.qpMax = 45; >- ref_codec.VP8()->complexity = webrtc::kComplexityHigher; >+ ref_codec.VP8()->complexity = >+ webrtc::VideoCodecComplexity::kComplexityHigher; > ref_codec.VP8()->denoisingOn = false; > ref_codec.startBitrate = 100; // Should equal to the target bitrate. > VerifyCodec(ref_codec, 0); >@@ -390,12 +436,11 @@ class TestSimulcastEncoderAdapterFake : public ::testing::Test, > > protected: > std::unique_ptr<TestSimulcastEncoderAdapterFakeHelper> helper_; >- std::unique_ptr<VP8Encoder> adapter_; >+ std::unique_ptr<VideoEncoder> adapter_; > VideoCodec codec_; > int last_encoded_image_width_; > int last_encoded_image_height_; > int last_encoded_image_simulcast_index_; >- TemporalLayersFactory tl_factory_; > std::unique_ptr<SimulcastRateAllocator> rate_allocator_; > }; > >@@ -464,11 +509,10 @@ TEST_F(TestSimulcastEncoderAdapterFake, EncodedCallbackForDifferentEncoders) { > // with the lowest stream. > TEST_F(TestSimulcastEncoderAdapterFake, ReusesEncodersInOrder) { > // Set up common settings for three streams. >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); >- tl_factory_.SetListener(rate_allocator_.get()); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); > adapter_->RegisterEncodeCompleteCallback(this); > > // Input data. >@@ -664,9 +708,9 @@ TEST_F(TestSimulcastEncoderAdapterFake, ReinitDoesNotReorderFrameSimulcastIdx) { > } > > TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.numberOfSimulcastStreams = 1; > EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); > adapter_->RegisterEncodeCompleteCallback(this); >@@ -678,39 +722,39 @@ TEST_F(TestSimulcastEncoderAdapterFake, SupportsNativeHandleForSingleStreams) { > } > > TEST_F(TestSimulcastEncoderAdapterFake, SetRatesUnderMinBitrate) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.minBitrate = 50; > codec_.numberOfSimulcastStreams = 1; > EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); >- rate_allocator_.reset(new SimulcastRateAllocator(codec_, nullptr)); >+ rate_allocator_.reset(new SimulcastRateAllocator(codec_)); > > // Above min should be respected. >- BitrateAllocation target_bitrate = >+ VideoBitrateAllocation target_bitrate = > rate_allocator_->GetAllocation(codec_.minBitrate * 1000, 30); > adapter_->SetRateAllocation(target_bitrate, 30); > EXPECT_EQ(target_bitrate, > helper_->factory()->encoders()[0]->last_set_bitrate()); > > // Below min but non-zero should be replaced with the min bitrate. >- BitrateAllocation too_low_bitrate = >+ VideoBitrateAllocation too_low_bitrate = > rate_allocator_->GetAllocation((codec_.minBitrate - 1) * 1000, 30); > adapter_->SetRateAllocation(too_low_bitrate, 30); > EXPECT_EQ(target_bitrate, > helper_->factory()->encoders()[0]->last_set_bitrate()); > > // Zero should be passed on as is, since it means "pause". >- adapter_->SetRateAllocation(BitrateAllocation(), 30); >- EXPECT_EQ(BitrateAllocation(), >+ adapter_->SetRateAllocation(VideoBitrateAllocation(), 30); >+ EXPECT_EQ(VideoBitrateAllocation(), > helper_->factory()->encoders()[0]->last_set_bitrate()); > } > > TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) { > EXPECT_STREQ("SimulcastEncoderAdapter", adapter_->ImplementationName()); >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > std::vector<const char*> encoder_names; > encoder_names.push_back("codec1"); > encoder_names.push_back("codec2"); >@@ -731,9 +775,9 @@ TEST_F(TestSimulcastEncoderAdapterFake, SupportsImplementationName) { > > TEST_F(TestSimulcastEncoderAdapterFake, > SupportsNativeHandleForMultipleStreams) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.numberOfSimulcastStreams = 3; > EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); > adapter_->RegisterEncodeCompleteCallback(this); >@@ -749,9 +793,10 @@ TEST_F(TestSimulcastEncoderAdapterFake, > } > > // TODO(nisse): Reuse definition in webrtc/test/fake_texture_handle.h. >-class FakeNativeBuffer : public VideoFrameBuffer { >+class FakeNativeBufferNoI420 : public VideoFrameBuffer { > public: >- FakeNativeBuffer(int width, int height) : width_(width), height_(height) {} >+ FakeNativeBufferNoI420(int width, int height) >+ : width_(width), height_(height) {} > > Type type() const override { return Type::kNative; } > int width() const override { return width_; } >@@ -769,9 +814,9 @@ class FakeNativeBuffer : public VideoFrameBuffer { > > TEST_F(TestSimulcastEncoderAdapterFake, > NativeHandleForwardingForMultipleStreams) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.numberOfSimulcastStreams = 3; > // High start bitrate, so all streams are enabled. > codec_.startBitrate = 3000; >@@ -783,7 +828,7 @@ TEST_F(TestSimulcastEncoderAdapterFake, > EXPECT_TRUE(adapter_->SupportsNativeHandle()); > > rtc::scoped_refptr<VideoFrameBuffer> buffer( >- new rtc::RefCountedObject<FakeNativeBuffer>(1280, 720)); >+ new rtc::RefCountedObject<FakeNativeBufferNoI420>(1280, 720)); > VideoFrame input_frame(buffer, 100, 1000, kVideoRotation_180); > // Expect calls with the given video frame verbatim, since it's a texture > // frame and can't otherwise be modified/resized. >@@ -794,9 +839,9 @@ TEST_F(TestSimulcastEncoderAdapterFake, > } > > TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.numberOfSimulcastStreams = 3; > EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); > adapter_->RegisterEncodeCompleteCallback(this); >@@ -816,9 +861,9 @@ TEST_F(TestSimulcastEncoderAdapterFake, TestFailureReturnCodesFromEncodeCalls) { > } > > TEST_F(TestSimulcastEncoderAdapterFake, TestInitFailureCleansUpEncoders) { >- TestVp8Simulcast::DefaultSettings( >- &codec_, static_cast<const int*>(kTestTemporalLayerProfile)); >- codec_.VP8()->tl_factory = &tl_factory_; >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); > codec_.numberOfSimulcastStreams = 3; > helper_->factory()->set_init_encode_return_value( > WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE); >@@ -827,5 +872,36 @@ TEST_F(TestSimulcastEncoderAdapterFake, TestInitFailureCleansUpEncoders) { > EXPECT_TRUE(helper_->factory()->encoders().empty()); > } > >-} // namespace testing >+TEST_F(TestSimulcastEncoderAdapterFake, DoesNotAlterMaxQpForScreenshare) { >+ const int kHighMaxQp = 56; >+ const int kLowMaxQp = 46; >+ >+ SimulcastTestFixtureImpl::DefaultSettings( >+ &codec_, static_cast<const int*>(kTestTemporalLayerProfile), >+ kVideoCodecVP8); >+ codec_.numberOfSimulcastStreams = 3; >+ codec_.simulcastStream[0].qpMax = kHighMaxQp; >+ codec_.mode = VideoCodecMode::kScreensharing; >+ >+ EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); >+ EXPECT_EQ(3u, helper_->factory()->encoders().size()); >+ >+ // Just check the lowest stream, which is the one that where the adapter >+ // might alter the max qp setting. >+ VideoCodec ref_codec; >+ InitRefCodec(0, &ref_codec); >+ ref_codec.qpMax = kHighMaxQp; >+ ref_codec.VP8()->complexity = webrtc::VideoCodecComplexity::kComplexityHigher; >+ ref_codec.VP8()->denoisingOn = false; >+ ref_codec.startBitrate = 100; // Should equal to the target bitrate. >+ VerifyCodec(ref_codec, 0); >+ >+ // Change the max qp and try again. >+ codec_.simulcastStream[0].qpMax = kLowMaxQp; >+ EXPECT_EQ(0, adapter_->InitEncode(&codec_, 1, 1200)); >+ EXPECT_EQ(3u, helper_->factory()->encoders().size()); >+ ref_codec.qpMax = kLowMaxQp; >+ VerifyCodec(ref_codec, 0); >+} >+} // namespace test > } // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_unittest.cc >index 1433c5c335d..29226d12114 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/simulcast_unittest.cc >@@ -1,5 +1,5 @@ > /* >- * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. >+ * Copyright 2018 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 >@@ -8,49 +8,159 @@ > * be found in the AUTHORS file in the root of the source tree. > */ > >-#include <string> >- > #include "media/engine/simulcast.h" >+ >+#include "media/engine/constants.h" >+#include "test/field_trial.h" > #include "test/gtest.h" > >-namespace cricket { >+namespace webrtc { >+namespace { >+constexpr int kQpMax = 55; >+constexpr double kBitratePriority = 2.0; >+constexpr int kMaxFps = 33; >+constexpr int kMaxBitrateBps = 0; >+constexpr bool kScreenshare = true; >+constexpr int kDefaultTemporalLayers = 3; // Value from simulcast.cc. >+ >+// Values from kSimulcastConfigs in simulcast.cc. >+const std::vector<VideoStream> GetSimulcastBitrates720p() { >+ std::vector<VideoStream> streams(3); >+ streams[0].min_bitrate_bps = 30000; >+ streams[0].target_bitrate_bps = 150000; >+ streams[0].max_bitrate_bps = 200000; >+ streams[1].min_bitrate_bps = 150000; >+ streams[1].target_bitrate_bps = 500000; >+ streams[1].max_bitrate_bps = 700000; >+ streams[2].min_bitrate_bps = 600000; >+ streams[2].target_bitrate_bps = 2500000; >+ streams[2].max_bitrate_bps = 2500000; >+ return streams; >+} >+} // namespace >+ >+TEST(SimulcastTest, TotalMaxBitrateIsZeroForNoStreams) { >+ std::vector<VideoStream> streams; >+ EXPECT_EQ(0, cricket::GetTotalMaxBitrateBps(streams)); >+} >+ >+TEST(SimulcastTest, GetTotalMaxBitrateForSingleStream) { >+ std::vector<VideoStream> streams(1); >+ streams[0].max_bitrate_bps = 100000; >+ EXPECT_EQ(100000, cricket::GetTotalMaxBitrateBps(streams)); >+} >+ >+TEST(SimulcastTest, GetTotalMaxBitrateForMultipleStreams) { >+ std::vector<VideoStream> streams(3); >+ streams[0].target_bitrate_bps = 100000; >+ streams[1].target_bitrate_bps = 200000; >+ streams[2].max_bitrate_bps = 400000; >+ EXPECT_EQ(700000, cricket::GetTotalMaxBitrateBps(streams)); >+} >+ >+TEST(SimulcastTest, BandwidthAboveTotalMaxBitrateGivenToHighestStream) { >+ std::vector<VideoStream> streams(3); >+ streams[0].target_bitrate_bps = 100000; >+ streams[1].target_bitrate_bps = 200000; >+ streams[2].max_bitrate_bps = 400000; >+ >+ // No bitrate above the total max to give to the highest stream. >+ const int kMaxTotalBps = cricket::GetTotalMaxBitrateBps(streams); >+ cricket::BoostMaxSimulcastLayer(kMaxTotalBps, &streams); >+ EXPECT_EQ(400000, streams[2].max_bitrate_bps); >+ EXPECT_EQ(kMaxTotalBps, cricket::GetTotalMaxBitrateBps(streams)); > >-class ScreenshareLayerConfigTest : public testing::Test, >- protected ScreenshareLayerConfig { >- public: >- ScreenshareLayerConfigTest() : ScreenshareLayerConfig(0, 0) {} >+ // The bitrate above the total max should be given to the highest stream. >+ cricket::BoostMaxSimulcastLayer(kMaxTotalBps + 1, &streams); >+ EXPECT_EQ(400000 + 1, streams[2].max_bitrate_bps); >+ EXPECT_EQ(kMaxTotalBps + 1, cricket::GetTotalMaxBitrateBps(streams)); >+} >+ >+TEST(SimulcastTest, GetConfig) { >+ const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p(); >+ >+ const size_t kMaxLayers = 3; >+ std::vector<VideoStream> streams = cricket::GetSimulcastConfig( >+ kMaxLayers, 1280, 720, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, >+ !kScreenshare); > >- void ExpectParsingFails(const std::string& group) { >- ScreenshareLayerConfig config(100, 1000); >- EXPECT_FALSE(FromFieldTrialGroup(group, &config)); >+ EXPECT_EQ(kMaxLayers, streams.size()); >+ EXPECT_EQ(320u, streams[0].width); >+ EXPECT_EQ(180u, streams[0].height); >+ EXPECT_EQ(640u, streams[1].width); >+ EXPECT_EQ(360u, streams[1].height); >+ EXPECT_EQ(1280u, streams[2].width); >+ EXPECT_EQ(720u, streams[2].height); >+ >+ for (size_t i = 0; i < streams.size(); ++i) { >+ EXPECT_EQ(size_t{kDefaultTemporalLayers}, streams[i].num_temporal_layers); >+ EXPECT_EQ(kMaxFps, streams[i].max_framerate); >+ EXPECT_EQ(kQpMax, streams[i].max_qp); >+ EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps); >+ EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps); >+ EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps); >+ EXPECT_TRUE(streams[i].active); > } >-}; >+ // Currently set on lowest stream. >+ EXPECT_EQ(kBitratePriority, streams[0].bitrate_priority); >+ EXPECT_FALSE(streams[1].bitrate_priority); >+ EXPECT_FALSE(streams[2].bitrate_priority); >+} >+ >+TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) { >+ const size_t kMaxLayers = 2; >+ std::vector<VideoStream> streams = cricket::GetSimulcastConfig( >+ kMaxLayers, 1280, 720, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, >+ !kScreenshare); > >-TEST_F(ScreenshareLayerConfigTest, UsesDefaultBitrateConfigForDefaultGroup) { >- ExpectParsingFails(""); >+ EXPECT_EQ(kMaxLayers, streams.size()); >+ EXPECT_EQ(320u, streams[0].width); >+ EXPECT_EQ(180u, streams[0].height); >+ EXPECT_EQ(640u, streams[1].width); >+ EXPECT_EQ(360u, streams[1].height); > } > >-TEST_F(ScreenshareLayerConfigTest, UsesDefaultConfigForInvalidBitrates) { >- ExpectParsingFails("-"); >- ExpectParsingFails("1-"); >- ExpectParsingFails("-1"); >- ExpectParsingFails("-12"); >- ExpectParsingFails("12-"); >- ExpectParsingFails("booh!"); >- ExpectParsingFails("1-b"); >- ExpectParsingFails("a-2"); >- ExpectParsingFails("49-1000"); >- ExpectParsingFails("50-6001"); >- ExpectParsingFails("100-99"); >- ExpectParsingFails("1002003004005006-99"); >- ExpectParsingFails("99-1002003004005006"); >+TEST(SimulcastTest, GetConfigWithNormalizedResolution) { >+ const size_t kMaxLayers = 2; >+ std::vector<VideoStream> streams = cricket::GetSimulcastConfig( >+ kMaxLayers, 640 + 1, 360 + 1, kMaxBitrateBps, kBitratePriority, kQpMax, >+ kMaxFps, !kScreenshare); >+ >+ // Must be dividable by |2 ^ (num_layers - 1)|. >+ EXPECT_EQ(kMaxLayers, streams.size()); >+ EXPECT_EQ(320u, streams[0].width); >+ EXPECT_EQ(180u, streams[0].height); >+ EXPECT_EQ(640u, streams[1].width); >+ EXPECT_EQ(360u, streams[1].height); >+} >+ >+TEST(SimulcastTest, GetConfigForScreenshareSimulcast) { >+ const size_t kMaxLayers = 3; >+ std::vector<VideoStream> streams = cricket::GetSimulcastConfig( >+ kMaxLayers, 1400, 800, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, >+ kScreenshare); >+ >+ EXPECT_GT(streams.size(), 1u); >+ for (size_t i = 0; i < streams.size(); ++i) { >+ EXPECT_EQ(1400u, streams[i].width) << "Screen content never scaled."; >+ EXPECT_EQ(800u, streams[i].height) << "Screen content never scaled."; >+ EXPECT_EQ(kQpMax, streams[i].max_qp); >+ EXPECT_TRUE(streams[i].active); >+ EXPECT_GT(streams[i].num_temporal_layers, size_t{1}); >+ EXPECT_GT(streams[i].max_framerate, 0); >+ EXPECT_GT(streams[i].min_bitrate_bps, 0); >+ EXPECT_GT(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps); >+ EXPECT_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps); >+ } > } > >-TEST_F(ScreenshareLayerConfigTest, ParsesValidBitrateConfig) { >- ScreenshareLayerConfig config(100, 1000); >- EXPECT_TRUE(ScreenshareLayerConfig::FromFieldTrialGroup("101-1001", &config)); >- EXPECT_EQ(101, config.tl0_bitrate_kbps); >- EXPECT_EQ(1001, config.tl1_bitrate_kbps); >+TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) { >+ const size_t kMaxLayers = 1; >+ std::vector<VideoStream> streams = cricket::GetSimulcastConfig( >+ kMaxLayers, 1400, 800, kMaxBitrateBps, kBitratePriority, kQpMax, kMaxFps, >+ kScreenshare); >+ >+ EXPECT_EQ(kMaxLayers, streams.size()); > } > >-} // namespace cricket >+} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.cc >deleted file mode 100644 >index 5ffb0c406dd..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.cc >+++ /dev/null >@@ -1,111 +0,0 @@ >-/* >- * Copyright (c) 2017 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 "media/engine/stereocodecfactory.h" >- >-#include <utility> >- >-#include "api/video_codecs/sdp_video_format.h" >-#include "media/base/codec.h" >-#include "media/base/mediaconstants.h" >-#include "modules/video_coding/codecs/stereo/include/stereo_decoder_adapter.h" >-#include "modules/video_coding/codecs/stereo/include/stereo_encoder_adapter.h" >-#include "rtc_base/logging.h" >- >-namespace { >- >-bool IsStereoCodec(const cricket::VideoCodec& codec) { >- return cricket::CodecNamesEq(codec.name.c_str(), cricket::kStereoCodecName); >-} >- >-} // anonymous namespace >- >-namespace webrtc { >- >-constexpr const char* kStereoAssociatedCodecName = cricket::kVp9CodecName; >- >-StereoEncoderFactory::StereoEncoderFactory( >- std::unique_ptr<VideoEncoderFactory> factory) >- : factory_(std::move(factory)) {} >- >-std::vector<SdpVideoFormat> StereoEncoderFactory::GetSupportedFormats() const { >- std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats(); >- for (const auto& format : formats) { >- if (cricket::CodecNamesEq(format.name, kStereoAssociatedCodecName)) { >- SdpVideoFormat stereo_format = format; >- stereo_format.parameters[cricket::kCodecParamAssociatedCodecName] = >- format.name; >- stereo_format.name = cricket::kStereoCodecName; >- formats.push_back(stereo_format); >- break; >- } >- } >- return formats; >-} >- >-VideoEncoderFactory::CodecInfo StereoEncoderFactory::QueryVideoEncoder( >- const SdpVideoFormat& format) const { >- if (!IsStereoCodec(cricket::VideoCodec(format))) >- return factory_->QueryVideoEncoder(format); >- return factory_->QueryVideoEncoder( >- SdpVideoFormat(kStereoAssociatedCodecName)); >-} >- >-std::unique_ptr<VideoEncoder> StereoEncoderFactory::CreateVideoEncoder( >- const SdpVideoFormat& format) { >- if (!IsStereoCodec(cricket::VideoCodec(format))) >- return factory_->CreateVideoEncoder(format); >- const auto& it = >- format.parameters.find(cricket::kCodecParamAssociatedCodecName); >- if (it == format.parameters.end()) { >- RTC_LOG(LS_ERROR) << "No assicated codec for stereo."; >- return nullptr; >- } >- SdpVideoFormat associated_format = format; >- associated_format.name = it->second; >- return std::unique_ptr<VideoEncoder>( >- new StereoEncoderAdapter(factory_.get(), associated_format)); >-} >- >-StereoDecoderFactory::StereoDecoderFactory( >- std::unique_ptr<VideoDecoderFactory> factory) >- : factory_(std::move(factory)) {} >- >-std::vector<SdpVideoFormat> StereoDecoderFactory::GetSupportedFormats() const { >- std::vector<SdpVideoFormat> formats = factory_->GetSupportedFormats(); >- for (const auto& format : formats) { >- if (cricket::CodecNamesEq(format.name, kStereoAssociatedCodecName)) { >- SdpVideoFormat stereo_format = format; >- stereo_format.parameters[cricket::kCodecParamAssociatedCodecName] = >- format.name; >- stereo_format.name = cricket::kStereoCodecName; >- formats.push_back(stereo_format); >- } >- } >- return formats; >-} >- >-std::unique_ptr<VideoDecoder> StereoDecoderFactory::CreateVideoDecoder( >- const SdpVideoFormat& format) { >- if (!IsStereoCodec(cricket::VideoCodec(format))) >- return factory_->CreateVideoDecoder(format); >- const auto& it = >- format.parameters.find(cricket::kCodecParamAssociatedCodecName); >- if (it == format.parameters.end()) { >- RTC_LOG(LS_ERROR) << "No assicated codec for stereo."; >- return nullptr; >- } >- SdpVideoFormat associated_format = format; >- associated_format.name = it->second; >- return std::unique_ptr<VideoDecoder>( >- new StereoDecoderAdapter(factory_.get(), associated_format)); >-} >- >-} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.h >deleted file mode 100644 >index 468d2faf0b6..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/stereocodecfactory.h >+++ /dev/null >@@ -1,49 +0,0 @@ >-/* >- * Copyright (c) 2017 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. >- */ >- >-#ifndef MEDIA_ENGINE_STEREOCODECFACTORY_H_ >-#define MEDIA_ENGINE_STEREOCODECFACTORY_H_ >- >-#include <memory> >-#include <vector> >- >-#include "api/video_codecs/video_decoder_factory.h" >-#include "api/video_codecs/video_encoder_factory.h" >- >-namespace webrtc { >- >-class StereoEncoderFactory : public VideoEncoderFactory { >- public: >- explicit StereoEncoderFactory(std::unique_ptr<VideoEncoderFactory> factory); >- >- std::vector<SdpVideoFormat> GetSupportedFormats() const override; >- CodecInfo QueryVideoEncoder(const SdpVideoFormat& format) const override; >- std::unique_ptr<VideoEncoder> CreateVideoEncoder( >- const SdpVideoFormat& format) override; >- >- private: >- std::unique_ptr<VideoEncoderFactory> factory_; >-}; >- >-class StereoDecoderFactory : public VideoDecoderFactory { >- public: >- explicit StereoDecoderFactory(std::unique_ptr<VideoDecoderFactory> factory); >- >- std::vector<SdpVideoFormat> GetSupportedFormats() const override; >- std::unique_ptr<VideoDecoder> CreateVideoDecoder( >- const SdpVideoFormat& format) override; >- >- private: >- std::unique_ptr<VideoDecoderFactory> factory_; >-}; >- >-} // namespace webrtc >- >-#endif // MEDIA_ENGINE_STEREOCODECFACTORY_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc >deleted file mode 100644 >index 87fb62239a2..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.cc >+++ /dev/null >@@ -1,141 +0,0 @@ >-/* >- * Copyright (c) 2016 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 "media/engine/videodecodersoftwarefallbackwrapper.h" >- >-#include <string> >-#include <utility> >- >-#include "media/engine/internaldecoderfactory.h" >-#include "modules/video_coding/include/video_error_codes.h" >-#include "rtc_base/checks.h" >-#include "rtc_base/logging.h" >-#include "rtc_base/trace_event.h" >- >-namespace webrtc { >- >-VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper( >- std::unique_ptr<VideoDecoder> sw_fallback_decoder, >- std::unique_ptr<VideoDecoder> hw_decoder) >- : use_hw_decoder_(true), >- hw_decoder_(std::move(hw_decoder)), >- hw_decoder_initialized_(false), >- fallback_decoder_(std::move(sw_fallback_decoder)), >- fallback_implementation_name_( >- std::string(fallback_decoder_->ImplementationName()) + >- " (fallback from: " + hw_decoder_->ImplementationName() + ")"), >- callback_(nullptr) {} >- >-int32_t VideoDecoderSoftwareFallbackWrapper::InitDecode( >- const VideoCodec* codec_settings, >- int32_t number_of_cores) { >- // Always try to use the HW decoder in this state. >- use_hw_decoder_ = true; >- codec_settings_ = *codec_settings; >- number_of_cores_ = number_of_cores; >- int32_t ret = hw_decoder_->InitDecode(codec_settings, number_of_cores); >- if (ret == WEBRTC_VIDEO_CODEC_OK) { >- hw_decoder_initialized_ = true; >- return ret; >- } >- hw_decoder_initialized_ = false; >- >- // Try to initialize fallback decoder. >- if (InitFallbackDecoder()) >- return WEBRTC_VIDEO_CODEC_OK; >- >- return ret; >-} >- >-bool VideoDecoderSoftwareFallbackWrapper::InitFallbackDecoder() { >- RTC_LOG(LS_WARNING) << "Decoder falling back to software decoding."; >- if (fallback_decoder_->InitDecode(&codec_settings_, number_of_cores_) != >- WEBRTC_VIDEO_CODEC_OK) { >- RTC_LOG(LS_ERROR) << "Failed to initialize software-decoder fallback."; >- use_hw_decoder_ = true; >- return false; >- } >- if (callback_) >- fallback_decoder_->RegisterDecodeCompleteCallback(callback_); >- use_hw_decoder_ = false; >- return true; >-} >- >-int32_t VideoDecoderSoftwareFallbackWrapper::Decode( >- const EncodedImage& input_image, >- bool missing_frames, >- const RTPFragmentationHeader* fragmentation, >- const CodecSpecificInfo* codec_specific_info, >- int64_t render_time_ms) { >- TRACE_EVENT0("webrtc", "VideoDecoderSoftwareFallbackWrapper::Decode"); >- // Try initializing and decoding with the provided decoder on every keyframe >- // or when there's no fallback decoder. This is the normal case. >- if (use_hw_decoder_ || input_image._frameType == kVideoFrameKey) { >- int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE; >- // Try reinitializing the decoder if it had failed before. >- if (!hw_decoder_initialized_) { >- hw_decoder_initialized_ = >- hw_decoder_->InitDecode(&codec_settings_, number_of_cores_) == >- WEBRTC_VIDEO_CODEC_OK; >- } >- if (hw_decoder_initialized_) { >- ret = hw_decoder_->Decode(input_image, missing_frames, fragmentation, >- codec_specific_info, render_time_ms); >- } >- if (ret == WEBRTC_VIDEO_CODEC_OK) { >- if (!use_hw_decoder_) { >- // Decode OK -> stop using fallback decoder. >- RTC_LOG(LS_WARNING) >- << "Decode OK, no longer using the software fallback decoder."; >- use_hw_decoder_ = true; >- return WEBRTC_VIDEO_CODEC_OK; >- } >- } >- if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) >- return ret; >- if (use_hw_decoder_) { >- // Try to initialize fallback decoder. >- if (!InitFallbackDecoder()) >- return ret; >- } >- } >- return fallback_decoder_->Decode(input_image, missing_frames, fragmentation, >- codec_specific_info, render_time_ms); >-} >- >-int32_t VideoDecoderSoftwareFallbackWrapper::RegisterDecodeCompleteCallback( >- DecodedImageCallback* callback) { >- callback_ = callback; >- int32_t ret = hw_decoder_->RegisterDecodeCompleteCallback(callback); >- if (!use_hw_decoder_) >- return fallback_decoder_->RegisterDecodeCompleteCallback(callback); >- return ret; >-} >- >-int32_t VideoDecoderSoftwareFallbackWrapper::Release() { >- if (!use_hw_decoder_) { >- RTC_LOG(LS_INFO) << "Releasing software fallback decoder."; >- fallback_decoder_->Release(); >- } >- hw_decoder_initialized_ = false; >- return hw_decoder_->Release(); >-} >- >-bool VideoDecoderSoftwareFallbackWrapper::PrefersLateDecoding() const { >- return use_hw_decoder_ ? hw_decoder_->PrefersLateDecoding() >- : fallback_decoder_->PrefersLateDecoding(); >-} >- >-const char* VideoDecoderSoftwareFallbackWrapper::ImplementationName() const { >- return use_hw_decoder_ ? hw_decoder_->ImplementationName() >- : fallback_implementation_name_.c_str(); >-} >- >-} // namespace webrtc >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h >deleted file mode 100644 >index 97953ddc826..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videodecodersoftwarefallbackwrapper.h >+++ /dev/null >@@ -1,64 +0,0 @@ >-/* >- * Copyright (c) 2016 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. >- */ >- >-#ifndef MEDIA_ENGINE_VIDEODECODERSOFTWAREFALLBACKWRAPPER_H_ >-#define MEDIA_ENGINE_VIDEODECODERSOFTWAREFALLBACKWRAPPER_H_ >- >-#include <memory> >-#include <string> >- >-#include "api/video_codecs/video_decoder.h" >- >-namespace webrtc { >- >-// Class used to wrap external VideoDecoders to provide a fallback option on >-// software decoding when a hardware decoder fails to decode a stream due to >-// hardware restrictions, such as max resolution. >-class VideoDecoderSoftwareFallbackWrapper : public VideoDecoder { >- public: >- VideoDecoderSoftwareFallbackWrapper( >- std::unique_ptr<VideoDecoder> sw_fallback_decoder, >- std::unique_ptr<VideoDecoder> hw_decoder); >- >- int32_t InitDecode(const VideoCodec* codec_settings, >- int32_t number_of_cores) override; >- >- int32_t Decode(const EncodedImage& input_image, >- bool missing_frames, >- const RTPFragmentationHeader* fragmentation, >- const CodecSpecificInfo* codec_specific_info, >- int64_t render_time_ms) override; >- >- int32_t RegisterDecodeCompleteCallback( >- DecodedImageCallback* callback) override; >- >- int32_t Release() override; >- bool PrefersLateDecoding() const override; >- >- const char* ImplementationName() const override; >- >- private: >- bool InitFallbackDecoder(); >- >- // Determines if we are trying to use the HW or SW decoder. >- bool use_hw_decoder_; >- std::unique_ptr<VideoDecoder> hw_decoder_; >- bool hw_decoder_initialized_; >- >- VideoCodec codec_settings_; >- int32_t number_of_cores_; >- const std::unique_ptr<VideoDecoder> fallback_decoder_; >- const std::string fallback_implementation_name_; >- DecodedImageCallback* callback_; >-}; >- >-} // namespace webrtc >- >-#endif // MEDIA_ENGINE_VIDEODECODERSOFTWAREFALLBACKWRAPPER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h >deleted file mode 100644 >index a9a349c221f..00000000000 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/videoencodersoftwarefallbackwrapper.h >+++ /dev/null >@@ -1,102 +0,0 @@ >-/* >- * Copyright (c) 2016 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. >- */ >- >-#ifndef MEDIA_ENGINE_VIDEOENCODERSOFTWAREFALLBACKWRAPPER_H_ >-#define MEDIA_ENGINE_VIDEOENCODERSOFTWAREFALLBACKWRAPPER_H_ >- >-#include <memory> >-#include <string> >-#include <vector> >- >-#include "api/video_codecs/video_encoder.h" >-#include "media/base/codec.h" >- >-namespace webrtc { >- >-// Class used to wrap external VideoEncoders to provide a fallback option on >-// software encoding when a hardware encoder fails to encode a stream due to >-// hardware restrictions, such as max resolution. >-class VideoEncoderSoftwareFallbackWrapper : public VideoEncoder { >- public: >- VideoEncoderSoftwareFallbackWrapper( >- std::unique_ptr<webrtc::VideoEncoder> sw_encoder, >- std::unique_ptr<webrtc::VideoEncoder> hw_encoder); >- >- int32_t InitEncode(const VideoCodec* codec_settings, >- int32_t number_of_cores, >- size_t max_payload_size) override; >- >- int32_t RegisterEncodeCompleteCallback( >- EncodedImageCallback* callback) override; >- >- int32_t Release() override; >- int32_t Encode(const VideoFrame& frame, >- const CodecSpecificInfo* codec_specific_info, >- const std::vector<FrameType>* frame_types) override; >- int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; >- int32_t SetRateAllocation(const BitrateAllocation& bitrate_allocation, >- uint32_t framerate) override; >- bool SupportsNativeHandle() const override; >- ScalingSettings GetScalingSettings() const override; >- const char *ImplementationName() const override; >- >- private: >- bool InitFallbackEncoder(); >- >- // If |forced_fallback_possible_| is true: >- // The forced fallback is requested if the resolution is less than or equal to >- // |max_pixels_|. The resolution is allowed to be scaled down to >- // |min_pixels_|. >- class ForcedFallbackParams { >- public: >- bool IsValid(const VideoCodec& codec) const { >- return codec.width * codec.height <= max_pixels_; >- } >- >- bool active_ = false; >- int min_pixels_ = 320 * 180; >- int max_pixels_ = 320 * 240; >- }; >- >- bool TryInitForcedFallbackEncoder(); >- bool TryReInitForcedFallbackEncoder(); >- void ValidateSettingsForForcedFallback(); >- bool IsForcedFallbackActive() const; >- void MaybeModifyCodecForFallback(); >- >- // Settings used in the last InitEncode call and used if a dynamic fallback to >- // software is required. >- VideoCodec codec_settings_; >- int32_t number_of_cores_; >- size_t max_payload_size_; >- >- // The last bitrate/framerate set, and a flag for noting they are set. >- bool rates_set_; >- BitrateAllocation bitrate_allocation_; >- uint32_t framerate_; >- >- // The last channel parameters set, and a flag for noting they are set. >- bool channel_parameters_set_; >- uint32_t packet_loss_; >- int64_t rtt_; >- >- bool use_fallback_encoder_; >- const std::unique_ptr<webrtc::VideoEncoder> encoder_; >- >- const std::unique_ptr<webrtc::VideoEncoder> fallback_encoder_; >- EncodedImageCallback* callback_; >- >- bool forced_fallback_possible_; >- ForcedFallbackParams forced_fallback_; >-}; >- >-} // namespace webrtc >- >-#endif // MEDIA_ENGINE_VIDEOENCODERSOFTWAREFALLBACKWRAPPER_H_ >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.cc >index b97e74e5efb..4d858630b58 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.cc >@@ -15,11 +15,15 @@ > #include "rtc_base/checks.h" > > namespace webrtc { >-VP8EncoderSimulcastProxy::VP8EncoderSimulcastProxy(VideoEncoderFactory* factory) >- : factory_(factory), callback_(nullptr) { >- encoder_ = factory_->CreateVideoEncoder(SdpVideoFormat("VP8")); >+VP8EncoderSimulcastProxy::VP8EncoderSimulcastProxy(VideoEncoderFactory* factory, >+ const SdpVideoFormat& format) >+ : factory_(factory), video_format_(format), callback_(nullptr) { >+ encoder_ = factory_->CreateVideoEncoder(format); > } > >+VP8EncoderSimulcastProxy::VP8EncoderSimulcastProxy(VideoEncoderFactory* factory) >+ : VP8EncoderSimulcastProxy(factory, SdpVideoFormat("VP8")) {} >+ > VP8EncoderSimulcastProxy::~VP8EncoderSimulcastProxy() {} > > int VP8EncoderSimulcastProxy::Release() { >@@ -31,7 +35,7 @@ int VP8EncoderSimulcastProxy::InitEncode(const VideoCodec* inst, > size_t max_payload_size) { > int ret = encoder_->InitEncode(inst, number_of_cores, max_payload_size); > if (ret == WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED) { >- encoder_.reset(new SimulcastEncoderAdapter(factory_)); >+ encoder_.reset(new SimulcastEncoderAdapter(factory_, video_format_)); > if (callback_) { > encoder_->RegisterEncodeCompleteCallback(callback_); > } >@@ -59,7 +63,7 @@ int VP8EncoderSimulcastProxy::SetChannelParameters(uint32_t packet_loss, > } > > int VP8EncoderSimulcastProxy::SetRateAllocation( >- const BitrateAllocation& bitrate, >+ const VideoBitrateAllocation& bitrate, > uint32_t new_framerate) { > return encoder_->SetRateAllocation(bitrate, new_framerate); > } >@@ -69,10 +73,6 @@ VideoEncoder::ScalingSettings VP8EncoderSimulcastProxy::GetScalingSettings() > return encoder_->GetScalingSettings(); > } > >-int32_t VP8EncoderSimulcastProxy::SetPeriodicKeyFrames(bool enable) { >- return encoder_->SetPeriodicKeyFrames(enable); >-} >- > bool VP8EncoderSimulcastProxy::SupportsNativeHandle() const { > return encoder_->SupportsNativeHandle(); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.h >index 5833124c508..11ab0c55cee 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy.h >@@ -15,6 +15,7 @@ > #include <memory> > #include <vector> > >+#include "api/video_codecs/sdp_video_format.h" > #include "api/video_codecs/video_encoder_factory.h" > #include "modules/video_coding/codecs/vp8/include/vp8.h" > >@@ -24,8 +25,13 @@ namespace webrtc { > // doesn't support simulcast for provided settings. > class VP8EncoderSimulcastProxy : public VP8Encoder { > public: >+ VP8EncoderSimulcastProxy(VideoEncoderFactory* factory, >+ const SdpVideoFormat& format); >+ // Deprecated. Remove once all clients use constructor with both factory and >+ // SdpVideoFormat; > explicit VP8EncoderSimulcastProxy(VideoEncoderFactory* factory); >- virtual ~VP8EncoderSimulcastProxy(); >+ >+ ~VP8EncoderSimulcastProxy() override; > > // Implements VideoEncoder. > int Release() override; >@@ -37,17 +43,17 @@ class VP8EncoderSimulcastProxy : public VP8Encoder { > const std::vector<FrameType>* frame_types) override; > int RegisterEncodeCompleteCallback(EncodedImageCallback* callback) override; > int SetChannelParameters(uint32_t packet_loss, int64_t rtt) override; >- int SetRateAllocation(const BitrateAllocation& bitrate, >+ int SetRateAllocation(const VideoBitrateAllocation& bitrate, > uint32_t new_framerate) override; > > VideoEncoder::ScalingSettings GetScalingSettings() const override; > >- int32_t SetPeriodicKeyFrames(bool enable) override; > bool SupportsNativeHandle() const override; > const char* ImplementationName() const override; > > private: > VideoEncoderFactory* const factory_; >+ SdpVideoFormat video_format_; > std::unique_ptr<VideoEncoder> encoder_; > EncodedImageCallback* callback_; > }; >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy_unittest.cc >index 3e2761cfb60..dfa35cbaf6a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/vp8_encoder_simulcast_proxy_unittest.cc >@@ -63,8 +63,6 @@ TEST(VP8EncoderSimulcastProxy, ChoosesCorrectImplementation) { > "SimulcastEncoderAdapter (Fake, Fake, Fake)"; > VideoCodec codec_settings; > webrtc::test::CodecSettings(kVideoCodecVP8, &codec_settings); >- TemporalLayersFactory tl_factory; >- codec_settings.VP8()->tl_factory = &tl_factory; > codec_settings.simulcastStream[0] = { > test::kTestWidth, test::kTestHeight, 2, 2000, 1000, 1000, 56}; > codec_settings.simulcastStream[1] = { >@@ -85,7 +83,8 @@ TEST(VP8EncoderSimulcastProxy, ChoosesCorrectImplementation) { > .Times(1) > .WillOnce(Return(mock_encoder)); > >- VP8EncoderSimulcastProxy simulcast_enabled_proxy(&simulcast_factory); >+ VP8EncoderSimulcastProxy simulcast_enabled_proxy(&simulcast_factory, >+ SdpVideoFormat("VP8")); > EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, > simulcast_enabled_proxy.InitEncode(&codec_settings, 4, 1200)); > EXPECT_EQ(kImplementationName, simulcast_enabled_proxy.ImplementationName()); >@@ -124,7 +123,8 @@ TEST(VP8EncoderSimulcastProxy, ChoosesCorrectImplementation) { > .WillOnce(Return(mock_encoder3)) > .WillOnce(Return(mock_encoder4)); > >- VP8EncoderSimulcastProxy simulcast_disabled_proxy(&nonsimulcast_factory); >+ VP8EncoderSimulcastProxy simulcast_disabled_proxy(&nonsimulcast_factory, >+ SdpVideoFormat("VP8")); > EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, > simulcast_disabled_proxy.InitEncode(&codec_settings, 4, 1200)); > EXPECT_EQ(kSimulcastAdaptedImplementationName, >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.cc >index 6c6464afcd9..82badc10440 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.cc >@@ -27,6 +27,7 @@ > > namespace cricket { > >+#if defined(USE_BUILTIN_SW_CODECS) > namespace { > > MediaEngineInterface* CreateWebRtcMediaEngine( >@@ -86,6 +87,7 @@ MediaEngineInterface* WebRtcMediaEngineFactory::Create( > adm, audio_encoder_factory, audio_decoder_factory, video_encoder_factory, > video_decoder_factory, audio_mixer, audio_processing); > } >+#endif > > std::unique_ptr<MediaEngineInterface> WebRtcMediaEngineFactory::Create( > rtc::scoped_refptr<webrtc::AudioDeviceModule> adm, >@@ -173,12 +175,12 @@ std::vector<webrtc::RtpExtension> FilterRtpExtensions( > // Sort by name, ascending (prioritise encryption), so that we don't reset > // extensions if they were specified in a different order (also allows us > // to use std::unique below). >- std::sort(result.begin(), result.end(), >- [](const webrtc::RtpExtension& rhs, >- const webrtc::RtpExtension& lhs) { >- return rhs.encrypt == lhs.encrypt ? rhs.uri < lhs.uri >- : rhs.encrypt > lhs.encrypt; >- }); >+ std::sort( >+ result.begin(), result.end(), >+ [](const webrtc::RtpExtension& rhs, const webrtc::RtpExtension& lhs) { >+ return rhs.encrypt == lhs.encrypt ? rhs.uri < lhs.uri >+ : rhs.encrypt > lhs.encrypt; >+ }); > > // Remove unnecessary extensions (used on send side). > if (filter_redundant_extensions) { >@@ -200,9 +202,8 @@ std::vector<webrtc::RtpExtension> FilterRtpExtensions( > return result; > } > >-webrtc::Call::Config::BitrateConfig GetBitrateConfigForCodec( >- const Codec& codec) { >- webrtc::Call::Config::BitrateConfig config; >+webrtc::BitrateConstraints GetBitrateConfigForCodec(const Codec& codec) { >+ webrtc::BitrateConstraints config; > int bitrate_kbps = 0; > if (codec.GetParam(kCodecParamMinBitrate, &bitrate_kbps) && > bitrate_kbps > 0) { >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.h b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.h >index 632e7304782..b9927b1a9d2 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.h >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine.h >@@ -25,11 +25,11 @@ class AudioMixer; > class AudioProcessing; > class VideoDecoderFactory; > class VideoEncoderFactory; >-} >+} // namespace webrtc > namespace cricket { > class WebRtcVideoDecoderFactory; > class WebRtcVideoEncoderFactory; >-} >+} // namespace cricket > > namespace cricket { > >@@ -85,8 +85,7 @@ std::vector<webrtc::RtpExtension> FilterRtpExtensions( > bool (*supported)(const std::string&), > bool filter_redundant_extensions); > >-webrtc::Call::Config::BitrateConfig GetBitrateConfigForCodec( >- const Codec& codec); >+webrtc::BitrateConstraints GetBitrateConfigForCodec(const Codec& codec); > > } // namespace cricket > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine_unittest.cc >index 85170e24e5c..446ad24e77c 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcmediaengine_unittest.cc >@@ -12,7 +12,10 @@ > > #include "api/audio_codecs/builtin_audio_decoder_factory.h" > #include "api/audio_codecs/builtin_audio_encoder_factory.h" >+#include "api/video_codecs/builtin_video_decoder_factory.h" >+#include "api/video_codecs/builtin_video_encoder_factory.h" > #include "media/engine/webrtcmediaengine.h" >+#include "modules/audio_processing/include/audio_processing.h" > #include "test/gtest.h" > > using webrtc::RtpExtension; >@@ -101,14 +104,14 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_EmptyList) { > std::vector<RtpExtension> extensions; > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions1, true); >- EXPECT_EQ(0, filtered.size()); >+ EXPECT_EQ(0u, filtered.size()); > } > > TEST(WebRtcMediaEngineTest, FilterRtpExtensions_IncludeOnlySupported) { > std::vector<RtpExtension> extensions = MakeUniqueExtensions(); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions1, false); >- EXPECT_EQ(2, filtered.size()); >+ EXPECT_EQ(2u, filtered.size()); > EXPECT_EQ("c", filtered[0].uri); > EXPECT_EQ("i", filtered[1].uri); > } >@@ -117,7 +120,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_1) { > std::vector<RtpExtension> extensions = MakeUniqueExtensions(); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, false); >- EXPECT_EQ(12, filtered.size()); >+ EXPECT_EQ(12u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > } > >@@ -125,7 +128,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_SortedByName_2) { > std::vector<RtpExtension> extensions = MakeUniqueExtensions(); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(12, filtered.size()); >+ EXPECT_EQ(12u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > } > >@@ -133,7 +136,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_DontRemoveRedundant) { > std::vector<RtpExtension> extensions = MakeRedundantExtensions(); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, false); >- EXPECT_EQ(12, filtered.size()); >+ EXPECT_EQ(12u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > EXPECT_EQ(filtered[0].uri, filtered[1].uri); > } >@@ -142,7 +145,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundant) { > std::vector<RtpExtension> extensions = MakeRedundantExtensions(); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(6, filtered.size()); >+ EXPECT_EQ(6u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > EXPECT_NE(filtered[0].uri, filtered[1].uri); > } >@@ -155,7 +158,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantEncrypted_1) { > extensions.push_back(webrtc::RtpExtension("b", 4)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(3, filtered.size()); >+ EXPECT_EQ(3u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > EXPECT_EQ(filtered[0].uri, filtered[1].uri); > EXPECT_NE(filtered[0].encrypt, filtered[1].encrypt); >@@ -171,7 +174,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantEncrypted_2) { > extensions.push_back(webrtc::RtpExtension("b", 4)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(3, filtered.size()); >+ EXPECT_EQ(3u, filtered.size()); > EXPECT_TRUE(IsSorted(filtered)); > EXPECT_EQ(filtered[0].uri, filtered[1].uri); > EXPECT_NE(filtered[0].encrypt, filtered[1].encrypt); >@@ -190,7 +193,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_1) { > extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 14)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(1, filtered.size()); >+ EXPECT_EQ(1u, filtered.size()); > EXPECT_EQ(RtpExtension::kTransportSequenceNumberUri, filtered[0].uri); > } > >@@ -209,7 +212,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBweEncrypted_1) { > extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 14)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(2, filtered.size()); >+ EXPECT_EQ(2u, filtered.size()); > EXPECT_EQ(RtpExtension::kTransportSequenceNumberUri, filtered[0].uri); > EXPECT_EQ(RtpExtension::kTransportSequenceNumberUri, filtered[1].uri); > EXPECT_NE(filtered[0].encrypt, filtered[1].encrypt); >@@ -222,7 +225,7 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_2) { > extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 7)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(1, filtered.size()); >+ EXPECT_EQ(1u, filtered.size()); > EXPECT_EQ(RtpExtension::kAbsSendTimeUri, filtered[0].uri); > } > >@@ -232,14 +235,17 @@ TEST(WebRtcMediaEngineTest, FilterRtpExtensions_RemoveRedundantBwe_3) { > extensions.push_back(RtpExtension(RtpExtension::kTimestampOffsetUri, 14)); > std::vector<webrtc::RtpExtension> filtered = > FilterRtpExtensions(extensions, SupportedExtensions2, true); >- EXPECT_EQ(1, filtered.size()); >+ EXPECT_EQ(1u, filtered.size()); > EXPECT_EQ(RtpExtension::kTimestampOffsetUri, filtered[0].uri); > } > > TEST(WebRtcMediaEngineFactoryTest, CreateWithBuiltinDecoders) { > std::unique_ptr<MediaEngineInterface> engine(WebRtcMediaEngineFactory::Create( >- nullptr, webrtc::CreateBuiltinAudioEncoderFactory(), >- webrtc::CreateBuiltinAudioDecoderFactory(), nullptr, nullptr)); >+ nullptr /* adm */, webrtc::CreateBuiltinAudioEncoderFactory(), >+ webrtc::CreateBuiltinAudioDecoderFactory(), >+ webrtc::CreateBuiltinVideoEncoderFactory(), >+ webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, >+ webrtc::AudioProcessingBuilder().Create())); > EXPECT_TRUE(engine); > } > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer.cc >index cf9eab6e6c5..f8a9f748a80 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer.cc >@@ -20,7 +20,10 @@ > #include "rtc_base/timeutils.h" > > #include "modules/video_capture/video_capture_factory.h" >+ >+#if defined(WEBRTC_WIN) > #include "rtc_base/win32.h" // Need this to #include the impl files. >+#endif // WEBRTC_WIN > #include "system_wrappers/include/field_trial.h" > > namespace cricket { >@@ -323,8 +326,7 @@ bool WebRtcVideoCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) { > return true; > } > >-void WebRtcVideoCapturer::OnFrame( >- const webrtc::VideoFrame& sample) { >+void WebRtcVideoCapturer::OnFrame(const webrtc::VideoFrame& sample) { > // This can only happen between Start() and Stop(). > RTC_DCHECK(start_thread_); > >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer_unittest.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer_unittest.cc >index 8770960c4c7..e98f1570e73 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer_unittest.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturer_unittest.cc >@@ -81,8 +81,7 @@ TEST_F(WebRtcVideoCapturerTest, TestInitVcm) { > TEST_F(WebRtcVideoCapturerTest, TestCapture) { > EXPECT_TRUE(capturer_->Init(cricket::Device(kTestDeviceName, kTestDeviceId))); > cricket::VideoCapturerListener listener(capturer_.get()); >- cricket::VideoFormat format( >- capturer_->GetSupportedFormats()->at(0)); >+ cricket::VideoFormat format(capturer_->GetSupportedFormats()->at(0)); > EXPECT_EQ(cricket::CS_STARTING, capturer_->Start(format)); > EXPECT_TRUE(capturer_->IsRunning()); > ASSERT_TRUE(capturer_->GetCaptureFormat() != NULL); >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturerfactory.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturerfactory.cc >index c948101ea89..333df6f165a 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturerfactory.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideocapturerfactory.cc >@@ -19,8 +19,7 @@ namespace cricket { > std::unique_ptr<VideoCapturer> WebRtcVideoDeviceCapturerFactory::Create( > const Device& device) { > #ifdef HAVE_WEBRTC_VIDEO >- std::unique_ptr<WebRtcVideoCapturer> capturer( >- new WebRtcVideoCapturer()); >+ std::unique_ptr<WebRtcVideoCapturer> capturer(new WebRtcVideoCapturer()); > if (!capturer->Init(device)) { > return std::unique_ptr<VideoCapturer>(); > } >diff --git a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideoengine.cc b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideoengine.cc >index d6c51d1f327..3a72cde891e 100644 >--- a/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideoengine.cc >+++ b/Source/ThirdParty/libwebrtc/Source/webrtc/media/engine/webrtcvideoengine.cc >@@ -25,7 +25,9 @@ > #include "call/call.h" > #include "common_video/h264/profile_level_id.h" > #include "media/engine/constants.h" >-#include "media/engine/convert_legacy_video_factory.h" >+#if defined(USE_BUILTIN_SW_CODECS) >+#include "media/engine/convert_legacy_video_factory.h" // nogncheck >+#endif > #include "media/engine/simulcast.h" > #include "media/engine/webrtcmediaengine.h" > #include "media/engine/webrtcvoiceengine.h" >@@ -37,8 +39,6 @@ > #include "rtc_base/trace_event.h" > #include "system_wrappers/include/field_trial.h" > >-using DegradationPreference = webrtc::VideoSendStream::DegradationPreference; >- > namespace cricket { > > // Hack in order to pass in |receive_stream_id| to legacy clients. >@@ -46,6 +46,7 @@ namespace cricket { > // webrtc:7925 is fixed. > class DecoderFactoryAdapter { > public: >+#if defined(USE_BUILTIN_SW_CODECS) > explicit DecoderFactoryAdapter( > std::unique_ptr<WebRtcVideoDecoderFactory> external_video_decoder_factory) > : cricket_decoder_with_params_(new CricketDecoderWithParams( >@@ -53,6 +54,7 @@ class DecoderFactoryAdapter { > decoder_factory_(ConvertVideoDecoderFactory( > std::unique_ptr<WebRtcVideoDecoderFactory>( > cricket_decoder_with_params_))) {} >+#endif > > explicit DecoderFactoryAdapter( > std::unique_ptr<webrtc::VideoDecoderFactory> video_decoder_factory) >@@ -136,7 +138,6 @@ class NullVideoDecoder : public webrtc::VideoDecoder { > > int32_t Decode(const webrtc::EncodedImage& input_image, > bool missing_frames, >- const webrtc::RTPFragmentationHeader* fragmentation, > const webrtc::CodecSpecificInfo* codec_specific_info, > int64_t render_time_ms) override { > RTC_LOG(LS_ERROR) << "The NullVideoDecoder doesn't support decoding."; >@@ -186,7 +187,6 @@ void AddDefaultFeedbackParams(VideoCodec* codec) { > codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamNack, kRtcpFbNackParamPli)); > } > >- > // This function will assign dynamic payload types (in the range [96, 127]) to > // the input codecs, and also add ULPFEC, RED, FlexFEC, and associated RTX > // codecs for recognized codecs (VP8, VP9, H264, and RED). It will also add >@@ -221,23 +221,23 @@ std::vector<VideoCodec> AssignPayloadTypesAndDefaultCodecs( > > // Increment payload type. > ++payload_type; >- if (payload_type > kLastDynamicPayloadType) >+ if (payload_type > kLastDynamicPayloadType) { >+ RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; > break; >+ } > >- // Add associated RTX codec for recognized codecs. >- // TODO(deadbeef): Should we add RTX codecs for external codecs whose names >- // we don't recognize? >- if (CodecNamesEq(codec.name, kVp8CodecName) || >- CodecNamesEq(codec.name, kVp9CodecName) || >- CodecNamesEq(codec.name, kH264CodecName) || >- CodecNamesEq(codec.name, kRedCodecName)) { >+ // Add associated RTX codec for non-FEC codecs. >+ if (!CodecNamesEq(codec.name, kUlpfecCodecName) && >+ !CodecNamesEq(codec.name, kFlexfecCodecName)) { > output_codecs.push_back( > VideoCodec::CreateRtxCodec(payload_type, codec.id)); > > // Increment payload type. > ++payload_type; >- if (payload_type > kLastDynamicPayloadType) >+ if (payload_type > kLastDynamicPayloadType) { >+ RTC_LOG(LS_ERROR) << "Out of dynamic payload types, skipping the rest."; > break; >+ } > } > } > return output_codecs; >@@ -318,8 +318,10 @@ static bool ValidateStreamParams(const StreamParams& sp) { > > // Returns true if the given codec is disallowed from doing simulcast. > bool IsCodecBlacklistedForSimulcast(const std::string& codec_name) { >- return CodecNamesEq(codec_name, kH264CodecName) || >- CodecNamesEq(codec_name, kVp9CodecName); >+ return webrtc::field_trial::IsEnabled("WebRTC-H264Simulcast") >+ ? CodecNamesEq(codec_name, kVp9CodecName) >+ : CodecNamesEq(codec_name, kH264CodecName) || >+ CodecNamesEq(codec_name, kVp9CodecName); > } > > // The selected thresholds for QVGA and VGA corresponded to a QP around 10. >@@ -336,67 +338,67 @@ static int GetMaxDefaultVideoBitrateKbps(int width, int height) { > } > } > >-bool GetVp9LayersFromFieldTrialGroup(int* num_spatial_layers, >- int* num_temporal_layers) { >+bool GetVp9LayersFromFieldTrialGroup(size_t* num_spatial_layers, >+ size_t* num_temporal_layers) { > std::string group = webrtc::field_trial::FindFullName("WebRTC-SupportVP9SVC"); > if (group.empty()) > return false; > >- if (sscanf(group.c_str(), "EnabledByFlag_%dSL%dTL", num_spatial_layers, >+ if (sscanf(group.c_str(), "EnabledByFlag_%zuSL%zuTL", num_spatial_layers, > num_temporal_layers) != 2) { > return false; > } >- const int kMaxSpatialLayers = 2; >+ const size_t kMaxSpatialLayers = 3; > if (*num_spatial_layers > kMaxSpatialLayers || *num_spatial_layers < 1) > return false; > >- const int kMaxTemporalLayers = 3; >+ const size_t kMaxTemporalLayers = 3; > if (*num_temporal_layers > kMaxTemporalLayers || *num_temporal_layers < 1) > return false; > > return true; > } > >-int GetDefaultVp9SpatialLayers() { >- int num_sl; >- int num_tl; >+absl::optional<size_t> GetVp9SpatialLayersFromFieldTrial() { >+ size_t num_sl; >+ size_t num_tl; > if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) { > return num_sl; > } >- return 1; >+ return absl::nullopt; > } > >-int GetDefaultVp9TemporalLayers() { >- int num_sl; >- int num_tl; >+absl::optional<size_t> GetVp9TemporalLayersFromFieldTrial() { >+ size_t num_sl; >+ size_t num_tl; > if (GetVp9LayersFromFieldTrialGroup(&num_sl, &num_tl)) { > return num_tl; > } >- return 1; >+ return absl::nullopt; > } > > const char kForcedFallbackFieldTrial[] = > "WebRTC-VP8-Forced-Fallback-Encoder-v2"; > >-rtc::Optional<int> GetFallbackMinBpsFromFieldTrial() { >+absl::optional<int> GetFallbackMinBpsFromFieldTrial() { > if (!webrtc::field_trial::IsEnabled(kForcedFallbackFieldTrial)) >- return rtc::nullopt; >+ return absl::nullopt; > > std::string group = >